LibreOffice Module sdext (master)  1
tests.cxx
Go to the documentation of this file.
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  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <config_features.h>
21 
22 #include "outputwrap.hxx"
23 #include <contentsink.hxx>
24 #include <pdfihelper.hxx>
25 #include <wrapper.hxx>
26 #include <pdfparse.hxx>
27 #include "../pdfiadaptor.hxx"
28 
29 #include <rtl/math.hxx>
30 #include <osl/file.hxx>
31 #include <comphelper/sequence.hxx>
32 
33 #include <cppunit/TestAssert.h>
34 #include <cppunit/extensions/HelperMacros.h>
35 #include <cppunit/plugin/TestPlugIn.h>
37 #include <test/xmltesttools.hxx>
38 
39 #include <com/sun/star/geometry/RealRectangle2D.hpp>
40 #include <com/sun/star/geometry/RealSize2D.hpp>
41 #include <com/sun/star/rendering/PathJoinType.hpp>
42 #include <com/sun/star/rendering/PathCapType.hpp>
43 #include <com/sun/star/rendering/BlendMode.hpp>
44 
49 
50 #include <unordered_map>
51 #include <vector>
52 
53 #include <rtl/ustring.hxx>
54 #include <rtl/ref.hxx>
55 
56 using namespace ::pdfparse;
57 using namespace ::pdfi;
58 using namespace ::com::sun::star;
59 
60 namespace
61 {
62 
63  class TestSink : public ContentSink
64  {
65  public:
66  TestSink() :
67  m_nNextFontId( 1 ),
68  m_aIdToFont(),
69  m_aFontToId(),
70  m_aGCStack(1),
71  m_aPageSize(),
72  m_aHyperlinkBounds(),
73  m_aURI(),
74  m_aTextOut(),
75  m_nNumPages(0),
76  m_bPageEnded(false),
77  m_bRedCircleSeen(false),
78  m_bGreenStrokeSeen(false),
79  m_bDashedLineSeen(false),
80  m_bImageSeen(false)
81  {}
82 
83  void check()
84  {
85  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "A4 page size (in 100th of points): Width", 79400, m_aPageSize.Width, 0.00000001);
86  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "A4 page size (in 100th of points): Height", 59500, m_aPageSize.Height, 0.0000001 );
87  CPPUNIT_ASSERT_MESSAGE( "endPage() called", m_bPageEnded );
88  CPPUNIT_ASSERT_EQUAL_MESSAGE( "Num pages equal one", sal_Int32(1), m_nNumPages );
89  CPPUNIT_ASSERT_MESSAGE( "Correct hyperlink bounding box",
90  rtl::math::approxEqual(m_aHyperlinkBounds.X1,34.7 ) );
91  CPPUNIT_ASSERT_MESSAGE( "Correct hyperlink bounding box",
92  rtl::math::approxEqual(m_aHyperlinkBounds.Y1,386.0) );
93  CPPUNIT_ASSERT_MESSAGE( "Correct hyperlink bounding box",
94  rtl::math::approxEqual(m_aHyperlinkBounds.X2,166.7) );
95  CPPUNIT_ASSERT_MESSAGE( "Correct hyperlink bounding box",
96  rtl::math::approxEqual(m_aHyperlinkBounds.Y2,406.2) );
97  CPPUNIT_ASSERT_EQUAL_MESSAGE( "Correct hyperlink URI", OUString("http://download.openoffice.org/"), m_aURI );
98 
99  const char* const sText = " \n \nThis is a testtext\nNew paragraph,\nnew line\n"
100  "Hyperlink, this is\n?\nThis is more text\noutline mode\n?\nNew paragraph\n";
101  OString aTmp;
102  m_aTextOut.makeStringAndClear().convertToString( &aTmp,
103  RTL_TEXTENCODING_ASCII_US,
104  OUSTRING_TO_OSTRING_CVTFLAGS );
105  CPPUNIT_ASSERT_EQUAL_MESSAGE( "Imported text is \"This is a testtext New paragraph, new line"
106  " Hyperlink, this is * This is more text outline mode * New paragraph\"",
107  aTmp, OString(sText) );
108 
109  CPPUNIT_ASSERT_MESSAGE( "red circle seen in input", m_bRedCircleSeen );
110  CPPUNIT_ASSERT_MESSAGE( "green stroke seen in input", m_bGreenStrokeSeen );
111  CPPUNIT_ASSERT_MESSAGE( "dashed line seen in input", m_bDashedLineSeen );
112  CPPUNIT_ASSERT_MESSAGE( "image seen in input", m_bImageSeen );
113  }
114 
115  private:
116  GraphicsContext& getCurrentContext() { return m_aGCStack.back(); }
117 
118  // ContentSink interface implementation
119  virtual void setPageNum( sal_Int32 nNumPages ) override
120  {
121  m_nNumPages = nNumPages;
122  }
123 
124  virtual void startPage( const geometry::RealSize2D& rSize ) override
125  {
126  m_aPageSize = rSize;
127  }
128 
129  virtual void endPage() override
130  {
131  m_bPageEnded = true;
132  }
133 
134  virtual void hyperLink( const geometry::RealRectangle2D& rBounds,
135  const OUString& rURI ) override
136  {
137  m_aHyperlinkBounds = rBounds;
138  m_aURI = rURI;
139  }
140 
141  virtual void pushState() override
142  {
143  GraphicsContextStack::value_type const a(m_aGCStack.back());
144  m_aGCStack.push_back(a);
145  }
146 
147  virtual void popState() override
148  {
149  m_aGCStack.pop_back();
150  }
151 
152  virtual void setTransformation( const geometry::AffineMatrix2D& rMatrix ) override
153  {
155  getCurrentContext().Transformation,
156  rMatrix );
157  }
158 
159  virtual void setLineDash( const uno::Sequence<double>& dashes,
160  double start ) override
161  {
162  GraphicsContext& rContext( getCurrentContext() );
163  if( dashes.hasElements() )
164  comphelper::sequenceToContainer(rContext.DashArray,dashes);
165  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "line dashing start offset", 0.0, start, 0.000000001 );
166  }
167 
168  virtual void setFlatness( double nFlatness ) override
169  {
170  getCurrentContext().Flatness = nFlatness;
171  }
172 
173  virtual void setLineJoin(sal_Int8 nJoin) override
174  {
175  getCurrentContext().LineJoin = nJoin;
176  }
177 
178  virtual void setLineCap(sal_Int8 nCap) override
179  {
180  getCurrentContext().LineCap = nCap;
181  }
182 
183  virtual void setMiterLimit(double nVal) override
184  {
185  getCurrentContext().MiterLimit = nVal;
186  }
187 
188  virtual void setLineWidth(double nVal) override
189  {
190  getCurrentContext().LineWidth = nVal;
191  }
192 
193  virtual void setFillColor( const rendering::ARGBColor& rColor ) override
194  {
195  getCurrentContext().FillColor = rColor;
196  }
197 
198  virtual void setStrokeColor( const rendering::ARGBColor& rColor ) override
199  {
200  getCurrentContext().LineColor = rColor;
201  }
202 
203  virtual void setFont( const FontAttributes& rFont ) override
204  {
205  FontToIdMap::const_iterator it = m_aFontToId.find( rFont );
206  if( it != m_aFontToId.end() )
207  getCurrentContext().FontId = it->second;
208  else
209  {
210  m_aFontToId[ rFont ] = m_nNextFontId;
211  m_aIdToFont[ m_nNextFontId ] = rFont;
212  getCurrentContext().FontId = m_nNextFontId;
213  m_nNextFontId++;
214  }
215  }
216 
217  virtual void strokePath( const uno::Reference<rendering::XPolyPolygon2D>& rPath ) override
218  {
219  GraphicsContext& rContext( getCurrentContext() );
221  aPath.transform( rContext.Transformation );
222 
223  if( rContext.DashArray.empty() )
224  {
225  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Line color is green", 1.0, rContext.LineColor.Alpha, 0.00000001);
226  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Line color is green", 0.0, rContext.LineColor.Blue, 0.00000001);
227  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Line color is green", 1.0, rContext.LineColor.Green, 0.00000001);
228  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Line color is green", 0.0, rContext.LineColor.Red, 0.00000001);
229 
230  CPPUNIT_ASSERT_MESSAGE( "Line width is 0",
231  rtl::math::approxEqual(rContext.LineWidth, 28.3) );
232 
233  static constexpr OUStringLiteral sExportString = u"m53570 7650-35430 24100";
234  CPPUNIT_ASSERT_EQUAL_MESSAGE( "Stroke is m535.7 518.5-354.3-241",
235  OUString(sExportString), basegfx::utils::exportToSvgD( aPath, true, true, false ) );
236 
237  m_bGreenStrokeSeen = true;
238  }
239  else
240  {
241  CPPUNIT_ASSERT_EQUAL_MESSAGE( "Dash array consists of four entries", std::vector<double>::size_type(4), rContext.DashArray.size());
242  CPPUNIT_ASSERT_DOUBLES_EQUAL( 14.3764, rContext.DashArray[0], 1E-12 );
243  CPPUNIT_ASSERT_DOUBLES_EQUAL( rContext.DashArray[0], rContext.DashArray[1], 1E-12 );
244  CPPUNIT_ASSERT_DOUBLES_EQUAL( rContext.DashArray[1], rContext.DashArray[2], 1E-12 );
245  CPPUNIT_ASSERT_DOUBLES_EQUAL( rContext.DashArray[2], rContext.DashArray[3], 1E-12 );
246 
247  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Line color is black", 1.0, rContext.LineColor.Alpha, 0.00000001);
248  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Line color is black", 0.0, rContext.LineColor.Blue, 0.00000001);
249  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Line color is black", 0.0, rContext.LineColor.Green, 0.00000001);
250  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Line color is black", 0.0, rContext.LineColor.Red, 0.00000001);
251 
252  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Line width is 0",
253  0, rContext.LineWidth, 0.0000001 );
254 
255  static constexpr OUStringLiteral sExportString = u"m49890 5670.00000000001-35430 24090";
256  CPPUNIT_ASSERT_EQUAL_MESSAGE( "Stroke is m49890 5670.00000000001-35430 24090",
257  OUString(sExportString), basegfx::utils::exportToSvgD( aPath, true, true, false ) );
258 
259  m_bDashedLineSeen = true;
260  }
261  CPPUNIT_ASSERT_EQUAL_MESSAGE( "Blend mode is normal",
262  rendering::BlendMode::NORMAL, rContext.BlendMode );
263  CPPUNIT_ASSERT_EQUAL_MESSAGE( "Join type is round",
264  rendering::PathJoinType::ROUND, rContext.LineJoin );
265  CPPUNIT_ASSERT_EQUAL_MESSAGE( "Cap type is butt",
266  rendering::PathCapType::BUTT, rContext.LineCap );
267  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Line miter limit is 10",
268  10, rContext.MiterLimit, 0.0000001 );
269  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Flatness is 0",
270  1, rContext.Flatness, 0.00000001 );
271  CPPUNIT_ASSERT_EQUAL_MESSAGE( "Font id is 0",
272  sal_Int32(0), rContext.FontId );
273  }
274 
275  virtual void fillPath( const uno::Reference<rendering::XPolyPolygon2D>& rPath ) override
276  {
277  GraphicsContext& rContext( getCurrentContext() );
279  aPath.transform( rContext.Transformation );
280 
281  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Line color is black", 1.0, rContext.LineColor.Alpha, 0.00000001);
282  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Line color is black", 0.0, rContext.LineColor.Blue, 0.00000001);
283  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Line color is black", 0.0, rContext.LineColor.Green, 0.00000001);
284  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Line color is black", 0.0, rContext.LineColor.Red, 0.00000001);
285 
286  CPPUNIT_ASSERT_EQUAL_MESSAGE( "Blend mode is normal",
287  rendering::BlendMode::NORMAL, rContext.BlendMode );
288  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Flatness is 10",
289  10, rContext.Flatness, 0.00000001 );
290  CPPUNIT_ASSERT_EQUAL_MESSAGE( "Font id is 0",
291  sal_Int32(0), rContext.FontId );
292  }
293 
294  virtual void eoFillPath( const uno::Reference<rendering::XPolyPolygon2D>& rPath ) override
295  {
296  GraphicsContext& rContext( getCurrentContext() );
298  aPath.transform( rContext.Transformation );
299 
300  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Line color is black", 1.0, rContext.LineColor.Alpha, 0.00000001);
301  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Line color is black", 0.0, rContext.LineColor.Blue, 0.00000001);
302  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Line color is black", 0.0, rContext.LineColor.Green, 0.00000001);
303  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Line color is black", 0.0, rContext.LineColor.Red, 0.00000001);
304 
305  CPPUNIT_ASSERT_EQUAL_MESSAGE( "Blend mode is normal",
306  rendering::BlendMode::NORMAL, rContext.BlendMode );
307  CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Flatness is 0",
308  1, rContext.Flatness, 0.00000001 );
309  CPPUNIT_ASSERT_EQUAL_MESSAGE( "Font id is 0",
310  sal_Int32(0), rContext.FontId );
311 
312  static constexpr OUStringLiteral sExportString
313  = u"m12050 49610c-4310 0-7800-3490-7800-7800 0-4300 "
314  "3490-7790 7800-7790 4300 0 7790 3490 7790 7790 0 4310-3490 7800-7790 7800z";
315  CPPUNIT_ASSERT_EQUAL_MESSAGE( "Stroke is a 4-bezier circle",
316  OUString(sExportString), basegfx::utils::exportToSvgD( aPath, true, true, false ) );
317 
318  m_bRedCircleSeen = true;
319  }
320 
321  virtual void intersectClip(const uno::Reference<rendering::XPolyPolygon2D>& rPath) override
322  {
324  basegfx::B2DPolyPolygon aCurClip = getCurrentContext().Clip;
325 
326  if( aCurClip.count() ) // #i92985# adapted API from (..., false, false) to (..., true, false)
327  aNewClip = basegfx::utils::clipPolyPolygonOnPolyPolygon( aCurClip, aNewClip, true, false );
328 
329  getCurrentContext().Clip = aNewClip;
330  }
331 
332  virtual void intersectEoClip(const uno::Reference<rendering::XPolyPolygon2D>& rPath) override
333  {
335  basegfx::B2DPolyPolygon aCurClip = getCurrentContext().Clip;
336 
337  if( aCurClip.count() ) // #i92985# adapted API from (..., false, false) to (..., true, false)
338  aNewClip = basegfx::utils::clipPolyPolygonOnPolyPolygon( aCurClip, aNewClip, true, false );
339 
340  getCurrentContext().Clip = aNewClip;
341  }
342 
343  virtual void drawGlyphs( const OUString& rGlyphs,
344  const geometry::RealRectangle2D& /*rRect*/,
345  const geometry::Matrix2D& /*rFontMatrix*/,
346  double /*fontSize*/) override
347  {
348  m_aTextOut.append(rGlyphs);
349  }
350 
351  virtual void endText() override
352  {
353  m_aTextOut.append( "\n" );
354  }
355 
356  virtual void drawMask(const uno::Sequence<beans::PropertyValue>& xBitmap,
357  bool /*bInvert*/ ) override
358  {
359  CPPUNIT_ASSERT_EQUAL_MESSAGE( "drawMask received two properties",
360  sal_Int32(3), xBitmap.getLength() );
361  CPPUNIT_ASSERT_EQUAL_MESSAGE( "drawMask got URL param",
362  OUString("URL"), xBitmap[0].Name );
363  CPPUNIT_ASSERT_EQUAL_MESSAGE( "drawMask got InputStream param",
364  OUString("InputStream"), xBitmap[1].Name );
365  }
366 
367  virtual void drawImage(const uno::Sequence<beans::PropertyValue>& xBitmap ) override
368  {
369  CPPUNIT_ASSERT_EQUAL_MESSAGE( "drawImage received two properties",
370  sal_Int32(3), xBitmap.getLength() );
371  CPPUNIT_ASSERT_EQUAL_MESSAGE( "drawImage got URL param",
372  OUString("URL"), xBitmap[0].Name );
373  CPPUNIT_ASSERT_EQUAL_MESSAGE( "drawImage got InputStream param",
374  OUString("InputStream"), xBitmap[1].Name );
375  m_bImageSeen = true;
376  }
377 
378  virtual void drawColorMaskedImage(const uno::Sequence<beans::PropertyValue>& xBitmap,
379  const uno::Sequence<uno::Any>& /*xMaskColors*/ ) override
380  {
381  CPPUNIT_ASSERT_EQUAL_MESSAGE( "drawColorMaskedImage received two properties",
382  sal_Int32(3), xBitmap.getLength() );
383  CPPUNIT_ASSERT_EQUAL_MESSAGE( "drawColorMaskedImage got URL param",
384  OUString("URL"), xBitmap[0].Name );
385  CPPUNIT_ASSERT_EQUAL_MESSAGE( "drawColorMaskedImage got InputStream param",
386  OUString("InputStream"), xBitmap[1].Name );
387  }
388 
389  virtual void drawMaskedImage(const uno::Sequence<beans::PropertyValue>& xBitmap,
390  const uno::Sequence<beans::PropertyValue>& xMask,
391  bool /*bInvertMask*/) override
392  {
393  CPPUNIT_ASSERT_EQUAL_MESSAGE( "drawMaskedImage received two properties #1",
394  sal_Int32(3), xBitmap.getLength() );
395  CPPUNIT_ASSERT_EQUAL_MESSAGE( "drawMaskedImage got URL param #1",
396  OUString("URL"), xBitmap[0].Name );
397  CPPUNIT_ASSERT_EQUAL_MESSAGE( "drawMaskedImage got InputStream param #1",
398  OUString("InputStream"), xBitmap[1].Name );
399 
400  CPPUNIT_ASSERT_EQUAL_MESSAGE( "drawMaskedImage received two properties #2",
401  sal_Int32(3), xMask.getLength() );
402  CPPUNIT_ASSERT_EQUAL_MESSAGE( "drawMaskedImage got URL param #2",
403  OUString("URL"), xMask[0].Name );
404  CPPUNIT_ASSERT_EQUAL_MESSAGE( "drawMaskedImage got InputStream param #2",
405  OUString("InputStream"), xMask[1].Name );
406  }
407 
408  virtual void drawAlphaMaskedImage(const uno::Sequence<beans::PropertyValue>& xBitmap,
409  const uno::Sequence<beans::PropertyValue>& xMask) override
410  {
411  CPPUNIT_ASSERT_EQUAL_MESSAGE( "drawAlphaMaskedImage received two properties #1",
412  sal_Int32(3), xBitmap.getLength() );
413  CPPUNIT_ASSERT_EQUAL_MESSAGE( "drawAlphaMaskedImage got URL param #1",
414  OUString("URL"), xBitmap[0].Name );
415  CPPUNIT_ASSERT_EQUAL_MESSAGE( "drawAlphaMaskedImage got InputStream param #1",
416  OUString("InputStream"), xBitmap[1].Name );
417 
418  CPPUNIT_ASSERT_EQUAL_MESSAGE( "drawAlphaMaskedImage received two properties #2",
419  sal_Int32(3), xMask.getLength() );
420  CPPUNIT_ASSERT_EQUAL_MESSAGE( "drawAlphaMaskedImage got URL param #2",
421  OUString("URL"), xMask[0].Name );
422  CPPUNIT_ASSERT_EQUAL_MESSAGE( "drawAlphaMaskedImage got InputStream param #2",
423  OUString("InputStream"), xMask[1].Name );
424  }
425 
426  virtual void setTextRenderMode( sal_Int32 ) override
427  {
428  }
429 
430  typedef std::unordered_map<sal_Int32,FontAttributes> IdToFontMap;
431  typedef std::unordered_map<FontAttributes,sal_Int32,FontAttrHash> FontToIdMap;
432 
433  typedef std::vector<GraphicsContext> GraphicsContextStack;
434 
435  sal_Int32 m_nNextFontId;
436  IdToFontMap m_aIdToFont;
437  FontToIdMap m_aFontToId;
438 
439  GraphicsContextStack m_aGCStack;
440  geometry::RealSize2D m_aPageSize;
441  geometry::RealRectangle2D m_aHyperlinkBounds;
442  OUString m_aURI;
443  OUStringBuffer m_aTextOut;
444  sal_Int32 m_nNumPages;
445  bool m_bPageEnded;
446  bool m_bRedCircleSeen;
447  bool m_bGreenStrokeSeen;
448  bool m_bDashedLineSeen;
449  bool m_bImageSeen;
450  };
451 
452  class PDFITest : public test::BootstrapFixture, public XmlTestTools
453  {
454  protected:
455  virtual void registerNamespaces(xmlXPathContextPtr& pXmlXPathCtx) override
456  {
458  };
459  public:
460  void testXPDFParser()
461  {
462 #if HAVE_FEATURE_POPPLER
463  auto pSink = std::make_shared<TestSink>();
464  CPPUNIT_ASSERT(
466  m_directories.getURLFromSrc(u"/sdext/source/pdfimport/test/testinput.pdf"),
467  pSink,
468  uno::Reference< task::XInteractionHandler >(),
469  OUString(),
470  getComponentContext(), "" ) );
471  pSink->check();
472 #endif
473  }
474 
475  void testOdfDrawExport()
476  {
477 #if HAVE_FEATURE_POPPLER
479  xAdaptor->setTreeVisitorFactory( createDrawTreeVisitorFactory() );
480 
481  OUString tempFileURL;
482  CPPUNIT_ASSERT_EQUAL( osl::File::E_None, osl::File::createTempFile( nullptr, nullptr, &tempFileURL ) );
483  osl::File::remove( tempFileURL ); // FIXME the below apparently fails silently if the file already exists
484  CPPUNIT_ASSERT_MESSAGE("Exporting to ODF",
485  xAdaptor->odfConvert( m_directories.getURLFromSrc(u"/sdext/source/pdfimport/test/testinput.pdf"),
486  new OutputWrap(tempFileURL),
487  nullptr ));
488  osl::File::remove( tempFileURL );
489 #endif
490  }
491 
492  void testOdfWriterExport()
493  {
494 #if HAVE_FEATURE_POPPLER
496  xAdaptor->setTreeVisitorFactory( createWriterTreeVisitorFactory() );
497 
498  OUString tempFileURL;
499  CPPUNIT_ASSERT_EQUAL( osl::File::E_None, osl::File::createTempFile( nullptr, nullptr, &tempFileURL ) );
500  osl::File::remove( tempFileURL ); // FIXME the below apparently fails silently if the file already exists
501  CPPUNIT_ASSERT_MESSAGE("Exporting to ODF",
502  xAdaptor->odfConvert( m_directories.getURLFromSrc(u"/sdext/source/pdfimport/test/testinput.pdf"),
503  new OutputWrap(tempFileURL),
504  nullptr ));
505  osl::File::remove( tempFileURL );
506 #endif
507  }
508 
509  void testTdf96993()
510  {
511 #if HAVE_FEATURE_POPPLER
513  xAdaptor->setTreeVisitorFactory(createDrawTreeVisitorFactory());
514 
515  OString aOutput;
516  CPPUNIT_ASSERT_MESSAGE("Exporting to ODF",
517  xAdaptor->odfConvert(m_directories.getURLFromSrc(u"/sdext/source/pdfimport/test/testTdf96993.pdf"),
518  new OutputWrapString(aOutput),
519  nullptr));
520  // This ensures that the imported image arrives properly flipped
521  CPPUNIT_ASSERT(aOutput.indexOf("draw:transform=\"matrix(18520.8333333333 0 0 26281.9444444444 0 0)\"") != -1);
522 #endif
523  }
524 
525  void testTdf98421()
526  {
527 #if HAVE_FEATURE_POPPLER
529  xAdaptor->setTreeVisitorFactory(createWriterTreeVisitorFactory());
530 
531  OString aOutput;
532  CPPUNIT_ASSERT_MESSAGE("Exporting to ODF",
533  xAdaptor->odfConvert(m_directories.getURLFromSrc(u"/sdext/source/pdfimport/test/testTdf96993.pdf"),
534  new OutputWrapString(aOutput),
535  nullptr));
536  // This ensures that the imported image arrives properly flipped
537  CPPUNIT_ASSERT(aOutput.indexOf("draw:transform=\"scale( 1.0 -1.0 ) translate( 0mm 0mm )\"") != -1);
538  CPPUNIT_ASSERT(aOutput.indexOf("svg:height=\"-262.82mm\"") != -1);
539 #endif
540  }
541 
542  void testTdf105536()
543  {
544 #if HAVE_FEATURE_POPPLER
546  xAdaptor->setTreeVisitorFactory(createDrawTreeVisitorFactory());
547 
548  OString aOutput;
549  CPPUNIT_ASSERT_MESSAGE("Exporting to ODF",
550  xAdaptor->odfConvert(m_directories.getURLFromSrc(u"/sdext/source/pdfimport/test/testTdf105536.pdf"),
551  new OutputWrapString(aOutput),
552  nullptr));
553  // This ensures that the imported image arrives properly flipped
554  CPPUNIT_ASSERT(aOutput.indexOf("draw:transform=\"matrix(-21488.4 0 0 -27978.1 21488.4 27978.1)\"") != -1);
555 #endif
556  }
557 
558  void testTdf141709()
559  {
560 #if HAVE_FEATURE_POPPLER
562  xAdaptor->setTreeVisitorFactory(createDrawTreeVisitorFactory());
563 
564  OString aOutput;
565  CPPUNIT_ASSERT_MESSAGE("Exporting to ODF",
566  xAdaptor->odfConvert(m_directories.getURLFromSrc(u"/sdext/source/pdfimport/test/testTdf141709.pdf"),
567  new OutputWrapString(aOutput),
568  nullptr));
569  std::cout << aOutput << std::endl;
570  // This ensures that the imported text contains all of the characters
571  CPPUNIT_ASSERT(aOutput.indexOf("敏") != -1);
572  CPPUNIT_ASSERT(aOutput.indexOf("捷") != -1);
573  CPPUNIT_ASSERT(aOutput.indexOf("的") != -1);
574  CPPUNIT_ASSERT(aOutput.indexOf("狐") != -1);
575  CPPUNIT_ASSERT(aOutput.indexOf("狸") != -1);
576  CPPUNIT_ASSERT(aOutput.indexOf("跨") != -1);
577  CPPUNIT_ASSERT(aOutput.indexOf("过") != -1);
578  CPPUNIT_ASSERT(aOutput.indexOf("慵") != -1);
579  CPPUNIT_ASSERT(aOutput.indexOf("懒") != -1);
580  CPPUNIT_ASSERT(aOutput.indexOf("的") != -1);
581  CPPUNIT_ASSERT(aOutput.indexOf("狗") != -1);
582  CPPUNIT_ASSERT(aOutput.indexOf("。") != -1);
583 #endif
584  }
585 
586  void testFontFeatures() // tdf#78427
587  {
589  xAdaptor->setTreeVisitorFactory(createDrawTreeVisitorFactory());
590 
591  OString aOutput;
592  CPPUNIT_ASSERT_MESSAGE("Converting PDF to ODF XML",
593  xAdaptor->odfConvert( m_directories.getURLFromSrc(u"/sdext/source/pdfimport/test/testdocs/testFontFeatures.pdf"),
594  new OutputWrapString(aOutput),
595  nullptr ));
596  std::cout << aOutput << std::endl;
597  xmlDocUniquePtr pXmlDoc(xmlParseDoc(reinterpret_cast<xmlChar const *>(aOutput.getStr())));
598  //CPPUNIT_ASSERT(pXmlDoc);
599 
600  /* Test for the 1st paragraph */
601  OUString styleName = getXPath(pXmlDoc, "//draw:frame[1]//text:span[1]", "style-name");
602  OString xpath = "//office:automatic-styles/style:style[@style:name=\"" +
603  OUStringToOString(styleName, RTL_TEXTENCODING_UTF8) +
604  "\"]/style:text-properties";
605  // the font-weight and font-style should be normal (e.g., no such attribute)
606  assertXPathNoAttribute(pXmlDoc, xpath, "font-weight");
607  assertXPathNoAttribute(pXmlDoc, xpath, "font-style");
608 
609  /* Test for the 2nd paragraph */
610  styleName = getXPath(pXmlDoc, "//draw:frame[2]//text:span[1]", "style-name");
611  xpath = "//office:automatic-styles/style:style[@style:name=\"" +
612  OUStringToOString(styleName, RTL_TEXTENCODING_UTF8) +
613  "\"]/style:text-properties";
614  // there should be a font-weight="bold", but no font-style italic
615  assertXPath(pXmlDoc, xpath, "font-weight", "bold");
616  assertXPathNoAttribute(pXmlDoc, xpath, "font-style");
617 
618  /* Test for the 3rd paragraph */
619  styleName = getXPath(pXmlDoc, "//draw:frame[3]//text:span[1]", "style-name");
620  xpath = "//office:automatic-styles/style:style[@style:name=\"" +
621  OUStringToOString(styleName, RTL_TEXTENCODING_UTF8) +
622  "\"]/style:text-properties";
623  // there should be a font-style="italic", but no font-weight bold
624  assertXPathNoAttribute(pXmlDoc, xpath, "font-weight");
625  assertXPath(pXmlDoc, xpath, "font-style", "italic");
626 
627  /* Test for the 4th paragraph */
628  styleName = getXPath(pXmlDoc, "//draw:frame[4]//text:span[1]", "style-name");
629  xpath = "//office:automatic-styles/style:style[@style:name=\"" +
630  OUStringToOString(styleName, RTL_TEXTENCODING_UTF8) +
631  "\"]/style:text-properties";
632  // there should be both font-style="italic" and font-weight="bold"
633  assertXPath(pXmlDoc, xpath, "font-weight", "bold");
634  assertXPath(pXmlDoc, xpath, "font-style", "italic");
635 
636  /* Test for the 5th paragraph */
637  styleName = getXPath(pXmlDoc, "//draw:frame[5]//text:span[1]", "style-name");
638  xpath = "//office:automatic-styles/style:style[@style:name=\"" +
639  OUStringToOString(styleName, RTL_TEXTENCODING_UTF8) +
640  "\"]/style:text-properties";
641  // the font should be Arial and font-weight="bold", no font-style
642  assertXPath(pXmlDoc, xpath, "font-family", "Arial");
643  assertXPath(pXmlDoc, xpath, "font-weight", "bold");
644  assertXPathNoAttribute(pXmlDoc, xpath, "font-style");
645 
646  /* Test for the 6th paragraph */
647  styleName = getXPath(pXmlDoc, "//draw:frame[6]//text:span[1]", "style-name");
648  xpath = "//office:automatic-styles/style:style[@style:name=\"" +
649  OUStringToOString(styleName, RTL_TEXTENCODING_UTF8) +
650  "\"]/style:text-properties";
651  // the font should be Arial without font-weight and font-style
652  assertXPath(pXmlDoc, xpath, "font-family", "Arial");
653  assertXPathNoAttribute(pXmlDoc, xpath, "font-weight");
654  assertXPathNoAttribute(pXmlDoc, xpath, "font-style");
655 
656  /* Test for the 7th paragraph */
657  styleName = getXPath(pXmlDoc, "//draw:frame[7]//text:span[1]", "style-name");
658  xpath = "//office:automatic-styles/style:style[@style:name=\"" +
659  OUStringToOString(styleName, RTL_TEXTENCODING_UTF8) +
660  "\"]/style:text-properties";
661  // the font should be SimSun without font-weight and font-style
662  assertXPath(pXmlDoc, xpath, "font-family", "SimSun"); // TODO: tdf#143095 use localized font name rather than PS name
663  assertXPathNoAttribute(pXmlDoc, xpath, "font-weight");
664  assertXPathNoAttribute(pXmlDoc, xpath, "font-style");
665 
666  /* Test for the 8th paragraph */
667  styleName = getXPath(pXmlDoc, "//draw:frame[8]//text:span[1]", "style-name");
668  xpath = "//office:automatic-styles/style:style[@style:name=\"" +
669  OUStringToOString(styleName, RTL_TEXTENCODING_UTF8) +
670  "\"]/style:text-properties";
671  // the font should be SimSun and font-weight="bold", no font-style italic
672  assertXPath(pXmlDoc, xpath, "font-family", "SimSun");
673  assertXPath(pXmlDoc, xpath, "font-weight", "bold");
674  assertXPathNoAttribute(pXmlDoc, xpath, "font-style");
675 
676  /* Test for the 9th paragraph */
677  styleName = getXPath(pXmlDoc, "//draw:frame[9]//text:span[1]", "style-name");
678  xpath = "//office:automatic-styles/style:style[@style:name=\"" +
679  OUStringToOString(styleName, RTL_TEXTENCODING_UTF8) +
680  "\"]/style:text-properties";
681  // the font should be SimSun, no font-weight="bold", with font-style="italic"
682  assertXPath(pXmlDoc, xpath, "font-family", "SimSun");
683  assertXPathNoAttribute(pXmlDoc, xpath, "font-weight");
684  // FIXME and remove the below comment:
685  // the chinese chars are shown in pdf as faux italic (fake italic). It is currencly imported wrongly as normal font style.
686  // See tdf#78427 for how the faux bold problem was handled. Faux italic may be handled using the transformation pattern.
687  // assertXPath(pXmlDoc, xpath, "font-style", "italic");
688 
689  /* Test for the 10th paragraph */
690  styleName = getXPath(pXmlDoc, "//draw:frame[10]//text:span[1]", "style-name");
691  xpath = "//office:automatic-styles/style:style[@style:name=\"" +
692  OUStringToOString(styleName, RTL_TEXTENCODING_UTF8) +
693  "\"]/style:text-properties";
694  // the font should be SimSun font-weight="bold" and font-style="italic"
695  assertXPath(pXmlDoc, xpath, "font-family", "SimSun");
696  assertXPath(pXmlDoc, xpath, "font-weight", "bold");
697  // FIXME: faux italic, see above
698  // assertXPath(pXmlDoc, xpath, "font-style", "italic");
699 
700  /* Test for the 11th paragraph */
701  styleName = getXPath(pXmlDoc, "//draw:frame[11]//text:span[1]", "style-name");
702  xpath = "//office:automatic-styles/style:style[@style:name=\"" +
703  OUStringToOString(styleName, RTL_TEXTENCODING_UTF8) +
704  "\"]/style:text-properties";
705  // the font should be SimSun and there should be style:text-outline="true"
706  // (i.e., the real "outline" font rather than faux bold / fake bold)
707  assertXPath(pXmlDoc, xpath, "font-family", "SimSun");
708  assertXPathNoAttribute(pXmlDoc, xpath, "font-weight");
709  assertXPathNoAttribute(pXmlDoc, xpath, "font-style");
710  assertXPath(pXmlDoc, xpath, "text-outline", "true");
711  }
712 
713  void testTdf143959_nameFromFontFile()
714  {
716  xAdaptor->setTreeVisitorFactory(createDrawTreeVisitorFactory());
717 
718  OString aOutput;
719  CPPUNIT_ASSERT_MESSAGE("Converting PDF to ODF XML",
720  xAdaptor->odfConvert( m_directories.getURLFromSrc(u"/sdext/source/pdfimport/test/testdocs/testTdf143959.pdf"),
721  new OutputWrapString(aOutput),
722  nullptr ));
723 
724  //std::cout << aOutput << std::endl;
725  xmlDocUniquePtr pXmlDoc(xmlParseDoc(reinterpret_cast<xmlChar const *>(aOutput.getStr())));
726 
727  /* Test for the 1st text paragraph */
728  OUString styleName = getXPath(pXmlDoc, "//draw:frame[2]//text:span[1]", "style-name");
729  OString xpath = "//office:automatic-styles/style:style[@style:name=\"" +
730  OUStringToOString(styleName, RTL_TEXTENCODING_UTF8) +
731  "\"]/style:text-properties";
732  CPPUNIT_ASSERT_EQUAL(OUString("TimesNewRoman"),
733  getXPath(pXmlDoc, xpath, "font-family").replaceAll(u" ", u""));
734 
735  /* Test for the "TOTAL ESTA HOJA USD" paragraph" */
736  styleName = getXPath(pXmlDoc, "//draw:frame[last()-1]//text:span[1]", "style-name");
737  xpath = "//office:automatic-styles/style:style[@style:name=\"" +
738  OUStringToOString(styleName, RTL_TEXTENCODING_UTF8) +
739  "\"]/style:text-properties";
740  CPPUNIT_ASSERT_EQUAL(OUString("TimesNewRoman"),
741  getXPath(pXmlDoc, xpath, "font-family").replaceAll(u" ", u""));
742  CPPUNIT_ASSERT_EQUAL(OUString("bold"),
743  getXPath(pXmlDoc, xpath, "font-weight"));
744  }
745 
746  CPPUNIT_TEST_SUITE(PDFITest);
747  CPPUNIT_TEST(testXPDFParser);
748  CPPUNIT_TEST(testOdfWriterExport);
749  CPPUNIT_TEST(testOdfDrawExport);
750  CPPUNIT_TEST(testTdf96993);
751  CPPUNIT_TEST(testTdf98421);
752  CPPUNIT_TEST(testTdf105536);
753  CPPUNIT_TEST(testTdf141709);
754  CPPUNIT_TEST(testFontFeatures);
755  CPPUNIT_TEST(testTdf143959_nameFromFontFile);
756  CPPUNIT_TEST_SUITE_END();
757  };
758 
759 }
760 
762 
764 
765 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static void registerODFNamespaces(xmlXPathContextPtr &pXmlXpathCtx)
std::unique_ptr< xmlDoc, xmlDocDeleter > xmlDocUniquePtr
signed char sal_Int8
B2DPolyPolygon clipPolyPolygonOnPolyPolygon(const B2DPolyPolygon &rCandidate, const B2DPolyPolygon &rClip, bool bInside, bool bStroke)
DstType sequenceToContainer(const css::uno::Sequence< SrcType > &i_Sequence)
bool xpdf_ImportFromFile(const OUString &rURL, const ContentSinkSharedPtr &rSink, const css::uno::Reference< css::task::XInteractionHandler > &xIHdl, const OUString &rPwd, const css::uno::Reference< css::uno::XComponentContext > &xContext, const OUString &rFilterOptions)
Adapts raw pdf import to XImportFilter interface.
Definition: pdfiadaptor.hxx:82
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
def getCurrentContext()
uno_Any a
TreeVisitorFactorySharedPtr createWriterTreeVisitorFactory()
float u
void transform(const basegfx::B2DHomMatrix &rMatrix)
::basegfx::B2DPolyPolygon b2DPolyPolygonFromXPolyPolygon2D(const uno::Reference< rendering::XPolyPolygon2D > &xPoly)
exports com.sun.star.xml. xpath
Reference< XComponentContext > getComponentContext(Reference< XMultiServiceFactory > const &factory)
virtual void registerNamespaces(xmlXPathContextPtr &pXmlXpathCtx)
void assertXPathNoAttribute(const xmlDocUniquePtr &pXmlDoc, const OString &rXPath, const OString &rAttribute)
void assertXPath(const xmlDocUniquePtr &pXmlDoc, const OString &rXPath)
void append(const B2DPolygon &rPolygon, sal_uInt32 nCount=1)
DESKTOP_DEPLOYMENTMISC_DLLPUBLIC css::uno::Sequence< css::uno::Reference< css::xml::dom::XElement > > check(dp_misc::DescriptionInfoset const &infoset)
sal_uInt32 count() const
CPPUNIT_PLUGIN_IMPLEMENT()
CPPUNIT_TEST_SUITE_REGISTRATION(PDFITest)
::basegfx::B2DHomMatrix & homMatrixFromAffineMatrix(::basegfx::B2DHomMatrix &output, const geometry::AffineMatrix2D &input)
OUString exportToSvgD(const B2DPolyPolygon &rPolyPoly, bool bUseRelativeCoordinates, bool bDetectQuadraticBeziers, bool bHandleRelativeNextPointCompatible, bool bOOXMLMotionPath=false)
TreeVisitorFactorySharedPtr createDrawTreeVisitorFactory()
OUString getXPath(const xmlDocUniquePtr &pXmlDoc, const OString &rXPath, const OString &rAttribute)