[Libreoffice-commits] core.git: basegfx/source drawinglayer/source filter/source include/basegfx include/vcl vcl/Library_vcl.mk vcl/source
Armin Le Grand
alg at apache.org
Wed Jun 12 07:39:12 PDT 2013
basegfx/source/polygon/b2dpolygontools.cxx | 2
basegfx/source/polygon/b2dpolypolygontools.cxx | 20
drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx | 76
drawinglayer/source/processor2d/vclprocessor2d.cxx | 36
filter/source/flash/swfexporter.cxx | 11
filter/source/graphicfilter/eos2met/eos2met.cxx | 19
include/basegfx/polygon/b2dpolypolygontools.hxx | 6
include/vcl/gdimetafiletools.hxx | 43
vcl/Library_vcl.mk | 1
vcl/source/filter/wmf/wmf.cxx | 25
vcl/source/gdi/gdimetafiletools.cxx | 1095 +++++++++++++
11 files changed, 1297 insertions(+), 37 deletions(-)
New commits:
commit 70e3eb2c1762fb1ca097cf671e3c7ce3d0dfd1b7
Author: Armin Le Grand <alg at apache.org>
Date: Fri Oct 26 11:00:48 2012 +0000
Resolves: #i121267# added support for taking clipping into account...
for metafile-based exporters to vector formats
(cherry picked from commit 229a79b97110c11ef21b7b99ffc768254ca01d96)
Conflicts:
basegfx/inc/basegfx/polygon/b2dpolypolygontools.hxx
filter/source/flash/swfexporter.cxx
filter/source/graphicfilter/eos2met/eos2met.cxx
svtools/source/filter/wmf/wmf.cxx
vcl/Package_inc.mk
Remove unused variable to prevent compile warnings.
(cherry picked from commit 60d19c1602e4fec740624fd20a7bfd39707297e4)
Change-Id: Iaeb02d7321bea2890cf4e969f1d45d58deef5584
106285f06a21f4f39f34c6755d12ac6cd4196a7f
diff --git a/basegfx/source/polygon/b2dpolygontools.cxx b/basegfx/source/polygon/b2dpolygontools.cxx
index 24affdf..59b2813 100644
--- a/basegfx/source/polygon/b2dpolygontools.cxx
+++ b/basegfx/source/polygon/b2dpolygontools.cxx
@@ -489,8 +489,6 @@ namespace basegfx
fRetval -= aPreviousPoint.getY() * aCurrentPoint.getX();
}
- fRetval /= 2.0;
-
// correct to zero if small enough. Also test the quadratic
// of the result since the precision is near quadratic due to
// the algorithm
diff --git a/basegfx/source/polygon/b2dpolypolygontools.cxx b/basegfx/source/polygon/b2dpolypolygontools.cxx
index 8a5337b..c2b18ef 100644
--- a/basegfx/source/polygon/b2dpolypolygontools.cxx
+++ b/basegfx/source/polygon/b2dpolypolygontools.cxx
@@ -243,6 +243,26 @@ namespace basegfx
return aRetval;
}
+ double getSignedArea(const B2DPolyPolygon& rCandidate)
+ {
+ double fRetval(0.0);
+ const sal_uInt32 nPolygonCount(rCandidate.count());
+
+ for(sal_uInt32 a(0L); a < nPolygonCount; a++)
+ {
+ const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
+
+ fRetval += tools::getSignedArea(aCandidate);
+ }
+
+ return fRetval;
+ }
+
+ double getArea(const B2DPolyPolygon& rCandidate)
+ {
+ return fabs(getSignedArea(rCandidate));
+ }
+
void applyLineDashing(const B2DPolyPolygon& rCandidate, const ::std::vector<double>& rDotDashArray, B2DPolyPolygon* pLineTarget, B2DPolyPolygon* pGapTarget, double fFullDashDotLen)
{
if(0.0 == fFullDashDotLen && rDotDashArray.size())
diff --git a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx
index cf3c79b..3511e57 100644
--- a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx
+++ b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx
@@ -1177,14 +1177,29 @@ namespace drawinglayer
// direct draw of hairline; use default processing
// support SvtGraphicStroke MetaCommentAction
const basegfx::BColor aLineColor(maBColorModifierStack.getModifiedColor(rHairlinePrimitive.getBColor()));
- SvtGraphicStroke* pSvtGraphicStroke = impTryToCreateSvtGraphicStroke(
- rHairlinePrimitive.getB2DPolygon(),
- &aLineColor,
- 0, 0, 0, 0);
+ SvtGraphicStroke* pSvtGraphicStroke = 0;
+
+ // #i121267# Not needed, does not give better quality compared with
+ // the META_POLYPOLYGON_ACTION written by RenderPolygonHairlinePrimitive2D
+ // below
+ bool bSupportSvtGraphicStroke(false);
+
+ if(bSupportSvtGraphicStroke)
+ {
+ pSvtGraphicStroke = impTryToCreateSvtGraphicStroke(
+ rHairlinePrimitive.getB2DPolygon(),
+ &aLineColor,
+ 0, 0, 0, 0);
+
+ impStartSvtGraphicStroke(pSvtGraphicStroke);
+ }
- impStartSvtGraphicStroke(pSvtGraphicStroke);
RenderPolygonHairlinePrimitive2D(static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate), false);
- impEndSvtGraphicStroke(pSvtGraphicStroke);
+
+ if(bSupportSvtGraphicStroke)
+ {
+ impEndSvtGraphicStroke(pSvtGraphicStroke);
+ }
}
break;
}
@@ -1653,7 +1668,12 @@ namespace drawinglayer
// XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END support
SvtGraphicFill* pSvtGraphicFill = 0;
- if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count())
+ // #i121267# Not needed, does not give better quality compared with
+ // the META_POLYPOLYGON_ACTION written by the DrawPolyPolygon command
+ // below
+ bool bSupportSvtGraphicFill(false);
+
+ if(bSupportSvtGraphicFill && !mnSvtGraphicFillCount && aLocalPolyPolygon.count())
{
// setup simple color fill stuff like in impgrfll
pSvtGraphicFill = new SvtGraphicFill(
@@ -1678,9 +1698,17 @@ namespace drawinglayer
mpOutputDevice->SetLineColor();
// call VCL directly; encapsulate with SvtGraphicFill
- impStartSvtGraphicFill(pSvtGraphicFill);
+ if(bSupportSvtGraphicFill)
+ {
+ impStartSvtGraphicFill(pSvtGraphicFill);
+ }
+
mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon);
- impEndSvtGraphicFill(pSvtGraphicFill);
+
+ if(bSupportSvtGraphicFill)
+ {
+ impEndSvtGraphicFill(pSvtGraphicFill);
+ }
break;
}
@@ -1739,16 +1767,13 @@ namespace drawinglayer
// Removed subdivision and fixed in Region::ImplPolyPolyRegionToBandRegionFunc() in VCL where
// the ClipRegion is built from the Polygon. A AdaptiveSubdivide on the source polygon was missing there
mpOutputDevice->Push(PUSH_CLIPREGION);
- //mpOutputDevice->SetClipRegion(Region(PolyPolygon(basegfx::tools::adaptiveSubdivideByAngle(maClipPolyPolygon))));
- //mpOutputDevice->SetClipRegion(Region(PolyPolygon(maClipPolyPolygon)));
mpOutputDevice->SetClipRegion(Region(maClipPolyPolygon));
- }
- // recursively paint content
- process(rMaskCandidate.getChildren());
+ // recursively paint content
+ // #i121267# Only need to process sub-content when clip polygon is *not* empty.
+ // If it is empty, the clip is empty and there can be nothing inside.
+ process(rMaskCandidate.getChildren());
- if(maClipPolyPolygon.count())
- {
// restore VCL clip region
mpOutputDevice->Pop();
}
@@ -1820,7 +1845,12 @@ namespace drawinglayer
// XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END support
SvtGraphicFill* pSvtGraphicFill = 0;
- if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count())
+ // #i121267# Not needed, does not give better quality compared with
+ // the META_POLYPOLYGON_ACTION written by the DrawPolyPolygon command
+ // below
+ bool bSupportSvtGraphicFill(false);
+
+ if(bSupportSvtGraphicFill && !mnSvtGraphicFillCount && aLocalPolyPolygon.count())
{
// setup simple color with transparence fill stuff like in impgrfll
pSvtGraphicFill = new SvtGraphicFill(
@@ -1846,11 +1876,19 @@ namespace drawinglayer
mpOutputDevice->SetLineColor();
// call VCL directly; encapsulate with SvtGraphicFill
- impStartSvtGraphicFill(pSvtGraphicFill);
+ if(bSupportSvtGraphicFill)
+ {
+ impStartSvtGraphicFill(pSvtGraphicFill);
+ }
+
mpOutputDevice->DrawTransparent(
PolyPolygon(aLocalPolyPolygon),
nTransPercentVcl);
- impEndSvtGraphicFill(pSvtGraphicFill);
+
+ if(bSupportSvtGraphicFill)
+ {
+ impEndSvtGraphicFill(pSvtGraphicFill);
+ }
}
else
{
diff --git a/drawinglayer/source/processor2d/vclprocessor2d.cxx b/drawinglayer/source/processor2d/vclprocessor2d.cxx
index d129251..9741bc8 100644
--- a/drawinglayer/source/processor2d/vclprocessor2d.cxx
+++ b/drawinglayer/source/processor2d/vclprocessor2d.cxx
@@ -538,14 +538,16 @@ namespace drawinglayer
// nBWidth, nBHeight is the pixel size of the neede bitmap. To not need to scale it
// in vcl many times, create a size-optimized version
const Size aNeededBitmapSizePixel(nBWidth, nBHeight);
- BitmapEx aBitmapEx(rFillGraphicAttribute.getGraphic().GetBitmapEx(
- GraphicConversionParameters(
- aNeededBitmapSizePixel, // get the correct size immediately
- false, // no unlimited size
- false, // Use AntiAliasing
- false, //SnapHorVerLines
- true // ScaleHighQuality
- )));
+ BitmapEx aBitmapEx(rFillGraphicAttribute.getGraphic().GetBitmapEx());
+ static bool bEnablePreScaling(true);
+ const bool bPreScaled(bEnablePreScaling && nBWidth * nBHeight < (250 * 250));
+
+ if(bPreScaled)
+ {
+ // ... but only up to a maximum size, else it gets too expensive
+ aBitmapEx.Scale(aNeededBitmapSizePixel, BMP_SCALE_INTERPOLATE);
+ }
+
bool bPainted(false);
if(maBColorModifierStack.count())
@@ -632,7 +634,14 @@ namespace drawinglayer
if(aOutRectPixel.IsOver(aVisiblePixel))
{
- mpOutputDevice->DrawBitmapEx(aOutRectPixel.TopLeft(), aBitmapEx);
+ if(bPreScaled)
+ {
+ mpOutputDevice->DrawBitmapEx(aOutRectPixel.TopLeft(), aBitmapEx);
+ }
+ else
+ {
+ mpOutputDevice->DrawBitmapEx(aOutRectPixel.TopLeft(), aNeededBitmapSizePixel, aBitmapEx);
+ }
}
}
}
@@ -652,7 +661,14 @@ namespace drawinglayer
if(aOutRectPixel.IsOver(aVisiblePixel))
{
- mpOutputDevice->DrawBitmapEx(aOutRectPixel.TopLeft(), aBitmapEx);
+ if(bPreScaled)
+ {
+ mpOutputDevice->DrawBitmapEx(aOutRectPixel.TopLeft(), aBitmapEx);
+ }
+ else
+ {
+ mpOutputDevice->DrawBitmapEx(aOutRectPixel.TopLeft(), aNeededBitmapSizePixel, aBitmapEx);
+ }
}
}
}
diff --git a/filter/source/flash/swfexporter.cxx b/filter/source/flash/swfexporter.cxx
index 8bc51b6..3e5e364 100644
--- a/filter/source/flash/swfexporter.cxx
+++ b/filter/source/flash/swfexporter.cxx
@@ -35,6 +35,7 @@
#include <vcl/metaact.hxx>
#include <vcl/wmf.hxx>
#include <vcl/graphicfilter.hxx>
+#include <vcl/gdimetafiletools.hxx>
#include "swfexporter.hxx"
#include "swfwriter.hxx"
@@ -707,8 +708,18 @@ bool FlashExporter::getMetaFile( Reference< XComponent >&xComponent, GDIMetaFile
}
else
+ {
rMtf.Read( *aFile.GetStream( STREAM_READ ) );
+ if(usesClipActions(rMtf))
+ {
+ // #i121267# It is necessary to prepare the metafile since the export does *not* support
+ // clip regions. This tooling method clips the geometry content of the metafile internally
+ // against it's own clip regions, so that the export is safe to ignore clip regions
+ clipMetafileContentAgainstOwnRegions(rMtf);
+ }
+ }
+
return rMtf.GetActionSize() != 0;
}
diff --git a/filter/source/graphicfilter/eos2met/eos2met.cxx b/filter/source/graphicfilter/eos2met/eos2met.cxx
index f5a5a23..761c456 100644
--- a/filter/source/graphicfilter/eos2met/eos2met.cxx
+++ b/filter/source/graphicfilter/eos2met/eos2met.cxx
@@ -34,7 +34,7 @@
#include <vcl/svapp.hxx>
#include <vcl/msgbox.hxx>
#include <svl/solar.hrc>
-
+#include <vcl/gdimetafiletools.hxx>
// -----------------------------Field Types-------------------------------
@@ -2558,10 +2558,21 @@ sal_Bool METWriter::WriteMET( const GDIMetaFile& rMTF, SvStream& rTargetStream,
extern "C" SAL_DLLPUBLIC_EXPORT sal_Bool SAL_CALL
GraphicExport( SvStream & rStream, Graphic & rGraphic, FilterConfigItem* pFilterConfigItem, sal_Bool )
-{ METWriter aMETWriter;
+{
+ METWriter aMETWriter;
+
+ // #119735# just use GetGDIMetaFile, it will create a buffered version of contained bitmap now automatically
+ GDIMetaFile aMetafile(rGraphic.GetGDIMetaFile());
+
+ if(usesClipActions(aMetafile))
+ {
+ // #i121267# It is necessary to prepare the metafile since the export does *not* support
+ // clip regions. This tooling method clips the geometry content of the metafile internally
+ // against it's own clip regions, so that the export is safe to ignore clip regions
+ clipMetafileContentAgainstOwnRegions(aMetafile);
+ }
- // #119735# just use GetGDIMetaFile, it will create a bufferd version of contained bitmap now automatically
- return aMETWriter.WriteMET( rGraphic.GetGDIMetaFile(), rStream, pFilterConfigItem );
+ return aMETWriter.WriteMET( aMetafile, rStream, pFilterConfigItem );
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/basegfx/polygon/b2dpolypolygontools.hxx b/include/basegfx/polygon/b2dpolypolygontools.hxx
index 29ae3e0..01c1306 100644
--- a/include/basegfx/polygon/b2dpolypolygontools.hxx
+++ b/include/basegfx/polygon/b2dpolypolygontools.hxx
@@ -78,6 +78,12 @@ namespace basegfx
*/
BASEGFX_DLLPUBLIC B2DRange getRange(const B2DPolyPolygon& rCandidate);
+ // get signed area of polygon
+ BASEGFX_DLLPUBLIC double getSignedArea(const B2DPolyPolygon& rCandidate);
+
+ // get area of polygon
+ BASEGFX_DLLPUBLIC double getArea(const B2DPolyPolygon& rCandidate);
+
/** Apply given LineDashing to given polyPolygon
For a description see applyLineDashing in b2dpolygontoos.hxx
diff --git a/include/vcl/gdimetafiletools.hxx b/include/vcl/gdimetafiletools.hxx
new file mode 100644
index 0000000..f6f3cfd
--- /dev/null
+++ b/include/vcl/gdimetafiletools.hxx
@@ -0,0 +1,43 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef _SV_GDIMETAFILETOOLS_HXX
+#define _SV_GDIMETAFILETOOLS_HXX
+
+#include <vcl/gdimtf.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+// #i121267# Added tooling to be able to support old exporters which are based on
+// metafiles as graphic content, but do not implement using the contained clip
+// regions.
+// The given metafile will internall yclip it's graphic content against the
+// included clip regions so that it is safe to ignore clip actions there. This
+// is not done completely, but implemented and extended as needed (on demand)
+// since all this is a workarund; the better and long term solution will be to
+// reimplement these im/exports to use primitives and not metafiles as bese
+// information.
+
+void VCL_DLLPUBLIC clipMetafileContentAgainstOwnRegions(GDIMetaFile& rSource);
+
+//////////////////////////////////////////////////////////////////////////////
+// Allow to check if a Metafile contains clipping or not
+
+bool VCL_DLLPUBLIC usesClipActions(const GDIMetaFile& rSource);
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif // _SV_GDIMETAFILETOOLS_HXX
diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk
index d9b19fa..761f497 100644
--- a/vcl/Library_vcl.mk
+++ b/vcl/Library_vcl.mk
@@ -206,6 +206,7 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\
vcl/source/gdi/extoutdevdata \
vcl/source/gdi/font \
vcl/source/gdi/gdimtf \
+ vcl/source/gdi/gdimetafiletools \
vcl/source/gdi/gfxlink \
vcl/source/gdi/gradient \
vcl/source/gdi/graph \
diff --git a/vcl/source/filter/wmf/wmf.cxx b/vcl/source/filter/wmf/wmf.cxx
index 91cf24f..3c06d55 100644
--- a/vcl/source/filter/wmf/wmf.cxx
+++ b/vcl/source/filter/wmf/wmf.cxx
@@ -22,6 +22,7 @@
#include "emfwr.hxx"
#include "wmfwr.hxx"
#include <vcl/wmf.hxx>
+#include <vcl/gdimetafiletools.hxx>
#include <comphelper/scopeguard.hxx>
// -----------------------------------------------------------------------------
@@ -88,7 +89,17 @@ bool ConvertGDIMetaFileToWMF( const GDIMetaFile & rMTF, SvStream & rTargetStream
FilterConfigItem* pConfigItem, bool bPlaceable)
{
WMFWriter aWMFWriter;
- return aWMFWriter.WriteWMF( rMTF, rTargetStream, pConfigItem, bPlaceable );
+ GDIMetaFile aGdiMetaFile(rMTF);
+
+ if(usesClipActions(aGdiMetaFile))
+ {
+ // #i121267# It is necessary to prepare the metafile since the export does *not* support
+ // clip regions. This tooling method clips the geometry content of the metafile internally
+ // against it's own clip regions, so that the export is safe to ignore clip regions
+ clipMetafileContentAgainstOwnRegions(aGdiMetaFile);
+ }
+
+ return aWMFWriter.WriteWMF( aGdiMetaFile, rTargetStream, pConfigItem, bPlaceable );
}
// -----------------------------------------------------------------------------
@@ -97,7 +108,17 @@ sal_Bool ConvertGDIMetaFileToEMF( const GDIMetaFile & rMTF, SvStream & rTargetSt
FilterConfigItem* pConfigItem )
{
EMFWriter aEMFWriter(rTargetStream);
- return aEMFWriter.WriteEMF( rMTF, pConfigItem );
+ GDIMetaFile aGdiMetaFile(rMTF);
+
+ if(usesClipActions(aGdiMetaFile))
+ {
+ // #i121267# It is necessary to prepare the metafile since the export does *not* support
+ // clip regions. This tooling method clips the geometry content of the metafile internally
+ // against it's own clip regions, so that the export is safe to ignore clip regions
+ clipMetafileContentAgainstOwnRegions(aGdiMetaFile);
+ }
+
+ return aEMFWriter.WriteEMF( aGdiMetaFile, pConfigItem );
}
// -----------------------------------------------------------------------------
diff --git a/vcl/source/gdi/gdimetafiletools.cxx b/vcl/source/gdi/gdimetafiletools.cxx
new file mode 100644
index 0000000..ec2c947
--- /dev/null
+++ b/vcl/source/gdi/gdimetafiletools.cxx
@@ -0,0 +1,1095 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vcl/gdimetafiletools.hxx>
+#include <vcl/metaact.hxx>
+#include <basegfx/polygon/b2dpolygonclipper.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/graphictools.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+// helpers
+
+namespace
+{
+ bool handleGeometricContent(
+ const basegfx::B2DPolyPolygon& rClip,
+ const basegfx::B2DPolyPolygon& rSource,
+ GDIMetaFile& rTarget,
+ bool bStroke)
+ {
+ if(rSource.count() && rClip.count())
+ {
+ const basegfx::B2DPolyPolygon aResult(
+ basegfx::tools::clipPolyPolygonOnPolyPolygon(
+ rSource,
+ rClip,
+ true, // inside
+ bStroke));
+
+ if(aResult.count())
+ {
+ if(aResult == rSource)
+ {
+ // not clipped, but inside. Add original
+ return false;
+ }
+ else
+ {
+ // add clipped geometry
+ if(bStroke)
+ {
+ for(sal_uInt32 a(0); a < aResult.count(); a++)
+ {
+ rTarget.AddAction(
+ new MetaPolyLineAction(
+ Polygon(aResult.getB2DPolygon(a))));
+ }
+ }
+ else
+ {
+ rTarget.AddAction(
+ new MetaPolyPolygonAction(
+ PolyPolygon(aResult)));
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
+ bool handleGradientContent(
+ const basegfx::B2DPolyPolygon& rClip,
+ const basegfx::B2DPolyPolygon& rSource,
+ const Gradient& rGradient,
+ GDIMetaFile& rTarget)
+ {
+ if(rSource.count() && rClip.count())
+ {
+ const basegfx::B2DPolyPolygon aResult(
+ basegfx::tools::clipPolyPolygonOnPolyPolygon(
+ rSource,
+ rClip,
+ true, // inside
+ false)); // stroke
+
+ if(aResult.count())
+ {
+ if(aResult == rSource)
+ {
+ // not clipped, but inside. Add original
+ return false;
+ }
+ else
+ {
+ // add clipped geometry
+ rTarget.AddAction(
+ new MetaGradientExAction(
+ PolyPolygon(aResult),
+ rGradient));
+ }
+ }
+ }
+
+ return true;
+ }
+
+ bool handleBitmapContent(
+ const basegfx::B2DPolyPolygon& rClip,
+ const Point& rPoint,
+ const Size& rSize,
+ const BitmapEx& rBitmapEx,
+ GDIMetaFile& rTarget)
+ {
+ if(!rSize.Width() || !rSize.Height() || rBitmapEx.IsEmpty())
+ {
+ // bitmap or size is empty
+ return true;
+ }
+
+ const basegfx::B2DRange aLogicBitmapRange(
+ rPoint.X(), rPoint.Y(),
+ rPoint.X() + rSize.Width(), rPoint.Y() + rSize.Height());
+ const basegfx::B2DPolyPolygon aClipOfBitmap(
+ basegfx::tools::clipPolyPolygonOnRange(
+ rClip,
+ aLogicBitmapRange,
+ true,
+ false)); // stroke
+
+ if(!aClipOfBitmap.count())
+ {
+ // outside clip region
+ return true;
+ }
+
+ // inside or overlapping. Use area to find out if it is completely
+ // covering (inside) or overlapping
+ const double fClipArea(basegfx::tools::getArea(aClipOfBitmap));
+ const double fBitmapArea(
+ aLogicBitmapRange.getWidth() * aLogicBitmapRange.getWidth() +
+ aLogicBitmapRange.getHeight() * aLogicBitmapRange.getHeight());
+ const double fFactor(fClipArea / fBitmapArea);
+
+ if(basegfx::fTools::more(fFactor, 1.0 - 0.001))
+ {
+ // completely covering (with 0.1% tolerance)
+ return false;
+ }
+
+ // needs clipping (with 0.1% tolerance). Prepare VirtualDevice
+ // in pixel mode for alpha channel painting (black is transparent,
+ // white to paint 100% opacity)
+ const Size aSizePixel(rBitmapEx.GetSizePixel());
+ VirtualDevice aVDev;
+
+ aVDev.SetOutputSizePixel(aSizePixel);
+ aVDev.EnableMapMode(false);
+ aVDev.SetFillColor(COL_WHITE);
+ aVDev.SetLineColor();
+
+ if(rBitmapEx.IsTransparent())
+ {
+ // use given alpha channel
+ aVDev.DrawBitmap(Point(0, 0), rBitmapEx.GetAlpha().GetBitmap());
+ }
+ else
+ {
+ // reset alpha channel
+ aVDev.SetBackground(Wallpaper(Color(COL_BLACK)));
+ aVDev.Erase();
+ }
+
+ // transform polygon from clipping to pixel coordinates
+ basegfx::B2DPolyPolygon aPixelPoly(aClipOfBitmap);
+ basegfx::B2DHomMatrix aTransform;
+
+ aTransform.translate(-aLogicBitmapRange.getMinX(), -aLogicBitmapRange.getMinY());
+ aTransform.scale(
+ static_cast< double >(aSizePixel.Width()) / aLogicBitmapRange.getWidth(),
+ static_cast< double >(aSizePixel.Height()) / aLogicBitmapRange.getHeight());
+ aPixelPoly.transform(aTransform);
+
+ // to fill the non-covered parts, use the Xor fill rule of
+ // PolyPolygon painting. Start with a all-covering polygon and
+ // add the clip polygon one
+ basegfx::B2DPolyPolygon aInvertPixelPoly;
+
+ aInvertPixelPoly.append(
+ basegfx::tools::createPolygonFromRect(
+ basegfx::B2DRange(
+ 0.0, 0.0,
+ aSizePixel.Width(), aSizePixel.Height())));
+ aInvertPixelPoly.append(aPixelPoly);
+
+ // paint as alpha
+ aVDev.DrawPolyPolygon(aInvertPixelPoly);
+
+ // get created alpha mask and set defaults
+ AlphaMask aAlpha(
+ aVDev.GetBitmap(
+ Point(0, 0),
+ aSizePixel));
+
+ aAlpha.SetPrefSize(rBitmapEx.GetPrefSize());
+ aAlpha.SetPrefMapMode(rBitmapEx.GetPrefMapMode());
+
+ // add new action replacing the old one
+ rTarget.AddAction(
+ new MetaBmpExScaleAction(
+ Point(
+ basegfx::fround(aLogicBitmapRange.getMinX()),
+ basegfx::fround(aLogicBitmapRange.getMinY())),
+ Size(
+ basegfx::fround(aLogicBitmapRange.getWidth()),
+ basegfx::fround(aLogicBitmapRange.getHeight())),
+ BitmapEx(rBitmapEx.GetBitmap(), aAlpha)));
+
+ return true;
+ }
+
+ void addSvtGraphicStroke(const SvtGraphicStroke& rStroke, GDIMetaFile& rTarget)
+ {
+ // write SvtGraphicFill
+ SvMemoryStream aMemStm;
+ aMemStm << rStroke;
+ rTarget.AddAction(
+ new MetaCommentAction(
+ "XPATHSTROKE_SEQ_BEGIN",
+ 0,
+ static_cast< const sal_uInt8* >(aMemStm.GetData()),
+ aMemStm.Seek(STREAM_SEEK_TO_END)));
+ }
+
+ void addSvtGraphicFill(const SvtGraphicFill &rFilling, GDIMetaFile& rTarget)
+ {
+ // write SvtGraphicFill
+ SvMemoryStream aMemStm;
+ aMemStm << rFilling;
+ rTarget.AddAction(
+ new MetaCommentAction(
+ "XPATHFILL_SEQ_BEGIN",
+ 0,
+ static_cast< const sal_uInt8* >(aMemStm.GetData()),
+ aMemStm.Seek(STREAM_SEEK_TO_END)));
+ }
+} // end of anonymous namespace
+
+//////////////////////////////////////////////////////////////////////////////
+// #i121267# Tooling to internally clip geometry against internal clip regions
+
+void clipMetafileContentAgainstOwnRegions(GDIMetaFile& rSource)
+{
+ const sal_uLong nObjCount(rSource.GetActionSize());
+
+ if(!nObjCount)
+ {
+ return;
+ }
+
+ // prepare target data container and push/pop stack data
+ GDIMetaFile aTarget;
+ bool bChanged(false);
+ std::vector< basegfx::B2DPolyPolygon > aClips;
+ std::vector< sal_uInt16 > aPushFlags;
+ std::vector< MapMode > aMapModes;
+
+ // start with empty region
+ aClips.push_back(basegfx::B2DPolyPolygon());
+
+ // start with default MapMode (MAP_PIXEL)
+ aMapModes.push_back(MapMode());
+
+ for(sal_uLong i(0); i < nObjCount; ++i)
+ {
+ const MetaAction* pAction(rSource.GetAction(i));
+ const sal_uInt16 nType(pAction->GetType());
+ bool bDone(false);
+
+ // basic operation takes care of clipregion actions (four) and push/pop of these
+ // to steer the currently set clip region. There *is* an active
+ // clip region when (aClips.size() && aClips.back().count()), see
+ // below
+ switch(nType)
+ {
+ case META_CLIPREGION_ACTION :
+ {
+ const MetaClipRegionAction* pA = static_cast< const MetaClipRegionAction* >(pAction);
+
+ if(pA->IsClipping())
+ {
+ const Region& rRegion = pA->GetRegion();
+ const basegfx::B2DPolyPolygon aNewClip(rRegion.GetAsB2DPolyPolygon());
+
+ aClips.back() = aNewClip;
+ }
+ else
+ {
+ aClips.back() = basegfx::B2DPolyPolygon();
+ }
+
+ break;
+ }
+
+ case META_ISECTRECTCLIPREGION_ACTION :
+ {
+ const MetaISectRectClipRegionAction* pA = static_cast< const MetaISectRectClipRegionAction* >(pAction);
+ const Rectangle& rRect = pA->GetRect();
+
+ if(!rRect.IsEmpty() && aClips.size() && aClips.back().count())
+ {
+ const basegfx::B2DRange aClipRange(
+ rRect.Left(), rRect.Top(),
+ rRect.Right(), rRect.Bottom());
+
+ aClips.back() = basegfx::tools::clipPolyPolygonOnRange(
+ aClips.back(),
+ aClipRange,
+ true, // inside
+ false); // stroke
+ }
+ break;
+ }
+
+ case META_ISECTREGIONCLIPREGION_ACTION :
+ {
+ const MetaISectRegionClipRegionAction* pA = static_cast< const MetaISectRegionClipRegionAction* >(pAction);
+ const Region& rRegion = pA->GetRegion();
+
+ if(!rRegion.IsEmpty() && aClips.size() && aClips.back().count())
+ {
+ const basegfx::B2DPolyPolygon aNewClip(rRegion.GetAsB2DPolyPolygon());
+
+ aClips.back() = basegfx::tools::clipPolyPolygonOnPolyPolygon(
+ aClips.back(),
+ aNewClip,
+ true, // inside
+ false); // stroke
+ }
+ break;
+ }
+
+ case META_MOVECLIPREGION_ACTION :
+ {
+ const MetaMoveClipRegionAction* pA = static_cast< const MetaMoveClipRegionAction* >(pAction);
+ const long aHorMove(pA->GetHorzMove());
+ const long aVerMove(pA->GetVertMove());
+
+ if((aHorMove || aVerMove) && aClips.size() && aClips.back().count())
+ {
+ aClips.back().transform(
+ basegfx::tools::createTranslateB2DHomMatrix(
+ aHorMove,
+ aVerMove));
+ }
+ break;
+ }
+
+ case META_PUSH_ACTION :
+ {
+ const MetaPushAction* pA = static_cast< const MetaPushAction* >(pAction);
+ const sal_uInt16 nFlags(pA->GetFlags());
+
+ aPushFlags.push_back(nFlags);
+
+ if(nFlags & PUSH_CLIPREGION)
+ {
+ aClips.push_back(aClips.back());
+ }
+
+ if(nFlags & PUSH_MAPMODE)
+ {
+ aMapModes.push_back(aMapModes.back());
+ }
+ break;
+ }
+
+ case META_POP_ACTION :
+ {
+
+ if(aPushFlags.size())
+ {
+ const sal_uInt16 nFlags(aPushFlags.back());
+ aPushFlags.pop_back();
+
+ if(nFlags & PUSH_CLIPREGION)
+ {
+ if(aClips.size() > 1)
+ {
+ aClips.pop_back();
+ }
+ else
+ {
+ OSL_ENSURE(false, "Wrong POP() in ClipRegions (!)");
+ }
+ }
+
+ if(nFlags & PUSH_MAPMODE)
+ {
+ if(aMapModes.size() > 1)
+ {
+ aMapModes.pop_back();
+ }
+ else
+ {
+ OSL_ENSURE(false, "Wrong POP() in MapModes (!)");
+ }
+ }
+ }
+ else
+ {
+ OSL_ENSURE(false, "Invalid pop() without push() (!)");
+ }
+
+ break;
+ }
+
+ case META_MAPMODE_ACTION :
+ {
+ const MetaMapModeAction* pA = static_cast< const MetaMapModeAction* >(pAction);
+
+ aMapModes.back() = pA->GetMapMode();
+ break;
+ }
+
+ default:
+ {
+ break;
+ }
+ }
+
+ // this area contains all actions which could potentially be clipped. Since
+ // this tooling is only a fallback (see comments in header), only the needed
+ // actions will be implemented. Extend using the pattern for the already
+ // implemented actions.
+ if(aClips.size() && aClips.back().count())
+ {
+ switch(nType)
+ {
+ //
+ // pixel actions, just check on inside
+ //
+ case META_PIXEL_ACTION :
+ {
+ const MetaPixelAction* pA = static_cast< const MetaPixelAction* >(pAction);
+ const Point& rPoint = pA->GetPoint();
+
+ if(!basegfx::tools::isInside(
+ aClips.back(),
+ basegfx::B2DPoint(rPoint.X(), rPoint.Y())))
+ {
+ // when not inside, do not add original
+ bDone = true;
+ }
+ break;
+ }
+
+ case META_POINT_ACTION :
+ {
+ const MetaPointAction* pA = static_cast< const MetaPointAction* >(pAction);
+ const Point& rPoint = pA->GetPoint();
+
+ if(!basegfx::tools::isInside(
+ aClips.back(),
+ basegfx::B2DPoint(rPoint.X(), rPoint.Y())))
+ {
+ // when not inside, do not add original
+ bDone = true;
+ }
+ break;
+ }
+
+ //
+ // geometry actions
+ //
+ case META_LINE_ACTION :
+ {
+ const MetaLineAction* pA = static_cast< const MetaLineAction* >(pAction);
+ const Point& rStart(pA->GetStartPoint());
+ const Point& rEnd(pA->GetEndPoint());
+ basegfx::B2DPolygon aLine;
+
+ aLine.append(basegfx::B2DPoint(rStart.X(), rStart.Y()));
+ aLine.append(basegfx::B2DPoint(rEnd.X(), rEnd.Y()));
+
+ bDone = handleGeometricContent(
+ aClips.back(),
+ basegfx::B2DPolyPolygon(aLine),
+ aTarget,
+ true); // stroke
+ break;
+ }
+
+ case META_RECT_ACTION :
+ {
+ const MetaRectAction* pA = static_cast< const MetaRectAction* >(pAction);
+ const Rectangle& rRect = pA->GetRect();
+
+ if(rRect.IsEmpty())
+ {
+ bDone = true;
+ }
+ else
+ {
+
+ bDone = handleGeometricContent(
+ aClips.back(),
+ basegfx::B2DPolyPolygon(
+ basegfx::tools::createPolygonFromRect(
+ basegfx::B2DRange(
+ rRect.Left(), rRect.Top(),
+ rRect.Right(), rRect.Bottom()))),
+ aTarget,
+ false); // stroke
+ }
+ break;
+ }
+
+ case META_ROUNDRECT_ACTION :
+ {
+ const MetaRoundRectAction* pA = static_cast< const MetaRoundRectAction* >(pAction);
+ const Rectangle& rRect = pA->GetRect();
+
+ if(rRect.IsEmpty())
+ {
+ bDone = true;
+ }
+ else
+ {
+ const sal_uInt32 nHor(pA->GetHorzRound());
+ const sal_uInt32 nVer(pA->GetVertRound());
+ const basegfx::B2DRange aRange(rRect.Left(), rRect.Top(), rRect.Right(), rRect.Bottom());
+ basegfx::B2DPolygon aOutline;
+
+ if(nHor || nVer)
+ {
+ double fRadiusX((nHor * 2.0) / (aRange.getWidth() > 0.0 ? aRange.getWidth() : 1.0));
+ double fRadiusY((nVer * 2.0) / (aRange.getHeight() > 0.0 ? aRange.getHeight() : 1.0));
+ fRadiusX = std::max(0.0, std::min(1.0, fRadiusX));
+ fRadiusY = std::max(0.0, std::min(1.0, fRadiusY));
+
+ aOutline = basegfx::tools::createPolygonFromRect(aRange, fRadiusX, fRadiusY);
+ }
+ else
+ {
+ aOutline = basegfx::tools::createPolygonFromRect(aRange);
+ }
+
+ bDone = handleGeometricContent(
+ aClips.back(),
+ basegfx::B2DPolyPolygon(aOutline),
+ aTarget,
+ false); // stroke
+ }
+ break;
+ }
+
+ case META_ELLIPSE_ACTION :
+ {
+ const MetaEllipseAction* pA = static_cast< const MetaEllipseAction* >(pAction);
+ const Rectangle& rRect = pA->GetRect();
+
+ if(rRect.IsEmpty())
+ {
+ bDone = true;
+ }
+ else
+ {
+ const basegfx::B2DRange aRange(rRect.Left(), rRect.Top(), rRect.Right(), rRect.Bottom());
+
+ bDone = handleGeometricContent(
+ aClips.back(),
+ basegfx::B2DPolyPolygon(
+ basegfx::tools::createPolygonFromEllipse(
+ aRange.getCenter(),
+ aRange.getWidth() * 0.5,
+ aRange.getHeight() * 0.5)),
+ aTarget,
+ false); // stroke
+ }
+ break;
+ }
+
+ case META_ARC_ACTION :
+ {
+ const MetaArcAction* pA = static_cast< const MetaArcAction* >(pAction);
+ const Rectangle& rRect = pA->GetRect();
+
+ if(rRect.IsEmpty())
+ {
+ bDone = true;
+ }
+ else
+ {
+ const Polygon aToolsPoly(
+ rRect,
+ pA->GetStartPoint(),
+ pA->GetEndPoint(),
+ POLY_ARC);
+
+ bDone = handleGeometricContent(
+ aClips.back(),
+ basegfx::B2DPolyPolygon(aToolsPoly.getB2DPolygon()),
+ aTarget,
+ true); // stroke
+ }
+ break;
+ }
+
+ case META_PIE_ACTION :
+ {
+ const MetaPieAction* pA = static_cast< const MetaPieAction* >(pAction);
+ const Rectangle& rRect = pA->GetRect();
+
+ if(rRect.IsEmpty())
+ {
+ bDone = true;
+ }
+ else
+ {
+ const Polygon aToolsPoly(
+ rRect,
+ pA->GetStartPoint(),
+ pA->GetEndPoint(),
+ POLY_PIE);
+
+ bDone = handleGeometricContent(
+ aClips.back(),
+ basegfx::B2DPolyPolygon(aToolsPoly.getB2DPolygon()),
+ aTarget,
+ false); // stroke
+ }
+ break;
+ }
+
+ case META_CHORD_ACTION :
+ {
+ const MetaChordAction* pA = static_cast< const MetaChordAction* >(pAction);
+ const Rectangle& rRect = pA->GetRect();
+
+ if(rRect.IsEmpty())
+ {
+ bDone = true;
+ }
+ else
+ {
+ const Polygon aToolsPoly(
+ rRect,
+ pA->GetStartPoint(),
+ pA->GetEndPoint(),
+ POLY_CHORD);
+
+ bDone = handleGeometricContent(
+ aClips.back(),
+ basegfx::B2DPolyPolygon(aToolsPoly.getB2DPolygon()),
+ aTarget,
+ false); // stroke
+ }
+ break;
+ }
+
+ case META_POLYLINE_ACTION :
+ {
+ const MetaPolyLineAction* pA = static_cast< const MetaPolyLineAction* >(pAction);
+
+ bDone = handleGeometricContent(
+ aClips.back(),
+ basegfx::B2DPolyPolygon(pA->GetPolygon().getB2DPolygon()),
+ aTarget,
+ true); // stroke
+ break;
+ }
+
+ case META_POLYGON_ACTION :
+ {
+ const MetaPolygonAction* pA = static_cast< const MetaPolygonAction* >(pAction);
+
+ bDone = handleGeometricContent(
+ aClips.back(),
+ basegfx::B2DPolyPolygon(pA->GetPolygon().getB2DPolygon()),
+ aTarget,
+ false); // stroke
+ break;
+ }
+
+ case META_POLYPOLYGON_ACTION :
+ {
+ const MetaPolyPolygonAction* pA = static_cast< const MetaPolyPolygonAction* >(pAction);
+ const PolyPolygon& rPoly = pA->GetPolyPolygon();
+
+ bDone = handleGeometricContent(
+ aClips.back(),
+ rPoly.getB2DPolyPolygon(),
+ aTarget,
+ false); // stroke
+ break;
+ }
+
+ //
+ // bitmap actions, create BitmapEx with alpha channel derived
+ // from clipping
+ //
+ case META_BMPEX_ACTION :
+ {
+ const MetaBmpExAction* pA = static_cast< const MetaBmpExAction* >(pAction);
+ const BitmapEx& rBitmapEx = pA->GetBitmapEx();
+
+ // the logical size depends on the PrefSize of the given bitmap in
+ // combination with the current MapMode
+ Size aLogicalSize(rBitmapEx.GetPrefSize());
+
+ if(MAP_PIXEL == rBitmapEx.GetPrefMapMode().GetMapUnit())
+ {
+ aLogicalSize = Application::GetDefaultDevice()->PixelToLogic(aLogicalSize, aMapModes.back().GetMapUnit());
+ }
+ else
+ {
+ aLogicalSize = OutputDevice::LogicToLogic(aLogicalSize, rBitmapEx.GetPrefMapMode(), aMapModes.back().GetMapUnit());
+ }
+
+ bDone = handleBitmapContent(
+ aClips.back(),
+ pA->GetPoint(),
+ aLogicalSize,
+ rBitmapEx,
+ aTarget);
+ break;
+ }
+
+ case META_BMP_ACTION :
+ {
+ const MetaBmpAction* pA = static_cast< const MetaBmpAction* >(pAction);
+ const Bitmap& rBitmap = pA->GetBitmap();
+
+ // the logical size depends on the PrefSize of the given bitmap in
+ // combination with the current MapMode
+ Size aLogicalSize(rBitmap.GetPrefSize());
+
+ if(MAP_PIXEL == rBitmap.GetPrefMapMode().GetMapUnit())
+ {
+ aLogicalSize = Application::GetDefaultDevice()->PixelToLogic(aLogicalSize, aMapModes.back().GetMapUnit());
+ }
+ else
+ {
+ aLogicalSize = OutputDevice::LogicToLogic(aLogicalSize, rBitmap.GetPrefMapMode(), aMapModes.back().GetMapUnit());
+ }
+
+ bDone = handleBitmapContent(
+ aClips.back(),
+ pA->GetPoint(),
+ aLogicalSize,
+ BitmapEx(rBitmap),
+ aTarget);
+ break;
+ }
+
+ case META_BMPEXSCALE_ACTION :
+ {
+ const MetaBmpExScaleAction* pA = static_cast< const MetaBmpExScaleAction* >(pAction);
+
+ bDone = handleBitmapContent(
+ aClips.back(),
+ pA->GetPoint(),
+ pA->GetSize(),
+ pA->GetBitmapEx(),
+ aTarget);
+ break;
+ }
+
+ case META_BMPSCALE_ACTION :
+ {
+ const MetaBmpScaleAction* pA = static_cast< const MetaBmpScaleAction* >(pAction);
+
+ bDone = handleBitmapContent(
+ aClips.back(),
+ pA->GetPoint(),
+ pA->GetSize(),
+ BitmapEx(pA->GetBitmap()),
+ aTarget);
+ break;
+ }
+
+ case META_BMPEXSCALEPART_ACTION :
+ {
+ const MetaBmpExScalePartAction* pA = static_cast< const MetaBmpExScalePartAction* >(pAction);
+ const BitmapEx& rBitmapEx = pA->GetBitmapEx();
+
+ if(rBitmapEx.IsEmpty())
+ {
+ // empty content
+ bDone = true;
+ }
+ else
+ {
+ BitmapEx aCroppedBitmapEx(rBitmapEx);
+ const Rectangle aCropRectangle(pA->GetSrcPoint(), pA->GetSrcSize());
+
+ if(aCropRectangle.IsEmpty())
+ {
+ // empty content
+ bDone = true;
+ }
+ else
+ {
+ aCroppedBitmapEx.Crop(aCropRectangle);
+ bDone = handleBitmapContent(
+ aClips.back(),
+ pA->GetDestPoint(),
+ pA->GetDestSize(),
+ aCroppedBitmapEx,
+ aTarget);
+ }
+ }
+ break;
+ }
+
+ case META_BMPSCALEPART_ACTION :
+ {
+ const MetaBmpScalePartAction* pA = static_cast< const MetaBmpScalePartAction* >(pAction);
+ const Bitmap& rBitmap = pA->GetBitmap();
+
+ if(rBitmap.IsEmpty())
+ {
+ // empty content
+ bDone = true;
+ }
+ else
+ {
+ Bitmap aCroppedBitmap(rBitmap);
+ const Rectangle aCropRectangle(pA->GetSrcPoint(), pA->GetSrcSize());
+
+ if(aCropRectangle.IsEmpty())
+ {
+ // empty content
+ bDone = true;
+ }
+ else
+ {
+ aCroppedBitmap.Crop(aCropRectangle);
+ bDone = handleBitmapContent(
+ aClips.back(),
+ pA->GetDestPoint(),
+ pA->GetDestSize(),
+ BitmapEx(aCroppedBitmap),
+ aTarget);
+ }
+ }
+ break;
+ }
+
+ //
+ // need to handle all those 'hacks' which hide data in comments
+ //
+ case META_COMMENT_ACTION :
+ {
+ const MetaCommentAction* pA = static_cast< const MetaCommentAction* >(pAction);
+ const OString& rComment = pA->GetComment();
+
+ if(rComment.equalsIgnoreAsciiCase("XGRAD_SEQ_BEGIN"))
+ {
+ // nothing to do; this just means that between here and XGRAD_SEQ_END
+ // exists a META_GRADIENTEX_ACTION mixed with Xor-tricked painiting
+ // commands. This comment is used to scan over these and filter for
+ // the gradient action. It is needed to support META_GRADIENTEX_ACTION
+ // in this processor to solve usages.
+ }
+ else if(rComment.equalsIgnoreAsciiCase("XPATHFILL_SEQ_BEGIN"))
+ {
+ SvtGraphicFill aFilling;
+ PolyPolygon aPath;
+
+ { // read SvtGraphicFill
+ SvMemoryStream aMemStm((void*)pA->GetData(), pA->GetDataSize(),STREAM_READ);
+ aMemStm >> aFilling;
+ }
+
+ aFilling.getPath(aPath);
+
+ if(aPath.Count())
+ {
+ const basegfx::B2DPolyPolygon aSource(aPath.getB2DPolyPolygon());
+ const basegfx::B2DPolyPolygon aResult(
+ basegfx::tools::clipPolyPolygonOnPolyPolygon(
+ aSource,
+ aClips.back(),
+ true, // inside
+ false)); // stroke
+
+ if(aResult.count())
+ {
+ if(aResult != aSource)
+ {
+ // add clipped geometry
+ aFilling.setPath(PolyPolygon(aResult));
+ addSvtGraphicFill(aFilling, aTarget);
+ bDone = true;
+ }
+ }
+ else
+ {
+ // exchange with empty polygon
+ aFilling.setPath(PolyPolygon());
+ addSvtGraphicFill(aFilling, aTarget);
+ bDone = true;
+ }
+ }
+ }
+ else if(rComment.equalsIgnoreAsciiCase("XPATHSTROKE_SEQ_BEGIN"))
+ {
+ SvtGraphicStroke aStroke;
+ Polygon aPath;
+
+ { // read SvtGraphicFill
+ SvMemoryStream aMemStm((void*)pA->GetData(), pA->GetDataSize(),STREAM_READ);
+ aMemStm >> aStroke;
+ }
+
+ aStroke.getPath(aPath);
+
+ if(aPath.GetSize())
+ {
+ const basegfx::B2DPolygon aSource(aPath.getB2DPolygon());
+ const basegfx::B2DPolyPolygon aResult(
+ basegfx::tools::clipPolygonOnPolyPolygon(
+ aSource,
+ aClips.back(),
+ true, // inside
+ true)); // stroke
+
+ if(aResult.count())
+ {
+ if(aResult.count() > 1 || aResult.getB2DPolygon(0) != aSource)
+ {
+ // add clipped geometry
+ for(sal_uInt32 a(0); a < aResult.count(); a++)
+ {
+ aStroke.setPath(Polygon(aResult.getB2DPolygon(a)));
+ addSvtGraphicStroke(aStroke, aTarget);
+ }
+
+ bDone = true;
+ }
+ }
+ else
+ {
+ // exchange with empty polygon
+ aStroke.setPath(Polygon());
+ addSvtGraphicStroke(aStroke, aTarget);
+ bDone = true;
+ }
+
+ }
+ }
+ break;
+ }
+
+ //
+ // need to handle gradient fills (hopefully only unroated ones)
+ //
+
+ case META_GRADIENT_ACTION :
+ {
+ const MetaGradientAction* pA = static_cast< const MetaGradientAction* >(pAction);
+ const Rectangle& rRect = pA->GetRect();
+
+ if(rRect.IsEmpty())
+ {
+ bDone = true;
+ }
+ else
+ {
+ bDone = handleGradientContent(
+ aClips.back(),
+ basegfx::B2DPolyPolygon(
+ basegfx::tools::createPolygonFromRect(
+ basegfx::B2DRange(
+ rRect.Left(), rRect.Top(),
+ rRect.Right(), rRect.Bottom()))),
+ pA->GetGradient(),
+ aTarget);
+ }
+
+
+ break;
+ }
+
+ case META_GRADIENTEX_ACTION :
+ {
+ const MetaGradientExAction* pA = static_cast< const MetaGradientExAction* >(pAction);
+ const PolyPolygon& rPolyPoly = pA->GetPolyPolygon();
+
+ bDone = handleGradientContent(
+ aClips.back(),
+ rPolyPoly.getB2DPolyPolygon(),
+ pA->GetGradient(),
+ aTarget);
+ break;
+ }
+
+ // not (yet) supported actions
+ //
+ // META_NULL_ACTION
+ // META_TEXT_ACTION
+ // META_TEXTARRAY_ACTION
+ // META_STRETCHTEXT_ACTION
+ // META_TEXTRECT_ACTION
+ // META_MASK_ACTION
+ // META_MASKSCALE_ACTION
+ // META_MASKSCALEPART_ACTION
+ // META_HATCH_ACTION
+ // META_WALLPAPER_ACTION
+ // META_FILLCOLOR_ACTION
+ // META_TEXTCOLOR_ACTION
+ // META_TEXTFILLCOLOR_ACTION
+ // META_TEXTALIGN_ACTION
+ // META_MAPMODE_ACTION
+ // META_FONT_ACTION
+ // META_TRANSPARENT_ACTION
+ // META_EPS_ACTION
+ // META_REFPOINT_ACTION
+ // META_TEXTLINECOLOR_ACTION
+ // META_TEXTLINE_ACTION
+ // META_FLOATTRANSPARENT_ACTION
+ // META_LAYOUTMODE_ACTION
+ // META_TEXTLANGUAGE_ACTION
+ // META_OVERLINECOLOR_ACTION
+
+ // if an action is not handled at all, it will simply get copied to the
+ // target (see below). This is the default for all non-implemented actions
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ if(bDone)
+ {
+ bChanged = true;
+ }
+ else
+ {
+ const_cast< MetaAction* >(pAction)->Duplicate();
+ aTarget.AddAction(const_cast< MetaAction* >(pAction));
+ }
+ }
+
+ if(bChanged)
+ {
+ // when changed, copy back and do not forget to set MapMode
+ // and PrefSize
+ aTarget.SetPrefMapMode(rSource.GetPrefMapMode());
+ aTarget.SetPrefSize(rSource.GetPrefSize());
+ rSource = aTarget;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+bool VCL_DLLPUBLIC usesClipActions(const GDIMetaFile& rSource)
+{
+ const sal_uLong nObjCount(rSource.GetActionSize());
+
+ for(sal_uLong i(0); i < nObjCount; ++i)
+ {
+ const MetaAction* pAction(rSource.GetAction(i));
+ const sal_uInt16 nType(pAction->GetType());
+
+ switch(nType)
+ {
+ case META_CLIPREGION_ACTION :
+ case META_ISECTRECTCLIPREGION_ACTION :
+ case META_ISECTREGIONCLIPREGION_ACTION :
+ case META_MOVECLIPREGION_ACTION :
+ {
+ return true;
+ break;
+ }
+
+ default: break;
+ }
+ }
+
+ return false;
+}
+
More information about the Libreoffice-commits
mailing list