summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBartosz Kosiorek <gang65@poczta.onet.pl>2017-11-05 00:02:49 +0100
committerMiklos Vajna <vmiklos@collabora.com>2020-03-12 09:22:08 +0100
commitff248538cbe5a74dbe31049097a0d569b829efa9 (patch)
tree82d13bda084c00072b035ac2b2fbab763605cab2
parent526f5ef73aad1d4e8d91b9c31aaa97b8215d1ee9 (diff)
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
-rw-r--r--cppcanvas/source/mtfrenderer/emfplus.cxx12
-rwxr-xr-xcppcanvas/source/mtfrenderer/emfpregion.cxx170
-rwxr-xr-xcppcanvas/source/mtfrenderer/emfpregion.hxx21
3 files changed, 165 insertions, 38 deletions
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);
};
}
}