summaryrefslogtreecommitdiff
path: root/vcl
diff options
context:
space:
mode:
authorArmin.Le.Grand (CIB) <Armin.Le.Grand@me.com>2020-03-03 11:34:45 +0100
committerThorsten Behrens <thorsten.behrens@allotropia.de>2021-04-09 23:21:27 +0200
commit1a9ef8b0e3fb77944dcd7223f90345645c7e7410 (patch)
tree5567044a35317d3405e69183afc2c83a79998ff9 /vcl
parent84092ae74d5ebb0685a6fe6b69cc7a544478b197 (diff)
tdf#130150 Improve clipping in PDF export
For more info and discusson please have a look at the task. It reverts the change from tdf#99680 which did a wrong paradigm change in how clip in Region(s) is defined and tries to fix the underlying error in a more correct way. This includes problems noted in tdf#44388 and tdf#113449. This is a decent improvement, but - due to dealing with numerical problems - not yet the whole healing. Still thinking about how to solve this for good. Adapted PdfExportTest::testTdf99680() and PdfExportTest::testTdf99680_2() as needed, empty clip regions are allowed again. Added comments, too. Had to change solvePolygonOperationAnd to work on ranges if both inputs *are* ranges. The AND-case is then completely solvable. Also increased geometry for transformations of clip geometries - may help later. Change-Id: I2370447597faa6efb81d58ee31c63654e304262e Reviewed-on: https://gerrit.libreoffice.org/c/core/+/89874 Tested-by: Jenkins Reviewed-by: Thorsten Behrens <Thorsten.Behrens@CIB.de>
Diffstat (limited to 'vcl')
-rw-r--r--vcl/qa/cppunit/pdfexport/pdfexport.cxx28
-rw-r--r--vcl/source/gdi/pdfwriter_impl.cxx54
2 files changed, 56 insertions, 26 deletions
diff --git a/vcl/qa/cppunit/pdfexport/pdfexport.cxx b/vcl/qa/cppunit/pdfexport/pdfexport.cxx
index f46f94b10b4c..ff5f877b050b 100644
--- a/vcl/qa/cppunit/pdfexport/pdfexport.cxx
+++ b/vcl/qa/cppunit/pdfexport/pdfexport.cxx
@@ -811,15 +811,17 @@ void PdfExportTest::testTdf99680()
aZCodec.Decompress(rObjectStream, aUncompressed);
CPPUNIT_ASSERT(aZCodec.EndCompression());
- // Make sure there are no empty clipping regions.
- OString aEmptyRegion("0 0 m h W* n");
- auto pStart = static_cast<const char*>(aUncompressed.GetData());
- const char* pEnd = pStart + aUncompressed.GetSize();
- auto it = std::search(pStart, pEnd, aEmptyRegion.getStr(), aEmptyRegion.getStr() + aEmptyRegion.getLength());
- CPPUNIT_ASSERT_EQUAL_MESSAGE("Empty clipping region detected!", it, pEnd);
+ // tdf#130150 See infos in task - short: tdf#99680 was not the
+ // correct fix, so empty clip regions are valid - allow again in tests
+ // Make sure there are no empty clipping regions.
+ // OString aEmptyRegion("0 0 m h W* n");
+ // auto it = std::search(pStart, pEnd, aEmptyRegion.getStr(), aEmptyRegion.getStr() + aEmptyRegion.getLength());
+ // CPPUNIT_ASSERT_EQUAL_MESSAGE("Empty clipping region detected!", it, pEnd);
// Count save graphic state (q) and restore (Q) operators
// and ensure their amount is equal
+ auto pStart = static_cast<const char*>(aUncompressed.GetData());
+ const char* pEnd = pStart + aUncompressed.GetSize();
size_t nSaveCount = std::count(pStart, pEnd, 'q');
size_t nRestoreCount = std::count(pStart, pEnd, 'Q');
CPPUNIT_ASSERT_EQUAL_MESSAGE("Save/restore graphic state operators count mismatch!", nSaveCount, nRestoreCount);
@@ -850,15 +852,17 @@ void PdfExportTest::testTdf99680_2()
aZCodec.Decompress(rObjectStream, aUncompressed);
CPPUNIT_ASSERT(aZCodec.EndCompression());
- // Make sure there are no empty clipping regions.
- OString aEmptyRegion("0 0 m h W* n");
- auto pStart = static_cast<const char*>(aUncompressed.GetData());
- const char* pEnd = pStart + aUncompressed.GetSize();
- auto it = std::search(pStart, pEnd, aEmptyRegion.getStr(), aEmptyRegion.getStr() + aEmptyRegion.getLength());
- CPPUNIT_ASSERT_EQUAL_MESSAGE("Empty clipping region detected!", it, pEnd);
+ // tdf#130150 See infos in task - short: tdf#99680 was not the
+ // correct fix, so empty clip regions are valid - allow again in tests
+ // Make sure there are no empty clipping regions.
+ // OString aEmptyRegion("0 0 m h W* n");
+ // auto it = std::search(pStart, pEnd, aEmptyRegion.getStr(), aEmptyRegion.getStr() + aEmptyRegion.getLength());
+ // CPPUNIT_ASSERT_EQUAL_MESSAGE("Empty clipping region detected!", it, pEnd);
// Count save graphic state (q) and restore (Q) operators
// and ensure their amount is equal
+ auto pStart = static_cast<const char*>(aUncompressed.GetData());
+ const char* pEnd = pStart + aUncompressed.GetSize();
size_t nSaveCount = std::count(pStart, pEnd, 'q');
size_t nRestoreCount = std::count(pStart, pEnd, 'Q');
CPPUNIT_ASSERT_EQUAL_MESSAGE("Save/restore graphic state operators count mismatch!", nSaveCount, nRestoreCount);
diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
index e1186fa22f32..1a5f772af2e5 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -9849,8 +9849,15 @@ void PDFWriterImpl::updateGraphicsState(Mode const mode)
if ( rNewState.m_aClipRegion.count() )
{
m_aPages.back().appendPolyPolygon( rNewState.m_aClipRegion, aLine );
- aLine.append( "W* n\n" );
}
+ else
+ {
+ // tdf#130150 Need to revert tdf#99680, that breaks the
+ // rule that an set but empty clip-region clips everything
+ // aka draws nothing -> nothing is in an empty clip-region
+ aLine.append( "0 0 m h " ); // NULL clip, i.e. nothing visible
+ }
+ aLine.append( "W* n\n" );
rNewState.m_aMapMode = aNewMapMode;
SetMapMode( rNewState.m_aMapMode );
@@ -9995,8 +10002,12 @@ void PDFWriterImpl::setMapMode( const MapMode& rMapMode )
void PDFWriterImpl::setClipRegion( const basegfx::B2DPolyPolygon& rRegion )
{
- basegfx::B2DPolyPolygon aRegion = LogicToPixel( rRegion, m_aGraphicsStack.front().m_aMapMode );
- aRegion = PixelToLogic( aRegion, m_aMapMode );
+ // tdf#130150 improve coordinate manipulations to double precision transformations
+ const basegfx::B2DHomMatrix aCurrentTransform(
+ GetInverseViewTransformation(m_aMapMode) * GetViewTransformation(m_aGraphicsStack.front().m_aMapMode));
+ basegfx::B2DPolyPolygon aRegion(rRegion);
+
+ aRegion.transform(aCurrentTransform);
m_aGraphicsStack.front().m_aClipRegion = aRegion;
m_aGraphicsStack.front().m_bClipRegion = true;
m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsStateUpdateFlags::ClipRegion;
@@ -10006,16 +10017,26 @@ void PDFWriterImpl::moveClipRegion( sal_Int32 nX, sal_Int32 nY )
{
if( m_aGraphicsStack.front().m_bClipRegion && m_aGraphicsStack.front().m_aClipRegion.count() )
{
- Point aPoint( lcl_convert( m_aGraphicsStack.front().m_aMapMode,
- m_aMapMode,
- this,
- Point( nX, nY ) ) );
- aPoint -= lcl_convert( m_aGraphicsStack.front().m_aMapMode,
- m_aMapMode,
- this,
- Point() );
+ // tdf#130150 improve coordinate manipulations to double precision transformations
+ basegfx::B2DHomMatrix aConvertA;
+
+ if(MapUnit::MapPixel == m_aGraphicsStack.front().m_aMapMode.GetMapUnit())
+ {
+ aConvertA = GetInverseViewTransformation(m_aMapMode);
+ }
+ else
+ {
+ aConvertA = LogicToLogic(m_aGraphicsStack.front().m_aMapMode, m_aMapMode);
+ }
+
+ basegfx::B2DPoint aB2DPointA(nX, nY);
+ basegfx::B2DPoint aB2DPointB(0.0, 0.0);
+ aB2DPointA *= aConvertA;
+ aB2DPointB *= aConvertA;
+ aB2DPointA -= aB2DPointB;
basegfx::B2DHomMatrix aMat;
- aMat.translate( aPoint.X(), aPoint.Y() );
+
+ aMat.translate(aB2DPointA.getX(), aB2DPointA.getY());
m_aGraphicsStack.front().m_aClipRegion.transform( aMat );
m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsStateUpdateFlags::ClipRegion;
}
@@ -10030,9 +10051,14 @@ void PDFWriterImpl::intersectClipRegion( const tools::Rectangle& rRect )
void PDFWriterImpl::intersectClipRegion( const basegfx::B2DPolyPolygon& rRegion )
{
- basegfx::B2DPolyPolygon aRegion( LogicToPixel( rRegion, m_aGraphicsStack.front().m_aMapMode ) );
- aRegion = PixelToLogic( aRegion, m_aMapMode );
+ // tdf#130150 improve coordinate manipulations to double precision transformations
+ const basegfx::B2DHomMatrix aCurrentTransform(
+ GetInverseViewTransformation(m_aMapMode) * GetViewTransformation(m_aGraphicsStack.front().m_aMapMode));
+ basegfx::B2DPolyPolygon aRegion(rRegion);
+
+ aRegion.transform(aCurrentTransform);
m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsStateUpdateFlags::ClipRegion;
+
if( m_aGraphicsStack.front().m_bClipRegion )
{
basegfx::B2DPolyPolygon aOld( basegfx::utils::prepareForPolygonOperation( m_aGraphicsStack.front().m_aClipRegion ) );