summaryrefslogtreecommitdiff
path: root/drawinglayer
diff options
context:
space:
mode:
authorTomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>2020-05-05 23:20:38 +0200
committerTomaž Vajngerl <quikee@gmail.com>2020-05-09 21:08:28 +0200
commit9e2a9f4151babc6cb22553798ee70f7f623924db (patch)
tree26660371fb3096e4b46dbb75cef6151f3f522624 /drawinglayer
parent3b0de78ed85c4944d74eaaa55a8f24a63dc6ea04 (diff)
remove vclmetafileprocessor2d.{cxx,hxx} from clang-format blacklist
Change-Id: I53f7660a22ed66ab7d50370d871f9d10d1bedc10 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/93825 Tested-by: Jenkins Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
Diffstat (limited to 'drawinglayer')
-rw-r--r--drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx3866
-rw-r--r--drawinglayer/source/processor2d/vclmetafileprocessor2d.hxx309
2 files changed, 2110 insertions, 2065 deletions
diff --git a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx
index d853820abbdc..231bf8bc9259 100644
--- a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx
+++ b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx
@@ -76,2215 +76,2241 @@ using namespace com::sun::star;
// To be on the safe side with the old tools polygon, use slightly less than
// the theoretical maximum (bad experiences with tools polygon)
-#define MAX_POLYGON_POINT_COUNT_METAFILE (0x0000fff0)
+#define MAX_POLYGON_POINT_COUNT_METAFILE (0x0000fff0)
namespace
{
- // #112245# helper to split line polygon in half
- void splitLinePolygon(
- const basegfx::B2DPolygon& rBasePolygon,
- basegfx::B2DPolygon& o_aLeft,
- basegfx::B2DPolygon& o_aRight)
+// #112245# helper to split line polygon in half
+void splitLinePolygon(const basegfx::B2DPolygon& rBasePolygon, basegfx::B2DPolygon& o_aLeft,
+ basegfx::B2DPolygon& o_aRight)
+{
+ const sal_uInt32 nCount(rBasePolygon.count());
+
+ if (nCount)
{
- const sal_uInt32 nCount(rBasePolygon.count());
+ const sal_uInt32 nHalfCount((nCount - 1) >> 1);
- if(nCount)
- {
- const sal_uInt32 nHalfCount((nCount - 1) >> 1);
+ o_aLeft = basegfx::B2DPolygon(rBasePolygon, 0, nHalfCount + 1);
+ o_aLeft.setClosed(false);
- o_aLeft = basegfx::B2DPolygon(rBasePolygon, 0, nHalfCount + 1);
- o_aLeft.setClosed(false);
+ o_aRight = basegfx::B2DPolygon(rBasePolygon, nHalfCount, nCount - nHalfCount);
+ o_aRight.setClosed(false);
- o_aRight = basegfx::B2DPolygon(rBasePolygon, nHalfCount, nCount - nHalfCount);
- o_aRight.setClosed(false);
+ if (rBasePolygon.isClosed())
+ {
+ o_aRight.append(rBasePolygon.getB2DPoint(0));
- if(rBasePolygon.isClosed())
+ if (rBasePolygon.areControlPointsUsed())
{
- o_aRight.append(rBasePolygon.getB2DPoint(0));
-
- if(rBasePolygon.areControlPointsUsed())
- {
- o_aRight.setControlPoints(
- o_aRight.count() - 1,
- rBasePolygon.getPrevControlPoint(0),
- rBasePolygon.getNextControlPoint(0));
- }
+ o_aRight.setControlPoints(o_aRight.count() - 1, rBasePolygon.getPrevControlPoint(0),
+ rBasePolygon.getNextControlPoint(0));
}
}
- else
- {
- o_aLeft.clear();
- o_aRight.clear();
- }
}
-
- // #112245# helper to evtl. split filled polygons to maximum metafile point count
- void fillPolyPolygonNeededToBeSplit(basegfx::B2DPolyPolygon& rPolyPolygon)
+ else
{
- const sal_uInt32 nPolyCount(rPolyPolygon.count());
+ o_aLeft.clear();
+ o_aRight.clear();
+ }
+}
+
+// #112245# helper to evtl. split filled polygons to maximum metafile point count
+void fillPolyPolygonNeededToBeSplit(basegfx::B2DPolyPolygon& rPolyPolygon)
+{
+ const sal_uInt32 nPolyCount(rPolyPolygon.count());
+
+ if (!nPolyCount)
+ return;
- if(!nPolyCount)
- return;
+ basegfx::B2DPolyPolygon aSplitted;
- basegfx::B2DPolyPolygon aSplitted;
+ for (sal_uInt32 a(0); a < nPolyCount; a++)
+ {
+ const basegfx::B2DPolygon& aCandidate(rPolyPolygon.getB2DPolygon(a));
+ const sal_uInt32 nPointCount(aCandidate.count());
+ bool bNeedToSplit(false);
- for(sal_uInt32 a(0); a < nPolyCount; a++)
+ if (aCandidate.areControlPointsUsed())
{
- const basegfx::B2DPolygon& aCandidate(rPolyPolygon.getB2DPolygon(a));
- const sal_uInt32 nPointCount(aCandidate.count());
- bool bNeedToSplit(false);
+ // compare with the maximum for bezier curved polygons
+ bNeedToSplit = nPointCount > ((MAX_POLYGON_POINT_COUNT_METAFILE / 3L) - 1);
+ }
+ else
+ {
+ // compare with the maximum for simple point polygons
+ bNeedToSplit = nPointCount > (MAX_POLYGON_POINT_COUNT_METAFILE - 1);
+ }
- if(aCandidate.areControlPointsUsed())
- {
- // compare with the maximum for bezier curved polygons
- bNeedToSplit = nPointCount > ((MAX_POLYGON_POINT_COUNT_METAFILE / 3L) - 1);
- }
- else
- {
- // compare with the maximum for simple point polygons
- bNeedToSplit = nPointCount > (MAX_POLYGON_POINT_COUNT_METAFILE - 1);
- }
+ if (bNeedToSplit)
+ {
+ // need to split the partial polygon
+ const basegfx::B2DRange aRange(aCandidate.getB2DRange());
+ const basegfx::B2DPoint aCenter(aRange.getCenter());
- if(bNeedToSplit)
+ if (aRange.getWidth() > aRange.getHeight())
{
- // need to split the partial polygon
- const basegfx::B2DRange aRange(aCandidate.getB2DRange());
- const basegfx::B2DPoint aCenter(aRange.getCenter());
-
- if(aRange.getWidth() > aRange.getHeight())
- {
- // clip in left and right
- const basegfx::B2DPolyPolygon aLeft(
- basegfx::utils::clipPolygonOnParallelAxis(
- aCandidate,
- false,
- true,
- aCenter.getX(),
- false));
- const basegfx::B2DPolyPolygon aRight(
- basegfx::utils::clipPolygonOnParallelAxis(
- aCandidate,
- false,
- false,
- aCenter.getX(),
- false));
-
- aSplitted.append(aLeft);
- aSplitted.append(aRight);
- }
- else
- {
- // clip in top and bottom
- const basegfx::B2DPolyPolygon aTop(
- basegfx::utils::clipPolygonOnParallelAxis(
- aCandidate,
- true,
- true,
- aCenter.getY(),
- false));
- const basegfx::B2DPolyPolygon aBottom(
- basegfx::utils::clipPolygonOnParallelAxis(
- aCandidate,
- true,
- false,
- aCenter.getY(),
- false));
-
- aSplitted.append(aTop);
- aSplitted.append(aBottom);
- }
+ // clip in left and right
+ const basegfx::B2DPolyPolygon aLeft(basegfx::utils::clipPolygonOnParallelAxis(
+ aCandidate, false, true, aCenter.getX(), false));
+ const basegfx::B2DPolyPolygon aRight(basegfx::utils::clipPolygonOnParallelAxis(
+ aCandidate, false, false, aCenter.getX(), false));
+
+ aSplitted.append(aLeft);
+ aSplitted.append(aRight);
}
else
{
- aSplitted.append(aCandidate);
+ // clip in top and bottom
+ const basegfx::B2DPolyPolygon aTop(basegfx::utils::clipPolygonOnParallelAxis(
+ aCandidate, true, true, aCenter.getY(), false));
+ const basegfx::B2DPolyPolygon aBottom(basegfx::utils::clipPolygonOnParallelAxis(
+ aCandidate, true, false, aCenter.getY(), false));
+
+ aSplitted.append(aTop);
+ aSplitted.append(aBottom);
}
}
-
- if(aSplitted.count() != nPolyCount)
+ else
{
- rPolyPolygon = aSplitted;
+ aSplitted.append(aCandidate);
}
}
- /** Filter input polypolygon for effectively empty sub-fills
+ if (aSplitted.count() != nPolyCount)
+ {
+ rPolyPolygon = aSplitted;
+ }
+}
+
+/** Filter input polypolygon for effectively empty sub-fills
- Needed to fix fdo#37559
+ Needed to fix fdo#37559
- @param rPoly
- tools::PolyPolygon to filter
+ @param rPoly
+ tools::PolyPolygon to filter
- @return converted tools PolyPolygon, w/o one-point fills
- */
- ::tools::PolyPolygon getFillPolyPolygon( const ::basegfx::B2DPolyPolygon& rPoly )
+ @return converted tools PolyPolygon, w/o one-point fills
+ */
+tools::PolyPolygon getFillPolyPolygon(const ::basegfx::B2DPolyPolygon& rPoly)
+{
+ // filter input rPoly
+ basegfx::B2DPolyPolygon aPoly;
+ sal_uInt32 nCount(rPoly.count());
+ for (sal_uInt32 i = 0; i < nCount; ++i)
{
- // filter input rPoly
- basegfx::B2DPolyPolygon aPoly;
- sal_uInt32 nCount(rPoly.count());
- for( sal_uInt32 i=0; i<nCount; ++i )
- {
- const basegfx::B2DPolygon& aCandidate(rPoly.getB2DPolygon(i));
- if( !aCandidate.isClosed() || aCandidate.count() > 1 )
- aPoly.append(aCandidate);
- }
- return ::tools::PolyPolygon(aPoly);
+ const basegfx::B2DPolygon& aCandidate(rPoly.getB2DPolygon(i));
+ if (!aCandidate.isClosed() || aCandidate.count() > 1)
+ aPoly.append(aCandidate);
}
+ return tools::PolyPolygon(aPoly);
+}
} // end of anonymous namespace
namespace drawinglayer::processor2d
{
- ::tools::Rectangle VclMetafileProcessor2D::impDumpToMetaFile(
- const primitive2d::Primitive2DContainer& rContent,
- GDIMetaFile& o_rContentMetafile)
- {
- // Prepare VDev, MetaFile and connections
- OutputDevice* pLastOutputDevice = mpOutputDevice;
- GDIMetaFile* pLastMetafile = mpMetaFile;
- basegfx::B2DRange aPrimitiveRange(rContent.getB2DRange(getViewInformation2D()));
-
- // transform primitive range with current transformation (e.g shadow offset)
- aPrimitiveRange.transform(maCurrentTransformation);
-
- const ::tools::Rectangle aPrimitiveRectangle(
- basegfx::fround(aPrimitiveRange.getMinX()), basegfx::fround(aPrimitiveRange.getMinY()),
- basegfx::fround(aPrimitiveRange.getMaxX()), basegfx::fround(aPrimitiveRange.getMaxY()));
- ScopedVclPtrInstance< VirtualDevice > aContentVDev;
- MapMode aNewMapMode(pLastOutputDevice->GetMapMode());
-
- mpOutputDevice = aContentVDev.get();
- mpMetaFile = &o_rContentMetafile;
- aContentVDev->EnableOutput(false);
- aContentVDev->SetMapMode(pLastOutputDevice->GetMapMode());
- o_rContentMetafile.Record(aContentVDev.get());
- aContentVDev->SetLineColor(pLastOutputDevice->GetLineColor());
- aContentVDev->SetFillColor(pLastOutputDevice->GetFillColor());
- aContentVDev->SetFont(pLastOutputDevice->GetFont());
- aContentVDev->SetDrawMode(pLastOutputDevice->GetDrawMode());
- aContentVDev->SetSettings(pLastOutputDevice->GetSettings());
- aContentVDev->SetRefPoint(pLastOutputDevice->GetRefPoint());
-
- // dump to MetaFile
- process(rContent);
-
- // cleanups
- o_rContentMetafile.Stop();
- o_rContentMetafile.WindStart();
- aNewMapMode.SetOrigin(aPrimitiveRectangle.TopLeft());
- o_rContentMetafile.SetPrefMapMode(aNewMapMode);
- o_rContentMetafile.SetPrefSize(aPrimitiveRectangle.GetSize());
- mpOutputDevice = pLastOutputDevice;
- mpMetaFile = pLastMetafile;
-
- return aPrimitiveRectangle;
- }
-
- void VclMetafileProcessor2D::impConvertFillGradientAttributeToVCLGradient(
- Gradient& o_rVCLGradient,
- const attribute::FillGradientAttribute& rFiGrAtt,
- bool bIsTransparenceGradient) const
- {
- if(bIsTransparenceGradient)
- {
- // it's about transparence channel intensities (black/white), do not use color modifier
- o_rVCLGradient.SetStartColor(Color(rFiGrAtt.getStartColor()));
- o_rVCLGradient.SetEndColor(Color(rFiGrAtt.getEndColor()));
- }
- else
- {
- // use color modifier to influence start/end color of gradient
- o_rVCLGradient.SetStartColor(Color(maBColorModifierStack.getModifiedColor(rFiGrAtt.getStartColor())));
- o_rVCLGradient.SetEndColor(Color(maBColorModifierStack.getModifiedColor(rFiGrAtt.getEndColor())));
- }
+tools::Rectangle
+VclMetafileProcessor2D::impDumpToMetaFile(const primitive2d::Primitive2DContainer& rContent,
+ GDIMetaFile& o_rContentMetafile)
+{
+ // Prepare VDev, MetaFile and connections
+ OutputDevice* pLastOutputDevice = mpOutputDevice;
+ GDIMetaFile* pLastMetafile = mpMetaFile;
+ basegfx::B2DRange aPrimitiveRange(rContent.getB2DRange(getViewInformation2D()));
+
+ // transform primitive range with current transformation (e.g shadow offset)
+ aPrimitiveRange.transform(maCurrentTransformation);
+
+ const tools::Rectangle aPrimitiveRectangle(
+ basegfx::fround(aPrimitiveRange.getMinX()), basegfx::fround(aPrimitiveRange.getMinY()),
+ basegfx::fround(aPrimitiveRange.getMaxX()), basegfx::fround(aPrimitiveRange.getMaxY()));
+ ScopedVclPtrInstance<VirtualDevice> aContentVDev;
+ MapMode aNewMapMode(pLastOutputDevice->GetMapMode());
+
+ mpOutputDevice = aContentVDev.get();
+ mpMetaFile = &o_rContentMetafile;
+ aContentVDev->EnableOutput(false);
+ aContentVDev->SetMapMode(pLastOutputDevice->GetMapMode());
+ o_rContentMetafile.Record(aContentVDev.get());
+ aContentVDev->SetLineColor(pLastOutputDevice->GetLineColor());
+ aContentVDev->SetFillColor(pLastOutputDevice->GetFillColor());
+ aContentVDev->SetFont(pLastOutputDevice->GetFont());
+ aContentVDev->SetDrawMode(pLastOutputDevice->GetDrawMode());
+ aContentVDev->SetSettings(pLastOutputDevice->GetSettings());
+ aContentVDev->SetRefPoint(pLastOutputDevice->GetRefPoint());
+
+ // dump to MetaFile
+ process(rContent);
+
+ // cleanups
+ o_rContentMetafile.Stop();
+ o_rContentMetafile.WindStart();
+ aNewMapMode.SetOrigin(aPrimitiveRectangle.TopLeft());
+ o_rContentMetafile.SetPrefMapMode(aNewMapMode);
+ o_rContentMetafile.SetPrefSize(aPrimitiveRectangle.GetSize());
+ mpOutputDevice = pLastOutputDevice;
+ mpMetaFile = pLastMetafile;
+
+ return aPrimitiveRectangle;
+}
+
+void VclMetafileProcessor2D::impConvertFillGradientAttributeToVCLGradient(
+ Gradient& o_rVCLGradient, const attribute::FillGradientAttribute& rFiGrAtt,
+ bool bIsTransparenceGradient) const
+{
+ if (bIsTransparenceGradient)
+ {
+ // it's about transparence channel intensities (black/white), do not use color modifier
+ o_rVCLGradient.SetStartColor(Color(rFiGrAtt.getStartColor()));
+ o_rVCLGradient.SetEndColor(Color(rFiGrAtt.getEndColor()));
+ }
+ else
+ {
+ // use color modifier to influence start/end color of gradient
+ o_rVCLGradient.SetStartColor(
+ Color(maBColorModifierStack.getModifiedColor(rFiGrAtt.getStartColor())));
+ o_rVCLGradient.SetEndColor(
+ Color(maBColorModifierStack.getModifiedColor(rFiGrAtt.getEndColor())));
+ }
- o_rVCLGradient.SetAngle(static_cast< sal_uInt16 >(rFiGrAtt.getAngle() * (1.0 / F_PI1800)));
- o_rVCLGradient.SetBorder(static_cast< sal_uInt16 >(rFiGrAtt.getBorder() * 100.0));
- o_rVCLGradient.SetOfsX(static_cast< sal_uInt16 >(rFiGrAtt.getOffsetX() * 100.0));
- o_rVCLGradient.SetOfsY(static_cast< sal_uInt16 >(rFiGrAtt.getOffsetY() * 100.0));
- o_rVCLGradient.SetSteps(rFiGrAtt.getSteps());
+ o_rVCLGradient.SetAngle(static_cast<sal_uInt16>(rFiGrAtt.getAngle() * (1.0 / F_PI1800)));
+ o_rVCLGradient.SetBorder(static_cast<sal_uInt16>(rFiGrAtt.getBorder() * 100.0));
+ o_rVCLGradient.SetOfsX(static_cast<sal_uInt16>(rFiGrAtt.getOffsetX() * 100.0));
+ o_rVCLGradient.SetOfsY(static_cast<sal_uInt16>(rFiGrAtt.getOffsetY() * 100.0));
+ o_rVCLGradient.SetSteps(rFiGrAtt.getSteps());
- // defaults for intensity; those were computed into the start/end colors already
- o_rVCLGradient.SetStartIntensity(100);
- o_rVCLGradient.SetEndIntensity(100);
+ // defaults for intensity; those were computed into the start/end colors already
+ o_rVCLGradient.SetStartIntensity(100);
+ o_rVCLGradient.SetEndIntensity(100);
- switch(rFiGrAtt.getStyle())
- {
- default : // attribute::GradientStyle::Linear :
- {
- o_rVCLGradient.SetStyle(GradientStyle::Linear);
- break;
- }
- case attribute::GradientStyle::Axial :
- {
- o_rVCLGradient.SetStyle(GradientStyle::Axial);
- break;
- }
- case attribute::GradientStyle::Radial :
- {
- o_rVCLGradient.SetStyle(GradientStyle::Radial);
- break;
- }
- case attribute::GradientStyle::Elliptical :
- {
- o_rVCLGradient.SetStyle(GradientStyle::Elliptical);
- break;
- }
- case attribute::GradientStyle::Square :
- {
- o_rVCLGradient.SetStyle(GradientStyle::Square);
- break;
- }
- case attribute::GradientStyle::Rect :
- {
- o_rVCLGradient.SetStyle(GradientStyle::Rect);
- break;
- }
- }
+ switch (rFiGrAtt.getStyle())
+ {
+ default: // attribute::GradientStyle::Linear :
+ {
+ o_rVCLGradient.SetStyle(GradientStyle::Linear);
+ break;
}
-
- void VclMetafileProcessor2D::impStartSvtGraphicFill(SvtGraphicFill const * pSvtGraphicFill)
+ case attribute::GradientStyle::Axial:
{
- if(pSvtGraphicFill && !mnSvtGraphicFillCount)
- {
- SvMemoryStream aMemStm;
-
- WriteSvtGraphicFill( aMemStm, *pSvtGraphicFill );
- mpMetaFile->AddAction(new MetaCommentAction("XPATHFILL_SEQ_BEGIN", 0, static_cast< const sal_uInt8* >(aMemStm.GetData()), aMemStm.TellEnd()));
- mnSvtGraphicFillCount++;
- }
+ o_rVCLGradient.SetStyle(GradientStyle::Axial);
+ break;
}
-
- void VclMetafileProcessor2D::impEndSvtGraphicFill(SvtGraphicFill const * pSvtGraphicFill)
+ case attribute::GradientStyle::Radial:
{
- if(pSvtGraphicFill && mnSvtGraphicFillCount)
- {
- mnSvtGraphicFillCount--;
- mpMetaFile->AddAction(new MetaCommentAction("XPATHFILL_SEQ_END"));
- }
+ o_rVCLGradient.SetStyle(GradientStyle::Radial);
+ break;
}
-
- double VclMetafileProcessor2D::getTransformedLineWidth( double fWidth ) const
+ case attribute::GradientStyle::Elliptical:
{
- // #i113922# the LineWidth is duplicated in the MetaPolylineAction,
- // and also inside the SvtGraphicStroke and needs transforming into
- // the same space as its coordinates here cf. fdo#61789
- // This is a partial fix. When an object transformation is used which
- // e.g. contains a scaleX != scaleY, an unproportional scaling will happen.
- const basegfx::B2DVector aDiscreteUnit( maCurrentTransformation * basegfx::B2DVector( fWidth, 0.0 ) );
-
- return aDiscreteUnit.getLength();
+ o_rVCLGradient.SetStyle(GradientStyle::Elliptical);
+ break;
}
-
- std::unique_ptr<SvtGraphicStroke> VclMetafileProcessor2D::impTryToCreateSvtGraphicStroke(
- const basegfx::B2DPolygon& rB2DPolygon,
- const basegfx::BColor* pColor,
- const attribute::LineAttribute* pLineAttribute,
- const attribute::StrokeAttribute* pStrokeAttribute,
- const attribute::LineStartEndAttribute* pStart,
- const attribute::LineStartEndAttribute* pEnd)
+ case attribute::GradientStyle::Square:
+ {
+ o_rVCLGradient.SetStyle(GradientStyle::Square);
+ break;
+ }
+ case attribute::GradientStyle::Rect:
{
- std::unique_ptr<SvtGraphicStroke> pRetval;
+ o_rVCLGradient.SetStyle(GradientStyle::Rect);
+ break;
+ }
+ }
+}
- if(rB2DPolygon.count() && !mnSvtGraphicStrokeCount)
- {
- basegfx::B2DPolygon aLocalPolygon(rB2DPolygon);
- basegfx::BColor aStrokeColor;
- basegfx::B2DPolyPolygon aStartArrow;
- basegfx::B2DPolyPolygon aEndArrow;
+void VclMetafileProcessor2D::impStartSvtGraphicFill(SvtGraphicFill const* pSvtGraphicFill)
+{
+ if (pSvtGraphicFill && !mnSvtGraphicFillCount)
+ {
+ SvMemoryStream aMemStm;
- if(pColor)
- {
- aStrokeColor = *pColor;
- }
- else if(pLineAttribute)
- {
- aStrokeColor = maBColorModifierStack.getModifiedColor(pLineAttribute->getColor());
- }
+ WriteSvtGraphicFill(aMemStm, *pSvtGraphicFill);
+ mpMetaFile->AddAction(new MetaCommentAction(
+ "XPATHFILL_SEQ_BEGIN", 0, static_cast<const sal_uInt8*>(aMemStm.GetData()),
+ aMemStm.TellEnd()));
+ mnSvtGraphicFillCount++;
+ }
+}
- // It IS needed to record the stroke color at all in the metafile,
- // SvtGraphicStroke has NO entry for stroke color(!)
- mpOutputDevice->SetLineColor(Color(aStrokeColor));
+void VclMetafileProcessor2D::impEndSvtGraphicFill(SvtGraphicFill const* pSvtGraphicFill)
+{
+ if (pSvtGraphicFill && mnSvtGraphicFillCount)
+ {
+ mnSvtGraphicFillCount--;
+ mpMetaFile->AddAction(new MetaCommentAction("XPATHFILL_SEQ_END"));
+ }
+}
- if(!aLocalPolygon.isClosed())
- {
- double fPolyLength(0.0);
- double fStart(0.0);
- double fEnd(0.0);
-
- if(pStart && pStart->isActive())
- {
- fPolyLength = basegfx::utils::getLength(aLocalPolygon);
-
- aStartArrow = basegfx::utils::createAreaGeometryForLineStartEnd(
- aLocalPolygon, pStart->getB2DPolyPolygon(), true, pStart->getWidth(),
- fPolyLength, pStart->isCentered() ? 0.5 : 0.0, &fStart);
- }
-
- if(pEnd && pEnd->isActive())
- {
- if(basegfx::fTools::equalZero(fPolyLength))
- {
- fPolyLength = basegfx::utils::getLength(aLocalPolygon);
- }
-
- aEndArrow = basegfx::utils::createAreaGeometryForLineStartEnd(
- aLocalPolygon, pEnd->getB2DPolyPolygon(), false, pEnd->getWidth(),
- fPolyLength, pEnd->isCentered() ? 0.5 : 0.0, &fEnd);
- }
-
- if(0.0 != fStart || 0.0 != fEnd)
- {
- // build new poly, consume something from old poly
- aLocalPolygon = basegfx::utils::getSnippetAbsolute(aLocalPolygon, fStart, fPolyLength - fEnd, fPolyLength);
- }
- }
+double VclMetafileProcessor2D::getTransformedLineWidth(double fWidth) const
+{
+ // #i113922# the LineWidth is duplicated in the MetaPolylineAction,
+ // and also inside the SvtGraphicStroke and needs transforming into
+ // the same space as its coordinates here cf. fdo#61789
+ // This is a partial fix. When an object transformation is used which
+ // e.g. contains a scaleX != scaleY, an unproportional scaling will happen.
+ const basegfx::B2DVector aDiscreteUnit(maCurrentTransformation
+ * basegfx::B2DVector(fWidth, 0.0));
+
+ return aDiscreteUnit.getLength();
+}
+
+std::unique_ptr<SvtGraphicStroke> VclMetafileProcessor2D::impTryToCreateSvtGraphicStroke(
+ const basegfx::B2DPolygon& rB2DPolygon, const basegfx::BColor* pColor,
+ const attribute::LineAttribute* pLineAttribute,
+ const attribute::StrokeAttribute* pStrokeAttribute,
+ const attribute::LineStartEndAttribute* pStart, const attribute::LineStartEndAttribute* pEnd)
+{
+ std::unique_ptr<SvtGraphicStroke> pRetval;
- SvtGraphicStroke::JoinType eJoin(SvtGraphicStroke::joinNone);
- SvtGraphicStroke::CapType eCap(SvtGraphicStroke::capButt);
- double fLineWidth(0.0);
- double fMiterLength(0.0);
- SvtGraphicStroke::DashArray aDashArray;
+ if (rB2DPolygon.count() && !mnSvtGraphicStrokeCount)
+ {
+ basegfx::B2DPolygon aLocalPolygon(rB2DPolygon);
+ basegfx::BColor aStrokeColor;
+ basegfx::B2DPolyPolygon aStartArrow;
+ basegfx::B2DPolyPolygon aEndArrow;
- if(pLineAttribute)
- {
- fLineWidth = fMiterLength = getTransformedLineWidth( pLineAttribute->getWidth() );
-
- // get Join
- switch(pLineAttribute->getLineJoin())
- {
- case basegfx::B2DLineJoin::NONE :
- {
- eJoin = SvtGraphicStroke::joinNone;
- break;
- }
- case basegfx::B2DLineJoin::Bevel :
- {
- eJoin = SvtGraphicStroke::joinBevel;
- break;
- }
- case basegfx::B2DLineJoin::Miter :
- {
- eJoin = SvtGraphicStroke::joinMiter;
- // ATM 15 degrees is assumed
- fMiterLength /= rtl::math::sin(basegfx::deg2rad(15.0));
- break;
- }
- case basegfx::B2DLineJoin::Round :
- {
- eJoin = SvtGraphicStroke::joinRound;
- break;
- }
- }
-
- // get stroke
- switch(pLineAttribute->getLineCap())
- {
- default: /* css::drawing::LineCap_BUTT */
- {
- eCap = SvtGraphicStroke::capButt;
- break;
- }
- case css::drawing::LineCap_ROUND:
- {
- eCap = SvtGraphicStroke::capRound;
- break;
- }
- case css::drawing::LineCap_SQUARE:
- {
- eCap = SvtGraphicStroke::capSquare;
- break;
- }
- }
- }
+ if (pColor)
+ {
+ aStrokeColor = *pColor;
+ }
+ else if (pLineAttribute)
+ {
+ aStrokeColor = maBColorModifierStack.getModifiedColor(pLineAttribute->getColor());
+ }
- if(pStrokeAttribute)
- {
- // copy dash array
- aDashArray = pStrokeAttribute->getDotDashArray();
- }
+ // It IS needed to record the stroke color at all in the metafile,
+ // SvtGraphicStroke has NO entry for stroke color(!)
+ mpOutputDevice->SetLineColor(Color(aStrokeColor));
- // #i101734# apply current object transformation to created geometry.
- // This is a partial fix. When an object transformation is used which
- // e.g. contains a scaleX != scaleY, an unproportional scaling would
- // have to be applied to the evtl. existing fat line. The current
- // concept of PDF export and SvtGraphicStroke usage does simply not
- // allow handling such definitions. The only clean way would be to
- // add the transformation to SvtGraphicStroke and to handle it there
- aLocalPolygon.transform(maCurrentTransformation);
- aStartArrow.transform(maCurrentTransformation);
- aEndArrow.transform(maCurrentTransformation);
-
- pRetval.reset(new SvtGraphicStroke(
- ::tools::Polygon(aLocalPolygon),
- ::tools::PolyPolygon(aStartArrow),
- ::tools::PolyPolygon(aEndArrow),
- mfCurrentUnifiedTransparence,
- fLineWidth,
- eCap,
- eJoin,
- fMiterLength,
- aDashArray));
- }
+ if (!aLocalPolygon.isClosed())
+ {
+ double fPolyLength(0.0);
+ double fStart(0.0);
+ double fEnd(0.0);
- return pRetval;
- }
+ if (pStart && pStart->isActive())
+ {
+ fPolyLength = basegfx::utils::getLength(aLocalPolygon);
- void VclMetafileProcessor2D::impStartSvtGraphicStroke(SvtGraphicStroke const * pSvtGraphicStroke)
- {
- if(pSvtGraphicStroke && !mnSvtGraphicStrokeCount)
+ aStartArrow = basegfx::utils::createAreaGeometryForLineStartEnd(
+ aLocalPolygon, pStart->getB2DPolyPolygon(), true, pStart->getWidth(),
+ fPolyLength, pStart->isCentered() ? 0.5 : 0.0, &fStart);
+ }
+
+ if (pEnd && pEnd->isActive())
{
- SvMemoryStream aMemStm;
+ if (basegfx::fTools::equalZero(fPolyLength))
+ {
+ fPolyLength = basegfx::utils::getLength(aLocalPolygon);
+ }
- WriteSvtGraphicStroke( aMemStm, *pSvtGraphicStroke );
- mpMetaFile->AddAction(new MetaCommentAction("XPATHSTROKE_SEQ_BEGIN", 0, static_cast< const sal_uInt8* >(aMemStm.GetData()), aMemStm.TellEnd()));
- mnSvtGraphicStrokeCount++;
+ aEndArrow = basegfx::utils::createAreaGeometryForLineStartEnd(
+ aLocalPolygon, pEnd->getB2DPolyPolygon(), false, pEnd->getWidth(), fPolyLength,
+ pEnd->isCentered() ? 0.5 : 0.0, &fEnd);
}
- }
- void VclMetafileProcessor2D::impEndSvtGraphicStroke(SvtGraphicStroke const * pSvtGraphicStroke)
- {
- if(pSvtGraphicStroke && mnSvtGraphicStrokeCount)
+ if (0.0 != fStart || 0.0 != fEnd)
{
- mnSvtGraphicStrokeCount--;
- mpMetaFile->AddAction(new MetaCommentAction("XPATHSTROKE_SEQ_END"));
+ // build new poly, consume something from old poly
+ aLocalPolygon = basegfx::utils::getSnippetAbsolute(aLocalPolygon, fStart,
+ fPolyLength - fEnd, fPolyLength);
}
}
- void VclMetafileProcessor2D::popStructureElement(vcl::PDFWriter::StructElement eElem)
- {
- if (!maListElements.empty() && maListElements.top() == eElem)
- {
- maListElements.pop();
- mpPDFExtOutDevData->EndStructureElement();
- }
- }
+ SvtGraphicStroke::JoinType eJoin(SvtGraphicStroke::joinNone);
+ SvtGraphicStroke::CapType eCap(SvtGraphicStroke::capButt);
+ double fLineWidth(0.0);
+ double fMiterLength(0.0);
+ SvtGraphicStroke::DashArray aDashArray;
- void VclMetafileProcessor2D::popListItem()
+ if (pLineAttribute)
{
- popStructureElement(vcl::PDFWriter::LIBody);
- popStructureElement(vcl::PDFWriter::ListItem);
- }
+ fLineWidth = fMiterLength = getTransformedLineWidth(pLineAttribute->getWidth());
- void VclMetafileProcessor2D::popList()
- {
- popListItem();
- popStructureElement(vcl::PDFWriter::List);
- }
-
- // init static break iterator
- uno::Reference< css::i18n::XBreakIterator > VclMetafileProcessor2D::mxBreakIterator;
-
- VclMetafileProcessor2D::VclMetafileProcessor2D(const geometry::ViewInformation2D& rViewInformation, OutputDevice& rOutDev)
- : VclProcessor2D(rViewInformation, rOutDev),
- mpMetaFile(rOutDev.GetConnectMetaFile()),
- mnSvtGraphicFillCount(0),
- mnSvtGraphicStrokeCount(0),
- mfCurrentUnifiedTransparence(0.0),
- mpPDFExtOutDevData(dynamic_cast< vcl::PDFExtOutDevData* >(rOutDev.GetExtOutDevData())),
- mnCurrentOutlineLevel(-1),
- mbInListItem(false),
- mbBulletPresent(false)
- {
- OSL_ENSURE(rOutDev.GetConnectMetaFile(), "VclMetafileProcessor2D: Used on OutDev which has no MetaFile Target (!)");
- // draw to logic coordinates, do not initialize maCurrentTransformation to viewTransformation
- // but only to ObjectTransformation. Do not change MapMode of destination.
- maCurrentTransformation = rViewInformation.getObjectTransformation();
- }
-
- VclMetafileProcessor2D::~VclMetafileProcessor2D()
- {
- // MapMode was not changed, no restore necessary
- }
-
- /***********************************************************************************************
-
- Support of MetaCommentActions in the VclMetafileProcessor2D
- Found MetaCommentActions and how they are supported:
-
- XGRAD_SEQ_BEGIN, XGRAD_SEQ_END:
-
- Used inside OutputDevice::DrawGradient to mark the start and end of a MetaGradientEx action.
- It is used in various exporters/importers to have direct access to the gradient before it
- is rendered by VCL (and thus fragmented to polygon color actions and others). On that base, e.g.
- the Metafile to SdrObject import creates its gradient objects.
- Best (and safest) way to support it here is to use PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D,
- map it back to the corresponding tools tools::PolyPolygon and the Gradient and just call
- OutputDevice::DrawGradient which creates the necessary compatible actions.
-
- XPATHFILL_SEQ_BEGIN, XPATHFILL_SEQ_END:
-
- Two producers, one is vcl/source/gdi/gdimtf.cxx, line 1273. There, it is transformed
- inside GDIMetaFile::Rotate, nothing to take care of here.
- The second producer is in graphics/svx/source/svdraw/impgrfll.cxx, line 374. This is used
- with each incarnation of Imp_GraphicFill when a metafile is recorded, fillstyle is not
- XFILL_NONE and not completely transparent. It creates a SvtGraphicFill and streams it
- to the comment action. A closing end token is created in the destructor.
- Usages of Imp_GraphicFill are in Do_Paint_Object-methods of SdrCircObj, SdrPathObj and
- SdrRectObj.
- The token users pick various actions from SvtGraphicFill, so it may need to be added for all kind
- of filled objects, even simple colored polygons. It is added as extra information; the
- Metafile actions between the two tokens are interpreted as output generated from those
- fills. Thus, users have the choice to use the SvtGraphicFill info or the created output
- actions.
- Even for XFillTransparenceItem it is used, thus it may need to be supported in
- UnifiedTransparencePrimitive2D, too, when interpreted as normally filled PolyPolygon.
- Implemented for:
- PRIMITIVE2D_ID_POLYPOLYGONGRAPHICPRIMITIVE2D,
- PRIMITIVE2D_ID_POLYPOLYGONHATCHPRIMITIVE2D,
- PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D,
- PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D,
- and for PRIMITIVE2D_ID_UNIFIEDTRANSPARENCEPRIMITIVE2D when detected unified transparence
-
- XPATHSTROKE_SEQ_BEGIN, XPATHSTROKE_SEQ_END:
-
- Similar to pathfill, but using SvtGraphicStroke instead. It also has two producers where one
- is also the GDIMetaFile::Rotate. Another user is MetaCommentAction::Move which modifies the
- contained path accordingly.
- The other one is SdrObject::Imp_DrawLineGeometry. It's done when MetaFile is set at OutDev and
- only when geometry is a single polygon (!). I see no reason for that; in the PS exporter this
- would hinder to make use of tools::PolyPolygon strokes. I will need to add support at:
- PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D
- PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D
- PRIMITIVE2D_ID_POLYGONSTROKEARROWPRIMITIVE2D
- This can be done hierarchical, too.
- Okay, base implementation done based on those three primitives.
-
- FIELD_SEQ_BEGIN, FIELD_SEQ_END
-
- Used from slideshow for URLs, created from diverse SvxField implementations inside
- createBeginComment()/createEndComment(). createBeginComment() is used from editeng\impedit3.cxx
- inside ImpEditEngine::Paint.
- Created TextHierarchyFieldPrimitive2D and added needed infos there; it is a group primitive and wraps
- text primitives (but is not limited to that). It contains the field type if special actions for the
- support of FIELD_SEQ_BEGIN/END are needed; this is the case for Page and URL fields. If more is
- needed, it may be supported there.
- FIELD_SEQ_BEGIN;PageField
- FIELD_SEQ_END
- Okay, these are now completely supported by TextHierarchyFieldPrimitive2D. URL works, too.
-
- XTEXT
-
- XTEXT_EOC(i) end of character
- XTEXT_EOW(i) end of word
- XTEXT_EOS(i) end of sentence
-
- this three are with index and are created with the help of an i18n::XBreakIterator in
- ImplDrawWithComments. Simplifying, moving out text painting, reworking to create some
- data structure for holding those TEXT infos.
- Supported directly by TextSimplePortionPrimitive2D with adding a Locale to the basic text
- primitive. In the MetaFileRenderer, the creation is now done (see below). This has the advantage
- that this creations do not need to be done for all paints all the time. This would be
- expensive since the BreakIterator and it's usage is expensive and for each paint also the
- whole character stops would need to be created.
- Created only for TextDecoratedPortionPrimitive2D due to XTEXT_EOL and XTEXT_EOP (see below)
-
- XTEXT_EOL() end of line
- XTEXT_EOP() end of paragraph
-
- First try with boolean marks at TextDecoratedPortionPrimitive2D did not work too well,
- i decided to solve it with structure. I added the TextHierarchyPrimitives for this,
- namely:
- - TextHierarchyLinePrimitive2D: Encapsulates single line
- - TextHierarchyParagraphPrimitive2D: Encapsulates single paragraph
- - TextHierarchyBlockPrimitive2D: encapsulates object texts (only one ATM)
- Those are now supported in hierarchy. This means the MetaFile renderer will support them
- by using them, recursively using their content and adding MetaFile comments as needed.
- This also means that when another text layouter will be used it will be necessary to
- create/support the same HierarchyPrimitives to support users.
- To transport the information using this hierarchy is best suited to all future needs;
- the slideshow will be able to profit from it directly when using primitives; all other
- renderers not interested in the text structure will just ignore the encapsulations.
-
- XTEXT_PAINTSHAPE_BEGIN, XTEXT_PAINTSHAPE_END
- Supported now by the TextHierarchyBlockPrimitive2D.
-
- EPSReplacementGraphic:
- Only used in goodies\source\filter.vcl\ieps\ieps.cxx and svx\source\xml\xmlgrhlp.cxx to
- hold the original EPS which was imported in the same MetaFile as first 2 entries. Only
- used to export the original again (if exists).
- Not necessary to support with MetaFuleRenderer.
-
- XTEXT_SCROLLRECT, XTEXT_PAINTRECT
- Currently used to get extra MetaFile infos using GraphicExporter which again uses
- SdrTextObj::GetTextScrollMetaFileAndRectangle(). ATM works with primitives since
- the rectangle data is added directly by the GraphicsExporter as comment. Does not need
- to be adapted at once.
- When adapting later, the only user - the diashow - should directly use the provided
- Animation infos in the appropriate primitives (e.g. AnimatedSwitchPrimitive2D)
-
- PRNSPOOL_TRANSPARENTBITMAP_BEGIN, PRNSPOOL_TRANSPARENTBITMAP_END
- VCL usage when printing PL -> THB. Okay, THB confirms that it is only used as
- a fix (hack) while VCL printing. It is needed to not downscale a bitmap which
- was explicitly created for the printer already again to some default maximum
- bitmap sizes.
- Nothing to do here for the primitive renderer.
-
- Support for vcl::PDFExtOutDevData:
- PL knows that SJ did that stuff, it's used to hold a pointer to PDFExtOutDevData at
- the OutDev. When set, some extra data is written there. Trying simple PDF export and
- watching if I get those infos.
- Well, a PDF export does not use e.g. ImpEditEngine::Paint since the PdfFilter uses
- the SdXImpressDocument::render and thus uses the VclMetafileProcessor2D. I will check
- if I get a PDFExtOutDevData at the target output device.
- Indeed, I get one. Checking what all may be done when that extra-device-info is there.
-
- All in all I have to talk to SJ. I will need to emulate some of those actions, but
- i need to discuss which ones.
- In the future, all those infos would be taken from the primitive sequence anyways,
- thus these extensions would potentially be temporary, too.
- Discussed with SJ, added the necessary support and tested it. Details follow.
-
- - In ImpEditEngine::Paint, paragraph infos and URL stuff is added.
- Added in primitive MetaFile renderer.
- Checking URL: Indeed, current version exports it, but it is missing in primitive
- CWS version. Adding support.
- Okay, URLs work. Checked, Done.
-
- - UnoControlPDFExportContact is only created when PDFExtOutDevData is used at the
- target and uno control data is created in UnoControlPDFExportContact::do_PaintObject.
- This may be added in primitive MetaFile renderer.
- Adding support...
- OOps, the necessary helper stuff is in svx/source/form/formpdxexport.cxx in namespace
- svxform. Have to talk to FS if this has to be like that. Especially since
- vcl::PDFWriter::AnyWidget is filled out, which is already part of vcl.
- Wrote an eMail to FS, he is on vacation currently. I see no reason why not to move
- that stuff to somewhere else, maybe tools or svtools ?!? We will see...
- Moved to toolkit, so I have to link against it. I tried VCL first, but it did
- not work since VCLUnoHelper::CreateFont is unresolved in VCL (!). Other than the name
- may imply, it is defined in toolkit (!). Since toolkit is linked against VCL itself,
- the lowest movement plane is toolkit.
- Checked form control export, it works well. Done.
-
- - In goodies, in GraphicObject::Draw, when the used Graphic is linked, infos are
- generated. I will need to check what happens here with primitives.
- To support, use of GraphicPrimitive2D (PRIMITIVE2D_ID_GRAPHICPRIMITIVE2D) may be needed.
- Added support, but feature is broken in main version, so i cannot test at all.
- Writing a bug to CL (or SJ) and seeing what happens (#i80380#).
- SJ took a look and we got it working. Tested VCL MetaFile Renderer based export,
- as intended, the original file is exported. Works, Done.
-
-
- To be done:
-
- - Maybe there are more places to take care of for vcl::PDFExtOutDevData!
-
-
- ****************************************************************************************************/
-
- void VclMetafileProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate)
- {
- switch(rCandidate.getPrimitive2DID())
+ // get Join
+ switch (pLineAttribute->getLineJoin())
{
- case PRIMITIVE2D_ID_WRONGSPELLPRIMITIVE2D :
- {
- // directdraw of wrong spell primitive
- // Ignore for VclMetafileProcessor2D, this is for printing and MetaFile recording only
- break;
- }
- case PRIMITIVE2D_ID_GRAPHICPRIMITIVE2D :
- {
- processGraphicPrimitive2D(static_cast<const primitive2d::GraphicPrimitive2D&>(rCandidate));
- break;
- }
- case PRIMITIVE2D_ID_CONTROLPRIMITIVE2D :
- {
- processControlPrimitive2D(static_cast<const primitive2d::ControlPrimitive2D&>(rCandidate));
- break;
- }
- case PRIMITIVE2D_ID_TEXTHIERARCHYFIELDPRIMITIVE2D :
- {
- processTextHierarchyFieldPrimitive2D(static_cast<const primitive2d::TextHierarchyFieldPrimitive2D& >(rCandidate));
- break;
- }
- case PRIMITIVE2D_ID_TEXTHIERARCHYLINEPRIMITIVE2D :
- {
- processTextHierarchyLinePrimitive2D(static_cast<const primitive2d::TextHierarchyLinePrimitive2D&>(rCandidate));
- break;
- }
- case PRIMITIVE2D_ID_TEXTHIERARCHYBULLETPRIMITIVE2D :
- {
- processTextHierarchyBulletPrimitive2D(static_cast<const primitive2d::TextHierarchyBulletPrimitive2D&>(rCandidate));
- break;
- }
- case PRIMITIVE2D_ID_TEXTHIERARCHYPARAGRAPHPRIMITIVE2D :
- {
- processTextHierarchyParagraphPrimitive2D(static_cast<const primitive2d::TextHierarchyParagraphPrimitive2D&>(rCandidate));
- break;
- }
- case PRIMITIVE2D_ID_TEXTHIERARCHYBLOCKPRIMITIVE2D :
- {
- processTextHierarchyBlockPrimitive2D(static_cast<const primitive2d::TextHierarchyBlockPrimitive2D&>(rCandidate));
- break;
- }
- case PRIMITIVE2D_ID_TEXTSIMPLEPORTIONPRIMITIVE2D :
- case PRIMITIVE2D_ID_TEXTDECORATEDPORTIONPRIMITIVE2D :
- {
- // for supporting TEXT_ MetaFile actions there is more to do here; get the candidate
- processTextSimplePortionPrimitive2D(static_cast<const primitive2d::TextSimplePortionPrimitive2D& >(rCandidate));
- break;
- }
- case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D :
- {
- processPolygonHairlinePrimitive2D(static_cast<const primitive2d::PolygonHairlinePrimitive2D&>(rCandidate));
- break;
- }
- case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D :
- {
- processPolygonStrokePrimitive2D(static_cast<const primitive2d::PolygonStrokePrimitive2D&>(rCandidate));
- break;
- }
- case PRIMITIVE2D_ID_POLYGONSTROKEARROWPRIMITIVE2D :
- {
- processPolygonStrokeArrowPrimitive2D(static_cast<const primitive2d::PolygonStrokeArrowPrimitive2D&>(rCandidate));
- break;
- }
- case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D :
- {
- // direct draw of transformed BitmapEx primitive; use default processing, but without
- // former testing if graphic content is inside discrete local viewport; this is not
- // setup for metafile targets (metafile renderer tries to render in logic coordinates,
- // the mapping is kept to the OutputDevice for better Metafile recording)
- RenderBitmapPrimitive2D(static_cast< const primitive2d::BitmapPrimitive2D& >(rCandidate));
- break;
- }
- case PRIMITIVE2D_ID_POLYPOLYGONGRAPHICPRIMITIVE2D :
- {
- processPolyPolygonGraphicPrimitive2D(static_cast<const primitive2d::PolyPolygonGraphicPrimitive2D& >(rCandidate));
- break;
- }
- case PRIMITIVE2D_ID_POLYPOLYGONHATCHPRIMITIVE2D :
- {
- processPolyPolygonHatchPrimitive2D(static_cast<const primitive2d::PolyPolygonHatchPrimitive2D&>(rCandidate));
- break;
- }
- case PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D :
- {
- processPolyPolygonGradientPrimitive2D(static_cast<const primitive2d::PolyPolygonGradientPrimitive2D&>(rCandidate));
- break;
- }
- case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D :
- {
- processPolyPolygonColorPrimitive2D(static_cast<const primitive2d::PolyPolygonColorPrimitive2D&>(rCandidate));
- break;
- }
- case PRIMITIVE2D_ID_MASKPRIMITIVE2D :
- {
- processMaskPrimitive2D(static_cast<const primitive2d::MaskPrimitive2D&>(rCandidate));
- break;
- }
- case PRIMITIVE2D_ID_MODIFIEDCOLORPRIMITIVE2D :
- {
- // modified color group. Force output to unified color. Use default pocessing.
- RenderModifiedColorPrimitive2D(static_cast< const primitive2d::ModifiedColorPrimitive2D& >(rCandidate));
- break;
- }
- case PRIMITIVE2D_ID_UNIFIEDTRANSPARENCEPRIMITIVE2D :
- {
- processUnifiedTransparencePrimitive2D(static_cast<const primitive2d::UnifiedTransparencePrimitive2D&>(rCandidate));
- break;
- }
- case PRIMITIVE2D_ID_TRANSPARENCEPRIMITIVE2D :
- {
- processTransparencePrimitive2D(static_cast<const primitive2d::TransparencePrimitive2D&>(rCandidate));
- break;
- }
- case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D :
+ case basegfx::B2DLineJoin::NONE:
{
- // use default transform group pocessing
- RenderTransformPrimitive2D(static_cast< const primitive2d::TransformPrimitive2D& >(rCandidate));
+ eJoin = SvtGraphicStroke::joinNone;
break;
}
- case PRIMITIVE2D_ID_PAGEPREVIEWPRIMITIVE2D :
+ case basegfx::B2DLineJoin::Bevel:
{
- // new XDrawPage for ViewInformation2D
- RenderPagePreviewPrimitive2D(static_cast< const primitive2d::PagePreviewPrimitive2D& >(rCandidate));
+ eJoin = SvtGraphicStroke::joinBevel;
break;
}
- case PRIMITIVE2D_ID_MARKERARRAYPRIMITIVE2D :
+ case basegfx::B2DLineJoin::Miter:
{
- // use default marker array pocessing
- RenderMarkerArrayPrimitive2D(static_cast< const primitive2d::MarkerArrayPrimitive2D& >(rCandidate));
+ eJoin = SvtGraphicStroke::joinMiter;
+ // ATM 15 degrees is assumed
+ fMiterLength /= rtl::math::sin(basegfx::deg2rad(15.0));
break;
}
- case PRIMITIVE2D_ID_POINTARRAYPRIMITIVE2D :
+ case basegfx::B2DLineJoin::Round:
{
- // use default point array pocessing
- RenderPointArrayPrimitive2D(static_cast< const primitive2d::PointArrayPrimitive2D& >(rCandidate));
+ eJoin = SvtGraphicStroke::joinRound;
break;
}
- case PRIMITIVE2D_ID_STRUCTURETAGPRIMITIVE2D :
- {
- processStructureTagPrimitive2D(static_cast<const primitive2d::StructureTagPrimitive2D&>(rCandidate));
- break;
- }
- case PRIMITIVE2D_ID_EPSPRIMITIVE2D :
+ }
+
+ // get stroke
+ switch (pLineAttribute->getLineCap())
+ {
+ default: /* css::drawing::LineCap_BUTT */
{
- RenderEpsPrimitive2D(static_cast< const primitive2d::EpsPrimitive2D& >(rCandidate));
+ eCap = SvtGraphicStroke::capButt;
break;
}
- case PRIMITIVE2D_ID_OBJECTINFOPRIMITIVE2D :
+ case css::drawing::LineCap_ROUND:
{
- RenderObjectInfoPrimitive2D(static_cast< const primitive2d::ObjectInfoPrimitive2D& >(rCandidate));
+ eCap = SvtGraphicStroke::capRound;
break;
}
- default :
+ case css::drawing::LineCap_SQUARE:
{
- // process recursively
- process(rCandidate);
+ eCap = SvtGraphicStroke::capSquare;
break;
}
}
}
- void VclMetafileProcessor2D::processGraphicPrimitive2D(const primitive2d::GraphicPrimitive2D& rGraphicPrimitive)
+ if (pStrokeAttribute)
{
- bool bUsingPDFExtOutDevData(false);
- basegfx::B2DVector aTranslate, aScale;
- static bool bSuppressPDFExtOutDevDataSupport(false); // loplugin:constvars:ignore
-
- if(mpPDFExtOutDevData && !bSuppressPDFExtOutDevDataSupport)
- {
- // emulate data handling from UnoControlPDFExportContact, original see
- // svtools/source/graphic/grfmgr.cxx
- const Graphic& rGraphic = rGraphicPrimitive.getGraphicObject().GetGraphic();
+ // copy dash array
+ aDashArray = pStrokeAttribute->getDotDashArray();
+ }
- if(rGraphic.IsGfxLink())
- {
- const GraphicAttr& rAttr = rGraphicPrimitive.getGraphicAttr();
-
- if(!rAttr.IsSpecialDrawMode() && !rAttr.IsAdjusted())
- {
- const basegfx::B2DHomMatrix& rTransform = rGraphicPrimitive.getTransform();
- double fRotate, fShearX;
- rTransform.decompose(aScale, aTranslate, fRotate, fShearX);
-
- if( basegfx::fTools::equalZero( fRotate ) && ( aScale.getX() > 0.0 ) && ( aScale.getY() > 0.0 ) )
- {
- bUsingPDFExtOutDevData = true;
- mpPDFExtOutDevData->BeginGroup();
- }
- }
- }
- }
+ // #i101734# apply current object transformation to created geometry.
+ // This is a partial fix. When an object transformation is used which
+ // e.g. contains a scaleX != scaleY, an unproportional scaling would
+ // have to be applied to the evtl. existing fat line. The current
+ // concept of PDF export and SvtGraphicStroke usage does simply not
+ // allow handling such definitions. The only clean way would be to
+ // add the transformation to SvtGraphicStroke and to handle it there
+ aLocalPolygon.transform(maCurrentTransformation);
+ aStartArrow.transform(maCurrentTransformation);
+ aEndArrow.transform(maCurrentTransformation);
+
+ pRetval.reset(
+ new SvtGraphicStroke(tools::Polygon(aLocalPolygon), tools::PolyPolygon(aStartArrow),
+ tools::PolyPolygon(aEndArrow), mfCurrentUnifiedTransparence,
+ fLineWidth, eCap, eJoin, fMiterLength, aDashArray));
+ }
- // process recursively and add MetaFile comment
- process(rGraphicPrimitive);
+ return pRetval;
+}
- if(!bUsingPDFExtOutDevData)
- return;
+void VclMetafileProcessor2D::impStartSvtGraphicStroke(SvtGraphicStroke const* pSvtGraphicStroke)
+{
+ if (pSvtGraphicStroke && !mnSvtGraphicStrokeCount)
+ {
+ SvMemoryStream aMemStm;
- // emulate data handling from UnoControlPDFExportContact, original see
- // svtools/source/graphic/grfmgr.cxx
- const basegfx::B2DRange aCurrentRange(
- aTranslate.getX(), aTranslate.getY(),
- aTranslate.getX() + aScale.getX(), aTranslate.getY() + aScale.getY());
- const ::tools::Rectangle aCurrentRect(
- sal_Int32(floor(aCurrentRange.getMinX())), sal_Int32(floor(aCurrentRange.getMinY())),
- sal_Int32(ceil(aCurrentRange.getMaxX())), sal_Int32(ceil(aCurrentRange.getMaxY())));
- const GraphicAttr& rAttr = rGraphicPrimitive.getGraphicAttr();
- // fdo#72530 don't pass empty Rectangle to EndGroup
- ::tools::Rectangle aCropRect(aCurrentRect);
+ WriteSvtGraphicStroke(aMemStm, *pSvtGraphicStroke);
+ mpMetaFile->AddAction(new MetaCommentAction(
+ "XPATHSTROKE_SEQ_BEGIN", 0, static_cast<const sal_uInt8*>(aMemStm.GetData()),
+ aMemStm.TellEnd()));
+ mnSvtGraphicStrokeCount++;
+ }
+}
- if(rAttr.IsCropped())
- {
- // calculate scalings between real image size and logic object size. This
- // is necessary since the crop values are relative to original bitmap size
- double fFactorX(1.0);
- double fFactorY(1.0);
+void VclMetafileProcessor2D::impEndSvtGraphicStroke(SvtGraphicStroke const* pSvtGraphicStroke)
+{
+ if (pSvtGraphicStroke && mnSvtGraphicStrokeCount)
+ {
+ mnSvtGraphicStrokeCount--;
+ mpMetaFile->AddAction(new MetaCommentAction("XPATHSTROKE_SEQ_END"));
+ }
+}
- {
- const MapMode aMapMode100thmm(MapUnit::Map100thMM);
- const Size aBitmapSize(OutputDevice::LogicToLogic(
- rGraphicPrimitive.getGraphicObject().GetPrefSize(),
- rGraphicPrimitive.getGraphicObject().GetPrefMapMode(), aMapMode100thmm));
- const double fDivX(aBitmapSize.Width() - rAttr.GetLeftCrop() - rAttr.GetRightCrop());
- const double fDivY(aBitmapSize.Height() - rAttr.GetTopCrop() - rAttr.GetBottomCrop());
-
- if(!basegfx::fTools::equalZero(fDivX))
- {
- fFactorX = aScale.getX() / fDivX;
- }
-
- if(!basegfx::fTools::equalZero(fDivY))
- {
- fFactorY = aScale.getY() / fDivY;
- }
- }
+void VclMetafileProcessor2D::popStructureElement(vcl::PDFWriter::StructElement eElem)
+{
+ if (!maListElements.empty() && maListElements.top() == eElem)
+ {
+ maListElements.pop();
+ mpPDFExtOutDevData->EndStructureElement();
+ }
+}
- // calculate crop range and rect
- basegfx::B2DRange aCropRange;
- aCropRange.expand(aCurrentRange.getMinimum() - basegfx::B2DPoint(rAttr.GetLeftCrop() * fFactorX, rAttr.GetTopCrop() * fFactorY));
- aCropRange.expand(aCurrentRange.getMaximum() + basegfx::B2DPoint(rAttr.GetRightCrop() * fFactorX, rAttr.GetBottomCrop() * fFactorY));
+void VclMetafileProcessor2D::popListItem()
+{
+ popStructureElement(vcl::PDFWriter::LIBody);
+ popStructureElement(vcl::PDFWriter::ListItem);
+}
- aCropRect = ::tools::Rectangle(
- sal_Int32(floor(aCropRange.getMinX())), sal_Int32(floor(aCropRange.getMinY())),
- sal_Int32(ceil(aCropRange.getMaxX())), sal_Int32(ceil(aCropRange.getMaxY())));
- }
+void VclMetafileProcessor2D::popList()
+{
+ popListItem();
+ popStructureElement(vcl::PDFWriter::List);
+}
+
+// init static break iterator
+uno::Reference<css::i18n::XBreakIterator> VclMetafileProcessor2D::mxBreakIterator;
+
+VclMetafileProcessor2D::VclMetafileProcessor2D(const geometry::ViewInformation2D& rViewInformation,
+ OutputDevice& rOutDev)
+ : VclProcessor2D(rViewInformation, rOutDev)
+ , mpMetaFile(rOutDev.GetConnectMetaFile())
+ , mnSvtGraphicFillCount(0)
+ , mnSvtGraphicStrokeCount(0)
+ , mfCurrentUnifiedTransparence(0.0)
+ , mpPDFExtOutDevData(dynamic_cast<vcl::PDFExtOutDevData*>(rOutDev.GetExtOutDevData()))
+ , mnCurrentOutlineLevel(-1)
+ , mbInListItem(false)
+ , mbBulletPresent(false)
+{
+ OSL_ENSURE(rOutDev.GetConnectMetaFile(),
+ "VclMetafileProcessor2D: Used on OutDev which has no MetaFile Target (!)");
+ // draw to logic coordinates, do not initialize maCurrentTransformation to viewTransformation
+ // but only to ObjectTransformation. Do not change MapMode of destination.
+ maCurrentTransformation = rViewInformation.getObjectTransformation();
+}
+
+VclMetafileProcessor2D::~VclMetafileProcessor2D()
+{
+ // MapMode was not changed, no restore necessary
+}
+
+/***********************************************************************************************
+
+ Support of MetaCommentActions in the VclMetafileProcessor2D
+ Found MetaCommentActions and how they are supported:
+
+ XGRAD_SEQ_BEGIN, XGRAD_SEQ_END:
+
+ Used inside OutputDevice::DrawGradient to mark the start and end of a MetaGradientEx action.
+ It is used in various exporters/importers to have direct access to the gradient before it
+ is rendered by VCL (and thus fragmented to polygon color actions and others). On that base, e.g.
+ the Metafile to SdrObject import creates its gradient objects.
+ Best (and safest) way to support it here is to use PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D,
+ map it back to the corresponding tools tools::PolyPolygon and the Gradient and just call
+ OutputDevice::DrawGradient which creates the necessary compatible actions.
+
+ XPATHFILL_SEQ_BEGIN, XPATHFILL_SEQ_END:
+
+ Two producers, one is vcl/source/gdi/gdimtf.cxx, line 1273. There, it is transformed
+ inside GDIMetaFile::Rotate, nothing to take care of here.
+ The second producer is in graphics/svx/source/svdraw/impgrfll.cxx, line 374. This is used
+ with each incarnation of Imp_GraphicFill when a metafile is recorded, fillstyle is not
+ XFILL_NONE and not completely transparent. It creates a SvtGraphicFill and streams it
+ to the comment action. A closing end token is created in the destructor.
+ Usages of Imp_GraphicFill are in Do_Paint_Object-methods of SdrCircObj, SdrPathObj and
+ SdrRectObj.
+ The token users pick various actions from SvtGraphicFill, so it may need to be added for all kind
+ of filled objects, even simple colored polygons. It is added as extra information; the
+ Metafile actions between the two tokens are interpreted as output generated from those
+ fills. Thus, users have the choice to use the SvtGraphicFill info or the created output
+ actions.
+ Even for XFillTransparenceItem it is used, thus it may need to be supported in
+ UnifiedTransparencePrimitive2D, too, when interpreted as normally filled PolyPolygon.
+ Implemented for:
+ PRIMITIVE2D_ID_POLYPOLYGONGRAPHICPRIMITIVE2D,
+ PRIMITIVE2D_ID_POLYPOLYGONHATCHPRIMITIVE2D,
+ PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D,
+ PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D,
+ and for PRIMITIVE2D_ID_UNIFIEDTRANSPARENCEPRIMITIVE2D when detected unified transparence
+
+ XPATHSTROKE_SEQ_BEGIN, XPATHSTROKE_SEQ_END:
+
+ Similar to pathfill, but using SvtGraphicStroke instead. It also has two producers where one
+ is also the GDIMetaFile::Rotate. Another user is MetaCommentAction::Move which modifies the
+ contained path accordingly.
+ The other one is SdrObject::Imp_DrawLineGeometry. It's done when MetaFile is set at OutDev and
+ only when geometry is a single polygon (!). I see no reason for that; in the PS exporter this
+ would hinder to make use of tools::PolyPolygon strokes. I will need to add support at:
+ PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D
+ PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D
+ PRIMITIVE2D_ID_POLYGONSTROKEARROWPRIMITIVE2D
+ This can be done hierarchical, too.
+ Okay, base implementation done based on those three primitives.
+
+ FIELD_SEQ_BEGIN, FIELD_SEQ_END
+
+ Used from slideshow for URLs, created from diverse SvxField implementations inside
+ createBeginComment()/createEndComment(). createBeginComment() is used from editeng\impedit3.cxx
+ inside ImpEditEngine::Paint.
+ Created TextHierarchyFieldPrimitive2D and added needed infos there; it is a group primitive and wraps
+ text primitives (but is not limited to that). It contains the field type if special actions for the
+ support of FIELD_SEQ_BEGIN/END are needed; this is the case for Page and URL fields. If more is
+ needed, it may be supported there.
+ FIELD_SEQ_BEGIN;PageField
+ FIELD_SEQ_END
+ Okay, these are now completely supported by TextHierarchyFieldPrimitive2D. URL works, too.
+
+ XTEXT
+
+ XTEXT_EOC(i) end of character
+ XTEXT_EOW(i) end of word
+ XTEXT_EOS(i) end of sentence
+
+ this three are with index and are created with the help of an i18n::XBreakIterator in
+ ImplDrawWithComments. Simplifying, moving out text painting, reworking to create some
+ data structure for holding those TEXT infos.
+ Supported directly by TextSimplePortionPrimitive2D with adding a Locale to the basic text
+ primitive. In the MetaFileRenderer, the creation is now done (see below). This has the advantage
+ that this creations do not need to be done for all paints all the time. This would be
+ expensive since the BreakIterator and it's usage is expensive and for each paint also the
+ whole character stops would need to be created.
+ Created only for TextDecoratedPortionPrimitive2D due to XTEXT_EOL and XTEXT_EOP (see below)
+
+ XTEXT_EOL() end of line
+ XTEXT_EOP() end of paragraph
+
+ First try with boolean marks at TextDecoratedPortionPrimitive2D did not work too well,
+ i decided to solve it with structure. I added the TextHierarchyPrimitives for this,
+ namely:
+ - TextHierarchyLinePrimitive2D: Encapsulates single line
+ - TextHierarchyParagraphPrimitive2D: Encapsulates single paragraph
+ - TextHierarchyBlockPrimitive2D: encapsulates object texts (only one ATM)
+ Those are now supported in hierarchy. This means the MetaFile renderer will support them
+ by using them, recursively using their content and adding MetaFile comments as needed.
+ This also means that when another text layouter will be used it will be necessary to
+ create/support the same HierarchyPrimitives to support users.
+ To transport the information using this hierarchy is best suited to all future needs;
+ the slideshow will be able to profit from it directly when using primitives; all other
+ renderers not interested in the text structure will just ignore the encapsulations.
+
+ XTEXT_PAINTSHAPE_BEGIN, XTEXT_PAINTSHAPE_END
+ Supported now by the TextHierarchyBlockPrimitive2D.
+
+ EPSReplacementGraphic:
+ Only used in goodies\source\filter.vcl\ieps\ieps.cxx and svx\source\xml\xmlgrhlp.cxx to
+ hold the original EPS which was imported in the same MetaFile as first 2 entries. Only
+ used to export the original again (if exists).
+ Not necessary to support with MetaFuleRenderer.
+
+ XTEXT_SCROLLRECT, XTEXT_PAINTRECT
+ Currently used to get extra MetaFile infos using GraphicExporter which again uses
+ SdrTextObj::GetTextScrollMetaFileAndRectangle(). ATM works with primitives since
+ the rectangle data is added directly by the GraphicsExporter as comment. Does not need
+ to be adapted at once.
+ When adapting later, the only user - the diashow - should directly use the provided
+ Animation infos in the appropriate primitives (e.g. AnimatedSwitchPrimitive2D)
+
+ PRNSPOOL_TRANSPARENTBITMAP_BEGIN, PRNSPOOL_TRANSPARENTBITMAP_END
+ VCL usage when printing PL -> THB. Okay, THB confirms that it is only used as
+ a fix (hack) while VCL printing. It is needed to not downscale a bitmap which
+ was explicitly created for the printer already again to some default maximum
+ bitmap sizes.
+ Nothing to do here for the primitive renderer.
+
+ Support for vcl::PDFExtOutDevData:
+ PL knows that SJ did that stuff, it's used to hold a pointer to PDFExtOutDevData at
+ the OutDev. When set, some extra data is written there. Trying simple PDF export and
+ watching if I get those infos.
+ Well, a PDF export does not use e.g. ImpEditEngine::Paint since the PdfFilter uses
+ the SdXImpressDocument::render and thus uses the VclMetafileProcessor2D. I will check
+ if I get a PDFExtOutDevData at the target output device.
+ Indeed, I get one. Checking what all may be done when that extra-device-info is there.
+
+ All in all I have to talk to SJ. I will need to emulate some of those actions, but
+ i need to discuss which ones.
+ In the future, all those infos would be taken from the primitive sequence anyways,
+ thus these extensions would potentially be temporary, too.
+ Discussed with SJ, added the necessary support and tested it. Details follow.
+
+ - In ImpEditEngine::Paint, paragraph infos and URL stuff is added.
+ Added in primitive MetaFile renderer.
+ Checking URL: Indeed, current version exports it, but it is missing in primitive
+ CWS version. Adding support.
+ Okay, URLs work. Checked, Done.
+
+ - UnoControlPDFExportContact is only created when PDFExtOutDevData is used at the
+ target and uno control data is created in UnoControlPDFExportContact::do_PaintObject.
+ This may be added in primitive MetaFile renderer.
+ Adding support...
+ OOps, the necessary helper stuff is in svx/source/form/formpdxexport.cxx in namespace
+ svxform. Have to talk to FS if this has to be like that. Especially since
+ vcl::PDFWriter::AnyWidget is filled out, which is already part of vcl.
+ Wrote an eMail to FS, he is on vacation currently. I see no reason why not to move
+ that stuff to somewhere else, maybe tools or svtools ?!? We will see...
+ Moved to toolkit, so I have to link against it. I tried VCL first, but it did
+ not work since VCLUnoHelper::CreateFont is unresolved in VCL (!). Other than the name
+ may imply, it is defined in toolkit (!). Since toolkit is linked against VCL itself,
+ the lowest movement plane is toolkit.
+ Checked form control export, it works well. Done.
+
+ - In goodies, in GraphicObject::Draw, when the used Graphic is linked, infos are
+ generated. I will need to check what happens here with primitives.
+ To support, use of GraphicPrimitive2D (PRIMITIVE2D_ID_GRAPHICPRIMITIVE2D) may be needed.
+ Added support, but feature is broken in main version, so i cannot test at all.
+ Writing a bug to CL (or SJ) and seeing what happens (#i80380#).
+ SJ took a look and we got it working. Tested VCL MetaFile Renderer based export,
+ as intended, the original file is exported. Works, Done.
+
+
+ To be done:
+
+ - Maybe there are more places to take care of for vcl::PDFExtOutDevData!
+
+
+****************************************************************************************************/
+
+void VclMetafileProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate)
+{
+ switch (rCandidate.getPrimitive2DID())
+ {
+ case PRIMITIVE2D_ID_WRONGSPELLPRIMITIVE2D:
+ {
+ // directdraw of wrong spell primitive
+ // Ignore for VclMetafileProcessor2D, this is for printing and MetaFile recording only
+ break;
+ }
+ case PRIMITIVE2D_ID_GRAPHICPRIMITIVE2D:
+ {
+ processGraphicPrimitive2D(
+ static_cast<const primitive2d::GraphicPrimitive2D&>(rCandidate));
+ break;
+ }
+ case PRIMITIVE2D_ID_CONTROLPRIMITIVE2D:
+ {
+ processControlPrimitive2D(
+ static_cast<const primitive2d::ControlPrimitive2D&>(rCandidate));
+ break;
+ }
+ case PRIMITIVE2D_ID_TEXTHIERARCHYFIELDPRIMITIVE2D:
+ {
+ processTextHierarchyFieldPrimitive2D(
+ static_cast<const primitive2d::TextHierarchyFieldPrimitive2D&>(rCandidate));
+ break;
+ }
+ case PRIMITIVE2D_ID_TEXTHIERARCHYLINEPRIMITIVE2D:
+ {
+ processTextHierarchyLinePrimitive2D(
+ static_cast<const primitive2d::TextHierarchyLinePrimitive2D&>(rCandidate));
+ break;
+ }
+ case PRIMITIVE2D_ID_TEXTHIERARCHYBULLETPRIMITIVE2D:
+ {
+ processTextHierarchyBulletPrimitive2D(
+ static_cast<const primitive2d::TextHierarchyBulletPrimitive2D&>(rCandidate));
+ break;
+ }
+ case PRIMITIVE2D_ID_TEXTHIERARCHYPARAGRAPHPRIMITIVE2D:
+ {
+ processTextHierarchyParagraphPrimitive2D(
+ static_cast<const primitive2d::TextHierarchyParagraphPrimitive2D&>(rCandidate));
+ break;
+ }
+ case PRIMITIVE2D_ID_TEXTHIERARCHYBLOCKPRIMITIVE2D:
+ {
+ processTextHierarchyBlockPrimitive2D(
+ static_cast<const primitive2d::TextHierarchyBlockPrimitive2D&>(rCandidate));
+ break;
+ }
+ case PRIMITIVE2D_ID_TEXTSIMPLEPORTIONPRIMITIVE2D:
+ case PRIMITIVE2D_ID_TEXTDECORATEDPORTIONPRIMITIVE2D:
+ {
+ // for supporting TEXT_ MetaFile actions there is more to do here; get the candidate
+ processTextSimplePortionPrimitive2D(
+ static_cast<const primitive2d::TextSimplePortionPrimitive2D&>(rCandidate));
+ break;
+ }
+ case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D:
+ {
+ processPolygonHairlinePrimitive2D(
+ static_cast<const primitive2d::PolygonHairlinePrimitive2D&>(rCandidate));
+ break;
+ }
+ case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D:
+ {
+ processPolygonStrokePrimitive2D(
+ static_cast<const primitive2d::PolygonStrokePrimitive2D&>(rCandidate));
+ break;
+ }
+ case PRIMITIVE2D_ID_POLYGONSTROKEARROWPRIMITIVE2D:
+ {
+ processPolygonStrokeArrowPrimitive2D(
+ static_cast<const primitive2d::PolygonStrokeArrowPrimitive2D&>(rCandidate));
+ break;
+ }
+ case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D:
+ {
+ // direct draw of transformed BitmapEx primitive; use default processing, but without
+ // former testing if graphic content is inside discrete local viewport; this is not
+ // setup for metafile targets (metafile renderer tries to render in logic coordinates,
+ // the mapping is kept to the OutputDevice for better Metafile recording)
+ RenderBitmapPrimitive2D(static_cast<const primitive2d::BitmapPrimitive2D&>(rCandidate));
+ break;
+ }
+ case PRIMITIVE2D_ID_POLYPOLYGONGRAPHICPRIMITIVE2D:
+ {
+ processPolyPolygonGraphicPrimitive2D(
+ static_cast<const primitive2d::PolyPolygonGraphicPrimitive2D&>(rCandidate));
+ break;
+ }
+ case PRIMITIVE2D_ID_POLYPOLYGONHATCHPRIMITIVE2D:
+ {
+ processPolyPolygonHatchPrimitive2D(
+ static_cast<const primitive2d::PolyPolygonHatchPrimitive2D&>(rCandidate));
+ break;
+ }
+ case PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D:
+ {
+ processPolyPolygonGradientPrimitive2D(
+ static_cast<const primitive2d::PolyPolygonGradientPrimitive2D&>(rCandidate));
+ break;
+ }
+ case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D:
+ {
+ processPolyPolygonColorPrimitive2D(
+ static_cast<const primitive2d::PolyPolygonColorPrimitive2D&>(rCandidate));
+ break;
+ }
+ case PRIMITIVE2D_ID_MASKPRIMITIVE2D:
+ {
+ processMaskPrimitive2D(static_cast<const primitive2d::MaskPrimitive2D&>(rCandidate));
+ break;
+ }
+ case PRIMITIVE2D_ID_MODIFIEDCOLORPRIMITIVE2D:
+ {
+ // modified color group. Force output to unified color. Use default pocessing.
+ RenderModifiedColorPrimitive2D(
+ static_cast<const primitive2d::ModifiedColorPrimitive2D&>(rCandidate));
+ break;
+ }
+ case PRIMITIVE2D_ID_UNIFIEDTRANSPARENCEPRIMITIVE2D:
+ {
+ processUnifiedTransparencePrimitive2D(
+ static_cast<const primitive2d::UnifiedTransparencePrimitive2D&>(rCandidate));
+ break;
+ }
+ case PRIMITIVE2D_ID_TRANSPARENCEPRIMITIVE2D:
+ {
+ processTransparencePrimitive2D(
+ static_cast<const primitive2d::TransparencePrimitive2D&>(rCandidate));
+ break;
+ }
+ case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D:
+ {
+ // use default transform group pocessing
+ RenderTransformPrimitive2D(
+ static_cast<const primitive2d::TransformPrimitive2D&>(rCandidate));
+ break;
+ }
+ case PRIMITIVE2D_ID_PAGEPREVIEWPRIMITIVE2D:
+ {
+ // new XDrawPage for ViewInformation2D
+ RenderPagePreviewPrimitive2D(
+ static_cast<const primitive2d::PagePreviewPrimitive2D&>(rCandidate));
+ break;
+ }
+ case PRIMITIVE2D_ID_MARKERARRAYPRIMITIVE2D:
+ {
+ // use default marker array pocessing
+ RenderMarkerArrayPrimitive2D(
+ static_cast<const primitive2d::MarkerArrayPrimitive2D&>(rCandidate));
+ break;
+ }
+ case PRIMITIVE2D_ID_POINTARRAYPRIMITIVE2D:
+ {
+ // use default point array pocessing
+ RenderPointArrayPrimitive2D(
+ static_cast<const primitive2d::PointArrayPrimitive2D&>(rCandidate));
+ break;
+ }
+ case PRIMITIVE2D_ID_STRUCTURETAGPRIMITIVE2D:
+ {
+ processStructureTagPrimitive2D(
+ static_cast<const primitive2d::StructureTagPrimitive2D&>(rCandidate));
+ break;
+ }
+ case PRIMITIVE2D_ID_EPSPRIMITIVE2D:
+ {
+ RenderEpsPrimitive2D(static_cast<const primitive2d::EpsPrimitive2D&>(rCandidate));
+ break;
+ }
+ case PRIMITIVE2D_ID_OBJECTINFOPRIMITIVE2D:
+ {
+ RenderObjectInfoPrimitive2D(
+ static_cast<const primitive2d::ObjectInfoPrimitive2D&>(rCandidate));
+ break;
+ }
+ default:
+ {
+ // process recursively
+ process(rCandidate);
+ break;
+ }
+ }
+}
- // Create image alternative description from ObjectInfoPrimitive2D info
- // for PDF export
- if(mpPDFExtOutDevData->GetIsExportTaggedPDF() && nullptr != getObjectInfoPrimitive2D())
- {
- OUString aAlternateDescription;
+void VclMetafileProcessor2D::processGraphicPrimitive2D(
+ const primitive2d::GraphicPrimitive2D& rGraphicPrimitive)
+{
+ bool bUsingPDFExtOutDevData(false);
+ basegfx::B2DVector aTranslate, aScale;
+ static bool bSuppressPDFExtOutDevDataSupport(false); // loplugin:constvars:ignore
- if(!getObjectInfoPrimitive2D()->getTitle().isEmpty())
- {
- aAlternateDescription += getObjectInfoPrimitive2D()->getTitle();
- }
+ if (mpPDFExtOutDevData && !bSuppressPDFExtOutDevDataSupport)
+ {
+ // emulate data handling from UnoControlPDFExportContact, original see
+ // svtools/source/graphic/grfmgr.cxx
+ const Graphic& rGraphic = rGraphicPrimitive.getGraphicObject().GetGraphic();
- if(!getObjectInfoPrimitive2D()->getDesc().isEmpty())
- {
- if(!aAlternateDescription.isEmpty())
- {
- aAlternateDescription += " - ";
- }
+ if (rGraphic.IsGfxLink())
+ {
+ const GraphicAttr& rAttr = rGraphicPrimitive.getGraphicAttr();
- aAlternateDescription += getObjectInfoPrimitive2D()->getDesc();
- }
+ if (!rAttr.IsSpecialDrawMode() && !rAttr.IsAdjusted())
+ {
+ const basegfx::B2DHomMatrix& rTransform = rGraphicPrimitive.getTransform();
+ double fRotate, fShearX;
+ rTransform.decompose(aScale, aTranslate, fRotate, fShearX);
- // Use SetAlternateText to set it. This will work as long as some
- // structure is used (see PDFWriterImpl::setAlternateText and
- // m_nCurrentStructElement - tagged PDF export works with this in
- // Draw/Impress/Writer, but not in Calc due to too less structure...)
- //Z maybe add structure to Calc PDF export, may need some BeginGroup/EndGroup stuff ..?
- if(!aAlternateDescription.isEmpty())
+ if (basegfx::fTools::equalZero(fRotate) && (aScale.getX() > 0.0)
+ && (aScale.getY() > 0.0))
{
- mpPDFExtOutDevData->SetAlternateText(aAlternateDescription);
+ bUsingPDFExtOutDevData = true;
+ mpPDFExtOutDevData->BeginGroup();
}
}
-
- // #i123295# 3rd param is uncropped rect, 4th is cropped. The primitive has the cropped
- // object transformation, thus aCurrentRect *is* the clip region while aCropRect is the expanded,
- // uncropped region. Thus, correct order is aCropRect, aCurrentRect
- mpPDFExtOutDevData->EndGroup(
- rGraphicPrimitive.getGraphicObject().GetGraphic(),
- rAttr.GetTransparency(),
- aCropRect,
- aCurrentRect);
}
+ }
- void VclMetafileProcessor2D::processControlPrimitive2D(const primitive2d::ControlPrimitive2D& rControlPrimitive)
- {
- const uno::Reference< awt::XControl >& rXControl(rControlPrimitive.getXControl());
- bool bIsPrintableControl(false);
+ // process recursively and add MetaFile comment
+ process(rGraphicPrimitive);
+
+ if (!bUsingPDFExtOutDevData)
+ return;
+
+ // emulate data handling from UnoControlPDFExportContact, original see
+ // svtools/source/graphic/grfmgr.cxx
+ const basegfx::B2DRange aCurrentRange(aTranslate.getX(), aTranslate.getY(),
+ aTranslate.getX() + aScale.getX(),
+ aTranslate.getY() + aScale.getY());
+ const tools::Rectangle aCurrentRect(
+ sal_Int32(floor(aCurrentRange.getMinX())), sal_Int32(floor(aCurrentRange.getMinY())),
+ sal_Int32(ceil(aCurrentRange.getMaxX())), sal_Int32(ceil(aCurrentRange.getMaxY())));
+ const GraphicAttr& rAttr = rGraphicPrimitive.getGraphicAttr();
+ // fdo#72530 don't pass empty Rectangle to EndGroup
+ tools::Rectangle aCropRect(aCurrentRect);
+
+ if (rAttr.IsCropped())
+ {
+ // calculate scalings between real image size and logic object size. This
+ // is necessary since the crop values are relative to original bitmap size
+ double fFactorX(1.0);
+ double fFactorY(1.0);
- // find out if control is printable
- if(rXControl.is())
+ {
+ const MapMode aMapMode100thmm(MapUnit::Map100thMM);
+ const Size aBitmapSize(OutputDevice::LogicToLogic(
+ rGraphicPrimitive.getGraphicObject().GetPrefSize(),
+ rGraphicPrimitive.getGraphicObject().GetPrefMapMode(), aMapMode100thmm));
+ const double fDivX(aBitmapSize.Width() - rAttr.GetLeftCrop() - rAttr.GetRightCrop());
+ const double fDivY(aBitmapSize.Height() - rAttr.GetTopCrop() - rAttr.GetBottomCrop());
+
+ if (!basegfx::fTools::equalZero(fDivX))
{
- try
- {
- uno::Reference< beans::XPropertySet > xModelProperties(rXControl->getModel(), uno::UNO_QUERY);
- uno::Reference< beans::XPropertySetInfo > xPropertyInfo(xModelProperties.is()
- ? xModelProperties->getPropertySetInfo()
- : uno::Reference< beans::XPropertySetInfo >());
- const OUString sPrintablePropertyName("Printable");
-
- if(xPropertyInfo.is() && xPropertyInfo->hasPropertyByName(sPrintablePropertyName))
- {
- OSL_VERIFY(xModelProperties->getPropertyValue(sPrintablePropertyName) >>= bIsPrintableControl);
- }
- }
- catch(const uno::Exception&)
- {
- TOOLS_WARN_EXCEPTION("drawinglayer", "VclMetafileProcessor2D: No access to printable flag of Control");
- }
+ fFactorX = aScale.getX() / fDivX;
}
- // PDF export and printing only for printable controls
- if(!bIsPrintableControl)
- return;
+ if (!basegfx::fTools::equalZero(fDivY))
+ {
+ fFactorY = aScale.getY() / fDivY;
+ }
+ }
- const bool bPDFExport(mpPDFExtOutDevData && mpPDFExtOutDevData->GetIsExportFormFields());
- bool bDoProcessRecursively(true);
+ // calculate crop range and rect
+ basegfx::B2DRange aCropRange;
+ aCropRange.expand(
+ aCurrentRange.getMinimum()
+ - basegfx::B2DPoint(rAttr.GetLeftCrop() * fFactorX, rAttr.GetTopCrop() * fFactorY));
+ aCropRange.expand(
+ aCurrentRange.getMaximum()
+ + basegfx::B2DPoint(rAttr.GetRightCrop() * fFactorX, rAttr.GetBottomCrop() * fFactorY));
+
+ aCropRect = tools::Rectangle(
+ sal_Int32(floor(aCropRange.getMinX())), sal_Int32(floor(aCropRange.getMinY())),
+ sal_Int32(ceil(aCropRange.getMaxX())), sal_Int32(ceil(aCropRange.getMaxY())));
+ }
- if(bPDFExport)
- {
- // PDF export. Emulate data handling from UnoControlPDFExportContact
- // I have now moved describePDFControl to toolkit, thus i can implement the PDF
- // form control support now as follows
- std::unique_ptr< vcl::PDFWriter::AnyWidget > pPDFControl(
- ::toolkitform::describePDFControl( rXControl, *mpPDFExtOutDevData ) );
+ // Create image alternative description from ObjectInfoPrimitive2D info
+ // for PDF export
+ if (mpPDFExtOutDevData->GetIsExportTaggedPDF() && nullptr != getObjectInfoPrimitive2D())
+ {
+ OUString aAlternateDescription;
- if (pPDFControl)
- {
- // still need to fill in the location (is a class Rectangle)
- const basegfx::B2DRange aRangeLogic(rControlPrimitive.getB2DRange(getViewInformation2D()));
- const ::tools::Rectangle aRectLogic(
- static_cast<sal_Int32>(floor(aRangeLogic.getMinX())), static_cast<sal_Int32>(floor(aRangeLogic.getMinY())),
- static_cast<sal_Int32>(ceil(aRangeLogic.getMaxX())), static_cast<sal_Int32>(ceil(aRangeLogic.getMaxY())));
- pPDFControl->Location = aRectLogic;
-
- Size aFontSize(pPDFControl->TextFont.GetFontSize());
- aFontSize = OutputDevice::LogicToLogic(aFontSize, MapMode(MapUnit::MapPoint), mpOutputDevice->GetMapMode());
- pPDFControl->TextFont.SetFontSize(aFontSize);
-
- mpPDFExtOutDevData->BeginStructureElement(vcl::PDFWriter::Form);
- mpPDFExtOutDevData->CreateControl(*pPDFControl);
- mpPDFExtOutDevData->EndStructureElement();
-
- // no normal paint needed (see original UnoControlPDFExportContact::do_PaintObject);
- // do not process recursively
- bDoProcessRecursively = false;
- }
- else
- {
- // PDF export did not work, try simple output.
- // Fallback to printer output by not setting bDoProcessRecursively
- // to false.
- }
- }
+ if (!getObjectInfoPrimitive2D()->getTitle().isEmpty())
+ {
+ aAlternateDescription += getObjectInfoPrimitive2D()->getTitle();
+ }
- // #i93169# used flag the wrong way; true means that nothing was done yet
- if(bDoProcessRecursively)
+ if (!getObjectInfoPrimitive2D()->getDesc().isEmpty())
+ {
+ if (!aAlternateDescription.isEmpty())
{
- // printer output
- try
- {
- // remember old graphics and create new
- uno::Reference< awt::XView > xControlView(rXControl, uno::UNO_QUERY_THROW);
- const uno::Reference< awt::XGraphics > xOriginalGraphics(xControlView->getGraphics());
- const uno::Reference< awt::XGraphics > xNewGraphics(mpOutputDevice->CreateUnoGraphics());
-
- if(xNewGraphics.is())
- {
- // link graphics and view
- xControlView->setGraphics(xNewGraphics);
-
- // get position
- const basegfx::B2DHomMatrix aObjectToDiscrete(getViewInformation2D().getObjectToViewTransformation() * rControlPrimitive.getTransform());
- const basegfx::B2DPoint aTopLeftDiscrete(aObjectToDiscrete * basegfx::B2DPoint(0.0, 0.0));
-
- // draw it
- xControlView->draw(basegfx::fround(aTopLeftDiscrete.getX()), basegfx::fround(aTopLeftDiscrete.getY()));
- bDoProcessRecursively = false;
-
- // restore original graphics
- xControlView->setGraphics(xOriginalGraphics);
- }
- }
- catch( const uno::Exception& )
- {
- TOOLS_WARN_EXCEPTION("drawinglayer", "VclMetafileProcessor2D: Printing of Control failed");
- }
+ aAlternateDescription += " - ";
}
- // process recursively if not done yet to export as decomposition (bitmap)
- if(bDoProcessRecursively)
- {
- process(rControlPrimitive);
- }
+ aAlternateDescription += getObjectInfoPrimitive2D()->getDesc();
}
- void VclMetafileProcessor2D::processTextHierarchyFieldPrimitive2D(const primitive2d::TextHierarchyFieldPrimitive2D& rFieldPrimitive)
+ // Use SetAlternateText to set it. This will work as long as some
+ // structure is used (see PDFWriterImpl::setAlternateText and
+ // m_nCurrentStructElement - tagged PDF export works with this in
+ // Draw/Impress/Writer, but not in Calc due to too less structure...)
+ //Z maybe add structure to Calc PDF export, may need some BeginGroup/EndGroup stuff ..?
+ if (!aAlternateDescription.isEmpty())
{
- // support for FIELD_SEQ_BEGIN, FIELD_SEQ_END and URL. It wraps text primitives (but is not limited to)
- // thus do the MetafileAction embedding stuff but just handle recursively.
- const OString aCommentStringCommon("FIELD_SEQ_BEGIN");
- const OString aCommentStringPage("FIELD_SEQ_BEGIN;PageField");
- const OString aCommentStringEnd("FIELD_SEQ_END");
- OUString aURL;
+ mpPDFExtOutDevData->SetAlternateText(aAlternateDescription);
+ }
+ }
- switch(rFieldPrimitive.getType())
- {
- default : // case drawinglayer::primitive2d::FIELD_TYPE_COMMON :
- {
- mpMetaFile->AddAction(new MetaCommentAction(aCommentStringCommon));
- break;
- }
- case drawinglayer::primitive2d::FIELD_TYPE_PAGE :
- {
- mpMetaFile->AddAction(new MetaCommentAction(aCommentStringPage));
- break;
- }
- case drawinglayer::primitive2d::FIELD_TYPE_URL :
- {
- aURL = rFieldPrimitive.getValue("URL");
+ // #i123295# 3rd param is uncropped rect, 4th is cropped. The primitive has the cropped
+ // object transformation, thus aCurrentRect *is* the clip region while aCropRect is the expanded,
+ // uncropped region. Thus, correct order is aCropRect, aCurrentRect
+ mpPDFExtOutDevData->EndGroup(rGraphicPrimitive.getGraphicObject().GetGraphic(),
+ rAttr.GetTransparency(), aCropRect, aCurrentRect);
+}
- if (!aURL.isEmpty())
- {
- mpMetaFile->AddAction(new MetaCommentAction(aCommentStringCommon, 0, reinterpret_cast<const sal_uInt8*>(aURL.getStr()), 2 * aURL.getLength()));
- }
+void VclMetafileProcessor2D::processControlPrimitive2D(
+ const primitive2d::ControlPrimitive2D& rControlPrimitive)
+{
+ const uno::Reference<awt::XControl>& rXControl(rControlPrimitive.getXControl());
+ bool bIsPrintableControl(false);
- break;
- }
+ // find out if control is printable
+ if (rXControl.is())
+ {
+ try
+ {
+ uno::Reference<beans::XPropertySet> xModelProperties(rXControl->getModel(),
+ uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySetInfo> xPropertyInfo(
+ xModelProperties.is() ? xModelProperties->getPropertySetInfo()
+ : uno::Reference<beans::XPropertySetInfo>());
+ const OUString sPrintablePropertyName("Printable");
+
+ if (xPropertyInfo.is() && xPropertyInfo->hasPropertyByName(sPrintablePropertyName))
+ {
+ OSL_VERIFY(xModelProperties->getPropertyValue(sPrintablePropertyName)
+ >>= bIsPrintableControl);
}
+ }
+ catch (const uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("drawinglayer",
+ "VclMetafileProcessor2D: No access to printable flag of Control");
+ }
+ }
- // process recursively
- primitive2d::Primitive2DContainer rContent;
- rFieldPrimitive.get2DDecomposition(rContent, getViewInformation2D());
- process(rContent);
+ // PDF export and printing only for printable controls
+ if (!bIsPrintableControl)
+ return;
- // for the end comment the type is not relevant yet, they are all the same. Just add.
- mpMetaFile->AddAction(new MetaCommentAction(aCommentStringEnd));
+ const bool bPDFExport(mpPDFExtOutDevData && mpPDFExtOutDevData->GetIsExportFormFields());
+ bool bDoProcessRecursively(true);
- if(!(mpPDFExtOutDevData && drawinglayer::primitive2d::FIELD_TYPE_URL == rFieldPrimitive.getType()))
- return;
+ if (bPDFExport)
+ {
+ // PDF export. Emulate data handling from UnoControlPDFExportContact
+ // I have now moved describePDFControl to toolkit, thus i can implement the PDF
+ // form control support now as follows
+ std::unique_ptr<vcl::PDFWriter::AnyWidget> pPDFControl(
+ ::toolkitform::describePDFControl(rXControl, *mpPDFExtOutDevData));
- // emulate data handling from ImpEditEngine::Paint
- const basegfx::B2DRange aViewRange(rContent.getB2DRange(getViewInformation2D()));
- const ::tools::Rectangle aRectLogic(
- static_cast<sal_Int32>(floor(aViewRange.getMinX())), static_cast<sal_Int32>(floor(aViewRange.getMinY())),
- static_cast<sal_Int32>(ceil(aViewRange.getMaxX())), static_cast<sal_Int32>(ceil(aViewRange.getMaxY())));
- vcl::PDFExtOutDevBookmarkEntry aBookmark;
- aBookmark.nLinkId = mpPDFExtOutDevData->CreateLink(aRectLogic);
- aBookmark.aBookmark = aURL;
- std::vector< vcl::PDFExtOutDevBookmarkEntry >& rBookmarks = mpPDFExtOutDevData->GetBookmarks();
- rBookmarks.push_back( aBookmark );
+ if (pPDFControl)
+ {
+ // still need to fill in the location (is a class Rectangle)
+ const basegfx::B2DRange aRangeLogic(
+ rControlPrimitive.getB2DRange(getViewInformation2D()));
+ const tools::Rectangle aRectLogic(static_cast<sal_Int32>(floor(aRangeLogic.getMinX())),
+ static_cast<sal_Int32>(floor(aRangeLogic.getMinY())),
+ static_cast<sal_Int32>(ceil(aRangeLogic.getMaxX())),
+ static_cast<sal_Int32>(ceil(aRangeLogic.getMaxY())));
+ pPDFControl->Location = aRectLogic;
+
+ Size aFontSize(pPDFControl->TextFont.GetFontSize());
+ aFontSize = OutputDevice::LogicToLogic(aFontSize, MapMode(MapUnit::MapPoint),
+ mpOutputDevice->GetMapMode());
+ pPDFControl->TextFont.SetFontSize(aFontSize);
+
+ mpPDFExtOutDevData->BeginStructureElement(vcl::PDFWriter::Form);
+ mpPDFExtOutDevData->CreateControl(*pPDFControl);
+ mpPDFExtOutDevData->EndStructureElement();
+
+ // no normal paint needed (see original UnoControlPDFExportContact::do_PaintObject);
+ // do not process recursively
+ bDoProcessRecursively = false;
}
-
- void VclMetafileProcessor2D::processTextHierarchyLinePrimitive2D(const primitive2d::TextHierarchyLinePrimitive2D& rLinePrimitive)
+ else
{
- const OString aCommentString("XTEXT_EOL");
-
- // process recursively and add MetaFile comment
- process(rLinePrimitive);
- mpMetaFile->AddAction(new MetaCommentAction(aCommentString));
+ // PDF export did not work, try simple output.
+ // Fallback to printer output by not setting bDoProcessRecursively
+ // to false.
}
+ }
- void VclMetafileProcessor2D::processTextHierarchyBulletPrimitive2D(const primitive2d::TextHierarchyBulletPrimitive2D& rBulletPrimitive)
+ // #i93169# used flag the wrong way; true means that nothing was done yet
+ if (bDoProcessRecursively)
+ {
+ // printer output
+ try
{
- // in Outliner::PaintBullet(), a MetafileComment for bullets is added, too. The
- // "XTEXT_EOC" is used, use here, too.
- const OString aCommentString("XTEXT_EOC");
+ // remember old graphics and create new
+ uno::Reference<awt::XView> xControlView(rXControl, uno::UNO_QUERY_THROW);
+ const uno::Reference<awt::XGraphics> xOriginalGraphics(xControlView->getGraphics());
+ const uno::Reference<awt::XGraphics> xNewGraphics(mpOutputDevice->CreateUnoGraphics());
- // this is a part of list item, start LILabel ( = bullet)
- if(mbInListItem)
+ if (xNewGraphics.is())
{
- maListElements.push(vcl::PDFWriter::LILabel);
- mpPDFExtOutDevData->BeginStructureElement(vcl::PDFWriter::LILabel);
+ // link graphics and view
+ xControlView->setGraphics(xNewGraphics);
+
+ // get position
+ const basegfx::B2DHomMatrix aObjectToDiscrete(
+ getViewInformation2D().getObjectToViewTransformation()
+ * rControlPrimitive.getTransform());
+ const basegfx::B2DPoint aTopLeftDiscrete(aObjectToDiscrete
+ * basegfx::B2DPoint(0.0, 0.0));
+
+ // draw it
+ xControlView->draw(basegfx::fround(aTopLeftDiscrete.getX()),
+ basegfx::fround(aTopLeftDiscrete.getY()));
+ bDoProcessRecursively = false;
+
+ // restore original graphics
+ xControlView->setGraphics(xOriginalGraphics);
}
+ }
+ catch (const uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("drawinglayer",
+ "VclMetafileProcessor2D: Printing of Control failed");
+ }
+ }
- // process recursively and add MetaFile comment
- process(rBulletPrimitive);
- mpMetaFile->AddAction(new MetaCommentAction(aCommentString));
+ // process recursively if not done yet to export as decomposition (bitmap)
+ if (bDoProcessRecursively)
+ {
+ process(rControlPrimitive);
+ }
+}
- if(mbInListItem)
- {
- if (maListElements.top() == vcl::PDFWriter::LILabel)
- {
- maListElements.pop();
- mpPDFExtOutDevData->EndStructureElement(); // end LILabel
- mbBulletPresent = true;
- }
- }
+void VclMetafileProcessor2D::processTextHierarchyFieldPrimitive2D(
+ const primitive2d::TextHierarchyFieldPrimitive2D& rFieldPrimitive)
+{
+ // support for FIELD_SEQ_BEGIN, FIELD_SEQ_END and URL. It wraps text primitives (but is not limited to)
+ // thus do the MetafileAction embedding stuff but just handle recursively.
+ const OString aCommentStringCommon("FIELD_SEQ_BEGIN");
+ const OString aCommentStringPage("FIELD_SEQ_BEGIN;PageField");
+ const OString aCommentStringEnd("FIELD_SEQ_END");
+ OUString aURL;
+
+ switch (rFieldPrimitive.getType())
+ {
+ default: // case drawinglayer::primitive2d::FIELD_TYPE_COMMON :
+ {
+ mpMetaFile->AddAction(new MetaCommentAction(aCommentStringCommon));
+ break;
}
-
- void VclMetafileProcessor2D::processTextHierarchyParagraphPrimitive2D(const primitive2d::TextHierarchyParagraphPrimitive2D& rParagraphPrimitive)
+ case drawinglayer::primitive2d::FIELD_TYPE_PAGE:
+ {
+ mpMetaFile->AddAction(new MetaCommentAction(aCommentStringPage));
+ break;
+ }
+ case drawinglayer::primitive2d::FIELD_TYPE_URL:
{
- const OString aCommentString("XTEXT_EOP");
- static bool bSuppressPDFExtOutDevDataSupport(false); // loplugin:constvars:ignore
+ aURL = rFieldPrimitive.getValue("URL");
- if(nullptr == mpPDFExtOutDevData || bSuppressPDFExtOutDevDataSupport)
+ if (!aURL.isEmpty())
{
- // Non-PDF export behaviour (metafile only).
- // Process recursively and add MetaFile comment.
- process(rParagraphPrimitive);
- mpMetaFile->AddAction(new MetaCommentAction(aCommentString));
- return;
+ mpMetaFile->AddAction(new MetaCommentAction(
+ aCommentStringCommon, 0, reinterpret_cast<const sal_uInt8*>(aURL.getStr()),
+ 2 * aURL.getLength()));
}
- if(!mpPDFExtOutDevData->GetIsExportTaggedPDF())
- {
- // No Tagged PDF -> Dump as Paragraph
- // Emulate data handling from old ImpEditEngine::Paint
- mpPDFExtOutDevData->BeginStructureElement( vcl::PDFWriter::Paragraph );
+ break;
+ }
+ }
- // Process recursively and add MetaFile comment
- process(rParagraphPrimitive);
- mpMetaFile->AddAction(new MetaCommentAction(aCommentString));
+ // process recursively
+ primitive2d::Primitive2DContainer rContent;
+ rFieldPrimitive.get2DDecomposition(rContent, getViewInformation2D());
+ process(rContent);
+
+ // for the end comment the type is not relevant yet, they are all the same. Just add.
+ mpMetaFile->AddAction(new MetaCommentAction(aCommentStringEnd));
+
+ if (!(mpPDFExtOutDevData
+ && drawinglayer::primitive2d::FIELD_TYPE_URL == rFieldPrimitive.getType()))
+ return;
+
+ // emulate data handling from ImpEditEngine::Paint
+ const basegfx::B2DRange aViewRange(rContent.getB2DRange(getViewInformation2D()));
+ const tools::Rectangle aRectLogic(static_cast<sal_Int32>(floor(aViewRange.getMinX())),
+ static_cast<sal_Int32>(floor(aViewRange.getMinY())),
+ static_cast<sal_Int32>(ceil(aViewRange.getMaxX())),
+ static_cast<sal_Int32>(ceil(aViewRange.getMaxY())));
+ vcl::PDFExtOutDevBookmarkEntry aBookmark;
+ aBookmark.nLinkId = mpPDFExtOutDevData->CreateLink(aRectLogic);
+ aBookmark.aBookmark = aURL;
+ std::vector<vcl::PDFExtOutDevBookmarkEntry>& rBookmarks = mpPDFExtOutDevData->GetBookmarks();
+ rBookmarks.push_back(aBookmark);
+}
+
+void VclMetafileProcessor2D::processTextHierarchyLinePrimitive2D(
+ const primitive2d::TextHierarchyLinePrimitive2D& rLinePrimitive)
+{
+ const OString aCommentString("XTEXT_EOL");
- // Emulate data handling from ImpEditEngine::Paint
- mpPDFExtOutDevData->EndStructureElement();
- return;
- }
+ // process recursively and add MetaFile comment
+ process(rLinePrimitive);
+ mpMetaFile->AddAction(new MetaCommentAction(aCommentString));
+}
- // Create Tagged PDF -> deeper tagged data using StructureElements.
- // Use OutlineLevel from ParagraphPrimitive, ensure not below -1 what
- // means 'not active'
- const sal_Int16 nNewOutlineLevel(std::max(static_cast<sal_Int16>(-1), rParagraphPrimitive.getOutlineLevel()));
+void VclMetafileProcessor2D::processTextHierarchyBulletPrimitive2D(
+ const primitive2d::TextHierarchyBulletPrimitive2D& rBulletPrimitive)
+{
+ // in Outliner::PaintBullet(), a MetafileComment for bullets is added, too. The
+ // "XTEXT_EOC" is used, use here, too.
+ const OString aCommentString("XTEXT_EOC");
- // Do we have a change in OutlineLevel compared to the current one?
- if(nNewOutlineLevel != mnCurrentOutlineLevel)
- {
- if(nNewOutlineLevel > mnCurrentOutlineLevel)
- {
- // increase List level
- for(sal_Int16 a(mnCurrentOutlineLevel); a != nNewOutlineLevel; ++a)
- {
- maListElements.push(vcl::PDFWriter::List);
- mpPDFExtOutDevData->BeginStructureElement( vcl::PDFWriter::List );
- }
- }
- else // if(nNewOutlineLevel < mnCurrentOutlineLevel)
- {
- // close list levels below nNewOutlineLevel completely by removing
- // list items as well as list tag itself
- for(sal_Int16 a(nNewOutlineLevel); a < mnCurrentOutlineLevel; ++a)
- {
- popList(); // end LBody LI and L
- }
+ // this is a part of list item, start LILabel ( = bullet)
+ if (mbInListItem)
+ {
+ maListElements.push(vcl::PDFWriter::LILabel);
+ mpPDFExtOutDevData->BeginStructureElement(vcl::PDFWriter::LILabel);
+ }
- // on nNewOutlineLevel close the previous list item (LBody and LI)
- popListItem();
+ // process recursively and add MetaFile comment
+ process(rBulletPrimitive);
+ mpMetaFile->AddAction(new MetaCommentAction(aCommentString));
- }
+ if (mbInListItem)
+ {
+ if (maListElements.top() == vcl::PDFWriter::LILabel)
+ {
+ maListElements.pop();
+ mpPDFExtOutDevData->EndStructureElement(); // end LILabel
+ mbBulletPresent = true;
+ }
+ }
+}
- // Remember new current OutlineLevel
- mnCurrentOutlineLevel = nNewOutlineLevel;
- }
- else // the same list level
- {
- // close the previous list item (LBody and LI)
- popListItem();
- }
+void VclMetafileProcessor2D::processTextHierarchyParagraphPrimitive2D(
+ const primitive2d::TextHierarchyParagraphPrimitive2D& rParagraphPrimitive)
+{
+ const OString aCommentString("XTEXT_EOP");
+ static bool bSuppressPDFExtOutDevDataSupport(false); // loplugin:constvars:ignore
+
+ if (nullptr == mpPDFExtOutDevData || bSuppressPDFExtOutDevDataSupport)
+ {
+ // Non-PDF export behaviour (metafile only).
+ // Process recursively and add MetaFile comment.
+ process(rParagraphPrimitive);
+ mpMetaFile->AddAction(new MetaCommentAction(aCommentString));
+ return;
+ }
+
+ if (!mpPDFExtOutDevData->GetIsExportTaggedPDF())
+ {
+ // No Tagged PDF -> Dump as Paragraph
+ // Emulate data handling from old ImpEditEngine::Paint
+ mpPDFExtOutDevData->BeginStructureElement(vcl::PDFWriter::Paragraph);
+
+ // Process recursively and add MetaFile comment
+ process(rParagraphPrimitive);
+ mpMetaFile->AddAction(new MetaCommentAction(aCommentString));
+
+ // Emulate data handling from ImpEditEngine::Paint
+ mpPDFExtOutDevData->EndStructureElement();
+ return;
+ }
- const bool bDumpAsListItem(-1 != mnCurrentOutlineLevel);
+ // Create Tagged PDF -> deeper tagged data using StructureElements.
+ // Use OutlineLevel from ParagraphPrimitive, ensure not below -1 what
+ // means 'not active'
+ const sal_Int16 nNewOutlineLevel(
+ std::max(static_cast<sal_Int16>(-1), rParagraphPrimitive.getOutlineLevel()));
- if(bDumpAsListItem)
+ // Do we have a change in OutlineLevel compared to the current one?
+ if (nNewOutlineLevel != mnCurrentOutlineLevel)
+ {
+ if (nNewOutlineLevel > mnCurrentOutlineLevel)
+ {
+ // increase List level
+ for (sal_Int16 a(mnCurrentOutlineLevel); a != nNewOutlineLevel; ++a)
{
- // Dump as ListItem
- maListElements.push(vcl::PDFWriter::ListItem);
- mpPDFExtOutDevData->BeginStructureElement( vcl::PDFWriter::ListItem );
- mbInListItem = true;
+ maListElements.push(vcl::PDFWriter::List);
+ mpPDFExtOutDevData->BeginStructureElement(vcl::PDFWriter::List);
}
- else
+ }
+ else // if(nNewOutlineLevel < mnCurrentOutlineLevel)
+ {
+ // close list levels below nNewOutlineLevel completely by removing
+ // list items as well as list tag itself
+ for (sal_Int16 a(nNewOutlineLevel); a < mnCurrentOutlineLevel; ++a)
{
- // Dump as Paragraph
- mpPDFExtOutDevData->BeginStructureElement( vcl::PDFWriter::Paragraph );
+ popList(); // end LBody LI and L
}
- // Process recursively and add MetaFile comment
- process(rParagraphPrimitive);
- mpMetaFile->AddAction(new MetaCommentAction(aCommentString));
-
- if(bDumpAsListItem)
- mbInListItem = false;
- else
- mpPDFExtOutDevData->EndStructureElement(); // end Paragraph
+ // on nNewOutlineLevel close the previous list item (LBody and LI)
+ popListItem();
}
- void VclMetafileProcessor2D::processTextHierarchyBlockPrimitive2D(const primitive2d::TextHierarchyBlockPrimitive2D& rBlockPrimitive)
- {
- const OString aCommentStringA("XTEXT_PAINTSHAPE_BEGIN");
- const OString aCommentStringB("XTEXT_PAINTSHAPE_END");
+ // Remember new current OutlineLevel
+ mnCurrentOutlineLevel = nNewOutlineLevel;
+ }
+ else // the same list level
+ {
+ // close the previous list item (LBody and LI)
+ popListItem();
+ }
- // add MetaFile comment, process recursively and add MetaFile comment
- mpMetaFile->AddAction(new MetaCommentAction(aCommentStringA));
- process(rBlockPrimitive);
+ const bool bDumpAsListItem(-1 != mnCurrentOutlineLevel);
- if (mnCurrentOutlineLevel >= 0 )
- {
- // end any opened List structure elements (LBody, LI, L)
- for(sal_Int16 a(0); a <= mnCurrentOutlineLevel; ++a)
- {
- popList();
- }
- }
+ if (bDumpAsListItem)
+ {
+ // Dump as ListItem
+ maListElements.push(vcl::PDFWriter::ListItem);
+ mpPDFExtOutDevData->BeginStructureElement(vcl::PDFWriter::ListItem);
+ mbInListItem = true;
+ }
+ else
+ {
+ // Dump as Paragraph
+ mpPDFExtOutDevData->BeginStructureElement(vcl::PDFWriter::Paragraph);
+ }
- mpMetaFile->AddAction(new MetaCommentAction(aCommentStringB));
- }
+ // Process recursively and add MetaFile comment
+ process(rParagraphPrimitive);
+ mpMetaFile->AddAction(new MetaCommentAction(aCommentString));
+
+ if (bDumpAsListItem)
+ mbInListItem = false;
+ else
+ mpPDFExtOutDevData->EndStructureElement(); // end Paragraph
+}
+
+void VclMetafileProcessor2D::processTextHierarchyBlockPrimitive2D(
+ const primitive2d::TextHierarchyBlockPrimitive2D& rBlockPrimitive)
+{
+ const OString aCommentStringA("XTEXT_PAINTSHAPE_BEGIN");
+ const OString aCommentStringB("XTEXT_PAINTSHAPE_END");
- void VclMetafileProcessor2D::processTextSimplePortionPrimitive2D(const primitive2d::TextSimplePortionPrimitive2D& rTextCandidate)
+ // add MetaFile comment, process recursively and add MetaFile comment
+ mpMetaFile->AddAction(new MetaCommentAction(aCommentStringA));
+ process(rBlockPrimitive);
+
+ if (mnCurrentOutlineLevel >= 0)
+ {
+ // end any opened List structure elements (LBody, LI, L)
+ for (sal_Int16 a(0); a <= mnCurrentOutlineLevel; ++a)
{
- // Adapt evtl. used special DrawMode
- const DrawModeFlags nOriginalDrawMode(mpOutputDevice->GetDrawMode());
- adaptTextToFillDrawMode();
+ popList();
+ }
+ }
- // this is a 2nd portion of list item
- // bullet has been already processed, start LIBody
- if (mbInListItem && mbBulletPresent)
- {
- maListElements.push(vcl::PDFWriter::LIBody);
- mpPDFExtOutDevData->BeginStructureElement(vcl::PDFWriter::LIBody);
- }
+ mpMetaFile->AddAction(new MetaCommentAction(aCommentStringB));
+}
- // directdraw of text simple portion; use default processing
- RenderTextSimpleOrDecoratedPortionPrimitive2D(rTextCandidate);
+void VclMetafileProcessor2D::processTextSimplePortionPrimitive2D(
+ const primitive2d::TextSimplePortionPrimitive2D& rTextCandidate)
+{
+ // Adapt evtl. used special DrawMode
+ const DrawModeFlags nOriginalDrawMode(mpOutputDevice->GetDrawMode());
+ adaptTextToFillDrawMode();
- if (mbInListItem && mbBulletPresent)
- mbBulletPresent = false;
+ // this is a 2nd portion of list item
+ // bullet has been already processed, start LIBody
+ if (mbInListItem && mbBulletPresent)
+ {
+ maListElements.push(vcl::PDFWriter::LIBody);
+ mpPDFExtOutDevData->BeginStructureElement(vcl::PDFWriter::LIBody);
+ }
- // restore DrawMode
- mpOutputDevice->SetDrawMode(nOriginalDrawMode);
+ // directdraw of text simple portion; use default processing
+ RenderTextSimpleOrDecoratedPortionPrimitive2D(rTextCandidate);
- // #i101169# if(pTextDecoratedCandidate)
- {
- // support for TEXT_ MetaFile actions only for decorated texts
- if(!mxBreakIterator.is())
- {
- uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
- mxBreakIterator = i18n::BreakIterator::create(xContext);
- }
+ if (mbInListItem && mbBulletPresent)
+ mbBulletPresent = false;
- const OUString& rTxt = rTextCandidate.getText();
- const sal_Int32 nTextLength(rTextCandidate.getTextLength()); // rTxt.getLength());
+ // restore DrawMode
+ mpOutputDevice->SetDrawMode(nOriginalDrawMode);
- if(nTextLength)
- {
- const css::lang::Locale& rLocale = rTextCandidate.getLocale();
- const sal_Int32 nTextPosition(rTextCandidate.getTextPosition());
-
- sal_Int32 nDone;
- sal_Int32 nNextCellBreak(mxBreakIterator->nextCharacters(rTxt, nTextPosition, rLocale, css::i18n::CharacterIteratorMode::SKIPCELL, 0, nDone));
- css::i18n::Boundary nNextWordBoundary(mxBreakIterator->getWordBoundary(rTxt, nTextPosition, rLocale, css::i18n::WordType::ANY_WORD, true));
- sal_Int32 nNextSentenceBreak(mxBreakIterator->endOfSentence(rTxt, nTextPosition, rLocale));
- const OString aCommentStringA("XTEXT_EOC");
- const OString aCommentStringB("XTEXT_EOW");
- const OString aCommentStringC("XTEXT_EOS");
-
- for(sal_Int32 i(nTextPosition); i < nTextPosition + nTextLength; i++)
- {
- // create the entries for the respective break positions
- if(i == nNextCellBreak)
- {
- mpMetaFile->AddAction(new MetaCommentAction(aCommentStringA, i - nTextPosition));
- nNextCellBreak = mxBreakIterator->nextCharacters(rTxt, i, rLocale, css::i18n::CharacterIteratorMode::SKIPCELL, 1, nDone);
- }
- if(i == nNextWordBoundary.endPos)
- {
- mpMetaFile->AddAction(new MetaCommentAction(aCommentStringB, i - nTextPosition));
- nNextWordBoundary = mxBreakIterator->getWordBoundary(rTxt, i + 1, rLocale, css::i18n::WordType::ANY_WORD, true);
- }
- if(i == nNextSentenceBreak)
- {
- mpMetaFile->AddAction(new MetaCommentAction(aCommentStringC, i - nTextPosition));
- nNextSentenceBreak = mxBreakIterator->endOfSentence(rTxt, i + 1, rLocale);
- }
- }
- }
- }
+ // #i101169# if(pTextDecoratedCandidate)
+ {
+ // support for TEXT_ MetaFile actions only for decorated texts
+ if (!mxBreakIterator.is())
+ {
+ uno::Reference<uno::XComponentContext> xContext(
+ ::comphelper::getProcessComponentContext());
+ mxBreakIterator = i18n::BreakIterator::create(xContext);
}
- void VclMetafileProcessor2D::processPolygonHairlinePrimitive2D(const primitive2d::PolygonHairlinePrimitive2D& rHairlinePrimitive)
- {
- const basegfx::B2DPolygon& rBasePolygon = rHairlinePrimitive.getB2DPolygon();
+ const OUString& rTxt = rTextCandidate.getText();
+ const sal_Int32 nTextLength(rTextCandidate.getTextLength()); // rTxt.getLength());
- if(rBasePolygon.count() > (MAX_POLYGON_POINT_COUNT_METAFILE - 1))
- {
- // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
- // per polygon. If there are more, split the polygon in half and call recursively
- basegfx::B2DPolygon aLeft, aRight;
- splitLinePolygon(rBasePolygon, aLeft, aRight);
- rtl::Reference< primitive2d::PolygonHairlinePrimitive2D > xPLeft(new primitive2d::PolygonHairlinePrimitive2D(aLeft, rHairlinePrimitive.getBColor()));
- rtl::Reference< primitive2d::PolygonHairlinePrimitive2D > xPRight(new primitive2d::PolygonHairlinePrimitive2D(aRight, rHairlinePrimitive.getBColor()));
-
- processBasePrimitive2D(*xPLeft);
- processBasePrimitive2D(*xPRight);
- }
- else
+ if (nTextLength)
+ {
+ const css::lang::Locale& rLocale = rTextCandidate.getLocale();
+ const sal_Int32 nTextPosition(rTextCandidate.getTextPosition());
+
+ sal_Int32 nDone;
+ sal_Int32 nNextCellBreak(mxBreakIterator->nextCharacters(
+ rTxt, nTextPosition, rLocale, css::i18n::CharacterIteratorMode::SKIPCELL, 0,
+ nDone));
+ css::i18n::Boundary nNextWordBoundary(mxBreakIterator->getWordBoundary(
+ rTxt, nTextPosition, rLocale, css::i18n::WordType::ANY_WORD, true));
+ sal_Int32 nNextSentenceBreak(
+ mxBreakIterator->endOfSentence(rTxt, nTextPosition, rLocale));
+ const OString aCommentStringA("XTEXT_EOC");
+ const OString aCommentStringB("XTEXT_EOW");
+ const OString aCommentStringC("XTEXT_EOS");
+
+ for (sal_Int32 i(nTextPosition); i < nTextPosition + nTextLength; i++)
{
- // direct draw of hairline; use default processing
- // support SvtGraphicStroke MetaCommentAction
- const basegfx::BColor aLineColor(maBColorModifierStack.getModifiedColor(rHairlinePrimitive.getBColor()));
- std::unique_ptr<SvtGraphicStroke> pSvtGraphicStroke;
-
- // #i121267# Not needed, does not give better quality compared with
- // the MetaActionType::POLYPOLYGON written by RenderPolygonHairlinePrimitive2D
- // below
- const bool bSupportSvtGraphicStroke(false);
-
- if(bSupportSvtGraphicStroke)
+ // create the entries for the respective break positions
+ if (i == nNextCellBreak)
{
- pSvtGraphicStroke = impTryToCreateSvtGraphicStroke(
- rHairlinePrimitive.getB2DPolygon(),
- &aLineColor,
- nullptr, nullptr, nullptr, nullptr);
-
- impStartSvtGraphicStroke(pSvtGraphicStroke.get());
+ mpMetaFile->AddAction(
+ new MetaCommentAction(aCommentStringA, i - nTextPosition));
+ nNextCellBreak = mxBreakIterator->nextCharacters(
+ rTxt, i, rLocale, css::i18n::CharacterIteratorMode::SKIPCELL, 1, nDone);
}
-
- RenderPolygonHairlinePrimitive2D(rHairlinePrimitive, false);
-
- if(bSupportSvtGraphicStroke)
+ if (i == nNextWordBoundary.endPos)
+ {
+ mpMetaFile->AddAction(
+ new MetaCommentAction(aCommentStringB, i - nTextPosition));
+ nNextWordBoundary = mxBreakIterator->getWordBoundary(
+ rTxt, i + 1, rLocale, css::i18n::WordType::ANY_WORD, true);
+ }
+ if (i == nNextSentenceBreak)
{
- impEndSvtGraphicStroke(pSvtGraphicStroke.get());
+ mpMetaFile->AddAction(
+ new MetaCommentAction(aCommentStringC, i - nTextPosition));
+ nNextSentenceBreak = mxBreakIterator->endOfSentence(rTxt, i + 1, rLocale);
}
}
}
+ }
+}
+
+void VclMetafileProcessor2D::processPolygonHairlinePrimitive2D(
+ const primitive2d::PolygonHairlinePrimitive2D& rHairlinePrimitive)
+{
+ const basegfx::B2DPolygon& rBasePolygon = rHairlinePrimitive.getB2DPolygon();
- void VclMetafileProcessor2D::processPolygonStrokePrimitive2D(const primitive2d::PolygonStrokePrimitive2D& rStrokePrimitive)
+ if (rBasePolygon.count() > (MAX_POLYGON_POINT_COUNT_METAFILE - 1))
+ {
+ // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
+ // per polygon. If there are more, split the polygon in half and call recursively
+ basegfx::B2DPolygon aLeft, aRight;
+ splitLinePolygon(rBasePolygon, aLeft, aRight);
+ rtl::Reference<primitive2d::PolygonHairlinePrimitive2D> xPLeft(
+ new primitive2d::PolygonHairlinePrimitive2D(aLeft, rHairlinePrimitive.getBColor()));
+ rtl::Reference<primitive2d::PolygonHairlinePrimitive2D> xPRight(
+ new primitive2d::PolygonHairlinePrimitive2D(aRight, rHairlinePrimitive.getBColor()));
+
+ processBasePrimitive2D(*xPLeft);
+ processBasePrimitive2D(*xPRight);
+ }
+ else
+ {
+ // direct draw of hairline; use default processing
+ // support SvtGraphicStroke MetaCommentAction
+ const basegfx::BColor aLineColor(
+ maBColorModifierStack.getModifiedColor(rHairlinePrimitive.getBColor()));
+ std::unique_ptr<SvtGraphicStroke> pSvtGraphicStroke;
+
+ // #i121267# Not needed, does not give better quality compared with
+ // the MetaActionType::POLYPOLYGON written by RenderPolygonHairlinePrimitive2D
+ // below
+ const bool bSupportSvtGraphicStroke(false);
+
+ if (bSupportSvtGraphicStroke)
{
- const basegfx::B2DPolygon& rBasePolygon = rStrokePrimitive.getB2DPolygon();
+ pSvtGraphicStroke
+ = impTryToCreateSvtGraphicStroke(rHairlinePrimitive.getB2DPolygon(), &aLineColor,
+ nullptr, nullptr, nullptr, nullptr);
- if(rBasePolygon.count() > (MAX_POLYGON_POINT_COUNT_METAFILE - 1))
- {
- // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
- // per polygon. If there are more, split the polygon in half and call recursively
- basegfx::B2DPolygon aLeft, aRight;
- splitLinePolygon(rBasePolygon, aLeft, aRight);
- rtl::Reference< primitive2d::PolygonStrokePrimitive2D > xPLeft(new primitive2d::PolygonStrokePrimitive2D(
- aLeft, rStrokePrimitive.getLineAttribute(), rStrokePrimitive.getStrokeAttribute()));
- rtl::Reference< primitive2d::PolygonStrokePrimitive2D > xPRight(new primitive2d::PolygonStrokePrimitive2D(
- aRight, rStrokePrimitive.getLineAttribute(), rStrokePrimitive.getStrokeAttribute()));
-
- processBasePrimitive2D(*xPLeft);
- processBasePrimitive2D(*xPRight);
- }
- else
- {
- mpOutputDevice->Push(PushFlags::LINECOLOR | PushFlags::FILLCOLOR);
+ impStartSvtGraphicStroke(pSvtGraphicStroke.get());
+ }
- // support SvtGraphicStroke MetaCommentAction
- std::unique_ptr<SvtGraphicStroke> pSvtGraphicStroke = impTryToCreateSvtGraphicStroke(
- rBasePolygon, nullptr,
- &rStrokePrimitive.getLineAttribute(),
- &rStrokePrimitive.getStrokeAttribute(),
- nullptr, nullptr);
+ RenderPolygonHairlinePrimitive2D(rHairlinePrimitive, false);
- impStartSvtGraphicStroke(pSvtGraphicStroke.get());
- const attribute::LineAttribute& rLine = rStrokePrimitive.getLineAttribute();
+ if (bSupportSvtGraphicStroke)
+ {
+ impEndSvtGraphicStroke(pSvtGraphicStroke.get());
+ }
+ }
+}
- // create MetaPolyLineActions, but without LineStyle::Dash
- if(basegfx::fTools::more(rLine.getWidth(), 0.0))
- {
- const attribute::StrokeAttribute& rStroke = rStrokePrimitive.getStrokeAttribute();
- basegfx::B2DPolyPolygon aHairLinePolyPolygon;
-
- if(0.0 == rStroke.getFullDotDashLen())
- {
- aHairLinePolyPolygon.append(rBasePolygon);
- }
- else
- {
- basegfx::utils::applyLineDashing(
- rBasePolygon, rStroke.getDotDashArray(),
- &aHairLinePolyPolygon, nullptr, rStroke.getFullDotDashLen());
- }
-
- const basegfx::BColor aHairlineColor(maBColorModifierStack.getModifiedColor(rLine.getColor()));
- mpOutputDevice->SetLineColor(Color(aHairlineColor));
- mpOutputDevice->SetFillColor();
- aHairLinePolyPolygon.transform(maCurrentTransformation);
-
- // use the transformed line width
- LineInfo aLineInfo(LineStyle::Solid, basegfx::fround(getTransformedLineWidth(rLine.getWidth())));
- aLineInfo.SetLineJoin(rLine.getLineJoin());
- aLineInfo.SetLineCap(rLine.getLineCap());
-
- for(sal_uInt32 a(0); a < aHairLinePolyPolygon.count(); a++)
- {
- const basegfx::B2DPolygon& aCandidate(aHairLinePolyPolygon.getB2DPolygon(a));
-
- if(aCandidate.count() > 1)
- {
- const ::tools::Polygon aToolsPolygon(aCandidate);
-
- mpMetaFile->AddAction(new MetaPolyLineAction(aToolsPolygon, aLineInfo));
- }
- }
- }
- else
- {
- process(rStrokePrimitive);
- }
+void VclMetafileProcessor2D::processPolygonStrokePrimitive2D(
+ const primitive2d::PolygonStrokePrimitive2D& rStrokePrimitive)
+{
+ const basegfx::B2DPolygon& rBasePolygon = rStrokePrimitive.getB2DPolygon();
- impEndSvtGraphicStroke(pSvtGraphicStroke.get());
+ if (rBasePolygon.count() > (MAX_POLYGON_POINT_COUNT_METAFILE - 1))
+ {
+ // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
+ // per polygon. If there are more, split the polygon in half and call recursively
+ basegfx::B2DPolygon aLeft, aRight;
+ splitLinePolygon(rBasePolygon, aLeft, aRight);
+ rtl::Reference<primitive2d::PolygonStrokePrimitive2D> xPLeft(
+ new primitive2d::PolygonStrokePrimitive2D(aLeft, rStrokePrimitive.getLineAttribute(),
+ rStrokePrimitive.getStrokeAttribute()));
+ rtl::Reference<primitive2d::PolygonStrokePrimitive2D> xPRight(
+ new primitive2d::PolygonStrokePrimitive2D(aRight, rStrokePrimitive.getLineAttribute(),
+ rStrokePrimitive.getStrokeAttribute()));
+
+ processBasePrimitive2D(*xPLeft);
+ processBasePrimitive2D(*xPRight);
+ }
+ else
+ {
+ mpOutputDevice->Push(PushFlags::LINECOLOR | PushFlags::FILLCOLOR);
- mpOutputDevice->Pop();
- }
- }
+ // support SvtGraphicStroke MetaCommentAction
+ std::unique_ptr<SvtGraphicStroke> pSvtGraphicStroke = impTryToCreateSvtGraphicStroke(
+ rBasePolygon, nullptr, &rStrokePrimitive.getLineAttribute(),
+ &rStrokePrimitive.getStrokeAttribute(), nullptr, nullptr);
- void VclMetafileProcessor2D::processPolygonStrokeArrowPrimitive2D(const primitive2d::PolygonStrokeArrowPrimitive2D& rStrokeArrowPrimitive)
+ impStartSvtGraphicStroke(pSvtGraphicStroke.get());
+ const attribute::LineAttribute& rLine = rStrokePrimitive.getLineAttribute();
+
+ // create MetaPolyLineActions, but without LineStyle::Dash
+ if (basegfx::fTools::more(rLine.getWidth(), 0.0))
{
- const basegfx::B2DPolygon& rBasePolygon = rStrokeArrowPrimitive.getB2DPolygon();
+ const attribute::StrokeAttribute& rStroke = rStrokePrimitive.getStrokeAttribute();
+ basegfx::B2DPolyPolygon aHairLinePolyPolygon;
- if(rBasePolygon.count() > (MAX_POLYGON_POINT_COUNT_METAFILE - 1))
+ if (0.0 == rStroke.getFullDotDashLen())
{
- // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
- // per polygon. If there are more, split the polygon in half and call recursively
- basegfx::B2DPolygon aLeft, aRight;
- splitLinePolygon(rBasePolygon, aLeft, aRight);
- const attribute::LineStartEndAttribute aEmpty;
- rtl::Reference< primitive2d::PolygonStrokeArrowPrimitive2D > xPLeft(new primitive2d::PolygonStrokeArrowPrimitive2D(
- aLeft,
- rStrokeArrowPrimitive.getLineAttribute(),
- rStrokeArrowPrimitive.getStrokeAttribute(),
- rStrokeArrowPrimitive.getStart(),
- aEmpty));
- rtl::Reference< primitive2d::PolygonStrokeArrowPrimitive2D > xPRight(new primitive2d::PolygonStrokeArrowPrimitive2D(
- aRight,
- rStrokeArrowPrimitive.getLineAttribute(),
- rStrokeArrowPrimitive.getStrokeAttribute(),
- aEmpty,
- rStrokeArrowPrimitive.getEnd()));
-
- processBasePrimitive2D(*xPLeft);
- processBasePrimitive2D(*xPRight);
+ aHairLinePolyPolygon.append(rBasePolygon);
}
else
{
- // support SvtGraphicStroke MetaCommentAction
- std::unique_ptr<SvtGraphicStroke> pSvtGraphicStroke = impTryToCreateSvtGraphicStroke(
- rBasePolygon, nullptr,
- &rStrokeArrowPrimitive.getLineAttribute(),
- &rStrokeArrowPrimitive.getStrokeAttribute(),
- &rStrokeArrowPrimitive.getStart(),
- &rStrokeArrowPrimitive.getEnd());
-
- // write LineGeometry start marker
- impStartSvtGraphicStroke(pSvtGraphicStroke.get());
-
- // #i116162# When B&W is set as DrawMode, DrawModeFlags::WhiteFill is used
- // to let all fills be just white; for lines DrawModeFlags::BlackLine is used
- // so all line geometry is supposed to get black. Since in the in-between
- // stages of line geometry drawing filled polygons are used (e.g. line
- // start/ends) it is necessary to change these drawmodes to preserve
- // that lines shall be black; thus change DrawModeFlags::WhiteFill to
- // DrawModeFlags::BlackFill during line geometry processing to have line geometry
- // parts filled black.
- const DrawModeFlags nOldDrawMode(mpOutputDevice->GetDrawMode());
- const bool bDrawmodeChange(nOldDrawMode & DrawModeFlags::WhiteFill && mnSvtGraphicStrokeCount);
-
- if(bDrawmodeChange)
- {
- mpOutputDevice->SetDrawMode((nOldDrawMode & ~DrawModeFlags::WhiteFill) | DrawModeFlags::BlackFill);
- }
+ basegfx::utils::applyLineDashing(rBasePolygon, rStroke.getDotDashArray(),
+ &aHairLinePolyPolygon, nullptr,
+ rStroke.getFullDotDashLen());
+ }
+
+ const basegfx::BColor aHairlineColor(
+ maBColorModifierStack.getModifiedColor(rLine.getColor()));
+ mpOutputDevice->SetLineColor(Color(aHairlineColor));
+ mpOutputDevice->SetFillColor();
+ aHairLinePolyPolygon.transform(maCurrentTransformation);
- // process sub-line geometry (evtl. filled PolyPolygons)
- process(rStrokeArrowPrimitive);
+ // use the transformed line width
+ LineInfo aLineInfo(LineStyle::Solid,
+ basegfx::fround(getTransformedLineWidth(rLine.getWidth())));
+ aLineInfo.SetLineJoin(rLine.getLineJoin());
+ aLineInfo.SetLineCap(rLine.getLineCap());
- if(bDrawmodeChange)
+ for (sal_uInt32 a(0); a < aHairLinePolyPolygon.count(); a++)
+ {
+ const basegfx::B2DPolygon& aCandidate(aHairLinePolyPolygon.getB2DPolygon(a));
+
+ if (aCandidate.count() > 1)
{
- mpOutputDevice->SetDrawMode(nOldDrawMode);
- }
+ const tools::Polygon aToolsPolygon(aCandidate);
- // write LineGeometry end marker
- impEndSvtGraphicStroke(pSvtGraphicStroke.get());
+ mpMetaFile->AddAction(new MetaPolyLineAction(aToolsPolygon, aLineInfo));
+ }
}
}
-
- void VclMetafileProcessor2D::processPolyPolygonGraphicPrimitive2D(const primitive2d::PolyPolygonGraphicPrimitive2D& rBitmapCandidate)
+ else
{
- // need to handle PolyPolygonGraphicPrimitive2D here to support XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END
- basegfx::B2DPolyPolygon aLocalPolyPolygon(rBitmapCandidate.getB2DPolyPolygon());
-
- fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon);
+ process(rStrokePrimitive);
+ }
- std::unique_ptr<SvtGraphicFill> pSvtGraphicFill;
+ impEndSvtGraphicStroke(pSvtGraphicStroke.get());
- if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count())
- {
- // #121194# Changed implementation and checked usages of convert to metafile,
- // presentation start (uses SvtGraphicFill) and printing.
+ mpOutputDevice->Pop();
+ }
+}
- // calculate transformation. Get real object size, all values in FillGraphicAttribute
- // are relative to the unified object
- aLocalPolyPolygon.transform(maCurrentTransformation);
- const basegfx::B2DVector aOutlineSize(aLocalPolyPolygon.getB2DRange().getRange());
-
- // the scaling needs scale from pixel to logic coordinate system
- const attribute::FillGraphicAttribute& rFillGraphicAttribute = rBitmapCandidate.getFillGraphic();
- const Size aBmpSizePixel(rFillGraphicAttribute.getGraphic().GetSizePixel());
-
- // setup transformation like in impgrfll. Multiply with aOutlineSize
- // to get from unit coordinates in rFillGraphicAttribute.getGraphicRange()
- // to object coordinates with object's top left being at (0,0). Divide
- // by pixel size so that scale from pixel to logic will work in SvtGraphicFill.
- const basegfx::B2DVector aTransformScale(
- rFillGraphicAttribute.getGraphicRange().getRange() /
- basegfx::B2DVector(
- std::max(1.0, double(aBmpSizePixel.Width())),
- std::max(1.0, double(aBmpSizePixel.Height()))) *
- aOutlineSize);
- const basegfx::B2DPoint aTransformPosition(
- rFillGraphicAttribute.getGraphicRange().getMinimum() * aOutlineSize);
-
- // setup transformation like in impgrfll
- SvtGraphicFill::Transform aTransform;
-
- // scale values are divided by bitmap pixel sizes
- aTransform.matrix[0] = aTransformScale.getX();
- aTransform.matrix[4] = aTransformScale.getY();
-
- // translates are absolute
- aTransform.matrix[2] = aTransformPosition.getX();
- aTransform.matrix[5] = aTransformPosition.getY();
-
- pSvtGraphicFill.reset( new SvtGraphicFill(
- getFillPolyPolygon(aLocalPolyPolygon),
- Color(),
- 0.0,
- SvtGraphicFill::fillEvenOdd,
- SvtGraphicFill::fillTexture,
- aTransform,
- rFillGraphicAttribute.getTiling(),
- SvtGraphicFill::hatchSingle,
- Color(),
- SvtGraphicFill::GradientType::Linear,
- Color(),
- Color(),
- 0,
- rFillGraphicAttribute.getGraphic()) );
- }
+void VclMetafileProcessor2D::processPolygonStrokeArrowPrimitive2D(
+ const primitive2d::PolygonStrokeArrowPrimitive2D& rStrokeArrowPrimitive)
+{
+ const basegfx::B2DPolygon& rBasePolygon = rStrokeArrowPrimitive.getB2DPolygon();
- // Do use decomposition; encapsulate with SvtGraphicFill
- impStartSvtGraphicFill(pSvtGraphicFill.get());
- process(rBitmapCandidate);
- impEndSvtGraphicFill(pSvtGraphicFill.get());
+ if (rBasePolygon.count() > (MAX_POLYGON_POINT_COUNT_METAFILE - 1))
+ {
+ // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
+ // per polygon. If there are more, split the polygon in half and call recursively
+ basegfx::B2DPolygon aLeft, aRight;
+ splitLinePolygon(rBasePolygon, aLeft, aRight);
+ const attribute::LineStartEndAttribute aEmpty;
+ rtl::Reference<primitive2d::PolygonStrokeArrowPrimitive2D> xPLeft(
+ new primitive2d::PolygonStrokeArrowPrimitive2D(
+ aLeft, rStrokeArrowPrimitive.getLineAttribute(),
+ rStrokeArrowPrimitive.getStrokeAttribute(), rStrokeArrowPrimitive.getStart(),
+ aEmpty));
+ rtl::Reference<primitive2d::PolygonStrokeArrowPrimitive2D> xPRight(
+ new primitive2d::PolygonStrokeArrowPrimitive2D(
+ aRight, rStrokeArrowPrimitive.getLineAttribute(),
+ rStrokeArrowPrimitive.getStrokeAttribute(), aEmpty,
+ rStrokeArrowPrimitive.getEnd()));
+
+ processBasePrimitive2D(*xPLeft);
+ processBasePrimitive2D(*xPRight);
+ }
+ else
+ {
+ // support SvtGraphicStroke MetaCommentAction
+ std::unique_ptr<SvtGraphicStroke> pSvtGraphicStroke = impTryToCreateSvtGraphicStroke(
+ rBasePolygon, nullptr, &rStrokeArrowPrimitive.getLineAttribute(),
+ &rStrokeArrowPrimitive.getStrokeAttribute(), &rStrokeArrowPrimitive.getStart(),
+ &rStrokeArrowPrimitive.getEnd());
+
+ // write LineGeometry start marker
+ impStartSvtGraphicStroke(pSvtGraphicStroke.get());
+
+ // #i116162# When B&W is set as DrawMode, DrawModeFlags::WhiteFill is used
+ // to let all fills be just white; for lines DrawModeFlags::BlackLine is used
+ // so all line geometry is supposed to get black. Since in the in-between
+ // stages of line geometry drawing filled polygons are used (e.g. line
+ // start/ends) it is necessary to change these drawmodes to preserve
+ // that lines shall be black; thus change DrawModeFlags::WhiteFill to
+ // DrawModeFlags::BlackFill during line geometry processing to have line geometry
+ // parts filled black.
+ const DrawModeFlags nOldDrawMode(mpOutputDevice->GetDrawMode());
+ const bool bDrawmodeChange(nOldDrawMode & DrawModeFlags::WhiteFill
+ && mnSvtGraphicStrokeCount);
+
+ if (bDrawmodeChange)
+ {
+ mpOutputDevice->SetDrawMode((nOldDrawMode & ~DrawModeFlags::WhiteFill)
+ | DrawModeFlags::BlackFill);
}
- void VclMetafileProcessor2D::processPolyPolygonHatchPrimitive2D(const primitive2d::PolyPolygonHatchPrimitive2D& rHatchCandidate)
- {
- // need to handle PolyPolygonHatchPrimitive2D here to support XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END
- const attribute::FillHatchAttribute& rFillHatchAttribute = rHatchCandidate.getFillHatch();
- basegfx::B2DPolyPolygon aLocalPolyPolygon(rHatchCandidate.getB2DPolyPolygon());
+ // process sub-line geometry (evtl. filled PolyPolygons)
+ process(rStrokeArrowPrimitive);
- if(aLocalPolyPolygon.getB2DRange() != rHatchCandidate.getDefinitionRange())
- {
- // the range which defines the hatch is different from the range of the
- // geometry (used for writer frames). This cannot be done calling vcl, thus use
- // decomposition here
- process(rHatchCandidate);
- return;
- }
+ if (bDrawmodeChange)
+ {
+ mpOutputDevice->SetDrawMode(nOldDrawMode);
+ }
- // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
- // per polygon. Split polygon until there are less than that
- fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon);
+ // write LineGeometry end marker
+ impEndSvtGraphicStroke(pSvtGraphicStroke.get());
+ }
+}
- if(rFillHatchAttribute.isFillBackground())
- {
- // with fixing #i111954# (see below) the possible background
- // fill of a hatched object was lost.Generate a background fill
- // primitive and render it
- const primitive2d::Primitive2DReference xBackground(
- new primitive2d::PolyPolygonColorPrimitive2D(
- aLocalPolyPolygon,
- rHatchCandidate.getBackgroundColor()));
-
- process(primitive2d::Primitive2DContainer { xBackground });
- }
+void VclMetafileProcessor2D::processPolyPolygonGraphicPrimitive2D(
+ const primitive2d::PolyPolygonGraphicPrimitive2D& rBitmapCandidate)
+{
+ // need to handle PolyPolygonGraphicPrimitive2D here to support XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END
+ basegfx::B2DPolyPolygon aLocalPolyPolygon(rBitmapCandidate.getB2DPolyPolygon());
- std::unique_ptr<SvtGraphicFill> pSvtGraphicFill;
- aLocalPolyPolygon.transform(maCurrentTransformation);
+ fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon);
- if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count())
- {
- // re-create a VCL hatch as base data
- SvtGraphicFill::HatchType eHatch(SvtGraphicFill::hatchSingle);
+ std::unique_ptr<SvtGraphicFill> pSvtGraphicFill;
- switch(rFillHatchAttribute.getStyle())
- {
- default: // attribute::HatchStyle::Single :
- {
- eHatch = SvtGraphicFill::hatchSingle;
- break;
- }
- case attribute::HatchStyle::Double :
- {
- eHatch = SvtGraphicFill::hatchDouble;
- break;
- }
- case attribute::HatchStyle::Triple :
- {
- eHatch = SvtGraphicFill::hatchTriple;
- break;
- }
- }
+ if (!mnSvtGraphicFillCount && aLocalPolyPolygon.count())
+ {
+ // #121194# Changed implementation and checked usages of convert to metafile,
+ // presentation start (uses SvtGraphicFill) and printing.
+
+ // calculate transformation. Get real object size, all values in FillGraphicAttribute
+ // are relative to the unified object
+ aLocalPolyPolygon.transform(maCurrentTransformation);
+ const basegfx::B2DVector aOutlineSize(aLocalPolyPolygon.getB2DRange().getRange());
+
+ // the scaling needs scale from pixel to logic coordinate system
+ const attribute::FillGraphicAttribute& rFillGraphicAttribute
+ = rBitmapCandidate.getFillGraphic();
+ const Size aBmpSizePixel(rFillGraphicAttribute.getGraphic().GetSizePixel());
+
+ // setup transformation like in impgrfll. Multiply with aOutlineSize
+ // to get from unit coordinates in rFillGraphicAttribute.getGraphicRange()
+ // to object coordinates with object's top left being at (0,0). Divide
+ // by pixel size so that scale from pixel to logic will work in SvtGraphicFill.
+ const basegfx::B2DVector aTransformScale(
+ rFillGraphicAttribute.getGraphicRange().getRange()
+ / basegfx::B2DVector(std::max(1.0, double(aBmpSizePixel.Width())),
+ std::max(1.0, double(aBmpSizePixel.Height())))
+ * aOutlineSize);
+ const basegfx::B2DPoint aTransformPosition(
+ rFillGraphicAttribute.getGraphicRange().getMinimum() * aOutlineSize);
+
+ // setup transformation like in impgrfll
+ SvtGraphicFill::Transform aTransform;
+
+ // scale values are divided by bitmap pixel sizes
+ aTransform.matrix[0] = aTransformScale.getX();
+ aTransform.matrix[4] = aTransformScale.getY();
+
+ // translates are absolute
+ aTransform.matrix[2] = aTransformPosition.getX();
+ aTransform.matrix[5] = aTransformPosition.getY();
+
+ pSvtGraphicFill.reset(new SvtGraphicFill(
+ getFillPolyPolygon(aLocalPolyPolygon), Color(), 0.0, SvtGraphicFill::fillEvenOdd,
+ SvtGraphicFill::fillTexture, aTransform, rFillGraphicAttribute.getTiling(),
+ SvtGraphicFill::hatchSingle, Color(), SvtGraphicFill::GradientType::Linear, Color(),
+ Color(), 0, rFillGraphicAttribute.getGraphic()));
+ }
- SvtGraphicFill::Transform aTransform;
-
- // scale
- aTransform.matrix[0] *= rFillHatchAttribute.getDistance();
- aTransform.matrix[4] *= rFillHatchAttribute.getDistance();
-
- // rotate (was never correct in impgrfll anyways, use correct angle now)
- aTransform.matrix[0] *= cos(rFillHatchAttribute.getAngle());
- aTransform.matrix[1] *= -sin(rFillHatchAttribute.getAngle());
- aTransform.matrix[3] *= sin(rFillHatchAttribute.getAngle());
- aTransform.matrix[4] *= cos(rFillHatchAttribute.getAngle());
-
- pSvtGraphicFill.reset( new SvtGraphicFill(
- getFillPolyPolygon(aLocalPolyPolygon),
- Color(),
- 0.0,
- SvtGraphicFill::fillEvenOdd,
- SvtGraphicFill::fillHatch,
- aTransform,
- false,
- eHatch,
- Color(maBColorModifierStack.getModifiedColor(rFillHatchAttribute.getColor())),
- SvtGraphicFill::GradientType::Linear,
- Color(),
- Color(),
- 0,
- Graphic()) );
- }
+ // Do use decomposition; encapsulate with SvtGraphicFill
+ impStartSvtGraphicFill(pSvtGraphicFill.get());
+ process(rBitmapCandidate);
+ impEndSvtGraphicFill(pSvtGraphicFill.get());
+}
- // Do use decomposition; encapsulate with SvtGraphicFill
- impStartSvtGraphicFill(pSvtGraphicFill.get());
+void VclMetafileProcessor2D::processPolyPolygonHatchPrimitive2D(
+ const primitive2d::PolyPolygonHatchPrimitive2D& rHatchCandidate)
+{
+ // need to handle PolyPolygonHatchPrimitive2D here to support XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END
+ const attribute::FillHatchAttribute& rFillHatchAttribute = rHatchCandidate.getFillHatch();
+ basegfx::B2DPolyPolygon aLocalPolyPolygon(rHatchCandidate.getB2DPolyPolygon());
- // #i111954# do NOT use decomposition, but use direct VCL-command
- // process(rCandidate.get2DDecomposition(getViewInformation2D()));
- const ::tools::PolyPolygon aToolsPolyPolygon(basegfx::utils::adaptiveSubdivideByAngle(aLocalPolyPolygon));
- const HatchStyle aHatchStyle(
- attribute::HatchStyle::Single == rFillHatchAttribute.getStyle() ? HatchStyle::Single :
- attribute::HatchStyle::Double == rFillHatchAttribute.getStyle() ? HatchStyle::Double :
- HatchStyle::Triple);
+ if (aLocalPolyPolygon.getB2DRange() != rHatchCandidate.getDefinitionRange())
+ {
+ // the range which defines the hatch is different from the range of the
+ // geometry (used for writer frames). This cannot be done calling vcl, thus use
+ // decomposition here
+ process(rHatchCandidate);
+ return;
+ }
- mpOutputDevice->DrawHatch(aToolsPolyPolygon,
- Hatch(aHatchStyle,
- Color(maBColorModifierStack.getModifiedColor(rFillHatchAttribute.getColor())),
- basegfx::fround(rFillHatchAttribute.getDistance()),
- basegfx::fround(rFillHatchAttribute.getAngle() / F_PI1800)));
+ // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
+ // per polygon. Split polygon until there are less than that
+ fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon);
- impEndSvtGraphicFill(pSvtGraphicFill.get());
- }
+ if (rFillHatchAttribute.isFillBackground())
+ {
+ // with fixing #i111954# (see below) the possible background
+ // fill of a hatched object was lost.Generate a background fill
+ // primitive and render it
+ const primitive2d::Primitive2DReference xBackground(
+ new primitive2d::PolyPolygonColorPrimitive2D(aLocalPolyPolygon,
+ rHatchCandidate.getBackgroundColor()));
+
+ process(primitive2d::Primitive2DContainer{ xBackground });
+ }
- void VclMetafileProcessor2D::processPolyPolygonGradientPrimitive2D(const primitive2d::PolyPolygonGradientPrimitive2D& rGradientCandidate)
- {
- basegfx::B2DVector aScale, aTranslate;
- double fRotate, fShearX;
+ std::unique_ptr<SvtGraphicFill> pSvtGraphicFill;
+ aLocalPolyPolygon.transform(maCurrentTransformation);
- maCurrentTransformation.decompose(aScale, aTranslate, fRotate, fShearX);
+ if (!mnSvtGraphicFillCount && aLocalPolyPolygon.count())
+ {
+ // re-create a VCL hatch as base data
+ SvtGraphicFill::HatchType eHatch(SvtGraphicFill::hatchSingle);
- if(!basegfx::fTools::equalZero(fRotate) || !basegfx::fTools::equalZero(fShearX))
+ switch (rFillHatchAttribute.getStyle())
+ {
+ default: // attribute::HatchStyle::Single :
{
- // #i121185# When rotation or shear is used, a VCL Gradient cannot be used directly.
- // This is because VCL Gradient mechanism does *not* support to rotate the gradient
- // with objects and this case is not expressible in a Metafile (and cannot be added
- // since the FileFormats used, e.g. *.wmf, do not support it either).
- // Such cases happen when a graphic object uses a Metafile as graphic information or
- // a fill style definition uses a Metafile. In this cases the graphic content is
- // rotated with the graphic or filled object; this is not supported by the target
- // format of this conversion renderer - Metafiles.
- // To solve this, not a Gradient is written, but the decomposition of this object
- // is written to the Metafile. This is the PolyPolygons building the gradient fill.
- // These will need more space and time, but the result will be as if the Gradient
- // was rotated with the object.
- // This mechanism is used by all exporters still not using Primitives (e.g. Print,
- // Slideshow, Export rto PDF, export to Picture, ...) but relying on Metafile
- // transfers. One more reason to *change* these to primitives.
- // BTW: One more example how useful the principles of primitives are; the decomposition
- // is by definition a simpler, maybe more expensive representation of the same content.
- process(rGradientCandidate);
- return;
+ eHatch = SvtGraphicFill::hatchSingle;
+ break;
}
-
- basegfx::B2DPolyPolygon aLocalPolyPolygon(rGradientCandidate.getB2DPolyPolygon());
-
- if(aLocalPolyPolygon.getB2DRange() != rGradientCandidate.getDefinitionRange())
+ case attribute::HatchStyle::Double:
{
- // the range which defines the gradient is different from the range of the
- // geometry (used for writer frames). This cannot be done calling vcl, thus use
- // decomposition here
- process(rGradientCandidate);
- return;
+ eHatch = SvtGraphicFill::hatchDouble;
+ break;
}
+ case attribute::HatchStyle::Triple:
+ {
+ eHatch = SvtGraphicFill::hatchTriple;
+ break;
+ }
+ }
- // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
- // per polygon. Split polygon until there are less than that
- fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon);
+ SvtGraphicFill::Transform aTransform;
- // for support of MetaCommentActions of the form XGRAD_SEQ_BEGIN, XGRAD_SEQ_END
- // it is safest to use the VCL OutputDevice::DrawGradient method which creates those.
- // re-create a VCL-gradient from FillGradientPrimitive2D and the needed tools PolyPolygon
- Gradient aVCLGradient;
- impConvertFillGradientAttributeToVCLGradient(aVCLGradient, rGradientCandidate.getFillGradient(), false);
- aLocalPolyPolygon.transform(maCurrentTransformation);
+ // scale
+ aTransform.matrix[0] *= rFillHatchAttribute.getDistance();
+ aTransform.matrix[4] *= rFillHatchAttribute.getDistance();
- // #i82145# ATM VCL printing of gradients using curved shapes does not work,
- // i submitted the bug with the given ID to THB. When that task is fixed it is
- // necessary to again remove this subdivision since it decreases possible
- // printing quality (not even resolution-dependent for now). THB will tell
- // me when that task is fixed in the master
- const ::tools::PolyPolygon aToolsPolyPolygon(
- getFillPolyPolygon(
- basegfx::utils::adaptiveSubdivideByAngle(aLocalPolyPolygon)));
+ // rotate (was never correct in impgrfll anyways, use correct angle now)
+ aTransform.matrix[0] *= cos(rFillHatchAttribute.getAngle());
+ aTransform.matrix[1] *= -sin(rFillHatchAttribute.getAngle());
+ aTransform.matrix[3] *= sin(rFillHatchAttribute.getAngle());
+ aTransform.matrix[4] *= cos(rFillHatchAttribute.getAngle());
+
+ pSvtGraphicFill.reset(new SvtGraphicFill(
+ getFillPolyPolygon(aLocalPolyPolygon), Color(), 0.0, SvtGraphicFill::fillEvenOdd,
+ SvtGraphicFill::fillHatch, aTransform, false, eHatch,
+ Color(maBColorModifierStack.getModifiedColor(rFillHatchAttribute.getColor())),
+ SvtGraphicFill::GradientType::Linear, Color(), Color(), 0, Graphic()));
+ }
+ // Do use decomposition; encapsulate with SvtGraphicFill
+ impStartSvtGraphicFill(pSvtGraphicFill.get());
+
+ // #i111954# do NOT use decomposition, but use direct VCL-command
+ // process(rCandidate.get2DDecomposition(getViewInformation2D()));
+ const tools::PolyPolygon aToolsPolyPolygon(
+ basegfx::utils::adaptiveSubdivideByAngle(aLocalPolyPolygon));
+ const HatchStyle aHatchStyle(
+ attribute::HatchStyle::Single == rFillHatchAttribute.getStyle()
+ ? HatchStyle::Single
+ : attribute::HatchStyle::Double == rFillHatchAttribute.getStyle() ? HatchStyle::Double
+ : HatchStyle::Triple);
+
+ mpOutputDevice->DrawHatch(
+ aToolsPolyPolygon,
+ Hatch(aHatchStyle,
+ Color(maBColorModifierStack.getModifiedColor(rFillHatchAttribute.getColor())),
+ basegfx::fround(rFillHatchAttribute.getDistance()),
+ basegfx::fround(rFillHatchAttribute.getAngle() / F_PI1800)));
+
+ impEndSvtGraphicFill(pSvtGraphicFill.get());
+}
+
+void VclMetafileProcessor2D::processPolyPolygonGradientPrimitive2D(
+ const primitive2d::PolyPolygonGradientPrimitive2D& rGradientCandidate)
+{
+ basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
- // XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END support
- std::unique_ptr<SvtGraphicFill> pSvtGraphicFill;
+ maCurrentTransformation.decompose(aScale, aTranslate, fRotate, fShearX);
- if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count())
- {
- // setup gradient stuff like in impgrfll
- SvtGraphicFill::GradientType eGrad(SvtGraphicFill::GradientType::Linear);
+ if (!basegfx::fTools::equalZero(fRotate) || !basegfx::fTools::equalZero(fShearX))
+ {
+ // #i121185# When rotation or shear is used, a VCL Gradient cannot be used directly.
+ // This is because VCL Gradient mechanism does *not* support to rotate the gradient
+ // with objects and this case is not expressible in a Metafile (and cannot be added
+ // since the FileFormats used, e.g. *.wmf, do not support it either).
+ // Such cases happen when a graphic object uses a Metafile as graphic information or
+ // a fill style definition uses a Metafile. In this cases the graphic content is
+ // rotated with the graphic or filled object; this is not supported by the target
+ // format of this conversion renderer - Metafiles.
+ // To solve this, not a Gradient is written, but the decomposition of this object
+ // is written to the Metafile. This is the PolyPolygons building the gradient fill.
+ // These will need more space and time, but the result will be as if the Gradient
+ // was rotated with the object.
+ // This mechanism is used by all exporters still not using Primitives (e.g. Print,
+ // Slideshow, Export rto PDF, export to Picture, ...) but relying on Metafile
+ // transfers. One more reason to *change* these to primitives.
+ // BTW: One more example how useful the principles of primitives are; the decomposition
+ // is by definition a simpler, maybe more expensive representation of the same content.
+ process(rGradientCandidate);
+ return;
+ }
- switch(aVCLGradient.GetStyle())
- {
- default : // GradientStyle::Linear:
- case GradientStyle::Axial:
- eGrad = SvtGraphicFill::GradientType::Linear;
- break;
- case GradientStyle::Radial:
- case GradientStyle::Elliptical:
- eGrad = SvtGraphicFill::GradientType::Radial;
- break;
- case GradientStyle::Square:
- case GradientStyle::Rect:
- eGrad = SvtGraphicFill::GradientType::Rectangular;
- break;
- }
+ basegfx::B2DPolyPolygon aLocalPolyPolygon(rGradientCandidate.getB2DPolyPolygon());
- pSvtGraphicFill.reset( new SvtGraphicFill(
- aToolsPolyPolygon,
- Color(),
- 0.0,
- SvtGraphicFill::fillEvenOdd,
- SvtGraphicFill::fillGradient,
- SvtGraphicFill::Transform(),
- false,
- SvtGraphicFill::hatchSingle,
- Color(),
- eGrad,
- aVCLGradient.GetStartColor(),
- aVCLGradient.GetEndColor(),
- aVCLGradient.GetSteps(),
- Graphic()) );
- }
+ if (aLocalPolyPolygon.getB2DRange() != rGradientCandidate.getDefinitionRange())
+ {
+ // the range which defines the gradient is different from the range of the
+ // geometry (used for writer frames). This cannot be done calling vcl, thus use
+ // decomposition here
+ process(rGradientCandidate);
+ return;
+ }
- // call VCL directly; encapsulate with SvtGraphicFill
- impStartSvtGraphicFill(pSvtGraphicFill.get());
- mpOutputDevice->DrawGradient(aToolsPolyPolygon, aVCLGradient);
- impEndSvtGraphicFill(pSvtGraphicFill.get());
- }
+ // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
+ // per polygon. Split polygon until there are less than that
+ fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon);
+
+ // for support of MetaCommentActions of the form XGRAD_SEQ_BEGIN, XGRAD_SEQ_END
+ // it is safest to use the VCL OutputDevice::DrawGradient method which creates those.
+ // re-create a VCL-gradient from FillGradientPrimitive2D and the needed tools PolyPolygon
+ Gradient aVCLGradient;
+ impConvertFillGradientAttributeToVCLGradient(aVCLGradient, rGradientCandidate.getFillGradient(),
+ false);
+ aLocalPolyPolygon.transform(maCurrentTransformation);
+
+ // #i82145# ATM VCL printing of gradients using curved shapes does not work,
+ // i submitted the bug with the given ID to THB. When that task is fixed it is
+ // necessary to again remove this subdivision since it decreases possible
+ // printing quality (not even resolution-dependent for now). THB will tell
+ // me when that task is fixed in the master
+ const tools::PolyPolygon aToolsPolyPolygon(
+ getFillPolyPolygon(basegfx::utils::adaptiveSubdivideByAngle(aLocalPolyPolygon)));
+
+ // XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END support
+ std::unique_ptr<SvtGraphicFill> pSvtGraphicFill;
+
+ if (!mnSvtGraphicFillCount && aLocalPolyPolygon.count())
+ {
+ // setup gradient stuff like in impgrfll
+ SvtGraphicFill::GradientType eGrad(SvtGraphicFill::GradientType::Linear);
- void VclMetafileProcessor2D::processPolyPolygonColorPrimitive2D(const primitive2d::PolyPolygonColorPrimitive2D& rPolygonCandidate)
+ switch (aVCLGradient.GetStyle())
{
- mpOutputDevice->Push(PushFlags::LINECOLOR | PushFlags::FILLCOLOR);
- basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon());
+ default: // GradientStyle::Linear:
+ case GradientStyle::Axial:
+ eGrad = SvtGraphicFill::GradientType::Linear;
+ break;
+ case GradientStyle::Radial:
+ case GradientStyle::Elliptical:
+ eGrad = SvtGraphicFill::GradientType::Radial;
+ break;
+ case GradientStyle::Square:
+ case GradientStyle::Rect:
+ eGrad = SvtGraphicFill::GradientType::Rectangular;
+ break;
+ }
- // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
- // per polygon. Split polygon until there are less than that
- fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon);
+ pSvtGraphicFill.reset(new SvtGraphicFill(
+ aToolsPolyPolygon, Color(), 0.0, SvtGraphicFill::fillEvenOdd,
+ SvtGraphicFill::fillGradient, SvtGraphicFill::Transform(), false,
+ SvtGraphicFill::hatchSingle, Color(), eGrad, aVCLGradient.GetStartColor(),
+ aVCLGradient.GetEndColor(), aVCLGradient.GetSteps(), Graphic()));
+ }
- const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rPolygonCandidate.getBColor()));
- aLocalPolyPolygon.transform(maCurrentTransformation);
+ // call VCL directly; encapsulate with SvtGraphicFill
+ impStartSvtGraphicFill(pSvtGraphicFill.get());
+ mpOutputDevice->DrawGradient(aToolsPolyPolygon, aVCLGradient);
+ impEndSvtGraphicFill(pSvtGraphicFill.get());
+}
- // set line and fill color
- mpOutputDevice->SetFillColor(Color(aPolygonColor));
- mpOutputDevice->SetLineColor();
+void VclMetafileProcessor2D::processPolyPolygonColorPrimitive2D(
+ const primitive2d::PolyPolygonColorPrimitive2D& rPolygonCandidate)
+{
+ mpOutputDevice->Push(PushFlags::LINECOLOR | PushFlags::FILLCOLOR);
+ basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon());
- mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon);
+ // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
+ // per polygon. Split polygon until there are less than that
+ fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon);
- mpOutputDevice->Pop();
- }
+ const basegfx::BColor aPolygonColor(
+ maBColorModifierStack.getModifiedColor(rPolygonCandidate.getBColor()));
+ aLocalPolyPolygon.transform(maCurrentTransformation);
- void VclMetafileProcessor2D::processMaskPrimitive2D(const primitive2d::MaskPrimitive2D& rMaskCandidate)
- {
- // mask group. Special handling for MetaFiles.
- if(rMaskCandidate.getChildren().empty())
- return;
+ // set line and fill color
+ mpOutputDevice->SetFillColor(Color(aPolygonColor));
+ mpOutputDevice->SetLineColor();
- basegfx::B2DPolyPolygon aMask(rMaskCandidate.getMask());
+ mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon);
- if(aMask.count())
- {
- // prepare new mask polygon and rescue current one
- aMask.transform(maCurrentTransformation);
- const basegfx::B2DPolyPolygon aLastClipPolyPolygon(maClipPolyPolygon);
+ mpOutputDevice->Pop();
+}
- if(maClipPolyPolygon.count())
- {
- // there is already a clip polygon set; build clipped union of
- // current mask polygon and new one
- maClipPolyPolygon = basegfx::utils::clipPolyPolygonOnPolyPolygon(
- aMask,
- maClipPolyPolygon,
- true, // #i106516# we want the inside of aMask, not the outside
- false);
- }
- else
- {
- // use mask directly
- maClipPolyPolygon = aMask;
- }
+void VclMetafileProcessor2D::processMaskPrimitive2D(
+ const primitive2d::MaskPrimitive2D& rMaskCandidate)
+{
+ // mask group. Special handling for MetaFiles.
+ if (rMaskCandidate.getChildren().empty())
+ return;
- if(maClipPolyPolygon.count())
- {
- // set VCL clip region; subdivide before conversion to tools polygon. Subdivision necessary (!)
- // Removed subdivision and fixed in vcl::Region::ImplPolyPolyRegionToBandRegionFunc() in VCL where
- // the ClipRegion is built from the Polygon. An AdaptiveSubdivide on the source polygon was missing there
- mpOutputDevice->Push(PushFlags::CLIPREGION);
- mpOutputDevice->SetClipRegion(vcl::Region(maClipPolyPolygon));
-
- // 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());
-
- // restore VCL clip region
- mpOutputDevice->Pop();
- }
+ basegfx::B2DPolyPolygon aMask(rMaskCandidate.getMask());
- // restore to rescued clip polygon
- maClipPolyPolygon = aLastClipPolyPolygon;
- }
- else
- {
- // no mask, no clipping. recursively paint content
- process(rMaskCandidate.getChildren());
- }
- }
+ if (aMask.count())
+ {
+ // prepare new mask polygon and rescue current one
+ aMask.transform(maCurrentTransformation);
+ const basegfx::B2DPolyPolygon aLastClipPolyPolygon(maClipPolyPolygon);
- void VclMetafileProcessor2D::processUnifiedTransparencePrimitive2D(const primitive2d::UnifiedTransparencePrimitive2D& rUniTransparenceCandidate)
+ if (maClipPolyPolygon.count())
{
- mpOutputDevice->Push(PushFlags::LINECOLOR | PushFlags::FILLCOLOR);
- // for metafile: Need to examine what the pure vcl version is doing here actually
- // - uses DrawTransparent with metafile for content and a gradient
- // - uses DrawTransparent for single PolyPolygons directly. Can be detected by
- // checking the content for single PolyPolygonColorPrimitive2D
- const primitive2d::Primitive2DContainer& rContent = rUniTransparenceCandidate.getChildren();
-
- if(!rContent.empty())
- {
- if(0.0 == rUniTransparenceCandidate.getTransparence())
- {
- // not transparent at all, use content
- process(rUniTransparenceCandidate.getChildren());
- }
- else if(rUniTransparenceCandidate.getTransparence() > 0.0 && rUniTransparenceCandidate.getTransparence() < 1.0)
- {
- // try to identify a single PolyPolygonColorPrimitive2D in the
- // content part of the transparence primitive
- const primitive2d::PolyPolygonColorPrimitive2D* pPoPoColor = nullptr;
- static bool bForceToMetafile(false); // loplugin:constvars:ignore
-
- if(!bForceToMetafile && 1 == rContent.size())
- {
- const primitive2d::Primitive2DReference xReference(rContent[0]);
- pPoPoColor = dynamic_cast< const primitive2d::PolyPolygonColorPrimitive2D* >(xReference.get());
- }
-
- // PolyPolygonGradientPrimitive2D, PolyPolygonHatchPrimitive2D and
- // PolyPolygonGraphicPrimitive2D are derived from PolyPolygonColorPrimitive2D.
- // Check also for correct ID to exclude derived implementations
- if(pPoPoColor && PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D == pPoPoColor->getPrimitive2DID())
- {
- // single transparent tools::PolyPolygon identified, use directly
- const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(pPoPoColor->getBColor()));
- basegfx::B2DPolyPolygon aLocalPolyPolygon(pPoPoColor->getB2DPolyPolygon());
-
- // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
- // per polygon. Split polygon until there are less than that
- fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon);
-
- // now transform
- aLocalPolyPolygon.transform(maCurrentTransformation);
-
- // set line and fill color
- const sal_uInt16 nTransPercentVcl(static_cast<sal_uInt16>(basegfx::fround(rUniTransparenceCandidate.getTransparence() * 100.0)));
- mpOutputDevice->SetFillColor(Color(aPolygonColor));
- mpOutputDevice->SetLineColor();
-
- mpOutputDevice->DrawTransparent(
- ::tools::PolyPolygon(aLocalPolyPolygon),
- nTransPercentVcl);
- }
- else
- {
- // save old mfCurrentUnifiedTransparence and set new one
- // so that contained SvtGraphicStroke may use the current one
- const double fLastCurrentUnifiedTransparence(mfCurrentUnifiedTransparence);
- // #i105377# paint the content metafile opaque as the transparency gets
- // split of into the gradient below
- // mfCurrentUnifiedTransparence = rUniTransparenceCandidate.getTransparence();
- mfCurrentUnifiedTransparence = 0;
-
- // various content, create content-metafile
- GDIMetaFile aContentMetafile;
- const ::tools::Rectangle aPrimitiveRectangle(impDumpToMetaFile(rContent, aContentMetafile));
-
- // restore mfCurrentUnifiedTransparence; it may have been used
- // while processing the sub-content in impDumpToMetaFile
- mfCurrentUnifiedTransparence = fLastCurrentUnifiedTransparence;
-
- // create uniform VCL gradient for uniform transparency
- Gradient aVCLGradient;
- const sal_uInt8 nTransPercentVcl(static_cast<sal_uInt8>(basegfx::fround(rUniTransparenceCandidate.getTransparence() * 255.0)));
- const Color aTransColor(nTransPercentVcl, nTransPercentVcl, nTransPercentVcl);
-
- aVCLGradient.SetStyle(GradientStyle::Linear);
- aVCLGradient.SetStartColor(aTransColor);
- aVCLGradient.SetEndColor(aTransColor);
- aVCLGradient.SetAngle(0);
- aVCLGradient.SetBorder(0);
- aVCLGradient.SetOfsX(0);
- aVCLGradient.SetOfsY(0);
- aVCLGradient.SetStartIntensity(100);
- aVCLGradient.SetEndIntensity(100);
- aVCLGradient.SetSteps(2);
-
- // render it to VCL
- mpOutputDevice->DrawTransparent(
- aContentMetafile, aPrimitiveRectangle.TopLeft(),
- aPrimitiveRectangle.GetSize(), aVCLGradient);
- }
- }
- }
-
- mpOutputDevice->Pop();
+ // there is already a clip polygon set; build clipped union of
+ // current mask polygon and new one
+ maClipPolyPolygon = basegfx::utils::clipPolyPolygonOnPolyPolygon(
+ aMask, maClipPolyPolygon,
+ true, // #i106516# we want the inside of aMask, not the outside
+ false);
+ }
+ else
+ {
+ // use mask directly
+ maClipPolyPolygon = aMask;
}
- void VclMetafileProcessor2D::processTransparencePrimitive2D(const primitive2d::TransparencePrimitive2D& rTransparenceCandidate)
+ if (maClipPolyPolygon.count())
{
- // for metafile: Need to examine what the pure vcl version is doing here actually
- // - uses DrawTransparent with metafile for content and a gradient
- // i can detect this here with checking the gradient part for a single
- // FillGradientPrimitive2D and reconstruct the gradient.
- // If that detection goes wrong, I have to create a transparence-blended bitmap. Eventually
- // do that in stripes, else RenderTransparencePrimitive2D may just be used
- const primitive2d::Primitive2DContainer& rContent = rTransparenceCandidate.getChildren();
- const primitive2d::Primitive2DContainer& rTransparence = rTransparenceCandidate.getTransparence();
+ // set VCL clip region; subdivide before conversion to tools polygon. Subdivision necessary (!)
+ // Removed subdivision and fixed in vcl::Region::ImplPolyPolyRegionToBandRegionFunc() in VCL where
+ // the ClipRegion is built from the Polygon. An AdaptiveSubdivide on the source polygon was missing there
+ mpOutputDevice->Push(PushFlags::CLIPREGION);
+ mpOutputDevice->SetClipRegion(vcl::Region(maClipPolyPolygon));
+
+ // 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());
+
+ // restore VCL clip region
+ mpOutputDevice->Pop();
+ }
- if(rContent.empty() || rTransparence.empty())
- return;
+ // restore to rescued clip polygon
+ maClipPolyPolygon = aLastClipPolyPolygon;
+ }
+ else
+ {
+ // no mask, no clipping. recursively paint content
+ process(rMaskCandidate.getChildren());
+ }
+}
- // try to identify a single FillGradientPrimitive2D in the
- // transparence part of the primitive
- const primitive2d::FillGradientPrimitive2D* pFiGradient = nullptr;
- static bool bForceToBigTransparentVDev(false); // loplugin:constvars:ignore
+void VclMetafileProcessor2D::processUnifiedTransparencePrimitive2D(
+ const primitive2d::UnifiedTransparencePrimitive2D& rUniTransparenceCandidate)
+{
+ mpOutputDevice->Push(PushFlags::LINECOLOR | PushFlags::FILLCOLOR);
+ // for metafile: Need to examine what the pure vcl version is doing here actually
+ // - uses DrawTransparent with metafile for content and a gradient
+ // - uses DrawTransparent for single PolyPolygons directly. Can be detected by
+ // checking the content for single PolyPolygonColorPrimitive2D
+ const primitive2d::Primitive2DContainer& rContent = rUniTransparenceCandidate.getChildren();
+
+ if (!rContent.empty())
+ {
+ if (0.0 == rUniTransparenceCandidate.getTransparence())
+ {
+ // not transparent at all, use content
+ process(rUniTransparenceCandidate.getChildren());
+ }
+ else if (rUniTransparenceCandidate.getTransparence() > 0.0
+ && rUniTransparenceCandidate.getTransparence() < 1.0)
+ {
+ // try to identify a single PolyPolygonColorPrimitive2D in the
+ // content part of the transparence primitive
+ const primitive2d::PolyPolygonColorPrimitive2D* pPoPoColor = nullptr;
+ static bool bForceToMetafile(false); // loplugin:constvars:ignore
- if(!bForceToBigTransparentVDev && 1 == rTransparence.size())
+ if (!bForceToMetafile && 1 == rContent.size())
{
- const primitive2d::Primitive2DReference xReference(rTransparence[0]);
- pFiGradient = dynamic_cast< const primitive2d::FillGradientPrimitive2D* >(xReference.get());
+ const primitive2d::Primitive2DReference xReference(rContent[0]);
+ pPoPoColor = dynamic_cast<const primitive2d::PolyPolygonColorPrimitive2D*>(
+ xReference.get());
}
+ // PolyPolygonGradientPrimitive2D, PolyPolygonHatchPrimitive2D and
+ // PolyPolygonGraphicPrimitive2D are derived from PolyPolygonColorPrimitive2D.
// Check also for correct ID to exclude derived implementations
- if(pFiGradient && PRIMITIVE2D_ID_FILLGRADIENTPRIMITIVE2D == pFiGradient->getPrimitive2DID())
+ if (pPoPoColor
+ && PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D == pPoPoColor->getPrimitive2DID())
{
- // various content, create content-metafile
- GDIMetaFile aContentMetafile;
- const ::tools::Rectangle aPrimitiveRectangle(impDumpToMetaFile(rContent, aContentMetafile));
+ // single transparent tools::PolyPolygon identified, use directly
+ const basegfx::BColor aPolygonColor(
+ maBColorModifierStack.getModifiedColor(pPoPoColor->getBColor()));
+ basegfx::B2DPolyPolygon aLocalPolyPolygon(pPoPoColor->getB2DPolyPolygon());
- // re-create a VCL-gradient from FillGradientPrimitive2D
- Gradient aVCLGradient;
- impConvertFillGradientAttributeToVCLGradient(aVCLGradient, pFiGradient->getFillGradient(), true);
+ // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
+ // per polygon. Split polygon until there are less than that
+ fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon);
- // render it to VCL
- mpOutputDevice->DrawTransparent(
- aContentMetafile, aPrimitiveRectangle.TopLeft(),
- aPrimitiveRectangle.GetSize(), aVCLGradient);
+ // now transform
+ aLocalPolyPolygon.transform(maCurrentTransformation);
+
+ // set line and fill color
+ const sal_uInt16 nTransPercentVcl(static_cast<sal_uInt16>(
+ basegfx::fround(rUniTransparenceCandidate.getTransparence() * 100.0)));
+ mpOutputDevice->SetFillColor(Color(aPolygonColor));
+ mpOutputDevice->SetLineColor();
+
+ mpOutputDevice->DrawTransparent(tools::PolyPolygon(aLocalPolyPolygon),
+ nTransPercentVcl);
}
else
{
- // sub-transparence group. Draw to VDev first.
- // this may get refined to tiling when resolution is too big here
-
- // need to avoid switching off MapMode stuff here; maybe need another
- // tooling class, cannot just do the same as with the pixel renderer.
- // Need to experiment...
-
- // Okay, basic implementation finished and tested. The DPI stuff was hard
- // and not easy to find out that it's needed.
- // Since this will not yet happen normally (as long as no one constructs
- // transparence primitives with non-trivial transparence content) i will for now not
- // refine to tiling here.
-
- basegfx::B2DRange aViewRange(rContent.getB2DRange(getViewInformation2D()));
- aViewRange.transform(maCurrentTransformation);
- const ::tools::Rectangle aRectLogic(
- static_cast<sal_Int32>(floor(aViewRange.getMinX())), static_cast<sal_Int32>(floor(aViewRange.getMinY())),
- static_cast<sal_Int32>(ceil(aViewRange.getMaxX())), static_cast<sal_Int32>(ceil(aViewRange.getMaxY())));
- const ::tools::Rectangle aRectPixel(mpOutputDevice->LogicToPixel(aRectLogic));
- Size aSizePixel(aRectPixel.GetSize());
- const Point aEmptyPoint;
- ScopedVclPtrInstance< VirtualDevice > aBufferDevice;
- const sal_uInt32 nMaxQuadratPixels(500000);
- const sal_uInt32 nViewVisibleArea(aSizePixel.getWidth() * aSizePixel.getHeight());
- double fReduceFactor(1.0);
-
- if(nViewVisibleArea > nMaxQuadratPixels)
- {
- // reduce render size
- fReduceFactor = sqrt(double(nMaxQuadratPixels) / static_cast<double>(nViewVisibleArea));
- aSizePixel = Size(basegfx::fround(static_cast<double>(aSizePixel.getWidth()) * fReduceFactor),
- basegfx::fround(static_cast<double>(aSizePixel.getHeight()) * fReduceFactor));
- }
+ // save old mfCurrentUnifiedTransparence and set new one
+ // so that contained SvtGraphicStroke may use the current one
+ const double fLastCurrentUnifiedTransparence(mfCurrentUnifiedTransparence);
+ // #i105377# paint the content metafile opaque as the transparency gets
+ // split of into the gradient below
+ // mfCurrentUnifiedTransparence = rUniTransparenceCandidate.getTransparence();
+ mfCurrentUnifiedTransparence = 0;
- if(aBufferDevice->SetOutputSizePixel(aSizePixel))
- {
- // create and set MapModes for target devices
- MapMode aNewMapMode(mpOutputDevice->GetMapMode());
- aNewMapMode.SetOrigin(Point(-aRectLogic.Left(), -aRectLogic.Top()));
- aBufferDevice->SetMapMode(aNewMapMode);
-
- // prepare view transformation for target renderers
- // ATTENTION! Need to apply another scaling because of the potential DPI differences
- // between Printer and VDev (mpOutputDevice and aBufferDevice here).
- // To get the DPI, LogicToPixel from (1,1) from MapUnit::MapInch needs to be used.
- basegfx::B2DHomMatrix aViewTransform(aBufferDevice->GetViewTransformation());
- const Size aDPIOld(mpOutputDevice->LogicToPixel(Size(1, 1), MapMode(MapUnit::MapInch)));
- const Size aDPINew(aBufferDevice->LogicToPixel(Size(1, 1), MapMode(MapUnit::MapInch)));
- const double fDPIXChange(static_cast<double>(aDPIOld.getWidth()) / static_cast<double>(aDPINew.getWidth()));
- const double fDPIYChange(static_cast<double>(aDPIOld.getHeight()) / static_cast<double>(aDPINew.getHeight()));
-
- if(!basegfx::fTools::equal(fDPIXChange, 1.0) || !basegfx::fTools::equal(fDPIYChange, 1.0))
- {
- aViewTransform.scale(fDPIXChange, fDPIYChange);
- }
-
- // also take scaling from Size reduction into account
- if(!basegfx::fTools::equal(fReduceFactor, 1.0))
- {
- aViewTransform.scale(fReduceFactor, fReduceFactor);
- }
-
- // create view information and pixel renderer. Reuse known ViewInformation
- // except new transformation and range
- const geometry::ViewInformation2D aViewInfo(
- getViewInformation2D().getObjectTransformation(),
- aViewTransform,
- aViewRange,
- getViewInformation2D().getVisualizedPage(),
- getViewInformation2D().getViewTime(),
- getViewInformation2D().getExtendedInformationSequence());
-
- VclPixelProcessor2D aBufferProcessor(aViewInfo, *aBufferDevice);
-
- // draw content using pixel renderer
- aBufferProcessor.process(rContent);
- const Bitmap aBmContent(aBufferDevice->GetBitmap(aEmptyPoint, aSizePixel));
-
- // draw transparence using pixel renderer
- aBufferDevice->Erase();
- aBufferProcessor.process(rTransparence);
- const AlphaMask aBmAlpha(aBufferDevice->GetBitmap(aEmptyPoint, aSizePixel));
-
- // paint
- mpOutputDevice->DrawBitmapEx(
- aRectLogic.TopLeft(),
- aRectLogic.GetSize(),
- BitmapEx(aBmContent, aBmAlpha));
- }
+ // various content, create content-metafile
+ GDIMetaFile aContentMetafile;
+ const tools::Rectangle aPrimitiveRectangle(
+ impDumpToMetaFile(rContent, aContentMetafile));
+
+ // restore mfCurrentUnifiedTransparence; it may have been used
+ // while processing the sub-content in impDumpToMetaFile
+ mfCurrentUnifiedTransparence = fLastCurrentUnifiedTransparence;
+
+ // create uniform VCL gradient for uniform transparency
+ Gradient aVCLGradient;
+ const sal_uInt8 nTransPercentVcl(static_cast<sal_uInt8>(
+ basegfx::fround(rUniTransparenceCandidate.getTransparence() * 255.0)));
+ const Color aTransColor(nTransPercentVcl, nTransPercentVcl, nTransPercentVcl);
+
+ aVCLGradient.SetStyle(GradientStyle::Linear);
+ aVCLGradient.SetStartColor(aTransColor);
+ aVCLGradient.SetEndColor(aTransColor);
+ aVCLGradient.SetAngle(0);
+ aVCLGradient.SetBorder(0);
+ aVCLGradient.SetOfsX(0);
+ aVCLGradient.SetOfsY(0);
+ aVCLGradient.SetStartIntensity(100);
+ aVCLGradient.SetEndIntensity(100);
+ aVCLGradient.SetSteps(2);
+
+ // render it to VCL
+ mpOutputDevice->DrawTransparent(aContentMetafile, aPrimitiveRectangle.TopLeft(),
+ aPrimitiveRectangle.GetSize(), aVCLGradient);
}
}
+ }
+
+ mpOutputDevice->Pop();
+}
+
+void VclMetafileProcessor2D::processTransparencePrimitive2D(
+ const primitive2d::TransparencePrimitive2D& rTransparenceCandidate)
+{
+ // for metafile: Need to examine what the pure vcl version is doing here actually
+ // - uses DrawTransparent with metafile for content and a gradient
+ // i can detect this here with checking the gradient part for a single
+ // FillGradientPrimitive2D and reconstruct the gradient.
+ // If that detection goes wrong, I have to create a transparence-blended bitmap. Eventually
+ // do that in stripes, else RenderTransparencePrimitive2D may just be used
+ const primitive2d::Primitive2DContainer& rContent = rTransparenceCandidate.getChildren();
+ const primitive2d::Primitive2DContainer& rTransparence
+ = rTransparenceCandidate.getTransparence();
+
+ if (rContent.empty() || rTransparence.empty())
+ return;
+
+ // try to identify a single FillGradientPrimitive2D in the
+ // transparence part of the primitive
+ const primitive2d::FillGradientPrimitive2D* pFiGradient = nullptr;
+ static bool bForceToBigTransparentVDev(false); // loplugin:constvars:ignore
+
+ if (!bForceToBigTransparentVDev && 1 == rTransparence.size())
+ {
+ const primitive2d::Primitive2DReference xReference(rTransparence[0]);
+ pFiGradient = dynamic_cast<const primitive2d::FillGradientPrimitive2D*>(xReference.get());
+ }
- void VclMetafileProcessor2D::processStructureTagPrimitive2D(const primitive2d::StructureTagPrimitive2D& rStructureTagCandidate)
+ // Check also for correct ID to exclude derived implementations
+ if (pFiGradient && PRIMITIVE2D_ID_FILLGRADIENTPRIMITIVE2D == pFiGradient->getPrimitive2DID())
+ {
+ // various content, create content-metafile
+ GDIMetaFile aContentMetafile;
+ const tools::Rectangle aPrimitiveRectangle(impDumpToMetaFile(rContent, aContentMetafile));
+
+ // re-create a VCL-gradient from FillGradientPrimitive2D
+ Gradient aVCLGradient;
+ impConvertFillGradientAttributeToVCLGradient(aVCLGradient, pFiGradient->getFillGradient(),
+ true);
+
+ // render it to VCL
+ mpOutputDevice->DrawTransparent(aContentMetafile, aPrimitiveRectangle.TopLeft(),
+ aPrimitiveRectangle.GetSize(), aVCLGradient);
+ }
+ else
+ {
+ // sub-transparence group. Draw to VDev first.
+ // this may get refined to tiling when resolution is too big here
+
+ // need to avoid switching off MapMode stuff here; maybe need another
+ // tooling class, cannot just do the same as with the pixel renderer.
+ // Need to experiment...
+
+ // Okay, basic implementation finished and tested. The DPI stuff was hard
+ // and not easy to find out that it's needed.
+ // Since this will not yet happen normally (as long as no one constructs
+ // transparence primitives with non-trivial transparence content) i will for now not
+ // refine to tiling here.
+
+ basegfx::B2DRange aViewRange(rContent.getB2DRange(getViewInformation2D()));
+ aViewRange.transform(maCurrentTransformation);
+ const tools::Rectangle aRectLogic(static_cast<sal_Int32>(floor(aViewRange.getMinX())),
+ static_cast<sal_Int32>(floor(aViewRange.getMinY())),
+ static_cast<sal_Int32>(ceil(aViewRange.getMaxX())),
+ static_cast<sal_Int32>(ceil(aViewRange.getMaxY())));
+ const tools::Rectangle aRectPixel(mpOutputDevice->LogicToPixel(aRectLogic));
+ Size aSizePixel(aRectPixel.GetSize());
+ const Point aEmptyPoint;
+ ScopedVclPtrInstance<VirtualDevice> aBufferDevice;
+ const sal_uInt32 nMaxQuadratPixels(500000);
+ const sal_uInt32 nViewVisibleArea(aSizePixel.getWidth() * aSizePixel.getHeight());
+ double fReduceFactor(1.0);
+
+ if (nViewVisibleArea > nMaxQuadratPixels)
{
- // structured tag primitive
- const vcl::PDFWriter::StructElement& rTagElement(rStructureTagCandidate.getStructureElement());
- bool bTagUsed((vcl::PDFWriter::NonStructElement != rTagElement));
+ // reduce render size
+ fReduceFactor = sqrt(double(nMaxQuadratPixels) / static_cast<double>(nViewVisibleArea));
+ aSizePixel = Size(
+ basegfx::fround(static_cast<double>(aSizePixel.getWidth()) * fReduceFactor),
+ basegfx::fround(static_cast<double>(aSizePixel.getHeight()) * fReduceFactor));
+ }
- if(mpPDFExtOutDevData && bTagUsed)
+ if (aBufferDevice->SetOutputSizePixel(aSizePixel))
+ {
+ // create and set MapModes for target devices
+ MapMode aNewMapMode(mpOutputDevice->GetMapMode());
+ aNewMapMode.SetOrigin(Point(-aRectLogic.Left(), -aRectLogic.Top()));
+ aBufferDevice->SetMapMode(aNewMapMode);
+
+ // prepare view transformation for target renderers
+ // ATTENTION! Need to apply another scaling because of the potential DPI differences
+ // between Printer and VDev (mpOutputDevice and aBufferDevice here).
+ // To get the DPI, LogicToPixel from (1,1) from MapUnit::MapInch needs to be used.
+ basegfx::B2DHomMatrix aViewTransform(aBufferDevice->GetViewTransformation());
+ const Size aDPIOld(mpOutputDevice->LogicToPixel(Size(1, 1), MapMode(MapUnit::MapInch)));
+ const Size aDPINew(aBufferDevice->LogicToPixel(Size(1, 1), MapMode(MapUnit::MapInch)));
+ const double fDPIXChange(static_cast<double>(aDPIOld.getWidth())
+ / static_cast<double>(aDPINew.getWidth()));
+ const double fDPIYChange(static_cast<double>(aDPIOld.getHeight())
+ / static_cast<double>(aDPINew.getHeight()));
+
+ if (!basegfx::fTools::equal(fDPIXChange, 1.0)
+ || !basegfx::fTools::equal(fDPIYChange, 1.0))
{
- // foreground object: tag as regular structure element
- if (!rStructureTagCandidate.isBackground())
- {
- mpPDFExtOutDevData->BeginStructureElement(rTagElement);
- }
- // background object
- else
- {
- // background image: tag as artifact
- if (rStructureTagCandidate.isImage())
- mpPDFExtOutDevData->BeginStructureElement(vcl::PDFWriter::NonStructElement);
- // any other background object: do not tag
- else
- bTagUsed = false;
- }
+ aViewTransform.scale(fDPIXChange, fDPIYChange);
}
- // process children normally
- process(rStructureTagCandidate.getChildren());
-
- if(mpPDFExtOutDevData && bTagUsed)
+ // also take scaling from Size reduction into account
+ if (!basegfx::fTools::equal(fReduceFactor, 1.0))
{
- // write end tag
- mpPDFExtOutDevData->EndStructureElement();
+ aViewTransform.scale(fReduceFactor, fReduceFactor);
}
+
+ // create view information and pixel renderer. Reuse known ViewInformation
+ // except new transformation and range
+ const geometry::ViewInformation2D aViewInfo(
+ getViewInformation2D().getObjectTransformation(), aViewTransform, aViewRange,
+ getViewInformation2D().getVisualizedPage(), getViewInformation2D().getViewTime(),
+ getViewInformation2D().getExtendedInformationSequence());
+
+ VclPixelProcessor2D aBufferProcessor(aViewInfo, *aBufferDevice);
+
+ // draw content using pixel renderer
+ aBufferProcessor.process(rContent);
+ const Bitmap aBmContent(aBufferDevice->GetBitmap(aEmptyPoint, aSizePixel));
+
+ // draw transparence using pixel renderer
+ aBufferDevice->Erase();
+ aBufferProcessor.process(rTransparence);
+ const AlphaMask aBmAlpha(aBufferDevice->GetBitmap(aEmptyPoint, aSizePixel));
+
+ // paint
+ mpOutputDevice->DrawBitmapEx(aRectLogic.TopLeft(), aRectLogic.GetSize(),
+ BitmapEx(aBmContent, aBmAlpha));
+ }
+ }
+}
+
+void VclMetafileProcessor2D::processStructureTagPrimitive2D(
+ const primitive2d::StructureTagPrimitive2D& rStructureTagCandidate)
+{
+ // structured tag primitive
+ const vcl::PDFWriter::StructElement& rTagElement(rStructureTagCandidate.getStructureElement());
+ bool bTagUsed((vcl::PDFWriter::NonStructElement != rTagElement));
+
+ if (mpPDFExtOutDevData && bTagUsed)
+ {
+ // foreground object: tag as regular structure element
+ if (!rStructureTagCandidate.isBackground())
+ {
+ mpPDFExtOutDevData->BeginStructureElement(rTagElement);
}
+ // background object
+ else
+ {
+ // background image: tag as artifact
+ if (rStructureTagCandidate.isImage())
+ mpPDFExtOutDevData->BeginStructureElement(vcl::PDFWriter::NonStructElement);
+ // any other background object: do not tag
+ else
+ bTagUsed = false;
+ }
+ }
+
+ // process children normally
+ process(rStructureTagCandidate.getChildren());
+
+ if (mpPDFExtOutDevData && bTagUsed)
+ {
+ // write end tag
+ mpPDFExtOutDevData->EndStructureElement();
+ }
+}
} // end of namespace
diff --git a/drawinglayer/source/processor2d/vclmetafileprocessor2d.hxx b/drawinglayer/source/processor2d/vclmetafileprocessor2d.hxx
index bf2cc266a685..0393039f4455 100644
--- a/drawinglayer/source/processor2d/vclmetafileprocessor2d.hxx
+++ b/drawinglayer/source/processor2d/vclmetafileprocessor2d.hxx
@@ -27,163 +27,182 @@
#include <vcl/pdfextoutdevdata.hxx> // vcl::PDFExtOutDevData support
class GDIMetaFile;
-namespace tools { class Rectangle; }
+namespace tools
+{
+class Rectangle;
+}
class Gradient;
class SvtGraphicFill;
class SvtGraphicStroke;
-namespace drawinglayer::attribute {
- class FillGradientAttribute;
- class LineAttribute;
- class StrokeAttribute;
- class LineStartEndAttribute;
+namespace drawinglayer::attribute
+{
+class FillGradientAttribute;
+class LineAttribute;
+class StrokeAttribute;
+class LineStartEndAttribute;
}
-namespace drawinglayer::primitive2d {
- class GraphicPrimitive2D;
- class ControlPrimitive2D;
- class TextHierarchyFieldPrimitive2D;
- class TextHierarchyLinePrimitive2D;
- class TextHierarchyBulletPrimitive2D;
- class TextHierarchyParagraphPrimitive2D;
- class TextHierarchyBlockPrimitive2D;
- class TextSimplePortionPrimitive2D;
- class PolygonHairlinePrimitive2D;
- class PolygonStrokePrimitive2D;
- class PolygonStrokeArrowPrimitive2D;
- class PolyPolygonGraphicPrimitive2D;
- class PolyPolygonHatchPrimitive2D;
- class PolyPolygonGradientPrimitive2D;
- class PolyPolygonColorPrimitive2D;
- class MaskPrimitive2D;
- class UnifiedTransparencePrimitive2D;
- class TransparencePrimitive2D;
- class StructureTagPrimitive2D;
+namespace drawinglayer::primitive2d
+{
+class GraphicPrimitive2D;
+class ControlPrimitive2D;
+class TextHierarchyFieldPrimitive2D;
+class TextHierarchyLinePrimitive2D;
+class TextHierarchyBulletPrimitive2D;
+class TextHierarchyParagraphPrimitive2D;
+class TextHierarchyBlockPrimitive2D;
+class TextSimplePortionPrimitive2D;
+class PolygonHairlinePrimitive2D;
+class PolygonStrokePrimitive2D;
+class PolygonStrokeArrowPrimitive2D;
+class PolyPolygonGraphicPrimitive2D;
+class PolyPolygonHatchPrimitive2D;
+class PolyPolygonGradientPrimitive2D;
+class PolyPolygonColorPrimitive2D;
+class MaskPrimitive2D;
+class UnifiedTransparencePrimitive2D;
+class TransparencePrimitive2D;
+class StructureTagPrimitive2D;
}
-namespace basegfx {
- class BColor;
+namespace basegfx
+{
+class BColor;
}
namespace drawinglayer::processor2d
{
- /** VclMetafileProcessor2D class
-
- This processor derived from VclProcessor2D is the base class for rendering
- all fed primitives to a classical VCL-Metafile, including all over the
- time grown extra data in comments and PDF exception data creations. Also
- printing needs some exception stuff.
-
- All in all it is needed to emulate the old ::paint output from the old
- Drawinglayer as long as exporters and/or filters still use the Metafile
- and the extra-data added to it (which can be seen mostly as 'extensions'
- or simply as 'hacks').
- */
- class VclMetafileProcessor2D : public VclProcessor2D
- {
- private:
- /// local helper(s)
- ::tools::Rectangle impDumpToMetaFile(
- const primitive2d::Primitive2DContainer& rContent,
- GDIMetaFile& o_rContentMetafile);
- void impConvertFillGradientAttributeToVCLGradient(
- Gradient& o_rVCLGradient,
- const attribute::FillGradientAttribute& rFiGrAtt,
- bool bIsTransparenceGradient) const;
- void impStartSvtGraphicFill(SvtGraphicFill const * pSvtGraphicFill);
- void impEndSvtGraphicFill(SvtGraphicFill const * pSvtGraphicFill);
- std::unique_ptr<SvtGraphicStroke> impTryToCreateSvtGraphicStroke(
- const basegfx::B2DPolygon& rB2DPolygon,
- const basegfx::BColor* pColor,
- const attribute::LineAttribute* pLineAttribute,
- const attribute::StrokeAttribute* pStrokeAttribute,
- const attribute::LineStartEndAttribute* pStart,
- const attribute::LineStartEndAttribute* pEnd);
- void impStartSvtGraphicStroke(SvtGraphicStroke const * pSvtGraphicStroke);
- void impEndSvtGraphicStroke(SvtGraphicStroke const * pSvtGraphicStroke);
- void popStructureElement(vcl::PDFWriter::StructElement eElem);
- void popListItem();
- void popList();
-
- void processGraphicPrimitive2D(const primitive2d::GraphicPrimitive2D& rGraphicPrimitive);
- void processControlPrimitive2D(const primitive2d::ControlPrimitive2D& rControlPrimitive);
- void processTextHierarchyFieldPrimitive2D(const primitive2d::TextHierarchyFieldPrimitive2D& rFieldPrimitive);
- void processTextHierarchyLinePrimitive2D(const primitive2d::TextHierarchyLinePrimitive2D& rLinePrimitive);
- void processTextHierarchyBulletPrimitive2D(const primitive2d::TextHierarchyBulletPrimitive2D& rBulletPrimitive);
- void processTextHierarchyParagraphPrimitive2D(const primitive2d::TextHierarchyParagraphPrimitive2D& rParagraphPrimitive);
- void processTextHierarchyBlockPrimitive2D(const primitive2d::TextHierarchyBlockPrimitive2D& rBlockPrimitive);
- void processTextSimplePortionPrimitive2D(const primitive2d::TextSimplePortionPrimitive2D& rTextCandidate);
- void processPolygonHairlinePrimitive2D(const primitive2d::PolygonHairlinePrimitive2D& rHairlinePrimitive);
- void processPolygonStrokePrimitive2D(const primitive2d::PolygonStrokePrimitive2D& rStrokePrimitive);
- void processPolygonStrokeArrowPrimitive2D(const primitive2d::PolygonStrokeArrowPrimitive2D& rStrokeArrowPrimitive);
- void processPolyPolygonGraphicPrimitive2D(const primitive2d::PolyPolygonGraphicPrimitive2D& rBitmapCandidate);
- void processPolyPolygonHatchPrimitive2D(const primitive2d::PolyPolygonHatchPrimitive2D& rHatchCandidate);
- void processPolyPolygonGradientPrimitive2D(const primitive2d::PolyPolygonGradientPrimitive2D& rGradientCandidate);
- void processPolyPolygonColorPrimitive2D(const primitive2d::PolyPolygonColorPrimitive2D& rPolygonCandidate);
- void processMaskPrimitive2D(const primitive2d::MaskPrimitive2D& rMaskCandidate);
- void processUnifiedTransparencePrimitive2D(const primitive2d::UnifiedTransparencePrimitive2D& rUniTransparenceCandidate);
- void processTransparencePrimitive2D(const primitive2d::TransparencePrimitive2D& rTransparenceCandidate);
- void processStructureTagPrimitive2D(const primitive2d::StructureTagPrimitive2D& rStructureTagCandidate);
-
- /// Convert the fWidth to the same space as its coordinates.
- double getTransformedLineWidth( double fWidth ) const;
-
- /// the current clipping tools::PolyPolygon from MaskPrimitive2D
- basegfx::B2DPolyPolygon maClipPolyPolygon;
-
- /// the target MetaFile
- GDIMetaFile* mpMetaFile;
-
- /* do not allow embedding SvtGraphicFills into each other,
- use a counter to prevent that
- */
- sal_uInt32 mnSvtGraphicFillCount;
-
- /// same for SvtGraphicStroke
- sal_uInt32 mnSvtGraphicStrokeCount;
-
- /* hold the last unified transparence value to have it handy
- on SvtGraphicStroke creation
- */
- double mfCurrentUnifiedTransparence;
-
- /* break iterator support
- made static so it only needs to be fetched once, even with many single
- constructed VclMetafileProcessor2D. It's still incarnated on demand,
- but exists for OOo runtime now by purpose.
- */
- static css::uno::Reference< css::i18n::XBreakIterator > mxBreakIterator;
-
- /* vcl::PDFExtOutDevData support
- For the first step, some extra actions at vcl::PDFExtOutDevData need to
- be emulated with the VclMetafileProcessor2D. These are potentially temporarily
- since PDF export may use PrimitiveSequences one day directly.
- */
- vcl::PDFExtOutDevData* mpPDFExtOutDevData;
-
- // Remember the current OutlineLevel. This is used when tagged PDF export
- // is used to create/write valid structured list entries using PDF statements
- // like '/L', '/LI', 'LBody' instead of simple '/P' (Paragraph).
- // The value -1 means 'no OutlineLevel' and values >= 0 express the level.
- sal_Int16 mnCurrentOutlineLevel;
- bool mbInListItem;
- bool mbBulletPresent;
-
- std::stack<vcl::PDFWriter::StructElement> maListElements;
-
- protected:
- /* the local processor for BasePrimitive2D-Implementation based primitives,
- called from the common process()-implementation
- */
- virtual void processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate) override;
-
- public:
- /// constructor/destructor
- VclMetafileProcessor2D(
- const geometry::ViewInformation2D& rViewInformation,
- OutputDevice& rOutDev);
- virtual ~VclMetafileProcessor2D() override;
- };
+/** VclMetafileProcessor2D class
+
+ This processor derived from VclProcessor2D is the base class for rendering
+ all fed primitives to a classical VCL-Metafile, including all over the
+ time grown extra data in comments and PDF exception data creations. Also
+ printing needs some exception stuff.
+
+ All in all it is needed to emulate the old ::paint output from the old
+ Drawinglayer as long as exporters and/or filters still use the Metafile
+ and the extra-data added to it (which can be seen mostly as 'extensions'
+ or simply as 'hacks').
+ */
+class VclMetafileProcessor2D : public VclProcessor2D
+{
+private:
+ tools::Rectangle impDumpToMetaFile(const primitive2d::Primitive2DContainer& rContent,
+ GDIMetaFile& o_rContentMetafile);
+ void
+ impConvertFillGradientAttributeToVCLGradient(Gradient& o_rVCLGradient,
+ const attribute::FillGradientAttribute& rFiGrAtt,
+ bool bIsTransparenceGradient) const;
+ void impStartSvtGraphicFill(SvtGraphicFill const* pSvtGraphicFill);
+ void impEndSvtGraphicFill(SvtGraphicFill const* pSvtGraphicFill);
+ std::unique_ptr<SvtGraphicStroke>
+ impTryToCreateSvtGraphicStroke(const basegfx::B2DPolygon& rB2DPolygon,
+ const basegfx::BColor* pColor,
+ const attribute::LineAttribute* pLineAttribute,
+ const attribute::StrokeAttribute* pStrokeAttribute,
+ const attribute::LineStartEndAttribute* pStart,
+ const attribute::LineStartEndAttribute* pEnd);
+ void impStartSvtGraphicStroke(SvtGraphicStroke const* pSvtGraphicStroke);
+ void impEndSvtGraphicStroke(SvtGraphicStroke const* pSvtGraphicStroke);
+ void popStructureElement(vcl::PDFWriter::StructElement eElem);
+ void popListItem();
+ void popList();
+
+ void processGraphicPrimitive2D(const primitive2d::GraphicPrimitive2D& rGraphicPrimitive);
+ void processControlPrimitive2D(const primitive2d::ControlPrimitive2D& rControlPrimitive);
+ void processTextHierarchyFieldPrimitive2D(
+ const primitive2d::TextHierarchyFieldPrimitive2D& rFieldPrimitive);
+ void processTextHierarchyLinePrimitive2D(
+ const primitive2d::TextHierarchyLinePrimitive2D& rLinePrimitive);
+ void processTextHierarchyBulletPrimitive2D(
+ const primitive2d::TextHierarchyBulletPrimitive2D& rBulletPrimitive);
+ void processTextHierarchyParagraphPrimitive2D(
+ const primitive2d::TextHierarchyParagraphPrimitive2D& rParagraphPrimitive);
+ void processTextHierarchyBlockPrimitive2D(
+ const primitive2d::TextHierarchyBlockPrimitive2D& rBlockPrimitive);
+ void processTextSimplePortionPrimitive2D(
+ const primitive2d::TextSimplePortionPrimitive2D& rTextCandidate);
+ void processPolygonHairlinePrimitive2D(
+ const primitive2d::PolygonHairlinePrimitive2D& rHairlinePrimitive);
+ void
+ processPolygonStrokePrimitive2D(const primitive2d::PolygonStrokePrimitive2D& rStrokePrimitive);
+ void processPolygonStrokeArrowPrimitive2D(
+ const primitive2d::PolygonStrokeArrowPrimitive2D& rStrokeArrowPrimitive);
+ void processPolyPolygonGraphicPrimitive2D(
+ const primitive2d::PolyPolygonGraphicPrimitive2D& rBitmapCandidate);
+ void processPolyPolygonHatchPrimitive2D(
+ const primitive2d::PolyPolygonHatchPrimitive2D& rHatchCandidate);
+ void processPolyPolygonGradientPrimitive2D(
+ const primitive2d::PolyPolygonGradientPrimitive2D& rGradientCandidate);
+ void processPolyPolygonColorPrimitive2D(
+ const primitive2d::PolyPolygonColorPrimitive2D& rPolygonCandidate);
+ void processMaskPrimitive2D(const primitive2d::MaskPrimitive2D& rMaskCandidate);
+ void processUnifiedTransparencePrimitive2D(
+ const primitive2d::UnifiedTransparencePrimitive2D& rUniTransparenceCandidate);
+ void processTransparencePrimitive2D(
+ const primitive2d::TransparencePrimitive2D& rTransparenceCandidate);
+ void processStructureTagPrimitive2D(
+ const primitive2d::StructureTagPrimitive2D& rStructureTagCandidate);
+
+ /// Convert the fWidth to the same space as its coordinates.
+ double getTransformedLineWidth(double fWidth) const;
+
+ /// the current clipping tools::PolyPolygon from MaskPrimitive2D
+ basegfx::B2DPolyPolygon maClipPolyPolygon;
+
+ /// the target MetaFile
+ GDIMetaFile* mpMetaFile;
+
+ /* do not allow embedding SvtGraphicFills into each other,
+ use a counter to prevent that
+ */
+ sal_uInt32 mnSvtGraphicFillCount;
+
+ /// same for SvtGraphicStroke
+ sal_uInt32 mnSvtGraphicStrokeCount;
+
+ /* hold the last unified transparence value to have it handy
+ on SvtGraphicStroke creation
+ */
+ double mfCurrentUnifiedTransparence;
+
+ /* break iterator support
+ made static so it only needs to be fetched once, even with many single
+ constructed VclMetafileProcessor2D. It's still incarnated on demand,
+ but exists for OOo runtime now by purpose.
+ */
+ static css::uno::Reference<css::i18n::XBreakIterator> mxBreakIterator;
+
+ /* vcl::PDFExtOutDevData support
+ For the first step, some extra actions at vcl::PDFExtOutDevData need to
+ be emulated with the VclMetafileProcessor2D. These are potentially temporarily
+ since PDF export may use PrimitiveSequences one day directly.
+ */
+ vcl::PDFExtOutDevData* mpPDFExtOutDevData;
+
+ // Remember the current OutlineLevel. This is used when tagged PDF export
+ // is used to create/write valid structured list entries using PDF statements
+ // like '/L', '/LI', 'LBody' instead of simple '/P' (Paragraph).
+ // The value -1 means 'no OutlineLevel' and values >= 0 express the level.
+ sal_Int16 mnCurrentOutlineLevel;
+ bool mbInListItem;
+ bool mbBulletPresent;
+
+ std::stack<vcl::PDFWriter::StructElement> maListElements;
+
+protected:
+ /* the local processor for BasePrimitive2D-Implementation based primitives,
+ called from the common process()-implementation
+ */
+ virtual void processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate) override;
+
+public:
+ /// constructor/destructor
+ VclMetafileProcessor2D(const geometry::ViewInformation2D& rViewInformation,
+ OutputDevice& rOutDev);
+ virtual ~VclMetafileProcessor2D() override;
+};
} // end of namespace processor2d::drawinglayer
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */