[Libreoffice-commits] core.git: Branch 'distro/vector/vtext-6.5' - 24 commits - basegfx/inc basegfx/source canvas/source cppcanvas/source embeddedobj/Library_emboleobj.mk embeddedobj/source sc/source sfx2/inc sfx2/sdi svtools/inc svtools/source sw/inc sw/source vcl/inc vcl/source

Fridrich Å trba fridrich.strba at bluewin.ch
Tue Apr 29 06:15:26 PDT 2014


 basegfx/inc/basegfx/polygon/b2dlinegeometry.hxx |    7 
 basegfx/source/polygon/b2dlinegeometry.cxx      |    7 
 canvas/source/cairo/cairo_textlayout.cxx        |    6 
 cppcanvas/source/inc/implrenderer.hxx           |   10 
 cppcanvas/source/mtfrenderer/emfplus.cxx        |  447 ++++++++++++++++++++++--
 embeddedobj/Library_emboleobj.mk                |    1 
 embeddedobj/source/msole/graphconvert.cxx       |   12 
 embeddedobj/source/msole/olepersist.cxx         |   11 
 sc/source/ui/view/viewfun5.cxx                  |    8 
 sfx2/inc/sfx2/sfxsids.hrc                       |    2 
 sfx2/sdi/sfx.sdi                                |    2 
 svtools/inc/svtools/transfer.hxx                |   10 
 svtools/source/misc/transfer.cxx                |    6 
 sw/inc/IDocumentStatistics.hxx                  |    6 
 sw/inc/doc.hxx                                  |   10 
 sw/source/core/doc/doc.cxx                      |   30 -
 sw/source/ui/dochdl/swdtflvr.cxx                |    8 
 sw/source/ui/uiview/view2.cxx                   |    9 
 vcl/inc/vcl/gdimtf.hxx                          |    2 
 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 
 vcl/source/gdi/gdimtf.cxx                       |   24 -
 vcl/source/gdi/pdfwriter_impl2.cxx              |    2 
 25 files changed, 661 insertions(+), 140 deletions(-)

New commits:
commit 1b6ce318c61751c5006ff8fbeec7a6cac9764e3a
Author: Fridrich Å trba <fridrich.strba at bluewin.ch>
Date:   Fri Jun 7 15:33:13 2013 +0200

    Transform the clipping polygon before using it
    
    (cherry picked from commit abdbb847fa135dd758ef3ef99db4c07a2671ca47)
    
    Change-Id: I71a00f7d4b80ef41b637889e51a414fac6883ba1
    Signed-off-by: Thorsten Behrens <tbehrens at suse.com>
    (cherry picked from commit 7765fbc5300587bd23fd9e56a325140ad89cface)

diff --git a/cppcanvas/source/mtfrenderer/emfplus.cxx b/cppcanvas/source/mtfrenderer/emfplus.cxx
index 59907ad..d43b2a6 100644
--- a/cppcanvas/source/mtfrenderer/emfplus.cxx
+++ b/cppcanvas/source/mtfrenderer/emfplus.cxx
@@ -2123,6 +2123,7 @@ namespace cppcanvas
                                                                                                                                                         mappedPoint.getX() + mappedSize.getX(),
                                                                                                                                                         mappedPoint.getY() + mappedSize.getY() ) ) ) );
 
+                        polyPolygon.transform(rState.mapModeTransform);
                         updateClipping (polyPolygon, rFactoryParms, combineMode == 1);
 
                         break;
commit 429b86bf615c19638dd9ab91facaedcbb2c77307
Author: Andras Timar <andras.timar at collabora.com>
Date:   Thu Apr 10 08:50:53 2014 +0000

    build fix
    
    Change-Id: I9b4e4f3fc60ee84e3c180360cc452ab1d9592acd

diff --git a/embeddedobj/source/msole/graphconvert.cxx b/embeddedobj/source/msole/graphconvert.cxx
index 006073c..b6512b6 100644
--- a/embeddedobj/source/msole/graphconvert.cxx
+++ b/embeddedobj/source/msole/graphconvert.cxx
@@ -54,7 +54,7 @@ sal_Bool ConvertBufferToFormat( void* pBuf,
         GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
         sal_uInt16 nRetFormat = 0;
         if (rFilter.CanImportGraphic(OUString(), aMemoryStream, GRFILTER_FORMAT_DONTKNOW, &nRetFormat) == GRFILTER_OK &&
-                rFilter.GetImportFormatMediaType(nRetFormat) == aMimeType)
+                rFilter.GetImportFormatMediaType(nRetFormat) == String(aMimeType))
         {
             aResult <<= uno::Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( aMemoryStream.GetData() ), aMemoryStream.Seek( STREAM_SEEK_TO_END ) );
             return sal_True;
commit 4961b23d48bdf6c10ca80491984daff7328d97ae
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Wed Apr 9 10:47:25 2014 +0200

    fdo#77229 EMF+ rendering: improve EmfPlusSetClipPath's CombineModeExclude case
    
    This is still not perfect, but at least we now don't do the opposite of
    what was asked.
    
    Change-Id: I5e144c5ec2987902e65b2eb472259d9c39bbbd11
    (cherry picked from commit c2af50eb6df396c957890a6b912b8f3185893551)
    
    Conflicts:
    	cppcanvas/source/mtfrenderer/emfplus.cxx

diff --git a/cppcanvas/source/mtfrenderer/emfplus.cxx b/cppcanvas/source/mtfrenderer/emfplus.cxx
index 942591a..59907ad 100644
--- a/cppcanvas/source/mtfrenderer/emfplus.cxx
+++ b/cppcanvas/source/mtfrenderer/emfplus.cxx
@@ -124,6 +124,16 @@ const sal_uInt32 EmfPlusLineJoinTypeMiterClipped = 0x00000003;
 #define EMFP_DEBUG(x)
 #endif
 
+enum EmfPlusCombineMode
+{
+    EmfPlusCombineModeReplace = 0x00000000,
+    EmfPlusCombineModeIntersect = 0x00000001,
+    EmfPlusCombineModeUnion = 0x00000002,
+    EmfPlusCombineModeXOR = 0x00000003,
+    EmfPlusCombineModeExclude = 0x00000004,
+    EmfPlusCombineModeComplement = 0x00000005
+};
+
 using namespace ::com::sun::star;
 using namespace ::basegfx;
 
@@ -2128,7 +2138,19 @@ namespace cppcanvas
                         ::basegfx::B2DPolyPolygon& clipPoly (path.GetPolygon (*this));
 
                         clipPoly.transform (rState.mapModeTransform);
-                        updateClipping (clipPoly, rFactoryParms, combineMode == 1);
+                        switch (combineMode)
+                        {
+                        case EmfPlusCombineModeReplace:
+                        case EmfPlusCombineModeIntersect:
+                        case EmfPlusCombineModeUnion: // Is this, EmfPlusCombineModeXOR and EmfPlusCombineModeComplement correct?
+                        case EmfPlusCombineModeXOR:
+                        case EmfPlusCombineModeComplement:
+                            updateClipping (clipPoly, rFactoryParms, combineMode == 1);
+                            break;
+                        case EmfPlusCombineModeExclude:
+                            // Not doing anything is better then including exactly what we wanted to exclude.
+                            break;
+                        }
 
                         break;
                     }
commit 4b3ba82086beb03399f6f87800c4d485ba6b1b48
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Mon Apr 7 16:51:29 2014 +0200

    fdo#77140 embeddedobj: avoid unneeded conversion in ConvertBufferToFormat()
    
    The primary reason is not performance: on export currently we loose some
    EMF+ properties. While it would be good to fix all those problems one by
    one, this is a small fix to avoid all kind of roundtrip problems in this
    situation.
    
    Change-Id: If5e1c1eabd8290f36b538e374c9707ae17097786
    (cherry picked from commit 2a7fdf2a7bb7345c49c988dfd1fcdb41cebb8a1e)

diff --git a/embeddedobj/Library_emboleobj.mk b/embeddedobj/Library_emboleobj.mk
index 32dfe09..1e72bf2 100644
--- a/embeddedobj/Library_emboleobj.mk
+++ b/embeddedobj/Library_emboleobj.mk
@@ -43,6 +43,7 @@ $(eval $(call gb_Library_use_libraries,emboleobj,\
 	sal \
 	tl \
 	utl \
+	vcl \
 	$(gb_UWINAPI) \
 ))
 
diff --git a/embeddedobj/source/msole/graphconvert.cxx b/embeddedobj/source/msole/graphconvert.cxx
index b1f69c4..006073c 100644
--- a/embeddedobj/source/msole/graphconvert.cxx
+++ b/embeddedobj/source/msole/graphconvert.cxx
@@ -32,6 +32,7 @@
 #include <comphelper/processfactory.hxx>
 #include <comphelper/seqstream.hxx>
 #include <tools/stream.hxx>
+#include <vcl/graphicfilter.hxx>
 
 #include "mtnotification.hxx"
 #include "oleembobj.hxx"
@@ -48,6 +49,17 @@ sal_Bool ConvertBufferToFormat( void* pBuf,
     // produces sequence with data in requested format and returns it in aResult
     if ( pBuf )
     {
+        // First, in case the buffer is already in the requested format, then avoid a conversion.
+        SvMemoryStream aMemoryStream(pBuf, nBufSize, STREAM_READ);
+        GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
+        sal_uInt16 nRetFormat = 0;
+        if (rFilter.CanImportGraphic(OUString(), aMemoryStream, GRFILTER_FORMAT_DONTKNOW, &nRetFormat) == GRFILTER_OK &&
+                rFilter.GetImportFormatMediaType(nRetFormat) == aMimeType)
+        {
+            aResult <<= uno::Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( aMemoryStream.GetData() ), aMemoryStream.Seek( STREAM_SEEK_TO_END ) );
+            return sal_True;
+        }
+
         uno::Sequence < sal_Int8 > aData( (sal_Int8*)pBuf, nBufSize );
         uno::Reference < io::XInputStream > xIn = new comphelper::SequenceInputStream( aData );
         try
commit f63bb421ceb341a6ec93d9e1d421fdb9fdce8beb
Author: Jan Holesovsky <kendy at collabora.com>
Date:   Tue Mar 4 22:49:08 2014 +0100

    OLE: Turn an OSL_ENSURE() into a real condition.
    
    This is part of some STAMPIT workaround; no idea what it is, but for sure it
    causes problems with PowerPoint OLE in Writer - so let's avoid updating if it
    is not "STAMPIT".
    
    Change-Id: I266b419ba3461c547f7ee8e447ef64a47a8511e8

diff --git a/embeddedobj/source/msole/olepersist.cxx b/embeddedobj/source/msole/olepersist.cxx
index 18e01cd..a6ba8db 100644
--- a/embeddedobj/source/msole/olepersist.cxx
+++ b/embeddedobj/source/msole/olepersist.cxx
@@ -891,13 +891,12 @@ void OleEmbeddedObject::OnViewChanged_Impl()
     // - if the verb execution is in progress and the view is changed the object will be stored
     // after the execution, so there is no need to send the notification.
     // - the STAMPIT object can never be active.
-    if ( m_aVerbExecutionController.CanDoNotification()
-      && m_pOleComponent && m_nUpdateMode == embed::EmbedUpdateModes::ALWAYS_UPDATE )
+    if (m_aVerbExecutionController.CanDoNotification() &&
+            m_pOleComponent && m_nUpdateMode == embed::EmbedUpdateModes::ALWAYS_UPDATE &&
+            (MimeConfigurationHelper::ClassIDsEqual(m_aClassID, MimeConfigurationHelper::GetSequenceClassID(0x852ee1c9, 0x9058, 0x44ba, 0x8c, 0x6c, 0x0c, 0x5f, 0xc6, 0x6b, 0xdb, 0x8d)) ||
+             MimeConfigurationHelper::ClassIDsEqual(m_aClassID, MimeConfigurationHelper::GetSequenceClassID(0xcf1b4491, 0xbea3, 0x4c9f, 0xa7, 0x0f, 0x22, 0x1b, 0x1e, 0xca, 0xef, 0x3e)))
+       )
     {
-        OSL_ENSURE( MimeConfigurationHelper::ClassIDsEqual( m_aClassID, MimeConfigurationHelper::GetSequenceClassID( 0x852ee1c9, 0x9058, 0x44ba, 0x8c,0x6c,0x0c,0x5f,0xc6,0x6b,0xdb,0x8d ) )
-                    || MimeConfigurationHelper::ClassIDsEqual( m_aClassID, MimeConfigurationHelper::GetSequenceClassID( 0xcf1b4491, 0xbea3, 0x4c9f, 0xa7,0x0f,0x22,0x1b,0x1e,0xca,0xef,0x3e ) ),
-                    "Expected to be triggered for STAMPIT only! Please contact developers!\n" );
-
         // The view is changed while the object is in running state, save the new object
         m_xCachedVisualRepresentation = uno::Reference< io::XStream >();
         SaveObject_Impl();
commit 4f15abd6535712c0c1fbb3c106e93f03992e7867
Author: Tor Lillqvist <tml at collabora.com>
Date:   Thu Feb 20 13:37:04 2014 +0200

    Re-introduce code to try to get GDI metafile replacement image
    
    The code was commented out in 2009 (with any rationale lost from
    version history) and then cleaned away in 2011. Re-introduce the bit
    that tries FORMAT_GDIMETAFILE.
    
    The other part was commented out in 2009 in CWS metropatch01_DEV300,
    with any reasoning behind it lost in history, and then cleaned away in
    2010. Re-introduce the bit that tries FORMAT_GDIMETAFILE. Seems to
    work for data that produces a reasonably sized metafile.
    
    Also limit the GDI metafile size to 100000 actions. Excel can copy huge
    metafiles to the clipboard, with over 3 million of actions, which are
    1) unusable, and 2) crash LibreOffice because of their size.
    
    Change-Id: I80a4ed1681c3833ef1a4b595623387e9d136a774

diff --git a/sc/source/ui/view/viewfun5.cxx b/sc/source/ui/view/viewfun5.cxx
index cf2c7e5..bb2ad16 100644
--- a/sc/source/ui/view/viewfun5.cxx
+++ b/sc/source/ui/view/viewfun5.cxx
@@ -180,6 +180,14 @@ sal_Bool ScViewFunc::PasteDataFormat( sal_uLong nFormatId,
                     Graphic aGraphic;
                     sal_uLong nGrFormat = 0;
 
+                    // limit the size of the preview metafile to 100000 actions
+                    GDIMetaFile aMetafile;
+                    if (aDataHelper.GetGDIMetaFile(FORMAT_GDIMETAFILE, aMetafile, 100000))
+                    {
+                        nGrFormat = SOT_FORMAT_GDIMETAFILE;
+                        aGraphic = aMetafile;
+                    }
+
                     // insert replacement image ( if there is one ) into the object helper
                     if ( nGrFormat )
                     {
diff --git a/svtools/inc/svtools/transfer.hxx b/svtools/inc/svtools/transfer.hxx
index 93dab75..3077715 100644
--- a/svtools/inc/svtools/transfer.hxx
+++ b/svtools/inc/svtools/transfer.hxx
@@ -350,7 +350,15 @@ public:
     sal_Bool                    GetBitmap( SotFormatStringId nFormat, Bitmap& rBmp );
     sal_Bool                    GetBitmap( const ::com::sun::star::datatransfer::DataFlavor& rFlavor, Bitmap& rBmp );
 
-    sal_Bool                    GetGDIMetaFile( SotFormatStringId nFormat, GDIMetaFile& rMtf );
+    /** Return as GDI metafile.
+
+        @param nMaxAction Allows you to limit the amount of actions; defaults to 0 which means no limit.
+
+        Whet you eg. Ctrl+a in Excel, you can get the entire sheet as
+        metafile, with over 3 million (!) actions; which is just too large for
+        any reasonable handling - and you need to set a limit.
+    */
+    sal_Bool                    GetGDIMetaFile( SotFormatStringId nFormat, GDIMetaFile& rMtf, size_t nMaxActions = 0 );
     sal_Bool                    GetGDIMetaFile( const ::com::sun::star::datatransfer::DataFlavor& rFlavor, GDIMetaFile& rMtf );
 
     sal_Bool                    GetGraphic( SotFormatStringId nFormat, Graphic& rGraphic );
diff --git a/svtools/source/misc/transfer.cxx b/svtools/source/misc/transfer.cxx
index 7082867..f09a2d5 100644
--- a/svtools/source/misc/transfer.cxx
+++ b/svtools/source/misc/transfer.cxx
@@ -1772,10 +1772,12 @@ sal_Bool TransferableDataHelper::GetBitmap( const DataFlavor& rFlavor, Bitmap& r
 
 // -----------------------------------------------------------------------------
 
-sal_Bool TransferableDataHelper::GetGDIMetaFile( SotFormatStringId nFormat, GDIMetaFile& rMtf )
+sal_Bool TransferableDataHelper::GetGDIMetaFile(SotFormatStringId nFormat, GDIMetaFile& rMtf, size_t nMaxActions)
 {
     DataFlavor aFlavor;
-    return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetGDIMetaFile( aFlavor, rMtf ) );
+    return SotExchange::GetFormatDataFlavor(nFormat, aFlavor) &&
+        GetGDIMetaFile(aFlavor, rMtf) &&
+        (nMaxActions == 0 || rMtf.GetActionSize() < nMaxActions);
 }
 
 // -----------------------------------------------------------------------------
diff --git a/sw/source/ui/dochdl/swdtflvr.cxx b/sw/source/ui/dochdl/swdtflvr.cxx
index 28bd60c..c2b74fa 100644
--- a/sw/source/ui/dochdl/swdtflvr.cxx
+++ b/sw/source/ui/dochdl/swdtflvr.cxx
@@ -1766,6 +1766,14 @@ int SwTransferable::_PasteOLE( TransferableDataHelper& rData, SwWrtShell& rSh,
             Graphic aGraphic;
             sal_uLong nGrFormat = 0;
 
+            // limit the size of the preview metafile to 100000 actions
+            GDIMetaFile aMetafile;
+            if (rData.GetGDIMetaFile(FORMAT_GDIMETAFILE, aMetafile, 100000))
+            {
+                nGrFormat = SOT_FORMAT_GDIMETAFILE;
+                aGraphic = aMetafile;
+            }
+
             // insert replacement image ( if there is one ) into the object helper
             if ( nGrFormat )
             {
commit 08515e4a8828c5e2b42d6da652c76ff94eaa3ee6
Author: Miklos Vajna <vmiklos at suse.cz>
Date:   Tue Jul 16 18:26:18 2013 +0200

    fdo#63273 sw: let word count not update stat. fields
    
    Updating fields would generate loads of selection change events and it's
    not what we asked for.
    
    Regression from ce14342c4292628a641a72d4f63d9c048e030c6a.
    
    (cherry picked from commit e2484e3998f2c5036fb8e3584d4b1c72db19bfd3)
    
    Change-Id: If237df1f31436357022ca8d77b924681e403abd8
    Reviewed-on: https://gerrit.libreoffice.org/4943
    Reviewed-by: Björn Michaelsen <bjoern.michaelsen at canonical.com>
    Tested-by: Björn Michaelsen <bjoern.michaelsen at canonical.com>
    (cherry picked from commit 699b7626222ea8be1c9713a7f5e274dbfbc029ff)
    
    This also fixes fdo#67223.
    
    Signed-off-by: Michael Stahl <mstahl at redhat.com>
    
    Conflicts:
    	sw/inc/doc.hxx
    	sw/source/core/doc/doc.cxx

diff --git a/sw/inc/IDocumentStatistics.hxx b/sw/inc/IDocumentStatistics.hxx
index 2c5a0501..950ea49 100644
--- a/sw/inc/IDocumentStatistics.hxx
+++ b/sw/inc/IDocumentStatistics.hxx
@@ -43,8 +43,9 @@
       * modified and returns a reference to the result.
       * \param bCompleteAsync if true will return a partial result,
       * and potentially trigger a timeout to complete the work.
+      * \param bFields if stat. fields should be updated
       */
-    virtual const SwDocStat &GetUpdatedDocStat(bool bCompleteAsync) = 0;
+    virtual const SwDocStat &GetUpdatedDocStat(bool bCompleteAsync, bool bFields) = 0;
 
     /// Set the document statistics
     virtual void SetDocStat(const SwDocStat& rStat) = 0;
@@ -53,8 +54,9 @@
       * Updates the internal document's statistics
       * \param bCompleteAsync if true it may do part of the
       * work and trigger a timeout to complete it.
+      * \param bFields if stat. fields should be updated
       */
-    virtual void UpdateDocStat(bool bCompleteAsync) = 0;
+    virtual void UpdateDocStat(bool bCompleteAsync, bool bFields) = 0;
 
 protected:
     virtual ~IDocumentStatistics() {};
diff --git a/sw/inc/doc.hxx b/sw/inc/doc.hxx
index cdd8dae..0d339a5 100644
--- a/sw/inc/doc.hxx
+++ b/sw/inc/doc.hxx
@@ -911,9 +911,9 @@ public:
     */
     virtual void DocInfoChgd();
     virtual const SwDocStat &GetDocStat() const;
-    virtual const SwDocStat &GetUpdatedDocStat(bool bCompleteAsync = false);
+    virtual const SwDocStat &GetUpdatedDocStat(bool bCompleteAsync = false, bool bFields = true);
     virtual void SetDocStat(const SwDocStat& rStat);
-    virtual void UpdateDocStat(bool bCompleteAsync = false);
+    virtual void UpdateDocStat(bool bCompleteAsync = false, bool bFields = true);
 
     /** IDocumentState
     */
@@ -2075,10 +2075,11 @@ private:
 
     /** continue computing a chunk of document statistics
       * \param nChars  number of characters to count before exiting
+      * \param bFields if stat. fields should be updated
       *
       * returns false when there is no more to calculate
       */
-    bool IncrementalDocStatCalculate(long nChars);
+    bool IncrementalDocStatCalculate(long nChars, bool bFields);
 
     /// Our own 'StatsUpdateTimer' calls the following method
     DECL_LINK( DoIdleStatsUpdate, Timer * );
diff --git a/sw/source/core/doc/doc.cxx b/sw/source/core/doc/doc.cxx
index ad19161..667ef5c 100644
--- a/sw/source/core/doc/doc.cxx
+++ b/sw/source/core/doc/doc.cxx
@@ -1157,11 +1157,11 @@ const SwDocStat& SwDoc::GetDocStat() const
     return *pDocStat;
 }
 
-const SwDocStat& SwDoc::GetUpdatedDocStat( bool bCompleteAsync )
+const SwDocStat& SwDoc::GetUpdatedDocStat( bool bCompleteAsync, bool bFields )
 {
     if( pDocStat->bModified )
     {
-        UpdateDocStat( bCompleteAsync );
+        UpdateDocStat( bCompleteAsync, bFields );
     }
     return *pDocStat;
 }
@@ -1684,7 +1684,7 @@ void SwDoc::CalculatePagePairsForProspectPrinting(
 }
 
 // returns true while there is more to do
-bool SwDoc::IncrementalDocStatCalculate(long nChars)
+bool SwDoc::IncrementalDocStatCalculate( long nChars, bool bFields )
 {
     pDocStat->Reset();
     pDocStat->nPara = 0; // default is 1!
@@ -1771,8 +1771,11 @@ bool SwDoc::IncrementalDocStatCalculate(long nChars)
     }
 
     // optionally update stat. fields
-    SwFieldType *pType = GetSysFldType(RES_DOCSTATFLD);
-    pType->UpdateFlds();
+    if (bFields)
+    {
+        SwFieldType *pType = GetSysFldType(RES_DOCSTATFLD);
+        pType->UpdateFlds();
+    }
 
     return nChars <= 0;
 }
@@ -1780,7 +1783,7 @@ bool SwDoc::IncrementalDocStatCalculate(long nChars)
 IMPL_LINK( SwDoc, DoIdleStatsUpdate, Timer *, pTimer )
 {
     (void)pTimer;
-    if (IncrementalDocStatCalculate(32000))
+    if (IncrementalDocStatCalculate(32000, true))
         aStatsUpdateTimer.Start();
 
     SwView* pView = GetDocShell() ? GetDocShell()->GetView() : NULL;
@@ -1789,16 +1792,16 @@ IMPL_LINK( SwDoc, DoIdleStatsUpdate, Timer *, pTimer )
     return 0;
 }
 
-void SwDoc::UpdateDocStat( bool bCompleteAsync )
+void SwDoc::UpdateDocStat( bool bCompleteAsync, bool bFields )
 {
     if( pDocStat->bModified )
     {
         if (!bCompleteAsync)
         {
-            while (IncrementalDocStatCalculate(5000)) {}
+            while (IncrementalDocStatCalculate(5000, bFields)) {}
             aStatsUpdateTimer.Stop();
         }
-        else if (IncrementalDocStatCalculate(5000))
+        else if (IncrementalDocStatCalculate(5000, bFields))
             aStatsUpdateTimer.Start();
     }
 }
diff --git a/sw/source/ui/uiview/view2.cxx b/sw/source/ui/uiview/view2.cxx
index b989b47..79230ba 100644
--- a/sw/source/ui/uiview/view2.cxx
+++ b/sw/source/ui/uiview/view2.cxx
@@ -1258,7 +1258,7 @@ void SwView::StateStatusLine(SfxItemSet &rSet)
                 SwDocStat documentStats;
                 {
                     rShell.CountWords(selectionStats);
-                    documentStats = rShell.GetDoc()->GetUpdatedDocStat( true /* complete-async */ );
+                    documentStats = rShell.GetDoc()->GetUpdatedDocStat( true /* complete-async */, false /* don't update fields */ );
                 }
 
                 const sal_uInt32 stringId = selectionStats.nWord? STR_STATUSBAR_WORDCOUNT : STR_STATUSBAR_WORDCOUNT_NO_SELECTION;
commit 12096fd0f11e2d1280096352b71de70fb66f9892
Author: Michael Stahl <mstahl at redhat.com>
Date:   Tue Aug 13 18:39:08 2013 +0200

    fdo#58040: sw: fine tune async word count
    
    - count characters instead of paragraphs to better account for large or
      small paragraphs
    - start out with a relatively small value (5k chars) on the first run to
      quickly show something to the user
    
    (cherry picked from commit 91c8008051c0bb7905a6acd822d022e144f2941f)
    
    Conflicts:
    	sw/inc/doc.hxx
    	sw/source/core/doc/doc.cxx
    
    Change-Id: Ic4013545692f267aab39e084415d5d794bb5a4ca
    Reviewed-on: https://gerrit.libreoffice.org/5392
    Reviewed-by: Tor Lillqvist <tml at iki.fi>
    Tested-by: Tor Lillqvist <tml at iki.fi>
    Reviewed-by: Caolán McNamara <caolanm at redhat.com>
    Tested-by: Caolán McNamara <caolanm at redhat.com>

diff --git a/sw/inc/doc.hxx b/sw/inc/doc.hxx
index ed16869..cdd8dae 100644
--- a/sw/inc/doc.hxx
+++ b/sw/inc/doc.hxx
@@ -2074,12 +2074,11 @@ private:
     void CopyMasterFooter(const SwPageDesc &rChged, const SwFmtFooter &rFoot, SwPageDesc *pDesc, bool bLeft);
 
     /** continue computing a chunk of document statistics
-      * \param nTextNodes number of paragraphs to calculate before
-      * exiting
+      * \param nChars  number of characters to count before exiting
       *
       * returns false when there is no more to calculate
       */
-    bool IncrementalDocStatCalculate(long nTextNodes = 250);
+    bool IncrementalDocStatCalculate(long nChars);
 
     /// Our own 'StatsUpdateTimer' calls the following method
     DECL_LINK( DoIdleStatsUpdate, Timer * );
diff --git a/sw/source/core/doc/doc.cxx b/sw/source/core/doc/doc.cxx
index b71288c..ad19161 100644
--- a/sw/source/core/doc/doc.cxx
+++ b/sw/source/core/doc/doc.cxx
@@ -1684,22 +1684,25 @@ void SwDoc::CalculatePagePairsForProspectPrinting(
 }
 
 // returns true while there is more to do
-bool SwDoc::IncrementalDocStatCalculate( long nTextNodes )
+bool SwDoc::IncrementalDocStatCalculate(long nChars)
 {
     pDocStat->Reset();
     pDocStat->nPara = 0; // default is 1!
     SwNode* pNd;
 
     // This is the inner loop - at least while the paras are dirty.
-    for( sal_uLong i = GetNodes().Count(); i > 0 && nTextNodes > 0; )
+    for( sal_uLong i = GetNodes().Count(); i > 0 && nChars > 0; )
     {
         switch( ( pNd = GetNodes()[ --i ])->GetNodeType() )
         {
         case ND_TEXTNODE:
         {
+            long const nOldChars(pDocStat->nChar);
             SwTxtNode *pTxt = static_cast< SwTxtNode * >( pNd );
             if( pTxt->CountWords( *pDocStat, 0, pTxt->GetTxt().Len() ) )
-                nTextNodes--;
+            {
+                nChars -= (pDocStat->nChar - nOldChars);
+            }
             break;
         }
         case ND_TABLENODE:      ++pDocStat->nTbl;   break;
@@ -1771,13 +1774,13 @@ bool SwDoc::IncrementalDocStatCalculate( long nTextNodes )
     SwFieldType *pType = GetSysFldType(RES_DOCSTATFLD);
     pType->UpdateFlds();
 
-    return nTextNodes <= 0;
+    return nChars <= 0;
 }
 
 IMPL_LINK( SwDoc, DoIdleStatsUpdate, Timer *, pTimer )
 {
     (void)pTimer;
-    if( IncrementalDocStatCalculate( 1000 ) )
+    if (IncrementalDocStatCalculate(32000))
         aStatsUpdateTimer.Start();
 
     SwView* pView = GetDocShell() ? GetDocShell()->GetView() : NULL;
@@ -1792,10 +1795,10 @@ void SwDoc::UpdateDocStat( bool bCompleteAsync )
     {
         if (!bCompleteAsync)
         {
-            while (IncrementalDocStatCalculate()) {}
+            while (IncrementalDocStatCalculate(5000)) {}
             aStatsUpdateTimer.Stop();
         }
-        else if (IncrementalDocStatCalculate())
+        else if (IncrementalDocStatCalculate(5000))
             aStatsUpdateTimer.Start();
     }
 }
commit fc66848b84b6a7744956231094d3e18965c763fe
Author: Mathias Supp <mathias.supp at vector.com>
Date:   Tue Feb 25 04:04:48 2014 +0100

    add parameter to supress dialog
    
    With the new parameter you can now supress the dialog for document
    compare in writer.
    
    Change-Id: I984ee75552e5c006332331510df5d437b687903f

diff --git a/sfx2/inc/sfx2/sfxsids.hrc b/sfx2/inc/sfx2/sfxsids.hrc
index 9a18100..cc5984e 100644
--- a/sfx2/inc/sfx2/sfxsids.hrc
+++ b/sfx2/inc/sfx2/sfxsids.hrc
@@ -261,6 +261,7 @@
 #define SID_MAIL_SENDDOCASFORMAT            (SID_SFX_START + 1707)
 #define SID_MAIL_SENDDOCASMS                (SID_SFX_START + 1708)
 #define SID_MAIL_SENDDOCASOOO               (SID_SFX_START + 1709)
+#define SID_NO_ACCEPT_DIALOG                (SID_SFX_START + 1710)
 #define SID_NOAUTOSAVE                      (SID_SFX_START + 1711)
 #define SID_PRINT_SELECTEDSHEET             (SID_SFX_START + 1712)
 #define SID_OPTIONS_PAGEURL                 (SID_SFX_START + 1713)
@@ -282,6 +283,7 @@
 //      SID_SFX_free_START                  (SID_SFX_START + 1728)
 //      SID_SFX_free_END                    (SID_SFX_START + 3999)
 
+
 #define SID_OPEN_NEW_VIEW                   (SID_SFX_START + 520)
     // FREE, was SID_VIEW_ZOOM_MODE
     // FREE, was SID_VIEW_POS_SIZE
diff --git a/sfx2/sdi/sfx.sdi b/sfx2/sdi/sfx.sdi
index 607f206..36cf845 100644
--- a/sfx2/sdi/sfx.sdi
+++ b/sfx2/sdi/sfx.sdi
@@ -1099,7 +1099,7 @@ SfxStringItem Comments SID_DOCINFO_COMMENTS
 
 //--------------------------------------------------------------------------
 SfxInt32Item CompareDocuments SID_DOCUMENT_COMPARE
-(SfxStringItem URL SID_FILE_NAME,SfxStringItem FilterName SID_FILTER_NAME,SfxStringItem Password SID_PASSWORD,SfxStringItem FilterOptions SID_FILE_FILTEROPTIONS,SfxInt16Item Version SID_VERSION)
+(SfxStringItem URL SID_FILE_NAME,SfxStringItem FilterName SID_FILTER_NAME,SfxStringItem Password SID_PASSWORD,SfxStringItem FilterOptions SID_FILE_FILTEROPTIONS,SfxInt16Item Version SID_VERSION, SfxBoolItem NoAcceptDialog SID_NO_ACCEPT_DIALOG)
 [
     /* flags: */
     AutoUpdate = FALSE,
diff --git a/sw/source/ui/uiview/view2.cxx b/sw/source/ui/uiview/view2.cxx
index b6a7d10..b989b47 100644
--- a/sw/source/ui/uiview/view2.cxx
+++ b/sw/source/ui/uiview/view2.cxx
@@ -690,6 +690,7 @@ void SwView::Execute(SfxRequest &rReq)
                 String sFileName, sFilterName;
                 sal_Int16 nVersion = 0;
                 bool bHasFileName = false;
+                bool bNoAcceptDialog = false;
                 pViewImpl->SetParam( 0 );
 
                 if( pArgs )
@@ -706,6 +707,10 @@ void SwView::Execute(SfxRequest &rReq)
                         nVersion = ((const SfxInt16Item *)pItem)->GetValue();
                         pViewImpl->SetParam( nVersion );
                     }
+                    if( SFX_ITEM_SET == pArgs->GetItemState( SID_NO_ACCEPT_DIALOG, sal_False, &pItem ))
+                    {
+                        bNoAcceptDialog = ((const SfxBoolItem *)pItem)->GetValue();
+                    }
                 }
 
                 pViewImpl->InitRequest( rReq );
@@ -715,7 +720,7 @@ void SwView::Execute(SfxRequest &rReq)
                 {
                     rReq.SetReturnValue( SfxInt32Item( nSlot, nFound ));
 
-                    if (nFound > 0) // Redline-Browser anzeigen
+                    if (nFound > 0 && !bNoAcceptDialog) // Redline-Browser anzeigen
                     {
                         SfxViewFrame* pVFrame = GetViewFrame();
                         pVFrame->ShowChildWindow(FN_REDLINE_ACCEPT);
commit 8c0134c31a2c21c84e1ea4da3b0f529ad41b1fc0
Author: Andrzej Hunt <andrzej.hunt at collabora.com>
Date:   Wed Jan 29 18:40:21 2014 +0000

    EMF+: Only draw endcap outline if not filled, fix endcap scaling.
    
    Change-Id: I4520eea08e43ccd657c1db03b258ef84612da971
    Reviewed-on: https://gerrit.libreoffice.org/7726
    Reviewed-by: Jan Holesovsky <kendy at collabora.com>
    Tested-by: Jan Holesovsky <kendy at collabora.com>
    (cherry picked from commit 8d1ca883b119857daa3b8d0ece9da90917589040)

diff --git a/cppcanvas/source/mtfrenderer/emfplus.cxx b/cppcanvas/source/mtfrenderer/emfplus.cxx
index 0767a50..942591a 100644
--- a/cppcanvas/source/mtfrenderer/emfplus.cxx
+++ b/cppcanvas/source/mtfrenderer/emfplus.cxx
@@ -1337,29 +1337,27 @@ namespace cppcanvas
             if (!rLineCap.count())
                 return 0.0;
 
-            // 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;
-
+            // createAreaGeometryForLineStartEnd normalises the arrows height
+            // before scaling (i.e. scales down by rPolygon.height), hence
+            // we pre-scale it (which means we can avoid changing the logic
+            // that would affect arrows rendered outside of EMF+).
+            const double fWidth = rAttributes.StrokeWidth*rLineCap.getB2DRange().getWidth();
+
+            // When drawing an outline (as opposed to a filled endCap), we also
+            // need to take account that the brush width also adds to the area
+            // of the polygon.
+            const double fShift = bIsFilled ? 0 : rAttributes.StrokeWidth;
+            double fConsumed = 0;
             basegfx::B2DPolyPolygon aArrow(basegfx::tools::createAreaGeometryForLineStartEnd(
                         rPolygon, rLineCap, bStart,
-                        fWidth, fPolyLength, 0, NULL, rAttributes.StrokeWidth));
+                        fWidth, fPolyLength, 0, &fConsumed, fShift));
 
             // 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;
-            }
-
+            // If the endcap is filled, we draw ONLY the filling, if it isn't
+            // filled we draw ONLY the outline, but never both.
             if (bIsFilled)
             {
                 bool bWasFillColorSet = rState.isFillColorSet;
@@ -1373,8 +1371,25 @@ namespace cppcanvas
                 }
                 rState.isFillColorSet = bWasFillColorSet;
             }
+            else
+            {
+                ActionSharedPtr pAction(internal::PolyPolyActionFactory::createPolyPolyAction(aArrow, rParms.mrCanvas, rState, rAttributes));
+                if (pAction)
+                {
+                    maActions.push_back(MtfAction(pAction, rParms.mrCurrActionIndex));
+                    rParms.mrCurrActionIndex += pAction->getActionCount()-1;
+                }
+            }
 
-            return rAttributes.StrokeWidth;
+            // There isn't any clear definition of how far the line should extend
+            // for arrows, however the following values seem to give best results
+            // (fConsumed/2 draws the line to the center-point of the endcap
+            // for filled caps -- however it is likely this will need to be
+            // changed once we start taking baseInset into account).
+            if (bIsFilled)
+                return fConsumed/2;
+            else
+                return rAttributes.StrokeWidth;
         }
 
         void ImplRenderer::EMFPPlusDrawPolygon (const ::basegfx::B2DPolyPolygon& polygon, const ActionFactoryParameters& rParms,
commit 4a63bc37d6e550161d15748069120691ed6de297
Author: Jan Holesovsky <kendy at collabora.com>
Date:   Fri Jan 31 09:28:55 2014 +0000

    cairo canvas: Zero font's width means "the same as height".
    
    Change-Id: I1d24b2039fb3c615e672189d12c77e960cc858ee

diff --git a/canvas/source/cairo/cairo_textlayout.cxx b/canvas/source/cairo/cairo_textlayout.cxx
index 6075029..9f862c8 100644
--- a/canvas/source/cairo/cairo_textlayout.cxx
+++ b/canvas/source/cairo/cairo_textlayout.cxx
@@ -527,7 +527,11 @@ namespace cairocanvas
             if (aSysLayoutData.orientation)
                 cairo_matrix_rotate(&m, (3600 - aSysLayoutData.orientation) * M_PI / 1800.0);
 
-            cairo_matrix_scale(&m, aFont.GetWidth(), aFont.GetHeight());
+            long nWidth = aFont.GetWidth();
+            long nHeight = aFont.GetHeight();
+            if (nWidth == 0)
+                nWidth = nHeight;
+            cairo_matrix_scale(&m, nWidth, nHeight);
 
             //faux italics
             if (rSysFontData.bFakeItalic)
commit 7184ae74f4f6f0e89fae9936a6de554cfe64ea76
Author: Andrzej Hunt <andrzej.hunt at collabora.com>
Date:   Wed Jan 1 17:07:56 2014 +0000

    EMF+: mapping can rotate the width vector, so use resulting length.
    
    Otherwise (i.e. with non-vertical lines) the width will be incorrect,
    and can result in lines disappearing as the resulting X component
    can be tiny/approaching zero.
    
    (cherry picked from commit 83f2b3c590120a60b5e94fb1a15054ebe0745dbb)
    
    Conflicts:
    	cppcanvas/source/mtfrenderer/emfplus.cxx
    
    Change-Id: Icf3b7c10c627594600b517b8ff445f8df87c56f8

diff --git a/cppcanvas/source/mtfrenderer/emfplus.cxx b/cppcanvas/source/mtfrenderer/emfplus.cxx
index 36a6f30..0767a50 100644
--- a/cppcanvas/source/mtfrenderer/emfplus.cxx
+++ b/cppcanvas/source/mtfrenderer/emfplus.cxx
@@ -785,7 +785,7 @@ namespace cppcanvas
             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());
+                rStrokeAttributes.StrokeWidth = fabs((rState.mapModeTransform * rR.MapSize (width == 0.0 ? 0.05 : width, 0)).getLength());
             }
 
             void SetStrokeAttributes(rendering::StrokeAttributes& rStrokeAttributes)
commit e5bfc3127b33ceb782bff1270cf164bcf4a13e4b
Author: Andrzej Hunt <andrzej.hunt at collabora.com>
Date:   Wed Jan 1 17:36:54 2014 +0000

    EMF+: actually use lineJoin attribute for polygons.
    
    Change-Id: I5b369703333332598353d9817f0253bbe5fc3601
    (cherry picked from commit 9b1ceabd5f696500d4fe2acb89170bd987966a9b)

diff --git a/cppcanvas/source/mtfrenderer/emfplus.cxx b/cppcanvas/source/mtfrenderer/emfplus.cxx
index 4381ecf..36a6f30 100644
--- a/cppcanvas/source/mtfrenderer/emfplus.cxx
+++ b/cppcanvas/source/mtfrenderer/emfplus.cxx
@@ -620,6 +620,19 @@ namespace cppcanvas
             return rendering::PathCapType::BUTT;
         }
 
+        sal_Int8 lcl_convertLineJoinType(sal_uInt32 nEmfLineJoin)
+        {
+            switch (nEmfLineJoin)
+            {
+                case EmfPlusLineJoinTypeMiter:        // fall-through
+                case EmfPlusLineJoinTypeMiterClipped: return rendering::PathJoinType::MITER;
+                case EmfPlusLineJoinTypeBevel:        return rendering::PathJoinType::BEVEL;
+                case EmfPlusLineJoinTypeRound:        return rendering::PathJoinType::ROUND;
+            }
+            assert(false); // Line Join type isn't in specification.
+            return 0;
+        }
+
         struct EMFPCustomLineCap : public EMFPObject
         {
             sal_uInt32 type;
@@ -641,14 +654,7 @@ namespace cppcanvas
             {
                 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.JoinType = lcl_convertLineJoinType(strokeJoin);
 
                 aAttributes.MiterLimit = miterLimit;
             }
@@ -782,8 +788,10 @@ namespace cppcanvas
                 rStrokeAttributes.StrokeWidth = fabs((rState.mapModeTransform * rR.MapSize (width == 0.0 ? 0.05 : width, 0)).getX());
             }
 
-            void SetStrokeDashing(rendering::StrokeAttributes& rStrokeAttributes)
+            void SetStrokeAttributes(rendering::StrokeAttributes& rStrokeAttributes)
             {
+                rStrokeAttributes.JoinType = lcl_convertLineJoinType(lineJoin);
+
                 if (dashStyle != EmfPlusLineStyleSolid)
                 {
                     const float dash[] = {3, 3};
@@ -1394,7 +1402,7 @@ namespace cppcanvas
                 // but eg. dashing has to be additionally set only on the
                 // polygon
                 rendering::StrokeAttributes aPolygonAttributes(aCommonAttributes);
-                pen->SetStrokeDashing(aPolygonAttributes);
+                pen->SetStrokeAttributes(aPolygonAttributes);
 
                 basegfx::B2DPolyPolygon aFinalPolyPolygon;
 
commit 82b83b625f8ea4c7c5d8581a6428200f69338654
Author: Andrzej Hunt <andrzej.hunt at collabora.com>
Date:   Thu Dec 26 18:57:28 2013 +0000

    EMF+: Integer coordinate values are signed.
    
    Change-Id: I5babcec50d48dc2a6288a01685db61fbb7058680
    (cherry picked from commit d8dedc775cedf0e9daf9284bc7e3a0331ccd2963)

diff --git a/cppcanvas/source/mtfrenderer/emfplus.cxx b/cppcanvas/source/mtfrenderer/emfplus.cxx
index b4a442c..4381ecf 100644
--- a/cppcanvas/source/mtfrenderer/emfplus.cxx
+++ b/cppcanvas/source/mtfrenderer/emfplus.cxx
@@ -179,8 +179,8 @@ namespace cppcanvas
             {
                 for (int i = 0; i < nPoints; i ++) {
                     if (pathFlags & 0x4000) {
-                        // points are stored in short 16bit integer format
-                        sal_uInt16 x, y;
+                        // points are stored in signed short 16bit integer format
+                        sal_Int16 x, y;
 
                         s >> x >> y;
                         EMFP_DEBUG (printf ("EMF+\tpoint [x,y]: %hd,%hd\n", x, y));
commit 11cb4e38dd55b4d92535536954e438899f0859df
Author: Julien Nabet <serval2412 at yahoo.fr>
Date:   Sun Dec 29 18:06:11 2013 +0000

    Resolves: fdo#72961 Crash when you open ODFver.1.0/1.1 created by LibO-3.5/3.6
    
    It seems pAction may be NULL so let's keep on to check it.
    
    Change-Id: Ie1a48c96bfa930364053c7c3ad0c940559544e33
    (cherry picked from commit ebe616de53b98e419c39782c6615877a12f0edc7)

diff --git a/vcl/source/gdi/gdimtf.cxx b/vcl/source/gdi/gdimtf.cxx
index d78ef5a..113541e 100644
--- a/vcl/source/gdi/gdimtf.cxx
+++ b/vcl/source/gdi/gdimtf.cxx
@@ -2908,15 +2908,17 @@ SvStream& operator>>( SvStream& rIStm, GDIMetaFile& rGDIMetaFile )
             {
                 pAction = MetaAction::ReadMetaAction( rIStm, &aReadData );
 
-                if (pAction->GetType() == META_COMMENT_ACTION)
-                {
-                    MetaCommentAction* pCommentAct = static_cast<MetaCommentAction*>(pAction);
-                    if ( pCommentAct->GetComment() == "EMF_PLUS" )
-                        rGDIMetaFile.UseCanvas( sal_True );
-                }
 
                 if( pAction )
+                {
+                    if (pAction->GetType() == META_COMMENT_ACTION)
+                    {
+                        MetaCommentAction* pCommentAct = static_cast<MetaCommentAction*>(pAction);
+                        if ( pCommentAct->GetComment() == "EMF_PLUS" )
+                            rGDIMetaFile.UseCanvas( sal_True );
+                    }
                     rGDIMetaFile.AddAction( pAction );
+                }
             }
         }
         else
commit b8ad8e1e3e072e2740a00389a4fb46cde61010b3
Author: Matúš Kukan <matus.kukan at collabora.com>
Date:   Fri Dec 6 13:40:50 2013 +0000

    EMF+: Fill line cap object if EmfPlusCustomLineCapDataFillPath is set.
    
    Change-Id: I7b53a8f18e1fb24b1ae0322bdf0980e431a0725f
    (cherry picked from commit 131f3230d98f24faf57d9404e333cb1fb183345b)

diff --git a/cppcanvas/source/inc/implrenderer.hxx b/cppcanvas/source/inc/implrenderer.hxx
index e3c9707..bd78ee1 100644
--- a/cppcanvas/source/inc/implrenderer.hxx
+++ b/cppcanvas/source/inc/implrenderer.hxx
@@ -276,7 +276,7 @@ static float GetSwapFloat( SvStream& rSt )
             /// Render LineCap, like the start or end arrow of a polygon.
             /// @return how much we should shorten the original polygon.
             double EMFPPlusDrawLineCap(const ::basegfx::B2DPolygon& rPolygon, double fPolyLength,
-                    const ::basegfx::B2DPolyPolygon& rLineCap, bool bStart,
+                    const ::basegfx::B2DPolyPolygon& rLineCap, bool isFilled, bool bStart,
                     const com::sun::star::rendering::StrokeAttributes& rAttributes,
                     const ActionFactoryParameters& rParms, OutDevState& rState);
 
diff --git a/cppcanvas/source/mtfrenderer/emfplus.cxx b/cppcanvas/source/mtfrenderer/emfplus.cxx
index 0abad0d..b4a442c 100644
--- a/cppcanvas/source/mtfrenderer/emfplus.cxx
+++ b/cppcanvas/source/mtfrenderer/emfplus.cxx
@@ -626,6 +626,7 @@ namespace cppcanvas
             sal_uInt32 strokeStartCap, strokeEndCap, strokeJoin;
             float miterLimit;
             basegfx::B2DPolyPolygon polygon;
+            bool mbIsFilled;
 
         public:
             EMFPCustomLineCap() : EMFPObject()
@@ -652,7 +653,7 @@ namespace cppcanvas
                 aAttributes.MiterLimit = miterLimit;
             }
 
-            void ReadPath(SvStream& s, ImplRenderer& rR, bool bClosed)
+            void ReadPath(SvStream& s, ImplRenderer& rR, bool bFill)
             {
                 sal_Int32 pathLength;
                 s >> pathLength;
@@ -669,7 +670,7 @@ namespace cppcanvas
                 path.Read(s, pathFlags, rR);
 
                 polygon = path.GetPolygon(rR, false);
-                polygon.setClosed(bClosed);
+                mbIsFilled = bFill;
 
                 // transformation to convert the path to what LibreOffice
                 // expects
@@ -1322,7 +1323,7 @@ namespace cppcanvas
         }
 
         double ImplRenderer::EMFPPlusDrawLineCap(const ::basegfx::B2DPolygon& rPolygon, double fPolyLength,
-                const ::basegfx::B2DPolyPolygon& rLineCap, bool bStart, const rendering::StrokeAttributes& rAttributes,
+                const ::basegfx::B2DPolyPolygon& rLineCap, bool bIsFilled, bool bStart, const rendering::StrokeAttributes& rAttributes,
                 const ActionFactoryParameters& rParms, OutDevState& rState)
         {
             if (!rLineCap.count())
@@ -1351,6 +1352,20 @@ namespace cppcanvas
                 rParms.mrCurrActionIndex += pAction->getActionCount()-1;
             }
 
+            if (bIsFilled)
+            {
+                bool bWasFillColorSet = rState.isFillColorSet;
+                rState.isFillColorSet = true;
+                rState.fillColor = rState.lineColor;
+                ActionSharedPtr pAction2(internal::PolyPolyActionFactory::createPolyPolyAction(aArrow, rParms.mrCanvas, rState));
+                if (pAction2)
+                {
+                    maActions.push_back(MtfAction(pAction2, rParms.mrCurrActionIndex));
+                    rParms.mrCurrActionIndex += pAction2->getActionCount()-1;
+                }
+                rState.isFillColorSet = bWasFillColorSet;
+            }
+
             return rAttributes.StrokeWidth;
         }
 
@@ -1405,6 +1420,7 @@ namespace cppcanvas
                                 pen->customStartCap->SetAttributes(aAttributes);
 
                                 fStart = EMFPPlusDrawLineCap(aPolygon, fPolyLength, pen->customStartCap->polygon,
+                                        pen->customStartCap->mbIsFilled,
                                         true, aAttributes, rParms, rState);
                             }
 
@@ -1415,6 +1431,7 @@ namespace cppcanvas
                                 pen->customEndCap->SetAttributes(aAttributes);
 
                                 fEnd = EMFPPlusDrawLineCap(aPolygon, fPolyLength, pen->customEndCap->polygon,
+                                        pen->customEndCap->mbIsFilled,
                                         false, aAttributes, rParms, rState);
                             }
 
commit 9991faaded25e9494a02619f053bb04b8aa2ec1a
Author: Andrzej J.R. Hunt <andrzej.hunt at collabora.com>
Date:   Thu Dec 5 11:36:53 2013 +0000

    EMF+: force canvas if EMF+ comments are used.
    
    Without this the drawinglayer renderer is used, whereas
    only the canvas renderer supports EMF+.
    
    Change-Id: Id8a10e400e08c1913e7d6864a51f7b73fc9be437
    (cherry picked from commit be7d87bea2611eb316b9b379aebc031179d4f794)

diff --git a/vcl/source/gdi/gdimtf.cxx b/vcl/source/gdi/gdimtf.cxx
index 172b477..d78ef5a 100644
--- a/vcl/source/gdi/gdimtf.cxx
+++ b/vcl/source/gdi/gdimtf.cxx
@@ -2908,6 +2908,13 @@ SvStream& operator>>( SvStream& rIStm, GDIMetaFile& rGDIMetaFile )
             {
                 pAction = MetaAction::ReadMetaAction( rIStm, &aReadData );
 
+                if (pAction->GetType() == META_COMMENT_ACTION)
+                {
+                    MetaCommentAction* pCommentAct = static_cast<MetaCommentAction*>(pAction);
+                    if ( pCommentAct->GetComment() == "EMF_PLUS" )
+                        rGDIMetaFile.UseCanvas( sal_True );
+                }
+
                 if( pAction )
                     rGDIMetaFile.AddAction( pAction );
             }
commit 5c17ea50509d46a26cf4204e6aa7294ba78f4739
Author: Matúš Kukan <matus.kukan at collabora.com>
Date:   Wed Dec 4 15:57:34 2013 +0000

    EMF+: Do not ignore source rectangle of the image to be rendered.
    
    Conflicts:
    	cppcanvas/source/mtfrenderer/emfplus.cxx
    
    Change-Id: I4f861c7653c89d8f1ca73696e885f33f7bfc3b06

diff --git a/cppcanvas/source/mtfrenderer/emfplus.cxx b/cppcanvas/source/mtfrenderer/emfplus.cxx
index 8b0b767..0abad0d 100644
--- a/cppcanvas/source/mtfrenderer/emfplus.cxx
+++ b/cppcanvas/source/mtfrenderer/emfplus.cxx
@@ -1808,6 +1808,7 @@ namespace cppcanvas
                             sal_Int32 aCount;
 
                             ReadRectangle (rMF, sx, sy, sw, sh);
+                            Rectangle aSource(Point(sx, sy), Size(sw, sh));
 
                             EMFP_DEBUG (printf ("EMF+ %s source rectangle: %f,%f %fx%f\n", type == EmfPlusRecordTypeDrawImagePoints ? "DrawImagePoints" : "DrawImage", sx, sy, sw, sh));
 
@@ -1848,6 +1849,7 @@ namespace cppcanvas
 
                             if (bValid) {
                                 BitmapEx aBmp( image.graphic.GetBitmapEx () );
+                                aBmp.Crop( aSource );
 
                                 Size aSize( aBmp.GetSizePixel() );
                                 EMFP_DEBUG (printf ("EMF+ bitmap size: %ldx%ld\n", aSize.Width(), aSize.Height()));
commit cc9fd0bf405ddc29a58672ce9d100946ff4f888c
Author: Radek Doulik <rodo at novell.com>
Date:   Sun Apr 28 22:00:00 2013 +0000

    Fix bnc#795857 Use correct sizes for EMF+ bitmap rendering
    
    Fix pdf export wrong size issues for embedded EMF+ images.
    
    (cherry picked from commit 4c676625d4016d428e9becd5512b7cfc8b0c4b24)
    
    Conflicts:
    	vcl/inc/vcl/gdimtf.hxx
    	vcl/source/gdi/gdimtf.cxx
    
    Signed-off-by: Michael Meeks <michael.meeks at suse.com>
    
    Conflicts:
    	vcl/source/gdi/gdimtf.cxx
    
    Change-Id: I998c9535bde32fc9f452d61d7cb7609c95f5528d

diff --git a/vcl/inc/vcl/gdimtf.hxx b/vcl/inc/vcl/gdimtf.hxx
index ecefb90..90fce69 100644
--- a/vcl/inc/vcl/gdimtf.hxx
+++ b/vcl/inc/vcl/gdimtf.hxx
@@ -124,7 +124,7 @@ private:
                                                       const OutputDevice&   rMapDev,
                                                       const PolyPolygon&    rPolyPoly,
                                                       const Gradient&       rGrad       );
-    SAL_DLLPRIVATE bool          ImplPlayWithRenderer( OutputDevice* pOut, const Point& rPos, Size rDestSize );
+    SAL_DLLPRIVATE bool          ImplPlayWithRenderer( OutputDevice* pOut, const Point& rPos, Size rLogicDestSize );
     SAL_DLLPRIVATE void          ImplDelegate2PluggableRenderer( const MetaCommentAction* pAct, OutputDevice* pOut );
 
 
diff --git a/vcl/source/gdi/gdimtf.cxx b/vcl/source/gdi/gdimtf.cxx
index 42ed63c..172b477 100644
--- a/vcl/source/gdi/gdimtf.cxx
+++ b/vcl/source/gdi/gdimtf.cxx
@@ -399,7 +399,7 @@ void GDIMetaFile::Play( OutputDevice* pOut, size_t nPos )
 
         OSL_TRACE("GDIMetaFile::Play on device of size: %d x %d", pOut->GetOutputSizePixel().Width(), pOut->GetOutputSizePixel().Height());
 
-        if( !ImplPlayWithRenderer( pOut, Point(0,0), pOut->GetOutputSizePixel() ) ) {
+        if( !ImplPlayWithRenderer( pOut, Point(0,0), pOut->GetOutputSize() ) ) {
             size_t  i  = 0;
             for( size_t nCurPos = nCurrentActionElement; nCurPos < nPos; nCurPos++ )
             {
@@ -428,13 +428,13 @@ void GDIMetaFile::Play( OutputDevice* pOut, size_t nPos )
     }
 }
 
-// ------------------------------------------------------------------------
-
-bool GDIMetaFile::ImplPlayWithRenderer( OutputDevice* pOut, const Point& rPos, Size rDestSize )
+bool GDIMetaFile::ImplPlayWithRenderer( OutputDevice* pOut, const Point& rPos, Size rLogicDestSize )
 {
     if (!bUseCanvas)
         return false;
 
+    Size rDestSize( pOut->LogicToPixel( rLogicDestSize ) );
+
     const Window* win = dynamic_cast <Window*> ( pOut );
 
     if (!win)
@@ -500,7 +500,10 @@ bool GDIMetaFile::ImplPlayWithRenderer( OutputDevice* pOut, const Point& rPos, S
                         Bitmap aMask( pSalMask );
                         AlphaMask aAlphaMask( aMask );
                         BitmapEx aBitmapEx( aBitmap, aAlphaMask );
-                        pOut->DrawBitmapEx( rPos, aBitmapEx );
+                        if ( pOut->GetMapMode() == MAP_PIXEL )
+                            pOut->DrawBitmapEx( rPos, aBitmapEx );
+                        else
+                            pOut->DrawBitmapEx( rPos, rLogicDestSize, aBitmapEx );
                         return true;
                     }
 
@@ -606,7 +609,7 @@ void GDIMetaFile::Play( OutputDevice* pOut, const Point& rPos,
     {
         GDIMetaFile*    pMtf = pOut->GetConnectMetaFile();
 
-        if( ImplPlayWithRenderer( pOut, rPos, aDestSize ) )
+        if( ImplPlayWithRenderer( pOut, rPos, rSize ) )
             return;
 
         Size aTmpPrefSize( pOut->LogicToPixel( GetPrefSize(), aDrawMap ) );
diff --git a/vcl/source/gdi/pdfwriter_impl2.cxx b/vcl/source/gdi/pdfwriter_impl2.cxx
index beee461..8579168 100644
--- a/vcl/source/gdi/pdfwriter_impl2.cxx
+++ b/vcl/source/gdi/pdfwriter_impl2.cxx
@@ -769,7 +769,7 @@ void PDFWriterImpl::playMetafile( const GDIMetaFile& i_rMtf, vcl::PDFExtOutDevDa
                     const MetaBmpAction* pA = (const MetaBmpAction*) pAction;
                     BitmapEx aBitmapEx( pA->GetBitmap() );
                     Size aSize( OutputDevice::LogicToLogic( aBitmapEx.GetPrefSize(),
-                            aBitmapEx.GetPrefMapMode(), pDummyVDev->GetMapMode() ) );
+                                                            aBitmapEx.GetPrefMapMode(), pDummyVDev->GetMapMode() ) );
                     if( ! ( aSize.Width() && aSize.Height() ) )
                         aSize = pDummyVDev->PixelToLogic( aBitmapEx.GetSizePixel() );
                     implWriteBitmapEx( pA->GetPoint(), aSize, aBitmapEx, pDummyVDev, i_rContext );
commit f8f8c3ab3741643c0601618ef9758d9049e526c1
Author: Jan Holesovsky <kendy at collabora.com>
Date:   Wed Nov 27 10:51:32 2013 +0000

    EMF+: Line thickness has to be considered when drawing the caps.
    
    Change-Id: I6043ee3c214f453afaef06125993c73be624c07e

diff --git a/basegfx/inc/basegfx/polygon/b2dlinegeometry.hxx b/basegfx/inc/basegfx/polygon/b2dlinegeometry.hxx
index 934158f..62e230f 100644
--- a/basegfx/inc/basegfx/polygon/b2dlinegeometry.hxx
+++ b/basegfx/inc/basegfx/polygon/b2dlinegeometry.hxx
@@ -63,6 +63,10 @@ namespace basegfx
             again calculating the length (which may be expensive with beziers). If 0.0 is
             given, the length is calculated on demand.
 
+            @param fShift
+            When it is necessary to count with the thickness of the line, it
+            makes sense to move the start position slightly - so define the shift.
+
             @return
             The Line start and end polygon, correctly rotated and scaled
         */
@@ -73,7 +77,8 @@ namespace basegfx
             double fWidth,
             double fCandidateLength = 0.0, // 0.0 -> calculate self
             double fDockingPosition = 0.5, // 0->top, 1->bottom
-            double* pConsumedLength = 0L);
+            double* pConsumedLength = 0L,
+            double fShift = 0.0);
 
         /** create filled polygon geometry for lines with a line width
 
diff --git a/basegfx/source/polygon/b2dlinegeometry.cxx b/basegfx/source/polygon/b2dlinegeometry.cxx
index 329b486..c6b5c74 100644
--- a/basegfx/source/polygon/b2dlinegeometry.cxx
+++ b/basegfx/source/polygon/b2dlinegeometry.cxx
@@ -44,7 +44,8 @@ namespace basegfx
             double fWidth,
             double fCandidateLength,
             double fDockingPosition, // 0->top, 1->bottom
-            double* pConsumedLength)
+            double* pConsumedLength,
+            double fShift)
         {
             B2DPolyPolygon aRetval;
             OSL_ENSURE(rCandidate.count() > 1L, "createAreaGeometryForLineStartEnd: Line polygon has too less points (!)");
@@ -89,7 +90,7 @@ namespace basegfx
                 const double fArrowYLength(B2DVector(aUpperCenter).getLength());
 
                 // move arrow to have docking position centered
-                aArrowTransform.translate(0.0, -fArrowYLength * fDockingPosition);
+                aArrowTransform.translate(0.0, -fArrowYLength * fDockingPosition + fShift);
 
                 // prepare polygon length
                 if(fTools::equalZero(fCandidateLength))
@@ -98,7 +99,7 @@ namespace basegfx
                 }
 
                 // get the polygon vector we want to plant this arrow on
-                const double fConsumedLength(fArrowYLength * (1.0 - fDockingPosition));
+                const double fConsumedLength(fArrowYLength * (1.0 - fDockingPosition) - fShift);
                 const B2DVector aHead(rCandidate.getB2DPoint((bStart) ? 0L : rCandidate.count() - 1L));
                 const B2DVector aTail(getPositionAbsolute(rCandidate,
                     (bStart) ? fConsumedLength : fCandidateLength - fConsumedLength, fCandidateLength));
diff --git a/cppcanvas/source/inc/implrenderer.hxx b/cppcanvas/source/inc/implrenderer.hxx
index 82099a2..e3c9707 100644
--- a/cppcanvas/source/inc/implrenderer.hxx
+++ b/cppcanvas/source/inc/implrenderer.hxx
@@ -274,7 +274,8 @@ static float GetSwapFloat( SvStream& rSt )
             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,
+            /// @return how much we should shorten the original polygon.
+            double 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);
diff --git a/cppcanvas/source/mtfrenderer/emfplus.cxx b/cppcanvas/source/mtfrenderer/emfplus.cxx
index dca9667..8b0b767 100644
--- a/cppcanvas/source/mtfrenderer/emfplus.cxx
+++ b/cppcanvas/source/mtfrenderer/emfplus.cxx
@@ -1321,13 +1321,12 @@ namespace cppcanvas
             }
         }
 
-
-        void ImplRenderer::EMFPPlusDrawLineCap(const ::basegfx::B2DPolygon& rPolygon, double fPolyLength,
+        double 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;
+                return 0.0;
 
             // it seems the line caps in EMF+ are 4*larger than what
             // LibreOffice expects, and the mapping in
@@ -1339,7 +1338,7 @@ namespace cppcanvas
 
             basegfx::B2DPolyPolygon aArrow(basegfx::tools::createAreaGeometryForLineStartEnd(
                         rPolygon, rLineCap, bStart,
-                        fWidth, fPolyLength, 0.0, NULL));
+                        fWidth, fPolyLength, 0, NULL, rAttributes.StrokeWidth));
 
             // createAreaGeometryForLineStartEnd from some reason always sets
             // the path as closed, correct it
@@ -1351,6 +1350,8 @@ namespace cppcanvas
                 maActions.push_back(MtfAction(pAction, rParms.mrCurrActionIndex));
                 rParms.mrCurrActionIndex += pAction->getActionCount()-1;
             }
+
+            return rAttributes.StrokeWidth;
         }
 
         void ImplRenderer::EMFPPlusDrawPolygon (const ::basegfx::B2DPolyPolygon& polygon, const ActionFactoryParameters& rParms,
@@ -1380,49 +1381,59 @@ namespace cppcanvas
                 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));
-                    rParms.mrCurrActionIndex += pPolyAction->getActionCount()-1;
-                }
+                basegfx::B2DPolyPolygon aFinalPolyPolygon;
 
-                // render line starts & ends
-                if (pen->customStartCap || pen->customEndCap)
+                // render line starts & ends if present
+                if (!pen->customStartCap && !pen->customEndCap)
+                    aFinalPolyPolygon = aPolyPolygon;
+                else
                 {
                     for (sal_uInt32 i = 0; i < aPolyPolygon.count(); ++i)
                     {
-                        // break the polypolygon into polygons
                         basegfx::B2DPolygon aPolygon(aPolyPolygon.getB2DPolygon(i));
 
-                        if (aPolygon.isClosed())
-                            continue;
+                        if (!aPolygon.isClosed())
+                        {
+                            double fStart = 0.0;
+                            double fEnd = 0.0;
+                            double fPolyLength = basegfx::tools::getLength(aPolygon);
 
-                        double fPolyLength = basegfx::tools::getLength(aPolygon);
+                            // line start
+                            if (pen->customStartCap)
+                            {
+                                rendering::StrokeAttributes aAttributes(aCommonAttributes);
+                                pen->customStartCap->SetAttributes(aAttributes);
 
-                        // line start
-                        if (pen->customStartCap)
-                        {
-                            rendering::StrokeAttributes aAttributes(aCommonAttributes);
-                            pen->customStartCap->SetAttributes(aAttributes);
+                                fStart = EMFPPlusDrawLineCap(aPolygon, fPolyLength, pen->customStartCap->polygon,
+                                        true, aAttributes, rParms, rState);
+                            }
 
-                            EMFPPlusDrawLineCap(aPolygon, fPolyLength, pen->customStartCap->polygon,
-                                    true, aAttributes, rParms, rState);
-                        }
+                            // line end
+                            if (pen->customEndCap)
+                            {
+                                rendering::StrokeAttributes aAttributes(aCommonAttributes);
+                                pen->customEndCap->SetAttributes(aAttributes);
 
-                        // line end
-                        if (pen->customEndCap)
-                        {
-                            rendering::StrokeAttributes aAttributes(aCommonAttributes);
-                            pen->customEndCap->SetAttributes(aAttributes);
+                                fEnd = EMFPPlusDrawLineCap(aPolygon, fPolyLength, pen->customEndCap->polygon,
+                                        false, aAttributes, rParms, rState);
+                            }
 
-                            EMFPPlusDrawLineCap(aPolygon, fPolyLength, pen->customEndCap->polygon,
-                                    false, aAttributes, rParms, rState);
+                            // build new poly, consume something from the old poly
+                            if (fStart != 0.0 || fEnd != 0.0)
+                                aPolygon = basegfx::tools::getSnippetAbsolute(aPolygon, fStart, fPolyLength - fEnd, fPolyLength);
                         }
+
+                        aFinalPolyPolygon.append(aPolygon);
                     }
                 }
 
+                // finally render the polygon
+                ActionSharedPtr pPolyAction(internal::PolyPolyActionFactory::createPolyPolyAction(aFinalPolyPolygon, rParms.mrCanvas, rState, aPolygonAttributes));
+                if( pPolyAction )
+                {
+                    maActions.push_back(MtfAction(pPolyAction, rParms.mrCurrActionIndex));
+                    rParms.mrCurrActionIndex += pPolyAction->getActionCount()-1;
+                }
             }
         }
 
commit 2c2856cf288cf899c2b848c72f8c08aa7a6d7a81
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 4537368..82099a2 100644
--- a/cppcanvas/source/inc/implrenderer.hxx
+++ b/cppcanvas/source/inc/implrenderer.hxx
@@ -272,7 +272,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 7be23f6..dca9667 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
@@ -587,6 +606,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;
@@ -604,21 +754,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};
@@ -660,12 +824,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;
 
@@ -731,24 +901,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);
@@ -1141,7 +1321,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];
@@ -1155,24 +1367,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);
+                        }
+                    }
+                }
+
             }
         }
 
@@ -1496,7 +1746,7 @@ namespace cppcanvas
 
                         rendering::StrokeAttributes aStrokeAttributes;
 
-                        pen->SetStrokeAttributes (aStrokeAttributes, *this, rState);
+                        pen->SetStrokeWidth (aStrokeAttributes, *this, rState);
 
             ActionSharedPtr pPolyAction(
                 internal::PolyPolyActionFactory::createPolyPolyAction(
commit ee52a8acbe145795c0fc4bc954286971d76b1026
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 6025eb7..7be23f6 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
@@ -610,6 +617,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 )
@@ -645,7 +680,10 @@ namespace cppcanvas
                     mitterLimit = 0;
 
                 if (penFlags & 32)
+                {
                     s >> dashStyle;
+                    SAL_INFO("cppcanvas.emf", "EMF+\t\tdashStyle: 0x" << std::hex << dashStyle);
+                }
                 else
                     dashStyle = 0;
 
@@ -659,14 +697,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 cc0de7e6a93596745936e7e715c8d46ad97e5b0e
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 f8b9884..541d68d 100644
--- a/vcl/source/filter/wmf/enhwmf.cxx
+++ b/vcl/source/filter/wmf/enhwmf.cxx
@@ -485,8 +485,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 :
@@ -518,14 +518,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;
 
@@ -917,7 +917,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;
 
@@ -1352,7 +1352,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;
@@ -1360,7 +1360,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();

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list