[Libreoffice-commits] core.git: 2 commits - cppcanvas/source

Jan Holesovsky kendy at collabora.com
Mon Nov 25 13:11:54 PST 2013


 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 <kendy at 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 <kendy at 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);
+                    }
+                }
+
             }
         }
 


More information about the Libreoffice-commits mailing list