Rebased ref, commits from common ancestor: commit 9e5b792642fe39b9558c26f9d76b8ed9b6752942 Author: Pranav Kant <pran...@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 <pran...@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 <pran...@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 <pran...@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 <pran...@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 <pran...@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 <pran...@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 <pran...@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: */ _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits