cppcanvas/source/inc/implrenderer.hxx | 7 + cppcanvas/source/mtfrenderer/emfplus.cxx | 191 +++++++++++++++++++++++++------ 2 files changed, 164 insertions(+), 34 deletions(-)
New commits: commit ad8875e2a007d918636e1e1a2f6214b0fdf0da04 Author: Jan Holesovsky <ke...@collabora.com> Date: Mon Nov 25 22:09:48 2013 +0100 EMF+: Set the stroke attributes on the custom line caps. This finally makes the rendering of the custom line caps nice & complete. Change-Id: If35ef1c44f34f5d5e6c50789c907105d03e96fca diff --git a/cppcanvas/source/mtfrenderer/emfplus.cxx b/cppcanvas/source/mtfrenderer/emfplus.cxx index 2fa121f0..4907b6f 100644 --- a/cppcanvas/source/mtfrenderer/emfplus.cxx +++ b/cppcanvas/source/mtfrenderer/emfplus.cxx @@ -37,8 +37,10 @@ #include <rtl/ustring.hxx> #include <sal/alloca.h> -#include <com/sun/star/rendering/XCanvas.hpp> +#include <com/sun/star/rendering/PathCapType.hpp> +#include <com/sun/star/rendering/PathJoinType.hpp> #include <com/sun/star/rendering/TexturingMode.hpp> +#include <com/sun/star/rendering/XCanvas.hpp> #include <bitmapaction.hxx> #include <implrenderer.hxx> @@ -103,6 +105,16 @@ const sal_uInt32 EmfPlusCustomLineCapDataTypeAdjustableArrow = 0x00000001; const sal_uInt32 EmfPlusCustomLineCapDataFillPath = 0x00000001; const sal_uInt32 EmfPlusCustomLineCapDataLinePath = 0x00000002; +const sal_uInt32 EmfPlusLineCapTypeFlat = 0x00000000; +const sal_uInt32 EmfPlusLineCapTypeSquare = 0x00000001; +const sal_uInt32 EmfPlusLineCapTypeRound = 0x00000002; +const sal_uInt32 EmfPlusLineCapTypeTriangle = 0x00000003; + +const sal_uInt32 EmfPlusLineJoinTypeMiter = 0x00000000; +const sal_uInt32 EmfPlusLineJoinTypeBevel = 0x00000001; +const sal_uInt32 EmfPlusLineJoinTypeRound = 0x00000002; +const sal_uInt32 EmfPlusLineJoinTypeMiterClipped = 0x00000003; + using namespace ::com::sun::star; using namespace ::basegfx; @@ -594,9 +606,25 @@ namespace cppcanvas } }; + /// Convert stroke caps between EMF+ and rendering API + sal_Int8 lcl_convertStrokeCap(sal_uInt32 nEmfStroke) + { + switch (nEmfStroke) + { + case EmfPlusLineCapTypeSquare: return rendering::PathCapType::SQUARE; + case EmfPlusLineCapTypeRound: return rendering::PathCapType::ROUND; + } + + // we have no mapping for EmfPlusLineCapTypeTriangle, so return + // BUTT always + return rendering::PathCapType::BUTT; + } + struct EMFPCustomLineCap : public EMFPObject { sal_uInt32 type; + sal_uInt32 strokeStartCap, strokeEndCap, strokeJoin; + float miterLimit; basegfx::B2DPolyPolygon polygon; public: @@ -608,6 +636,22 @@ namespace cppcanvas { } + void SetAttributes(rendering::StrokeAttributes& aAttributes) + { + aAttributes.StartCapType = lcl_convertStrokeCap(strokeStartCap); + aAttributes.EndCapType = lcl_convertStrokeCap(strokeEndCap); + + switch (strokeJoin) + { + case EmfPlusLineJoinTypeMiter: // fall-through + case EmfPlusLineJoinTypeMiterClipped: aAttributes.JoinType = rendering::PathJoinType::MITER; break; + case EmfPlusLineJoinTypeBevel: aAttributes.JoinType = rendering::PathJoinType::BEVEL; break; + case EmfPlusLineJoinTypeRound: aAttributes.JoinType = rendering::PathJoinType::ROUND; break; + } + + aAttributes.MiterLimit = miterLimit; + } + void ReadPath(SvStream& s, ImplRenderer& rR, bool bClosed) { sal_Int32 pathLength; @@ -648,13 +692,12 @@ namespace cppcanvas { sal_uInt32 customLineCapDataFlags, baseCap; float baseInset; - sal_uInt32 strokeStartCap, strokeEndCap, strokeJoin; - float strokeMiterLimit, widthScale; + float widthScale; float fillHotSpotX, fillHotSpotY, strokeHotSpotX, strokeHotSpotY; s >> customLineCapDataFlags >> baseCap >> baseInset >> strokeStartCap >> strokeEndCap >> strokeJoin - >> strokeMiterLimit >> widthScale + >> miterLimit >> widthScale >> fillHotSpotX >> fillHotSpotY >> strokeHotSpotX >> strokeHotSpotY; SAL_INFO("cppcanvas.emf", "EMF+\t\tcustomLineCapDataFlags: 0x" << std::hex << customLineCapDataFlags); @@ -663,7 +706,7 @@ namespace cppcanvas SAL_INFO("cppcanvas.emf", "EMF+\t\tstrokeStartCap: 0x" << std::hex << strokeStartCap); SAL_INFO("cppcanvas.emf", "EMF+\t\tstrokeEndCap: 0x" << std::hex << strokeEndCap); SAL_INFO("cppcanvas.emf", "EMF+\t\tstrokeJoin: 0x" << std::hex << strokeJoin); - SAL_INFO("cppcanvas.emf", "EMF+\t\tstrokeMiterLimit: " << strokeMiterLimit); + SAL_INFO("cppcanvas.emf", "EMF+\t\tmiterLimit: " << miterLimit); SAL_INFO("cppcanvas.emf", "EMF+\t\twidthScale: " << widthScale); if (customLineCapDataFlags & EmfPlusCustomLineCapDataFillPath) @@ -682,11 +725,11 @@ namespace cppcanvas // no test document to be able to implement it] sal_Int32 width, height, middleInset, fillState, lineStartCap; - sal_Int32 lineEndCap, lineJoin, lineMiterLimit, widthScale; + sal_Int32 lineEndCap, lineJoin, widthScale; float fillHotSpotX, fillHotSpotY, lineHotSpotX, lineHotSpotY; s >> width >> height >> middleInset >> fillState >> lineStartCap - >> lineEndCap >> lineJoin >> lineMiterLimit >> widthScale + >> lineEndCap >> lineJoin >> miterLimit >> widthScale >> fillHotSpotX >> fillHotSpotY >> lineHotSpotX >> lineHotSpotY; SAL_INFO("cppcanvas.emf", "EMF+\t\tTODO - actually read EmfPlusCustomLineCapArrowData object (section 2.2.2.12)"); @@ -1358,13 +1401,23 @@ namespace cppcanvas // line start if (pen->customStartCap) + { + rendering::StrokeAttributes aAttributes(aCommonAttributes); + pen->customStartCap->SetAttributes(aAttributes); + EMFPPlusDrawLineCap(aPolygon, fPolyLength, pen->customStartCap->polygon, - true, aCommonAttributes, rParms, rState); + true, aAttributes, rParms, rState); + } // line end if (pen->customEndCap) + { + rendering::StrokeAttributes aAttributes(aCommonAttributes); + pen->customEndCap->SetAttributes(aAttributes); + EMFPPlusDrawLineCap(aPolygon, fPolyLength, pen->customEndCap->polygon, - false, aCommonAttributes, rParms, rState); + false, aAttributes, rParms, rState); + } } } commit ff98a070eb03b5c3fe97053ce7afda70b1e74677 Author: Jan Holesovsky <ke...@collabora.com> Date: Mon Nov 25 21:35:26 2013 +0100 EMF+: Render custom line cap data. Change-Id: Ic5e2e2d105fb006503b63e4e162d4dc09dab9e68 diff --git a/cppcanvas/source/inc/implrenderer.hxx b/cppcanvas/source/inc/implrenderer.hxx index 02fc003..c649db3 100644 --- a/cppcanvas/source/inc/implrenderer.hxx +++ b/cppcanvas/source/inc/implrenderer.hxx @@ -280,6 +280,13 @@ static float GetSwapFloat( SvStream& rSt ) /* EMF+ */ void processEMFPlus( MetaCommentAction* pAct, const ActionFactoryParameters& rFactoryParms, OutDevState& rState, const CanvasSharedPtr& rCanvas ); double setFont( sal_uInt8 objectId, const ActionFactoryParameters& rParms, OutDevState& rState ); + + /// Render LineCap, like the start or end arrow of a polygon. + void EMFPPlusDrawLineCap(const ::basegfx::B2DPolygon& rPolygon, double fPolyLength, + const ::basegfx::B2DPolyPolygon& rLineCap, bool bStart, + const com::sun::star::rendering::StrokeAttributes& rAttributes, + const ActionFactoryParameters& rParms, OutDevState& rState); + void EMFPPlusDrawPolygon (const ::basegfx::B2DPolyPolygon& polygon, const ActionFactoryParameters& rParms, OutDevState& rState, const CanvasSharedPtr& rCanvas, sal_uInt32 penIndex); void EMFPPlusFillPolygon (::basegfx::B2DPolyPolygon& polygon, const ActionFactoryParameters& rParms, OutDevState& rState, const CanvasSharedPtr& rCanvas, bool isColor, sal_uInt32 brushIndexOrColor); diff --git a/cppcanvas/source/mtfrenderer/emfplus.cxx b/cppcanvas/source/mtfrenderer/emfplus.cxx index 69568d3..2fa121f0 100644 --- a/cppcanvas/source/mtfrenderer/emfplus.cxx +++ b/cppcanvas/source/mtfrenderer/emfplus.cxx @@ -597,6 +597,7 @@ namespace cppcanvas struct EMFPCustomLineCap : public EMFPObject { sal_uInt32 type; + basegfx::B2DPolyPolygon polygon; public: EMFPCustomLineCap() : EMFPObject() @@ -607,6 +608,33 @@ namespace cppcanvas { } + void ReadPath(SvStream& s, ImplRenderer& rR, bool bClosed) + { + sal_Int32 pathLength; + s >> pathLength; + SAL_INFO("cppcanvas.emf", "EMF+\t\tpath length: " << pathLength); + + sal_uInt32 pathHeader; + sal_Int32 pathPoints, pathFlags; + s >> pathHeader >> pathPoints >> pathFlags; + + SAL_INFO("cppcanvas.emf", "EMF+\t\tpath (custom cap line path)"); + SAL_INFO("cppcanvas.emf", "EMF+\t\theader: 0x" << std::hex << pathHeader << " points: " << std::dec << pathPoints << " additional flags: 0x" << std::hex << pathFlags << std::dec ); + + EMFPPath path(pathPoints); + path.Read(s, pathFlags, rR); + + polygon = path.GetPolygon(rR, false); + polygon.setClosed(bClosed); + + // transformation to convert the path to what LibreOffice + // expects + B2DHomMatrix aMatrix; + aMatrix.scale(1.0, -1.0); + + polygon.transform(aMatrix); + }; + void Read (SvStream& s, ImplRenderer& rR) { sal_uInt32 header; @@ -618,9 +646,10 @@ namespace cppcanvas if (type == EmfPlusCustomLineCapDataTypeDefault) { - sal_Int32 customLineCapDataFlags, baseCap, baseInset; - sal_Int32 strokeStartCap, strokeEndCap, strokeJoin; - sal_Int32 strokeMiterLimit, widthScale; + sal_uInt32 customLineCapDataFlags, baseCap; + float baseInset; + sal_uInt32 strokeStartCap, strokeEndCap, strokeJoin; + float strokeMiterLimit, widthScale; float fillHotSpotX, fillHotSpotY, strokeHotSpotX, strokeHotSpotY; s >> customLineCapDataFlags >> baseCap >> baseInset @@ -628,40 +657,23 @@ namespace cppcanvas >> strokeMiterLimit >> widthScale >> fillHotSpotX >> fillHotSpotY >> strokeHotSpotX >> strokeHotSpotY; - SAL_INFO("cppcanvas.emf", "EMF+\t\tcustomLinCapDataFlags: 0x" << std::hex << customLineCapDataFlags); + SAL_INFO("cppcanvas.emf", "EMF+\t\tcustomLineCapDataFlags: 0x" << std::hex << customLineCapDataFlags); + SAL_INFO("cppcanvas.emf", "EMF+\t\tbaseCap: 0x" << std::hex << baseCap); + SAL_INFO("cppcanvas.emf", "EMF+\t\tbaseInset: " << baseInset); + SAL_INFO("cppcanvas.emf", "EMF+\t\tstrokeStartCap: 0x" << std::hex << strokeStartCap); + SAL_INFO("cppcanvas.emf", "EMF+\t\tstrokeEndCap: 0x" << std::hex << strokeEndCap); + SAL_INFO("cppcanvas.emf", "EMF+\t\tstrokeJoin: 0x" << std::hex << strokeJoin); + SAL_INFO("cppcanvas.emf", "EMF+\t\tstrokeMiterLimit: " << strokeMiterLimit); + SAL_INFO("cppcanvas.emf", "EMF+\t\twidthScale: " << widthScale); if (customLineCapDataFlags & EmfPlusCustomLineCapDataFillPath) { - sal_Int32 pathLength; - s >> pathLength; - SAL_INFO("cppcanvas.emf", "EMF+\t\tpath length: " << pathLength); - - sal_uInt32 pathHeader; - sal_Int32 pathPoints, pathFlags; - s >> pathHeader >> pathPoints >> pathFlags; - - SAL_INFO("cppcanvas.emf", "EMF+\t\tpath (custom cap fill path)"); - SAL_INFO("cppcanvas.emf", "EMF+\t\theader: 0x" << std::hex << pathHeader << " points: " << std::dec << pathPoints << " additional flags: 0x" << std::hex << pathFlags << std::dec ); - - EMFPPath path(pathPoints); - path.Read(s, pathFlags, rR); + ReadPath(s, rR, true); } if (customLineCapDataFlags & EmfPlusCustomLineCapDataLinePath) { - sal_Int32 pathLength; - s >> pathLength; - SAL_INFO("cppcanvas.emf", "EMF+\t\tpath length: " << pathLength); - - sal_uInt32 pathHeader; - sal_Int32 pathPoints, pathFlags; - s >> pathHeader >> pathPoints >> pathFlags; - - SAL_INFO("cppcanvas.emf", "EMF+\t\tpath (custom cap line path)"); - SAL_INFO("cppcanvas.emf", "EMF+\t\theader: 0x" << std::hex << pathHeader << " points: " << std::dec << pathPoints << " additional flags: 0x" << std::hex << pathFlags << std::dec ); - - EMFPPath path(pathPoints); - path.Read(s, pathFlags, rR); + ReadPath(s, rR, false); } } else if (type == EmfPlusCustomLineCapDataTypeAdjustableArrow) @@ -1264,6 +1276,38 @@ namespace cppcanvas } } + + void ImplRenderer::EMFPPlusDrawLineCap(const ::basegfx::B2DPolygon& rPolygon, double fPolyLength, + const ::basegfx::B2DPolyPolygon& rLineCap, bool bStart, const rendering::StrokeAttributes& rAttributes, + const ActionFactoryParameters& rParms, OutDevState& rState) + { + if (!rLineCap.count()) + return; + + // it seems the line caps in EMF+ are 4*larger than what + // LibreOffice expects, and the mapping in + // createAreaGeometryForLineStartEnd scales that down, so + // correct it + // [unfortunately found no proof for this in the spec :-( - please + // feel free to correct this if it causes trouble] + double fWidth = rAttributes.StrokeWidth*4; + + basegfx::B2DPolyPolygon aArrow(basegfx::tools::createAreaGeometryForLineStartEnd( + rPolygon, rLineCap, bStart, + fWidth, fPolyLength, 0.0, NULL)); + + // createAreaGeometryForLineStartEnd from some reason always sets + // the path as closed, correct it + aArrow.setClosed(rLineCap.isClosed()); + + ActionSharedPtr pAction(internal::PolyPolyActionFactory::createPolyPolyAction(aArrow, rParms.mrCanvas, rState, rAttributes)); + if (pAction) + { + maActions.push_back(MtfAction(pAction, rParms.mrCurrActionIndex)); + rParms.mrCurrActionIndex += pAction->getActionCount()-1; + } + } + void ImplRenderer::EMFPPlusDrawPolygon (const ::basegfx::B2DPolyPolygon& polygon, const ActionFactoryParameters& rParms, OutDevState& rState, const CanvasSharedPtr& rCanvas, sal_uInt32 penIndex) { @@ -1298,6 +1342,32 @@ namespace cppcanvas maActions.push_back(MtfAction(pPolyAction, rParms.mrCurrActionIndex)); rParms.mrCurrActionIndex += pPolyAction->getActionCount()-1; } + + // render line starts & ends + if (pen->customStartCap || pen->customEndCap) + { + for (sal_uInt32 i = 0; i < aPolyPolygon.count(); ++i) + { + // break the polypolygon into polygons + basegfx::B2DPolygon aPolygon(aPolyPolygon.getB2DPolygon(i)); + + if (aPolygon.isClosed()) + continue; + + double fPolyLength = basegfx::tools::getLength(aPolygon); + + // line start + if (pen->customStartCap) + EMFPPlusDrawLineCap(aPolygon, fPolyLength, pen->customStartCap->polygon, + true, aCommonAttributes, rParms, rState); + + // line end + if (pen->customEndCap) + EMFPPlusDrawLineCap(aPolygon, fPolyLength, pen->customEndCap->polygon, + false, aCommonAttributes, rParms, rState); + } + } + } } _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits