Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : */
9 :
10 : #include <boost/scoped_array.hpp>
11 : #include <boost/scoped_ptr.hpp>
12 : #include <cppunit/TestFixture.h>
13 : #include <cppunit/plugin/TestPlugIn.h>
14 : #include <cppunit/extensions/HelperMacros.h>
15 : #include <cstdlib>
16 : #include <string>
17 : #include <stdio.h>
18 :
19 : #include <osl/file.hxx>
20 : #include <rtl/bootstrap.hxx>
21 :
22 : #include <config_options.h>
23 : // see use of ENABLE_RUNTIME_OPTIMIZATIONS in LibreOfficeKintInit.h
24 : #define LOK_USE_UNSTABLE_API
25 : #include <LibreOfficeKit/LibreOfficeKitInit.h>
26 : #include <LibreOfficeKit/LibreOfficeKit.hxx>
27 : #include <LibreOfficeKit/LibreOfficeKitEnums.h>
28 :
29 : using namespace ::boost;
30 : using namespace ::lok;
31 : using namespace ::std;
32 :
33 1 : OUString getFileURLFromSystemPath(OUString const & path)
34 : {
35 1 : OUString url;
36 1 : osl::FileBase::RC e = osl::FileBase::getFileURLFromSystemPath(path, url);
37 1 : CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, e);
38 1 : if (!url.endsWith("/"))
39 1 : url += "/";
40 1 : return url;
41 : }
42 :
43 : // We specifically don't use the usual BootStrapFixture, as LOK does
44 : // all it's own setup and bootstrapping, and should be useable in a
45 : // raw C++ program.
46 2 : class TiledRenderingTest : public ::CppUnit::TestFixture
47 : {
48 : public:
49 : const string m_sSrcRoot;
50 : const string m_sInstDir;
51 : const string m_sLOPath;
52 :
53 1 : TiledRenderingTest()
54 1 : : m_sSrcRoot( getenv( "SRC_ROOT" ) )
55 1 : , m_sInstDir( getenv( "INSTDIR" ) )
56 3 : , m_sLOPath( m_sInstDir + "/program" )
57 : {
58 1 : }
59 :
60 : // Currently it isn't possible to do multiple startup/shutdown
61 : // cycle of LOK in a single process -- hence we run all our tests
62 : // as one test, which simply carries out the individual test
63 : // components on the one Office instance that we retrieve.
64 : void runAllTests();
65 :
66 : void testDocumentLoadFail( Office* pOffice );
67 : void testDocumentTypes( Office* pOffice );
68 : #if 0
69 : void testImpressSlideNames( Office* pOffice );
70 : void testOverlay( Office* pOffice );
71 : #endif
72 :
73 2 : CPPUNIT_TEST_SUITE(TiledRenderingTest);
74 1 : CPPUNIT_TEST(runAllTests);
75 5 : CPPUNIT_TEST_SUITE_END();
76 : };
77 :
78 1 : void TiledRenderingTest::runAllTests()
79 : {
80 : // set UserInstallation to user profile dir in test/user-template
81 1 : const char* pWorkdirRoot = getenv("WORKDIR_FOR_BUILD");
82 1 : OUString aWorkdirRootPath = OUString::createFromAscii(pWorkdirRoot);
83 2 : OUString aWorkdirRootURL = getFileURLFromSystemPath(aWorkdirRootPath);
84 2 : OUString sUserInstallURL = aWorkdirRootURL + "/unittest";
85 1 : rtl::Bootstrap::set(OUString("UserInstallation"), sUserInstallURL);
86 :
87 : scoped_ptr< Office > pOffice( lok_cpp_init(
88 2 : m_sLOPath.c_str() ) );
89 1 : CPPUNIT_ASSERT( pOffice.get() );
90 :
91 1 : testDocumentLoadFail( pOffice.get() );
92 2 : testDocumentTypes( pOffice.get() );
93 : #if 0
94 : testImpressSlideNames( pOffice.get() );
95 : testOverlay( pOffice.get() );
96 : #endif
97 1 : }
98 :
99 1 : void TiledRenderingTest::testDocumentLoadFail( Office* pOffice )
100 : {
101 1 : const string sDocPath = m_sSrcRoot + "/libreofficekit/qa/data/IDONOTEXIST.odt";
102 2 : scoped_ptr< Document> pDocument( pOffice->documentLoad( sDocPath.c_str() ) );
103 2 : CPPUNIT_ASSERT( !pDocument.get() );
104 : // TODO: we probably want to have some way of returning what
105 : // the cause of failure was. getError() will return
106 : // something along the lines of:
107 : // "Unsupported URL <file:///SRC_ROOT/libreofficekit/qa/data/IDONOTEXIST.odt>: "type detection failed""
108 1 : }
109 :
110 : // Our dumped .png files end up in
111 : // workdir/CppunitTest/libreofficekit_tiledrendering.test.core
112 :
113 1 : int getDocumentType( Office* pOffice, const string& rPath )
114 : {
115 1 : scoped_ptr< Document> pDocument( pOffice->documentLoad( rPath.c_str() ) );
116 1 : CPPUNIT_ASSERT( pDocument.get() );
117 1 : return pDocument->getDocumentType();
118 : }
119 :
120 1 : void TiledRenderingTest::testDocumentTypes( Office* pOffice )
121 : {
122 1 : const string sTextDocPath = m_sSrcRoot + "/libreofficekit/qa/data/blank_text.odt";
123 2 : const string sTextLockFile = m_sSrcRoot +"/libreofficekit/qa/data/.~lock.blank_text.odt#";
124 :
125 : // FIXME: same comment as below wrt lockfile removal.
126 1 : remove( sTextLockFile.c_str() );
127 :
128 2 : std::unique_ptr<Document> pDocument(pOffice->documentLoad( sTextDocPath.c_str()));
129 1 : CPPUNIT_ASSERT(pDocument.get());
130 1 : CPPUNIT_ASSERT_EQUAL(LOK_DOCTYPE_TEXT, static_cast<LibreOfficeKitDocumentType>(pDocument->getDocumentType()));
131 : // This crashed.
132 1 : pDocument->postUnoCommand(".uno:Bold");
133 :
134 2 : const string sPresentationDocPath = m_sSrcRoot + "/libreofficekit/qa/data/blank_presentation.odp";
135 2 : const string sPresentationLockFile = m_sSrcRoot +"/libreofficekit/qa/data/.~lock.blank_presentation.odp#";
136 :
137 : // FIXME: same comment as below wrt lockfile removal.
138 1 : remove( sPresentationLockFile.c_str() );
139 :
140 2 : CPPUNIT_ASSERT( getDocumentType( pOffice, sPresentationDocPath ) == LOK_DOCTYPE_PRESENTATION );
141 :
142 : // TODO: do this for all supported document types
143 1 : }
144 :
145 : #if 0
146 : void TiledRenderingTest::testImpressSlideNames( Office* pOffice )
147 : {
148 : const string sDocPath = m_sSrcRoot + "/libreofficekit/qa/data/impress_slidenames.odp";
149 : const string sLockFile = m_sSrcRoot +"/libreofficekit/qa/data/.~lock.impress_slidenames.odp#";
150 :
151 : // FIXME: this is a temporary hack: LOK will fail when trying to open a
152 : // locked file, and since we're reusing the file for a different unit
153 : // test it's entirely possible that an unwanted lock file will remain.
154 : // Hence forcefully remove it here.
155 : remove( sLockFile.c_str() );
156 :
157 : scoped_ptr< Document> pDocument( pOffice->documentLoad( sDocPath.c_str() ) );
158 :
159 : CPPUNIT_ASSERT( pDocument->getParts() == 3 );
160 : CPPUNIT_ASSERT( strcmp( pDocument->getPartName( 0 ), "TestText1" ) == 0 );
161 : CPPUNIT_ASSERT( strcmp( pDocument->getPartName( 1 ), "TestText2" ) == 0 );
162 : // The third slide hasn't had a name given to it (i.e. using the rename
163 : // context menu in Impress), thus it should (as far as I can determine)
164 : // have a localised version of "Slide 3".
165 : }
166 :
167 : static void dumpRGBABitmap( const OUString& rPath, const unsigned char* pBuffer,
168 : const int nWidth, const int nHeight )
169 : {
170 : Bitmap aBitmap( Size( nWidth, nHeight ), 32 );
171 : Bitmap::ScopedWriteAccess pWriteAccess( aBitmap );
172 : memcpy( pWriteAccess->GetBuffer(), pBuffer, 4*nWidth*nHeight );
173 :
174 : BitmapEx aBitmapEx( aBitmap );
175 : vcl::PNGWriter aWriter( aBitmapEx );
176 : SvFileStream sOutput( rPath, StreamMode::WRITE );
177 : aWriter.Write( sOutput );
178 : sOutput.Close();
179 : }
180 :
181 : void TiledRenderingTest::testOverlay( Office* /*pOffice*/ )
182 : {
183 : const string sDocPath = m_sSrcRoot + "/odk/examples/java/DocumentHandling/test/test1.odt";
184 : const string sLockFile = m_sSrcRoot + "/odk/examples/java/DocumentHandling/test/.~lock.test1.odt#";
185 :
186 : // FIXME: this is a temporary hack: LOK will fail when trying to open a
187 : // locked file, and since we're reusing the file for a different unit
188 : // test it's entirely possible that an unwanted lock file will remain.
189 : // Hence forcefully remove it here.
190 : remove( sLockFile.c_str() );
191 : scoped_ptr< Office > pOffice( lok_cpp_init(
192 : m_sLOPath.c_str() ) );
193 : assert( pOffice.get() );
194 :
195 : scoped_ptr< Document> pDocument( pOffice->documentLoad(
196 : sDocPath.c_str() ) );
197 :
198 : if ( !pDocument.get() )
199 : {
200 : fprintf( stderr, "documentLoad failed: %s\n", pOffice->getError() );
201 : CPPUNIT_FAIL( "Document could not be loaded -- tiled rendering not possible." );
202 : }
203 :
204 : // We render one large tile, then subdivide it into 4 and render those parts, and finally
205 : // iterate over each smaller tile and check whether their contents match the large
206 : // tile.
207 : const int nTotalWidthPix = 512;
208 : const int nTotalHeightPix = 512;
209 : int nRowStride;
210 :
211 : long nTotalWidthDoc;
212 : long nTotalHeightDoc;
213 : // pDocument->getDocumentSize( &nTotalWidthDoc, &nTotalHeightDoc );
214 : // TODO: make sure we select an actually interesting part of the document
215 : // for this comparison, i.e. ideally an image and lots of text, in order
216 : // to test as many edge cases as possible.
217 : // Alternatively we could rewrite this to actually grab the document size
218 : // and iterate over it (subdividing into an arbitrary number of tiles rather
219 : // than our less sophisticated test of just 4 sub-tiles).
220 : nTotalWidthDoc = 8000;
221 : nTotalHeightDoc = 9000;
222 :
223 : scoped_array< unsigned char > pLarge( new unsigned char[ 4*nTotalWidthPix*nTotalHeightPix ] );
224 : pDocument->paintTile( pLarge.get(), nTotalWidthPix, nTotalHeightPix, &nRowStride,
225 : 0, 0,
226 : nTotalWidthDoc, nTotalHeightDoc );
227 : dumpRGBABitmap( "large.png", pLarge.get(), nTotalWidthPix, nTotalHeightPix );
228 :
229 : scoped_array< unsigned char > pSmall[4];
230 : for ( int i = 0; i < 4; i++ )
231 : {
232 : pSmall[i].reset( new unsigned char[ 4*(nTotalWidthPix/2)*(nTotalHeightPix/2) ] );
233 : pDocument->paintTile( pSmall[i].get(), nTotalWidthPix / 2, nTotalHeightPix / 2, &nRowStride,
234 : // Tile 0/2: left. Tile 1/3: right. Tile 0/1: top. Tile 2/3: bottom
235 : ((i%2 == 0) ? 0 : nTotalWidthDoc / 2), ((i < 2 ) ? 0 : nTotalHeightDoc / 2),
236 : nTotalWidthDoc / 2, nTotalHeightDoc / 2);
237 : dumpRGBABitmap( "small_" + OUString::number(i) + ".png",
238 : pSmall[i].get(), nTotalWidthPix/2, nTotalHeightPix/2 );
239 : }
240 :
241 : // Iterate over each pixel of the sub-tile, and compare that pixel for every
242 : // tile with the equivalent super-tile pixel.
243 : for ( int i = 0; i < 4*nTotalWidthPix / 2 * nTotalHeightPix / 2; i++ )
244 : {
245 : int xSmall = i % (4*nTotalWidthPix/2);
246 : int ySmall = i / (4*nTotalWidthPix/2);
247 : // Iterate over our array of tiles
248 : // However for now we only bother with the top-left
249 : // tile as the other ones don't match yet...
250 : for ( int x = 0; x < 2; x++ )
251 : {
252 : for ( int y = 0; y < 2; y++ )
253 : {
254 : int xLarge = (x * (4 * nTotalWidthPix / 2)) + xSmall;
255 : int yLarge = (y * (nTotalHeightPix / 2)) + ySmall;
256 : CPPUNIT_ASSERT( pSmall[2*y+x][i] == pLarge[yLarge*4*nTotalWidthPix + xLarge] );
257 : }
258 : }
259 : }
260 : }
261 : #endif
262 :
263 1 : CPPUNIT_TEST_SUITE_REGISTRATION(TiledRenderingTest);
264 :
265 4 : CPPUNIT_PLUGIN_IMPLEMENT();
266 :
267 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|