Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / sdext / qa / unit / pdfimport.cxx
blobc344394ab1c3bf3b986baaa772c40cae367326ad
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <config_features.h>
22 #include <outputwrap.hxx>
23 #include <contentsink.hxx>
24 #include <pdfihelper.hxx>
25 #include <wrapper.hxx>
26 #include <pdfparse.hxx>
27 #include <../pdfiadaptor.hxx>
29 #include <rtl/math.hxx>
30 #include <osl/file.hxx>
31 #include <comphelper/sequence.hxx>
32 #include <comphelper/string.hxx>
34 #include <cppunit/TestAssert.h>
35 #include <cppunit/extensions/HelperMacros.h>
36 #include <cppunit/plugin/TestPlugIn.h>
37 #include <test/bootstrapfixture.hxx>
38 #include <test/xmltesttools.hxx>
40 #include <com/sun/star/geometry/RealRectangle2D.hpp>
41 #include <com/sun/star/geometry/RealSize2D.hpp>
42 #include <com/sun/star/rendering/PathJoinType.hpp>
43 #include <com/sun/star/rendering/PathCapType.hpp>
44 #include <com/sun/star/rendering/BlendMode.hpp>
46 #include <basegfx/utils/canvastools.hxx>
47 #include <basegfx/polygon/b2dpolypolygon.hxx>
48 #include <basegfx/polygon/b2dpolypolygontools.hxx>
49 #include <basegfx/polygon/b2dpolygonclipper.hxx>
51 #include <unordered_map>
52 #include <vector>
54 #include <rtl/ustring.hxx>
55 #include <rtl/ref.hxx>
57 using namespace ::pdfparse;
58 using namespace ::pdfi;
59 using namespace ::com::sun::star;
61 namespace
64 class TestSink : public ContentSink
66 public:
67 TestSink() :
68 m_nNextFontId( 1 ),
69 m_aIdToFont(),
70 m_aFontToId(),
71 m_aGCStack(1),
72 m_aPageSize(),
73 m_aHyperlinkBounds(),
74 m_aURI(),
75 m_aTextOut(),
76 m_nNumPages(0),
77 m_bPageEnded(false),
78 m_bRedCircleSeen(false),
79 m_bGreenStrokeSeen(false),
80 m_bDashedLineSeen(false),
81 m_bImageSeen(false)
84 void check()
86 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "A4 page size (in 100th of points): Width", 79400, m_aPageSize.Width, 0.00000001);
87 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "A4 page size (in 100th of points): Height", 59500, m_aPageSize.Height, 0.0000001 );
88 CPPUNIT_ASSERT_MESSAGE( "endPage() called", m_bPageEnded );
89 CPPUNIT_ASSERT_EQUAL_MESSAGE( "Num pages equal one", sal_Int32(1), m_nNumPages );
90 CPPUNIT_ASSERT_MESSAGE( "Correct hyperlink bounding box",
91 rtl::math::approxEqual(m_aHyperlinkBounds.X1,34.7 ) );
92 CPPUNIT_ASSERT_MESSAGE( "Correct hyperlink bounding box",
93 rtl::math::approxEqual(m_aHyperlinkBounds.Y1,386.0) );
94 CPPUNIT_ASSERT_MESSAGE( "Correct hyperlink bounding box",
95 rtl::math::approxEqual(m_aHyperlinkBounds.X2,166.7) );
96 CPPUNIT_ASSERT_MESSAGE( "Correct hyperlink bounding box",
97 rtl::math::approxEqual(m_aHyperlinkBounds.Y2,406.2) );
98 CPPUNIT_ASSERT_EQUAL_MESSAGE( "Correct hyperlink URI", OUString("http://download.openoffice.org/"), m_aURI );
100 const char* const sText = " \n \nThis is a testtext\nNew paragraph,\nnew line\n"
101 "Hyperlink, this is\n?\nThis is more text\noutline mode\n?\nNew paragraph\n";
102 OString aTmp;
103 m_aTextOut.makeStringAndClear().convertToString( &aTmp,
104 RTL_TEXTENCODING_ASCII_US,
105 OUSTRING_TO_OSTRING_CVTFLAGS );
106 CPPUNIT_ASSERT_EQUAL_MESSAGE( "Imported text is \"This is a testtext New paragraph, new line"
107 " Hyperlink, this is * This is more text outline mode * New paragraph\"",
108 aTmp, OString(sText) );
110 CPPUNIT_ASSERT_MESSAGE( "red circle seen in input", m_bRedCircleSeen );
111 CPPUNIT_ASSERT_MESSAGE( "green stroke seen in input", m_bGreenStrokeSeen );
112 CPPUNIT_ASSERT_MESSAGE( "dashed line seen in input", m_bDashedLineSeen );
113 CPPUNIT_ASSERT_MESSAGE( "image seen in input", m_bImageSeen );
116 private:
117 GraphicsContext& getCurrentContext() { return m_aGCStack.back(); }
119 // ContentSink interface implementation
120 virtual void setPageNum( sal_Int32 nNumPages ) override
122 m_nNumPages = nNumPages;
125 virtual void startPage( const geometry::RealSize2D& rSize ) override
127 m_aPageSize = rSize;
130 virtual void endPage() override
132 m_bPageEnded = true;
135 virtual void hyperLink( const geometry::RealRectangle2D& rBounds,
136 const OUString& rURI ) override
138 m_aHyperlinkBounds = rBounds;
139 m_aURI = rURI;
142 virtual void pushState() override
144 GraphicsContextStack::value_type const a(m_aGCStack.back());
145 m_aGCStack.push_back(a);
148 virtual void popState() override
150 m_aGCStack.pop_back();
153 virtual void setTransformation( const geometry::AffineMatrix2D& rMatrix ) override
155 basegfx::unotools::homMatrixFromAffineMatrix(
156 getCurrentContext().Transformation,
157 rMatrix );
160 virtual void setLineDash( const uno::Sequence<double>& dashes,
161 double start ) override
163 GraphicsContext& rContext( getCurrentContext() );
164 if( dashes.hasElements() )
165 comphelper::sequenceToContainer(rContext.DashArray,dashes);
166 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "line dashing start offset", 0.0, start, 0.000000001 );
169 virtual void setFlatness( double nFlatness ) override
171 getCurrentContext().Flatness = nFlatness;
174 virtual void setLineJoin(sal_Int8 nJoin) override
176 getCurrentContext().LineJoin = nJoin;
179 virtual void setLineCap(sal_Int8 nCap) override
181 getCurrentContext().LineCap = nCap;
184 virtual void setMiterLimit(double nVal) override
186 getCurrentContext().MiterLimit = nVal;
189 virtual void setLineWidth(double nVal) override
191 getCurrentContext().LineWidth = nVal;
194 virtual void setFillColor( const rendering::ARGBColor& rColor ) override
196 getCurrentContext().FillColor = rColor;
199 virtual void setStrokeColor( const rendering::ARGBColor& rColor ) override
201 getCurrentContext().LineColor = rColor;
204 virtual void setFont( const FontAttributes& rFont ) override
206 FontToIdMap::const_iterator it = m_aFontToId.find( rFont );
207 if( it != m_aFontToId.end() )
208 getCurrentContext().FontId = it->second;
209 else
211 m_aFontToId[ rFont ] = m_nNextFontId;
212 m_aIdToFont[ m_nNextFontId ] = rFont;
213 getCurrentContext().FontId = m_nNextFontId;
214 m_nNextFontId++;
218 virtual void strokePath( const uno::Reference<rendering::XPolyPolygon2D>& rPath ) override
220 GraphicsContext& rContext( getCurrentContext() );
221 basegfx::B2DPolyPolygon aPath = basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(rPath);
222 aPath.transform( rContext.Transformation );
224 if( rContext.DashArray.empty() )
226 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Line color is green", 1.0, rContext.LineColor.Alpha, 0.00000001);
227 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Line color is green", 0.0, rContext.LineColor.Blue, 0.00000001);
228 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Line color is green", 1.0, rContext.LineColor.Green, 0.00000001);
229 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Line color is green", 0.0, rContext.LineColor.Red, 0.00000001);
231 CPPUNIT_ASSERT_MESSAGE( "Line width is 0",
232 rtl::math::approxEqual(rContext.LineWidth, 28.3) );
234 static constexpr OUStringLiteral sExportString = u"m53570 7650-35430 24100";
235 CPPUNIT_ASSERT_EQUAL_MESSAGE( "Stroke is m535.7 518.5-354.3-241",
236 OUString(sExportString), basegfx::utils::exportToSvgD( aPath, true, true, false ) );
238 m_bGreenStrokeSeen = true;
240 else
242 CPPUNIT_ASSERT_EQUAL_MESSAGE( "Dash array consists of four entries", std::vector<double>::size_type(4), rContext.DashArray.size());
243 CPPUNIT_ASSERT_DOUBLES_EQUAL( 14.3764, rContext.DashArray[0], 1E-12 );
244 CPPUNIT_ASSERT_DOUBLES_EQUAL( rContext.DashArray[0], rContext.DashArray[1], 1E-12 );
245 CPPUNIT_ASSERT_DOUBLES_EQUAL( rContext.DashArray[1], rContext.DashArray[2], 1E-12 );
246 CPPUNIT_ASSERT_DOUBLES_EQUAL( rContext.DashArray[2], rContext.DashArray[3], 1E-12 );
248 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Line color is black", 1.0, rContext.LineColor.Alpha, 0.00000001);
249 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Line color is black", 0.0, rContext.LineColor.Blue, 0.00000001);
250 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Line color is black", 0.0, rContext.LineColor.Green, 0.00000001);
251 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Line color is black", 0.0, rContext.LineColor.Red, 0.00000001);
253 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Line width is 0",
254 0, rContext.LineWidth, 0.0000001 );
256 static constexpr OUStringLiteral sExportString = u"m49890 5670.00000000001-35430 24090";
257 CPPUNIT_ASSERT_EQUAL_MESSAGE( "Stroke is m49890 5670.00000000001-35430 24090",
258 OUString(sExportString), basegfx::utils::exportToSvgD( aPath, true, true, false ) );
260 m_bDashedLineSeen = true;
262 CPPUNIT_ASSERT_EQUAL_MESSAGE( "Blend mode is normal",
263 rendering::BlendMode::NORMAL, rContext.BlendMode );
264 CPPUNIT_ASSERT_EQUAL_MESSAGE( "Join type is round",
265 rendering::PathJoinType::ROUND, rContext.LineJoin );
266 CPPUNIT_ASSERT_EQUAL_MESSAGE( "Cap type is butt",
267 rendering::PathCapType::BUTT, rContext.LineCap );
268 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Line miter limit is 10",
269 10, rContext.MiterLimit, 0.0000001 );
270 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Flatness is 0",
271 1, rContext.Flatness, 0.00000001 );
272 CPPUNIT_ASSERT_EQUAL_MESSAGE( "Font id is 0",
273 sal_Int32(0), rContext.FontId );
276 virtual void fillPath( const uno::Reference<rendering::XPolyPolygon2D>& rPath ) override
278 GraphicsContext& rContext( getCurrentContext() );
279 basegfx::B2DPolyPolygon aPath = basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(rPath);
280 aPath.transform( rContext.Transformation );
282 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Line color is black", 1.0, rContext.LineColor.Alpha, 0.00000001);
283 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Line color is black", 0.0, rContext.LineColor.Blue, 0.00000001);
284 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Line color is black", 0.0, rContext.LineColor.Green, 0.00000001);
285 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Line color is black", 0.0, rContext.LineColor.Red, 0.00000001);
287 CPPUNIT_ASSERT_EQUAL_MESSAGE( "Blend mode is normal",
288 rendering::BlendMode::NORMAL, rContext.BlendMode );
289 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Flatness is 10",
290 10, rContext.Flatness, 0.00000001 );
291 CPPUNIT_ASSERT_EQUAL_MESSAGE( "Font id is 0",
292 sal_Int32(0), rContext.FontId );
295 virtual void eoFillPath( const uno::Reference<rendering::XPolyPolygon2D>& rPath ) override
297 GraphicsContext& rContext( getCurrentContext() );
298 basegfx::B2DPolyPolygon aPath = basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(rPath);
299 aPath.transform( rContext.Transformation );
301 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Line color is black", 1.0, rContext.LineColor.Alpha, 0.00000001);
302 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Line color is black", 0.0, rContext.LineColor.Blue, 0.00000001);
303 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Line color is black", 0.0, rContext.LineColor.Green, 0.00000001);
304 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Line color is black", 0.0, rContext.LineColor.Red, 0.00000001);
306 CPPUNIT_ASSERT_EQUAL_MESSAGE( "Blend mode is normal",
307 rendering::BlendMode::NORMAL, rContext.BlendMode );
308 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Flatness is 0",
309 1, rContext.Flatness, 0.00000001 );
310 CPPUNIT_ASSERT_EQUAL_MESSAGE( "Font id is 0",
311 sal_Int32(0), rContext.FontId );
313 static constexpr OUStringLiteral sExportString
314 = u"m12050 49610c-4310 0-7800-3490-7800-7800 0-4300 "
315 "3490-7790 7800-7790 4300 0 7790 3490 7790 7790 0 4310-3490 7800-7790 7800z";
316 CPPUNIT_ASSERT_EQUAL_MESSAGE( "Stroke is a 4-bezier circle",
317 OUString(sExportString), basegfx::utils::exportToSvgD( aPath, true, true, false ) );
319 m_bRedCircleSeen = true;
322 virtual void intersectClip(const uno::Reference<rendering::XPolyPolygon2D>& rPath) override
324 basegfx::B2DPolyPolygon aNewClip = basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(rPath);
325 basegfx::B2DPolyPolygon aCurClip = getCurrentContext().Clip;
327 if( aCurClip.count() ) // #i92985# adapted API from (..., false, false) to (..., true, false)
328 aNewClip = basegfx::utils::clipPolyPolygonOnPolyPolygon( aCurClip, aNewClip, true, false );
330 getCurrentContext().Clip = aNewClip;
333 virtual void intersectEoClip(const uno::Reference<rendering::XPolyPolygon2D>& rPath) override
335 basegfx::B2DPolyPolygon aNewClip = basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(rPath);
336 basegfx::B2DPolyPolygon aCurClip = getCurrentContext().Clip;
338 if( aCurClip.count() ) // #i92985# adapted API from (..., false, false) to (..., true, false)
339 aNewClip = basegfx::utils::clipPolyPolygonOnPolyPolygon( aCurClip, aNewClip, true, false );
341 getCurrentContext().Clip = aNewClip;
344 virtual void drawGlyphs( const OUString& rGlyphs,
345 const geometry::RealRectangle2D& /*rRect*/,
346 const geometry::Matrix2D& /*rFontMatrix*/,
347 double /*fontSize*/) override
349 m_aTextOut.append(rGlyphs);
352 virtual void endText() override
354 m_aTextOut.append( "\n" );
357 virtual void drawMask(const uno::Sequence<beans::PropertyValue>& xBitmap,
358 bool /*bInvert*/ ) override
360 CPPUNIT_ASSERT_EQUAL_MESSAGE( "drawMask received two properties",
361 sal_Int32(3), xBitmap.getLength() );
362 CPPUNIT_ASSERT_EQUAL_MESSAGE( "drawMask got URL param",
363 OUString("URL"), xBitmap[0].Name );
364 CPPUNIT_ASSERT_EQUAL_MESSAGE( "drawMask got InputStream param",
365 OUString("InputStream"), xBitmap[1].Name );
368 virtual void drawImage(const uno::Sequence<beans::PropertyValue>& xBitmap ) override
370 CPPUNIT_ASSERT_EQUAL_MESSAGE( "drawImage received two properties",
371 sal_Int32(3), xBitmap.getLength() );
372 CPPUNIT_ASSERT_EQUAL_MESSAGE( "drawImage got URL param",
373 OUString("URL"), xBitmap[0].Name );
374 CPPUNIT_ASSERT_EQUAL_MESSAGE( "drawImage got InputStream param",
375 OUString("InputStream"), xBitmap[1].Name );
376 m_bImageSeen = true;
379 virtual void drawColorMaskedImage(const uno::Sequence<beans::PropertyValue>& xBitmap,
380 const uno::Sequence<uno::Any>& /*xMaskColors*/ ) override
382 CPPUNIT_ASSERT_EQUAL_MESSAGE( "drawColorMaskedImage received two properties",
383 sal_Int32(3), xBitmap.getLength() );
384 CPPUNIT_ASSERT_EQUAL_MESSAGE( "drawColorMaskedImage got URL param",
385 OUString("URL"), xBitmap[0].Name );
386 CPPUNIT_ASSERT_EQUAL_MESSAGE( "drawColorMaskedImage got InputStream param",
387 OUString("InputStream"), xBitmap[1].Name );
390 virtual void drawMaskedImage(const uno::Sequence<beans::PropertyValue>& xBitmap,
391 const uno::Sequence<beans::PropertyValue>& xMask,
392 bool /*bInvertMask*/) override
394 CPPUNIT_ASSERT_EQUAL_MESSAGE( "drawMaskedImage received two properties #1",
395 sal_Int32(3), xBitmap.getLength() );
396 CPPUNIT_ASSERT_EQUAL_MESSAGE( "drawMaskedImage got URL param #1",
397 OUString("URL"), xBitmap[0].Name );
398 CPPUNIT_ASSERT_EQUAL_MESSAGE( "drawMaskedImage got InputStream param #1",
399 OUString("InputStream"), xBitmap[1].Name );
401 CPPUNIT_ASSERT_EQUAL_MESSAGE( "drawMaskedImage received two properties #2",
402 sal_Int32(3), xMask.getLength() );
403 CPPUNIT_ASSERT_EQUAL_MESSAGE( "drawMaskedImage got URL param #2",
404 OUString("URL"), xMask[0].Name );
405 CPPUNIT_ASSERT_EQUAL_MESSAGE( "drawMaskedImage got InputStream param #2",
406 OUString("InputStream"), xMask[1].Name );
409 virtual void drawAlphaMaskedImage(const uno::Sequence<beans::PropertyValue>& xBitmap,
410 const uno::Sequence<beans::PropertyValue>& xMask) override
412 CPPUNIT_ASSERT_EQUAL_MESSAGE( "drawAlphaMaskedImage received two properties #1",
413 sal_Int32(3), xBitmap.getLength() );
414 CPPUNIT_ASSERT_EQUAL_MESSAGE( "drawAlphaMaskedImage got URL param #1",
415 OUString("URL"), xBitmap[0].Name );
416 CPPUNIT_ASSERT_EQUAL_MESSAGE( "drawAlphaMaskedImage got InputStream param #1",
417 OUString("InputStream"), xBitmap[1].Name );
419 CPPUNIT_ASSERT_EQUAL_MESSAGE( "drawAlphaMaskedImage received two properties #2",
420 sal_Int32(3), xMask.getLength() );
421 CPPUNIT_ASSERT_EQUAL_MESSAGE( "drawAlphaMaskedImage got URL param #2",
422 OUString("URL"), xMask[0].Name );
423 CPPUNIT_ASSERT_EQUAL_MESSAGE( "drawAlphaMaskedImage got InputStream param #2",
424 OUString("InputStream"), xMask[1].Name );
427 virtual void setTextRenderMode( sal_Int32 ) override
431 typedef std::unordered_map<sal_Int32,FontAttributes> IdToFontMap;
432 typedef std::unordered_map<FontAttributes,sal_Int32,FontAttrHash> FontToIdMap;
434 typedef std::vector<GraphicsContext> GraphicsContextStack;
436 sal_Int32 m_nNextFontId;
437 IdToFontMap m_aIdToFont;
438 FontToIdMap m_aFontToId;
440 GraphicsContextStack m_aGCStack;
441 geometry::RealSize2D m_aPageSize;
442 geometry::RealRectangle2D m_aHyperlinkBounds;
443 OUString m_aURI;
444 OUStringBuffer m_aTextOut;
445 sal_Int32 m_nNumPages;
446 bool m_bPageEnded;
447 bool m_bRedCircleSeen;
448 bool m_bGreenStrokeSeen;
449 bool m_bDashedLineSeen;
450 bool m_bImageSeen;
453 class PDFITest : public test::BootstrapFixture, public XmlTestTools
455 public:
456 void testXPDFParser()
458 #if HAVE_FEATURE_POPPLER
459 auto pSink = std::make_shared<TestSink>();
460 CPPUNIT_ASSERT(
461 pdfi::xpdf_ImportFromFile(
462 m_directories.getURLFromSrc(u"/sdext/source/pdfimport/test/testinput.pdf"),
463 pSink,
464 uno::Reference< task::XInteractionHandler >(),
465 OUString(),
466 getComponentContext(), "" ) );
467 pSink->check();
468 #endif
471 void testOdfDrawExport()
473 #if HAVE_FEATURE_POPPLER
474 rtl::Reference<pdfi::PDFIRawAdaptor> xAdaptor( new pdfi::PDFIRawAdaptor(OUString(), getComponentContext()) );
475 xAdaptor->setTreeVisitorFactory( createDrawTreeVisitorFactory() );
477 OUString tempFileURL;
478 CPPUNIT_ASSERT_EQUAL( osl::File::E_None, osl::File::createTempFile( nullptr, nullptr, &tempFileURL ) );
479 osl::File::remove( tempFileURL ); // FIXME the below apparently fails silently if the file already exists
480 CPPUNIT_ASSERT_MESSAGE("Exporting to ODF",
481 xAdaptor->odfConvert( m_directories.getURLFromSrc(u"/sdext/source/pdfimport/test/testinput.pdf"),
482 new OutputWrap(tempFileURL),
483 nullptr ));
484 osl::File::remove( tempFileURL );
485 #endif
488 void testOdfWriterExport()
490 #if HAVE_FEATURE_POPPLER
491 rtl::Reference<pdfi::PDFIRawAdaptor> xAdaptor( new pdfi::PDFIRawAdaptor(OUString(), getComponentContext()) );
492 xAdaptor->setTreeVisitorFactory( createWriterTreeVisitorFactory() );
494 OUString tempFileURL;
495 CPPUNIT_ASSERT_EQUAL( osl::File::E_None, osl::File::createTempFile( nullptr, nullptr, &tempFileURL ) );
496 osl::File::remove( tempFileURL ); // FIXME the below apparently fails silently if the file already exists
497 CPPUNIT_ASSERT_MESSAGE("Exporting to ODF",
498 xAdaptor->odfConvert( m_directories.getURLFromSrc(u"/sdext/source/pdfimport/test/testinput.pdf"),
499 new OutputWrap(tempFileURL),
500 nullptr ));
501 osl::File::remove( tempFileURL );
502 #endif
505 void testTdf96993()
507 #if HAVE_FEATURE_POPPLER
508 rtl::Reference<pdfi::PDFIRawAdaptor> xAdaptor(new pdfi::PDFIRawAdaptor(OUString(), getComponentContext()));
509 xAdaptor->setTreeVisitorFactory(createDrawTreeVisitorFactory());
511 OString aOutput;
512 CPPUNIT_ASSERT_MESSAGE("Exporting to ODF",
513 xAdaptor->odfConvert(m_directories.getURLFromSrc(u"/sdext/source/pdfimport/test/testTdf96993.pdf"),
514 new OutputWrapString(aOutput),
515 nullptr));
516 // This ensures that the imported image arrives properly flipped
517 CPPUNIT_ASSERT(aOutput.indexOf("draw:transform=\"matrix(18520.8333333333 0 0 26281.9444444444 0 0)\"") != -1);
518 #endif
521 void testTdf98421()
523 #if HAVE_FEATURE_POPPLER
524 rtl::Reference<pdfi::PDFIRawAdaptor> xAdaptor(new pdfi::PDFIRawAdaptor(OUString(), getComponentContext()));
525 xAdaptor->setTreeVisitorFactory(createWriterTreeVisitorFactory());
527 OString aOutput;
528 CPPUNIT_ASSERT_MESSAGE("Exporting to ODF",
529 xAdaptor->odfConvert(m_directories.getURLFromSrc(u"/sdext/source/pdfimport/test/testTdf96993.pdf"),
530 new OutputWrapString(aOutput),
531 nullptr));
532 // This ensures that the imported image arrives properly flipped
533 CPPUNIT_ASSERT(aOutput.indexOf("draw:transform=\"scale( 1.0 -1.0 ) translate( 0mm 0mm )\"") != -1);
534 CPPUNIT_ASSERT(aOutput.indexOf("svg:height=\"-262.82mm\"") != -1);
535 #endif
538 void testTdf105536()
540 #if HAVE_FEATURE_POPPLER
541 rtl::Reference<pdfi::PDFIRawAdaptor> xAdaptor(new pdfi::PDFIRawAdaptor(OUString(), getComponentContext()));
542 xAdaptor->setTreeVisitorFactory(createDrawTreeVisitorFactory());
544 OString aOutput;
545 CPPUNIT_ASSERT_MESSAGE("Exporting to ODF",
546 xAdaptor->odfConvert(m_directories.getURLFromSrc(u"/sdext/source/pdfimport/test/testTdf105536.pdf"),
547 new OutputWrapString(aOutput),
548 nullptr));
549 // This ensures that the imported image arrives properly flipped
550 CPPUNIT_ASSERT(aOutput.indexOf("draw:transform=\"matrix(-21488.4 0 0 -27978.1 21488.4 27978.1)\"") != -1);
551 #endif
554 void testTdf141709_chinesechar()
556 // this test crashes on the windows jenkins boxes, but no-one can catch it locally
557 #if HAVE_FEATURE_POPPLER
558 rtl::Reference<pdfi::PDFIRawAdaptor> xAdaptor(new pdfi::PDFIRawAdaptor(OUString(), getComponentContext()));
559 xAdaptor->setTreeVisitorFactory(createDrawTreeVisitorFactory());
561 OString aOutput;
562 CPPUNIT_ASSERT_MESSAGE("Exporting to ODF",
563 xAdaptor->odfConvert(m_directories.getURLFromSrc(u"/sdext/qa/unit/data/testTdf141709_chinesechar.pdf"),
564 new OutputWrapString(aOutput),
565 nullptr));
566 xmlDocUniquePtr pXmlDoc(xmlParseDoc(reinterpret_cast<xmlChar const *>(aOutput.getStr())));
567 // This ensures that the imported text contains all of the characters
568 OString xpath = "//draw:frame[@draw:z-index='3'][1]/draw:text-box/text:p/text:span[1]";
569 OUString sContent = getXPathContent(pXmlDoc, xpath).replaceAll("\n", "");
570 CPPUNIT_ASSERT_EQUAL_MESSAGE(aOutput.getStr(), OUString(u"敏捷的狐狸跨过慵懒的"), sContent);
571 xpath = "//draw:frame[@draw:z-index='4'][1]/draw:text-box/text:p/text:span[1]";
572 sContent = getXPathContent(pXmlDoc, xpath).replaceAll("\n", "");
573 CPPUNIT_ASSERT_EQUAL_MESSAGE(aOutput.getStr(), OUString(u"狗。"), sContent);
574 #endif
577 void testTdf78427_FontFeatures()
579 #if HAVE_FEATURE_POPPLER
580 rtl::Reference<pdfi::PDFIRawAdaptor> xAdaptor(new pdfi::PDFIRawAdaptor(OUString(), getComponentContext()));
581 xAdaptor->setTreeVisitorFactory(createDrawTreeVisitorFactory());
583 OString aOutput;
584 CPPUNIT_ASSERT_MESSAGE("Converting PDF to ODF XML",
585 xAdaptor->odfConvert( m_directories.getURLFromSrc(
586 u"/sdext/qa/unit/data/tdf78427-testFontFeatures.pdf"),
587 new OutputWrapString(aOutput),
588 nullptr ));
589 // Un-comment the following debug line to see the content of generated XML content in
590 // workdir/CppunitTest/sdext_pdfimport.test.log after running "make CppunitTest_sdext_pdfimport".
591 //std::cout << aOutput << std::endl;
592 xmlDocUniquePtr pXmlDoc(xmlParseDoc(reinterpret_cast<xmlChar const *>(aOutput.getStr())));
593 //CPPUNIT_ASSERT(pXmlDoc);
595 /* Test for the 1st paragraph */
596 OUString styleName = getXPath(pXmlDoc, "//draw:frame[1]//text:span[1]", "style-name");
597 OString xpath = "//office:automatic-styles/style:style[@style:name=\"" +
598 OUStringToOString(styleName, RTL_TEXTENCODING_UTF8) +
599 "\"]/style:text-properties";
600 // the font-weight and font-style should be normal
601 assertXPath(pXmlDoc, xpath, "font-weight", "normal");
602 assertXPathNoAttribute(pXmlDoc, xpath, "font-style");
604 /* Test for the 2nd paragraph */
605 styleName = getXPath(pXmlDoc, "//draw:frame[2]//text:span[1]", "style-name");
606 xpath = "//office:automatic-styles/style:style[@style:name=\"" +
607 OUStringToOString(styleName, RTL_TEXTENCODING_UTF8) +
608 "\"]/style:text-properties";
609 // there should be a font-weight="bold", but no font-style italic
610 assertXPath(pXmlDoc, xpath, "font-weight", "bold");
611 assertXPathNoAttribute(pXmlDoc, xpath, "font-style");
613 /* Test for the 3rd paragraph */
614 styleName = getXPath(pXmlDoc, "//draw:frame[3]//text:span[1]", "style-name");
615 xpath = "//office:automatic-styles/style:style[@style:name=\"" +
616 OUStringToOString(styleName, RTL_TEXTENCODING_UTF8) +
617 "\"]/style:text-properties";
618 // there should be a font-style="italic", but no font-weight bold
619 assertXPath(pXmlDoc, xpath, "font-weight", "normal");
620 assertXPath(pXmlDoc, xpath, "font-style", "italic");
622 /* Test for the 4th paragraph */
623 styleName = getXPath(pXmlDoc, "//draw:frame[4]//text:span[1]", "style-name");
624 xpath = "//office:automatic-styles/style:style[@style:name=\"" +
625 OUStringToOString(styleName, RTL_TEXTENCODING_UTF8) +
626 "\"]/style:text-properties";
627 // there should be both font-style="italic" and font-weight="bold"
628 assertXPath(pXmlDoc, xpath, "font-weight", "bold");
629 assertXPath(pXmlDoc, xpath, "font-style", "italic");
631 /* Test for the 5th paragraph */
632 styleName = getXPath(pXmlDoc, "//draw:frame[5]//text:span[1]", "style-name");
633 xpath = "//office:automatic-styles/style:style[@style:name=\"" +
634 OUStringToOString(styleName, RTL_TEXTENCODING_UTF8) +
635 "\"]/style:text-properties";
636 // the font should be Arial and font-weight="bold", no font-style
637 assertXPath(pXmlDoc, xpath, "font-family", "Arial");
638 assertXPath(pXmlDoc, xpath, "font-weight", "bold");
639 assertXPathNoAttribute(pXmlDoc, xpath, "font-style");
641 /* Test for the 6th paragraph */
642 styleName = getXPath(pXmlDoc, "//draw:frame[6]//text:span[1]", "style-name");
643 xpath = "//office:automatic-styles/style:style[@style:name=\"" +
644 OUStringToOString(styleName, RTL_TEXTENCODING_UTF8) +
645 "\"]/style:text-properties";
646 // the font should be Arial without font-weight and font-style
647 assertXPath(pXmlDoc, xpath, "font-family", "Arial");
648 assertXPath(pXmlDoc, xpath, "font-weight", "normal");
649 assertXPathNoAttribute(pXmlDoc, xpath, "font-style");
651 /* Test for the 7th paragraph */
652 styleName = getXPath(pXmlDoc, "//draw:frame[7]//text:span[1]", "style-name");
653 xpath = "//office:automatic-styles/style:style[@style:name=\"" +
654 OUStringToOString(styleName, RTL_TEXTENCODING_UTF8) +
655 "\"]/style:text-properties";
656 // the font should be SimSun without font-weight and font-style
657 assertXPath(pXmlDoc, xpath, "font-family", "SimSun"); // TODO: tdf#143095 use localized font name rather than PS name
658 assertXPath(pXmlDoc, xpath, "font-weight", "normal");
659 assertXPathNoAttribute(pXmlDoc, xpath, "font-style");
661 /* Test for the 8th paragraph */
662 styleName = getXPath(pXmlDoc, "//draw:frame[8]//text:span[1]", "style-name");
663 xpath = "//office:automatic-styles/style:style[@style:name=\"" +
664 OUStringToOString(styleName, RTL_TEXTENCODING_UTF8) +
665 "\"]/style:text-properties";
666 // the font should be SimSun and font-weight="bold", no font-style italic
667 assertXPath(pXmlDoc, xpath, "font-family", "SimSun");
668 assertXPath(pXmlDoc, xpath, "font-weight", "bold");
669 assertXPathNoAttribute(pXmlDoc, xpath, "font-style");
671 /* Test for the 9th paragraph */
672 styleName = getXPath(pXmlDoc, "//draw:frame[9]//text:span[1]", "style-name");
673 xpath = "//office:automatic-styles/style:style[@style:name=\"" +
674 OUStringToOString(styleName, RTL_TEXTENCODING_UTF8) +
675 "\"]/style:text-properties";
676 // the font should be SimSun, font-weight should be "normal", font-style="italic"
677 assertXPath(pXmlDoc, xpath, "font-family", "SimSun");
678 assertXPath(pXmlDoc, xpath, "font-weight", "normal");
679 // FIXME and remove the below comment:
680 // the chinese chars are shown in pdf as faux italic (fake italic). It is currencly imported wrongly as normal font style.
681 // See tdf#78427 for how the faux bold problem was handled. Faux italic may be handled using the transformation pattern.
682 // assertXPath(pXmlDoc, xpath, "font-style", "italic");
684 /* Test for the 10th paragraph */
685 styleName = getXPath(pXmlDoc, "//draw:frame[10]//text:span[1]", "style-name");
686 xpath = "//office:automatic-styles/style:style[@style:name=\"" +
687 OUStringToOString(styleName, RTL_TEXTENCODING_UTF8) +
688 "\"]/style:text-properties";
689 // the font should be SimSun font-weight="bold" and font-style="italic"
690 assertXPath(pXmlDoc, xpath, "font-family", "SimSun");
691 assertXPath(pXmlDoc, xpath, "font-weight", "bold");
692 // FIXME: faux italic, see above
693 // assertXPath(pXmlDoc, xpath, "font-style", "italic");
695 /* Test for the 11th paragraph */
696 styleName = getXPath(pXmlDoc, "//draw:frame[11]//text:span[1]", "style-name");
697 xpath = "//office:automatic-styles/style:style[@style:name=\"" +
698 OUStringToOString(styleName, RTL_TEXTENCODING_UTF8) +
699 "\"]/style:text-properties";
700 // the font should be SimSun and there should be style:text-outline="true"
701 // (i.e., the real "outline" font rather than faux bold / fake bold)
702 assertXPath(pXmlDoc, xpath, "font-family", "SimSun");
703 assertXPath(pXmlDoc, xpath, "font-weight", "normal");
704 assertXPathNoAttribute(pXmlDoc, xpath, "font-style");
705 assertXPath(pXmlDoc, xpath, "text-outline", "true");
706 #endif
709 void testTdf78427_FontWeight_MyraidProSemibold() // Related to attachment 155937.
711 #if HAVE_FEATURE_POPPLER
712 rtl::Reference<pdfi::PDFIRawAdaptor> xAdaptor(new pdfi::PDFIRawAdaptor(OUString(), getComponentContext()));
713 xAdaptor->setTreeVisitorFactory(createDrawTreeVisitorFactory());
715 OString aOutput;
716 CPPUNIT_ASSERT_MESSAGE("Converting PDF to ODF XML",
717 xAdaptor->odfConvert( m_directories.getURLFromSrc(
718 u"/sdext/qa/unit/data/tdf78427-MyraidPro-Semibold-Light.pdf"),
719 new OutputWrapString(aOutput),
720 nullptr ));
721 //std::cout << aOutput << std::endl;
723 xmlDocUniquePtr pXmlDoc(xmlParseDoc(reinterpret_cast<xmlChar const *>(aOutput.getStr())));
724 //CPPUNIT_ASSERT(pXmlDoc);
726 // The for the 1st frame */
727 OUString styleName = getXPath(pXmlDoc, "//draw:frame[1]//text:span[1]", "style-name");
728 OString xpath = "//office:automatic-styles/style:style[@style:name=\"" +
729 OUStringToOString(styleName, RTL_TEXTENCODING_UTF8) +
730 "\"]/style:text-properties";
731 // the font-weight and font-style should be 600 (Semibold)
732 assertXPath(pXmlDoc, xpath, "font-weight", "600");
734 // The for the 2nd frame */
735 styleName = getXPath(pXmlDoc, "//draw:frame[2]//text:span[1]", "style-name");
736 xpath = "//office:automatic-styles/style:style[@style:name=\"" +
737 OUStringToOString(styleName, RTL_TEXTENCODING_UTF8) +
738 "\"]/style:text-properties";
739 // the font-weight and font-style should be 300 (Light)
740 assertXPath(pXmlDoc, xpath, "font-weight", "300");
741 #endif
744 void testTdf143959_nameFromFontFile()
746 #if HAVE_FEATURE_POPPLER
747 rtl::Reference<pdfi::PDFIRawAdaptor> xAdaptor(new pdfi::PDFIRawAdaptor(OUString(), getComponentContext()));
748 xAdaptor->setTreeVisitorFactory(createDrawTreeVisitorFactory());
750 OString aOutput;
751 CPPUNIT_ASSERT_MESSAGE("Converting PDF to ODF XML",
752 xAdaptor->odfConvert( m_directories.getURLFromSrc(u"/sdext/qa/unit/data/testTdf143959.pdf"),
753 new OutputWrapString(aOutput),
754 nullptr ));
756 //std::cout << aOutput << std::endl;
757 xmlDocUniquePtr pXmlDoc(xmlParseDoc(reinterpret_cast<xmlChar const *>(aOutput.getStr())));
759 /* Test for the 1st text paragraph */
760 OUString styleName = getXPath(pXmlDoc, "//draw:frame[2]//text:span[1]", "style-name");
761 OString xpath = "//office:automatic-styles/style:style[@style:name=\"" +
762 OUStringToOString(styleName, RTL_TEXTENCODING_UTF8) +
763 "\"]/style:text-properties";
764 CPPUNIT_ASSERT_EQUAL(OUString("TimesNewRoman"),
765 getXPath(pXmlDoc, xpath, "font-family").replaceAll(u" ", u""));
767 /* Test for the "TOTAL ESTA HOJA USD" paragraph" */
768 styleName = getXPath(pXmlDoc, "//draw:frame[last()-1]//text:span[1]", "style-name");
769 xpath = "//office:automatic-styles/style:style[@style:name=\"" +
770 OUStringToOString(styleName, RTL_TEXTENCODING_UTF8) +
771 "\"]/style:text-properties";
772 CPPUNIT_ASSERT_EQUAL(OUString("TimesNewRoman"),
773 getXPath(pXmlDoc, xpath, "font-family").replaceAll(u" ", u""));
774 CPPUNIT_ASSERT_EQUAL(OUString("bold"),
775 getXPath(pXmlDoc, xpath, "font-weight"));
776 #endif
779 void testTdf104597_textrun()
781 #if HAVE_FEATURE_POPPLER
782 rtl::Reference<pdfi::PDFIRawAdaptor> xAdaptor(new pdfi::PDFIRawAdaptor(OUString(), getComponentContext()));
783 xAdaptor->setTreeVisitorFactory(createDrawTreeVisitorFactory());
785 OString aOutput;
786 CPPUNIT_ASSERT_MESSAGE("Converting PDF to ODF XML",
787 xAdaptor->odfConvert(m_directories.getURLFromSrc(u"/sdext/qa/unit/data/tdf104597_textrun.pdf"),
788 new OutputWrapString(aOutput),
789 nullptr));
791 xmlDocUniquePtr pXmlDoc(xmlParseDoc(reinterpret_cast<xmlChar const *>(aOutput.getStr())));
793 // Test for امُ عَلَيْكَ
794 OString xpath = "string(//draw:frame[@draw:transform='matrix(917.222222222222 0 0 917.222222222222 14821.9583333333 2159.23861112778)']/draw:text-box/text:p/text:span)";
795 OUString sContent = getXPathContent(pXmlDoc, xpath);
796 CPPUNIT_ASSERT_EQUAL_MESSAGE(aOutput.getStr(), OUString(u"امُ عَلَيَْك"), sContent.replaceAll("\n\n", " ").replaceAll("\n", ""));
798 // Test for ٱلسََّل . It appears in the 3rd frame, i.e. after the امُ عَلَيَْك which is in the 2nd frame (from left to right)
799 // thus these two frames together appear as ٱلسََّل امُ عَلَيْكَ in Draw‬.
800 // FIXME: Should be ٱلسَّلَامُ عَلَيْكَ (i.e. the two text frames should be merged into one so that the ل and the ا will show as لَا rather than ل ا)
801 xpath = "string(//draw:frame[@draw:transform='matrix(917.222222222222 0 0 917.222222222222 17420.1666666667 2159.23861112778)']/draw:text-box/text:p/text:span)";
802 sContent = getXPathContent(pXmlDoc, xpath);
803 CPPUNIT_ASSERT_EQUAL_MESSAGE(aOutput.getStr(), OUString(u"ٱلسََّل"), sContent.replaceAll("\n\n", " ").replaceAll("\n", ""));
805 // Test for "LibreOffice RTL"
806 xpath = "string(//draw:frame[@draw:transform='matrix(917.222222222222 0 0 917.222222222222 12779.375 5121.79583335)']/draw:text-box/text:p/text:span)";
807 sContent = getXPathContent(pXmlDoc, xpath);
808 CPPUNIT_ASSERT_EQUAL_MESSAGE(aOutput.getStr(), OUString(u"LibreOffice RTL"), sContent.replaceAll("\n\n", " ").replaceAll("\n", ""));
810 // Test for "LibreOffice LTR (test)"
811 xpath = "string(//draw:frame[last()-1]/draw:text-box/text:p/text:span[last()])";
812 sContent = getXPathContent(pXmlDoc, xpath);
813 CPPUNIT_ASSERT_EQUAL_MESSAGE(aOutput.getStr(), OUString(u"LibreOffice LTR (test)"), sContent.replaceAll("\n\n", " ").replaceAll("\n", ""));
815 /* Test for Chinese characters */
816 // Use last() instead of matrix below, because the matrix may be different on different OS due to fallback of Chinese fonts.
817 xpath = "string(//draw:frame[last()]/draw:text-box/text:p/text:span)";
818 sContent = getXPathContent(pXmlDoc, xpath);
819 CPPUNIT_ASSERT_EQUAL_MESSAGE(aOutput.getStr(), OUString(u"中文测试,中文"), sContent.replaceAll("\n\n", " ").replaceAll("\n", ""));
821 // Test pdf text run in the Writer PDF import filter
822 xAdaptor->setTreeVisitorFactory(createWriterTreeVisitorFactory());
823 OString aOutput2;
824 xAdaptor->odfConvert(m_directories.getURLFromSrc(u"/sdext/qa/unit/data/tdf104597_textrun.pdf"),
825 new OutputWrapString(aOutput2),
826 nullptr);
827 xmlDocUniquePtr pXmlDoc2(xmlParseDoc(reinterpret_cast<xmlChar const *>(aOutput2.getStr())));
828 xpath = "string(//draw:frame[@draw:z-index='3'][1]/draw:text-box/text:p/text:span)";
829 sContent = getXPathContent(pXmlDoc2, xpath).replaceAll("\n\n", " ").replaceAll("\n", "");
830 CPPUNIT_ASSERT_EQUAL_MESSAGE(aOutput2.getStr(), OUString(u"ٱلسََّل"), sContent);
831 xpath = "string(//draw:frame[@draw:z-index='2'][1]/draw:text-box/text:p/text:span)";
832 sContent = getXPathContent(pXmlDoc2, xpath).replaceAll("\n\n", " ").replaceAll("\n", "");
833 CPPUNIT_ASSERT_EQUAL(OUString(u"امُ عَلَيَْك"), sContent);
834 xpath = "string(//draw:frame[last()]/draw:text-box/text:p/text:span)";
835 sContent = getXPathContent(pXmlDoc2, xpath).replaceAll("\n\n", " ").replaceAll("\n", "");
836 CPPUNIT_ASSERT_EQUAL_MESSAGE(aOutput2.getStr(), OUString(u"中文测试,中文"), sContent);
837 #endif
840 void testSpaces()
842 #if HAVE_FEATURE_POPPLER
843 rtl::Reference<pdfi::PDFIRawAdaptor> xAdaptor(new pdfi::PDFIRawAdaptor(OUString(), getComponentContext()));
844 xAdaptor->setTreeVisitorFactory(createWriterTreeVisitorFactory());
846 OString aOutput;
847 xAdaptor->odfConvert(m_directories.getURLFromSrc(u"/sdext/qa/unit/data/testSpace.pdf"),
848 new OutputWrapString(aOutput),
849 nullptr);
850 xmlDocUniquePtr pXmlDoc(xmlParseDoc(reinterpret_cast<xmlChar const *>(aOutput.getStr())));
852 // Space test: there are 10 spaces, each space is expressed as a <text:s text:c="1" ...>,
853 // thus the 10th text:s should exist and the attribute "text:c" should be "1".
854 OString xpath = "//draw:frame[@draw:z-index='1'][1]/draw:text-box/text:p/text:span/text:s[10]";
855 OUString sContent = getXPath(pXmlDoc, xpath, "c");
856 CPPUNIT_ASSERT_EQUAL_MESSAGE(aOutput.getStr(), OUString("1"), sContent);
858 // Tab test: there are 10 tabs. Text before and after the tabs are shown in different draw frames.
859 // With the Liberation Serif font, the horizontal position of the first frame is 20.03mm and the
860 // second frame is 94.12mm.
861 xpath = "//draw:frame[@draw:z-index='2'][1]";
862 sContent = getXPath(pXmlDoc, xpath, "transform");
863 CPPUNIT_ASSERT_EQUAL_MESSAGE(aOutput.getStr(), OUString("translate( 20.03mm 25.05mm )"), sContent);
864 xpath = "//draw:frame[@draw:z-index='3'][1]";
865 sContent = getXPath(pXmlDoc, xpath, "transform");
866 CPPUNIT_ASSERT_EQUAL_MESSAGE(aOutput.getStr(), OUString("translate( 94.12mm 25.05mm )"), sContent);
868 // Non-breaking space test: there are 10 NBSpaces, which are treated as the same as normal space in PDF,
869 // thus each is expressed as a <text:s text:c="1" ...>.
870 // The 10th text:s should exist and the attribute "text:c" should be "1".
871 xpath = "//draw:frame[@draw:z-index='4'][1]/draw:text-box/text:p/text:span/text:s[10]";
872 sContent = getXPath(pXmlDoc, xpath, "c");
873 CPPUNIT_ASSERT_EQUAL_MESSAGE(aOutput.getStr(), OUString("1"), sContent);
874 #endif
877 CPPUNIT_TEST_SUITE(PDFITest);
878 CPPUNIT_TEST(testXPDFParser);
879 CPPUNIT_TEST(testOdfWriterExport);
880 CPPUNIT_TEST(testOdfDrawExport);
881 CPPUNIT_TEST(testTdf96993);
882 CPPUNIT_TEST(testTdf98421);
883 CPPUNIT_TEST(testTdf105536);
884 CPPUNIT_TEST(testTdf141709_chinesechar);
885 CPPUNIT_TEST(testTdf78427_FontFeatures);
886 CPPUNIT_TEST(testTdf78427_FontWeight_MyraidProSemibold);
887 CPPUNIT_TEST(testTdf143959_nameFromFontFile);
888 CPPUNIT_TEST(testTdf104597_textrun);
889 CPPUNIT_TEST(testSpaces);
890 CPPUNIT_TEST_SUITE_END();
895 CPPUNIT_TEST_SUITE_REGISTRATION(PDFITest);
897 CPPUNIT_PLUGIN_IMPLEMENT();
899 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */