cppcanvas/source/mtfrenderer/emfplus.cxx | 12 - cppcanvas/source/mtfrenderer/emfpregion.cxx | 170 +++++++++++++++++++++++----- cppcanvas/source/mtfrenderer/emfpregion.hxx | 21 ++- 3 files changed, 165 insertions(+), 38 deletions(-)
New commits: commit ff248538cbe5a74dbe31049097a0d569b829efa9 Author: Bartosz Kosiorek <[email protected]> AuthorDate: Sun Nov 5 00:02:49 2017 +0100 Commit: Miklos Vajna <[email protected]> CommitDate: Thu Mar 12 09:22:08 2020 +0100 tdf#113704 Implement proper reading of the EmfPlusRegionNode Regions are specified as a binary tree of region nodes, and each node must either be a terminal node or specify one or two child nodes. Nodes contains two child nodes: RegionNodeDataTypeAnd = 0x00000001, RegionNodeDataTypeOr = 0x00000002, RegionNodeDataTypeXor = 0x00000003, RegionNodeDataTypeExclude = 0x00000004, RegionNodeDataTypeComplement = 0x00000005, Terminal nodes: RegionNodeDataTypeRect = 0x10000000, RegionNodeDataTypePath = 0x10000001, RegionNodeDataTypeEmpty = 0x10000002, RegionNodeDataTypeInfinite = 0x10000003 RegionNode must contain at least one element. (cherry picked from commit d0c4cee7e5ad00363d264aec0011a4b07983b19d) Conflicts: drawinglayer/source/tools/emfpbrush.cxx drawinglayer/source/tools/emfpcustomlinecap.cxx drawinglayer/source/tools/emfphelperdata.cxx drawinglayer/source/tools/emfphelperdata.hxx drawinglayer/source/tools/emfppath.cxx drawinglayer/source/tools/emfpregion.cxx sw/source/ui/config/optload.src vcl/source/src/units.src Change-Id: I668e5892701b979f09bcf5bbce44a43226676192 diff --git a/cppcanvas/source/mtfrenderer/emfplus.cxx b/cppcanvas/source/mtfrenderer/emfplus.cxx index 8cfd1127540e..736e181dcbfe 100644 --- a/cppcanvas/source/mtfrenderer/emfplus.cxx +++ b/cppcanvas/source/mtfrenderer/emfplus.cxx @@ -129,8 +129,6 @@ namespace #define EmfPlusObjectTypeImageAttributes 0x800 #define EmfPlusObjectTypeCustomLineCap 0x900 -#define EmfPlusRegionInitialStateInfinite 0x10000003 - enum EmfPlusCombineMode { EmfPlusCombineModeReplace = 0x00000000, @@ -748,7 +746,7 @@ namespace cppcanvas EMFPRegion *region; aObjects [index] = region = new EMFPRegion (); - region->Read (rObjectStream); + region->ReadRegion (rObjectStream, *this); break; } @@ -1572,11 +1570,9 @@ namespace cppcanvas SAL_INFO("cppcanvas.emf", "EMF+\tregion in slot: " << (flags & 0xff) << " combine mode: " << combineMode); EMFPRegion *region = static_cast<EMFPRegion*>(aObjects [flags & 0xff]); - // reset clip - if (region && region->parts == 0 && region->initialState == EmfPlusRegionInitialStateInfinite) { - updateClipping (::basegfx::B2DPolyPolygon (), rFactoryParms, combineMode == 1); - } else { - SAL_INFO("cppcanvas.emf", "EMF+\tTODO"); + if (region) + { + updateClipping(region->regionPolyPolygon, rFactoryParms, combineMode == 1); } break; } diff --git a/cppcanvas/source/mtfrenderer/emfpregion.cxx b/cppcanvas/source/mtfrenderer/emfpregion.cxx index 99db436fb5aa..08a7b5afe906 100755 --- a/cppcanvas/source/mtfrenderer/emfpregion.cxx +++ b/cppcanvas/source/mtfrenderer/emfpregion.cxx @@ -37,56 +37,176 @@ #include <vcl/canvastools.hxx> #include <implrenderer.hxx> #include <emfpregion.hxx> +#include <emfppath.hxx> +#include <basegfx/polygon/b2dpolygonclipper.hxx> +#include <basegfx/polygon/b2dpolypolygoncutter.hxx> using namespace ::com::sun::star; using namespace ::basegfx; +enum EmfPlusCombineMode +{ + EmfPlusCombineModeReplace = 0x00000000, + EmfPlusCombineModeIntersect = 0x00000001, + EmfPlusCombineModeUnion = 0x00000002, + EmfPlusCombineModeXOR = 0x00000003, + EmfPlusCombineModeExclude = 0x00000004, + EmfPlusCombineModeComplement = 0x00000005 +}; + namespace cppcanvas { namespace internal { EMFPRegion::EMFPRegion() - : parts(0) - , combineMode(nullptr) - , initialState(0) - , ix(0.0) - , iy(0.0) - , iw(0.0) - , ih(0.0) { } EMFPRegion::~EMFPRegion() { - if (combineMode) { - delete[] combineMode; - combineMode = nullptr; + } + + ::basegfx::B2DPolyPolygon combineClip(::basegfx::B2DPolyPolygon const & leftPolygon, int combineMode, ::basegfx::B2DPolyPolygon const & rightPolygon) + { + basegfx::B2DPolyPolygon aClippedPolyPolygon; + switch (combineMode) + { + case EmfPlusCombineModeReplace: + { + aClippedPolyPolygon = rightPolygon; + break; + } + case EmfPlusCombineModeIntersect: + { + if (leftPolygon.count()) + { + aClippedPolyPolygon = basegfx::tools::clipPolyPolygonOnPolyPolygon( + leftPolygon, + rightPolygon, + true, + false); + } + break; + } + case EmfPlusCombineModeUnion: + { + aClippedPolyPolygon = ::basegfx::tools::solvePolygonOperationOr(leftPolygon, rightPolygon); + break; + } + case EmfPlusCombineModeXOR: + { + aClippedPolyPolygon = ::basegfx::tools::solvePolygonOperationXor(leftPolygon, rightPolygon); + break; + } + case EmfPlusCombineModeExclude: + { + // Replaces the existing region with the part of itself that is not in the new region. + aClippedPolyPolygon = ::basegfx::tools::solvePolygonOperationDiff(leftPolygon, rightPolygon); + break; + } + case EmfPlusCombineModeComplement: + { + // Replaces the existing region with the part of the new region that is not in the existing region. + aClippedPolyPolygon = ::basegfx::tools::solvePolygonOperationDiff(rightPolygon, leftPolygon); + break; + } } + return aClippedPolyPolygon; } - void EMFPRegion::Read(SvStream& s) + ::basegfx::B2DPolyPolygon EMFPRegion::ReadRegionNode(SvStream& s, ImplRenderer& rR) { - sal_uInt32 header; + // Regions are specified as a binary tree of region nodes, and each node must either be a terminal node + // (RegionNodeDataTypeRect, RegionNodeDataTypePath, RegionNodeDataTypeEmpty, RegionNodeDataTypeInfinite) + // or specify one or two child nodes + // (RegionNodeDataTypeAnd, RegionNodeDataTypeOr, RegionNodeDataTypeXor, + // RegionNodeDataTypeExclude, RegionNodeDataTypeComplement). + sal_uInt32 dataType; + ::basegfx::B2DPolyPolygon polygon; + s.ReadUInt32(dataType); + SAL_INFO("cppcanvas.emf", "EMF+\t Region node data type 0x" << std::hex << dataType << std::dec); - s.ReadUInt32(header).ReadInt32(parts); + switch (dataType) + { + case RegionNodeDataTypeAnd: // CombineModeIntersect + case RegionNodeDataTypeOr: // CombineModeUnion + case RegionNodeDataTypeXor: // CombineModeXOR + case RegionNodeDataTypeExclude: // CombineModeExclude + case RegionNodeDataTypeComplement: // CombineModeComplement + { + ::basegfx::B2DPolyPolygon leftPolygon = ReadRegionNode(s, rR); + ::basegfx::B2DPolyPolygon rightPolygon = ReadRegionNode(s, rR); + polygon = combineClip(leftPolygon, dataType, rightPolygon); + break; + } + case RegionNodeDataTypeRect: + { + float dx, dy, dw, dh; + s.ReadFloat(dx).ReadFloat(dy).ReadFloat(dw).ReadFloat(dh); + SAL_INFO("cppcanvas.emf", "EMF+\t\t RegionNodeDataTypeRect x:" << dx << ", y:" << dy << + ", width:" << dw << ", height:" << dh); - SAL_INFO("cppcanvas.emf", "EMF+\tregion"); - SAL_INFO("cppcanvas.emf", "EMF+\theader: 0x" << std::hex << header << " parts: " << parts << std::dec); + const ::basegfx::B2DPoint mappedStartPoint(rR.Map(dx, dy)); + const ::basegfx::B2DPoint mappedEndPoint(rR.Map(dx + dw, dy + dh)); + const ::basegfx::B2DPolyPolygon polyPolygon( + ::basegfx::tools::createPolygonFromRect( + ::basegfx::B2DRectangle( + mappedStartPoint.getX(), + mappedStartPoint.getY(), + mappedEndPoint.getX(), + mappedEndPoint.getY()))); + polygon = polyPolygon; + break; + } + case RegionNodeDataTypePath: + { + sal_Int32 pathLength; + s.ReadInt32(pathLength); + SAL_INFO("cppcanvas.emf", "EMF+\t\t RegionNodeDataTypePath, Path Length: " << pathLength << " bytes"); - if (parts) { - if (parts<0 || sal_uInt32(parts)>SAL_MAX_INT32 / sizeof(sal_Int32)) - parts = SAL_MAX_INT32 / sizeof(sal_Int32); + sal_uInt32 header, pathFlags; + sal_Int32 points; - combineMode = new sal_Int32[parts]; + s.ReadUInt32(header).ReadInt32(points).ReadUInt32(pathFlags); + SAL_INFO("cppcanvas.emf", "EMF+\t\t header: 0x" << std::hex << header << + " points: " << std::dec << points << " additional flags: 0x" << std::hex << pathFlags << std::dec); - for (int i = 0; i < parts; i++) { - s.ReadInt32(combineMode[i]); - SAL_INFO("cppcanvas.emf", "EMF+\tcombine mode [" << i << "]: 0x" << std::hex << combineMode[i] << std::dec); - } + EMFPPath path(points); + path.Read(s, pathFlags, rR); + polygon = path.GetPolygon(rR); + break; + } + case RegionNodeDataTypeEmpty: + { + SAL_INFO("cppcanvas.emf", "EMF+\t\t RegionNodeDataTypeEmpty"); + SAL_WARN("cppcanvas.emf", "EMF+\t\t TODO we need to set empty polygon here"); + polygon = ::basegfx::B2DPolyPolygon(); + + break; + } + case RegionNodeDataTypeInfinite: + { + SAL_INFO("cppcanvas.emf", "EMF+\t\t RegionNodeDataTypeInfinite"); + polygon = ::basegfx::B2DPolyPolygon(); + break; } + default: + { + SAL_WARN("cppcanvas.emf", "EMF+\t\t Unhandled region type: 0x" << std::hex << dataType << std::dec); + polygon = ::basegfx::B2DPolyPolygon(); + } + } + return polygon; + } + + void EMFPRegion::ReadRegion(SvStream& s, ImplRenderer& rR) + { + sal_uInt32 header, count; + s.ReadUInt32(header).ReadUInt32(count); + // An array should be RegionNodeCount+1 of EmfPlusRegionNode objects. + SAL_INFO("cppcanvas.emf", "EMF+\t version: 0x" << std::hex << header << std::dec << ", region node count: " << count); - s.ReadInt32(initialState); - SAL_INFO("cppcanvas.emf", "EMF+\tinitial state: 0x" << std::hex << initialState << std::dec); + regionPolyPolygon = ReadRegionNode(s, rR); } } } diff --git a/cppcanvas/source/mtfrenderer/emfpregion.hxx b/cppcanvas/source/mtfrenderer/emfpregion.hxx index 876aebcdbd67..a1e1ca0c22ab 100755 --- a/cppcanvas/source/mtfrenderer/emfpregion.hxx +++ b/cppcanvas/source/mtfrenderer/emfpregion.hxx @@ -24,16 +24,27 @@ namespace cppcanvas { namespace internal { + typedef enum + { + RegionNodeDataTypeAnd = 0x00000001, + RegionNodeDataTypeOr = 0x00000002, + RegionNodeDataTypeXor = 0x00000003, + RegionNodeDataTypeExclude = 0x00000004, + RegionNodeDataTypeComplement = 0x00000005, + RegionNodeDataTypeRect = 0x10000000, + RegionNodeDataTypePath = 0x10000001, + RegionNodeDataTypeEmpty = 0x10000002, + RegionNodeDataTypeInfinite = 0x10000003 + } RegionNodeDataType; + struct EMFPRegion : public EMFPObject { - sal_Int32 parts; - sal_Int32 *combineMode; - sal_Int32 initialState; - float ix, iy, iw, ih; + ::basegfx::B2DPolyPolygon regionPolyPolygon; EMFPRegion(); virtual ~EMFPRegion() override; - void Read(SvStream& s); + void ReadRegion(SvStream& s, ImplRenderer& rR); + ::basegfx::B2DPolyPolygon ReadRegionNode(SvStream& s, ImplRenderer& rR); }; } } _______________________________________________ Libreoffice-commits mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits
