Bookshelf view and Tiling Support for Evince

Link to Proposal : Add Bookshelf View & Tiling support to Evince
Blog : GSoC 2013 - A random desi coder's (ir)regular ramblings
Repository : Gitorious repo for GSoC 2013 work on Evince
Mentor : José Aliste
Me : Aakash Goenka

Project Update: 21st September, 2013

Description of Tiled Rendering

The most current implementation of tiled rendering can be found in the 'tiling_clean' branch on my GSoC Gitorious repo. Patches can also be applied from Bug 708082 which I have opened mainly to help in reviewing and integrating the code.

Before I go onto describe how tiling has been implemented, lets keep in mind why we want it:

  • Bug 303365 - increase zooming level

  • When we zoom in, a page may become very big, while only a small portion of the page is in the view port.
  • Memory, however, is consumed for the entire page, because Evince renders the whole page.
  • This limits the maximum zoom level as we have to stop zooming in more once the memory occupied reaches a limit.
  • Tiled rendering will help because it will allow us to only render portions of page that are visible.
  • Zoom level will not be limited because memory will only be used for the visible tiles.

Now, some constraints which we have due to the way Poppler works:

  • Poppler rendering time & memory - Here, we can see that single page rendering time != total rendering of time of its tiles .

  • So, we need to try and have as few tiles as possible in the view port.
  • This calls for tile areas to be at least as big as the view port, or for simplicity, the screen size.

A page is divided into tiles only if its area goes beyond a certain threshold (MAX_TILE_SIZE).

https://dl.dropboxusercontent.com/u/14970473/illustration1.gif

As you can see in the above illustration, we keep increasing the tile_level in powers of 2 till the individual tiles' area become less than MAX_TILE_SIZE. Now, note that to identify a particular tile, we just need its top left coordinates (in terms of the tile number), page number and tile_level.

As an example, lets take the following situation.

https://dl.dropboxusercontent.com/u/14970473/illustration4.png

Here, 6 particular tiles are in the view port. Now, to describe the visible tiles of a page, we use a EvPageVisibleTiles structure, which is explained in the above illustration. As we can see, the EvPageVisibleTiles structure is a really efficient way to denote which tiles of the page are visible. It is of constant size, regardless of how many tiles of the page are visible.

Now, let's go module-by-module, to see what modifications have been made, to do the rendering of tiles as described above.

libdocument
  • Attributes x, y and tile_level have been included in EvRenderContext so that it can be indicated which tile is to be rendered. See commit.

libpdf
  • Modified pdf_page_render () to utilize tiling information from the EvRenderContext. See this.

  • pdf_selection_render_selection () has also been updated to render tiles. See commit.

libview: ev-jobs
  • The EvJob - EvJobRender has been modified to support rendering of tiles by setting tiling information in the EvRenderContext. See commit.

libview: ev-view
  • Implemented methods to calculate the appropriate tile level for a page, for a given scale and rotation and another to calculate which tiles of a page are presently in view. See commit.

  • These are used to identify all the tiles that are presently visible, by view_get_visible_page_tiles_array () - commit.

  • Finally, altered draw_one_page () to actually draw the visible portion of the page using surfaces for the individual tiles, rather than pages. Here is the new code.

libview: ev-pixbuf-cache

Since the work here was very complex, I broke it up into steps, and proceeded the following way-

  • Modified to use a GHashTable rather than a list. See commit. As a first step, the key is simply the page number.

  • Then, as a second step, I updated the key to be a bit more complex using the following JobInfoKey structure -

    • typedef struct _JobInfoKey { 

      •         gint page; 
                guint x, y; 
                guint tile_level;
                } JobInfoKey; 

    x and y are the coordinates of the tile as explained in the above illustration. See commit. This allows easy fetching of specific tiles.

  • Modified ev_pixbuf_cache_update_range() to use the EvPixbufPageTiles array being generated by view_get_visible_page_tiles_array (). See commit.

  • With the basic support for tiling in place, modified EvPixbufCache to use some of the tiled rendering functions. See commit.

  • Finally, updated ev_pixbuf_cache_update_range () to add tiled rendering jobs. See commit. With this in place, the EvView can make requests for tiles.

  • Made changes to ev_pixbuf_cache_get_selection_region () to work correctly while rendering tiles. This is the commit.

  • Updated ev_pixbuf_cache_reload_page() for tiling. See code.


To conclude, let's see what remains, before the work is good enough for release-
1. Managing of the tile cache, ie., preloading of tiles, and clearing old ones - Some progress has been made in this, in the "tiling_clean_experimental" branch of my Gitorious repo. However, it isn't fully functional yet.
2. Have some way of deciding the MAX_TILE_SIZE, possibly based on screen size.
3. Update the policy which decides the maximum allowed zoom level, now that tiling is enabled.
4. Presently, tiling support has only been added to libpdf backend. So, there needs to be some mechanism to turn off tiling for documents where the backend doesn't support tiling yet.

Some performance improvements can be brought around by-

Apart from the specific project work, I managed to get my hands dirty with some bugs :) -

Project Update: 26th July, 2013

https://dl.dropboxusercontent.com/u/14970473/bookshelf_screenshot_3.png

While in the bookshelf/recent view, the toolbar is quite different from the regular one. There are just 3 buttons
1. Open a document using a file chooser dialog
2. Display 'About' dialog
3. Close the application

To open any recent document from the view, just click on it. It opens in the same window, in place of the bookshelf, and the toolbar changes to the regular one.

https://dl.dropboxusercontent.com/u/14970473/bookshelf_screenshot_4.png

Now, you might notice the new button on the top left. This button allows you to go back to the recent view without closing the current document. So, while reading a document, if you want to open another recently accessed document, you just need to click on this button. Then, once you're back to the bookshelf view, you can click on any other document you want to open and it will open in a new window. To go back to the document you were reading, just click on its icon.

Patches for this and the discussion can be found on Bugzilla - Bug 633501. Latest code is in the 'bookshelf' branch on the Gitorious repo I have made.

User interface improvements that remain (in order of priority)

  • Highlight currently open document in the recent view
  • Highlight a document on mouse hover
  • Show path of document over which the mouse is hovering, using an overlay in the bottom left (like in web browsers)

Improvements to make in the implementation

  • Rename EvMinimalToolbar to EvRecentViewToolbar, rename EvToolbar to EvMainToolbar, and move the common code among them to EvToolbar

  • Use libgnome-desktop to generate, store and retrieve thumbnails

Outreach/SummerOfCode/2013/Projects/AakashGoenka_BookshelfTilingEvince (last edited 2013-12-03 18:34:15 by WilliamJonMcCann)