1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
54 #include <rtl/ustring.hxx>
55 #include <rtl/ref.hxx>
57 using namespace ::pdfparse
;
58 using namespace ::pdfi
;
59 using namespace ::com::sun::star
;
64 class TestSink
: public ContentSink
78 m_bRedCircleSeen(false),
79 m_bGreenStrokeSeen(false),
80 m_bDashedLineSeen(false),
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";
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
);
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
130 virtual void endPage() override
135 virtual void hyperLink( const geometry::RealRectangle2D
& rBounds
,
136 const OUString
& rURI
) override
138 m_aHyperlinkBounds
= rBounds
;
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
,
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
;
211 m_aFontToId
[ rFont
] = m_nNextFontId
;
212 m_aIdToFont
[ m_nNextFontId
] = rFont
;
213 getCurrentContext().FontId
= 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;
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
);
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
;
444 OUStringBuffer m_aTextOut
;
445 sal_Int32 m_nNumPages
;
447 bool m_bRedCircleSeen
;
448 bool m_bGreenStrokeSeen
;
449 bool m_bDashedLineSeen
;
453 class PDFITest
: public test::BootstrapFixture
, public XmlTestTools
456 void testXPDFParser()
458 #if HAVE_FEATURE_POPPLER
459 auto pSink
= std::make_shared
<TestSink
>();
461 pdfi::xpdf_ImportFromFile(
462 m_directories
.getURLFromSrc(u
"/sdext/source/pdfimport/test/testinput.pdf"),
464 uno::Reference
< task::XInteractionHandler
>(),
466 getComponentContext(), "" ) );
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
),
484 osl::File::remove( tempFileURL
);
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
),
501 osl::File::remove( tempFileURL
);
507 #if HAVE_FEATURE_POPPLER
508 rtl::Reference
<pdfi::PDFIRawAdaptor
> xAdaptor(new pdfi::PDFIRawAdaptor(OUString(), getComponentContext()));
509 xAdaptor
->setTreeVisitorFactory(createDrawTreeVisitorFactory());
512 CPPUNIT_ASSERT_MESSAGE("Exporting to ODF",
513 xAdaptor
->odfConvert(m_directories
.getURLFromSrc(u
"/sdext/source/pdfimport/test/testTdf96993.pdf"),
514 new OutputWrapString(aOutput
),
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);
523 #if HAVE_FEATURE_POPPLER
524 rtl::Reference
<pdfi::PDFIRawAdaptor
> xAdaptor(new pdfi::PDFIRawAdaptor(OUString(), getComponentContext()));
525 xAdaptor
->setTreeVisitorFactory(createWriterTreeVisitorFactory());
528 CPPUNIT_ASSERT_MESSAGE("Exporting to ODF",
529 xAdaptor
->odfConvert(m_directories
.getURLFromSrc(u
"/sdext/source/pdfimport/test/testTdf96993.pdf"),
530 new OutputWrapString(aOutput
),
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);
540 #if HAVE_FEATURE_POPPLER
541 rtl::Reference
<pdfi::PDFIRawAdaptor
> xAdaptor(new pdfi::PDFIRawAdaptor(OUString(), getComponentContext()));
542 xAdaptor
->setTreeVisitorFactory(createDrawTreeVisitorFactory());
545 CPPUNIT_ASSERT_MESSAGE("Exporting to ODF",
546 xAdaptor
->odfConvert(m_directories
.getURLFromSrc(u
"/sdext/source/pdfimport/test/testTdf105536.pdf"),
547 new OutputWrapString(aOutput
),
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);
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());
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
),
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
);
577 void testTdf78427_FontFeatures()
579 #if HAVE_FEATURE_POPPLER
580 rtl::Reference
<pdfi::PDFIRawAdaptor
> xAdaptor(new pdfi::PDFIRawAdaptor(OUString(), getComponentContext()));
581 xAdaptor
->setTreeVisitorFactory(createDrawTreeVisitorFactory());
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
),
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");
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());
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
),
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");
744 void testTdf143959_nameFromFontFile()
746 #if HAVE_FEATURE_POPPLER
747 rtl::Reference
<pdfi::PDFIRawAdaptor
> xAdaptor(new pdfi::PDFIRawAdaptor(OUString(), getComponentContext()));
748 xAdaptor
->setTreeVisitorFactory(createDrawTreeVisitorFactory());
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
),
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"));
779 void testTdf104597_textrun()
781 #if HAVE_FEATURE_POPPLER
782 rtl::Reference
<pdfi::PDFIRawAdaptor
> xAdaptor(new pdfi::PDFIRawAdaptor(OUString(), getComponentContext()));
783 xAdaptor
->setTreeVisitorFactory(createDrawTreeVisitorFactory());
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
),
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());
824 xAdaptor
->odfConvert(m_directories
.getURLFromSrc(u
"/sdext/qa/unit/data/tdf104597_textrun.pdf"),
825 new OutputWrapString(aOutput2
),
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
);
842 #if HAVE_FEATURE_POPPLER
843 rtl::Reference
<pdfi::PDFIRawAdaptor
> xAdaptor(new pdfi::PDFIRawAdaptor(OUString(), getComponentContext()));
844 xAdaptor
->setTreeVisitorFactory(createWriterTreeVisitorFactory());
847 xAdaptor
->odfConvert(m_directories
.getURLFromSrc(u
"/sdext/qa/unit/data/testSpace.pdf"),
848 new OutputWrapString(aOutput
),
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
);
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: */