[Libreoffice-commits] core.git: Branch 'libreoffice-5-0' - 21 commits - filter/source include/filter oox/source sw/qa sw/source vcl/headless vcl/inc vcl/unx

Julien Nabet serval2412 at yahoo.fr
Thu Jun 25 12:34:54 PDT 2015


 filter/source/msfilter/escherex.cxx           |   47 ++++---
 include/filter/msfilter/escherex.hxx          |   12 +
 oox/source/export/drawingml.cxx               |   58 ++++++---
 oox/source/export/vmlexport.cxx               |   81 +++++++------
 sw/qa/extras/ooxmlexport/data/fdo60957-2.docx |binary
 sw/qa/extras/ooxmlexport/data/kde216114-1.odt |binary
 sw/qa/extras/ooxmlexport/data/kde302504-1.odt |binary
 sw/qa/extras/ooxmlexport/data/ooo106020-1.odt |binary
 sw/qa/extras/ooxmlexport/data/ooo34469-1.odt  |binary
 sw/qa/extras/ooxmlexport/data/ooo39845-7.odt  |binary
 sw/qa/extras/ooxmlexport/data/ooo47778-3.odt  |binary
 sw/qa/extras/ooxmlexport/data/ooo47778-4.odt  |binary
 sw/qa/extras/ooxmlexport/data/ooo67471-2.odt  |binary
 sw/qa/extras/ooxmlexport/data/ooo72950-1.odt  |binary
 sw/qa/extras/ooxmlexport/ooxmlexport5.cxx     |   53 ++++++++
 sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx |   13 ++
 sw/source/filter/ww8/WW8TableInfo.cxx         |   95 ++++++++++-----
 sw/source/filter/ww8/WW8TableInfo.hxx         |   21 ++-
 sw/source/filter/ww8/docxattributeoutput.cxx  |   42 ++++--
 sw/source/filter/ww8/rtfsdrexport.cxx         |   79 +++++++------
 sw/source/filter/ww8/wrtww8.cxx               |   96 +++++++++++----
 sw/source/filter/ww8/wrtww8.hxx               |    4 
 vcl/headless/svpgdi.cxx                       |  158 +++++++++++++++++++++++---
 vcl/inc/headless/svpgdi.hxx                   |    9 +
 vcl/inc/unx/gtk/gtkgdi.hxx                    |    2 
 vcl/unx/gtk/window/gtksalframe.cxx            |   26 ++--
 vcl/unx/gtk3/gdi/gtk3salnativewidgets-gtk.cxx |   25 ----
 27 files changed, 585 insertions(+), 236 deletions(-)

New commits:
commit 1b39e54ecd02fe16ad045bb787c09ded76c4ac33
Author: Julien Nabet <serval2412 at yahoo.fr>
Date:   Wed Jun 24 22:41:31 2015 +0200

    GtkSettings:gtk-menu-images deprecated
    
    Reviewed-on: https://gerrit.libreoffice.org/16456
    Reviewed-by: Caolán McNamara <caolanm at redhat.com>
    Tested-by: Caolán McNamara <caolanm at redhat.com>
    (cherry picked from commit c301d8c8fa1de36d8aae03cfa76772b537b10980)
    
    Change-Id: I120c33bf726150506d282e972facd4dca0db83aa

diff --git a/vcl/unx/gtk3/gdi/gtk3salnativewidgets-gtk.cxx b/vcl/unx/gtk3/gdi/gtk3salnativewidgets-gtk.cxx
index b13674c..ac99078 100644
--- a/vcl/unx/gtk3/gdi/gtk3salnativewidgets-gtk.cxx
+++ b/vcl/unx/gtk3/gdi/gtk3salnativewidgets-gtk.cxx
@@ -1740,12 +1740,11 @@ void GtkSalGraphics::updateSettings( AllSettings& rSettings )
     aMouseSettings.SetMenuDelay( MENU_POPUP_DELAY );
     rSettings.SetMouseSettings( aMouseSettings );
 
-    gboolean showmenuicons = true, primarybuttonwarps = false;
+    gboolean primarybuttonwarps = false;
     g_object_get( pSettings,
-        "gtk-menu-images", &showmenuicons,
         "gtk-primary-button-warps-slider", &primarybuttonwarps,
         (char *)NULL );
-    aStyleSet.SetPreferredUseImagesInMenus(showmenuicons);
+    aStyleSet.SetPreferredUseImagesInMenus(false);
     aStyleSet.SetPrimaryButtonWarpsSlider(primarybuttonwarps);
 
     // set scrollbar settings
commit 155ada9a58fba6ab48029135f6cb9778e2fddffd
Author: Julien Nabet <serval2412 at yahoo.fr>
Date:   Tue Jun 23 18:37:11 2015 +0200

    GtkSettings:gtk-menu-popup-delay deprecated
    
    I took example from https://mail.gnome.org/archives/commits-list/2013-June/msg06434.html
    
    Reviewed-on: https://gerrit.libreoffice.org/16432
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Caolán McNamara <caolanm at redhat.com>
    Tested-by: Caolán McNamara <caolanm at redhat.com>
    (cherry picked from commit 25befc0a1b1448527c645ed1963b4f29d3126a53)
    
    Change-Id: I5fb090c3245848c92238f34259f1a2f77f9080c7

diff --git a/vcl/unx/gtk3/gdi/gtk3salnativewidgets-gtk.cxx b/vcl/unx/gtk3/gdi/gtk3salnativewidgets-gtk.cxx
index 84c138c..b13674c 100644
--- a/vcl/unx/gtk3/gdi/gtk3salnativewidgets-gtk.cxx
+++ b/vcl/unx/gtk3/gdi/gtk3salnativewidgets-gtk.cxx
@@ -1725,19 +1725,19 @@ void GtkSalGraphics::updateSettings( AllSettings& rSettings )
         aStyleSet.SetCursorBlinkTime( STYLE_CURSOR_NOBLINKTIME );
 
     MouseSettings aMouseSettings = rSettings.GetMouseSettings();
-    int iDoubleClickTime, iDoubleClickDistance, iDragThreshold, iMenuPopupDelay;
+    int iDoubleClickTime, iDoubleClickDistance, iDragThreshold;
+    static const int MENU_POPUP_DELAY = 225;
     g_object_get( pSettings,
                   "gtk-double-click-time", &iDoubleClickTime,
                   "gtk-double-click-distance", &iDoubleClickDistance,
                   "gtk-dnd-drag-threshold", &iDragThreshold,
-                  "gtk-menu-popup-delay", &iMenuPopupDelay,
                   (char *)NULL );
     aMouseSettings.SetDoubleClickTime( iDoubleClickTime );
     aMouseSettings.SetDoubleClickWidth( iDoubleClickDistance );
     aMouseSettings.SetDoubleClickHeight( iDoubleClickDistance );
     aMouseSettings.SetStartDragWidth( iDragThreshold );
     aMouseSettings.SetStartDragHeight( iDragThreshold );
-    aMouseSettings.SetMenuDelay( iMenuPopupDelay );
+    aMouseSettings.SetMenuDelay( MENU_POPUP_DELAY );
     rSettings.SetMouseSettings( aMouseSettings );
 
     gboolean showmenuicons = true, primarybuttonwarps = false;
commit 432c33cc1059c220194e2c4a949ffb51b4dddcc4
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Thu Jun 25 20:21:46 2015 +0100

    these ancient baselines are breaking my spirit
    
    Change-Id: I96dbe2c1213c78da1114f9270953334a38c7b2ae
    (cherry picked from commit 6a01c78435c4237e8702966d30de2a47b58e7620)

diff --git a/vcl/unx/gtk/window/gtksalframe.cxx b/vcl/unx/gtk/window/gtksalframe.cxx
index 99adfff..a7b9b88 100644
--- a/vcl/unx/gtk/window/gtksalframe.cxx
+++ b/vcl/unx/gtk/window/gtksalframe.cxx
@@ -2872,6 +2872,19 @@ void GtkSalFrame::Sync()
     gdk_display_sync( getGdkDisplay() );
 }
 
+#ifndef GDK_Open
+#define GDK_Open 0x1008ff6b
+#endif
+#ifndef GDK_Paste
+#define GDK_Paste 0x1008ff6d
+#endif
+#ifndef GDK_Copy
+#define GDK_Copy 0x1008ff57
+#endif
+#ifndef GDK_Cut
+#define GDK_Cut 0x1008ff58
+#endif
+
 void GtkSalFrame::KeyCodeToGdkKey(const vcl::KeyCode& rKeyCode,
     guint* pGdkKeyCode, GdkModifierType *pGdkModifiers)
 {
commit c2a667666fb1bb286c22ba87d18d81bb53029079
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Sat Jun 20 18:04:12 2015 +0100

    fix assert on exporting ooo106020-1.odt to docx
    
    the dread msword column limit
    
    Change-Id: Icbf7fc396de62286d523516da815dabf62336567
    (cherry picked from commit 20e64b6012442749d01810869229613ea36be3a9)

diff --git a/sw/qa/extras/ooxmlexport/data/ooo106020-1.odt b/sw/qa/extras/ooxmlexport/data/ooo106020-1.odt
new file mode 100644
index 0000000..9cc774b
Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/ooo106020-1.odt differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx
index 0c215a9..dd3a11f 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx
@@ -858,6 +858,14 @@ DECLARE_OOXMLEXPORT_TEST(fdo60957, "fdo60957-2.docx")
         assertXPath(pXmlDoc, "//w:tbl", 2);
 }
 
+//This has more cells than msword supports, we must balance the
+//number of cell start and ends
+DECLARE_OOXMLEXPORT_TEST(testOO106020, "ooo106020-1.odt")
+{
+    if (xmlDocPtr pXmlDoc = parseExport("word/document.xml"))
+        assertXPath(pXmlDoc, "//w:tbl", 1);
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx
index 0064d4d..54b511c 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -688,16 +688,18 @@ void DocxAttributeOutput::EndSdtBlock()
     m_pSerializer->endElementNS( XML_w, XML_sdt );
 }
 
+#define MAX_CELL_IN_WORD 62
+
 void DocxAttributeOutput::SyncNodelessCells(ww8::WW8TableNodeInfoInner::Pointer_t pInner, sal_Int32 nCell, sal_uInt32 nRow)
 {
     sal_Int32 nOpenCell = lastOpenCell.back();
-    if (nOpenCell != -1 && nOpenCell != nCell)
+    if (nOpenCell != -1 && nOpenCell != nCell && nOpenCell < MAX_CELL_IN_WORD)
         EndTableCell(pInner, nOpenCell, nRow);
 
     sal_Int32 nClosedCell = lastClosedCell.back();
     for (sal_Int32 i = nClosedCell+1; i < nCell; ++i)
     {
-        if (i >= 62)    //words limit
+        if (i >= MAX_CELL_IN_WORD)
             break;
 
         if (i == 0)
@@ -725,11 +727,11 @@ void DocxAttributeOutput::FinishTableRowCell( ww8::WW8TableNodeInfoInner::Pointe
         // so simply if there are more columns, don't close the last one msoffice will handle
         // and merge the contents of the remaining ones into it (since we don't close the cell
         // here, following ones will not be opened)
-        const bool limitWorkaround = (nCell >= 62 && !pInner->isEndOfLine());
+        const bool limitWorkaround = (nCell >= MAX_CELL_IN_WORD && !pInner->isEndOfLine());
         const bool bEndCell = pInner->isEndOfCell() && !limitWorkaround;
         const bool bEndRow = pInner->isEndOfLine();
 
-        if ( bEndCell )
+        if (bEndCell)
         {
             while (pInner->getDepth() < m_tableReference->m_nTableDepth)
             {
commit fbe0ba4c92e4feef429fcab4aa49fdef6ac63b8c
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Wed Jun 17 13:21:23 2015 +0100

    fix crash on re-export of fdo60957-2.docx to docx
    
    Change-Id: I1a74a5f1877bfa72818ff0a38788eafe77eea581
    (cherry picked from commit 89c85a4b7674ddfd697d539d59d27176c683a46c)

diff --git a/sw/qa/extras/ooxmlexport/data/fdo60957-2.docx b/sw/qa/extras/ooxmlexport/data/fdo60957-2.docx
new file mode 100644
index 0000000..3819aaf
Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/fdo60957-2.docx differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx
index dddbdee..0c215a9 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx
@@ -849,6 +849,15 @@ DECLARE_OOXMLEXPORT_TEST(testOO72950, "ooo72950-1.odt")
         assertXPath(pXmlDoc, "//w:tbl", 1);
 }
 
+//There are two tables to export in this doc the second of which is inside a
+//frame anchored to first cell of the first table. They must not be
+//considered the same table
+DECLARE_OOXMLEXPORT_TEST(fdo60957, "fdo60957-2.docx")
+{
+    if (xmlDocPtr pXmlDoc = parseExport("word/document.xml"))
+        assertXPath(pXmlDoc, "//w:tbl", 2);
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx
index 88cfdc7..0064d4d 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -567,15 +567,15 @@ void DocxAttributeOutput::EndParagraph( ww8::WW8TableNodeInfoInner::Pointer_t pT
     // Write framePr
     if(!aFramePrTextbox.empty())
     {
-        ww8::WW8TableInfo::Pointer_t pOldTableInfo = m_rExport.m_pTableInfo;
         for (std::vector< boost::shared_ptr<sw::Frame> > ::iterator it = aFramePrTextbox.begin() ; it != aFramePrTextbox.end(); ++it)
         {
-            m_rExport.m_pTableInfo = ww8::WW8TableInfo::Pointer_t(new ww8::WW8TableInfo());
+            DocxTableExportContext aTableExportContext;
+            pushToTableExportContext(aTableExportContext);
             m_pCurrentFrame = it->get();
             m_rExport.SdrExporter().writeOnlyTextOfFrame(it->get());
             m_pCurrentFrame = NULL;
+            popFromTableExportContext(aTableExportContext);
         }
-        m_rExport.m_pTableInfo = pOldTableInfo;
         aFramePrTextbox.clear();
     }
     // Check for end of cell, rows, tables here
commit b8a6477f4ba00b6253cfb33d4e8edccf60685168
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Thu Jun 11 14:30:18 2015 +0100

    best effort export of ooo72950-1.odt to docx without crashing
    
    the curious case of ooo72950-1.odt which has no nodes in the first line of the
    table as seen from the visual layout perspective seeing as the table is split
    over two columns with the second column portion of the table higher than the
    left column portion
    
    Change-Id: I38526bf80ff8cef1688aa5f5f686e437c4a3d6e5
    (cherry picked from commit f81c775b0782259c1b5504af859237fd71ac89e6)

diff --git a/sw/qa/extras/ooxmlexport/data/ooo72950-1.odt b/sw/qa/extras/ooxmlexport/data/ooo72950-1.odt
new file mode 100644
index 0000000..df0ac91
Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/ooo72950-1.odt differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx
index 14be93e..dddbdee 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx
@@ -843,6 +843,12 @@ DECLARE_OOXMLEXPORT_TEST(testKDE216114, "kde216114-1.odt")
         assertXPath(pXmlDoc, "//w:pict", 1);
 }
 
+DECLARE_OOXMLEXPORT_TEST(testOO72950, "ooo72950-1.odt")
+{
+    if (xmlDocPtr pXmlDoc = parseExport("word/document.xml"))
+        assertXPath(pXmlDoc, "//w:tbl", 1);
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx
index c6e980c..88cfdc7 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -250,7 +250,7 @@ void DocxAttributeOutput::StartParagraph( ww8::WW8TableNodeInfo::Pointer_t pText
 
         sal_uInt32 nRow = pTextNodeInfo->getRow();
         sal_uInt32 nCell = pTextNodeInfo->getCell();
-        if ( nRow == 0 && nCell == 0 )
+        if (nCell == 0)
         {
             // Do we have to start the table?
             // [If we are at the right depth already, it means that we
@@ -260,14 +260,14 @@ void DocxAttributeOutput::StartParagraph( ww8::WW8TableNodeInfo::Pointer_t pText
             if ( nCurrentDepth > m_tableReference->m_nTableDepth )
             {
                 // Start all the tables that begin here
-                for ( sal_uInt32 nDepth = m_tableReference->m_nTableDepth + 1; nDepth <= pTextNodeInfo->getDepth(); ++nDepth )
+                for ( sal_uInt32 nDepth = m_tableReference->m_nTableDepth + 1; nDepth <= nCurrentDepth; ++nDepth )
                 {
                     ww8::WW8TableNodeInfoInner::Pointer_t pInner( pTextNodeInfo->getInnerForDepth( nDepth ) );
 
                     StartTable( pInner );
                     StartTableRow( pInner );
 
-                    StartTableCell(pInner, 0, 0);
+                    StartTableCell(pInner, 0, nDepth == nCurrentDepth ? nRow : 0);
                 }
 
                 m_tableReference->m_nTableDepth = nCurrentDepth;
commit eca8386ce0f7693bfe3520f6cd86bc7c1cbb4dc0
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Wed Jun 10 15:34:44 2015 +0100

    Prop_pSegmentInfo is totally misunderstood apparently
    
    digging into the crash on export of kde216114-1.odt
    reveals various horrors
    
    Change-Id: I0d24fe303d561a00a08098b306d10fd8273af928
    (cherry picked from commit b04e1e79e64cb7bb3106fd08a019c27b09bdd5c6)

diff --git a/filter/source/msfilter/escherex.cxx b/filter/source/msfilter/escherex.cxx
index 3bc125f..eded8e8 100644
--- a/filter/source/msfilter/escherex.cxx
+++ b/filter/source/msfilter/escherex.cxx
@@ -3258,85 +3258,92 @@ void EscherPropertyContainer::CreateCustomShapeProperties( const MSO_SPT eShapeT
                                                .WriteUInt16( nElementSize );
                                             for ( j = 0; j < nElements; j++ )
                                             {
+                                                // The segment type is stored in the upper 3 bits
+                                                // and segment count is stored in the lower 13
+                                                // bits.
+                                                //
+                                                // If the segment type is msopathEscape, the lower 13 bits
+                                                // are divided in a 5 bit escape code and 8 bit
+                                                // vertex count (not segment count!)
                                                 sal_uInt16 nVal = (sal_uInt16)aSegments[ j ].Count;
                                                 switch( aSegments[ j ].Command )
                                                 {
-                                                    case com::sun::star::drawing::EnhancedCustomShapeSegmentCommand::UNKNOWN :
-                                                    case com::sun::star::drawing::EnhancedCustomShapeSegmentCommand::LINETO : break;
-                                                    case com::sun::star::drawing::EnhancedCustomShapeSegmentCommand::MOVETO :
-                                                    {
-                                                        nVal = 0x4000;
-                                                    }
-                                                    break;
+                                                    case css::drawing::EnhancedCustomShapeSegmentCommand::UNKNOWN :
+                                                    case css::drawing::EnhancedCustomShapeSegmentCommand::LINETO :
+                                                        break;
+                                                    case css::drawing::EnhancedCustomShapeSegmentCommand::MOVETO :
+                                                        nVal = (msopathMoveTo << 13);
+                                                        break;
                                                     case com::sun::star::drawing::EnhancedCustomShapeSegmentCommand::CURVETO :
                                                     {
-                                                        nVal |= 0x2000;
+                                                        nVal |= (msopathCurveTo << 13);
                                                     }
                                                     break;
                                                     case com::sun::star::drawing::EnhancedCustomShapeSegmentCommand::CLOSESUBPATH :
                                                     {
-                                                        nVal = 0x6001;
+                                                        nVal = 1;
+                                                        nVal |= (msopathClose << 13);
                                                     }
                                                     break;
                                                     case com::sun::star::drawing::EnhancedCustomShapeSegmentCommand::ENDSUBPATH :
                                                     {
-                                                        nVal = 0x8000;
+                                                        nVal = (msopathEnd << 13);
                                                     }
                                                     break;
                                                     case com::sun::star::drawing::EnhancedCustomShapeSegmentCommand::NOFILL :
                                                     {
-                                                        nVal = 0xaa00;
+                                                        nVal = (msopathEscape << 13) | (5 << 8);
                                                     }
                                                     break;
                                                     case com::sun::star::drawing::EnhancedCustomShapeSegmentCommand::NOSTROKE :
                                                     {
-                                                        nVal = 0xab00;
+                                                        nVal = (msopathEscape << 13) | (11 << 8);
                                                     }
                                                     break;
                                                     case com::sun::star::drawing::EnhancedCustomShapeSegmentCommand::ANGLEELLIPSETO :
                                                     {
                                                         nVal *= 3;
-                                                        nVal |= 0xa100;
+                                                        nVal |= (msopathEscape << 13) | (1 << 8);
                                                     }
                                                     break;
                                                     case com::sun::star::drawing::EnhancedCustomShapeSegmentCommand::ANGLEELLIPSE :
                                                     {
                                                         nVal *= 3;
-                                                        nVal |= 0xa200;
+                                                        nVal |= (msopathEscape << 13) | (2 << 8);
                                                     }
                                                     break;
                                                     case com::sun::star::drawing::EnhancedCustomShapeSegmentCommand::ARCTO :
                                                     {
                                                         nVal <<= 2;
-                                                        nVal |= 0xa300;
+                                                        nVal |= (msopathEscape << 13) | (3 << 8);
                                                     }
                                                     break;
                                                     case com::sun::star::drawing::EnhancedCustomShapeSegmentCommand::ARC :
                                                     {
                                                         nVal <<= 2;
-                                                        nVal |= 0xa400;
+                                                        nVal |= (msopathEscape << 13) | (4 << 8);
                                                     }
                                                     break;
                                                     case com::sun::star::drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARCTO :
                                                     {
                                                         nVal <<= 2;
-                                                        nVal |= 0xa500;
+                                                        nVal |= (msopathEscape << 13) | (5 << 8);
                                                     }
                                                     break;
                                                     case com::sun::star::drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARC :
                                                     {
                                                         nVal <<= 2;
-                                                        nVal |= 0xa600;
+                                                        nVal |= (msopathEscape << 13) | (6 << 8);
                                                     }
                                                     break;
                                                     case com::sun::star::drawing::EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTX :
                                                     {
-                                                        nVal |= 0xa700;
+                                                        nVal |= (msopathEscape << 13) | (7 << 8);
                                                     }
                                                     break;
                                                     case com::sun::star::drawing::EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTY :
                                                     {
-                                                        nVal |= 0xa800;
+                                                        nVal |= (msopathEscape << 13) | (8 << 8);
                                                     }
                                                     break;
                                                 }
diff --git a/include/filter/msfilter/escherex.hxx b/include/filter/msfilter/escherex.hxx
index 4e3f8d7..ca3465a 100644
--- a/include/filter/msfilter/escherex.hxx
+++ b/include/filter/msfilter/escherex.hxx
@@ -424,6 +424,18 @@ enum ESCHER_LineCap
     ESCHER_LineEndCapFlat     // Line ends at end point
 };
 
+enum MSOPATHTYPE
+{
+    msopathLineTo,        // Draw a straight line (one point)
+    msopathCurveTo,       // Draw a cubic Bezier curve (three points)
+    msopathMoveTo,        // Move to a new point (one point)
+    msopathClose,         // Close a sub - path (no points)
+    msopathEnd,           // End a path (no points)
+    msopathEscape,        // Escape code
+    msopathClientEscape,  // Escape code interpreted by the client
+    msopathInvalid        // Invalid - should never be found
+};
+
 // Shape Properties
 // 1pt = 12700 EMU (English Metric Units)
 // 1pt = 20 Twip = 20/1440" = 1/72"
diff --git a/oox/source/export/vmlexport.cxx b/oox/source/export/vmlexport.cxx
index 9e8e6d2..7161a2f 100644
--- a/oox/source/export/vmlexport.cxx
+++ b/oox/source/export/vmlexport.cxx
@@ -474,27 +474,56 @@ void VMLExport::Commit( EscherPropertyContainer& rProps, const Rectangle& rRect
                         for ( ; nSegments; --nSegments )
                         {
                             sal_uInt16 nSeg = impl_GetUInt16( pSegmentIt );
-                            switch ( nSeg )
+
+                            // The segment type is stored in the upper 3 bits
+                            // and segment count is stored in the lower 13
+                            // bits.
+                            unsigned char nSegmentType = (nSeg & 0xE000) >> 13;
+                            unsigned short nSegmentCount = nSeg & 0x03FF;
+
+                            switch (nSegmentType)
                             {
-                                case 0x4000: // moveto
+                                case msopathMoveTo:
+                                {
+                                    sal_Int32 nX = impl_GetPointComponent( pVerticesIt, nPointSize );
+                                    sal_Int32 nY = impl_GetPointComponent( pVerticesIt, nPointSize );
+                                    if (nX >= 0 && nY >= 0 )
+                                        aPath.append( "m" ).append( nX ).append( "," ).append( nY );
+                                    break;
+                                }
+                                case msopathClientEscape:
+                                    break;
+                                case msopathEscape:
+                                {
+                                    // If the segment type is msopathEscape, the lower 13 bits are
+                                    // divided in a 5 bit escape code and 8 bit
+                                    // vertex count (not segment count!)
+                                    unsigned char nEscapeCode = (nSegmentCount & 0x1F00) >> 8;
+                                    unsigned char nVertexCount = nSegmentCount & 0x00FF;
+                                    pVerticesIt += nVertexCount;
+
+                                    switch (nEscapeCode)
                                     {
-                                        sal_Int32 nX = impl_GetPointComponent( pVerticesIt, nPointSize );
-                                        sal_Int32 nY = impl_GetPointComponent( pVerticesIt, nPointSize );
-                                        if (nX >= 0 && nY >= 0 )
-                                            aPath.append( "m" ).append( nX ).append( "," ).append( nY );
+                                        case 0xa: // nofill
+                                            aPath.append( "nf" );
+                                            break;
+                                        case 0xb: // nostroke
+                                            aPath.append( "ns" );
+                                            break;
                                     }
+
                                     break;
-                                case 0xb300:
-                                case 0xac00:
-                                    break;
-                                case 0x0001: // lineto
+                                }
+                                case msopathLineTo:
+                                    for (unsigned short i = 0; i < nSegmentCount; ++i)
                                     {
                                         sal_Int32 nX = impl_GetPointComponent( pVerticesIt, nPointSize );
                                         sal_Int32 nY = impl_GetPointComponent( pVerticesIt, nPointSize );
                                         aPath.append( "l" ).append( nX ).append( "," ).append( nY );
                                     }
                                     break;
-                                case 0x2001: // curveto
+                                case msopathCurveTo:
+                                    for (unsigned short i = 0; i < nSegmentCount; ++i)
                                     {
                                         sal_Int32 nX1 = impl_GetPointComponent( pVerticesIt, nPointSize );
                                         sal_Int32 nY1 = impl_GetPointComponent( pVerticesIt, nPointSize );
@@ -507,35 +536,17 @@ void VMLExport::Commit( EscherPropertyContainer& rProps, const Rectangle& rRect
                                             .append( nX3 ).append( "," ).append( nY3 );
                                     }
                                     break;
-                                case 0xaa00: // nofill
-                                    aPath.append( "nf" );
-                                    break;
-                                case 0xab00: // nostroke
-                                    aPath.append( "ns" );
-                                    break;
-                                case 0x6001: // close
+                                case msopathClose:
                                     aPath.append( "x" );
                                     break;
-                                case 0x8000: // end
+                                case msopathEnd:
                                     aPath.append( "e" );
                                     break;
                                 default:
-                                    // See EscherPropertyContainer::CreateCustomShapeProperties, by default nSeg is simply the number of points.
-                                    // FIXME: we miss out a significant amount of complexity from
-                                    // the above method here, and do some rather odd things to match.
-                                    int nElems = !nPointSize ? 0 : aVertices.nPropSize / (nPointSize * 2);
-                                    if (nSeg > nElems)
-                                    {
-                                        SAL_WARN("oox", "Busted escher export " << nSeg << "vs . " << nElems << " truncating point stream");
-                                        nSeg = nElems;
-                                    }
-                                    for (int i = 0; i < nSeg; ++i)
-                                    {
-                                        sal_Int32 nX = impl_GetPointComponent(pVerticesIt, nPointSize);
-                                        sal_Int32 nY = impl_GetPointComponent(pVerticesIt, nPointSize);
-                                        if (nX >= 0 && nY >= 0 )
-                                            aPath.append("l").append(nX).append(",").append(nY);
-                                    }
+                                    SAL_WARN("oox", "Totally b0rked\n");
+                                    break;
+                                case msopathInvalid:
+                                    SAL_WARN("oox", "Invalid - should never be found");
                                     break;
                             }
                         }
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx
index aea445e..14be93e 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx
@@ -837,11 +837,11 @@ DECLARE_OOXMLEXPORT_TEST(testKDE302504, "kde302504-1.odt")
         assertXPath(pXmlDoc, "//v:shape", "ID", "KoPathShape");
 }
 
-//DECLARE_OOXMLEXPORT_TEST(testKDE216114, "kde216114-1.odt")
-//{
-//    if (xmlDocPtr pXmlDoc = parseExport("word/document.xml"))
-//        assertXPath(pXmlDoc, "//w:pict", 1);
-//}
+DECLARE_OOXMLEXPORT_TEST(testKDE216114, "kde216114-1.odt")
+{
+    if (xmlDocPtr pXmlDoc = parseExport("word/document.xml"))
+        assertXPath(pXmlDoc, "//w:pict", 1);
+}
 
 CPPUNIT_PLUGIN_IMPLEMENT();
 
diff --git a/sw/source/filter/ww8/rtfsdrexport.cxx b/sw/source/filter/ww8/rtfsdrexport.cxx
index da441f5..cb8e8f6 100644
--- a/sw/source/filter/ww8/rtfsdrexport.cxx
+++ b/sw/source/filter/ww8/rtfsdrexport.cxx
@@ -278,48 +278,61 @@ void RtfSdrExport::Commit(EscherPropertyContainer& rProps, const Rectangle& rRec
                 for (; nSegments; --nSegments)
                 {
                     sal_uInt16 nSeg = impl_GetUInt16(pSegmentIt);
+
+                    // The segment type is stored in the upper 3 bits
+                    // and segment count is stored in the lower 13
+                    // bits.
+                    unsigned char nSegmentType = (nSeg & 0xE000) >> 13;
+                    unsigned short nSegmentCount = nSeg & 0x03FF;
+
                     aSegmentInfo.append(';').append((sal_Int32)nSeg);
-                    switch (nSeg)
-                    {
-                    case 0x0001: // lineto
-                    case 0x4000: // moveto
-                    {
-                        sal_Int32 nX = impl_GetPointComponent(pVerticesIt, nVerticesPos, nPointSize);
-                        sal_Int32 nY = impl_GetPointComponent(pVerticesIt, nVerticesPos, nPointSize);
-                        aVerticies.append(";(").append(nX).append(",").append(nY).append(")");
-                        nVertices ++;
-                    }
-                    break;
-                    case 0x2001: // curveto
+                    switch (nSegmentType)
                     {
-                        for (int i = 0; i < 3; i++)
+                        case msopathLineTo:
+                            for (unsigned short i = 0; i < nSegmentCount; ++i)
+                            {
+                                sal_Int32 nX = impl_GetPointComponent(pVerticesIt, nVerticesPos, nPointSize);
+                                sal_Int32 nY = impl_GetPointComponent(pVerticesIt, nVerticesPos, nPointSize);
+                                aVerticies.append(";(").append(nX).append(",").append(nY).append(")");
+                                nVertices ++;
+                            }
+                            break;
+                        case msopathMoveTo:
                         {
                             sal_Int32 nX = impl_GetPointComponent(pVerticesIt, nVerticesPos, nPointSize);
                             sal_Int32 nY = impl_GetPointComponent(pVerticesIt, nVerticesPos, nPointSize);
                             aVerticies.append(";(").append(nX).append(",").append(nY).append(")");
-                            nVertices ++;
+                            nVertices++;
+                            break;
                         }
-                    }
-                    break;
-                    case 0xb300:
-                    case 0xac00:
-                    case 0xaa00: // nofill
-                    case 0xab00: // nostroke
-                    case 0x6001: // close
-                    case 0x8000: // end
-                        break;
-                    default:
-                        // See EscherPropertyContainer::CreateCustomShapeProperties, by default nSeg is simply the number of points.
-                        for (int i = 0; i < nSeg; ++i)
+                        case msopathCurveTo:
+                            for (unsigned short j = 0; j < nSegmentCount; ++j)
+                            {
+                                for (int i = 0; i < 3; i++)
+                                {
+                                    sal_Int32 nX = impl_GetPointComponent(pVerticesIt, nVerticesPos, nPointSize);
+                                    sal_Int32 nY = impl_GetPointComponent(pVerticesIt, nVerticesPos, nPointSize);
+                                    aVerticies.append(";(").append(nX).append(",").append(nY).append(")");
+                                    nVertices ++;
+                                }
+                            }
+                            break;
+                        case msopathEscape:
                         {
-                            if (nVerticesPos >= aVertices.nPropSize)
-                                break;
-                            sal_Int32 nX = impl_GetPointComponent(pVerticesIt, nVerticesPos, nPointSize);
-                            sal_Int32 nY = impl_GetPointComponent(pVerticesIt, nVerticesPos, nPointSize);
-                            aVerticies.append(";(").append(nX).append(",").append(nY).append(")");
-                            ++nVertices;
+                            // If the segment type is msopathEscape, the lower 13 bits are
+                            // divided in a 5 bit escape code and 8 bit
+                            // vertex count (not segment count!)
+                            unsigned char nVertexCount = nSegmentCount & 0x00FF;
+                            nVerticesPos += nVertexCount;
+                            break;
                         }
-                        break;
+                        case msopathClientEscape:
+                        case msopathClose:
+                        case msopathEnd:
+                            break;
+                        default:
+                            SAL_WARN("oox", "Totally b0rked\n");
+                            break;
                     }
                 }
 
commit c0d691b9d3266823e2ca64164b1738965699b8c9
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Wed Jun 10 13:42:37 2015 +0100

    VMLExport::Commit is riddled with out of bounds writes on export
    
    Change-Id: I9490d888ad148caecba034ef12b7398ae5c66a3f
    (cherry picked from commit 169cd9f675b6c868b829caf4bed0d829d9404b41)

diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx
index 14be93e..aea445e 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx
@@ -837,11 +837,11 @@ DECLARE_OOXMLEXPORT_TEST(testKDE302504, "kde302504-1.odt")
         assertXPath(pXmlDoc, "//v:shape", "ID", "KoPathShape");
 }
 
-DECLARE_OOXMLEXPORT_TEST(testKDE216114, "kde216114-1.odt")
-{
-    if (xmlDocPtr pXmlDoc = parseExport("word/document.xml"))
-        assertXPath(pXmlDoc, "//w:pict", 1);
-}
+//DECLARE_OOXMLEXPORT_TEST(testKDE216114, "kde216114-1.odt")
+//{
+//    if (xmlDocPtr pXmlDoc = parseExport("word/document.xml"))
+//        assertXPath(pXmlDoc, "//w:pict", 1);
+//}
 
 CPPUNIT_PLUGIN_IMPLEMENT();
 
commit 5e9483c0e2573d759a96050070f51ff3b068c6af
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Wed Jun 10 13:05:51 2015 +0100

    similarly fix fatal export of kde216114-1.odt to docx
    
    Change-Id: I78478de91473681fd8d836293dabe7b790dda516
    (cherry picked from commit 80fbd731d8b8b101a10466a4d16d4867e9de968b)

diff --git a/oox/source/export/drawingml.cxx b/oox/source/export/drawingml.cxx
index b795c3e..9d4d84d 100644
--- a/oox/source/export/drawingml.cxx
+++ b/oox/source/export/drawingml.cxx
@@ -2282,9 +2282,11 @@ void DrawingML::WriteCustomGeometry( Reference< XShape > rXShape )
                 }
                 else
                 {
-                    sal_Int32 nXMin = aPairs[0].First.Value.get<sal_Int32>();
+                    sal_Int32 nXMin(0);
+                    aPairs[0].First.Value >>= nXMin;
                     sal_Int32 nXMax = nXMin;
-                    sal_Int32 nYMin = aPairs[0].Second.Value.get<sal_Int32>();
+                    sal_Int32 nYMin(0);
+                    aPairs[0].Second.Value >>= nYMin;
                     sal_Int32 nYMax = nYMin;
 
                     for ( int j = 0; j < aPairs.getLength(); ++j )
@@ -2321,9 +2323,13 @@ void DrawingML::WriteCustomGeometry( Reference< XShape > rXShape )
                             {
                                 mpFS->startElementNS( XML_a, XML_moveTo, FSEND );
 
+                                sal_Int32 nX(0), nY(0);
+                                aPairs[nPairIndex].First.Value >>= nX;
+                                aPairs[nPairIndex].Second.Value >>= nY;
+
                                 mpFS->singleElementNS( XML_a, XML_pt,
-                                   XML_x, I64S( aPairs[nPairIndex].First.Value.get<sal_Int32>() ),
-                                   XML_y, I64S( aPairs[nPairIndex].Second.Value.get<sal_Int32>() ),
+                                   XML_x, I64S(nX),
+                                   XML_y, I64S(nY),
                                    FSEND );
 
                                 mpFS->endElementNS( XML_a, XML_moveTo );
@@ -2333,9 +2339,14 @@ void DrawingML::WriteCustomGeometry( Reference< XShape > rXShape )
                             case drawing::EnhancedCustomShapeSegmentCommand::LINETO :
                             {
                                 mpFS->startElementNS( XML_a, XML_lnTo, FSEND );
+
+                                sal_Int32 nX(0), nY(0);
+                                aPairs[nPairIndex].First.Value >>= nX;
+                                aPairs[nPairIndex].Second.Value >>= nY;
+
                                 mpFS->singleElementNS( XML_a, XML_pt,
-                                   XML_x, I64S( aPairs[nPairIndex].First.Value.get<sal_Int32>() ),
-                                   XML_y, I64S( aPairs[nPairIndex].Second.Value.get<sal_Int32>() ),
+                                   XML_x, I64S(nX),
+                                   XML_y, I64S(nY),
                                    FSEND );
                                 mpFS->endElementNS( XML_a, XML_lnTo );
                                 nPairIndex++;
@@ -2346,9 +2357,13 @@ void DrawingML::WriteCustomGeometry( Reference< XShape > rXShape )
                                 mpFS->startElementNS( XML_a, XML_cubicBezTo, FSEND );
                                 for( sal_uInt8 l = 0; l <= 2; ++l )
                                 {
+                                    sal_Int32 nX(0), nY(0);
+                                    aPairs[nPairIndex+l].First.Value >>= nX;
+                                    aPairs[nPairIndex+l].Second.Value >>= nY;
+
                                     mpFS->singleElementNS( XML_a, XML_pt,
-                                    XML_x, I64S( aPairs[nPairIndex+l].First.Value.get<sal_Int32>() ),
-                                    XML_y, I64S( aPairs[nPairIndex+l].Second.Value.get<sal_Int32>() ),
+                                    XML_x, I64S( nX ),
+                                    XML_y, I64S( nY ),
                                     FSEND );
 
                                 }
@@ -2381,10 +2396,14 @@ void DrawingML::WriteCustomGeometry( Reference< XShape > rXShape )
                                 mpFS->startElementNS( XML_a, XML_quadBezTo, FSEND );
                                 for( sal_uInt8 l = 0; l < 2; ++l )
                                 {
+                                    sal_Int32 nX(0), nY(0);
+                                    aPairs[nPairIndex+l].First.Value >>= nX;
+                                    aPairs[nPairIndex+l].Second.Value >>= nY;
+
                                     mpFS->singleElementNS( XML_a, XML_pt,
-                                    XML_x, I64S( aPairs[nPairIndex+l].First.Value.get<sal_Int32>() ),
-                                    XML_y, I64S( aPairs[nPairIndex+l].Second.Value.get<sal_Int32>() ),
-                                    FSEND );
+                                        XML_x, I64S( nX ),
+                                        XML_y, I64S( nY ),
+                                        FSEND );
 
                                 }
                                 mpFS->endElementNS( XML_a, XML_quadBezTo );
diff --git a/sw/qa/extras/ooxmlexport/data/kde216114-1.odt b/sw/qa/extras/ooxmlexport/data/kde216114-1.odt
new file mode 100644
index 0000000..536da72
Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/kde216114-1.odt differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx
index 67ad8df..14be93e 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx
@@ -837,6 +837,12 @@ DECLARE_OOXMLEXPORT_TEST(testKDE302504, "kde302504-1.odt")
         assertXPath(pXmlDoc, "//v:shape", "ID", "KoPathShape");
 }
 
+DECLARE_OOXMLEXPORT_TEST(testKDE216114, "kde216114-1.odt")
+{
+    if (xmlDocPtr pXmlDoc = parseExport("word/document.xml"))
+        assertXPath(pXmlDoc, "//w:pict", 1);
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit 02d527344d8d18a01664f32416471161e2f78e27
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Wed Jun 10 12:20:31 2015 +0100

    fix fatal attempt to export kde302504-1.odt to docx
    
    the enhanced-path contains decimal points so the
    last element is a double not an integer
    
    Change-Id: I90be76a2d4cb90ee7a904aa72fe65770c675fc53
    (cherry picked from commit aeb52a855d55475ff2e74f5308ae580dce3e069f)

diff --git a/oox/source/export/drawingml.cxx b/oox/source/export/drawingml.cxx
index 15a8cb7..b795c3e 100644
--- a/oox/source/export/drawingml.cxx
+++ b/oox/source/export/drawingml.cxx
@@ -2289,14 +2289,15 @@ void DrawingML::WriteCustomGeometry( Reference< XShape > rXShape )
 
                     for ( int j = 0; j < aPairs.getLength(); ++j )
                     {
-                        if ( aPairs[j].First.Value.get<sal_Int32>() < nXMin )
-                            nXMin = aPairs[j].First.Value.get<sal_Int32>();
-                        if ( aPairs[j].Second.Value.get<sal_Int32>() < nYMin )
-                            nYMin = aPairs[j].Second.Value.get<sal_Int32>();
-                        if ( aPairs[j].First.Value.get<sal_Int32>() > nXMax )
-                            nXMax = aPairs[j].First.Value.get<sal_Int32>();
-                        if ( aPairs[j].Second.Value.get<sal_Int32>() > nYMax )
-                            nYMax = aPairs[j].Second.Value.get<sal_Int32>();
+                        sal_Int32 nCandidate(0);
+                        if ((aPairs[j].First.Value >>= nCandidate) && nCandidate < nXMin)
+                            nXMin = nCandidate;
+                        if ((aPairs[j].Second.Value >>= nCandidate) && nCandidate < nYMin)
+                            nYMin = nCandidate;
+                        if ((aPairs[j].First.Value >>= nCandidate) && nCandidate > nXMax)
+                            nXMax = nCandidate;
+                        if ((aPairs[j].Second.Value >>= nCandidate) && nCandidate > nYMax)
+                            nYMax = nCandidate;
                     }
                     mpFS->startElementNS( XML_a, XML_path,
                           XML_w, I64S( nXMax - nXMin ),
diff --git a/sw/qa/extras/ooxmlexport/data/kde302504-1.odt b/sw/qa/extras/ooxmlexport/data/kde302504-1.odt
new file mode 100644
index 0000000..d0b7c60
Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/kde302504-1.odt differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx
index b63d755..67ad8df 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx
@@ -831,6 +831,12 @@ DECLARE_OOXMLEXPORT_TEST(testOO67471, "ooo67471-2.odt")
         assertXPathContent(pXmlDoc, "(//w:t)[2]", "B");
 }
 
+DECLARE_OOXMLEXPORT_TEST(testKDE302504, "kde302504-1.odt")
+{
+    if (xmlDocPtr pXmlDoc = parseExport("word/document.xml"))
+        assertXPath(pXmlDoc, "//v:shape", "ID", "KoPathShape");
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit 7d60c07613c5efec3ce1f217f00458296aeb5e3b
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Tue Jun 9 17:26:14 2015 +0100

    fix crash on export of ooo67471-2.sxw to docx
    
    This old-school table has three rows in it, but the second row is of 0 height
    so is indistinguisable from the third row by layout positioning, so the
    WW8TableNodeInfo view of the table is that it has two rows, and the comparison
    of being on the last row is done with the m_xTableWrt->GetRows view which
    considers it to have 3, so the table end marks are never output.
    
    add a new finalEndOfLine property that the WW8TableNodeInfo sets on the last
    end of row of the table as it sees it, which should resolve this.
    
    old style tables are a cess pit, which is why they were replaced
    
    Change-Id: I996aa59a338a594487f49ec0f228af3fb3032d15
    (cherry picked from commit 6f9b3532ee81850500d9e87ad329c00ea9c83bba)

diff --git a/sw/qa/extras/ooxmlexport/data/ooo67471-2.odt b/sw/qa/extras/ooxmlexport/data/ooo67471-2.odt
new file mode 100644
index 0000000..82daa57
Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/ooo67471-2.odt differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx
index 5fe36fd..b63d755 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx
@@ -825,6 +825,12 @@ DECLARE_OOXMLEXPORT_TEST(testOO47778_2, "ooo47778-4.odt")
         assertXPathContent(pXmlDoc, "(//w:t)[4]", "c");
 }
 
+DECLARE_OOXMLEXPORT_TEST(testOO67471, "ooo67471-2.odt")
+{
+    if (xmlDocPtr pXmlDoc = parseExport("word/document.xml"))
+        assertXPathContent(pXmlDoc, "(//w:t)[2]", "B");
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/ww8/WW8TableInfo.cxx b/sw/source/filter/ww8/WW8TableInfo.cxx
index 1ff3298..ad729bc 100644
--- a/sw/source/filter/ww8/WW8TableInfo.cxx
+++ b/sw/source/filter/ww8/WW8TableInfo.cxx
@@ -40,6 +40,7 @@ WW8TableNodeInfoInner::WW8TableNodeInfoInner(WW8TableNodeInfo * pParent)
 , mnShadowsBefore(0)
 , mnShadowsAfter(0)
 , mbEndOfLine(false)
+, mbFinalEndOfLine(false)
 , mbEndOfCell(false)
 , mbFirstInTable(false)
 , mbVertMerge(false)
@@ -82,6 +83,11 @@ void WW8TableNodeInfoInner::setEndOfLine(bool bEndOfLine)
     mbEndOfLine = bEndOfLine;
 }
 
+void WW8TableNodeInfoInner::setFinalEndOfLine(bool bFinalEndOfLine)
+{
+    mbFinalEndOfLine = bFinalEndOfLine;
+}
+
 void WW8TableNodeInfoInner::setEndOfCell(bool bEndOfCell)
 {
     mbEndOfCell = bEndOfCell;
@@ -531,8 +537,6 @@ const SwTableBox * WW8TableNodeInfo::getTableBox() const
     return getInnerForDepth(mnDepth)->getTableBox();
 }
 
-
-
 sal_uInt32 WW8TableNodeInfo::getCell() const
 {
     return getInnerForDepth(mnDepth)->getCell();
@@ -543,6 +547,10 @@ sal_uInt32 WW8TableNodeInfo::getRow() const
     return getInnerForDepth(mnDepth)->getRow();
 }
 
+bool WW8TableNodeInfo::isEndOfLine() const
+{
+    return getInnerForDepth(mnDepth)->isEndOfLine();
+}
 
 const WW8TableNodeInfoInner::Pointer_t WW8TableNodeInfo::getFirstInner() const
 {
@@ -576,10 +584,9 @@ WW8TableInfo::~WW8TableInfo()
 }
 
 WW8TableNodeInfo *
-WW8TableInfo::processSwTableByLayout(const SwTable * pTable)
+WW8TableInfo::processSwTableByLayout(const SwTable * pTable, RowEndInners_t &rLastRowEnds)
 {
     SwTableCellInfo aTableCellInfo(pTable);
-    WW8TableNodeInfo * pPrev = NULL;
 
     while (aTableCellInfo.getNext())
     {
@@ -619,9 +626,7 @@ WW8TableInfo::processSwTableByLayout(const SwTable * pTable)
         SAL_INFO( "sw.ww8", "</CellFrm>" );
     }
 
-    pPrev = reorderByLayout(pTable);
-
-    return pPrev;
+    return reorderByLayout(pTable, rLastRowEnds);
 }
 
 void WW8TableInfo::processSwTable(const SwTable * pTable)
@@ -629,11 +634,11 @@ void WW8TableInfo::processSwTable(const SwTable * pTable)
     SAL_INFO( "sw.ww8", "<processSwTable>" );
 
     WW8TableNodeInfo * pPrev = NULL;
+    RowEndInners_t aLastRowEnds;
 
     if (pTable->IsTableComplex() && pTable->HasLayout())
     {
-        pPrev = processSwTableByLayout(pTable);
-
+        pPrev = processSwTableByLayout(pTable, aLastRowEnds);
 #ifdef DBG_UTIL
         SAL_INFO( "sw.ww8", getCellGridForTable(pTable)->toString());
 #endif
@@ -646,17 +651,22 @@ void WW8TableInfo::processSwTable(const SwTable * pTable)
         {
             const SwTableLine * pLine = rLines[n];
 
-            pPrev = processTableLine(pTable, pLine, static_cast<sal_uInt32>(n), 1, pPrev);
+            pPrev = processTableLine(pTable, pLine, static_cast<sal_uInt32>(n), 1, pPrev, aLastRowEnds);
         }
 
     }
 
-    if (pPrev != NULL)
+    if (pPrev)
     {
         SwTableNode * pTableNode = pTable->GetTableNode();
         SwEndNode * pEndNode = pTableNode->EndOfSectionNode();
-
         pPrev->setNextNode(pEndNode);
+        assert(!aLastRowEnds.empty());
+        for (auto &a : aLastRowEnds)
+        {
+            assert(a.second->isEndOfLine());
+            a.second->setFinalEndOfLine(true);
+        }
     }
     SAL_INFO( "sw.ww8", "</processSwTable>" );
 }
@@ -665,7 +675,9 @@ WW8TableNodeInfo *
 WW8TableInfo::processTableLine(const SwTable * pTable,
                                const SwTableLine * pTableLine,
                                sal_uInt32 nRow,
-                               sal_uInt32 nDepth, WW8TableNodeInfo * pPrev)
+                               sal_uInt32 nDepth,
+                               WW8TableNodeInfo * pPrev,
+                               RowEndInners_t &rLastRowEnds)
 {
     SAL_INFO( "sw.ww8", "<processTableLine row=\"" << nRow << "\" depth=\"" << nDepth << "\">" );
 
@@ -677,7 +689,7 @@ WW8TableInfo::processTableLine(const SwTable * pTable,
     {
         const SwTableBox * pBox = rBoxes[n];
 
-        pPrev = processTableBox(pTable, pBox, nRow, static_cast<sal_uInt32>(n), nDepth, n == rBoxes.size() - 1, pPrev);
+        pPrev = processTableBox(pTable, pBox, nRow, static_cast<sal_uInt32>(n), nDepth, n == rBoxes.size() - 1, pPrev, rLastRowEnds);
     }
 
     SAL_INFO( "sw.ww8", "</processTableLine>" );
@@ -736,6 +748,16 @@ WW8TableInfo::processTableBoxLines(const SwTableBox * pBox,
     return pNodeInfo;
 }
 
+void updateFinalEndOfLine(RowEndInners_t &rLastRowEnds, WW8TableNodeInfo* pEndOfCellInfo)
+{
+    sal_Int32 nDepth = pEndOfCellInfo->getDepth();
+    WW8TableNodeInfoInner::Pointer_t pInner = pEndOfCellInfo->getInnerForDepth(nDepth);
+
+    auto aIt = rLastRowEnds.find(nDepth);
+    if (aIt == rLastRowEnds.end() || (pInner->getRow() > aIt->second->getRow()))
+        rLastRowEnds[nDepth] = pInner.get();
+}
+
 WW8TableNodeInfo *
 WW8TableInfo::processTableBox(const SwTable * pTable,
                               const SwTableBox * pBox,
@@ -743,7 +765,8 @@ WW8TableInfo::processTableBox(const SwTable * pTable,
                               sal_uInt32 nCell,
                               sal_uInt32 nDepth,
                               bool bEndOfLine,
-                              WW8TableNodeInfo * pPrev)
+                              WW8TableNodeInfo * pPrev,
+                              RowEndInners_t &rLastRowEnds)
 {
     SAL_INFO( "sw.ww8", "<processTableBox row=\"" << nRow << "\" cell=\"" << nCell
         << "\" depth=\"" << nDepth << "\">" );
@@ -758,13 +781,16 @@ WW8TableInfo::processTableBox(const SwTable * pTable,
         pNodeInfo = processTableBoxLines(pBox, pTable, pBox, nRow, nCell, nDepth);
         pNodeInfo->setEndOfCell(true);
         if (bEndOfLine)
+        {
             pNodeInfo->setEndOfLine(true);
+            updateFinalEndOfLine(rLastRowEnds, pNodeInfo.get());
+        }
 
         for (sal_uInt32 n = 0; n < rLines.size(); n++)
         {
             const SwTableLine * pLine = rLines[n];
 
-            pPrev = processTableLine(pTable, pLine, n, 1, pPrev);
+            pPrev = processTableLine(pTable, pLine, n, 1, pPrev, rLastRowEnds);
         }
     }
     else
@@ -788,7 +814,7 @@ WW8TableInfo::processTableBox(const SwTable * pTable,
 
             pNodeInfo = insertTableNodeInfo(&rNode, pTable, pBox, nRow, nCell, nDepth);
 
-            if (pPrev != NULL)
+            if (pPrev)
                 pPrev->setNext(pNodeInfo.get());
 
             pPrev = pNodeInfo.get();
@@ -800,7 +826,7 @@ WW8TableInfo::processTableBox(const SwTable * pTable,
             {
                 nDepthInsideCell--;
 
-                if (nDepthInsideCell == 0 && pEndOfCellInfo.get() == NULL)
+                if (nDepthInsideCell == 0 && !pEndOfCellInfo)
                     pEndOfCellInfo = pNodeInfo;
 
                 SwEndNode * pEndNode = rNode.GetEndNode( );
@@ -818,7 +844,10 @@ WW8TableInfo::processTableBox(const SwTable * pTable,
             pEndOfCellInfo->setEndOfCell(true);
 
             if (bEndOfLine)
+            {
                 pEndOfCellInfo->setEndOfLine(true);
+                updateFinalEndOfLine(rLastRowEnds, pEndOfCellInfo.get());
+            }
         }
     }
 
@@ -973,7 +1002,7 @@ bool CellInfo::operator < (const CellInfo & aCellInfo) const
                     aRet = true;
                 else if (height() == aCellInfo.height())
                 {
-                    if (aCellInfo.getTableNodeInfo() != NULL)
+                    if (aCellInfo.getTableNodeInfo())
                     {
                         if (m_pNodeInfo == NULL)
                             aRet = true;
@@ -1011,9 +1040,8 @@ bool CellInfo::operator < (const CellInfo & aCellInfo) const
 }
 #endif
 
-WW8TableNodeInfo * WW8TableInfo::reorderByLayout(const SwTable * pTable)
+WW8TableNodeInfo * WW8TableInfo::reorderByLayout(const SwTable * pTable, RowEndInners_t &rLastRowEnds)
 {
-    WW8TableNodeInfo * pPrev = NULL;
     WW8TableCellGrid::Pointer_t pCellGrid = getCellGridForTable(pTable);
 
 #ifdef DBG_UTIL
@@ -1021,9 +1049,7 @@ WW8TableNodeInfo * WW8TableInfo::reorderByLayout(const SwTable * pTable)
 #endif
 
     pCellGrid->addShadowCells();
-    pPrev = pCellGrid->connectCells();
-
-    return pPrev;
+    return pCellGrid->connectCells(rLastRowEnds);
 }
 
 WW8TableCellGrid::WW8TableCellGrid()
@@ -1138,13 +1164,13 @@ void WW8TableCellGrid::addShadowCells()
                     nRowSpan++;
                 }
 
-                if (pNodeInfo != NULL)
+                if (pNodeInfo)
                     pRowSpans->push_back(nRowSpan);
                 else
                     pRowSpans->push_back(-nRowSpan);
             }
 
-            if (pNodeInfo != NULL)
+            if (pNodeInfo)
             {
                 pNodeInfo->setVertMerge(bVertMerge);
             }
@@ -1166,7 +1192,7 @@ void WW8TableCellGrid::addShadowCells()
     SAL_INFO( "sw.ww8", "</addShadowCells>" );
 }
 
-WW8TableNodeInfo * WW8TableCellGrid::connectCells()
+WW8TableNodeInfo * WW8TableCellGrid::connectCells(RowEndInners_t &rLastRowEnds)
 {
     RowTops_t::const_iterator aTopsIt = getRowTopsBegin();
     sal_uInt32 nRow = 0;
@@ -1188,7 +1214,7 @@ WW8TableNodeInfo * WW8TableCellGrid::connectCells()
         {
             long nCellX = aCellIt->left();
             WW8TableNodeInfo * pNodeInfo = aCellIt->getTableNodeInfo();
-            if (pNodeInfo != NULL)
+            if (pNodeInfo)
             {
                 const SwNode * pNode = pNodeInfo->getNode();
 
@@ -1204,7 +1230,7 @@ WW8TableNodeInfo * WW8TableCellGrid::connectCells()
                 pNodeInfo->setShadowsBefore(nShadows);
                 pNodeInfo->setCell(nCell);
                 pNodeInfo->setRow(nRow);
-                if (pLastNodeInfo != NULL)
+                if (pLastNodeInfo)
                 {
                     pLastNodeInfo->setNext(pNodeInfo);
                     pLastNodeInfo->setNextNode(pNode);
@@ -1216,7 +1242,7 @@ WW8TableNodeInfo * WW8TableCellGrid::connectCells()
                 {
                     nDepthInCell--;
 
-                    if (nDepthInCell == 0 && pEndOfCellInfo == NULL)
+                    if (nDepthInCell == 0 && !pEndOfCellInfo)
                         pEndOfCellInfo = pNodeInfo;
                 }
             }
@@ -1229,7 +1255,7 @@ WW8TableNodeInfo * WW8TableCellGrid::connectCells()
             {
                 pWidths->push_back(aCellIt->getFormatFrmWidth());
 
-                if (pNodeInfo != NULL)
+                if (pNodeInfo)
                     pTableBoxes->push_back(pNodeInfo->getTableBox());
                 else
                     pTableBoxes->push_back(NULL);
@@ -1243,7 +1269,7 @@ WW8TableNodeInfo * WW8TableCellGrid::connectCells()
                 nCell++;
                 bBeginningOfCell = true;
 
-                if (pEndOfCellInfo != NULL)
+                if (pEndOfCellInfo)
                 {
                     pEndOfCellInfo->setEndOfCell(true);
                 }
@@ -1254,13 +1280,14 @@ WW8TableNodeInfo * WW8TableCellGrid::connectCells()
 
         pLastNodeInfo->setShadowsAfter(nShadows);
 
-        if (pEndOfCellInfo == NULL)
+        if (!pEndOfCellInfo)
         {
             pEndOfCellInfo = pLastNodeInfo;
         }
 
         pEndOfCellInfo->setEndOfCell(true);
         pLastNodeInfo->setEndOfLine(true);
+        updateFinalEndOfLine(rLastRowEnds, pLastNodeInfo);
 
         WW8TableCellGridRow::Pointer_t pRow(getRow(*aTopsIt));
         pRow->setTableBoxVector(pTableBoxes);
@@ -1297,7 +1324,7 @@ WW8TableNodeInfo * WW8TableCellGrid::connectCells()
             sResult += sBuffer;
 
             WW8TableNodeInfo * pInfo = aCellIt->getTableNodeInfo();
-            if (pInfo != NULL)
+            if (pInfo)
                 sResult += pInfo->toString();
             else
                 sResult += "<shadow/>\n";
diff --git a/sw/source/filter/ww8/WW8TableInfo.hxx b/sw/source/filter/ww8/WW8TableInfo.hxx
index 8a3013a..722302c 100644
--- a/sw/source/filter/ww8/WW8TableInfo.hxx
+++ b/sw/source/filter/ww8/WW8TableInfo.hxx
@@ -58,6 +58,7 @@ class WW8TableNodeInfoInner
     sal_uInt32 mnShadowsBefore;
     sal_uInt32 mnShadowsAfter;
     bool mbEndOfLine;
+    bool mbFinalEndOfLine;
     bool mbEndOfCell;
     bool mbFirstInTable;
     bool mbVertMerge;
@@ -77,10 +78,11 @@ public:
     void setShadowsBefore(sal_uInt32 nShadowsBefore);
     void setShadowsAfter(sal_uInt32 nShadowsAfter);
     void setEndOfLine(bool bEndOfLine);
+    void setFinalEndOfLine(bool bEndOfLine);
     void setEndOfCell(bool bEndOfCell);
     void setFirstInTable(bool bFirstInTable);
-    void setVertMerge(bool bVertMErge);
-    void setTableBox(const SwTableBox * pTableBox);
+    void setVertMerge(bool bVertMerge);
+    void setTableBox(const SwTableBox *pTableBox);
     void setTable(const SwTable * pTable);
     void setRect(const SwRect & rRect);
 
@@ -91,6 +93,7 @@ public:
     sal_uInt32 getShadowsAfter() const { return mnShadowsAfter;}
     bool isEndOfCell() const { return mbEndOfCell;}
     bool isEndOfLine() const { return mbEndOfLine;}
+    bool isFinalEndOfLine() const { return mbFinalEndOfLine;}
     bool isFirstInTable() const { return mbFirstInTable;}
     bool isVertMerge() const;
     const SwTableBox * getTableBox() const { return mpTableBox;}
@@ -156,6 +159,9 @@ public:
 
 typedef ::std::multiset<CellInfo, ::std::less<CellInfo> > CellInfoMultiSet;
 typedef boost::shared_ptr<CellInfoMultiSet> CellInfoMultiSetPtr;
+typedef ::std::map<sal_uInt32, WW8TableNodeInfoInner*,
+            ::std::greater<sal_uInt32> > RowEndInners_t;
+
 
 class WW8TableInfo;
 class WW8TableNodeInfo
@@ -278,7 +284,7 @@ public:
     void insert(const SwRect & rRect, WW8TableNodeInfo * pNodeInfo,
                 unsigned long * pFormatFrmWidth = NULL);
     void addShadowCells();
-    WW8TableNodeInfo * connectCells();
+    WW8TableNodeInfo *connectCells(RowEndInners_t &rLastRowEnds);
 
 #ifdef DBG_UTIL
     ::std::string toString();
@@ -305,14 +311,15 @@ class WW8TableInfo
     processTableLine(const SwTable * pTable,
                      const SwTableLine * pTableLine,
                      sal_uInt32 nRow,
-                     sal_uInt32 nDepth, WW8TableNodeInfo * pPrev);
+                     sal_uInt32 nDepth, WW8TableNodeInfo * pPrev, RowEndInners_t &rLastRowEnds);
 
     WW8TableNodeInfo *
     processTableBox(const SwTable * pTable,
                     const SwTableBox * pTableBox,
                     sal_uInt32 nRow,
                     sal_uInt32 nCell,
-                    sal_uInt32 nDepth, bool bEndOfLine, WW8TableNodeInfo * pPrev);
+                    sal_uInt32 nDepth, bool bEndOfLine,
+                    WW8TableNodeInfo * pPrev, RowEndInners_t &rLastRowEnds);
 
     WW8TableNodeInfo::Pointer_t
     processTableBoxLines(const SwTableBox * pBox,
@@ -341,12 +348,12 @@ public:
     virtual ~WW8TableInfo();
 
     void processSwTable(const SwTable * pTable);
-    WW8TableNodeInfo * processSwTableByLayout(const SwTable * pTable);
+    WW8TableNodeInfo * processSwTableByLayout(const SwTable * pTable, RowEndInners_t &rLastRowEnds);
     WW8TableNodeInfo::Pointer_t getTableNodeInfo(const SwNode * pNode);
     const SwNode * getNextNode(const SwNode * pNode);
     const WW8TableNodeInfo * getFirstTableNodeInfo() const;
 
-    WW8TableNodeInfo * reorderByLayout(const SwTable * pTable);
+    WW8TableNodeInfo * reorderByLayout(const SwTable * pTable, RowEndInners_t &rLastRowEnds);
 };
 
 }
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx
index 79ced22..c6e980c 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -719,8 +719,6 @@ void DocxAttributeOutput::FinishTableRowCell( ww8::WW8TableNodeInfoInner::Pointe
 
         InitTableHelper( pInner );
 
-        const size_t nLinesCount = m_xTableWrt->GetRows().size();
-
         // HACK
         // msoffice seems to have an internal limitation of 63 columns for tables
         // and refuses to load .docx with more, even though the spec seems to allow that;
@@ -764,7 +762,7 @@ void DocxAttributeOutput::FinishTableRowCell( ww8::WW8TableNodeInfoInner::Pointe
             EndTableRow();
 
         // This is the end of the table
-        if ( pInner->isEndOfLine( ) && ( nRow + 1 ) == nLinesCount )
+        if (pInner->isFinalEndOfLine())
             EndTable();
     }
 }
commit c34014b97bb8afcaded8fb1a75b1fd5f89758769
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Tue Jun 9 10:11:28 2015 +0100

    Resolves: more crash on export of ooo47778-3.sxw to docx
    
    This is more of the horror where the table in the frame has its cells out of
    visual sequence, extend the previous fix of this kind to accept cells within
    the original unmodified selected range
    
    Change-Id: I6e8220f712fe9de5d4b98fb3cb5ed67e3762e929
    (cherry picked from commit 60f8dd78fa3f19e8bed867f7f5926fcf9a8d8e67)

diff --git a/sw/qa/extras/ooxmlexport/data/ooo47778-4.odt b/sw/qa/extras/ooxmlexport/data/ooo47778-4.odt
new file mode 100644
index 0000000..ae6b56b
Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/ooo47778-4.odt differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx
index 6b2fb6e..5fe36fd 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx
@@ -813,12 +813,18 @@ DECLARE_OOXMLEXPORT_TEST(testSectionHeader, "sectionprot.odt")
     }
 }
 
-DECLARE_OOXMLEXPORT_TEST(testOO47778, "ooo47778-3.odt")
+DECLARE_OOXMLEXPORT_TEST(testOO47778_1, "ooo47778-3.odt")
 {
     if (xmlDocPtr pXmlDoc = parseExport("word/document.xml"))
         assertXPathContent(pXmlDoc, "(//w:t)[3]", "c");
 }
 
+DECLARE_OOXMLEXPORT_TEST(testOO47778_2, "ooo47778-4.odt")
+{
+    if (xmlDocPtr pXmlDoc = parseExport("word/document.xml"))
+        assertXPathContent(pXmlDoc, "(//w:t)[4]", "c");
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/ww8/wrtww8.cxx b/sw/source/filter/ww8/wrtww8.cxx
index 6d1cd84..01a95cf 100644
--- a/sw/source/filter/ww8/wrtww8.cxx
+++ b/sw/source/filter/ww8/wrtww8.cxx
@@ -1720,6 +1720,8 @@ void MSWordExportBase::WriteSpecialText( sal_uLong nStart, sal_uLong nEnd, sal_u
     sal_uInt8 nOldTyp = m_nTextTyp;
     m_nTextTyp = nTTyp;
     SwPaM* pOldPam = m_pCurPam;       //!! Simply shifting the PaM without restoring should do the job too
+    sal_uLong nOldStart = m_nCurStart;
+    sal_uLong nOldEnd = m_nCurEnd;
     SwPaM* pOldEnd = m_pOrigPam;
     bool bOldPageDescs = m_bOutPageDescs;
     m_bOutPageDescs = false;
@@ -1731,6 +1733,8 @@ void MSWordExportBase::WriteSpecialText( sal_uLong nStart, sal_uLong nEnd, sal_u
     m_bOutPageDescs = bOldPageDescs;
     delete m_pCurPam;                    // delete Pam
     m_pCurPam = pOldPam;
+    m_nCurStart = nOldStart;
+    m_nCurEnd = nOldEnd;
     m_pOrigPam = pOldEnd;
     m_nTextTyp = nOldTyp;
 }
@@ -1791,6 +1795,8 @@ void WW8Export::WriteChar( sal_Unicode c )
 
 void MSWordExportBase::SetCurPam(sal_uLong nStt, sal_uLong nEnd)
 {
+    m_nCurStart = nStt;
+    m_nCurEnd = nEnd;
     m_pCurPam = Writer::NewSwPaM( *m_pDoc, nStt, nEnd );
 
     // Recognize tables in special cases
@@ -1842,6 +1848,8 @@ void MSWordExportBase::RestoreData()
 
     delete m_pCurPam;
     m_pCurPam = rData.pOldPam;
+    m_nCurStart = rData.nOldStart;
+    m_nCurEnd = rData.nOldEnd;
     m_pOrigPam = rData.pOldEnd;
 
     m_bOutTable = rData.bOldOutTable;
@@ -2530,11 +2538,12 @@ class TrackContentToExport
 {
 private:
     SwPaM *m_pCurPam;
-    SwPaM m_aOrigPam;
+    sal_uLong m_nStart, m_nEnd;
 public:
-    TrackContentToExport(SwPaM *pCurPam)
+    TrackContentToExport(SwPaM *pCurPam, sal_uLong nCurStart, sal_uLong nCurEnd)
         : m_pCurPam(pCurPam)
-        , m_aOrigPam(*pCurPam, NULL)
+        , m_nStart(nCurStart)
+        , m_nEnd(nCurEnd)
     {
     }
 
@@ -2559,8 +2568,8 @@ public:
 
         if (pNextNode && pCurrentNode != pNextNode)
         {
-            return pNextNode->GetIndex() >= m_aOrigPam.GetPoint()->nNode.GetIndex() &&
-                   pNextNode->GetIndex() < m_aOrigPam.GetMark()->nNode.GetIndex();
+            return pNextNode->GetIndex() >= m_nStart &&
+                   pNextNode->GetIndex() < m_nEnd;
         }
 
         return false;
@@ -2569,7 +2578,7 @@ public:
 
 void MSWordExportBase::WriteText()
 {
-    TrackContentToExport aContentTracking(m_pCurPam);
+    TrackContentToExport aContentTracking(m_pCurPam, m_nCurStart, m_nCurEnd);
     while (aContentTracking.contentRemainsToExport(m_pTableInfo.get()))
     {
         SwNode& rNd = m_pCurPam->GetNode();
@@ -3558,6 +3567,8 @@ MSWordExportBase::MSWordExportBase( SwDoc *pDocument, SwPaM *pCurrentPam, SwPaM
     , m_bOutOutlineOnly(false)
     , m_bFontSizeWritten(false)
     , m_pDoc(pDocument)
+    , m_nCurStart(pCurrentPam->GetPoint()->nNode.GetIndex())
+    , m_nCurEnd(pCurrentPam->GetMark()->nNode.GetIndex())
     , m_pCurPam(pCurrentPam)
     , m_pOrigPam(pOriginalPam)
 {
diff --git a/sw/source/filter/ww8/wrtww8.hxx b/sw/source/filter/ww8/wrtww8.hxx
index 898051e..957ab28 100644
--- a/sw/source/filter/ww8/wrtww8.hxx
+++ b/sw/source/filter/ww8/wrtww8.hxx
@@ -437,6 +437,7 @@ struct MSWordSaveData
     RndStdIds eOldAnchorType;
     ww::bytes* pOOld;                ///< WW8Export only
     SwPaM* pOldPam, *pOldEnd;
+    sal_uLong nOldStart, nOldEnd;
     const sw::Frame* pOldFlyFormat;
     const SwPageDesc* pOldPageDesc;
 
@@ -554,6 +555,7 @@ public:
     bool m_bFontSizeWritten;
 
     SwDoc *m_pDoc;
+    sal_uLong m_nCurStart, m_nCurEnd;
     SwPaM *m_pCurPam, *m_pOrigPam;
 
     /// Stack to remember the nesting (see MSWordSaveData for more)
commit cf079c58295be078631caa5091817f276b505c74
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Tue Jun 9 09:43:43 2015 +0100

    combine duplicate code into shared method
    
    Change-Id: I76d50a135153a7022b481e4025f9b5f948ce7efa
    (cherry picked from commit fce7587b4deea4d79c9da695bb8f43a2a5864ce2)

diff --git a/sw/source/filter/ww8/wrtww8.cxx b/sw/source/filter/ww8/wrtww8.cxx
index 6e71f61..6d1cd84 100644
--- a/sw/source/filter/ww8/wrtww8.cxx
+++ b/sw/source/filter/ww8/wrtww8.cxx
@@ -1724,17 +1724,7 @@ void MSWordExportBase::WriteSpecialText( sal_uLong nStart, sal_uLong nEnd, sal_u
     bool bOldPageDescs = m_bOutPageDescs;
     m_bOutPageDescs = false;
                                     // bOutKF was setted / stored in WriteKF1
-    m_pCurPam = Writer::NewSwPaM( *m_pDoc, nStart, nEnd );
-
-    // Tabelle in Sonderbereichen erkennen
-    if ( ( nStart != m_pCurPam->GetMark()->nNode.GetIndex() ) &&
-         m_pDoc->GetNodes()[ nStart ]->IsTableNode() )
-    {
-        m_pCurPam->GetMark()->nNode = nStart;
-    }
-
-    m_pOrigPam = m_pCurPam;
-    m_pCurPam->Exchange();
+    SetCurPam(nStart, nEnd);
 
     WriteText();
 
@@ -1799,6 +1789,21 @@ void WW8Export::WriteChar( sal_Unicode c )
         Strm().WriteUChar( c );
 }
 
+void MSWordExportBase::SetCurPam(sal_uLong nStt, sal_uLong nEnd)
+{
+    m_pCurPam = Writer::NewSwPaM( *m_pDoc, nStt, nEnd );
+
+    // Recognize tables in special cases
+    if ( nStt != m_pCurPam->GetMark()->nNode.GetIndex() &&
+         m_pDoc->GetNodes()[ nStt ]->IsTableNode() )
+    {
+        m_pCurPam->GetMark()->nNode = nStt;
+    }
+
+    m_pOrigPam = m_pCurPam;
+    m_pCurPam->Exchange();
+}
+
 void MSWordExportBase::SaveData( sal_uLong nStt, sal_uLong nEnd )
 {
     MSWordSaveData aData;
@@ -1820,17 +1825,7 @@ void MSWordExportBase::SaveData( sal_uLong nStt, sal_uLong nEnd )
     aData.bOldStartTOX = m_bStartTOX;
     aData.bOldInWriteTOX = m_bInWriteTOX;
 
-    m_pCurPam = Writer::NewSwPaM( *m_pDoc, nStt, nEnd );
-
-    // Recognize tables in special cases
-    if ( nStt != m_pCurPam->GetMark()->nNode.GetIndex() &&
-         m_pDoc->GetNodes()[ nStt ]->IsTableNode() )
-    {
-        m_pCurPam->GetMark()->nNode = nStt;
-    }
-
-    m_pOrigPam = m_pCurPam;
-    m_pCurPam->Exchange();
+    SetCurPam(nStt, nEnd);
 
     m_bOutTable = false;
     // Caution: bIsInTable should not be set here
diff --git a/sw/source/filter/ww8/wrtww8.hxx b/sw/source/filter/ww8/wrtww8.hxx
index 2b7cdff..898051e 100644
--- a/sw/source/filter/ww8/wrtww8.hxx
+++ b/sw/source/filter/ww8/wrtww8.hxx
@@ -860,6 +860,8 @@ protected:
 
     const NfKeywordTable & GetNfKeywordTable();
 
+    void SetCurPam(sal_uLong nStt, sal_uLong nEnd);
+
     /// Populates m_vecBulletPic with all the bullet graphics used by numberings.
     int CollectGrfsOfBullets();
     /// Write the numbering picture bullets.
commit 9e0e4f54fc43eabbd235c5e5d022c18660b611ad
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Mon Jun 8 10:25:13 2015 +0100

    Resolves: crash on export of ooo47778-3.sxw to docx
    
    This is a horror where the table in the frame has its cells out
    of visual sequence, so the last row appears before the last node
    so on hitting the last node we have to really jump backwards to
    a previously skipped set of nodes to find the end of the table
    
    Change-Id: I93545e0c425267647d5f048c3bd95fe0cfddf8f3
    (cherry picked from commit 89a28f54a295e1e05116176346763b16c8d187e0)

diff --git a/sw/qa/extras/ooxmlexport/data/ooo47778-3.odt b/sw/qa/extras/ooxmlexport/data/ooo47778-3.odt
new file mode 100644
index 0000000..69005b1
Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/ooo47778-3.odt differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx
index f97d6a3..6b2fb6e 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx
@@ -813,6 +813,12 @@ DECLARE_OOXMLEXPORT_TEST(testSectionHeader, "sectionprot.odt")
     }
 }
 
+DECLARE_OOXMLEXPORT_TEST(testOO47778, "ooo47778-3.odt")
+{
+    if (xmlDocPtr pXmlDoc = parseExport("word/document.xml"))
+        assertXPathContent(pXmlDoc, "(//w:t)[3]", "c");
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/ww8/wrtww8.cxx b/sw/source/filter/ww8/wrtww8.cxx
index c7883a6..6e71f61 100644
--- a/sw/source/filter/ww8/wrtww8.cxx
+++ b/sw/source/filter/ww8/wrtww8.cxx
@@ -2531,11 +2531,51 @@ void WW8Export::SectionBreaksAndFrames( const SwTextNode& rNode )
         OutWW6FlyFrmsInContent( rNode );
 }
 
+class TrackContentToExport
+{
+private:
+    SwPaM *m_pCurPam;
+    SwPaM m_aOrigPam;
+public:
+    TrackContentToExport(SwPaM *pCurPam)
+        : m_pCurPam(pCurPam)
+        , m_aOrigPam(*pCurPam, NULL)
+    {
+    }
+
+    bool contentRemainsToExport(ww8::WW8TableInfo *pTableInfo)
+    {
+        bool bSimpleContentRemains = m_pCurPam->GetPoint()->nNode < m_pCurPam->GetMark()->nNode ||
+            (m_pCurPam->GetPoint()->nNode == m_pCurPam->GetMark()->nNode &&
+              m_pCurPam->GetPoint()->nContent.GetIndex() <= m_pCurPam->GetMark()->nContent.GetIndex());
+        if (bSimpleContentRemains)
+            return true;
+
+        if (!pTableInfo)
+            return false;
+
+        //An old-school table where one cell may points back to a previous node as the next cell
+        //so if this node is the last node in the range, we may need to jump back to a previously
+        //skipped cell to output it in a sane sequence. See ooo47778-3.sxw for one of these
+        //horrors. So if we are at the end of the selection, but this end point is a table
+        //cell whose next cell is in the selection allow jumping back to it
+        const SwNode* pCurrentNode = &m_pCurPam->GetPoint()->nNode.GetNode();
+        const SwNode* pNextNode = pTableInfo->getNextNode(pCurrentNode);
+
+        if (pNextNode && pCurrentNode != pNextNode)
+        {
+            return pNextNode->GetIndex() >= m_aOrigPam.GetPoint()->nNode.GetIndex() &&
+                   pNextNode->GetIndex() < m_aOrigPam.GetMark()->nNode.GetIndex();
+        }
+
+        return false;
+    }
+};
+
 void MSWordExportBase::WriteText()
 {
-    while( m_pCurPam->GetPoint()->nNode < m_pCurPam->GetMark()->nNode ||
-           ( m_pCurPam->GetPoint()->nNode == m_pCurPam->GetMark()->nNode &&
-             m_pCurPam->GetPoint()->nContent.GetIndex() <= m_pCurPam->GetMark()->nContent.GetIndex() ) )
+    TrackContentToExport aContentTracking(m_pCurPam);
+    while (aContentTracking.contentRemainsToExport(m_pTableInfo.get()))
     {
         SwNode& rNd = m_pCurPam->GetNode();
 
commit 47bd63e9bf9c36551c5760a9037acfd36d264827
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Wed Jun 3 15:20:13 2015 +0100

    fix crash on export of ooo39845-7.sxw to .docx
    
    only bump m_nFieldsInHyperlink if the field isn't erased
    from the stack
    
    Change-Id: Idb75d087f6fa3ce3cd399623d8ace1e7f3899b5c
    (cherry picked from commit 77df4faa4783df38383020a6236136a88eb51069)

diff --git a/sw/qa/extras/ooxmlexport/data/ooo39845-7.odt b/sw/qa/extras/ooxmlexport/data/ooo39845-7.odt
new file mode 100644
index 0000000..ee8d139
Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/ooo39845-7.odt differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx b/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx
index 5e18937..f702fa9 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx
@@ -677,6 +677,13 @@ DECLARE_OOXMLEXPORT_TEST(testOO34469, "ooo34469-1.odt")
         assertXPath(pXmlDoc, "/w:document/w:body/w:p[1]/w:hyperlink[1]", "anchor", "2.9.2.Creating New files|outline");
 }
 
+DECLARE_OOXMLEXPORT_TEST(testOO39845, "ooo39845-7.odt")
+{
+    if (xmlDocPtr pXmlDoc = parseExport())
+        assertXPath(pXmlDoc, "/w:document/w:body/w:p[1]/w:hyperlink[1]", "anchor", "Figure4|graphic");
+}
+
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx
index 629a9ae..79ced22 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -1059,9 +1059,6 @@ void DocxAttributeOutput::EndRun()
         {
             StartField_Impl( *pIt );
 
-            if (m_startedHyperlink)
-                ++m_nFieldsInHyperlink;
-
             // Remove the field from the stack if only the start has to be written
             // Unknown fields should be removed too
             if ( !pIt->bClose || ( pIt->eType == ww::eUNKNOWN ) )
@@ -1070,6 +1067,9 @@ void DocxAttributeOutput::EndRun()
                 continue;
             }
 
+            if (m_startedHyperlink)
+                ++m_nFieldsInHyperlink;
+
             if ( m_pHyperlinkAttrList )
             {
                 m_nFieldsInHyperlink++;
commit 56ef1d03ceecf47c21b6012a733da9e9562f180b
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Wed Jun 3 10:20:01 2015 +0100

    fix crash on export of ooo34469-1.sxw to docx
    
    Change-Id: I94a11bd24ccbc550c9fa555b1a0b5493ccd9f904
    (cherry picked from commit 9d0c6308be5fb086e51cb8b4b0652f3d6184fd3c)

diff --git a/sw/qa/extras/ooxmlexport/data/ooo34469-1.odt b/sw/qa/extras/ooxmlexport/data/ooo34469-1.odt
new file mode 100644
index 0000000..7cf031f
Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/ooo34469-1.odt differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx b/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx
index 9121588..5e18937 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx
@@ -671,6 +671,12 @@ DECLARE_OOXMLEXPORT_TEST(testFixedDateFields, "fixed-date-field.docx")
     }
 }
 
+DECLARE_OOXMLEXPORT_TEST(testOO34469, "ooo34469-1.odt")
+{
+    if (xmlDocPtr pXmlDoc = parseExport())
+        assertXPath(pXmlDoc, "/w:document/w:body/w:p[1]/w:hyperlink[1]", "anchor", "2.9.2.Creating New files|outline");
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx
index f6fa97a..629a9ae 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -1052,7 +1052,7 @@ void DocxAttributeOutput::EndRun()
     }
 
     // Write field starts
-    for ( std::vector<FieldInfos>::iterator pIt = m_Fields.begin(); pIt != m_Fields.end(); )
+    for ( std::vector<FieldInfos>::iterator pIt = m_Fields.begin() + nFieldsInPrevHyperlink; pIt != m_Fields.end(); )
     {
         // Add the fields starts for all but hyperlinks and TOCs
         if ( pIt->bOpen && pIt->pField )
@@ -1266,6 +1266,7 @@ void DocxAttributeOutput::EndRun()
                 EndField_Impl( m_Fields.back( ) );
                 m_Fields.pop_back();
             }
+            m_nFieldsInHyperlink = 0;
 
             m_pSerializer->endElementNS( XML_w, XML_hyperlink );
             m_startedHyperlink = false;
@@ -1274,12 +1275,15 @@ void DocxAttributeOutput::EndRun()
         m_closeHyperlinkInThisRun = false;
     }
 
-    if(!m_startedHyperlink)
+    if (!m_startedHyperlink)
+    {
         while ( m_Fields.begin() != m_Fields.end() )
         {
             EndField_Impl( m_Fields.front( ) );
             m_Fields.erase( m_Fields.begin( ) );
         }
+        m_nFieldsInHyperlink = 0;
+    }
 }
 
 void DocxAttributeOutput::DoWriteBookmarks()
commit 362897df5ef52b42d40550a6a896a8e1873a35ed
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Tue Jun 2 16:00:59 2015 +0100

    move ++m_nFieldsInHyperlink from StartField_Impl to callers
    
    no logic change at all, justs makes it clear the dubiousness
    of this unconditional increment
    
    Change-Id: I32e3cb2c45b1b45826a59642c33ab850d698c206
    (cherry picked from commit 6d50c6ccdf85e7d01f16d3edb957eed2a4ad5e47)

diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx
index 073ec34..f6fa97a 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -1059,6 +1059,9 @@ void DocxAttributeOutput::EndRun()
         {
             StartField_Impl( *pIt );
 
+            if (m_startedHyperlink)
+                ++m_nFieldsInHyperlink;
+
             // Remove the field from the stack if only the start has to be written
             // Unknown fields should be removed too
             if ( !pIt->bClose || ( pIt->eType == ww::eUNKNOWN ) )
@@ -1124,6 +1127,9 @@ void DocxAttributeOutput::EndRun()
         {
             StartField_Impl( *pIt, true );
 
+            if (m_startedHyperlink)
+                ++m_nFieldsInHyperlink;
+
             // Remove the field if no end needs to be written
             if ( !pIt->bClose ) {
                 pIt = m_Fields.erase( pIt );
@@ -1413,8 +1419,6 @@ void DocxAttributeOutput::WriteFFData(  const FieldInfos& rInfos )
 
 void DocxAttributeOutput::StartField_Impl( FieldInfos& rInfos, bool bWriteRun )
 {
-    if ( m_startedHyperlink )
-        ++m_nFieldsInHyperlink;
     if ( rInfos.pField && rInfos.eType == ww::eUNKNOWN )
     {
         // Expand unsupported fields
commit b69febafa040de1e7654d3fb48b9a3357ca061e9
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Wed Jun 24 10:30:28 2015 +0100

    gtk3: fix 'degenerate' clip in cairo clipping
    
    fix spelling in basebmp clipping case and downgrade
    to INFO
    
    (cherry picked from commit 8eb8ef879320960fe2147a039bbb933484856693)
    
    Change-Id: I16ec943bd4be8ca374ded7827e4ec24e7df03e8e

diff --git a/vcl/headless/svpgdi.cxx b/vcl/headless/svpgdi.cxx
index 085933e..be86a63 100644
--- a/vcl/headless/svpgdi.cxx
+++ b/vcl/headless/svpgdi.cxx
@@ -120,10 +120,13 @@ namespace
 
 void SvpSalGraphics::clipRegion(cairo_t* cr)
 {
+    RectangleVector aRectangles;
     if (!m_aClipRegion.IsEmpty())
     {
-        RectangleVector aRectangles;
         m_aClipRegion.GetRegionRectangles(aRectangles);
+    }
+    if (!aRectangles.empty())
+    {
         for (RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); ++aRectIter)
         {
             cairo_rectangle(cr, aRectIter->Left(), aRectIter->Top(), aRectIter->GetWidth(), aRectIter->GetHeight());
@@ -153,6 +156,8 @@ bool SvpSalGraphics::drawAlphaRect(long nX, long nY, long nWidth, long nHeight,
         cairo_translate(cr, 0.0, -m_aDevice->getSize().getY());
     }
 
+    clipRegion(cr);
+
     const double fTransparency = (100 - nTransparency) * (1.0/100);
     cairo_set_source_rgba(cr, m_aFillColor.getRed()/255.0,
                               m_aFillColor.getGreen()/255.0,
@@ -330,7 +335,7 @@ bool SvpSalGraphics::isClippedSetup( const basegfx::B2IBox &aRange, SvpSalGraphi
 
     if( nHit == 0 ) // rendering outside any clipping region
     {
-//        fprintf (stderr, "denegerate case detected ...\n");
+        SAL_INFO("vcl.headless", "SvpSalGraphics::isClippedSetup: degenerate case detected ...");
         return true;
     }
     else if( nHit == 1 ) // common path: rendering against just one clipping region
@@ -339,10 +344,10 @@ bool SvpSalGraphics::isClippedSetup( const basegfx::B2IBox &aRange, SvpSalGraphi
         {
             //The region to be painted (aRect) is equal to or inside the
             //current clipping region
-//        fprintf (stderr, " is inside ! avoid deeper clip ...\n");
+            SAL_INFO("vcl.headless", "SvpSalGraphics::isClippedSetup: is inside ! avoid deeper clip ...");
             return false;
         }
-//    fprintf (stderr, " operation only overlaps with a single clip zone\n" );
+        SAL_INFO("vcl.headless", "SvpSalGraphics::isClippedSetup: operation only overlaps with a single clip zone");
         rUndo.m_aDevice = m_aDevice;
         m_aDevice = basebmp::subsetBitmapDevice( m_aOrigDevice,
                                                  basegfx::B2IBox (aHitRect.Left(),
commit 83484b7b0b3ab73dedced59a52426ab9178c7605
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Wed Jun 24 10:09:26 2015 +0100

    gtk3: move cairo region clipping to svp
    
    Change-Id: I4b4f09ee3fb7edbda3b6bb5af024c0966e3a2082
    (cherry picked from commit edf56cb4300f68a3e513420feccbf8d5287a0428)

diff --git a/vcl/headless/svpgdi.cxx b/vcl/headless/svpgdi.cxx
index 43ace36..085933e 100644
--- a/vcl/headless/svpgdi.cxx
+++ b/vcl/headless/svpgdi.cxx
@@ -118,6 +118,20 @@ namespace
     }
 }
 
+void SvpSalGraphics::clipRegion(cairo_t* cr)
+{
+    if (!m_aClipRegion.IsEmpty())
+    {
+        RectangleVector aRectangles;
+        m_aClipRegion.GetRegionRectangles(aRectangles);
+        for (RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); ++aRectIter)
+        {
+            cairo_rectangle(cr, aRectIter->Left(), aRectIter->Top(), aRectIter->GetWidth(), aRectIter->GetHeight());
+        }
+        cairo_clip(cr);
+    }
+}
+
 #endif
 
 bool SvpSalGraphics::drawAlphaRect(long nX, long nY, long nWidth, long nHeight, sal_uInt8 nTransparency)
diff --git a/vcl/inc/headless/svpgdi.hxx b/vcl/inc/headless/svpgdi.hxx
index 9698e3d..9b8a25a 100644
--- a/vcl/inc/headless/svpgdi.hxx
+++ b/vcl/inc/headless/svpgdi.hxx
@@ -212,6 +212,7 @@ public:
 #if ENABLE_CAIRO_CANVAS
 
     static cairo_t*         createCairoContext(const basebmp::BitmapDeviceSharedPtr& rBuffer);
+    void                    clipRegion(cairo_t* cr);
 
 #endif // ENABLE_CAIRO_CANVAS
 
diff --git a/vcl/inc/unx/gtk/gtkgdi.hxx b/vcl/inc/unx/gtk/gtkgdi.hxx
index 0d02188..80de62b 100644
--- a/vcl/inc/unx/gtk/gtkgdi.hxx
+++ b/vcl/inc/unx/gtk/gtkgdi.hxx
@@ -61,8 +61,6 @@ public:
 
     cairo_t* getCairoContext() const;
 
-    void clipRegion(cairo_t* cr);
-
 private:
     GtkWidget       *mpWindow;
     static GtkStyleContext *mpButtonStyle;
diff --git a/vcl/unx/gtk3/gdi/gtk3salnativewidgets-gtk.cxx b/vcl/unx/gtk3/gdi/gtk3salnativewidgets-gtk.cxx
index 080f6cc..84c138c 100644
--- a/vcl/unx/gtk3/gdi/gtk3salnativewidgets-gtk.cxx
+++ b/vcl/unx/gtk3/gdi/gtk3salnativewidgets-gtk.cxx
@@ -2104,18 +2104,4 @@ cairo_t* GtkSalGraphics::getCairoContext() const
     return mpFrame->getCairoContext();
 }
 
-void GtkSalGraphics::clipRegion(cairo_t* cr)
-{
-    if (!m_aClipRegion.IsEmpty())
-    {
-        RectangleVector aRectangles;
-        m_aClipRegion.GetRegionRectangles(aRectangles);
-        for (RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); ++aRectIter)
-        {
-            cairo_rectangle(cr, aRectIter->Left(), aRectIter->Top(), aRectIter->GetWidth(), aRectIter->GetHeight());
-        }
-        cairo_clip(cr);
-    }
-}
-
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit 7357f6f8bff02d403e88c7e9f4a2a36d5f269fa9
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Wed Jun 24 10:07:14 2015 +0100

    gtk3: alpha rects using cairo
    
    (cherry picked from commit 65d31de78dd3f5055102122e60b7261f8b170df5)
    
    Change-Id: I7fdcd6336fdc7ea8149c385a177db91ffaa61c94
    
    stinking ancient cairo impls
    
    Change-Id: I35e826bc78556a912358dfad2fac7c45ca35bfd1
    (cherry picked from commit a7a95af74badcb745bb1c86c7f9a21444ca12c77)
    
    WaE: -Werror=unused-parameter on Android
    
    Change-Id: Ie5a4015794350a513c39a60ae650f4626d92e1b8
    (cherry picked from commit b28a63728ac081b3cc94c76d0bac4a573087ca5e)
    
    error: missing binary operator before token '('
    
    Change-Id: Ieafb13245a11347cbda8a33e49ad618bf85d8a89
    (cherry picked from commit 3928a1514c9202a52d698570022c197ecc8703eb)
    
    WaE: error: 'CAIRO_VERSION' is not defined
    
    Change-Id: I9e4f0d0af541226089a6295962a91ca09debb418
    (cherry picked from commit b51fe01f7c8853c353401001bdd417b9ed27fb87)
    
    try harder to hide this from android tinderbox
    
    Change-Id: I586fea9f1570b68ed789da8b10a3b46216c42969
    (cherry picked from commit f1761903cdafd12d4b33d4e8733971a3d9ad8a10)

diff --git a/vcl/headless/svpgdi.cxx b/vcl/headless/svpgdi.cxx
index 6811e93..43ace36 100644
--- a/vcl/headless/svpgdi.cxx
+++ b/vcl/headless/svpgdi.cxx
@@ -96,10 +96,89 @@ bool SvpSalGraphics::drawTransformedBitmap(
     return false;
 }
 
-bool SvpSalGraphics::drawAlphaRect( long /*nX*/, long /*nY*/, long /*nWidth*/, long /*nHeight*/, sal_uInt8 /*nTransparency*/ )
+#if ENABLE_CAIRO_CANVAS
+
+namespace
 {
-    // TODO(P3) implement alpha blending
-    return false;
+    bool isCairoCompatible(const basebmp::BitmapDeviceSharedPtr &rBuffer)
+    {
+        if (!rBuffer)
+            return false;
+
+        if (rBuffer->getScanlineFormat() != basebmp::FORMAT_THIRTYTWO_BIT_TC_MASK_BGRX)
+            return false;
+
+#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 6, 0)
+        basegfx::B2IVector size = rBuffer->getSize();
+        sal_Int32 nStride = rBuffer->getScanlineStride();
+        return (cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, size.getX()) == nStride);
+#else
+        return false;
+#endif
+    }
+}
+
+#endif
+
+bool SvpSalGraphics::drawAlphaRect(long nX, long nY, long nWidth, long nHeight, sal_uInt8 nTransparency)
+{
+    bool bRet = false;
+    (void)nX; (void)nY; (void)nWidth; (void)nHeight; (void)nTransparency;
+#if ENABLE_CAIRO_CANVAS
+#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 6, 0)
+    if (m_bUseLineColor || !m_bUseFillColor)
+        return bRet;
+
+    cairo_t* cr = createCairoContext(m_aDevice);
+    if (!cr)
+        return bRet;
+
+    if (!m_aDevice->isTopDown())
+    {
+        cairo_scale(cr, 1, -1.0);
+        cairo_translate(cr, 0.0, -m_aDevice->getSize().getY());
+    }
+
+    const double fTransparency = (100 - nTransparency) * (1.0/100);
+    cairo_set_source_rgba(cr, m_aFillColor.getRed()/255.0,
+                              m_aFillColor.getGreen()/255.0,
+                              m_aFillColor.getBlue()/255.0,
+                              fTransparency);
+    cairo_rectangle(cr, nX, nY, nWidth, nHeight);
+
+
+    cairo_rectangle_int_t extents;
+    basebmp::IBitmapDeviceDamageTrackerSharedPtr xDamageTracker(m_aDevice->getDamageTracker());
+    if (xDamageTracker)
+    {
+        double x1, y1, x2, y2;
+
+        cairo_clip_extents(cr, &x1, &y1, &x2, &y2);
+        extents.x = x1, extents.y = x2, extents.width = x2-x1, extents.height = y2-y1;
+        cairo_region_t *region = cairo_region_create_rectangle(&extents);
+
+        cairo_fill_extents(cr, &x1, &y1, &x2, &y2);
+        extents.x = x1, extents.y = x2, extents.width = x2-x1, extents.height = y2-y1;
+        cairo_region_intersect_rectangle(region, &extents);
+
+        cairo_region_get_extents(region, &extents);
+        cairo_region_destroy(region);
+    }
+
+    cairo_fill(cr);
+
+    cairo_surface_flush(cairo_get_target(cr));
+    cairo_destroy(cr); // unref
+
+    if (xDamageTracker)
+    {
+        xDamageTracker->damaged(basegfx::B2IBox(extents.x, extents.y, extents.x + extents.width,
+                                                extents.y + extents.height));
+    }
+    bRet = true;
+#endif
+#endif
+    return bRet;
 }
 
 SvpSalGraphics::SvpSalGraphics() :
@@ -727,32 +806,15 @@ bool SvpSalGraphics::drawEPS( long, long, long, long, void*, sal_uLong )
     return false;
 }
 
-#ifndef IOS
-
-SystemGraphicsData SvpSalGraphics::GetGraphicsData() const
-{
-    return SystemGraphicsData();
-}
-
-bool SvpSalGraphics::supportsOperation( OutDevSupportType ) const
-{
-    return false;
-}
-
-#endif
-
 #if ENABLE_CAIRO_CANVAS
 
 cairo_t* SvpSalGraphics::createCairoContext(const basebmp::BitmapDeviceSharedPtr &rBuffer)
 {
-#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 6, 0)
-    if (rBuffer->getScanlineFormat() != basebmp::FORMAT_THIRTYTWO_BIT_TC_MASK_BGRX)
+    if (!isCairoCompatible(rBuffer))
         return NULL;
 
     basegfx::B2IVector size = rBuffer->getSize();
     sal_Int32 nStride = rBuffer->getScanlineStride();
-    if (cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, size.getX()) != nStride)
-        return NULL;
 
     basebmp::RawMemorySharedArray data = rBuffer->getBuffer();
     cairo_surface_t *target =
@@ -763,9 +825,6 @@ cairo_t* SvpSalGraphics::createCairoContext(const basebmp::BitmapDeviceSharedPtr
     cairo_t* cr = cairo_create(target);
     cairo_surface_destroy(target);
     return cr;
-#else
-    return NULL;
-#endif
 }
 
 #endif
@@ -795,4 +854,25 @@ css::uno::Any SvpSalGraphics::GetNativeSurfaceHandle(cairo::SurfaceSharedPtr& /*
     return css::uno::Any();
 }
 
+#ifndef IOS
+
+SystemGraphicsData SvpSalGraphics::GetGraphicsData() const
+{
+    return SystemGraphicsData();
+}
+
+bool SvpSalGraphics::supportsOperation(OutDevSupportType eType) const
+{
+#if ENABLE_CAIRO_CANVAS
+    return m_aDrawMode != basebmp::DrawMode_XOR &&
+           OutDevSupport_TransparentRect == eType &&
+           isCairoCompatible(m_aDevice);
+#else
+    (void)eType;
+    return false;
+#endif
+}
+
+#endif
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit bb7687b295367ad7572af130298a03d7915625d4
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Tue Jun 23 20:33:18 2015 +0100

    gtk3: move createCairoContext down to svpgdi
    
    (cherry picked from commit 253c0f073715b1d0f6ba063b1182016e45951bf4)
    
    Change-Id: Ib3c6d6689c4b79a636a3f2f0f985f3573aa46f3d
    
    cairo_format_stride_for_width is 1.6 onwards
    
    (cherry picked from commit 5ce9954c5ec244b9a858ab7e996d5201a21dc3fe)
    
    Change-Id: Ic233b4b6c7067f2473eb76b0c7e520cfe1dfcd14

diff --git a/vcl/headless/svpgdi.cxx b/vcl/headless/svpgdi.cxx
index a41626f..6811e93 100644
--- a/vcl/headless/svpgdi.cxx
+++ b/vcl/headless/svpgdi.cxx
@@ -32,6 +32,10 @@
 #include <basegfx/polygon/b2dpolygontools.hxx>
 #include <basebmp/scanlineformats.hxx>
 
+#if ENABLE_CAIRO_CANVAS
+#include <cairo.h>
+#endif
+
 #if OSL_DEBUG_LEVEL > 2
 #include <basebmp/debug.hxx>
 #include <fstream>
@@ -737,6 +741,35 @@ bool SvpSalGraphics::supportsOperation( OutDevSupportType ) const
 
 #endif
 
+#if ENABLE_CAIRO_CANVAS
+
+cairo_t* SvpSalGraphics::createCairoContext(const basebmp::BitmapDeviceSharedPtr &rBuffer)
+{
+#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 6, 0)
+    if (rBuffer->getScanlineFormat() != basebmp::FORMAT_THIRTYTWO_BIT_TC_MASK_BGRX)
+        return NULL;
+
+    basegfx::B2IVector size = rBuffer->getSize();
+    sal_Int32 nStride = rBuffer->getScanlineStride();
+    if (cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, size.getX()) != nStride)
+        return NULL;
+
+    basebmp::RawMemorySharedArray data = rBuffer->getBuffer();
+    cairo_surface_t *target =
+        cairo_image_surface_create_for_data(data.get(),
+                                        CAIRO_FORMAT_RGB24,
+                                        size.getX(), size.getY(),
+                                        nStride);
+    cairo_t* cr = cairo_create(target);
+    cairo_surface_destroy(target);
+    return cr;
+#else
+    return NULL;
+#endif
+}
+
+#endif
+
 bool SvpSalGraphics::SupportsCairo() const
 {
     return false;
diff --git a/vcl/inc/headless/svpgdi.hxx b/vcl/inc/headless/svpgdi.hxx
index 297d28a..9698e3d 100644
--- a/vcl/inc/headless/svpgdi.hxx
+++ b/vcl/inc/headless/svpgdi.hxx
@@ -24,6 +24,7 @@
 #include <basebmp/color.hxx>
 #include <vcl/sysdata.hxx>
 #include <vcl/metric.hxx>
+#include <config_cairo_canvas.h>
 
 #include "salgdi.hxx"
 #include "sallayout.hxx"
@@ -35,6 +36,7 @@
 
 class GlyphCache;
 class ServerFont;
+typedef struct _cairo cairo_t;
 
 class VCL_DLLPUBLIC SvpSalGraphics : public SalGraphics
 {
@@ -207,6 +209,12 @@ public:
 
     virtual SystemFontData  GetSysFontData( int nFallbacklevel ) const SAL_OVERRIDE;
 
+#if ENABLE_CAIRO_CANVAS
+
+    static cairo_t*         createCairoContext(const basebmp::BitmapDeviceSharedPtr& rBuffer);
+
+#endif // ENABLE_CAIRO_CANVAS
+
     virtual void            BeginPaint() SAL_OVERRIDE { };
     virtual void            EndPaint() SAL_OVERRIDE { };
 };
diff --git a/vcl/unx/gtk/window/gtksalframe.cxx b/vcl/unx/gtk/window/gtksalframe.cxx
index 98c02f2..99adfff 100644
--- a/vcl/unx/gtk/window/gtksalframe.cxx
+++ b/vcl/unx/gtk/window/gtksalframe.cxx
@@ -3550,17 +3550,8 @@ gboolean GtkSalFrame::signalCrossing( GtkWidget*, GdkEventCrossing* pEvent, gpoi
 
 cairo_t* GtkSalFrame::getCairoContext() const
 {
-    basebmp::RawMemorySharedArray data = m_aFrame->getBuffer();
-    basegfx::B2IVector size = m_aFrame->getSize();
-    sal_Int32 nStride = m_aFrame->getScanlineStride();
-    assert(cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, size.getX()) == nStride);
-    cairo_surface_t *target =
-        cairo_image_surface_create_for_data(data.get(),
-                                        CAIRO_FORMAT_RGB24,
-                                        size.getX(), size.getY(),
-                                        nStride);
-    cairo_t* cr = cairo_create(target);
-    cairo_surface_destroy(target);
+    cairo_t* cr = SvpSalGraphics::createCairoContext(m_aFrame);
+    assert(cr);
     return cr;
 }
 


More information about the Libreoffice-commits mailing list