[Libreoffice-commits] core.git: Branch 'distro/collabora/cp-4.0' - 4 commits - cppcanvas/source vcl/source

Jan Holesovsky kendy at collabora.com
Tue Nov 26 02:04:22 PST 2013


 cppcanvas/source/inc/implrenderer.hxx    |    9 
 cppcanvas/source/mtfrenderer/emfplus.cxx |  365 ++++++++++++++++++++++++++++---
 vcl/source/filter/wmf/enhwmf.cxx         |   14 -
 vcl/source/filter/wmf/winmtf.cxx         |  146 ++++++++----
 vcl/source/filter/wmf/winmtf.hxx         |   20 +
 vcl/source/filter/wmf/winwmf.cxx         |    1 
 6 files changed, 462 insertions(+), 93 deletions(-)

New commits:
commit 3a7c314e77ef2e619136f00c949aee30b1ae9cd1
Author: Jan Holesovsky <kendy at collabora.com>
Date:   Fri Nov 22 17:06:10 2013 +0100

    EMF+: Parse and render custom line cap data.
    
    Contains the following commits:
    
    * EMF+: Small cleanup & more logging in preparation for line starts & ends.
    * EMF+: Parse custom line cap data for start and end line caps.
    * EMF+: Render custom line cap data.
    * EMF+: Set the stroke attributes on the custom line caps.
    
    Change-Id: If35ef1c44f34f5d5e6c50789c907105d03e96fca

diff --git a/cppcanvas/source/inc/implrenderer.hxx b/cppcanvas/source/inc/implrenderer.hxx
index 4d5918b..786af41 100644
--- a/cppcanvas/source/inc/implrenderer.hxx
+++ b/cppcanvas/source/inc/implrenderer.hxx
@@ -276,7 +276,14 @@ 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 );
-            void EMFPPlusDrawPolygon (::basegfx::B2DPolyPolygon& polygon, const ActionFactoryParameters& rParms, OutDevState& rState, const CanvasSharedPtr& rCanvas, sal_uInt32 penIndex);
+
+            /// 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);
 
             ActionVector maActions;
diff --git a/cppcanvas/source/mtfrenderer/emfplus.cxx b/cppcanvas/source/mtfrenderer/emfplus.cxx
index 72926a0..f663638 100644
--- a/cppcanvas/source/mtfrenderer/emfplus.cxx
+++ b/cppcanvas/source/mtfrenderer/emfplus.cxx
@@ -28,6 +28,7 @@
 #include <basegfx/vector/b2dsize.hxx>
 #include <basegfx/range/b2drange.hxx>
 #include <basegfx/range/b2drectangle.hxx>
+#include <basegfx/polygon/b2dlinegeometry.hxx>
 #include <basegfx/polygon/b2dpolygon.hxx>
 #include <basegfx/polygon/b2dpolygontools.hxx>
 #include <basegfx/polygon/b2dpolypolygon.hxx>
@@ -36,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>
@@ -99,6 +102,22 @@ const sal_Int32 EmfPlusLineStyleDashDot = 0x00000003;
 const sal_Int32 EmfPlusLineStyleDashDotDot = 0x00000004;
 const sal_Int32 EmfPlusLineStyleCustom = 0x00000005;
 
+const sal_uInt32 EmfPlusCustomLineCapDataTypeDefault = 0x00000000;
+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;
+
 #if OSL_DEBUG_LEVEL > 1
 #define EMFP_DEBUG(x) x
 #else
@@ -582,6 +601,137 @@ 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:
+            EMFPCustomLineCap() : EMFPObject()
+            {
+            }
+
+            ~EMFPCustomLineCap()
+            {
+            }
+
+            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;
+                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;
+
+                s >> header >> type;
+
+                SAL_INFO("cppcanvas.emf", "EMF+\t\tcustom cap");
+                SAL_INFO("cppcanvas.emf", "EMF+\t\theader: 0x" << std::hex << header << " type: " << type << std::dec);
+
+                if (type == EmfPlusCustomLineCapDataTypeDefault)
+                {
+                    sal_uInt32 customLineCapDataFlags, baseCap;
+                    float baseInset;
+                    float widthScale;
+                    float fillHotSpotX, fillHotSpotY, strokeHotSpotX, strokeHotSpotY;
+
+                    s >> customLineCapDataFlags >> baseCap >> baseInset
+                      >> strokeStartCap >> strokeEndCap >> strokeJoin
+                      >> miterLimit >> widthScale
+                      >> fillHotSpotX >> fillHotSpotY >> strokeHotSpotX >> strokeHotSpotY;
+
+                    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\tmiterLimit: " << miterLimit);
+                    SAL_INFO("cppcanvas.emf", "EMF+\t\twidthScale: " << widthScale);
+
+                    if (customLineCapDataFlags & EmfPlusCustomLineCapDataFillPath)
+                    {
+                        ReadPath(s, rR, true);
+                    }
+
+                    if (customLineCapDataFlags & EmfPlusCustomLineCapDataLinePath)
+                    {
+                        ReadPath(s, rR, false);
+                    }
+                }
+                else if (type == EmfPlusCustomLineCapDataTypeAdjustableArrow)
+                {
+                    // TODO only reads the data, does not use them [I've had
+                    // no test document to be able to implement it]
+
+                    sal_Int32 width, height, middleInset, fillState, lineStartCap;
+                    sal_Int32 lineEndCap, lineJoin, widthScale;
+                    float fillHotSpotX, fillHotSpotY, lineHotSpotX, lineHotSpotY;
+
+                    s >> width >> height >> middleInset >> fillState >> lineStartCap
+                      >> lineEndCap >> lineJoin >> miterLimit >> widthScale
+                      >> fillHotSpotX >> fillHotSpotY >> lineHotSpotX >> lineHotSpotY;
+
+                    SAL_INFO("cppcanvas.emf", "EMF+\t\tTODO - actually read EmfPlusCustomLineCapArrowData object (section 2.2.2.12)");
+                }
+            }
+        };
+
         struct EMFPPen : public EMFPBrush
         {
             XForm transformation;
@@ -599,21 +749,35 @@ namespace cppcanvas
             sal_Int32 compoundArrayLen;
             float *compoundArray;
             sal_Int32 customStartCapLen;
-            sal_uInt8 *customStartCap;
+            EMFPCustomLineCap *customStartCap;
             sal_Int32 customEndCapLen;
-            sal_uInt8 *customEndCap;
+            EMFPCustomLineCap *customEndCap;
 
         public:
             EMFPPen () : EMFPBrush ()
             {
+                dashPattern = NULL;
+                compoundArray = NULL;
+                customStartCap = NULL;
+                customEndCap = NULL;
             }
 
-            void SetStrokeAttributes (rendering::StrokeAttributes& rStrokeAttributes, ImplRenderer& rR, const OutDevState& rState)
+            ~EMFPPen ()
+            {
+                delete[] dashPattern;
+                delete[] compoundArray;
+                delete customStartCap;
+                delete customEndCap;
+            }
+
+            void SetStrokeWidth(rendering::StrokeAttributes& rStrokeAttributes, ImplRenderer& rR, const OutDevState& rState)
             {
                 EMFP_DEBUG (if (width == 0.0) printf ("EMF+\tTODO: pen with zero width - using minimal which might not be correct\n"));
                 rStrokeAttributes.StrokeWidth = fabs((rState.mapModeTransform * rR.MapSize (width == 0.0 ? 0.05 : width, 0)).getX());
+            }
 
-                // set dashing
+            void SetStrokeDashing(rendering::StrokeAttributes& rStrokeAttributes)
+            {
                 if (dashStyle != EmfPlusLineStyleSolid)
                 {
                     const float dash[] = {3, 3};
@@ -655,12 +819,18 @@ namespace cppcanvas
                     s >> transformation;
 
                 if (penFlags & 2)
+                {
                     s >> startCap;
+                    SAL_INFO("cppcanvas.emf", "EMF+\t\tstartCap: 0x" << std::hex << startCap);
+                }
                 else
                     startCap = 0;
 
                 if (penFlags & 4)
+                {
                     s >> endCap;
+                    SAL_INFO("cppcanvas.emf", "EMF+\t\tendCap: 0x" << std::hex << endCap);
+                }
                 else
                     endCap = 0;
 
@@ -726,24 +896,34 @@ namespace cppcanvas
                 } else
                     compoundArrayLen = 0;
 
-                if (penFlags & 2048) {
+                if (penFlags & 2048)
+                {
                     s >> customStartCapLen;
-                    if( customStartCapLen<0 )
-                        customStartCapLen=0;
-                    customStartCap = new sal_uInt8 [customStartCapLen];
-                    for (i = 0; i < customStartCapLen; i++)
-                        s >> customStartCap [i];
-                } else
+                    SAL_INFO("cppcanvas.emf", "EMF+\t\tcustomStartCapLen: " << customStartCapLen);
+                    sal_uInt32 pos = s.Tell();
+
+                    customStartCap = new EMFPCustomLineCap();
+                    customStartCap->Read(s, rR);
+
+                    // maybe we don't read everything yet, play it safe ;-)
+                    s.Seek(pos + customStartCapLen);
+                }
+                else
                     customStartCapLen = 0;
 
-                if (penFlags & 4096) {
+                if (penFlags & 4096)
+                {
                     s >> customEndCapLen;
-                    if( customEndCapLen<0 )
-                        customEndCapLen=0;
-                    customEndCap = new sal_uInt8 [customEndCapLen];
-                    for (i = 0; i < customEndCapLen; i++)
-                        s >> customEndCap [i];
-                } else
+                    SAL_INFO("cppcanvas.emf", "EMF+\t\tcustomEndCapLen: " << customEndCapLen);
+                    sal_uInt32 pos = s.Tell();
+
+                    customEndCap = new EMFPCustomLineCap();
+                    customEndCap->Read(s, rR);
+
+                    // maybe we don't read everything yet, play it safe ;-)
+                    s.Seek(pos + customEndCapLen);
+                }
+                else
                     customEndCapLen = 0;
 
                 EMFPBrush::Read (s, rR);
@@ -1136,7 +1316,39 @@ namespace cppcanvas
             }
         }
 
-        void ImplRenderer::EMFPPlusDrawPolygon (::basegfx::B2DPolyPolygon& polygon, const ActionFactoryParameters& rParms,
+
+        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)
         {
             EMFPPen* pen = (EMFPPen*) aObjects [penIndex & 0xff];
@@ -1150,24 +1362,62 @@ namespace cppcanvas
                 rState.lineColor = ::vcl::unotools::colorToDoubleSequence (pen->GetColor (),
                                                                            rCanvas->getUNOCanvas ()->getDevice()->getDeviceColorSpace());
 
-                polygon.transform( rState.mapModeTransform );
-                rendering::StrokeAttributes aStrokeAttributes;
+                basegfx::B2DPolyPolygon aPolyPolygon(polygon);
+                aPolyPolygon.transform(rState.mapModeTransform);
+                rendering::StrokeAttributes aCommonAttributes;
 
-                pen->SetStrokeAttributes (aStrokeAttributes, *this, rState);
+                // some attributes are common for the polygon, and the line
+                // starts & ends - like the stroke width
+                pen->SetStrokeWidth(aCommonAttributes, *this, rState);
 
-                ActionSharedPtr pPolyAction(
-                                            internal::PolyPolyActionFactory::createPolyPolyAction(
-                                                                                                  polygon, rParms.mrCanvas, rState, aStrokeAttributes ) );
+                // but eg. dashing has to be additionally set only on the
+                // polygon
+                rendering::StrokeAttributes aPolygonAttributes(aCommonAttributes);
+                pen->SetStrokeDashing(aPolygonAttributes);
 
+                // render the polygon
+                ActionSharedPtr pPolyAction(internal::PolyPolyActionFactory::createPolyPolyAction(aPolyPolygon, rParms.mrCanvas, rState, aPolygonAttributes));
                 if( pPolyAction )
                 {
-                    maActions.push_back(
-                                        MtfAction(
-                                                  pPolyAction,
-                                                  rParms.mrCurrActionIndex ) );
-
+                    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)
+                        {
+                            rendering::StrokeAttributes aAttributes(aCommonAttributes);
+                            pen->customStartCap->SetAttributes(aAttributes);
+
+                            EMFPPlusDrawLineCap(aPolygon, fPolyLength, pen->customStartCap->polygon,
+                                    true, aAttributes, rParms, rState);
+                        }
+
+                        // line end
+                        if (pen->customEndCap)
+                        {
+                            rendering::StrokeAttributes aAttributes(aCommonAttributes);
+                            pen->customEndCap->SetAttributes(aAttributes);
+
+                            EMFPPlusDrawLineCap(aPolygon, fPolyLength, pen->customEndCap->polygon,
+                                    false, aAttributes, rParms, rState);
+                        }
+                    }
+                }
+
             }
         }
 
@@ -1504,7 +1754,7 @@ namespace cppcanvas
 
                         rendering::StrokeAttributes aStrokeAttributes;
 
-                        pen->SetStrokeAttributes (aStrokeAttributes, *this, rState);
+                        pen->SetStrokeWidth (aStrokeAttributes, *this, rState);
 
             ActionSharedPtr pPolyAction(
                 internal::PolyPolyActionFactory::createPolyPolyAction(
commit dda6f654d7d061017fbd671fe78c2a019aeef501
Author: Jan Holesovsky <kendy at collabora.com>
Date:   Fri Nov 22 12:01:15 2013 +0100

    EMF+: Implement line dashing.
    
    Conflicts:
    	cppcanvas/source/mtfrenderer/emfplus.cxx
    
    Change-Id: I9eb21c0a8b5baa5b0080845f61b12fc65034d959

diff --git a/cppcanvas/source/mtfrenderer/emfplus.cxx b/cppcanvas/source/mtfrenderer/emfplus.cxx
index 41cb383..72926a0 100644
--- a/cppcanvas/source/mtfrenderer/emfplus.cxx
+++ b/cppcanvas/source/mtfrenderer/emfplus.cxx
@@ -92,6 +92,13 @@
 #define EmfPlusRegionInitialStateEmpty 0x10000002
 #define EmfPlusRegionInitialStateInfinite 0x10000003
 
+const sal_Int32 EmfPlusLineStyleSolid = 0x00000000;
+const sal_Int32 EmfPlusLineStyleDash = 0x00000001;
+const sal_Int32 EmfPlusLineStyleDot = 0x00000002;
+const sal_Int32 EmfPlusLineStyleDashDot = 0x00000003;
+const sal_Int32 EmfPlusLineStyleDashDotDot = 0x00000004;
+const sal_Int32 EmfPlusLineStyleCustom = 0x00000005;
+
 #if OSL_DEBUG_LEVEL > 1
 #define EMFP_DEBUG(x) x
 #else
@@ -605,6 +612,34 @@ namespace cppcanvas
             {
                 EMFP_DEBUG (if (width == 0.0) printf ("EMF+\tTODO: pen with zero width - using minimal which might not be correct\n"));
                 rStrokeAttributes.StrokeWidth = fabs((rState.mapModeTransform * rR.MapSize (width == 0.0 ? 0.05 : width, 0)).getX());
+
+                // set dashing
+                if (dashStyle != EmfPlusLineStyleSolid)
+                {
+                    const float dash[] = {3, 3};
+                    const float dot[] = {1, 3};
+                    const float dashdot[] = {3, 3, 1, 3};
+                    const float dashdotdot[] = {3, 3, 1, 3, 1, 3};
+
+                    sal_Int32 nLen = 0;
+                    const float *pPattern;
+                    switch (dashStyle)
+                    {
+                        case EmfPlusLineStyleDash:       nLen = SAL_N_ELEMENTS(dash); pPattern = dash; break;
+                        case EmfPlusLineStyleDot:        nLen = SAL_N_ELEMENTS(dot); pPattern = dot; break;
+                        case EmfPlusLineStyleDashDot:    nLen = SAL_N_ELEMENTS(dashdot); pPattern = dashdot; break;
+                        case EmfPlusLineStyleDashDotDot: nLen = SAL_N_ELEMENTS(dashdotdot); pPattern = dashdotdot; break;
+                        case EmfPlusLineStyleCustom:     nLen = dashPatternLen; pPattern = dashPattern; break;
+                    }
+                    if (nLen > 0)
+                    {
+                        uno::Sequence<double> aDashArray(nLen);
+                        for (int i = 0; i < nLen; ++i)
+                            aDashArray[i] = pPattern[i];
+
+                        rStrokeAttributes.DashArray = aDashArray;
+                    }
+                }
             }
 
             void Read (SvStream& s, ImplRenderer& rR, sal_Int32, sal_Int32 )
@@ -640,7 +675,10 @@ namespace cppcanvas
                     mitterLimit = 0;
 
                 if (penFlags & 32)
+                {
                     s >> dashStyle;
+                    SAL_INFO("cppcanvas.emf", "EMF+\t\tdashStyle: 0x" << std::hex << dashStyle);
+                }
                 else
                     dashStyle = 0;
 
@@ -654,14 +692,23 @@ namespace cppcanvas
                 else
                     dashOffset = 0;
 
-                if (penFlags & 256) {
+                if (penFlags & 256)
+                {
+                    dashStyle = EmfPlusLineStyleCustom;
+
                     s >> dashPatternLen;
+                    SAL_INFO("cppcanvas.emf", "EMF+\t\tdashPatternLen: " << dashPatternLen);
+
                     if( dashPatternLen<0 || sal_uInt32(dashPatternLen)>SAL_MAX_INT32/sizeof(float) )
                         dashPatternLen = SAL_MAX_INT32/sizeof(float);
                     dashPattern = new float [dashPatternLen];
                     for (i = 0; i < dashPatternLen; i++)
+                    {
                         s >> dashPattern [i];
-                } else
+                        SAL_INFO("cppcanvas.emf", "EMF+\t\t\tdashPattern[" << i << "]: " << dashPattern[i]);
+                    }
+                }
+                else
                     dashPatternLen = 0;
 
                 if (penFlags & 512)
commit eb50cba358a3db1d49ac1cdc7aa39ef308fb6dc0
Author: Jan Holesovsky <kendy at collabora.com>
Date:   Mon Nov 25 16:21:12 2013 +0100

    fdo#61272: Do the mapping correctly both for WMF and EMF.
    
    Turns out that for the WMF, we already had everything set up correctly, we
    were just overwriting the right settings with default data again :-) - fix
    that.
    
    Includes the following commits:
    
    * Revert "wmf-mm-text-1.diff: Fix WMF rendering, n#417818"
    * Revert "wmf-mm-text.diff: Fix WMF rendering, n#417818"
    * fdo#56886 EMF: Fixes some scaling problems of clipped regions, Twips
    
    Change-Id: I14b0c12b10f58eb7031f9da712dee76344c75159

diff --git a/vcl/source/filter/wmf/enhwmf.cxx b/vcl/source/filter/wmf/enhwmf.cxx
index b74b992..51e564a 100644
--- a/vcl/source/filter/wmf/enhwmf.cxx
+++ b/vcl/source/filter/wmf/enhwmf.cxx
@@ -490,8 +490,8 @@ sal_Bool EnhWMFReader::ReadEnhWMF()
                     EMFP_DEBUG(printf ("\t\tunknown id: 0x%x\n",(unsigned int) id));
                 }
             }
-        } else if( !bEMFPlus || bHaveDC || nRecType == EMR_EOF )
-
+        }
+        else if( !bEMFPlus || bHaveDC || nRecType == EMR_EOF )
         switch( nRecType )
         {
             case EMR_POLYBEZIERTO :
@@ -523,14 +523,14 @@ sal_Bool EnhWMFReader::ReadEnhWMF()
             case EMR_SETWINDOWEXTEX :
             {                                                       // #75383#
                 *pWMF >> nW >> nH;
-                pOut->SetWinExt( Size( nW, nH ) );
+                pOut->SetWinExt( Size( nW, nH ), true);
             }
             break;
 
             case EMR_SETWINDOWORGEX :
             {
                 *pWMF >> nX32 >> nY32;
-                pOut->SetWinOrg( Point( nX32, nY32 ) );
+                pOut->SetWinOrg( Point( nX32, nY32 ), true);
             }
             break;
 
@@ -922,7 +922,7 @@ sal_Bool EnhWMFReader::ReadEnhWMF()
                 PolyPolygon aPolyPoly;
                 if ( cbRgnData )
                     ImplReadRegion( aPolyPoly, *pWMF, nRecSize );
-                pOut->SetClipPath( aPolyPoly, iMode, sal_False );
+                pOut->SetClipPath( aPolyPoly, iMode, sal_True );
             }
             break;
 
@@ -1357,7 +1357,7 @@ sal_Bool EnhWMFReader::ReadHeader()
         return sal_False;
 
     // bound size
-    Rectangle rclBounds;    // rectangle in logical units 1/100th mm
+    Rectangle rclBounds;    // rectangle in logical units
     *pWMF >> nLeft >> nTop >> nRight >> nBottom;
     rclBounds.Left() = nLeft;
     rclBounds.Top() = nTop;
@@ -1365,7 +1365,7 @@ sal_Bool EnhWMFReader::ReadHeader()
     rclBounds.Bottom() = nBottom;
 
     // picture frame size
-    Rectangle rclFrame;     // rectangle in device units
+    Rectangle rclFrame;     // rectangle in device units 1/100th mm
     *pWMF >> nLeft >> nTop >> nRight >> nBottom;
     rclFrame.Left() = nLeft;
     rclFrame.Top() = nTop;
diff --git a/vcl/source/filter/wmf/winmtf.cxx b/vcl/source/filter/wmf/winmtf.cxx
index 63b0996..fc972e8 100644
--- a/vcl/source/filter/wmf/winmtf.cxx
+++ b/vcl/source/filter/wmf/winmtf.cxx
@@ -352,6 +352,20 @@ Color WinMtf::ReadColor()
 //-----------------------------------------------------------------------------------
 //-----------------------------------------------------------------------------------
 
+Point WinMtfOutput::ImplScale( const Point& rPt)//Hack to set varying defaults for incompletely defined files.
+{
+        if (mbIsMapDevSet && mbIsMapWinSet)
+        {
+            return Point((rPt.X())*mnWinExtX/mnDevWidth-mrclFrame.Left(),(rPt.Y())*mnWinExtY/mnDevHeight-mrclFrame.Top());
+        }
+        else
+        {
+            return Point((rPt.X())*UNDOCUMENTED_WIN_RCL_RELATION-mrclFrame.Left(),(rPt.Y())*UNDOCUMENTED_WIN_RCL_RELATION-mrclFrame.Top());
+        }
+}
+
+//-----------------------------------------------------------------------------------
+
 Point WinMtfOutput::ImplMap( const Point& rPt )
 {
     if ( mnWinExtX && mnWinExtY )
@@ -366,35 +380,32 @@ Point WinMtfOutput::ImplMap( const Point& rPt )
         {
             switch( mnMapMode )
             {
-                case MM_TEXT:
+                case MM_LOENGLISH :
+                {
                     fX2 -= mnWinOrgX;
-                    fY2 -= mnWinOrgY;
-                    if( mnDevWidth != 1 || mnDevHeight != 1 ) {
-                        fX2 *= 2540.0/mnUnitsPerInch;
-                        fY2 *= 2540.0/mnUnitsPerInch;
-                    }
+                    fY2  = mnWinOrgY-fY2;
+                    fX2 *= HUNDREDTH_MILLIMETERS_PER_MILLIINCH*10;
+                    fY2 *= HUNDREDTH_MILLIMETERS_PER_MILLIINCH*10;
                     fX2 += mnDevOrgX;
                     fY2 += mnDevOrgY;
-                    fX2 *= (double)mnMillX * 100.0 / (double)mnPixX;
-                    fY2 *= (double)mnMillY * 100.0 / (double)mnPixY;
-
-                    break;
-                case MM_LOENGLISH :
+                }
+                break;
+                case MM_HIENGLISH :
                 {
                     fX2 -= mnWinOrgX;
                     fY2  = mnWinOrgY-fY2;
-                    fX2 *= 25.40;
-                    fY2 *= 25.40;
+                    fX2 *= HUNDREDTH_MILLIMETERS_PER_MILLIINCH;
+                    fY2 *= HUNDREDTH_MILLIMETERS_PER_MILLIINCH;
                     fX2 += mnDevOrgX;
                     fY2 += mnDevOrgY;
                 }
                 break;
-                case MM_HIENGLISH :
+                case MM_TWIPS:
                 {
                     fX2 -= mnWinOrgX;
                     fY2  = mnWinOrgY-fY2;
-                    fX2 *= 2.540;
-                    fY2 *= 2.540;
+                    fX2 *= HUNDREDTH_MILLIMETERS_PER_MILLIINCH/MILLIINCH_PER_TWIPS;
+                    fY2 *= HUNDREDTH_MILLIMETERS_PER_MILLIINCH/MILLIINCH_PER_TWIPS;
                     fX2 += mnDevOrgX;
                     fY2 += mnDevOrgY;
                 }
@@ -409,7 +420,7 @@ Point WinMtfOutput::ImplMap( const Point& rPt )
                     fY2 += mnDevOrgY;
                 }
                 break;
-                case MM_HIMETRIC :
+                case MM_HIMETRIC : //in hundredth of a millimeter
                 {
                     fX2 -= mnWinOrgX;
                     fY2  = mnWinOrgY-fY2;
@@ -454,25 +465,16 @@ Size WinMtfOutput::ImplMap( const Size& rSz )
         {
             switch( mnMapMode )
             {
-                case MM_TEXT:
-                if( mnDevWidth != 1 && mnDevHeight != 1 ) {
-                    fWidth *= 2540.0/mnUnitsPerInch;
-                    fHeight*= 2540.0/mnUnitsPerInch;
-                } else {
-                    fWidth *= (double)mnMillX * 100 / (double)mnPixX;
-                    fHeight *= (double)mnMillY * 100 / (double)mnPixY;
-                }
-                break;
                 case MM_LOENGLISH :
                 {
-                    fWidth *= 25.40;
-                    fHeight*=-25.40;
+                    fWidth *= HUNDREDTH_MILLIMETERS_PER_MILLIINCH*10;
+                    fHeight*=-HUNDREDTH_MILLIMETERS_PER_MILLIINCH*10;
                 }
                 break;
                 case MM_HIENGLISH :
                 {
-                    fWidth *= 2.540;
-                    fHeight*=-2.540;
+                    fWidth *= HUNDREDTH_MILLIMETERS_PER_MILLIINCH;
+                    fHeight*=-HUNDREDTH_MILLIMETERS_PER_MILLIINCH;
                 }
                 break;
                 case MM_LOMETRIC :
@@ -481,11 +483,17 @@ Size WinMtfOutput::ImplMap( const Size& rSz )
                     fHeight*=-10;
                 }
                 break;
-                case MM_HIMETRIC :
+                case MM_HIMETRIC : //in hundredth of millimeters
                 {
                     fHeight *= -1;
                 }
                 break;
+                case MM_TWIPS:
+                {
+                    fWidth *= HUNDREDTH_MILLIMETERS_PER_MILLIINCH/MILLIINCH_PER_TWIPS;
+                    fHeight*=-HUNDREDTH_MILLIMETERS_PER_MILLIINCH/MILLIINCH_PER_TWIPS;
+                }
+                break;
                 default :
                 {
                     fWidth /= mnWinExtX;
@@ -543,6 +551,27 @@ Polygon& WinMtfOutput::ImplMap( Polygon& rPolygon )
 
 //-----------------------------------------------------------------------------------
 
+Polygon& WinMtfOutput::ImplScale( Polygon& rPolygon )
+{
+    sal_uInt16 nPoints = rPolygon.GetSize();
+    for ( sal_uInt16 i = 0; i < nPoints; i++ )
+    {
+        rPolygon[ i ] = ImplScale( rPolygon[ i ] );
+    }
+    return rPolygon;
+}
+
+//-----------------------------------------------------------------------------------
+
+PolyPolygon& WinMtfOutput::ImplScale( PolyPolygon& rPolyPolygon )
+{
+    sal_uInt16 nPolys = rPolyPolygon.Count();
+    for ( sal_uInt16 i = 0; i < nPolys; ImplScale( rPolyPolygon[ i++ ] ) ) ;
+    return rPolyPolygon;
+}
+
+//-----------------------------------------------------------------------------------
+
 PolyPolygon& WinMtfOutput::ImplMap( PolyPolygon& rPolyPolygon )
 {
     sal_uInt16 nPolys = rPolyPolygon.Count();
@@ -838,6 +867,10 @@ void WinMtfOutput::DeleteObject( sal_Int32 nIndex )
 void WinMtfOutput::IntersectClipRect( const Rectangle& rRect )
 {
     mbClipNeedsUpdate=true;
+    if ((rRect.Left()-rRect.Right()==0) && (rRect.Top()-rRect.Bottom()==0))
+    {
+        return; // empty rectangles cause trouble
+    }
     aClipPath.intersectClipRect( ImplMap( rRect ) );
 }
 
@@ -861,7 +894,10 @@ void WinMtfOutput::SetClipPath( const PolyPolygon& rPolyPolygon, sal_Int32 nClip
 {
     mbClipNeedsUpdate=true;
     if ( bIsMapped )
-        aClipPath.setClipPath( rPolyPolygon, nClippingMode );
+    {
+        PolyPolygon aPP( rPolyPolygon );
+        aClipPath.setClipPath( ImplScale( aPP ), nClippingMode );
+    }
     else
     {
         PolyPolygon aPP( rPolyPolygon );
@@ -891,7 +927,6 @@ WinMtfOutput::WinMtfOutput( GDIMetaFile& rGDIMetaFile ) :
     mbComplexClip       ( false ),
     mnGfxMode           ( GM_COMPATIBLE ),
     mnMapMode           ( MM_TEXT ),
-    mnUnitsPerInch ( 96 ),
     mnDevOrgX           ( 0 ),
     mnDevOrgY           ( 0 ),
     mnDevWidth          ( 1 ),
@@ -906,6 +941,8 @@ WinMtfOutput::WinMtfOutput( GDIMetaFile& rGDIMetaFile ) :
     mnMillY             ( 1 ),
     mpGDIMetaFile       ( &rGDIMetaFile )
 {
+    mbIsMapWinSet = sal_False;
+    mbIsMapDevSet = sal_False;
     mpGDIMetaFile->AddAction( new MetaPushAction( PUSH_CLIPREGION ) );      // The original clipregion has to be on top
                                                                             // of the stack so it can always be restored
                                                                             // this is necessary to be able to support
@@ -1116,7 +1153,6 @@ void WinMtfOutput::MoveTo( const Point& rPoint, sal_Bool bRecordPath )
 void WinMtfOutput::LineTo( const Point& rPoint, sal_Bool bRecordPath )
 {
     UpdateClipRegion();
-
     Point aDest( ImplMap( rPoint ) );
     if ( bRecordPath )
         aPathObj.AddPoint( aDest );
@@ -1896,7 +1932,7 @@ void WinMtfOutput::SetDevOrgOffset( sal_Int32 nXAdd, sal_Int32 nYAdd )
 
 //-----------------------------------------------------------------------------------
 
-void WinMtfOutput::SetDevExt( const Size& rSize )
+void WinMtfOutput::SetDevExt( const Size& rSize ,sal_Bool regular)
 {
     if ( rSize.Width() && rSize.Height() )
     {
@@ -1909,6 +1945,10 @@ void WinMtfOutput::SetDevExt( const Size& rSize )
                 mnDevHeight = rSize.Height();
             }
         }
+        if (regular)
+        {
+            mbIsMapDevSet=sal_True;
+        }
     }
 }
 
@@ -1922,10 +1962,15 @@ void WinMtfOutput::ScaleDevExt( double fX, double fY )
 
 //-----------------------------------------------------------------------------------
 
-void WinMtfOutput::SetWinOrg( const Point& rPoint )
+void WinMtfOutput::SetWinOrg( const Point& rPoint , sal_Bool bIsEMF)
 {
     mnWinOrgX = rPoint.X();
     mnWinOrgY = rPoint.Y();
+    if (bIsEMF)
+    {
+        SetDevByWin();
+    }
+    mbIsMapWinSet=sal_True;
 }
 
 //-----------------------------------------------------------------------------------
@@ -1938,9 +1983,21 @@ void WinMtfOutput::SetWinOrgOffset( sal_Int32 nXAdd, sal_Int32 nYAdd )
 
 //-----------------------------------------------------------------------------------
 
-void WinMtfOutput::SetWinExt( const Size& rSize )
+void WinMtfOutput::SetDevByWin() //mnWinExt...-stuff has to be assigned before.
 {
+    if (!mbIsMapDevSet)
+    {
+        if ((mnMapMode == MM_ISOTROPIC) ) //TODO: WHAT ABOUT ANISOTROPIC???
+        {
+            SetDevExt(Size((mnWinExtX+mnWinOrgX)>>MS_FIXPOINT_BITCOUNT_28_4,-((mnWinExtY-mnWinOrgY)>>MS_FIXPOINT_BITCOUNT_28_4)),sal_False);
+        }
+    }
+}
+
+//-----------------------------------------------------------------------------------
 
+void WinMtfOutput::SetWinExt( const Size& rSize, sal_Bool bIsEMF )
+{
     if( rSize.Width() && rSize.Height() )
     {
         switch( mnMapMode )
@@ -1950,6 +2007,11 @@ void WinMtfOutput::SetWinExt( const Size& rSize )
             {
                 mnWinExtX = rSize.Width();
                 mnWinExtY = rSize.Height();
+                if (bIsEMF)
+                {
+                    SetDevByWin();
+                }
+                mbIsMapWinSet=sal_True;
             }
         }
     }
@@ -1998,7 +2060,7 @@ void WinMtfOutput::SetRefMill( const Size& rSize )
 void WinMtfOutput::SetMapMode( sal_uInt32 nMapMode )
 {
     mnMapMode = nMapMode;
-    if ( nMapMode == MM_TEXT )
+    if ( nMapMode == MM_TEXT && !mbIsMapWinSet )
     {
         mnWinExtX = mnDevWidth;
         mnWinExtY = mnDevHeight;
@@ -2012,14 +2074,6 @@ void WinMtfOutput::SetMapMode( sal_uInt32 nMapMode )
 
 //-----------------------------------------------------------------------------------
 
-void WinMtfOutput::SetUnitsPerInch( sal_uInt16 nUnitsPerInch )
-{
-    if( nUnitsPerInch != 0 )
-    mnUnitsPerInch = nUnitsPerInch;
-}
-
-//-----------------------------------------------------------------------------------
-
 void WinMtfOutput::SetWorldTransform( const XForm& rXForm )
 {
     maXForm.eM11 = rXForm.eM11;
diff --git a/vcl/source/filter/wmf/winmtf.hxx b/vcl/source/filter/wmf/winmtf.hxx
index bc368e6e..dd80833 100644
--- a/vcl/source/filter/wmf/winmtf.hxx
+++ b/vcl/source/filter/wmf/winmtf.hxx
@@ -278,6 +278,13 @@ struct WMF_EXTERNALHEADER;
 
 #define PRIVATE_ESCAPE_UNICODE  2
 
+//Scalar constants
+
+#define UNDOCUMENTED_WIN_RCL_RELATION 32
+#define MS_FIXPOINT_BITCOUNT_28_4 4
+#define HUNDREDTH_MILLIMETERS_PER_MILLIINCH 2.54
+#define MILLIINCH_PER_TWIPS   1.44
+
 //============================ WMFReader ==================================
 
 #ifdef WIN_MTF_ASSERT
@@ -617,13 +624,14 @@ class WinMtfOutput
 
     sal_uInt32          mnGfxMode;
     sal_uInt32          mnMapMode;
-    sal_uInt16          mnUnitsPerInch;
 
     XForm               maXForm;
     sal_Int32           mnDevOrgX, mnDevOrgY;
     sal_Int32           mnDevWidth, mnDevHeight;
     sal_Int32           mnWinOrgX, mnWinOrgY;       // aktuelles Window-Origin
     sal_Int32           mnWinExtX, mnWinExtY;       // aktuelles Window-Extent
+    sal_Bool            mbIsMapWinSet;
+    sal_Bool            mbIsMapDevSet;
 
     sal_Int32           mnPixX, mnPixY;             // Reference Device in pixel
     sal_Int32           mnMillX, mnMillY;           // Reference Device in Mill
@@ -636,11 +644,14 @@ class WinMtfOutput
     void                UpdateFillStyle();
 
     Point               ImplMap( const Point& rPt );
+    Point               ImplScale( const Point& rPt );
     Size                ImplMap( const Size& rSz );
     Rectangle           ImplMap( const Rectangle& rRectangle );
     void                ImplMap( Font& rFont );
     Polygon&            ImplMap( Polygon& rPolygon );
     PolyPolygon&        ImplMap( PolyPolygon& rPolyPolygon );
+    Polygon&            ImplScale( Polygon& rPolygon );
+    PolyPolygon&        ImplScale( PolyPolygon& rPolyPolygon );
     void                ImplResizeObjectArry( sal_uInt32 nNewEntry );
     void                ImplSetNonPersistentLineColorTransparenz();
     void                ImplDrawClippedPolyPolygon( const PolyPolygon& rPolyPoly );
@@ -648,14 +659,15 @@ class WinMtfOutput
 
 public:
 
+    void                SetDevByWin(); //Hack to set varying defaults for incompletely defined files.
     void                SetDevOrg( const Point& rPoint );
     void                SetDevOrgOffset( sal_Int32 nXAdd, sal_Int32 nYAdd );
-    void                SetDevExt( const Size& rSize );
+    void                SetDevExt( const Size& rSize ,sal_Bool regular = true);
     void                ScaleDevExt( double fX, double fY );
 
-    void                SetWinOrg( const Point& rPoint );
+    void                SetWinOrg( const Point& rPoint , sal_Bool bIsEMF = false);
     void                SetWinOrgOffset( sal_Int32 nX, sal_Int32 nY );
-    void                SetWinExt( const Size& rSize );
+    void                SetWinExt( const Size& rSize , sal_Bool bIsEMF = false);
     void                ScaleWinExt( double fX, double fY );
 
     void                SetrclBounds( const Rectangle& rRect );
diff --git a/vcl/source/filter/wmf/winwmf.cxx b/vcl/source/filter/wmf/winwmf.cxx
index 0d6276a..0178e3d 100644
--- a/vcl/source/filter/wmf/winwmf.cxx
+++ b/vcl/source/filter/wmf/winwmf.cxx
@@ -1096,7 +1096,6 @@ sal_Bool WMFReader::ReadHeader()
         }
     }
 
-    pOut->SetUnitsPerInch( nUnitsPerInch );
     pOut->SetWinOrg( aPlaceableBound.TopLeft() );
     Size aWMFSize( labs( aPlaceableBound.GetWidth() ), labs( aPlaceableBound.GetHeight() ) );
     pOut->SetWinExt( aWMFSize );
commit e88d04749fb9938b997dbf7a5e7d91a7588c8b83
Author: Jan Holesovsky <kendy at collabora.com>
Date:   Tue Nov 19 10:02:12 2013 +0100

    EMF+: Stroke size is always supposed to be absolute.
    
    Conflicts:
    	cppcanvas/source/mtfrenderer/emfplus.cxx
    
    Change-Id: I7221311e5dee6384dc2d1c071bf6f1c61811895a

diff --git a/cppcanvas/source/mtfrenderer/emfplus.cxx b/cppcanvas/source/mtfrenderer/emfplus.cxx
index c77d16b..41cb383 100644
--- a/cppcanvas/source/mtfrenderer/emfplus.cxx
+++ b/cppcanvas/source/mtfrenderer/emfplus.cxx
@@ -604,7 +604,7 @@ namespace cppcanvas
             void SetStrokeAttributes (rendering::StrokeAttributes& rStrokeAttributes, ImplRenderer& rR, const OutDevState& rState)
             {
                 EMFP_DEBUG (if (width == 0.0) printf ("EMF+\tTODO: pen with zero width - using minimal which might not be correct\n"));
-                rStrokeAttributes.StrokeWidth = (rState.mapModeTransform * rR.MapSize (width == 0.0 ? 0.05 : width, 0)).getX ();
+                rStrokeAttributes.StrokeWidth = fabs((rState.mapModeTransform * rR.MapSize (width == 0.0 ? 0.05 : width, 0)).getX());
             }
 
             void Read (SvStream& s, ImplRenderer& rR, sal_Int32, sal_Int32 )


More information about the Libreoffice-commits mailing list