[Libreoffice-commits] core.git: 13 commits - desktop/source include/LibreOfficeKit include/sal include/vcl libreofficekit/CppunitTest_libreofficekit_tiledrendering.mk libreofficekit/Executable_gtktiledviewer.mk libreofficekit/Module_libreofficekit.mk libreofficekit/qa libreofficekit/source sc/inc sc/source sd/source sw/inc sw/source

Andrzej Hunt andrzej.hunt at collabora.com
Fri Jul 11 20:22:25 PDT 2014


 desktop/source/lib/init.cxx                                 |   54 ++
 include/LibreOfficeKit/LibreOfficeKit.h                     |    3 
 include/LibreOfficeKit/LibreOfficeKit.hxx                   |   11 
 include/LibreOfficeKit/LibreOfficeKitGtk.h                  |    7 
 include/sal/log-areas.dox                                   |    5 
 include/vcl/ITiledRenderable.hxx                            |   16 
 libreofficekit/CppunitTest_libreofficekit_tiledrendering.mk |   56 ++
 libreofficekit/Executable_gtktiledviewer.mk                 |    4 
 libreofficekit/Module_libreofficekit.mk                     |    4 
 libreofficekit/qa/gtktiledviewer/gtktiledviewer.cxx         |  104 ++++
 libreofficekit/qa/lokdocview_quad/lokdocview_quad.c         |  256 ++++++++++++
 libreofficekit/qa/lokdocview_quad/lokdocview_quad.h         |   66 +++
 libreofficekit/qa/unit/tiledrendering.cxx                   |  111 +++++
 libreofficekit/source/gtk/lokdocview.c                      |   23 +
 sc/inc/docuno.hxx                                           |    3 
 sc/source/ui/unoobj/docuno.cxx                              |   18 
 sd/source/ui/inc/unomodel.hxx                               |   18 
 sd/source/ui/unoidl/unomodel.cxx                            |   81 +++
 sw/inc/unotxdoc.hxx                                         |    3 
 sw/source/uibase/uno/unotxdoc.cxx                           |   15 
 20 files changed, 838 insertions(+), 20 deletions(-)

New commits:
commit f9d3dbe549ae87c5799173e52d2d6a684dbfc55a
Author: Andrzej Hunt <andrzej.hunt at collabora.com>
Date:   Fri Jul 11 16:21:15 2014 +0200

    Impress: implement tiled rendering.
    
    However we cannot as of yet select between rendering just the slide,
    just the notes, or both combined -- this simply defaults to whatever
    mode the document was last opened in for now.
    
    Change-Id: Ia8ec0280aab75a36e430aa04c47cee4fea2db974

diff --git a/sd/source/ui/unoidl/unomodel.cxx b/sd/source/ui/unoidl/unomodel.cxx
index 74133b8..f86e9cb 100644
--- a/sd/source/ui/unoidl/unomodel.cxx
+++ b/sd/source/ui/unoidl/unomodel.cxx
@@ -87,6 +87,7 @@
 #include <unokywds.hxx>
 #include "FrameView.hxx"
 #include "ClientView.hxx"
+#include "DrawViewShell.hxx"
 #include "ViewShell.hxx"
 #include "app.hrc"
 #include <vcl/pdfextoutdevdata.hxx>
@@ -108,6 +109,7 @@
 using namespace ::osl;
 using namespace ::cppu;
 using namespace ::com::sun::star;
+using namespace ::sd;
 
 class SdUnoForbiddenCharsTable : public SvxUnoForbiddenCharsTable,
                                  public SfxListener
@@ -2190,33 +2192,77 @@ void SdXImpressDocument::paintTile( VirtualDevice& rDevice,
                             int nTilePosX, int nTilePosY,
                             long nTileWidth, long nTileHeight )
 {
-    (void) rDevice;
-    (void) nOutputWidth;
-    (void) nOutputHeight;
-    (void) nTilePosX;
-    (void) nTilePosY;
-    (void) nTileWidth;
-    (void) nTileHeight;
+    // Scaling. Must convert from pixels to twips. We know
+    // that VirtualDevices use a DPI of 96.
+    // We specifically calculate these scales first as we're still
+    // in TWIPs, and might as well minimise the number of conversions.
+    Fraction scaleX = Fraction( nOutputWidth, 96 ) * Fraction(1440L) /
+                                Fraction( nTileWidth);
+    Fraction scaleY = Fraction( nOutputHeight, 96 ) * Fraction(1440L) /
+                                Fraction( nTileHeight);
+
+    // svx seems to be the only component that works natively in
+    // 100th mm rather than TWIP. It makes most sense just to
+    // convert here and in getDocumentSize, and leave the tiled
+    // rendering API working in TWIPs.
+    nTileWidth = convertTwipToMm100( nTileWidth );
+    nTileHeight = convertTwipToMm100( nTileHeight );
+    nTilePosX = convertTwipToMm100( nTilePosX );
+    nTilePosY = convertTwipToMm100( nTilePosY );
+
+    MapMode aMapMode = rDevice.GetMapMode();
+    aMapMode.SetMapUnit( MAP_100TH_MM );
+    aMapMode.SetOrigin( Point( -nTilePosX,
+                               -nTilePosY) );
+    aMapMode.SetScaleX( scaleX );
+    aMapMode.SetScaleY( scaleY );
+
+    rDevice.SetMapMode( aMapMode );
+
+    rDevice.SetOutputSizePixel( Size(nOutputWidth, nOutputHeight) );
+    mpDoc->GetDocSh()->GetViewShell()->GetView()->CompleteRedraw(
+        &rDevice,
+        Region(
+            Rectangle( Point( nTilePosX, nTilePosY ),
+                       Size( nTileWidth, nTileHeight ) ) ) );
+
+    // TODO: Set page kind in frameview?
 }
 
 void SdXImpressDocument::setPart( int nPart )
 {
-    (void) nPart;
+    DrawViewShell* pViewSh = dynamic_cast< DrawViewShell* >( mpDoc->GetDocSh()->GetViewShell() );
+    if (pViewSh)
+    {
+        pViewSh->SwitchPage( nPart );
+    }
 }
 
 int SdXImpressDocument::getParts()
 {
-    return mpDoc->GetPageCount();
+    // TODO: master pages?
+    // Read: drviews1.cxx
+    return mpDoc->GetSdPageCount(PK_STANDARD);
 }
 
 int SdXImpressDocument::getPart()
 {
+    DrawViewShell* pViewSh = dynamic_cast< DrawViewShell* >( mpDoc->GetDocSh()->GetViewShell() );
+    if (pViewSh)
+    {
+        return pViewSh->GetCurPageId();
+    }
     return 0;
 }
 
 Size SdXImpressDocument::getDocumentSize()
 {
-    return Size( 100, 100 );
+    SdrPageView* pCurPageView = mpDoc->GetDocSh()->GetViewShell()->GetView()->GetSdrPageView();
+    Size aSize = pCurPageView->GetPageRect().GetSize();
+    // Convert the size in 100th mm to TWIP
+    // See paintTile above for further info.
+    return Size( convertMm100ToTwip( aSize.getWidth() ),
+                 convertMm100ToTwip( aSize.getHeight() ) );
 }
 
 
commit 01f43039aa083a127b595075837770b2ad38b8b9
Author: Andrzej Hunt <andrzej.hunt at collabora.com>
Date:   Fri Jul 11 16:09:30 2014 +0200

    LOK: use solar mutex for setPart.
    
    Needed e.g. for changing slides in impress.
    
    Change-Id: I2f5de40d4efbacde910e27225768979a98ff1c0a

diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index b8f8ae8..6c4d5cc 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -462,7 +462,11 @@ static void doc_setPart(LibreOfficeKitDocument* pThis, int nPart)
         return;
     }
 
-    pDoc->setPart( nPart );
+    Application::AcquireSolarMutex(1);
+    {
+        pDoc->setPart( nPart );
+    }
+    Application::ReleaseSolarMutex();
 }
 
 void doc_paintTile (LibreOfficeKitDocument* pThis,
commit d27a14053440743502dd18641b7d476b7e53023c
Author: Andrzej Hunt <andrzej.hunt at collabora.com>
Date:   Fri Jul 11 09:13:21 2014 +0200

    LOK: some logging for tiled rendering.
    
    Change-Id: I5779eec97507b1996cda89174a6e6c55cdd57baf

diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index bde1c50..b8f8ae8 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -472,6 +472,9 @@ void doc_paintTile (LibreOfficeKitDocument* pThis,
                     const int nTilePosX, const int nTilePosY,
                     const int nTileWidth, const int nTileHeight)
 {
+    SAL_INFO( "lok.tiledrendering", "paintTile: painting [" << nTileWidth << "x" << nTileHeight <<
+              "]@(" << nTilePosX << ", " << nTilePosY << ") to [" <<
+              nCanvasWidth << "x" << nCanvasHeight << "]px" );
     LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
 
     ::vcl::ITiledRenderable* pDoc = dynamic_cast< ::vcl::ITiledRenderable* >( pDocument->mxComponent.get() );
commit 082de4795d10e0fd9b650c4fbdeb102e49724da5
Author: Andrzej Hunt <andrzej.hunt at collabora.com>
Date:   Fri Jul 11 09:12:58 2014 +0200

    Add LOK and tiledrendering log areas.
    
    Change-Id: I885acc9b4a52835fa256c2ecd1b8da917b4f7ba7

diff --git a/include/sal/log-areas.dox b/include/sal/log-areas.dox
index c5d1196..c22b8e6 100644
--- a/include/sal/log-areas.dox
+++ b/include/sal/log-areas.dox
@@ -236,6 +236,11 @@ certain functionality.
 @li @c jfw.level1
 @li @c jfw.level2
 
+ at section LibreOfficeKit
+
+ at li @c lok
+ at li @c lok.tiledrendering
+
 @section l10ntools
 
 @li @c l10ntools
commit a5fe08855b3200bd369b9345d43ae559d5aac4dd
Author: Andrzej Hunt <andrzej.hunt at collabora.com>
Date:   Fri Jul 11 09:12:27 2014 +0200

    Add LOK tiled rendering divided-tile unit test.
    
    I.e. we render the same area as one larger tile, and then
    as 4 sub-tiles (which, when put together, should be identical
    to the larger tile). However currently only the top-left sub-tile
    actually matches the larger tile, so we have to disable the test
    for the remaining sub-tiles.
    
    Change-Id: If1130022b43898e20fefff3e9f592102da3e413a

diff --git a/libreofficekit/CppunitTest_libreofficekit_tiledrendering.mk b/libreofficekit/CppunitTest_libreofficekit_tiledrendering.mk
new file mode 100644
index 0000000..3c41c0a
--- /dev/null
+++ b/libreofficekit/CppunitTest_libreofficekit_tiledrendering.mk
@@ -0,0 +1,56 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#*************************************************************************
+#
+# 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/.
+#
+#*************************************************************************
+
+$(eval $(call gb_CppunitTest_CppunitTest,libreofficekit_tiledrendering))
+
+$(eval $(call gb_CppunitTest_add_exception_objects,libreofficekit_tiledrendering, \
+    libreofficekit/qa/unit/tiledrendering \
+))
+
+$(eval $(call gb_CppunitTest_use_external,libreofficekit_tiledrendering,boost_headers))
+
+# We need all these libraries / etc. due for CppunitTest to work, even though
+# our test specifically tests LOK only functionality which would otherwise not
+# require any normal LO api/libraries.
+$(eval $(call gb_CppunitTest_use_libraries,libreofficekit_tiledrendering, \
+	test \
+	cppu \
+	sal \
+	vcl \
+	$(gb_UWINAPI) \
+))
+
+
+# 	unotest \
+
+ifeq ($(OS),LINUX)
+$(eval $(call gb_CppunitTest_add_libs,libreofficekit_tiledrendering,\
+    -lm \
+    -ldl \
+    -lpthread \
+))
+endif
+
+$(eval $(call gb_CppunitTest_use_sdk_api,libreofficekit_tiledrendering))
+
+$(eval $(call gb_CppunitTest_use_static_libraries,libreofficekit_tiledrendering,\
+    libreofficekit \
+))
+
+$(eval $(call gb_CppunitTest_use_ure,libreofficekit_tiledrendering))
+#$(eval $(call gb_CppunitTest_use_vcl,libreofficekit_tiledrendering))
+
+# Depend on ~everything, as tiled rendering can use most parts of LO.
+$(eval $(call gb_CppunitTest_use_rdb,libreofficekit_tiledrendering,services))
+
+$(eval $(call gb_CppunitTest_use_configuration,libreofficekit_tiledrendering))
+
+# vim: set noet sw=4 ts=4:
diff --git a/libreofficekit/Module_libreofficekit.mk b/libreofficekit/Module_libreofficekit.mk
index b349a5d..2d9b98c 100644
--- a/libreofficekit/Module_libreofficekit.mk
+++ b/libreofficekit/Module_libreofficekit.mk
@@ -15,6 +15,10 @@ $(eval $(call gb_Module_add_targets,libreofficekit,\
     StaticLibrary_libreofficekit \
 ))
 
+$(eval $(call gb_Module_add_check_targets,libreofficekit,\
+    CppunitTest_libreofficekit_tiledrendering \
+))
+
 ifneq ($(ENABLE_GTK),)
 $(eval $(call gb_Module_add_targets,libreofficekit,\
     Library_libreofficekitgtk \
diff --git a/libreofficekit/qa/unit/tiledrendering.cxx b/libreofficekit/qa/unit/tiledrendering.cxx
new file mode 100644
index 0000000..1cc93f7
--- /dev/null
+++ b/libreofficekit/qa/unit/tiledrendering.cxx
@@ -0,0 +1,111 @@
+/* -*- 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 <boost/scoped_array.hpp>
+#include <boost/scoped_ptr.hpp>
+#include <cppunit/TestFixture.h>
+#include <cppunit/plugin/TestPlugIn.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <cstdlib>
+#include <string>
+
+#include <sal/types.h>
+
+#define LOK_USE_UNSTABLE_API
+#include <LibreOfficeKit/LibreOfficeKit.hxx>
+
+using namespace ::boost;
+using namespace ::lok;
+using namespace ::std;
+
+// We specifically don't use the usual BootStrapFixture, as LOK does
+// all it's own setup and bootstrapping, and should be useable in a
+// raw C++ program.
+class TiledRenderingTest : public ::CppUnit::TestFixture
+{
+public:
+    TiledRenderingTest() {}
+
+    void testOverlay();
+
+    CPPUNIT_TEST_SUITE(TiledRenderingTest);
+    CPPUNIT_TEST(testOverlay);
+    CPPUNIT_TEST_SUITE_END();
+};
+
+void TiledRenderingTest::testOverlay()
+{
+    const string sSrcRoot = getenv( "SRC_ROOT" );
+    const string sLOPath = sSrcRoot + "/instdir/program";
+    const string sDocPath = sSrcRoot + "/odk/examples/java/DocumentHandling/test/test1.odt";
+
+    scoped_ptr< Office > pOffice( lok_cpp_init(
+                                      sLOPath.c_str() ) );
+    scoped_ptr< Document> pDocument( pOffice->documentLoad(
+                                         sDocPath.c_str() ) );
+
+    // We render one large tile, then subdivide it into 4 and render those parts, and finally
+    // iterate over each smaller tile and check whether their contents match the large
+    // tile.
+    const int nTotalWidthPix = 512;
+    const int nTotalHeightPix = 512;
+    int nRowStride;
+
+    long nTotalWidthDoc;
+    long nTotalHeightDoc;
+    // pDocument->getDocumentSize( &nTotalWidthDoc, &nTotalHeightDoc );
+    // TODO: make sure we select an actually interesting part of the document
+    // for this comparison, i.e. ideally an image and lots of text, in order
+    // to test as many edge cases as possible.
+    // Alternatively we could rewrite this to actually grab the document size
+    // and iterate over it (subdividing into an arbitrary number of tiles rather
+    // than our less sophisticated test of just 4 sub-tiles).
+    nTotalWidthDoc = 8000;
+    nTotalHeightDoc = 9000;
+
+    scoped_array< unsigned char > pLarge( new unsigned char[ 4*nTotalWidthPix*nTotalHeightPix ] );
+    pDocument->paintTile( pLarge.get(),  nTotalWidthPix, nTotalHeightPix, &nRowStride,
+                          0, 0,
+                          nTotalWidthDoc, nTotalHeightDoc );
+    scoped_array< unsigned char > pSmall[4];
+    for ( int i = 0; i < 4; i++ )
+    {
+        pSmall[i].reset( new unsigned char[ 4*(nTotalWidthPix/2)*(nTotalHeightPix/2) ] );
+        pDocument->paintTile( pSmall[i].get(),  nTotalWidthPix / 2, nTotalHeightPix / 2, &nRowStride,
+                              // Tile 0/2: left. Tile 1/3: right. Tile 0/1: top. Tile 2/3: bottom
+                              ((i%2 == 0) ?  0 : nTotalWidthDoc / 2), ((i < 2 ) ? 0 : nTotalHeightDoc / 2),
+                              nTotalWidthDoc / 2, nTotalHeightDoc / 2);
+    }
+
+    // Iterate over each pixel of the sub-tile, and compare that pixel for every
+    // tile with the equivalent super-tile pixel.
+    for ( int i = 0; i < 4*nTotalWidthPix / 2 * nTotalHeightPix / 2; i++ )
+    {
+        int xSmall = i % (4*nTotalWidthPix/2);
+        int ySmall = i / (4*nTotalWidthPix/2);
+        // Iterate over our array of tiles
+        // However for now we only bother with the top-left
+        // tile as the other ones don't match yet...
+        for ( int x = 0; x < 1; x++ )
+        {
+            for ( int y = 0; y < 1; y++ )
+            {
+                int xLarge = (x * (4 * nTotalWidthPix / 2)) + xSmall;
+                int yLarge = (y * (nTotalHeightPix / 2)) + ySmall;
+                CPPUNIT_ASSERT( pSmall[2*y+x][i] == pLarge[yLarge*4*nTotalWidthPix + xLarge] );
+            }
+        }
+    }
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION(TiledRenderingTest);
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit 1d6dca3cb0182ddc11d334190544350b09dc6de2
Author: Andrzej Hunt <andrzej.hunt at collabora.com>
Date:   Tue Jul 8 16:41:56 2014 +0200

    Add Tiled Rendering outline to sd.
    
    Change-Id: I810d827f330690f8071b662b9ddd05cc41655a71

diff --git a/sd/source/ui/inc/unomodel.hxx b/sd/source/ui/inc/unomodel.hxx
index f9fafdd..6887663 100644
--- a/sd/source/ui/inc/unomodel.hxx
+++ b/sd/source/ui/inc/unomodel.hxx
@@ -45,6 +45,8 @@
 #include <sfx2/sfxbasemodel.hxx>
 #include <svx/fmdmod.hxx>
 
+#include <vcl/ITiledRenderable.hxx>
+
 #include <editeng/unoipset.hxx>
 
 #include <comphelper/servicehelper.hxx>
@@ -76,7 +78,8 @@ class SdXImpressDocument : public SfxBaseModel, // implements SfxListener, OWEAK
                            public ::com::sun::star::lang::XServiceInfo,
                            public ::com::sun::star::ucb::XAnyCompareFactory,
                            public ::com::sun::star::presentation::XHandoutMasterSupplier,
-                           public ::com::sun::star::view::XRenderable
+                           public ::com::sun::star::view::XRenderable,
+                           public ::vcl::ITiledRenderable
 {
     friend class SdDrawPagesAccess;
     friend class SdMasterPagesAccess;
@@ -218,6 +221,19 @@ public:
     virtual ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > SAL_CALL getRenderer( sal_Int32 nRenderer, const ::com::sun::star::uno::Any& aSelection, const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& xOptions ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
     virtual void SAL_CALL render( sal_Int32 nRenderer, const ::com::sun::star::uno::Any& aSelection, const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& xOptions ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
 
+    // ITiledRenderable
+    virtual void paintTile( VirtualDevice& rDevice,
+                            int nOutputWidth,
+                            int nOutputHeight,
+                            int nTilePosX,
+                            int nTilePosY,
+                            long nTileWidth,
+                            long nTileHeight ) SAL_OVERRIDE;
+    virtual Size getDocumentSize() SAL_OVERRIDE;
+    virtual void setPart(   int nPart ) SAL_OVERRIDE;
+    virtual int  getPart() SAL_OVERRIDE;
+    virtual int  getParts() SAL_OVERRIDE;
+
     // XComponent
 
     /** This dispose implementation releases the resources held by the
diff --git a/sd/source/ui/unoidl/unomodel.cxx b/sd/source/ui/unoidl/unomodel.cxx
index bc970e9..74133b8 100644
--- a/sd/source/ui/unoidl/unomodel.cxx
+++ b/sd/source/ui/unoidl/unomodel.cxx
@@ -2185,6 +2185,41 @@ void SAL_CALL SdXImpressDocument::render( sal_Int32 nRenderer, const uno::Any& r
     }
 }
 
+void SdXImpressDocument::paintTile( VirtualDevice& rDevice,
+                            int nOutputWidth, int nOutputHeight,
+                            int nTilePosX, int nTilePosY,
+                            long nTileWidth, long nTileHeight )
+{
+    (void) rDevice;
+    (void) nOutputWidth;
+    (void) nOutputHeight;
+    (void) nTilePosX;
+    (void) nTilePosY;
+    (void) nTileWidth;
+    (void) nTileHeight;
+}
+
+void SdXImpressDocument::setPart( int nPart )
+{
+    (void) nPart;
+}
+
+int SdXImpressDocument::getParts()
+{
+    return mpDoc->GetPageCount();
+}
+
+int SdXImpressDocument::getPart()
+{
+    return 0;
+}
+
+Size SdXImpressDocument::getDocumentSize()
+{
+    return Size( 100, 100 );
+}
+
+
 uno::Reference< i18n::XForbiddenCharacters > SdXImpressDocument::getForbiddenCharsTable()
 {
     uno::Reference< i18n::XForbiddenCharacters > xForb(mxForbidenCharacters);
commit 855eb54ffe70a6c7eb423ebdcc9f25295c1f3474
Author: Andrzej Hunt <andrzej.hunt at collabora.com>
Date:   Tue Jul 8 15:32:46 2014 +0200

    Add part selector to gtktiledviewer.
    
    Change-Id: I569c8f0ebf4476c0a247cde15a263d1db956a14b

diff --git a/libreofficekit/qa/gtktiledviewer/gtktiledviewer.cxx b/libreofficekit/qa/gtktiledviewer/gtktiledviewer.cxx
index 3a232e8..b4ed50e 100644
--- a/libreofficekit/qa/gtktiledviewer/gtktiledviewer.cxx
+++ b/libreofficekit/qa/gtktiledviewer/gtktiledviewer.cxx
@@ -117,6 +117,29 @@ void changeQuadView( GtkWidget* /*pButton*/, gpointer /* pItem */ )
     }
 }
 
+void populatePartSelector( GtkComboBoxText* pSelector, LOKDocView* pView )
+{
+    char sText[10];
+    for ( int i = 0; i < lok_docview_get_parts(pView); i++ )
+    {
+        sprintf( sText, "%i", i+1 );
+        gtk_combo_box_text_append_text( pSelector, sText );
+    }
+    gtk_combo_box_set_active( GTK_COMBO_BOX(pSelector), 0 );
+}
+
+void changePart( GtkWidget* pSelector, gpointer /* pItem */ )
+{
+    int nPart = gtk_combo_box_get_active( GTK_COMBO_BOX(pSelector) );
+
+    // We don't really care about the quad view for now -- it's only purpose
+    // is to check that the edges of tiles aren't messed up, and no real
+    // reason to maintain it to be able to show other document parts etc.
+    if ( pDocView )
+    {
+        lok_docview_set_part( LOK_DOCVIEW(pDocView), nPart );
+    }
+}
 
 int main( int argc, char* argv[] )
 {
@@ -165,6 +188,15 @@ int main( int argc, char* argv[] )
     GtkToolItem* pSeparator1 = gtk_separator_tool_item_new();
     gtk_toolbar_insert( GTK_TOOLBAR(pToolbar), pSeparator1, -1);
 
+    GtkToolItem* pPartSelectorToolItem = gtk_tool_item_new();
+    GtkWidget* pComboBox = gtk_combo_box_text_new();
+    gtk_container_add( GTK_CONTAINER(pPartSelectorToolItem), pComboBox );
+    gtk_toolbar_insert( GTK_TOOLBAR(pToolbar), pPartSelectorToolItem, -1 );
+    g_signal_connect( G_OBJECT(pComboBox), "changed", G_CALLBACK(changePart), NULL );
+
+    GtkToolItem* pSeparator2 = gtk_separator_tool_item_new();
+    gtk_toolbar_insert( GTK_TOOLBAR(pToolbar), pSeparator2, -1);
+
     GtkToolItem* pEnableQuadView = gtk_toggle_tool_button_new();
     gtk_tool_button_set_label( GTK_TOOL_BUTTON(pEnableQuadView), "Use Quad View" );
     gtk_toolbar_insert( GTK_TOOLBAR(pToolbar), pEnableQuadView, -1 );
@@ -181,6 +213,7 @@ int main( int argc, char* argv[] )
 
     pFileName = argv[2];
     lok_docview_open_document( LOK_DOCVIEW(pDocView), argv[2] );
+    populatePartSelector( GTK_COMBO_BOX_TEXT(pComboBox), LOK_DOCVIEW(pDocView) );
 
     gtk_main();
 
commit c49e26cb447cf8d601209da2be1e37c0e17ef1d2
Author: Andrzej Hunt <andrzej.hunt at collabora.com>
Date:   Tue Jul 8 15:32:20 2014 +0200

    LOK DocView: implement part selection.
    
    Change-Id: I2e16ca9d2d5fcd25b0435f1b9b0fbcb52b92e012

diff --git a/include/LibreOfficeKit/LibreOfficeKitGtk.h b/include/LibreOfficeKit/LibreOfficeKitGtk.h
index f160925..37d21f0 100644
--- a/include/LibreOfficeKit/LibreOfficeKitGtk.h
+++ b/include/LibreOfficeKit/LibreOfficeKitGtk.h
@@ -58,8 +58,13 @@ void            lok_docview_set_zoom        (LOKDocView* pDocView,
                                              float fZoom);
 float           lok_docview_get_zoom        (LOKDocView* pDocView);
 
+int             lok_docview_get_parts       (LOKDocView* pDocView);
+int             lok_docview_get_part        (LOKDocView* pDocView);
+void            lok_docview_set_part        (LOKDocView* pDocView,
+                                             int nPart);
+
 #ifdef __cplusplus
 }
 #endif
 
-#endif
\ No newline at end of file
+#endif
diff --git a/libreofficekit/source/gtk/lokdocview.c b/libreofficekit/source/gtk/lokdocview.c
index 12b004e08..cdc2339 100644
--- a/libreofficekit/source/gtk/lokdocview.c
+++ b/libreofficekit/source/gtk/lokdocview.c
@@ -174,4 +174,21 @@ SAL_DLLPUBLIC_EXPORT float lok_docview_get_zoom ( LOKDocView* pDocView )
     return pDocView->fZoom;
 }
 
+SAL_DLLPUBLIC_EXPORT int lok_docview_get_parts( LOKDocView* pDocView )
+{
+    return pDocView->pDocument->pClass->getParts( pDocView->pDocument );
+}
+
+SAL_DLLPUBLIC_EXPORT int lok_docview_get_part( LOKDocView* pDocView )
+{
+    return pDocView->pDocument->pClass->getPart( pDocView->pDocument );
+}
+
+SAL_DLLPUBLIC_EXPORT void lok_docview_set_part( LOKDocView* pDocView, int nPart)
+{
+    pDocView->pDocument->pClass->setPart( pDocView->pDocument, nPart );
+    renderDocument( pDocView );
+}
+
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit 4d15212ef8de89a71387c00bdeb7d9a41409e467
Author: Andrzej Hunt <andrzej.hunt at collabora.com>
Date:   Tue Jul 8 15:23:06 2014 +0200

    Add get/setPart to ITiledRenderable, and implement for sw/sc.
    
    Change-Id: Iec3d6374f029149cadf8fb9c9b16fec90146c31e

diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index 273446f1..bde1c50 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -181,7 +181,8 @@ extern "C"
 static void doc_destroy(LibreOfficeKitDocument* pThis);
 static int  doc_saveAs(LibreOfficeKitDocument* pThis, const char* pUrl, const char* pFormat, const char* pFilterOptions);
 static LibreOfficeKitDocumentType doc_getDocumentType(LibreOfficeKitDocument* pThis);
-static int doc_getNumberOfParts(LibreOfficeKitDocument* pThis);
+static int doc_getParts(LibreOfficeKitDocument* pThis);
+static int doc_getPart(LibreOfficeKitDocument* pThis);
 static void doc_setPart(LibreOfficeKitDocument* pThis, int nPart);
 void        doc_paintTile(LibreOfficeKitDocument* pThis,
                           unsigned char* pBuffer,
@@ -210,7 +211,8 @@ struct LibLODocument_Impl : public _LibreOfficeKitDocument
             m_pDocumentClass->destroy = doc_destroy;
             m_pDocumentClass->saveAs = doc_saveAs;
             m_pDocumentClass->getDocumentType = doc_getDocumentType;
-            m_pDocumentClass->getNumberOfParts = doc_getNumberOfParts;
+            m_pDocumentClass->getParts = doc_getParts;
+            m_pDocumentClass->getPart = doc_getPart;
             m_pDocumentClass->setPart = doc_setPart;
             m_pDocumentClass->paintTile = doc_paintTile;
             m_pDocumentClass->getDocumentSize = doc_getDocumentSize;
@@ -421,17 +423,46 @@ static LibreOfficeKitDocumentType doc_getDocumentType (LibreOfficeKitDocument* p
     return LOK_DOCTYPE_OTHER;
 }
 
-static int doc_getNumberOfParts (LibreOfficeKitDocument* pThis)
+static int doc_getParts (LibreOfficeKitDocument* pThis)
 {
-    (void) pThis;
-    // Assume writer document for now.
-    return 1;
+    LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
+
+    ::vcl::ITiledRenderable* pDoc = dynamic_cast< ::vcl::ITiledRenderable* >( pDocument->mxComponent.get() );
+    if (!pDoc)
+    {
+        gImpl->maLastExceptionMsg = "Document doesn't support tiled rendering";
+        return 0;
+    }
+
+    return pDoc->getParts();
+}
+
+static int doc_getPart (LibreOfficeKitDocument* pThis)
+{
+    LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
+
+    ::vcl::ITiledRenderable* pDoc = dynamic_cast< ::vcl::ITiledRenderable* >( pDocument->mxComponent.get() );
+    if (!pDoc)
+    {
+        gImpl->maLastExceptionMsg = "Document doesn't support tiled rendering";
+        return 0;
+    }
+
+    return pDoc->getPart();
 }
 
 static void doc_setPart(LibreOfficeKitDocument* pThis, int nPart)
 {
-    (void) pThis;
-    (void) nPart;
+    LibLODocument_Impl* pDocument = static_cast<LibLODocument_Impl*>(pThis);
+
+    ::vcl::ITiledRenderable* pDoc = dynamic_cast< ::vcl::ITiledRenderable* >( pDocument->mxComponent.get() );
+    if (!pDoc)
+    {
+        gImpl->maLastExceptionMsg = "Document doesn't support tiled rendering";
+        return;
+    }
+
+    pDoc->setPart( nPart );
 }
 
 void doc_paintTile (LibreOfficeKitDocument* pThis,
diff --git a/include/LibreOfficeKit/LibreOfficeKit.h b/include/LibreOfficeKit/LibreOfficeKit.h
index ba4319f..675eabc 100644
--- a/include/LibreOfficeKit/LibreOfficeKit.h
+++ b/include/LibreOfficeKit/LibreOfficeKit.h
@@ -77,8 +77,9 @@ struct _LibreOfficeKitDocumentClass
 
   // Part refers to either indivual sheets in a Spreadsheet, or slides
   // in a Slideshow, and has no relevance for wrtier documents.
-  int (*getNumberOfParts) (LibreOfficeKitDocument* pThis);
+  int (*getParts) (LibreOfficeKitDocument* pThis);
 
+  int (*getPart)          (LibreOfficeKitDocument* pThis);
   void (*setPart)         (LibreOfficeKitDocument* pThis,
                            int nPart);
 
diff --git a/include/LibreOfficeKit/LibreOfficeKit.hxx b/include/LibreOfficeKit/LibreOfficeKit.hxx
index 427ea83..32faf26 100644
--- a/include/LibreOfficeKit/LibreOfficeKit.hxx
+++ b/include/LibreOfficeKit/LibreOfficeKit.hxx
@@ -49,9 +49,14 @@ public:
         return mpDoc->pClass->getDocumentType(mpDoc);
     }
 
-    inline int getNumberOfParts()
+    inline int getParts()
     {
-        return mpDoc->pClass->getNumberOfParts(mpDoc);
+        return mpDoc->pClass->getParts(mpDoc);
+    }
+
+    inline int getPart()
+    {
+        return mpDoc->pClass->getPart(mpDoc);
     }
 
     inline void setPart(int nPart)
@@ -75,7 +80,7 @@ public:
 
     inline void getDocumentSize(long* pWidth, long* pHeight)
     {
-        mpDoc->getDocumentSize(mpDoc, pWidth, pHeight);
+        mpDoc->pClass->getDocumentSize(mpDoc, pWidth, pHeight);
     }
 #endif // LOK_USE_UNSTABLE_API
 };
diff --git a/include/vcl/ITiledRenderable.hxx b/include/vcl/ITiledRenderable.hxx
index e9cea10..55e1b39 100644
--- a/include/vcl/ITiledRenderable.hxx
+++ b/include/vcl/ITiledRenderable.hxx
@@ -41,6 +41,22 @@ public:
      */
     virtual Size getDocumentSize() = 0;
 
+    /**
+     * Set the document "part", i.e. slide for a slideshow, and
+     * tab for a spreadsheet.
+     */
+    virtual void setPart( int nPart ) = 0;
+
+    /**
+     * Get the number of parts -- see setPart for further details.
+     */
+    virtual int getParts() = 0;
+
+    /**
+     * Get the currently displayed/selected part -- see setPart for further
+     * details.
+     */
+    virtual int getPart() = 0;
 };
 
 } // namespace vcl
diff --git a/sc/inc/docuno.hxx b/sc/inc/docuno.hxx
index 27575fe..932017d 100644
--- a/sc/inc/docuno.hxx
+++ b/sc/inc/docuno.hxx
@@ -363,6 +363,9 @@ public:
                             long nTileWidth,
                             long nTileHeight ) SAL_OVERRIDE;
     virtual Size getDocumentSize() SAL_OVERRIDE;
+    virtual void setPart(   int nPart ) SAL_OVERRIDE;
+    virtual int  getPart() SAL_OVERRIDE;
+    virtual int  getParts() SAL_OVERRIDE;
 };
 
 class ScDrawPagesObj : public cppu::WeakImplHelper2<
diff --git a/sc/source/ui/unoobj/docuno.cxx b/sc/source/ui/unoobj/docuno.cxx
index 6852d1c..2893974 100644
--- a/sc/source/ui/unoobj/docuno.cxx
+++ b/sc/source/ui/unoobj/docuno.cxx
@@ -461,6 +461,24 @@ void ScModelObj::paintTile( VirtualDevice& rDevice,
                             nTilePosX, nTilePosY, nTileWidth, nTileHeight );
 }
 
+void ScModelObj::setPart( int nPart )
+{
+    ScViewData* pViewData = ScDocShell::GetViewData();
+    pViewData->SetTabNo( nPart );
+}
+
+int ScModelObj::getParts()
+{
+    ScDocument& rDoc = pDocShell->GetDocument();
+    return rDoc.GetTableCount();
+}
+
+int ScModelObj::getPart()
+{
+    ScViewData* pViewData = ScDocShell::GetViewData();
+    return pViewData->GetTabNo();
+}
+
 Size ScModelObj::getDocumentSize()
 {
     // TODO: not sure what we want to do here, maybe just return the size for a certain
diff --git a/sw/inc/unotxdoc.hxx b/sw/inc/unotxdoc.hxx
index a48a8f3..1318071 100644
--- a/sw/inc/unotxdoc.hxx
+++ b/sw/inc/unotxdoc.hxx
@@ -439,6 +439,9 @@ public:
                             long nTileWidth,
                             long nTileHeight ) SAL_OVERRIDE;
     virtual Size getDocumentSize() SAL_OVERRIDE;
+    virtual void setPart(   int nPart ) SAL_OVERRIDE;
+    virtual int  getPart() SAL_OVERRIDE;
+    virtual int  getParts() SAL_OVERRIDE;
 
     void                        Invalidate();
     void                        Reactivate(SwDocShell* pNewDocShell);
diff --git a/sw/source/uibase/uno/unotxdoc.cxx b/sw/source/uibase/uno/unotxdoc.cxx
index 9ceee45..10f6185 100644
--- a/sw/source/uibase/uno/unotxdoc.cxx
+++ b/sw/source/uibase/uno/unotxdoc.cxx
@@ -3137,6 +3137,21 @@ Size SwXTextDocument::getDocumentSize()
     return pViewShell->GetDocSize();
 }
 
+void SwXTextDocument::setPart( int /*nPart*/ )
+{
+}
+
+int SwXTextDocument::getPart()
+{
+    return 0;
+}
+
+int SwXTextDocument::getParts()
+{
+    // For now we treat the document as one large piece.
+    return 1;
+}
+
 void * SAL_CALL SwXTextDocument::operator new( size_t t) throw()
 {
     return SwXTextDocumentBaseClass::operator new(t);
commit 312883ad755e76cee95735f9faca4a8354b068fd
Author: Andrzej Hunt <andrzej.hunt at collabora.com>
Date:   Tue Jul 8 09:53:42 2014 +0200

    gtktiledviewer: allow selecting between normal and quad-tile view.
    
    Change-Id: I85b22b93fe4ce2ffb62df8766ceea7a1bd8961ee

diff --git a/libreofficekit/qa/gtktiledviewer/gtktiledviewer.cxx b/libreofficekit/qa/gtktiledviewer/gtktiledviewer.cxx
index bc4ad09..3a232e8 100644
--- a/libreofficekit/qa/gtktiledviewer/gtktiledviewer.cxx
+++ b/libreofficekit/qa/gtktiledviewer/gtktiledviewer.cxx
@@ -14,6 +14,7 @@
 #include <gtk/gtk.h>
 
 #include <LibreOfficeKit/LibreOfficeKitGtk.h>
+#include "../lokdocview_quad/lokdocview_quad.h"
 
 static int help()
 {
@@ -22,6 +23,10 @@ static int help()
 }
 
 static GtkWidget* pDocView;
+static GtkWidget* pDocViewQuad;
+static GtkWidget* pVBox;
+static LibreOfficeKit* pOffice;
+static char* pFileName;
 
 const float fZooms[] = { 0.25, 0.5, 0.75, 1.0, 1.5, 2.0, 3.0, 5.0 };
 
@@ -30,7 +35,17 @@ void changeZoom( GtkWidget* pButton, gpointer /* pItem */ )
     const char *sName = gtk_tool_button_get_stock_id( GTK_TOOL_BUTTON(pButton) );
 
     float fZoom = 0;
-    const float fCurrentZoom = lok_docview_get_zoom( LOK_DOCVIEW(pDocView) );
+    float fCurrentZoom;
+
+    if ( pDocView )
+    {
+        fCurrentZoom = lok_docview_get_zoom( LOK_DOCVIEW(pDocView) );
+    }
+    else if ( pDocViewQuad )
+    {
+        fCurrentZoom = lok_docview_quad_get_zoom( LOK_DOCVIEW_QUAD(pDocView) );
+    }
+
     if ( strcmp(sName, "gtk-zoom-in") == 0)
     {
         for ( unsigned int i = 0; i < sizeof( fZooms ) / sizeof( fZooms[0] ); i++ )
@@ -63,10 +78,46 @@ void changeZoom( GtkWidget* pButton, gpointer /* pItem */ )
 
     if ( fZoom != 0 )
     {
-        lok_docview_set_zoom( LOK_DOCVIEW(pDocView), fZoom );
+        if ( pDocView )
+        {
+            lok_docview_set_zoom( LOK_DOCVIEW(pDocView), fZoom );
+        }
+        else if ( pDocViewQuad )
+        {
+            lok_docview_quad_set_zoom( LOK_DOCVIEW_QUAD(pDocViewQuad), fZoom );
+        }
     }
 }
 
+void changeQuadView( GtkWidget* /*pButton*/, gpointer /* pItem */ )
+{
+    if ( pDocView )
+    {
+        const float fCurrentZoom = lok_docview_get_zoom( LOK_DOCVIEW(pDocView) );
+        gtk_widget_destroy( pDocView );
+        pDocView = 0;
+        pDocViewQuad = lok_docview_quad_new( pOffice );
+        gtk_container_add( GTK_CONTAINER(pVBox), pDocViewQuad );
+        gtk_widget_show( pDocViewQuad );
+
+        lok_docview_quad_set_zoom( LOK_DOCVIEW_QUAD(pDocViewQuad), fCurrentZoom );
+        lok_docview_quad_open_document( LOK_DOCVIEW_QUAD(pDocViewQuad), pFileName );
+    }
+    else if ( pDocViewQuad )
+    {
+        const float fCurrentZoom = lok_docview_quad_get_zoom( LOK_DOCVIEW_QUAD(pDocViewQuad) );
+        gtk_widget_destroy( pDocViewQuad );
+        pDocViewQuad = 0;
+        pDocView = lok_docview_new( pOffice );
+        gtk_container_add( GTK_CONTAINER(pVBox), pDocView );
+        gtk_widget_show( pDocView );
+
+        lok_docview_set_zoom( LOK_DOCVIEW(pDocView), fCurrentZoom );
+        lok_docview_open_document( LOK_DOCVIEW(pDocView), pFileName );
+    }
+}
+
+
 int main( int argc, char* argv[] )
 {
     if( argc < 2 ||
@@ -79,7 +130,7 @@ int main( int argc, char* argv[] )
         return 1;
     }
 
-    LibreOfficeKit* pOffice = lok_init( argv[1] );
+    pOffice = lok_init( argv[1] );
 
     gtk_init( &argc, &argv );
 
@@ -88,7 +139,7 @@ int main( int argc, char* argv[] )
     gtk_window_set_default_size(GTK_WINDOW(pWindow), 800, 600);
     g_signal_connect( pWindow, "destroy", G_CALLBACK(gtk_main_quit), NULL );
 
-    GtkWidget* pVBox = gtk_vbox_new( FALSE, 0 );
+    pVBox = gtk_vbox_new( FALSE, 0 );
     gtk_container_add( GTK_CONTAINER(pWindow), pVBox );
 
     // Toolbar
@@ -111,17 +162,27 @@ int main( int argc, char* argv[] )
     gtk_toolbar_insert( GTK_TOOLBAR(pToolbar), pZoomOut, -1);
     g_signal_connect( G_OBJECT(pZoomOut), "clicked", G_CALLBACK(changeZoom), NULL );
 
+    GtkToolItem* pSeparator1 = gtk_separator_tool_item_new();
+    gtk_toolbar_insert( GTK_TOOLBAR(pToolbar), pSeparator1, -1);
+
+    GtkToolItem* pEnableQuadView = gtk_toggle_tool_button_new();
+    gtk_tool_button_set_label( GTK_TOOL_BUTTON(pEnableQuadView), "Use Quad View" );
+    gtk_toolbar_insert( GTK_TOOLBAR(pToolbar), pEnableQuadView, -1 );
+    g_signal_connect( G_OBJECT(pEnableQuadView), "toggled", G_CALLBACK(changeQuadView), NULL );
+
     gtk_box_pack_start( GTK_BOX(pVBox), pToolbar, FALSE, FALSE, 0 ); // Adds to top.
 
     // Docview
     pDocView = lok_docview_new( pOffice );
+    pDocViewQuad = 0;
     gtk_container_add( GTK_CONTAINER(pVBox), pDocView );
 
     gtk_widget_show_all( pWindow );
 
+    pFileName = argv[2];
     lok_docview_open_document( LOK_DOCVIEW(pDocView), argv[2] );
 
     gtk_main();
 
     return 0;
-}
\ No newline at end of file
+}
commit d5b2c1908094adedc916545dfffca4d84b1661d3
Author: Andrzej Hunt <andrzej.hunt at collabora.com>
Date:   Tue Jul 8 09:44:40 2014 +0200

    Quad Docview: only rerender on zoom if we have a document open.
    
    Same as
    "LOK DocView: only rerender on zoom if we have a document open."
    but for our quad-tiled test widget.
    
    Change-Id: I6c1b946cc9d576d1dcc4687048339d9f0b3e6eff

diff --git a/libreofficekit/qa/lokdocview_quad/lokdocview_quad.c b/libreofficekit/qa/lokdocview_quad/lokdocview_quad.c
index cbff885..c920f1f 100644
--- a/libreofficekit/qa/lokdocview_quad/lokdocview_quad.c
+++ b/libreofficekit/qa/lokdocview_quad/lokdocview_quad.c
@@ -241,7 +241,10 @@ SAL_DLLPUBLIC_EXPORT gboolean lok_docview_quad_open_document( LOKDocViewQuad* pD
 SAL_DLLPUBLIC_EXPORT void lok_docview_quad_set_zoom ( LOKDocViewQuad* pDocView, float fZoom )
 {
     pDocView->fZoom = fZoom;
-    renderDocument( pDocView );
+    if ( pDocView->pDocument )
+    {
+        renderDocument( pDocView );
+    }
     // TODO: maybe remember and reset positiong?
 }
 
commit cdd76e8877571556eba1a2d070e5fe23a2d4bd10
Author: Andrzej Hunt <andrzej.hunt at collabora.com>
Date:   Tue Jul 8 09:43:09 2014 +0200

    LOK DocView: only rerender on zoom if we have a document open.
    
    Otherwise we would segfault, and it's perfectly valid to set a zoom
    level _before_ opening a document (as that would e.g. save the document
    first being rendered on opening if the client wants to immediately
    render at a non-standard zoom level).
    
    Change-Id: Ide261b09f4aab8dc3b552f6c3bf55f78ffd7870c

diff --git a/libreofficekit/source/gtk/lokdocview.c b/libreofficekit/source/gtk/lokdocview.c
index f813e68..12b004e08 100644
--- a/libreofficekit/source/gtk/lokdocview.c
+++ b/libreofficekit/source/gtk/lokdocview.c
@@ -161,7 +161,11 @@ SAL_DLLPUBLIC_EXPORT gboolean lok_docview_open_document( LOKDocView* pDocView, c
 SAL_DLLPUBLIC_EXPORT void lok_docview_set_zoom ( LOKDocView* pDocView, float fZoom )
 {
     pDocView->fZoom = fZoom;
-    renderDocument( pDocView );
+
+    if ( pDocView->pDocument )
+    {
+        renderDocument( pDocView );
+    }
     // TODO: maybe remember and reset positiong?
 }
 
commit a864ab2ef17e02930df5ae91112b5104bdea1e39
Author: Andrzej Hunt <andrzej.hunt at collabora.com>
Date:   Tue Jul 8 08:54:13 2014 +0200

    Implement a (qa-only) quad-tiled viewer.
    
    I.e. we subdivide the document into 4 tiles: one at 100% scaling,
    one at 200%, one at 50%, one at 25% -- these are then post-scaled
    in gdk) and assembled to show as one document again.
    
    This is specifically a test only widget, primarily to be able to quickly
    spot any tile positioning/border-transition issues.
    
    We could theoretically make this widget inherit from the original widget,
    however that would mean having to introduce virtual methods etc., which
    is not something that we'd want in production -- in the longer run
    that widget will hopefully be extended to have proper tile composition etc.,
    which would then break this widget too if it were inheriting from there.
    
    Change-Id: Ib880a1614f89724135e753013cf91aec25973e39

diff --git a/libreofficekit/Executable_gtktiledviewer.mk b/libreofficekit/Executable_gtktiledviewer.mk
index 0ce9222..d4ef643 100644
--- a/libreofficekit/Executable_gtktiledviewer.mk
+++ b/libreofficekit/Executable_gtktiledviewer.mk
@@ -42,6 +42,10 @@ $(eval $(call gb_Executable_add_libs,gtktiledviewer,\
 ))
 endif
 
+$(eval $(call gb_Executable_add_cobjects,gtktiledviewer,\
+    libreofficekit/qa/lokdocview_quad/lokdocview_quad \
+))
+
 $(eval $(call gb_Executable_add_exception_objects,gtktiledviewer,\
     libreofficekit/qa/gtktiledviewer/gtktiledviewer \
 ))
diff --git a/libreofficekit/qa/lokdocview_quad/lokdocview_quad.c b/libreofficekit/qa/lokdocview_quad/lokdocview_quad.c
new file mode 100644
index 0000000..cbff885
--- /dev/null
+++ b/libreofficekit/qa/lokdocview_quad/lokdocview_quad.c
@@ -0,0 +1,253 @@
+/* -*- 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 <sal/types.h>
+
+#define LOK_USE_UNSTABLE_API
+#include <LibreOfficeKit/LibreOfficeKit.h>
+
+#include "lokdocview_quad.h"
+
+static void lok_docview_quad_class_init( LOKDocViewQuadClass* pClass );
+static void lok_docview_quad_init( LOKDocViewQuad* pDocView );
+
+// We specifically need to destroy the document when closing in order to ensure
+// that lock files etc. are cleaned up.
+void lcl_onDestroy( LOKDocViewQuad* pDocView, gpointer pData )
+{
+    (void) pData;
+    if ( pDocView->pDocument )
+        pDocView->pDocument->pClass->destroy( pDocView->pDocument );
+    pDocView->pDocument = NULL;
+}
+
+SAL_DLLPUBLIC_EXPORT guint lok_docview_quad_get_type()
+{
+    static guint lok_docview_quad_type = 0;
+
+    if (!lok_docview_quad_type)
+    {
+        GtkTypeInfo lok_docview_quad_info =
+        {
+            "LokDocViewQuad",
+            sizeof( LOKDocViewQuad ),
+            sizeof( LOKDocViewQuadClass ),
+            (GtkClassInitFunc) lok_docview_quad_class_init,
+            (GtkObjectInitFunc) lok_docview_quad_init,
+            NULL,
+            NULL,
+            (GtkClassInitFunc) NULL
+        };
+
+        lok_docview_quad_type = gtk_type_unique( gtk_scrolled_window_get_type(), &lok_docview_quad_info );
+    }
+    return lok_docview_quad_type;
+}
+
+static void lok_docview_quad_class_init( LOKDocViewQuadClass* pClass )
+{
+    pClass->lok_docview_quad = NULL;
+}
+
+static void lok_docview_quad_init( LOKDocViewQuad* pDocView )
+{
+    int x, y;
+
+    // Gtk ScrolledWindow is apparently not fully initialised yet, we specifically
+    // have to set the [hv]adjustment to prevent GTK assertions from firing, see
+    // https://bugzilla.gnome.org/show_bug.cgi?id=438114 for more info.
+    gtk_scrolled_window_set_hadjustment( GTK_SCROLLED_WINDOW( pDocView ), NULL );
+    gtk_scrolled_window_set_vadjustment( GTK_SCROLLED_WINDOW( pDocView ), NULL );
+
+    pDocView->pEventBox = gtk_event_box_new();
+    gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW(pDocView),
+                                           pDocView->pEventBox );
+
+    pDocView->pGrid = gtk_table_new( 2, 2, TRUE );
+    gtk_container_add( GTK_CONTAINER( pDocView->pEventBox ), pDocView->pGrid );
+
+    for ( x = 0; x < 2; x++ )
+    {
+        for ( y = 0; y < 2; y++ )
+        {
+            pDocView->pCanvas[x][y] = gtk_image_new();
+            gtk_table_attach_defaults( GTK_TABLE( pDocView->pGrid ), pDocView->pCanvas[x][y], x, x+1, y, y+1 );
+            //gtk_container_add( GTK_CONTAINER( pDocView->pEventBox ), pDocView->pCanvas );
+            gtk_widget_show( pDocView->pCanvas[x][y] );
+
+            pDocView->pPixBuf[x][y] = 0;
+        }
+    }
+
+    gtk_widget_show( pDocView->pGrid );
+    gtk_widget_show( pDocView->pEventBox );
+
+    // TODO: figure out a clever view of getting paths set up.
+    pDocView->pOffice = 0;
+    pDocView->pDocument = 0;
+
+    pDocView->fZoom = 1;
+
+    gtk_signal_connect( GTK_OBJECT(pDocView), "destroy",
+                        GTK_SIGNAL_FUNC(lcl_onDestroy), NULL );
+}
+
+SAL_DLLPUBLIC_EXPORT GtkWidget* lok_docview_quad_new( LibreOfficeKit* pOffice )
+{
+    LOKDocViewQuad* pDocView = gtk_type_new( lok_docview_quad_get_type() );
+    pDocView->pOffice = pOffice;
+    return GTK_WIDGET( pDocView );
+}
+
+void renderDocument( LOKDocViewQuad* pDocView )
+{
+    long nWidth, nHeight;
+    int nRenderWidth, nRenderHeight;
+    int nRowStride;
+    int x, y;
+    GdkPixbuf* pTempBuf;
+
+    g_assert( pDocView->pDocument );
+
+    for ( x = 0; x < 2; x++ )
+    {
+        for ( y = 0; y < 2; y++ )
+        {
+            if ( pDocView->pPixBuf[x][y] )
+            {
+                g_object_unref( G_OBJECT( pDocView->pPixBuf[x][y] ) );
+            }
+        }
+    }
+
+    pDocView->pDocument->pClass->getDocumentSize( pDocView->pDocument, &nWidth, &nHeight );
+
+    // Draw the whole document at once (for now)
+
+    // TODO: we really should scale by screen DPI here -- 10 seems to be a vaguely
+    // correct factor for my screen at least.
+    nRenderWidth = nWidth * pDocView->fZoom / 10;
+    nRenderHeight = nHeight * pDocView->fZoom / 10;
+
+    // TOP-LEFT: standard
+    // TOP-RIGHT: 2x resolution rendered (post-scaled to 50%)
+    // BOTTOM-LEFT: 1/2 resolution rendered (post-scaled 200%)
+    // BOTTOM-RIGHT: 1/2 resolution rendered (post-scaled 400%)
+    pDocView->pPixBuf[0][0] = gdk_pixbuf_new( GDK_COLORSPACE_RGB,
+                                              TRUE, 8,
+                                              nRenderWidth / 2, nRenderHeight / 2 );
+    pDocView->pDocument->pClass->paintTile( pDocView->pDocument,
+                                            gdk_pixbuf_get_pixels( pDocView->pPixBuf[0][0] ),
+                                            nRenderWidth / 2, nRenderHeight / 2,
+                                            &nRowStride,
+                                            0, 0, // origin
+                                            nWidth / 2, nHeight / 2 );
+
+    pDocView->pPixBuf[1][0] = gdk_pixbuf_new( GDK_COLORSPACE_RGB,
+                                              TRUE, 8,
+                                              nRenderWidth, nRenderHeight );
+    pDocView->pDocument->pClass->paintTile( pDocView->pDocument,
+                                            gdk_pixbuf_get_pixels( pDocView->pPixBuf[1][0] ),
+                                            nRenderWidth, nRenderHeight,
+                                            &nRowStride,
+                                            nWidth / 2, 0,
+                                            nWidth / 2, nHeight / 2 );
+    pTempBuf = gdk_pixbuf_scale_simple( GDK_PIXBUF( pDocView->pPixBuf[1][0] ),
+                                        nRenderWidth / 2,
+                                        nRenderHeight / 2,
+                                        GDK_INTERP_BILINEAR );
+    g_object_unref( G_OBJECT( pDocView->pPixBuf[1][0] ) );
+    pDocView->pPixBuf[1][0] = pTempBuf;
+
+
+    pDocView->pPixBuf[0][1] = gdk_pixbuf_new( GDK_COLORSPACE_RGB,
+                                              TRUE, 8,
+                                              nRenderWidth / 4, nRenderHeight / 4 );
+    pDocView->pDocument->pClass->paintTile( pDocView->pDocument,
+                                            gdk_pixbuf_get_pixels( pDocView->pPixBuf[0][1] ),
+                                            nRenderWidth / 4, nRenderHeight / 4,
+                                            &nRowStride,
+                                            0, nHeight / 2,
+                                            nWidth / 2, nHeight / 2 );
+    pTempBuf = gdk_pixbuf_scale_simple( GDK_PIXBUF( pDocView->pPixBuf[0][1] ),
+                                        nRenderWidth / 2,
+                                        nRenderHeight / 2,
+                                        GDK_INTERP_BILINEAR );
+    g_object_unref( G_OBJECT( pDocView->pPixBuf[0][1] ) );
+    pDocView->pPixBuf[0][1] = pTempBuf;
+
+    pDocView->pPixBuf[1][1] = gdk_pixbuf_new( GDK_COLORSPACE_RGB,
+                                              TRUE, 8,
+                                              nRenderWidth / 8, nRenderHeight / 8 );
+    pDocView->pDocument->pClass->paintTile( pDocView->pDocument,
+                                            gdk_pixbuf_get_pixels( pDocView->pPixBuf[1][1] ),
+                                            nRenderWidth / 8, nRenderHeight / 8,
+                                            &nRowStride,
+                                            nWidth / 2, nHeight / 2,
+                                            nWidth / 2, nHeight / 2 );
+    pTempBuf = gdk_pixbuf_scale_simple( GDK_PIXBUF( pDocView->pPixBuf[1][1] ),
+                                        nRenderWidth / 2,
+                                        nRenderHeight / 2,
+                                        GDK_INTERP_BILINEAR );
+    g_object_unref( G_OBJECT( pDocView->pPixBuf[1][1] ) );
+    pDocView->pPixBuf[1][1] = pTempBuf;
+
+
+
+    // TODO: double check that the rowstride really matches what we expected,
+    // although presumably we'd already be crashing by now if things were
+    // wrong.
+    (void) nRowStride;
+
+    //    gtk_image_set_from_pixbuf( GTK_IMAGE( pDocView->pCanvas ), pDocView->pPixBuf );
+    for ( x = 0; x < 2; x++ )
+    {
+        for ( y = 0; y < 2; y++ )
+        {
+            gtk_image_set_from_pixbuf( GTK_IMAGE( pDocView->pCanvas[x][y] ), pDocView->pPixBuf[x][y] );
+        }
+    }
+}
+
+SAL_DLLPUBLIC_EXPORT gboolean lok_docview_quad_open_document( LOKDocViewQuad* pDocView, char* pPath )
+{
+    if ( pDocView->pDocument )
+    {
+        pDocView->pDocument->pClass->destroy( pDocView->pDocument );
+        pDocView->pDocument = NULL;
+    }
+
+    pDocView->pDocument = pDocView->pOffice->pClass->documentLoad( pDocView->pOffice,
+                                                                   pPath );
+    if ( !pDocView->pDocument )
+    {
+        // FIXME: should have a GError parameter and populate it.
+        char *pError = pDocView->pOffice->pClass->getError( pDocView->pOffice );
+        fprintf( stderr, "Error opening document '%s'\n", pError );
+        return FALSE;
+    }
+    else
+        renderDocument( pDocView );
+
+    return TRUE;
+}
+
+SAL_DLLPUBLIC_EXPORT void lok_docview_quad_set_zoom ( LOKDocViewQuad* pDocView, float fZoom )
+{
+    pDocView->fZoom = fZoom;
+    renderDocument( pDocView );
+    // TODO: maybe remember and reset positiong?
+}
+
+SAL_DLLPUBLIC_EXPORT float lok_docview_quad_get_zoom ( LOKDocViewQuad* pDocView )
+{
+    return pDocView->fZoom;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/libreofficekit/qa/lokdocview_quad/lokdocview_quad.h b/libreofficekit/qa/lokdocview_quad/lokdocview_quad.h
new file mode 100644
index 0000000..3124e5f
--- /dev/null
+++ b/libreofficekit/qa/lokdocview_quad/lokdocview_quad.h
@@ -0,0 +1,66 @@
+/* -*- 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_LOK_QA_INC_LIBREOFFICEKITGTK_H
+#define INCLUDED_LOK_QA_INC_LIBREOFFICEKITGTK_H
+
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+
+#define LOK_USE_UNSTABLE_API
+#include <LibreOfficeKit/LibreOfficeKit.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#define LOK_DOCVIEW_QUAD(obj)          GTK_CHECK_CAST (obj, lok_docview_quad_get_type(), LOKDocViewQuad)
+#define LOK_DOCVIEW_QUAD_CLASS(klass)  GTK_CHECK_CLASS_CAST (klass, lok_docview_quad_get_type(), LOKDocViewQuadClass)
+#define IS_LOK_DOCVIEW_QUAD(obj)       GTK_CHECK_TYPE (obj, lok_docview_quad_get_type())
+
+
+typedef struct _LOKDocViewQuad       LOKDocViewQuad;
+typedef struct _LOKDocViewQuadClass  LOKDocViewQuadClass;
+
+struct _LOKDocViewQuad
+{
+    GtkScrolledWindow scrollWindow;
+
+    GtkWidget* pEventBox;
+    GtkWidget* pGrid;
+    GtkWidget* pCanvas[2][2];
+    GdkPixbuf* pPixBuf[2][2];
+
+    float fZoom;
+
+    LibreOfficeKit* pOffice;
+    LibreOfficeKitDocument* pDocument;
+};
+
+struct _LOKDocViewQuadClass
+{
+  GtkScrolledWindowClass parent_class;
+
+  void (*lok_docview_quad) (LOKDocViewQuad* pDocView);
+};
+
+guint           lok_docview_quad_get_type        (void);
+GtkWidget*      lok_docview_quad_new             ( LibreOfficeKit* pOffice );
+gboolean        lok_docview_quad_open_document   (LOKDocViewQuad* pDocView,
+                                             char* pPath);
+void            lok_docview_quad_set_zoom        (LOKDocViewQuad* pDocView,
+                                             float fZoom);
+float           lok_docview_quad_get_zoom        (LOKDocViewQuad* pDocView);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif


More information about the Libreoffice-commits mailing list