[Libreoffice-commits] core.git: Branch 'feature/gsoc-tiled-rendering' - 8 commits - libreofficekit/Library_libreofficekitgtk.mk libreofficekit/source

Pranav Kant pranavk at gnome.org
Thu Jun 4 10:06:53 PDT 2015


Rebased ref, commits from common ancestor:
commit 9e5b792642fe39b9558c26f9d76b8ed9b6752942
Author: Pranav Kant <pranavk at gnome.org>
Date:   Thu Jun 4 22:09:57 2015 +0530

    lokdocview, tilebuffer: clean up
    
    Improve documentation, style fixes
    
    Change-Id: I5000e32e90cd8e3b75e8df2907673efc303a55fd

diff --git a/libreofficekit/source/gtk/lokdocview.cxx b/libreofficekit/source/gtk/lokdocview.cxx
index 50ddc76..4191fa1 100644
--- a/libreofficekit/source/gtk/lokdocview.cxx
+++ b/libreofficekit/source/gtk/lokdocview.cxx
@@ -1,4 +1,4 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /*
  * This file is part of the LibreOffice project.
  *
@@ -177,12 +177,12 @@ struct LOKDocView_Impl
     /// Implementation of the timeout handler, invoked by handleTimeout().
     gboolean handleTimeoutImpl();
     /**
-     * Renders the document to a number of tiles.
+     * Renders the document to a number of visible tiles.
      *
      * This method is invoked only manually, not when some Gtk signal is
      * emitted.
      *
-     * @param pPartial if 0, then the full document is rendered, otherwise only
+     * @param pPartial if 0, then the full visible document is rendered, otherwise only
      * the tiles that intersect with pPartial.
      */
     void renderDocument(GdkRectangle* pPartial);
@@ -665,7 +665,7 @@ void LOKDocView_Impl::setTilesInvalid(const GdkRectangle& rRectangle)
 
     for (int i = aStart.x; i < aEnd.x; i++)
         for (int j = aStart.y; j < aEnd.y; j++)
-            m_pTileBuffer->tile_buffer_set_invalid(i, j);
+            m_pTileBuffer->setInvalid(i, j);
 }
 
 void LOKDocView_Impl::renderHandle(cairo_t* pCairo, const GdkRectangle& rCursor, cairo_surface_t* pHandle, GdkRectangle& rRectangle)
@@ -824,10 +824,10 @@ void LOKDocView_Impl::renderDocument(GdkRectangle* pPartial)
 
             if (bPaint)
             {
-                //                g_info("gettile: (%d %d)", nRow, nColumn);
+                g_info("tile_buffer_get_tile (%d, %d)", nRow, nColumn);
 
-                Tile& currentTile = m_pTileBuffer->tile_buffer_get_tile(nRow, nColumn);
-                GdkPixbuf* pPixBuf = currentTile.tile_get_buffer();
+                Tile& currentTile = m_pTileBuffer->getTile(nRow, nColumn);
+                GdkPixbuf* pPixBuf = currentTile.getBuffer();
 
                 gdk_cairo_set_source_pixbuf (pcairo, pPixBuf, twipToPixel(aTileRectangleTwips.x, m_fZoom), twipToPixel(aTileRectangleTwips.y, m_fZoom));
                 cairo_paint(pcairo);
@@ -942,7 +942,7 @@ gboolean LOKDocView_Impl::callbackImpl(CallbackData* pCallback)
         }
         else
         {
-            m_pTileBuffer->tile_buffer_reset_all_tiles();
+            m_pTileBuffer->resetAllTiles();
             renderDocument(0);
         }
     }
@@ -1148,21 +1148,28 @@ static void lok_docview_init( GTypeInstance* pInstance, gpointer )
     gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW(pDocView),
                                            pDocView->m_pImpl->m_pDrawingArea );
 
-    g_signal_connect(GTK_OBJECT(pDocView->m_pImpl->m_pDrawingArea),
+    g_signal_connect(G_OBJECT(pDocView->m_pImpl->m_pDrawingArea),
                      "expose-event",
-                     GTK_SIGNAL_FUNC(LOKDocView_Impl::on_exposed), pDocView);
-    g_signal_connect(GTK_OBJECT(pDocView->m_pImpl->m_pDrawingArea),
+                     G_CALLBACK(LOKDocView_Impl::on_exposed), pDocView);
+    g_signal_connect(G_OBJECT(pDocView->m_pImpl->m_pDrawingArea),
                      "expose-event",
-                     GTK_SIGNAL_FUNC(LOKDocView_Impl::renderOverlay), pDocView);
+                     G_CALLBACK(LOKDocView_Impl::renderOverlay), pDocView);
     gtk_widget_add_events(pDocView->m_pImpl->m_pDrawingArea,
-                          GDK_BUTTON_PRESS_MASK
-                          | GDK_BUTTON_RELEASE_MASK
-                          | GDK_BUTTON_MOTION_MASK);
-    g_signal_connect(G_OBJECT(pDocView->m_pImpl->m_pDrawingArea), "button-press-event", G_CALLBACK(LOKDocView_Impl::signalButton), pDocView);
-    g_signal_connect(G_OBJECT(pDocView->m_pImpl->m_pDrawingArea), "button-release-event", G_CALLBACK(LOKDocView_Impl::signalButton), pDocView);
-    g_signal_connect(G_OBJECT(pDocView->m_pImpl->m_pDrawingArea), "motion-notify-event", G_CALLBACK(LOKDocView_Impl::signalMotion), pDocView);
-
-    gtk_signal_connect(GTK_OBJECT(pDocView), "destroy", GTK_SIGNAL_FUNC(LOKDocView_Impl::destroy), 0);
+                           GDK_BUTTON_PRESS_MASK
+                          |GDK_BUTTON_RELEASE_MASK
+                          |GDK_BUTTON_MOTION_MASK);
+
+    g_signal_connect(G_OBJECT(pDocView->m_pImpl->m_pDrawingArea),
+                     "button-press-event",
+                     G_CALLBACK(LOKDocView_Impl::signalButton), pDocView);
+    g_signal_connect(G_OBJECT(pDocView->m_pImpl->m_pDrawingArea),
+                     "button-release-event",
+                     G_CALLBACK(LOKDocView_Impl::signalButton), pDocView);
+    g_signal_connect(G_OBJECT(pDocView->m_pImpl->m_pDrawingArea),
+                     "motion-notify-event",
+                     G_CALLBACK(LOKDocView_Impl::signalMotion), pDocView);
+
+    g_signal_connect(G_OBJECT(pDocView), "destroy", G_CALLBACK(LOKDocView_Impl::destroy), 0);
 }
 
 SAL_DLLPUBLIC_EXPORT guint lok_docview_get_type()
@@ -1253,7 +1260,7 @@ SAL_DLLPUBLIC_EXPORT void lok_docview_set_zoom ( LOKDocView* pDocView, float fZo
     guint nRows = ceil((double)nDocumentHeightPixels / nTileSizePixels);
     guint nColumns = ceil((double)nDocumentWidthPixels / nTileSizePixels);
 
-    pDocView->m_pImpl->m_pTileBuffer->tile_buffer_set_zoom(fZoom, nRows, nColumns);
+    pDocView->m_pImpl->m_pTileBuffer->setZoom(fZoom, nRows, nColumns);
 
     if ( pDocView->m_pImpl->m_pDocument )
         pDocView->m_pImpl->renderDocument(0);
diff --git a/libreofficekit/source/gtk/tilebuffer.cxx b/libreofficekit/source/gtk/tilebuffer.cxx
index 3e5e01f..936d472 100644
--- a/libreofficekit/source/gtk/tilebuffer.cxx
+++ b/libreofficekit/source/gtk/tilebuffer.cxx
@@ -1,4 +1,4 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /*
  * This file is part of the LibreOffice project.
  *
@@ -9,6 +9,10 @@
 
 #include "tilebuffer.hxx"
 
+/* ------------------
+   Utility functions
+   ------------------
+*/
 float pixelToTwip(float fInput, float zoom)
 {
     return (fInput / DPI / zoom) * 1440.0f;
@@ -19,84 +23,94 @@ float twipToPixel(float fInput, float zoom)
     return fInput / 1440.0f * DPI * zoom;
 }
 
-GdkPixbuf* Tile::tile_get_buffer()
+/* ----------------------------
+   Tile class member functions
+   ----------------------------
+*/
+GdkPixbuf* Tile::getBuffer()
 {
     return m_pBuffer;
 }
 
-void Tile::tile_release()
+void Tile::release()
 {
     g_object_unref (m_pBuffer);
     m_pBuffer = NULL;
 }
 
-void TileBuffer::tile_buffer_set_zoom(float newZoomFactor, int rows, int columns)
+void Tile::setPixbuf(GdkPixbuf *buffer)
+{
+    m_pBuffer = buffer;
+}
+
+/* ----------------------------------
+   TileBuffer class member functions
+   ----------------------------------
+*/
+void TileBuffer::setZoom(float newZoomFactor, int rows, int columns)
 {
     m_fZoomFactor = newZoomFactor;
 
-    tile_buffer_reset_all_tiles();
+    resetAllTiles();
 
     // set new buffer width and height
     m_nWidth = columns;
     m_nHeight = rows;
 }
 
-void TileBuffer::tile_buffer_reset_all_tiles()
+void TileBuffer::resetAllTiles()
 {
     std::map<int, Tile>::iterator it = m_mTiles.begin();
     for (; it != m_mTiles.end(); it++)
         {
-            it->second.tile_release();
+            it->second.release();
         }
     m_mTiles.clear();
 }
 
-void TileBuffer::tile_buffer_set_invalid(int x, int y)
+void TileBuffer::setInvalid(int x, int y)
 {
     int index = x * m_nWidth + y;
     g_info("setting invalid : %d %d",x, y);
     if (m_mTiles.find(index) != m_mTiles.end())
         {
             m_mTiles[index].valid = 0;
-            m_mTiles[index].tile_release();
+            m_mTiles[index].release();
             m_mTiles.erase(index);
         }
 }
 
-Tile& TileBuffer::tile_buffer_get_tile(int x, int y)
+Tile& TileBuffer::getTile(int x, int y)
 {
     int index = x * m_nWidth + y;
     if(m_mTiles.find(index) == m_mTiles.end() || !m_mTiles[index].valid)
-        {
+    {
 
-            GdkPixbuf* pPixBuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, m_nTileSize, m_nTileSize);
-            if (!pPixBuf){
-                g_info ("error allocating memory to pixbuf");
-            }
-            unsigned char* pBuffer = gdk_pixbuf_get_pixels(pPixBuf);
-            GdkRectangle aTileRectangle;
-            aTileRectangle.x = pixelToTwip(m_nTileSize, m_fZoomFactor) * y;
-            aTileRectangle.y = pixelToTwip(m_nTileSize, m_fZoomFactor) * x;
-
-            g_info ("rendering (%d %d)", x, y);
-            m_pLOKDocument->pClass->paintTile(m_pLOKDocument,
-                                              // Buffer and its size, depends on the position only.
-                                              pBuffer,
-                                              m_nTileSize, m_nTileSize,
-                                              // Position of the tile.
-                                              aTileRectangle.x, aTileRectangle.y,
-                                              // Size of the tile, depends on the zoom factor and the tile position only.
-                                              pixelToTwip(m_nTileSize, m_fZoomFactor), pixelToTwip(m_nTileSize, m_fZoomFactor));
-
-            //create a mapping for it
-            m_mTiles[index].tile_set_pixbuf(pPixBuf);
-            m_mTiles[index].valid = 1;
+        GdkPixbuf* pPixBuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, m_nTileSize, m_nTileSize);
+        if (!pPixBuf)
+        {
+            g_info ("error allocating memory to pixbuf");
         }
+        unsigned char* pBuffer = gdk_pixbuf_get_pixels(pPixBuf);
+        GdkRectangle aTileRectangle;
+        aTileRectangle.x = pixelToTwip(m_nTileSize, m_fZoomFactor) * y;
+        aTileRectangle.y = pixelToTwip(m_nTileSize, m_fZoomFactor) * x;
+
+        g_info ("rendering (%d %d)", x, y);
+        m_pLOKDocument->pClass->paintTile(m_pLOKDocument,
+                                          pBuffer,
+                                          m_nTileSize, m_nTileSize,
+                                          aTileRectangle.x, aTileRectangle.y,
+                                          pixelToTwip(m_nTileSize, m_fZoomFactor),
+                                          pixelToTwip(m_nTileSize, m_fZoomFactor));
+
+        //create a mapping for it
+        m_mTiles[index].setPixbuf(pPixBuf);
+        m_mTiles[index].valid = 1;
+    }
 
     return m_mTiles[index];
 }
 
-void Tile::tile_set_pixbuf(GdkPixbuf *buffer)
-{
-    m_pBuffer = buffer;
-}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/libreofficekit/source/gtk/tilebuffer.hxx b/libreofficekit/source/gtk/tilebuffer.hxx
index 15b276f..7e2132f 100644
--- a/libreofficekit/source/gtk/tilebuffer.hxx
+++ b/libreofficekit/source/gtk/tilebuffer.hxx
@@ -1,4 +1,4 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /*
  * This file is part of the LibreOffice project.
  *
@@ -24,32 +24,60 @@ const int DPI = 96;
 // Lets use a square of side 256 pixels for each tile.
 const int nTileSizePixels = 256;
 
+/**
+   Converts the pixel value to zoom independent twip value.
+
+   @param fInput value to convert
+   @param zoom the current zoom level
+
+   @return the pixels value corresponding to given twip value
+*/
 float pixelToTwip(float fInput, float zoom);
 
+/**
+   Converts the zoom independent twip value pixel value.
+
+   @param fInput value to convert
+   @param zoom the current zoom level
+
+   @return the twip value corresponding to given pixel value
+*/
 float twipToPixel(float fInput, float zoom);
 
-/*
-  This class represents a single tile in the tile buffer.
-  TODO: Extend it to support features like double buffering
+/**
+   This class represents a single tile in the tile buffer.
+   It encloses a reference to GdkPixBuf containing the pixel data of the tile.
 */
 class Tile
 {
  public:
- Tile() : valid(0) {}
-    ~Tile() {
-    }
+    Tile() : valid(0) {}
+    ~Tile() { }
 
-    GdkPixbuf* tile_get_buffer();
-    void tile_release();
-    void tile_set_pixbuf(GdkPixbuf*);
+    /**
+       Tells if this tile is valid or not. Initialised to 0 (invalid) during
+       object creation.
+    */
     bool valid;
- private:
+
+    /// Function to get the pointer to enclosing GdkPixbuf
+    GdkPixbuf* getBuffer();
+    /// Destroys the enclosing GdkPixbuf object pointed to by m_pBuffer
+    void release();
+    /// Used to set the pixel buffer of this object
+    void setPixbuf(GdkPixbuf*);
+
+private:
+    /// Pixel buffer data for this tile
     GdkPixbuf *m_pBuffer;
 };
 
-/*
-  TileBuffer is the buffer caching all the recently rendered tiles.
-  The buffer is set to invalid when zoom factor changes.
+/**
+   This class represents the tile buffer which is responsible for managing,
+   reusing and caching all the already rendered tiles. If the given tile is not
+   present in the buffer, call to LOK Document's (m_pLOKDocument) paintTile
+   method is made which fetches the rendered tile from LO core and store it in
+   buffer for future reuse.
 */
 class TileBuffer
 {
@@ -67,19 +95,58 @@ class TileBuffer
 
     ~TileBuffer() {}
 
-    void tile_buffer_set_zoom(float zoomFactor, int rows, int columns);
-    Tile& tile_buffer_get_tile(int x, int y);
-    void tile_buffer_update();
-    void tile_buffer_reset_all_tiles();
-    void tile_buffer_set_invalid(int x, int y);
+    /**
+       Sets the zoom factor (m_fZoomFactor) for this tile buffer. Setting the
+       zoom factor invalidates whole of the tile buffer, destroys all tiles
+       contained within it, and sets new width, height values for tile
+       buffer. The width, height value of tile buffer is the width and height of
+       the table containing all possible tiles (rendered and non-rendered) that
+       this buffer can have.
+
+       @param zoomFactor the new zoom factor value to set
+     */
+    void setZoom(float zoomFactor, int rows, int columns);
+    /**
+       Gets the underlying Tile object for given position. The position (0, 0)
+       points to the left top most tile of the buffer.
+
+       If the tile is not cached by the tile buffer, it makes a paintTile call
+       to LO core asking to render the given tile. It then stores the tile for
+       future reuse.
+
+       @param x the tile along the x-axis of the buffer
+       @param y the tile along the y-axis of the buffer
+
+       @return the tile at the mentioned position (x, y)
+     */
+    Tile& getTile(int x, int y);
+    /// Destroys all the tiles in the tile buffer; also frees the memory allocated
+    /// for all the Tile objects.
+    void resetAllTiles();
+    /**
+       Marks the tile as invalid. The tile (0, 0) is the left topmost tile in
+       the tile buffer.
+
+       @param x the position of tile along x-axis
+       @param y the position of tile along y-axis
+     */
+    void setInvalid(int x, int y);
+
  private:
+    /// Contains the reference to the LOK Document that this tile buffer is for.
     LibreOfficeKitDocument *m_pLOKDocument;
+    /// The side of each squared tile in pixels.
     int m_nTileSize;
+    /// The zoom factor that the tile buffer is currently rendered to.
     float m_fZoomFactor;
+    /// Stores all the tiles cached by this tile buffer.
     std::map<int, Tile> m_mTiles;
-    //TODO: Also set width and height when document size changes
+    /// Width of the current tile buffer (number of columns)
     int m_nWidth;
+    /// Height of the current tile buffer (numbero of rows)
     int m_nHeight;
 };
 
 #endif // INCLUDED_TILEBUFFER_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit 34e44f5509c474a590b747fa1bc39cb69a4349bd
Author: Pranav Kant <pranavk at gnome.org>
Date:   Thu Jun 4 14:15:58 2015 +0530

    lokdocview: wrap a functionality inside a member function
    
    Lets use a member function to set invalid tiles that come under the
    given GdkRectangle.
    
    Change-Id: I440336ddf3c5fd9094f35bb89479aa76a42477fa

diff --git a/libreofficekit/source/gtk/lokdocview.cxx b/libreofficekit/source/gtk/lokdocview.cxx
index 478375d..50ddc76 100644
--- a/libreofficekit/source/gtk/lokdocview.cxx
+++ b/libreofficekit/source/gtk/lokdocview.cxx
@@ -212,6 +212,8 @@ struct LOKDocView_Impl
     void searchNotFound(const std::string& rPayload);
     /// LOK decided to change parts, need to update UI.
     void setPart(const std::string& rPayload);
+    /// Sets the tiles enclosed by rRectangle as invalid in m_pTileBuffer
+    void setTilesInvalid(const GdkRectangle& rRectangle);
 };
 
 namespace {
@@ -646,6 +648,26 @@ bool LOKDocView_Impl::isEmptyRectangle(const GdkRectangle& rRectangle)
     return rRectangle.x == 0 && rRectangle.y == 0 && rRectangle.width == 0 && rRectangle.height == 0;
 }
 
+void LOKDocView_Impl::setTilesInvalid(const GdkRectangle& rRectangle)
+{
+    GdkRectangle aRectanglePixels;
+    GdkPoint aStart, aEnd;
+
+    aRectanglePixels.x = twipToPixel(rRectangle.x, m_fZoom);
+    aRectanglePixels.y = twipToPixel(rRectangle.y, m_fZoom);
+    aRectanglePixels.width = twipToPixel(rRectangle.width, m_fZoom);
+    aRectanglePixels.height = twipToPixel(rRectangle.height, m_fZoom);
+
+    aStart.x = aRectanglePixels.y / nTileSizePixels;
+    aStart.y = aRectanglePixels.x / nTileSizePixels;
+    aEnd.x = (aRectanglePixels.y + aRectanglePixels.height + nTileSizePixels) / nTileSizePixels;
+    aEnd.y = (aRectanglePixels.x + aRectanglePixels.width + nTileSizePixels) / nTileSizePixels;
+
+    for (int i = aStart.x; i < aEnd.x; i++)
+        for (int j = aStart.y; j < aEnd.y; j++)
+            m_pTileBuffer->tile_buffer_set_invalid(i, j);
+}
+
 void LOKDocView_Impl::renderHandle(cairo_t* pCairo, const GdkRectangle& rCursor, cairo_surface_t* pHandle, GdkRectangle& rRectangle)
 {
     GdkPoint aCursorBottom;
@@ -915,21 +937,7 @@ gboolean LOKDocView_Impl::callbackImpl(CallbackData* pCallback)
         if (pCallback->m_aPayload != "EMPTY")
         {
             GdkRectangle aRectangle = LOKDocView_Impl::payloadToRectangle(pCallback->m_aPayload.c_str());
-            GdkRectangle aRectanglePixels;
-            aRectanglePixels.x = twipToPixel(aRectangle.x, m_fZoom);
-            aRectanglePixels.y = twipToPixel(aRectangle.y, m_fZoom);
-            aRectanglePixels.width = twipToPixel(aRectangle.width, m_fZoom);
-            aRectanglePixels.height = twipToPixel(aRectangle.height, m_fZoom);
-            int rowStart = aRectanglePixels.y / nTileSizePixels;
-            int colStart = aRectanglePixels.x / nTileSizePixels;
-            int rowEnd = (aRectanglePixels.y + aRectanglePixels.height + nTileSizePixels) / nTileSizePixels;
-            int colEnd = (aRectanglePixels.x + aRectanglePixels.width + nTileSizePixels) / nTileSizePixels;
-            int i,j;
-            for (i = rowStart; i < rowEnd; i++) {
-                for (j = colStart; j < colEnd; j++) {
-                    m_pTileBuffer->tile_buffer_set_invalid(i, j);
-                }
-            }
+            setTilesInvalid(aRectangle);
             renderDocument(0);
         }
         else
@@ -943,21 +951,7 @@ gboolean LOKDocView_Impl::callbackImpl(CallbackData* pCallback)
     {
         m_aVisibleCursor = LOKDocView_Impl::payloadToRectangle(pCallback->m_aPayload.c_str());
         m_bCursorOverlayVisible = true;
-        GdkRectangle aRectanglePixels;
-        aRectanglePixels.x = twipToPixel(m_aVisibleCursor.x, m_fZoom);
-        aRectanglePixels.y = twipToPixel(m_aVisibleCursor.y, m_fZoom);
-        aRectanglePixels.width = twipToPixel(m_aVisibleCursor.width, m_fZoom);
-        aRectanglePixels.height = twipToPixel(m_aVisibleCursor.height, m_fZoom);
-        int rowStart = aRectanglePixels.y / nTileSizePixels;
-        int colStart = aRectanglePixels.x / nTileSizePixels;
-        int rowEnd = (aRectanglePixels.y + aRectanglePixels.height + nTileSizePixels) / nTileSizePixels;
-        int colEnd = (aRectanglePixels.x + aRectanglePixels.width + nTileSizePixels) / nTileSizePixels;
-        int i,j;
-        for (i = rowStart; i < rowEnd; i++) {
-            for (j = colStart; j < colEnd; j++) {
-                m_pTileBuffer->tile_buffer_set_invalid(i, j);
-            }
-        }
+        setTilesInvalid(m_aVisibleCursor);
         renderDocument(0);
     }
     break;
commit 3021e56a81142af59e455ca4f7bb38f5facadf7d
Author: Pranav Kant <pranavk at gnome.org>
Date:   Thu Jun 4 13:56:46 2015 +0530

    lokdocview: move commonly used functions and variables to common header
    
    twipToPixel and pixelToTwip are also being used by the new TileBuffer
    clsas. Lets move these utility functions to a common header,
    tilebuffer.hxx
    
    The variables for DPI and tileSize are also moved to tilebuffer.hxx
    
    Change-Id: I9d0bec7f2aefe412df232040a7a9abc6db3e4ccb

diff --git a/libreofficekit/source/gtk/lokdocview.cxx b/libreofficekit/source/gtk/lokdocview.cxx
index d3f0820..478375d 100644
--- a/libreofficekit/source/gtk/lokdocview.cxx
+++ b/libreofficekit/source/gtk/lokdocview.cxx
@@ -37,11 +37,6 @@
 // Number of handles around a graphic selection.
 #define GRAPHIC_HANDLE_COUNT 8
 
-// We know that VirtualDevices use a DPI of 96.
-static const int DPI = 96;
-// Lets use a square of side 256 pixels.
-static const int nTileSizePixels = 256;
-
 namespace {
 
 /// Sets rWidth and rHeight from a "width, height" string.
@@ -145,10 +140,6 @@ struct LOKDocView_Impl
     static void destroy(LOKDocView* pDocView, gpointer pData);
     /// Connected to the expose-event of the GtkDrawingArea
     static void on_exposed(GtkWidget *widget, GdkEvent *event, gpointer user_data);
-    /// Converts from screen pixels to document coordinates.
-    float pixelToTwip(float fInput);
-    /// Converts from document coordinates to screen pixels.
-    float twipToPixel(float fInput);
     /// Receives a key press or release event.
     void signalKey(GdkEventKey* pEvent);
     /**
@@ -316,16 +307,6 @@ void LOKDocView_Impl::on_exposed(GtkWidget* /*widget*/, GdkEvent* /*event*/, gpo
     pDocView->m_pImpl->renderDocument(0);
 }
 
-float LOKDocView_Impl::pixelToTwip(float fInput)
-{
-    return (fInput / DPI / m_fZoom) * 1440.0f;
-}
-
-float LOKDocView_Impl::twipToPixel(float fInput)
-{
-    return fInput / 1440.0f * DPI * m_fZoom;
-}
-
 void LOKDocView_Impl::signalKey(GdkEventKey* pEvent)
 {
     int nCharCode = 0;
@@ -390,7 +371,7 @@ gboolean LOKDocView_Impl::signalButton(GtkWidget* /*pEventBox*/, GdkEventButton*
 /// Receives a button press event.
 gboolean LOKDocView_Impl::signalButtonImpl(GdkEventButton* pEvent)
 {
-    g_info("LOKDocView_Impl::signalButton: %d, %d (in twips: %d, %d)", (int)pEvent->x, (int)pEvent->y, (int)pixelToTwip(pEvent->x), (int)pixelToTwip(pEvent->y));
+    g_info("LOKDocView_Impl::signalButton: %d, %d (in twips: %d, %d)", (int)pEvent->x, (int)pEvent->y, (int)pixelToTwip(pEvent->x, m_fZoom), (int)pixelToTwip(pEvent->y, m_fZoom));
 
     if (pEvent->type == GDK_BUTTON_RELEASE)
     {
@@ -419,7 +400,7 @@ gboolean LOKDocView_Impl::signalButtonImpl(GdkEventButton* pEvent)
             {
                 g_info("LOKDocView_Impl::signalButton: end of drag graphic handle #%d", i);
                 m_bInDragGraphicHandles[i] = false;
-                m_pDocument->pClass->setGraphicSelection(m_pDocument, LOK_SETGRAPHICSELECTION_END, pixelToTwip(pEvent->x), pixelToTwip(pEvent->y));
+                m_pDocument->pClass->setGraphicSelection(m_pDocument, LOK_SETGRAPHICSELECTION_END, pixelToTwip(pEvent->x, m_fZoom), pixelToTwip(pEvent->y, m_fZoom));
                 return FALSE;
             }
         }
@@ -428,7 +409,7 @@ gboolean LOKDocView_Impl::signalButtonImpl(GdkEventButton* pEvent)
         {
             g_info("LOKDocView_Impl::signalButton: end of drag graphic selection");
             m_bInDragGraphicSelection = false;
-            m_pDocument->pClass->setGraphicSelection(m_pDocument, LOK_SETGRAPHICSELECTION_END, pixelToTwip(pEvent->x), pixelToTwip(pEvent->y));
+            m_pDocument->pClass->setGraphicSelection(m_pDocument, LOK_SETGRAPHICSELECTION_END, pixelToTwip(pEvent->x, m_fZoom), pixelToTwip(pEvent->y, m_fZoom));
             return FALSE;
         }
     }
@@ -469,8 +450,8 @@ gboolean LOKDocView_Impl::signalButtonImpl(GdkEventButton* pEvent)
                     m_bInDragGraphicHandles[i] = true;
                     m_pDocument->pClass->setGraphicSelection(m_pDocument,
                                                              LOK_SETGRAPHICSELECTION_START,
-                                                             pixelToTwip(m_aGraphicHandleRects[i].x + m_aGraphicHandleRects[i].width / 2),
-                                                             pixelToTwip(m_aGraphicHandleRects[i].y + m_aGraphicHandleRects[i].height / 2));
+                                                             pixelToTwip(m_aGraphicHandleRects[i].x + m_aGraphicHandleRects[i].width / 2, m_fZoom),
+                                                             pixelToTwip(m_aGraphicHandleRects[i].y + m_aGraphicHandleRects[i].height / 2, m_fZoom));
                     return FALSE;
                 }
             }
@@ -488,7 +469,7 @@ gboolean LOKDocView_Impl::signalButtonImpl(GdkEventButton* pEvent)
         if ((pEvent->time - m_nLastButtonPressTime) < 250)
             nCount++;
         m_nLastButtonPressTime = pEvent->time;
-        m_pDocument->pClass->postMouseEvent(m_pDocument, LOK_MOUSEEVENT_MOUSEBUTTONDOWN, pixelToTwip(pEvent->x), pixelToTwip(pEvent->y), nCount);
+        m_pDocument->pClass->postMouseEvent(m_pDocument, LOK_MOUSEEVENT_MOUSEBUTTONDOWN, pixelToTwip(pEvent->x, m_fZoom), pixelToTwip(pEvent->y, m_fZoom), nCount);
         break;
     }
     case GDK_BUTTON_RELEASE:
@@ -497,7 +478,7 @@ gboolean LOKDocView_Impl::signalButtonImpl(GdkEventButton* pEvent)
         if ((pEvent->time - m_nLastButtonReleaseTime) < 250)
             nCount++;
         m_nLastButtonReleaseTime = pEvent->time;
-        m_pDocument->pClass->postMouseEvent(m_pDocument, LOK_MOUSEEVENT_MOUSEBUTTONUP, pixelToTwip(pEvent->x), pixelToTwip(pEvent->y), nCount);
+        m_pDocument->pClass->postMouseEvent(m_pDocument, LOK_MOUSEEVENT_MOUSEBUTTONUP, pixelToTwip(pEvent->x, m_fZoom), pixelToTwip(pEvent->y, m_fZoom), nCount);
         break;
     }
     default:
@@ -534,21 +515,21 @@ gboolean LOKDocView_Impl::signalMotionImpl(GdkEventButton* pEvent)
     {
         g_info("lcl_signalMotion: dragging the middle handle");
         LOKDocView_Impl::getDragPoint(&m_aHandleMiddleRect, pEvent, &aPoint);
-        m_pDocument->pClass->setTextSelection(m_pDocument, LOK_SETTEXTSELECTION_RESET, pixelToTwip(aPoint.x), pixelToTwip(aPoint.y));
+        m_pDocument->pClass->setTextSelection(m_pDocument, LOK_SETTEXTSELECTION_RESET, pixelToTwip(aPoint.x, m_fZoom), pixelToTwip(aPoint.y, m_fZoom));
         return FALSE;
     }
     if (m_bInDragStartHandle)
     {
         g_info("lcl_signalMotion: dragging the start handle");
         LOKDocView_Impl::getDragPoint(&m_aHandleStartRect, pEvent, &aPoint);
-        m_pDocument->pClass->setTextSelection(m_pDocument, LOK_SETTEXTSELECTION_START, pixelToTwip(aPoint.x), pixelToTwip(aPoint.y));
+        m_pDocument->pClass->setTextSelection(m_pDocument, LOK_SETTEXTSELECTION_START, pixelToTwip(aPoint.x, m_fZoom), pixelToTwip(aPoint.y, m_fZoom));
         return FALSE;
     }
     if (m_bInDragEndHandle)
     {
         g_info("lcl_signalMotion: dragging the end handle");
         LOKDocView_Impl::getDragPoint(&m_aHandleEndRect, pEvent, &aPoint);
-        m_pDocument->pClass->setTextSelection(m_pDocument, LOK_SETTEXTSELECTION_END, pixelToTwip(aPoint.x), pixelToTwip(aPoint.y));
+        m_pDocument->pClass->setTextSelection(m_pDocument, LOK_SETTEXTSELECTION_END, pixelToTwip(aPoint.x, m_fZoom), pixelToTwip(aPoint.y, m_fZoom));
         return FALSE;
     }
     for (int i = 0; i < GRAPHIC_HANDLE_COUNT; ++i)
@@ -566,20 +547,20 @@ gboolean LOKDocView_Impl::signalMotionImpl(GdkEventButton* pEvent)
     }
 
     GdkRectangle aMotionInTwipsInTwips;
-    aMotionInTwipsInTwips.x = pixelToTwip(pEvent->x);
-    aMotionInTwipsInTwips.y = pixelToTwip(pEvent->y);
+    aMotionInTwipsInTwips.x = pixelToTwip(pEvent->x, m_fZoom);
+    aMotionInTwipsInTwips.y = pixelToTwip(pEvent->y, m_fZoom);
     aMotionInTwipsInTwips.width = 1;
     aMotionInTwipsInTwips.height = 1;
     if (gdk_rectangle_intersect(&aMotionInTwipsInTwips, &m_aGraphicSelection, 0))
     {
         g_info("lcl_signalMotion: start of drag graphic selection");
         m_bInDragGraphicSelection = true;
-        m_pDocument->pClass->setGraphicSelection(m_pDocument, LOK_SETGRAPHICSELECTION_START, pixelToTwip(pEvent->x), pixelToTwip(pEvent->y));
+        m_pDocument->pClass->setGraphicSelection(m_pDocument, LOK_SETGRAPHICSELECTION_START, pixelToTwip(pEvent->x, m_fZoom), pixelToTwip(pEvent->y, m_fZoom));
         return FALSE;
     }
 
     // Otherwise a mouse move, as on the desktop.
-    m_pDocument->pClass->postMouseEvent(m_pDocument, LOK_MOUSEEVENT_MOUSEMOVE, pixelToTwip(pEvent->x), pixelToTwip(pEvent->y), 1);
+    m_pDocument->pClass->postMouseEvent(m_pDocument, LOK_MOUSEEVENT_MOUSEMOVE, pixelToTwip(pEvent->x, m_fZoom), pixelToTwip(pEvent->y, m_fZoom), 1);
 
     return FALSE;
 }
@@ -602,10 +583,10 @@ gboolean LOKDocView_Impl::renderOverlayImpl(GtkWidget* pWidget)
 
         cairo_set_source_rgb(pCairo, 0, 0, 0);
         cairo_rectangle(pCairo,
-                        twipToPixel(m_aVisibleCursor.x),
-                        twipToPixel(m_aVisibleCursor.y),
-                        twipToPixel(m_aVisibleCursor.width),
-                        twipToPixel(m_aVisibleCursor.height));
+                        twipToPixel(m_aVisibleCursor.x, m_fZoom),
+                        twipToPixel(m_aVisibleCursor.y, m_fZoom),
+                        twipToPixel(m_aVisibleCursor.width, m_fZoom),
+                        twipToPixel(m_aVisibleCursor.height, m_fZoom));
         cairo_fill(pCairo);
     }
 
@@ -624,10 +605,10 @@ gboolean LOKDocView_Impl::renderOverlayImpl(GtkWidget* pWidget)
             // Blue with 75% transparency.
             cairo_set_source_rgba(pCairo, ((double)0x43)/255, ((double)0xac)/255, ((double)0xe8)/255, 0.25);
             cairo_rectangle(pCairo,
-                            twipToPixel(rRectangle.x),
-                            twipToPixel(rRectangle.y),
-                            twipToPixel(rRectangle.width),
-                            twipToPixel(rRectangle.height));
+                            twipToPixel(rRectangle.x, m_fZoom),
+                            twipToPixel(rRectangle.y, m_fZoom),
+                            twipToPixel(rRectangle.width, m_fZoom),
+                            twipToPixel(rRectangle.height, m_fZoom));
             cairo_fill(pCairo);
         }
 
@@ -674,10 +655,10 @@ void LOKDocView_Impl::renderHandle(cairo_t* pCairo, const GdkRectangle& rCursor,
     nHandleWidth = cairo_image_surface_get_width(pHandle);
     nHandleHeight = cairo_image_surface_get_height(pHandle);
     // We want to scale down the handle, so that its height is the same as the cursor caret.
-    fHandleScale = twipToPixel(rCursor.height) / nHandleHeight;
+    fHandleScale = twipToPixel(rCursor.height, m_fZoom) / nHandleHeight;
     // We want the top center of the handle bitmap to be at the bottom center of the cursor rectangle.
-    aCursorBottom.x = twipToPixel(rCursor.x) + twipToPixel(rCursor.width) / 2 - (nHandleWidth * fHandleScale) / 2;
-    aCursorBottom.y = twipToPixel(rCursor.y) + twipToPixel(rCursor.height);
+    aCursorBottom.x = twipToPixel(rCursor.x, m_fZoom) + twipToPixel(rCursor.width, m_fZoom) / 2 - (nHandleWidth * fHandleScale) / 2;
+    aCursorBottom.y = twipToPixel(rCursor.y, m_fZoom) + twipToPixel(rCursor.height, m_fZoom);
     cairo_save(pCairo);
     cairo_translate(pCairo, aCursorBottom.x, aCursorBottom.y);
     cairo_scale(pCairo, fHandleScale, fHandleScale);
@@ -700,10 +681,10 @@ void LOKDocView_Impl::renderGraphicHandle(cairo_t* pCairo, const GdkRectangle& r
     nHandleWidth = cairo_image_surface_get_width(pHandle);
     nHandleHeight = cairo_image_surface_get_height(pHandle);
 
-    aSelection.x = twipToPixel(rSelection.x);
-    aSelection.y = twipToPixel(rSelection.y);
-    aSelection.width = twipToPixel(rSelection.width);
-    aSelection.height = twipToPixel(rSelection.height);
+    aSelection.x = twipToPixel(rSelection.x, m_fZoom);
+    aSelection.y = twipToPixel(rSelection.y, m_fZoom);
+    aSelection.width = twipToPixel(rSelection.width, m_fZoom);
+    aSelection.height = twipToPixel(rSelection.height, m_fZoom);
 
     for (int i = 0; i < GRAPHIC_HANDLE_COUNT; ++i)
     {
@@ -781,8 +762,8 @@ void LOKDocView_Impl::renderDocument(GdkRectangle* pPartial)
     GdkRectangle visibleArea;
     lok_docview_get_visarea (m_pDocView, &visibleArea);
 
-    long nDocumentWidthPixels = twipToPixel(m_nDocumentWidthTwips);
-    long nDocumentHeightPixels = twipToPixel(m_nDocumentHeightTwips);
+    long nDocumentWidthPixels = twipToPixel(m_nDocumentWidthTwips, m_fZoom);
+    long nDocumentHeightPixels = twipToPixel(m_nDocumentHeightTwips, m_fZoom);
     // Total number of rows / columns in this document.
     guint nRows = ceil((double)nDocumentHeightPixels / nTileSizePixels);
     guint nColumns = ceil((double)nDocumentWidthPixels / nTileSizePixels);
@@ -809,10 +790,10 @@ void LOKDocView_Impl::renderDocument(GdkRectangle* pPartial)
                 aTileRectanglePixels.height = nTileSizePixels;
 
             // Determine size and position of the tile in document coordinates, so we can decide if we can skip painting for partial rendering.
-            aTileRectangleTwips.x = pixelToTwip(nTileSizePixels) * nColumn;
-            aTileRectangleTwips.y = pixelToTwip(nTileSizePixels) * nRow;
-            aTileRectangleTwips.width = pixelToTwip(aTileRectanglePixels.width);
-            aTileRectangleTwips.height = pixelToTwip(aTileRectanglePixels.height);
+            aTileRectangleTwips.x = pixelToTwip(nTileSizePixels, m_fZoom) * nColumn;
+            aTileRectangleTwips.y = pixelToTwip(nTileSizePixels, m_fZoom) * nRow;
+            aTileRectangleTwips.width = pixelToTwip(aTileRectanglePixels.width, m_fZoom);
+            aTileRectangleTwips.height = pixelToTwip(aTileRectanglePixels.height, m_fZoom);
             if (pPartial && !gdk_rectangle_intersect(pPartial, &aTileRectangleTwips, 0))
                 bPaint = false;
 
@@ -826,7 +807,7 @@ void LOKDocView_Impl::renderDocument(GdkRectangle* pPartial)
                 Tile& currentTile = m_pTileBuffer->tile_buffer_get_tile(nRow, nColumn);
                 GdkPixbuf* pPixBuf = currentTile.tile_get_buffer();
 
-                gdk_cairo_set_source_pixbuf (pcairo, pPixBuf, twipToPixel(aTileRectangleTwips.x), twipToPixel(aTileRectangleTwips.y));
+                gdk_cairo_set_source_pixbuf (pcairo, pPixBuf, twipToPixel(aTileRectangleTwips.x, m_fZoom), twipToPixel(aTileRectangleTwips.y, m_fZoom));
                 cairo_paint(pcairo);
             }
         }
@@ -935,10 +916,10 @@ gboolean LOKDocView_Impl::callbackImpl(CallbackData* pCallback)
         {
             GdkRectangle aRectangle = LOKDocView_Impl::payloadToRectangle(pCallback->m_aPayload.c_str());
             GdkRectangle aRectanglePixels;
-            aRectanglePixels.x = twipToPixel(aRectangle.x);
-            aRectanglePixels.y = twipToPixel(aRectangle.y);
-            aRectanglePixels.width = twipToPixel(aRectangle.width);
-            aRectanglePixels.height = twipToPixel(aRectangle.height);
+            aRectanglePixels.x = twipToPixel(aRectangle.x, m_fZoom);
+            aRectanglePixels.y = twipToPixel(aRectangle.y, m_fZoom);
+            aRectanglePixels.width = twipToPixel(aRectangle.width, m_fZoom);
+            aRectanglePixels.height = twipToPixel(aRectangle.height, m_fZoom);
             int rowStart = aRectanglePixels.y / nTileSizePixels;
             int colStart = aRectanglePixels.x / nTileSizePixels;
             int rowEnd = (aRectanglePixels.y + aRectanglePixels.height + nTileSizePixels) / nTileSizePixels;
@@ -963,10 +944,10 @@ gboolean LOKDocView_Impl::callbackImpl(CallbackData* pCallback)
         m_aVisibleCursor = LOKDocView_Impl::payloadToRectangle(pCallback->m_aPayload.c_str());
         m_bCursorOverlayVisible = true;
         GdkRectangle aRectanglePixels;
-        aRectanglePixels.x = twipToPixel(m_aVisibleCursor.x);
-        aRectanglePixels.y = twipToPixel(m_aVisibleCursor.y);
-        aRectanglePixels.width = twipToPixel(m_aVisibleCursor.width);
-        aRectanglePixels.height = twipToPixel(m_aVisibleCursor.height);
+        aRectanglePixels.x = twipToPixel(m_aVisibleCursor.x, m_fZoom);
+        aRectanglePixels.y = twipToPixel(m_aVisibleCursor.y, m_fZoom);
+        aRectanglePixels.width = twipToPixel(m_aVisibleCursor.width, m_fZoom);
+        aRectanglePixels.height = twipToPixel(m_aVisibleCursor.height, m_fZoom);
         int rowStart = aRectanglePixels.y / nTileSizePixels;
         int colStart = aRectanglePixels.x / nTileSizePixels;
         int rowEnd = (aRectanglePixels.y + aRectanglePixels.height + nTileSizePixels) / nTileSizePixels;
@@ -1246,10 +1227,11 @@ SAL_DLLPUBLIC_EXPORT gboolean lok_docview_open_document( LOKDocView* pDocView, c
         pDocView->m_pImpl->m_pDocument->pClass->getDocumentSize(pDocView->m_pImpl->m_pDocument, &pDocView->m_pImpl->m_nDocumentWidthTwips, &pDocView->m_pImpl->m_nDocumentHeightTwips);
         g_timeout_add(600, &LOKDocView_Impl::handleTimeout, pDocView);
 
+        float zoom = pDocView->m_pImpl->m_fZoom;
         long nDocumentWidthTwips = pDocView->m_pImpl->m_nDocumentWidthTwips;
         long nDocumentHeightTwips = pDocView->m_pImpl->m_nDocumentHeightTwips;
-        long nDocumentWidthPixels = pDocView->m_pImpl->twipToPixel(nDocumentWidthTwips);
-        long nDocumentHeightPixels = pDocView->m_pImpl->twipToPixel(nDocumentHeightTwips);
+        long nDocumentWidthPixels = twipToPixel(nDocumentWidthTwips, zoom);
+        long nDocumentHeightPixels = twipToPixel(nDocumentHeightTwips, zoom);
         // Total number of rows / columns in this document.
         guint nRows = ceil((double)nDocumentHeightPixels / nTileSizePixels);
         guint nColumns = ceil((double)nDocumentWidthPixels / nTileSizePixels);
@@ -1271,8 +1253,8 @@ SAL_DLLPUBLIC_EXPORT LibreOfficeKitDocument* lok_docview_get_document(LOKDocView
 SAL_DLLPUBLIC_EXPORT void lok_docview_set_zoom ( LOKDocView* pDocView, float fZoom )
 {
     pDocView->m_pImpl->m_fZoom = fZoom;
-    long nDocumentWidthPixels = pDocView->m_pImpl->twipToPixel(pDocView->m_pImpl->m_nDocumentWidthTwips);
-    long nDocumentHeightPixels = pDocView->m_pImpl->twipToPixel(pDocView->m_pImpl->m_nDocumentHeightTwips);
+    long nDocumentWidthPixels = twipToPixel(pDocView->m_pImpl->m_nDocumentWidthTwips, fZoom);
+    long nDocumentHeightPixels = twipToPixel(pDocView->m_pImpl->m_nDocumentHeightTwips, fZoom);
     // Total number of rows / columns in this document.
     guint nRows = ceil((double)nDocumentHeightPixels / nTileSizePixels);
     guint nColumns = ceil((double)nDocumentWidthPixels / nTileSizePixels);
@@ -1350,12 +1332,13 @@ SAL_DLLPUBLIC_EXPORT void lok_docview_post_key(GtkWidget* /*pWidget*/, GdkEventK
 
 SAL_DLLPUBLIC_EXPORT void lok_docview_get_visarea(LOKDocView* pThis, GdkRectangle* pArea)
 {
+    float zoom = pThis->m_pImpl->m_fZoom;
     GtkAdjustment* pHAdjustment = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(pThis));
-    pArea->x = pThis->m_pImpl->pixelToTwip(gtk_adjustment_get_value(pHAdjustment));
-    pArea->width = pThis->m_pImpl->pixelToTwip(gtk_adjustment_get_page_size(pHAdjustment));
+    pArea->x = pixelToTwip(gtk_adjustment_get_value(pHAdjustment),zoom);
+    pArea->width = pixelToTwip(gtk_adjustment_get_page_size(pHAdjustment), zoom);
     GtkAdjustment* pVAdjustment = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(pThis));
-    pArea->y = pThis->m_pImpl->pixelToTwip(gtk_adjustment_get_value(pVAdjustment));
-    pArea->height = pThis->m_pImpl->pixelToTwip(gtk_adjustment_get_page_size(pVAdjustment));
+    pArea->y = pixelToTwip(gtk_adjustment_get_value(pVAdjustment), zoom);
+    pArea->height = pixelToTwip(gtk_adjustment_get_page_size(pVAdjustment), zoom);
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/libreofficekit/source/gtk/tilebuffer.cxx b/libreofficekit/source/gtk/tilebuffer.cxx
index e13f5b0..3e5e01f 100644
--- a/libreofficekit/source/gtk/tilebuffer.cxx
+++ b/libreofficekit/source/gtk/tilebuffer.cxx
@@ -9,14 +9,12 @@
 
 #include "tilebuffer.hxx"
 
-static const int DPI = 96;
-
-static float pixelToTwip(float fInput, float zoom)
+float pixelToTwip(float fInput, float zoom)
 {
     return (fInput / DPI / zoom) * 1440.0f;
 }
 
-static float twipToPixel(float fInput, float zoom)
+float twipToPixel(float fInput, float zoom)
 {
     return fInput / 1440.0f * DPI * zoom;
 }
diff --git a/libreofficekit/source/gtk/tilebuffer.hxx b/libreofficekit/source/gtk/tilebuffer.hxx
index 088df93..15b276f 100644
--- a/libreofficekit/source/gtk/tilebuffer.hxx
+++ b/libreofficekit/source/gtk/tilebuffer.hxx
@@ -19,6 +19,15 @@
 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
 #include <LibreOfficeKit/LibreOfficeKitGtk.h>
 
+// We know that VirtualDevices use a DPI of 96.
+const int DPI = 96;
+// Lets use a square of side 256 pixels for each tile.
+const int nTileSizePixels = 256;
+
+float pixelToTwip(float fInput, float zoom);
+
+float twipToPixel(float fInput, float zoom);
+
 /*
   This class represents a single tile in the tile buffer.
   TODO: Extend it to support features like double buffering
commit 4d6c2b7197502da85bd7cbfce57d62c412f8ebd4
Author: Pranav Kant <pranavk at gnome.org>
Date:   Thu Jun 4 03:32:18 2015 +0530

    lokdocview: Add support for editing documents
    
    Change-Id: I8637d99e6fa59129af207e667bcdf03dc212efeb

diff --git a/libreofficekit/source/gtk/lokdocview.cxx b/libreofficekit/source/gtk/lokdocview.cxx
index f476a23..d3f0820 100644
--- a/libreofficekit/source/gtk/lokdocview.cxx
+++ b/libreofficekit/source/gtk/lokdocview.cxx
@@ -821,7 +821,7 @@ void LOKDocView_Impl::renderDocument(GdkRectangle* pPartial)
 
             if (bPaint)
             {
-                g_info("gettile: (%d %d)", nRow, nColumn);
+                //                g_info("gettile: (%d %d)", nRow, nColumn);
 
                 Tile& currentTile = m_pTileBuffer->tile_buffer_get_tile(nRow, nColumn);
                 GdkPixbuf* pPixBuf = currentTile.tile_get_buffer();
@@ -934,17 +934,50 @@ gboolean LOKDocView_Impl::callbackImpl(CallbackData* pCallback)
         if (pCallback->m_aPayload != "EMPTY")
         {
             GdkRectangle aRectangle = LOKDocView_Impl::payloadToRectangle(pCallback->m_aPayload.c_str());
-            renderDocument(&aRectangle);
+            GdkRectangle aRectanglePixels;
+            aRectanglePixels.x = twipToPixel(aRectangle.x);
+            aRectanglePixels.y = twipToPixel(aRectangle.y);
+            aRectanglePixels.width = twipToPixel(aRectangle.width);
+            aRectanglePixels.height = twipToPixel(aRectangle.height);
+            int rowStart = aRectanglePixels.y / nTileSizePixels;
+            int colStart = aRectanglePixels.x / nTileSizePixels;
+            int rowEnd = (aRectanglePixels.y + aRectanglePixels.height + nTileSizePixels) / nTileSizePixels;
+            int colEnd = (aRectanglePixels.x + aRectanglePixels.width + nTileSizePixels) / nTileSizePixels;
+            int i,j;
+            for (i = rowStart; i < rowEnd; i++) {
+                for (j = colStart; j < colEnd; j++) {
+                    m_pTileBuffer->tile_buffer_set_invalid(i, j);
+                }
+            }
+            renderDocument(0);
         }
         else
+        {
+            m_pTileBuffer->tile_buffer_reset_all_tiles();
             renderDocument(0);
+        }
     }
     break;
     case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR:
     {
         m_aVisibleCursor = LOKDocView_Impl::payloadToRectangle(pCallback->m_aPayload.c_str());
         m_bCursorOverlayVisible = true;
-        gtk_widget_queue_draw(GTK_WIDGET(m_pDrawingArea));
+        GdkRectangle aRectanglePixels;
+        aRectanglePixels.x = twipToPixel(m_aVisibleCursor.x);
+        aRectanglePixels.y = twipToPixel(m_aVisibleCursor.y);
+        aRectanglePixels.width = twipToPixel(m_aVisibleCursor.width);
+        aRectanglePixels.height = twipToPixel(m_aVisibleCursor.height);
+        int rowStart = aRectanglePixels.y / nTileSizePixels;
+        int colStart = aRectanglePixels.x / nTileSizePixels;
+        int rowEnd = (aRectanglePixels.y + aRectanglePixels.height + nTileSizePixels) / nTileSizePixels;
+        int colEnd = (aRectanglePixels.x + aRectanglePixels.width + nTileSizePixels) / nTileSizePixels;
+        int i,j;
+        for (i = rowStart; i < rowEnd; i++) {
+            for (j = colStart; j < colEnd; j++) {
+                m_pTileBuffer->tile_buffer_set_invalid(i, j);
+            }
+        }
+        renderDocument(0);
     }
     break;
     case LOK_CALLBACK_TEXT_SELECTION:
@@ -961,7 +994,6 @@ gboolean LOKDocView_Impl::callbackImpl(CallbackData* pCallback)
         }
         else
             memset(&m_aHandleMiddleRect, 0, sizeof(m_aHandleMiddleRect));
-        gtk_widget_queue_draw(GTK_WIDGET(m_pDrawingArea));
     }
     break;
     case LOK_CALLBACK_TEXT_SELECTION_START:
@@ -1144,6 +1176,16 @@ static void lok_docview_init( GTypeInstance* pInstance, gpointer )
     g_signal_connect(GTK_OBJECT(pDocView->m_pImpl->m_pDrawingArea),
                      "expose-event",
                      GTK_SIGNAL_FUNC(LOKDocView_Impl::on_exposed), pDocView);
+    g_signal_connect(GTK_OBJECT(pDocView->m_pImpl->m_pDrawingArea),
+                     "expose-event",
+                     GTK_SIGNAL_FUNC(LOKDocView_Impl::renderOverlay), pDocView);
+    gtk_widget_add_events(pDocView->m_pImpl->m_pDrawingArea,
+                          GDK_BUTTON_PRESS_MASK
+                          | GDK_BUTTON_RELEASE_MASK
+                          | GDK_BUTTON_MOTION_MASK);
+    g_signal_connect(G_OBJECT(pDocView->m_pImpl->m_pDrawingArea), "button-press-event", G_CALLBACK(LOKDocView_Impl::signalButton), pDocView);
+    g_signal_connect(G_OBJECT(pDocView->m_pImpl->m_pDrawingArea), "button-release-event", G_CALLBACK(LOKDocView_Impl::signalButton), pDocView);
+    g_signal_connect(G_OBJECT(pDocView->m_pImpl->m_pDrawingArea), "motion-notify-event", G_CALLBACK(LOKDocView_Impl::signalMotion), pDocView);
 
     gtk_signal_connect(GTK_OBJECT(pDocView), "destroy", GTK_SIGNAL_FUNC(LOKDocView_Impl::destroy), 0);
 }
diff --git a/libreofficekit/source/gtk/tilebuffer.cxx b/libreofficekit/source/gtk/tilebuffer.cxx
index e1b5b32..e13f5b0 100644
--- a/libreofficekit/source/gtk/tilebuffer.cxx
+++ b/libreofficekit/source/gtk/tilebuffer.cxx
@@ -23,69 +23,82 @@ static float twipToPixel(float fInput, float zoom)
 
 GdkPixbuf* Tile::tile_get_buffer()
 {
-  return m_pBuffer;
+    return m_pBuffer;
 }
 
 void Tile::tile_release()
 {
-  gdk_pixbuf_unref(m_pBuffer);
-  m_pBuffer = NULL;
+    g_object_unref (m_pBuffer);
+    m_pBuffer = NULL;
 }
 
 void TileBuffer::tile_buffer_set_zoom(float newZoomFactor, int rows, int columns)
 {
-  m_fZoomFactor = newZoomFactor;
+    m_fZoomFactor = newZoomFactor;
 
-  tile_buffer_reset_all_tiles();
+    tile_buffer_reset_all_tiles();
 
-  // set new buffer width and height
-  m_nWidth = columns;
-  m_nHeight = rows;
+    // set new buffer width and height
+    m_nWidth = columns;
+    m_nHeight = rows;
 }
 
 void TileBuffer::tile_buffer_reset_all_tiles()
 {
-  std::map<int, Tile>::iterator it = m_mTiles.begin();
-  for (; it != m_mTiles.end(); it++)
-    {
-       it->second.tile_release();
-    }
-  m_mTiles.clear();
+    std::map<int, Tile>::iterator it = m_mTiles.begin();
+    for (; it != m_mTiles.end(); it++)
+        {
+            it->second.tile_release();
+        }
+    m_mTiles.clear();
+}
+
+void TileBuffer::tile_buffer_set_invalid(int x, int y)
+{
+    int index = x * m_nWidth + y;
+    g_info("setting invalid : %d %d",x, y);
+    if (m_mTiles.find(index) != m_mTiles.end())
+        {
+            m_mTiles[index].valid = 0;
+            m_mTiles[index].tile_release();
+            m_mTiles.erase(index);
+        }
 }
 
 Tile& TileBuffer::tile_buffer_get_tile(int x, int y)
 {
-  int index = x * m_nWidth + y;
-  if(m_mTiles.find(index) == m_mTiles.end())
-    {
-      GdkPixbuf* pPixBuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, m_nTileSize, m_nTileSize);
-      if (!pPixBuf){
-        g_info ("error allocating memory to pixbuf");
-      }
-      unsigned char* pBuffer = gdk_pixbuf_get_pixels(pPixBuf);
-      GdkRectangle aTileRectangle;
-      aTileRectangle.x = pixelToTwip(m_nTileSize, m_fZoomFactor) * y;
-      aTileRectangle.y = pixelToTwip(m_nTileSize, m_fZoomFactor) * x;
-
-      g_info ("rendering (%d %d)", x, y);
-      m_pLOKDocument->pClass->paintTile(m_pLOKDocument,
-                                        // Buffer and its size, depends on the position only.
-                                        pBuffer,
-                                        m_nTileSize, m_nTileSize,
-                                        // Position of the tile.
-                                        aTileRectangle.x, aTileRectangle.y,
-                                        // Size of the tile, depends on the zoom factor and the tile position only.
-                                        pixelToTwip(m_nTileSize, m_fZoomFactor), pixelToTwip(m_nTileSize, m_fZoomFactor));
-
-      //create a mapping for it
-      m_mTiles[index].tile_set_pixbuf(pPixBuf);
-      m_mTiles[index].valid = 1;
-    }
-
-  return m_mTiles[index];
+    int index = x * m_nWidth + y;
+    if(m_mTiles.find(index) == m_mTiles.end() || !m_mTiles[index].valid)
+        {
+
+            GdkPixbuf* pPixBuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, m_nTileSize, m_nTileSize);
+            if (!pPixBuf){
+                g_info ("error allocating memory to pixbuf");
+            }
+            unsigned char* pBuffer = gdk_pixbuf_get_pixels(pPixBuf);
+            GdkRectangle aTileRectangle;
+            aTileRectangle.x = pixelToTwip(m_nTileSize, m_fZoomFactor) * y;
+            aTileRectangle.y = pixelToTwip(m_nTileSize, m_fZoomFactor) * x;
+
+            g_info ("rendering (%d %d)", x, y);
+            m_pLOKDocument->pClass->paintTile(m_pLOKDocument,
+                                              // Buffer and its size, depends on the position only.
+                                              pBuffer,
+                                              m_nTileSize, m_nTileSize,
+                                              // Position of the tile.
+                                              aTileRectangle.x, aTileRectangle.y,
+                                              // Size of the tile, depends on the zoom factor and the tile position only.
+                                              pixelToTwip(m_nTileSize, m_fZoomFactor), pixelToTwip(m_nTileSize, m_fZoomFactor));
+
+            //create a mapping for it
+            m_mTiles[index].tile_set_pixbuf(pPixBuf);
+            m_mTiles[index].valid = 1;
+        }
+
+    return m_mTiles[index];
 }
 
 void Tile::tile_set_pixbuf(GdkPixbuf *buffer)
 {
-  m_pBuffer = buffer;
+    m_pBuffer = buffer;
 }
diff --git a/libreofficekit/source/gtk/tilebuffer.hxx b/libreofficekit/source/gtk/tilebuffer.hxx
index 0bc2d38..088df93 100644
--- a/libreofficekit/source/gtk/tilebuffer.hxx
+++ b/libreofficekit/source/gtk/tilebuffer.hxx
@@ -25,18 +25,17 @@
 */
 class Tile
 {
-public:
-  Tile() : valid(0) {}
-  ~Tile() {
-    tile_release();
-  }
+ public:
+ Tile() : valid(0) {}
+    ~Tile() {
+    }
 
-  GdkPixbuf* tile_get_buffer();
-  void tile_release();
-  void tile_set_pixbuf(GdkPixbuf*);
-  bool valid;
-private:
-  GdkPixbuf *m_pBuffer;
+    GdkPixbuf* tile_get_buffer();
+    void tile_release();
+    void tile_set_pixbuf(GdkPixbuf*);
+    bool valid;
+ private:
+    GdkPixbuf *m_pBuffer;
 };
 
 /*
@@ -45,32 +44,33 @@ private:
 */
 class TileBuffer
 {
-public:
-  TileBuffer(LibreOfficeKitDocument *document,
-             int tileSize,
-             int rows,
-             int columns)
-    : m_pLOKDocument(document)
-    , m_nTileSize(tileSize)
-    , m_fZoomFactor(1)
-    , m_nWidth(columns)
-    , m_nHeight(rows)
+ public:
+ TileBuffer(LibreOfficeKitDocument *document,
+            int tileSize,
+            int rows,
+            int columns)
+     : m_pLOKDocument(document)
+        , m_nTileSize(tileSize)
+        , m_fZoomFactor(1)
+        , m_nWidth(columns)
+        , m_nHeight(rows)
     {  }
 
-  ~TileBuffer() {}
+    ~TileBuffer() {}
 
-  void tile_buffer_set_zoom(float zoomFactor, int rows, int columns);
-  Tile& tile_buffer_get_tile(int x, int y);
-  void tile_buffer_update();
-  void tile_buffer_reset_all_tiles();
-private:
-  LibreOfficeKitDocument *m_pLOKDocument;
-  int m_nTileSize;
-  float m_fZoomFactor;
-  std::map<int, Tile> m_mTiles;
-  //TODO: Also set width and height when document size changes
-  int m_nWidth;
-  int m_nHeight;
+    void tile_buffer_set_zoom(float zoomFactor, int rows, int columns);
+    Tile& tile_buffer_get_tile(int x, int y);
+    void tile_buffer_update();
+    void tile_buffer_reset_all_tiles();
+    void tile_buffer_set_invalid(int x, int y);
+ private:
+    LibreOfficeKitDocument *m_pLOKDocument;
+    int m_nTileSize;
+    float m_fZoomFactor;
+    std::map<int, Tile> m_mTiles;
+    //TODO: Also set width and height when document size changes
+    int m_nWidth;
+    int m_nHeight;
 };
 
 #endif // INCLUDED_TILEBUFFER_HXX
commit 5415bd512768de45df93e292b33beeedf128388b
Author: Pranav Kant <pranavk at gnome.org>
Date:   Thu Jun 4 01:44:47 2015 +0530

    lokdocview: Use maps instead of vector
    
    Using vector each tile needs to be allocated memory irrespective of
    whether tile is required or not. This approach fails when we zoom in to
    a very high level to have thousands of tiles due to lot of memory
    required. Using maps instead of vector takes care of this, and only
    allocates Tiles when required.
    
    Change-Id: I523f815618451a7f014e28258e0de7b1c0693370

diff --git a/libreofficekit/source/gtk/tilebuffer.cxx b/libreofficekit/source/gtk/tilebuffer.cxx
index ca66ae90..e1b5b32 100644
--- a/libreofficekit/source/gtk/tilebuffer.cxx
+++ b/libreofficekit/source/gtk/tilebuffer.cxx
@@ -41,22 +41,22 @@ void TileBuffer::tile_buffer_set_zoom(float newZoomFactor, int rows, int columns
   // set new buffer width and height
   m_nWidth = columns;
   m_nHeight = rows;
-  m_aTiles.resize(m_nWidth * m_nHeight);
 }
 
 void TileBuffer::tile_buffer_reset_all_tiles()
 {
-  for (size_t i = 0; i < m_aTiles.size(); i++)
+  std::map<int, Tile>::iterator it = m_mTiles.begin();
+  for (; it != m_mTiles.end(); it++)
     {
-      m_aTiles[i].tile_release();
+       it->second.tile_release();
     }
-  m_aTiles.clear();
+  m_mTiles.clear();
 }
 
 Tile& TileBuffer::tile_buffer_get_tile(int x, int y)
 {
   int index = x * m_nWidth + y;
-  if(!m_aTiles[index].valid)
+  if(m_mTiles.find(index) == m_mTiles.end())
     {
       GdkPixbuf* pPixBuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, m_nTileSize, m_nTileSize);
       if (!pPixBuf){
@@ -77,11 +77,12 @@ Tile& TileBuffer::tile_buffer_get_tile(int x, int y)
                                         // Size of the tile, depends on the zoom factor and the tile position only.
                                         pixelToTwip(m_nTileSize, m_fZoomFactor), pixelToTwip(m_nTileSize, m_fZoomFactor));
 
-      m_aTiles[index].tile_set_pixbuf(pPixBuf);
-      m_aTiles[index].valid = 1;
+      //create a mapping for it
+      m_mTiles[index].tile_set_pixbuf(pPixBuf);
+      m_mTiles[index].valid = 1;
     }
 
-  return m_aTiles[index];
+  return m_mTiles[index];
 }
 
 void Tile::tile_set_pixbuf(GdkPixbuf *buffer)
diff --git a/libreofficekit/source/gtk/tilebuffer.hxx b/libreofficekit/source/gtk/tilebuffer.hxx
index a5ed0dc..0bc2d38 100644
--- a/libreofficekit/source/gtk/tilebuffer.hxx
+++ b/libreofficekit/source/gtk/tilebuffer.hxx
@@ -12,7 +12,7 @@
 
 #include <gdk/gdkkeysyms.h>
 #include <gdk-pixbuf/gdk-pixbuf.h>
-#include <vector>
+#include <map>
 
 #define LOK_USE_UNSTABLE_API
 #include <LibreOfficeKit/LibreOfficeKit.h>
@@ -55,9 +55,7 @@ public:
     , m_fZoomFactor(1)
     , m_nWidth(columns)
     , m_nHeight(rows)
-  {
-    m_aTiles.resize(rows * columns);
-  }
+    {  }
 
   ~TileBuffer() {}
 
@@ -69,7 +67,7 @@ private:
   LibreOfficeKitDocument *m_pLOKDocument;
   int m_nTileSize;
   float m_fZoomFactor;
-  std::vector<Tile> m_aTiles;
+  std::map<int, Tile> m_mTiles;
   //TODO: Also set width and height when document size changes
   int m_nWidth;
   int m_nHeight;
commit fef9bc9c0b172f9b4393b59686515deaf2f47ad2
Author: Pranav Kant <pranavk at gnome.org>
Date:   Thu Jun 4 00:06:46 2015 +0530

    Add tile buffering support
    
    The TileBuffer class now manages all the tiles. The tile rendering calls
    to LO core is also managed by this class.
    
    Change-Id: Ic667a93dcf1c097e0601c0496e8a083c4742e8cb

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

    lokdocview: use GtkDrawingArea for drawing tiles
    
    Change-Id: I1a3d8a9229f416418f0f3e9c720b78af09b35978

diff --git a/libreofficekit/source/gtk/lokdocview.cxx b/libreofficekit/source/gtk/lokdocview.cxx
index a766b8a..676952c 100644
--- a/libreofficekit/source/gtk/lokdocview.cxx
+++ b/libreofficekit/source/gtk/lokdocview.cxx
@@ -65,6 +65,9 @@ struct LOKDocView_Impl
     GtkWidget* m_pEventBox;
     GtkWidget* m_pTable;
     GtkWidget** m_pCanvas;
+    GtkWidget *darea;
+
+    TileBuffer *mTileBuffer;
 
     float m_fZoom;
 
@@ -140,6 +143,8 @@ struct LOKDocView_Impl
     ~LOKDocView_Impl();
     /// Connected to the destroy signal of LOKDocView, deletes its LOKDocView_Impl.
     static void destroy(LOKDocView* pDocView, gpointer pData);
+    /// Connected to the expose-event of the GtkDrawingArea
+    static void on_exposed(GtkWidget *widget, GdkEvent *event, gpointer user_data);
     /// Converts from screen pixels to document coordinates.
     float pixelToTwip(float fInput);
     /// Converts from document coordinates to screen pixels.
@@ -258,6 +263,7 @@ LOKDocView_Impl::CallbackData::CallbackData(int nType, const std::string& rPaylo
 LOKDocView_Impl::LOKDocView_Impl(LOKDocView* pDocView)
     : m_pDocView(pDocView),
     m_pEventBox(gtk_event_box_new()),
+    darea(gtk_drawing_area_new()),
     m_pTable(0),
     m_pCanvas(0),
     m_fZoom(1),
@@ -307,6 +313,12 @@ void LOKDocView_Impl::destroy(LOKDocView* pDocView, gpointer /*pData*/)
     delete pDocView->m_pImpl;
 }
 
+void LOKDocView_Impl::on_exposed(GtkWidget *widget, GdkEvent *event, gpointer userdata)
+{
+    LOKDocView *pDocView = LOK_DOCVIEW (userdata);
+    pDocView->m_pImpl->renderDocument(0);
+}
+
 float LOKDocView_Impl::pixelToTwip(float fInput)
 {
     return (fInput / DPI / m_fZoom) * 1440.0f;
@@ -771,40 +783,17 @@ void LOKDocView_Impl::renderDocument(GdkRectangle* pPartial)
 {
     const int nTileSizePixels = 256;
 
+    GdkRectangle visibleArea;
+    lok_docview_get_visarea (m_pDocView, &visibleArea);
+
     long nDocumentWidthPixels = twipToPixel(m_nDocumentWidthTwips);
     long nDocumentHeightPixels = twipToPixel(m_nDocumentHeightTwips);
     // Total number of rows / columns in this document.
     guint nRows = ceil((double)nDocumentHeightPixels / nTileSizePixels);
     guint nColumns = ceil((double)nDocumentWidthPixels / nTileSizePixels);
 
-    // Set up our table and the tile pointers.
-    if (!m_pTable)
-        pPartial = 0;
-    if (pPartial)
-    {
-        // Same as nRows / nColumns, but from the previous renderDocument() call.
-        guint nOldRows, nOldColumns;
-
-#if GTK_CHECK_VERSION(2,22,0)
-        gtk_table_get_size(GTK_TABLE(m_pTable), &nOldRows, &nOldColumns);
-        if (nOldRows != nRows || nOldColumns != nColumns)
-            // Can't do partial rendering, document size changed.
-            pPartial = 0;
-#else
-        pPartial = 0;
-#endif
-    }
-    if (!pPartial)
-    {
-        if (m_pTable)
-            gtk_container_remove(GTK_CONTAINER(m_pEventBox), m_pTable);
-        m_pTable = gtk_table_new(nRows, nColumns, FALSE);
-        gtk_container_add(GTK_CONTAINER(m_pEventBox), m_pTable);
-        gtk_widget_show(m_pTable);
-        if (m_pCanvas)
-            g_free(m_pCanvas);
-        m_pCanvas = static_cast<GtkWidget**>(g_malloc0(sizeof(GtkWidget*) * nRows * nColumns));
-    }
+    gtk_widget_set_size_request(darea, nDocumentWidthPixels, nDocumentHeightPixels);
+    cairo_t *pcairo = gdk_cairo_create(darea->window);
 
     // Render the tiles.
     for (guint nRow = 0; nRow < nRows; ++nRow)
@@ -830,7 +819,10 @@ void LOKDocView_Impl::renderDocument(GdkRectangle* pPartial)
             aTileRectangleTwips.width = pixelToTwip(aTileRectanglePixels.width);
             aTileRectangleTwips.height = pixelToTwip(aTileRectanglePixels.height);
             if (pPartial && !gdk_rectangle_intersect(pPartial, &aTileRectangleTwips, 0))
-                    bPaint = false;
+                bPaint = false;
+
+            if (!gdk_rectangle_intersect(&visibleArea, &aTileRectangleTwips, 0))
+                bPaint = false;
 
             if (bPaint)
             {
@@ -849,21 +841,16 @@ void LOKDocView_Impl::renderDocument(GdkRectangle* pPartial)
                                                // Size of the tile, depends on the zoom factor and the tile position only.
                                                aTileRectangleTwips.width, aTileRectangleTwips.height);
 
-                if (m_pCanvas[nTile])
-                    gtk_widget_destroy(GTK_WIDGET(m_pCanvas[nTile]));
-                m_pCanvas[nTile] = gtk_image_new();
-                gtk_image_set_from_pixbuf(GTK_IMAGE(m_pCanvas[nTile]), pPixBuf);
-                g_object_unref(G_OBJECT(pPixBuf));
-                gtk_widget_show(m_pCanvas[nTile]);
-                gtk_table_attach(GTK_TABLE(m_pTable),
-                                 m_pCanvas[nTile],
-                                 nColumn, nColumn + 1, nRow, nRow + 1,
-                                 GTK_SHRINK, GTK_SHRINK, 0, 0);
+                gdk_cairo_set_source_pixbuf (pcairo, pPixBuf, twipToPixel(aTileRectangleTwips.x), twipToPixel(aTileRectangleTwips.y));
+                cairo_paint(pcairo);
             }
         }
     }
+
+    cairo_destroy(pcairo);
 }
 
+
 GdkRectangle LOKDocView_Impl::payloadToRectangle(const char* pPayload)
 {
     GdkRectangle aRet;
@@ -1167,17 +1154,13 @@ static void lok_docview_init( GTypeInstance* pInstance, gpointer )
 
     pDocView->m_pImpl = new LOKDocView_Impl(pDocView);
     gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW(pDocView),
-                                           pDocView->m_pImpl->m_pEventBox );
-
-    gtk_widget_set_events(pDocView->m_pImpl->m_pEventBox, GDK_BUTTON_PRESS_MASK); // So that drag doesn't try to move the whole window.
-    gtk_signal_connect(GTK_OBJECT(pDocView->m_pImpl->m_pEventBox), "button-press-event", GTK_SIGNAL_FUNC(LOKDocView_Impl::signalButton), pDocView);
-    gtk_signal_connect(GTK_OBJECT(pDocView->m_pImpl->m_pEventBox), "button-release-event", GTK_SIGNAL_FUNC(LOKDocView_Impl::signalButton), pDocView);
-    gtk_signal_connect(GTK_OBJECT(pDocView->m_pImpl->m_pEventBox), "motion-notify-event", GTK_SIGNAL_FUNC(LOKDocView_Impl::signalMotion), pDocView);
+                                           pDocView->m_pImpl->darea );
 
-    gtk_widget_show( pDocView->m_pImpl->m_pEventBox );
+    g_signal_connect(GTK_OBJECT(pDocView->m_pImpl->darea),
+                     "expose-event",
+                     GTK_SIGNAL_FUNC(LOKDocView_Impl::on_exposed), pDocView);
 
     gtk_signal_connect(GTK_OBJECT(pDocView), "destroy", GTK_SIGNAL_FUNC(LOKDocView_Impl::destroy), 0);
-    g_signal_connect_after(pDocView->m_pImpl->m_pEventBox, "expose-event", G_CALLBACK(LOKDocView_Impl::renderOverlay), pDocView);
 }
 
 SAL_DLLPUBLIC_EXPORT guint lok_docview_get_type()
commit 9fc51dc5f5f4e108a21127abf5e03fc01bb6ddc0
Author: Pranav Kant <pranavk at gnome.org>
Date:   Tue Jun 2 18:26:12 2015 +0530

    lokdocview: add width and height to the visible rectangle
    
    Change-Id: I64212113750893f33f8a859ba52ecd8815a820f4

diff --git a/libreofficekit/source/gtk/lokdocview.cxx b/libreofficekit/source/gtk/lokdocview.cxx
index 064e534..a766b8a 100644
--- a/libreofficekit/source/gtk/lokdocview.cxx
+++ b/libreofficekit/source/gtk/lokdocview.cxx
@@ -1323,8 +1323,10 @@ SAL_DLLPUBLIC_EXPORT void lok_docview_get_visarea(LOKDocView* pThis, GdkRectangl
 {
     GtkAdjustment* pHAdjustment = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(pThis));
     pArea->x = pThis->m_pImpl->pixelToTwip(gtk_adjustment_get_value(pHAdjustment));
+    pArea->width = pThis->m_pImpl->pixelToTwip(gtk_adjustment_get_page_size(pHAdjustment));
     GtkAdjustment* pVAdjustment = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(pThis));
     pArea->y = pThis->m_pImpl->pixelToTwip(gtk_adjustment_get_value(pVAdjustment));
+    pArea->height = pThis->m_pImpl->pixelToTwip(gtk_adjustment_get_page_size(pVAdjustment));
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */


More information about the Libreoffice-commits mailing list