tdf#147818 EMF+ Fix restoring clipping states
With previous implementation the clipping restoring with EmfPlusRecordTypeRestore
was implemented wrongly as it is only taken to account
the shape of clipping (state.getClipPolyPolygon) and doesn't
take if clipping was even enabled (state.getClipPolyPolygonActive).
Additionally the changing states should be made by using method:
wmfemfhelper::HandleNewClipRegion() and not directly.
The similar implementation was applied also to EmfPlusRecordTypeGetDC.
Additionally the clipping for
EmfPlusRecordTypeSetClipRect
EmfPlusRecordTypeSetClipPath
EmfPlusRecordTypeSetClipRegion
was fixed, as initially the clipping is disabled (state.getClipPolyPolygonActive)
and the clipping shape is empty (state.getClipPolyPolygon).
It means that combination other than EmfPlusCombineModeReplace,
was not working correctly.
With this implementation, if Clipping is disabled, then treat clip combining
in special way.
Change-Id: I258bda64e8bfdade7f47ffc7518bf04b7340344f
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132415
Tested-by: Jenkins
Reviewed-by: Bartosz Kosiorek <gang65@poczta.onet.pl>
diff --git a/drawinglayer/source/tools/emfphelperdata.cxx b/drawinglayer/source/tools/emfphelperdata.cxx
index 4476861..e60f881 100644
--- a/drawinglayer/source/tools/emfphelperdata.cxx
+++ b/drawinglayer/source/tools/emfphelperdata.cxx
@@ -486,18 +486,32 @@ namespace emfplushelper
map[ index ] = state;
}
void EmfPlusHelperData::GraphicStatePop(GraphicStateMap& map, sal_Int32 index, wmfemfhelper::PropertyHolder& rState)
void EmfPlusHelperData::GraphicStatePop(GraphicStateMap& map, sal_Int32 index)
{
GraphicStateMap::iterator iter = map.find( index );
GraphicStateMap::iterator iter = map.find(index);
if ( iter != map.end() )
if (iter != map.end())
{
wmfemfhelper::PropertyHolder state = iter->second;
maWorldTransform = state.getTransformation();
rState.setClipPolyPolygon( state.getClipPolyPolygon() );
if (state.getClipPolyPolygonActive())
{
SAL_INFO("drawinglayer.emf",
"EMF+\t Restore clipping region to saved in index: " << index);
wmfemfhelper::HandleNewClipRegion(state.getClipPolyPolygon(), mrTargetHolders,
mrPropertyHolders);
}
else
{
SAL_INFO("drawinglayer.emf", "EMF+\t Disable clipping");
wmfemfhelper::HandleNewClipRegion(::basegfx::B2DPolyPolygon(), mrTargetHolders,
mrPropertyHolders);
}
mappingChanged();
SAL_INFO("drawinglayer.emf", "EMF+\t\tStack index: " << index << " found, maWorldTransform: " << maWorldTransform);
SAL_INFO("drawinglayer.emf",
"EMF+\t\tStack index: " << index
<< " found, maWorldTransform: " << maWorldTransform);
}
}
@@ -1000,14 +1014,8 @@ namespace emfplushelper
}
case EmfPlusCombineModeIntersect:
{
if (leftPolygon.count())
{
aClippedPolyPolygon = basegfx::utils::clipPolyPolygonOnPolyPolygon(
leftPolygon,
rightPolygon,
true,
false);
}
aClippedPolyPolygon = basegfx::utils::clipPolyPolygonOnPolyPolygon(
leftPolygon, rightPolygon, true, false);
break;
}
case EmfPlusCombineModeUnion:
@@ -1080,8 +1088,18 @@ namespace emfplushelper
if (bIsGetDCProcessing)
{
SAL_INFO("drawinglayer.emf", "EMF+\t reset the current clipping region for the world space to infinity.");
wmfemfhelper::HandleNewClipRegion(::basegfx::B2DPolyPolygon(), mrTargetHolders, mrPropertyHolders);
if (aGetDCState.getClipPolyPolygonActive())
{
SAL_INFO("drawinglayer.emf", "EMF+\t Restore region to GetDC saved");
wmfemfhelper::HandleNewClipRegion(aGetDCState.getClipPolyPolygon(), mrTargetHolders,
mrPropertyHolders);
}
else
{
SAL_INFO("drawinglayer.emf", "EMF+\t Disable clipping");
wmfemfhelper::HandleNewClipRegion(::basegfx::B2DPolyPolygon(), mrTargetHolders,
mrPropertyHolders);
}
bIsGetDCProcessing = false;
}
if (type == EmfPlusRecordTypeObject && ((mbMultipart && (flags & 0x7fff) == (mMFlags & 0x7fff)) || (flags & 0x8000)))
@@ -1160,6 +1178,7 @@ namespace emfplushelper
case EmfPlusRecordTypeGetDC:
{
bIsGetDCProcessing = true;
aGetDCState = mrPropertyHolders.Current();
SAL_INFO("drawinglayer.emf", "EMF+\tAlready used in svtools wmf/emf filter parser");
break;
}
@@ -1819,7 +1838,7 @@ namespace emfplushelper
rMS.ReadUInt32(stackIndex);
SAL_INFO("drawinglayer.emf", "EMF+\t Restore stack index: " << stackIndex);
GraphicStatePop(mGSStack, stackIndex, mrPropertyHolders.Current());
GraphicStatePop(mGSStack, stackIndex);
break;
}
case EmfPlusRecordTypeBeginContainer:
@@ -1866,7 +1885,7 @@ namespace emfplushelper
rMS.ReadUInt32(stackIndex);
SAL_INFO("drawinglayer.emf", "EMF+\t End Container stack index: " << stackIndex);
GraphicStatePop(mGSContainerStack, stackIndex, mrPropertyHolders.Current());
GraphicStatePop(mGSContainerStack, stackIndex);
break;
}
case EmfPlusRecordTypeSetWorldTransform:
@@ -2001,62 +2020,95 @@ namespace emfplushelper
break;
}
case EmfPlusRecordTypeSetClipRect:
{
int combineMode = (flags >> 8) & 0xf;
SAL_INFO("drawinglayer.emf", "EMF+\t SetClipRect combine mode: " << combineMode);
float dx, dy, dw, dh;
ReadRectangle(rMS, dx, dy, dw, dh);
SAL_INFO("drawinglayer.emf", "EMF+\t RectData: " << dx << "," << dy << " " << dw << "x" << dh);
::basegfx::B2DPoint mappedPoint1(Map(dx, dy));
::basegfx::B2DPoint mappedPoint2(Map(dx + dw, dy + dh));
::basegfx::B2DPolyPolygon polyPolygon(
::basegfx::utils::createPolygonFromRect(
::basegfx::B2DRectangle(
mappedPoint1.getX(),
mappedPoint1.getY(),
mappedPoint2.getX(),
mappedPoint2.getY())));
HandleNewClipRegion(combineClip(mrPropertyHolders.Current().getClipPolyPolygon(),
combineMode, polyPolygon), mrTargetHolders, mrPropertyHolders);
break;
}
case EmfPlusRecordTypeSetClipPath:
{
int combineMode = (flags >> 8) & 0xf;
SAL_INFO("drawinglayer.emf", "EMF+\t SetClipPath combine mode: " << combineMode);
SAL_INFO("drawinglayer.emf", "EMF+\t Path in slot: " << (flags & 0xff));
EMFPPath *path = dynamic_cast<EMFPPath*>(maEMFPObjects[flags & 0xff].get());
if (!path)
{
SAL_WARN("drawinglayer.emf", "EMF+\t TODO Unable to find path in slot: " << (flags & 0xff));
break;
}
::basegfx::B2DPolyPolygon& clipPoly(path->GetPolygon(*this));
HandleNewClipRegion(combineClip(mrPropertyHolders.Current().getClipPolyPolygon(),
combineMode, clipPoly), mrTargetHolders, mrPropertyHolders);
break;
}
case EmfPlusRecordTypeSetClipRegion:
{
int combineMode = (flags >> 8) & 0xf;
SAL_INFO("drawinglayer.emf", "EMF+\t Region in slot: " << (flags & 0xff));
SAL_INFO("drawinglayer.emf", "EMF+\t Combine mode: " << combineMode);
EMFPRegion *region = dynamic_cast<EMFPRegion*>(maEMFPObjects[flags & 0xff].get());
if (!region)
::basegfx::B2DPolyPolygon polyPolygon;
if (type == EmfPlusRecordTypeSetClipRect)
{
SAL_WARN("drawinglayer.emf", "EMF+\t TODO Unable to find region in slot: " << (flags & 0xff));
break;
}
SAL_INFO("drawinglayer.emf", "EMF+\t SetClipRect");
HandleNewClipRegion(combineClip(mrPropertyHolders.Current().getClipPolyPolygon(),
combineMode, region->regionPolyPolygon), mrTargetHolders, mrPropertyHolders);
float dx, dy, dw, dh;
ReadRectangle(rMS, dx, dy, dw, dh);
SAL_INFO("drawinglayer.emf",
"EMF+\t RectData: " << dx << "," << dy << " " << dw << "x" << dh);
::basegfx::B2DPoint mappedPoint1(Map(dx, dy));
::basegfx::B2DPoint mappedPoint2(Map(dx + dw, dy + dh));
polyPolygon
= ::basegfx::B2DPolyPolygon(::basegfx::utils::createPolygonFromRect(
::basegfx::B2DRectangle(mappedPoint1.getX(), mappedPoint1.getY(),
mappedPoint2.getX(), mappedPoint2.getY())));
}
else if (type == EmfPlusRecordTypeSetClipPath)
{
SAL_INFO("drawinglayer.emf", "EMF+\tSetClipPath " << (flags & 0xff));
EMFPPath* path = dynamic_cast<EMFPPath*>(maEMFPObjects[flags & 0xff].get());
if (!path)
{
SAL_WARN("drawinglayer.emf",
"EMF+\t TODO Unable to find path in slot: " << (flags & 0xff));
break;
}
polyPolygon = path->GetPolygon(*this);
}
else if (type == EmfPlusRecordTypeSetClipRegion)
{
SAL_INFO("drawinglayer.emf", "EMF+\t Region in slot: " << (flags & 0xff));
EMFPRegion* region
= dynamic_cast<EMFPRegion*>(maEMFPObjects[flags & 0xff].get());
if (!region)
{
SAL_WARN(
"drawinglayer.emf",
"EMF+\t TODO Unable to find region in slot: " << (flags & 0xff));
break;
}
polyPolygon = region->regionPolyPolygon;
}
SAL_INFO("drawinglayer.emf", "EMF+\t Combine mode: " << combineMode);
::basegfx::B2DPolyPolygon aClippedPolyPolygon;
if (mrPropertyHolders.Current().getClipPolyPolygonActive())
{
aClippedPolyPolygon
= combineClip(mrPropertyHolders.Current().getClipPolyPolygon(),
combineMode, polyPolygon);
}
else
{
//Combine with infinity
switch (combineMode)
{
case EmfPlusCombineModeReplace:
case EmfPlusCombineModeIntersect:
{
aClippedPolyPolygon = polyPolygon;
break;
}
case EmfPlusCombineModeUnion:
{
// Disable clipping as the clipping is infinity
aClippedPolyPolygon = ::basegfx::B2DPolyPolygon();
break;
}
case EmfPlusCombineModeXOR:
case EmfPlusCombineModeComplement:
{
//TODO It is not correct and it should be fixed
aClippedPolyPolygon = polyPolygon;
break;
}
case EmfPlusCombineModeExclude:
{
//TODO It is not correct and it should be fixed
aClippedPolyPolygon = ::basegfx::B2DPolyPolygon();
break;
}
}
}
HandleNewClipRegion(aClippedPolyPolygon, mrTargetHolders, mrPropertyHolders);
break;
}
case EmfPlusRecordTypeOffsetClip:
diff --git a/drawinglayer/source/tools/emfphelperdata.hxx b/drawinglayer/source/tools/emfphelperdata.hxx
index cf3474b..563f777 100644
--- a/drawinglayer/source/tools/emfphelperdata.hxx
+++ b/drawinglayer/source/tools/emfphelperdata.hxx
@@ -213,6 +213,7 @@ namespace emfplushelper
/// data holders
wmfemfhelper::TargetHolders& mrTargetHolders;
wmfemfhelper::PropertyHolders& mrPropertyHolders;
wmfemfhelper::PropertyHolder aGetDCState;
bool bIsGetDCProcessing;
// readers
@@ -224,7 +225,7 @@ namespace emfplushelper
// stack actions
void GraphicStatePush(GraphicStateMap& map, sal_Int32 index);
void GraphicStatePop (GraphicStateMap& map, sal_Int32 index, wmfemfhelper::PropertyHolder& rState);
void GraphicStatePop(GraphicStateMap& map, sal_Int32 index);
// primitive creators
void EMFPPlusDrawPolygon(const ::basegfx::B2DPolyPolygon& polygon, sal_uInt32 penIndex);
diff --git a/emfio/qa/cppunit/emf/EmfImportTest.cxx b/emfio/qa/cppunit/emf/EmfImportTest.cxx
index fce8961..0f28169 100644
--- a/emfio/qa/cppunit/emf/EmfImportTest.cxx
+++ b/emfio/qa/cppunit/emf/EmfImportTest.cxx
@@ -63,6 +63,8 @@ class Test : public test::BootstrapFixture, public XmlTestTools, public unotest:
void TestSetArcDirection();
void TestDrawPolyLine16WithClip();
void TestFillRegion();
void TestEmfPlusGetDC();
void TestEmfPlusSave();
void TestExtTextOutOpaqueAndClipTransform();
void TestBitBltStretchBltWMF();
@@ -106,6 +108,8 @@ public:
CPPUNIT_TEST(TestSetArcDirection);
CPPUNIT_TEST(TestDrawPolyLine16WithClip);
CPPUNIT_TEST(TestFillRegion);
CPPUNIT_TEST(TestEmfPlusGetDC);
CPPUNIT_TEST(TestEmfPlusSave);
CPPUNIT_TEST(TestExtTextOutOpaqueAndClipTransform);
CPPUNIT_TEST(TestBitBltStretchBltWMF);
@@ -828,6 +832,68 @@ void Test::TestPolylinetoCloseStroke()
assertXPath(pDocument, aXPathPrefix + "polygonhairline[2]", "color", "#000000");
}
void Test::TestEmfPlusGetDC()
{
// tdf#147818 EMF+ records: GetDC, DrawPath, FillRects
Primitive2DSequence aSequence = parseEmf(u"/emfio/qa/cppunit/emf/data/TestEmfPlusGetDC.emf");
CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aSequence.getLength()));
drawinglayer::Primitive2dXmlDump dumper;
xmlDocUniquePtr pDocument = dumper.dumpAndParse(Primitive2DContainer(aSequence));
CPPUNIT_ASSERT(pDocument);
assertXPath(pDocument, aXPathPrefix + "textsimpleportion", "text", "sd CCCCCCCCCCCCCCC");
assertXPath(pDocument, aXPathPrefix + "textsimpleportion", "fontcolor", "#000000");
assertXPath(pDocument, aXPathPrefix + "group", 5);
assertXPath(
pDocument, aXPathPrefix + "group[4]/textsimpleportion", "text",
"Getttttttttttttttttttttttttttttt, uuuu: \"eeeeeeeeeeeeeeeeeeeeeee-7acd04a3953b\")");
assertXPath(pDocument, aXPathPrefix + "group[5]/textsimpleportion", "text",
"TTTTTTTTTTTTTTTTTTTTTTTTTTTTT, trackId: 55)");
assertXPath(pDocument, aXPathPrefix + "group[5]/textsimpleportion", "fontcolor", "#000000");
assertXPath(pDocument, aXPathPrefix + "polypolygoncolor", 6);
assertXPath(pDocument, aXPathPrefix + "polypolygoncolor[1]/polypolygon", "path",
"m105.78125 "
"776.111111111111h3878.64583333333l458.385416666667-493.888888888889v-176."
"388888888889h-4337.03125v670.277777777778");
assertXPath(pDocument, aXPathPrefix + "polypolygoncolor[1]", "color", "#ffffff");
assertXPath(pDocument, aXPathPrefix + "polypolygoncolor[3]/polypolygon", "path",
"m2291.92708333333 4550.83333333333h317.34375v-317.5h-317.34375z");
assertXPath(pDocument, aXPathPrefix + "polypolygoncolor[3]", "color", "#fcf2e3");
assertXPath(pDocument, aXPathPrefix + "polypolygoncolor[6]/polypolygon", "path",
"m19428.4895833333 6632.22222222222h317.34375v-2398.88888888889h-317.34375z");
assertXPath(pDocument, aXPathPrefix + "polypolygoncolor[6]", "color", "#fcf2e3");
assertXPath(pDocument, aXPathPrefix + "polypolygonstroke", 15);
}
void Test::TestEmfPlusSave()
{
// tdf#147818 EMF+ records: Save, Restore, SetWorldTransform, FillRects, SetClipRegion
Primitive2DSequence aSequence = parseEmf(u"/emfio/qa/cppunit/emf/data/TestEmfPlusSave.emf");
CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aSequence.getLength()));
drawinglayer::Primitive2dXmlDump dumper;
xmlDocUniquePtr pDocument = dumper.dumpAndParse(Primitive2DContainer(aSequence));
CPPUNIT_ASSERT(pDocument);
assertXPath(pDocument, aXPathPrefix + "mask/polypolygon", "path", "m0 0h33544v21311h-33544z");
assertXPath(pDocument, aXPathPrefix + "mask/group/mask/polypolygoncolor/polypolygon", "path",
"m327.458333333333 638.222222222222h437007.1875v295555.555555556h-437007.1875z");
assertXPath(pDocument, aXPathPrefix + "mask/group/mask/polypolygoncolor", "color", "#ff0cad");
assertXPath(pDocument, aXPathPrefix + "mask/polypolygoncolor/polypolygon", "path",
"m10853.4145539602 7321.41354709201h41952690v29630720h-41952690z");
assertXPath(pDocument, aXPathPrefix + "mask/polypolygoncolor", "color", "#00ffad");
assertXPath(pDocument, aXPathPrefix + "mask/polypolygonstroke/line", "color", "#000000");
assertXPath(pDocument, aXPathPrefix + "mask/polypolygonstroke/polypolygon", "path",
"m10853.4145539602 7321.41354709201v-2413.87029012044h1979.24116969109");
}
void Test::TestExtTextOutOpaqueAndClipTransform()
{
// tdf#142495 EMF records: SETBKCOLOR, SELECTOBJECT, EXTTEXTOUTW, MODIFYWORLDTRANSFORM, CREATEFONTINDIRECT.
diff --git a/emfio/qa/cppunit/emf/data/TestEmfPlusGetDC.emf b/emfio/qa/cppunit/emf/data/TestEmfPlusGetDC.emf
new file mode 100644
index 0000000..665364a
--- /dev/null
+++ b/emfio/qa/cppunit/emf/data/TestEmfPlusGetDC.emf
Binary files differ
diff --git a/emfio/qa/cppunit/emf/data/TestEmfPlusSave.emf b/emfio/qa/cppunit/emf/data/TestEmfPlusSave.emf
new file mode 100644
index 0000000..2466223
--- /dev/null
+++ b/emfio/qa/cppunit/emf/data/TestEmfPlusSave.emf
Binary files differ