[Libreoffice-commits] core.git: include/oox oox/source sc/source sd/qa

Gülşah Köse (via logerrit) logerrit at kemper.freedesktop.org
Thu Jul 8 21:12:43 UTC 2021


 include/oox/core/contexthandler2.hxx          |   19 +++++
 include/oox/core/fragmenthandler2.hxx         |   11 ---
 include/oox/drawingml/graphicshapecontext.hxx |    1 
 include/oox/ole/oleobjecthelper.hxx           |    1 
 oox/source/core/contexthandler2.cxx           |   85 +++++++++++++++++++++++++-
 oox/source/core/fragmenthandler2.cxx          |   70 ---------------------
 oox/source/drawingml/graphicshapecontext.cxx  |   11 +++
 sc/source/filter/oox/worksheetfragment.cxx    |    6 -
 sd/qa/unit/data/pptx/tdf143222.pptx           |binary
 sd/qa/unit/export-tests-ooxml3.cxx            |   30 +++++++++
 10 files changed, 148 insertions(+), 86 deletions(-)

New commits:
commit 92a407b7f90a98704a238c5ffa3a3491eaf3263a
Author:     Gülşah Köse <gulsah.kose at collabora.com>
AuthorDate: Wed Jul 7 00:27:58 2021 +0300
Commit:     Gülşah Köse <gulsah.kose at collabora.com>
CommitDate: Thu Jul 8 23:12:07 2021 +0200

    tdf143222 Handle alternate content of graphicData element.
    
    Handle alternate content and make true choice.
    
    According to ooxml spec ole object requires exactly one pic
    element. (ECMA-376 Part 1, Annex A, CT_OleObject). In the
    current case first choice has not pic element and we should
    allow fallback processing.
    
    Change-Id: I30b7de703b8c2f00d6bf286e05eea505ac3627f2
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/118539
    Tested-by: Jenkins
    Reviewed-by: Gülşah Köse <gulsah.kose at collabora.com>

diff --git a/include/oox/core/contexthandler2.hxx b/include/oox/core/contexthandler2.hxx
index 4e256089ac8e..3a75aff5706a 100644
--- a/include/oox/core/contexthandler2.hxx
+++ b/include/oox/core/contexthandler2.hxx
@@ -72,7 +72,7 @@ struct ElementInfo;
 class OOX_DLLPUBLIC ContextHandler2Helper
 {
 public:
-    explicit            ContextHandler2Helper( bool bEnableTrimSpace );
+    explicit            ContextHandler2Helper( bool bEnableTrimSpace, XmlFilterBase& rFilter );
     explicit            ContextHandler2Helper( const ContextHandler2Helper& rParent );
     virtual             ~ContextHandler2Helper();
 
@@ -201,6 +201,21 @@ protected:
     /** Must be called from endRecord() in derived classes. */
     void                implEndRecord( sal_Int32 nRecId );
 
+    bool                prepareMceContext( sal_Int32 nElement, const AttributeList& rAttribs );
+    XmlFilterBase&      getDocFilter() const { return mrFilter; }
+
+    enum class MCE_STATE
+    {
+        Started,
+        FoundChoice
+    };
+
+    MCE_STATE           getMCEState() const { return aMceState.back(); }
+    void                setMCEState( MCE_STATE aState ) { aMceState.back() = aState; }
+    void                addMCEState( MCE_STATE aState ) { aMceState.push_back( aState ); }
+    void                removeMCEState() { aMceState.pop_back(); }
+    bool                isMCEStateEmpty() { return aMceState.empty(); }
+
 private:
     ContextHandler2Helper& operator=( const ContextHandler2Helper& ) = delete;
 
@@ -214,9 +229,11 @@ private:
 
     ContextStackRef     mxContextStack;     ///< Stack of all processed elements.
     size_t              mnRootStackSize;    ///< Stack size on construction time.
+    std::vector<MCE_STATE> aMceState;
 
 protected:
     bool                mbEnableTrimSpace;  ///< True = trim whitespace in characters().
+    XmlFilterBase&      mrFilter;
 };
 
 class OOX_DLLPUBLIC ContextHandler2 : public ContextHandler, public ContextHandler2Helper
diff --git a/include/oox/core/fragmenthandler2.hxx b/include/oox/core/fragmenthandler2.hxx
index 86d1453f13a1..598426ee681e 100644
--- a/include/oox/core/fragmenthandler2.hxx
+++ b/include/oox/core/fragmenthandler2.hxx
@@ -47,17 +47,6 @@ class XmlFilterBase;
 
 class OOX_DLLPUBLIC FragmentHandler2 : public FragmentHandler, public ContextHandler2Helper
 {
-protected:
-    enum class MCE_STATE
-    {
-        Started,
-        FoundChoice
-    };
-    ::std::vector<MCE_STATE>           aMceState;
-
-    bool                prepareMceContext( sal_Int32 nElement, const AttributeList& rAttribs );
-
-
 public:
     explicit            FragmentHandler2(
                             XmlFilterBase& rFilter,
diff --git a/include/oox/drawingml/graphicshapecontext.hxx b/include/oox/drawingml/graphicshapecontext.hxx
index 4813d5fc9aed..ffd579f00bb1 100644
--- a/include/oox/drawingml/graphicshapecontext.hxx
+++ b/include/oox/drawingml/graphicshapecontext.hxx
@@ -62,6 +62,7 @@ public:
     OleObjectGraphicDataContext( ::oox::core::ContextHandler2Helper const & rParent, const ShapePtr& pShapePtr );
     virtual ~OleObjectGraphicDataContext() override;
     virtual ::oox::core::ContextHandlerRef onCreateContext( ::sal_Int32 Element, const ::oox::AttributeList& rAttribs ) override;
+    virtual void onEndElement() override;
 
 private:
     ::oox::vml::OleObjectInfo& mrOleObjectInfo;
diff --git a/include/oox/ole/oleobjecthelper.hxx b/include/oox/ole/oleobjecthelper.hxx
index d2506f3d4949..5b792f2048b1 100644
--- a/include/oox/ole/oleobjecthelper.hxx
+++ b/include/oox/ole/oleobjecthelper.hxx
@@ -47,6 +47,7 @@ struct OleObjectInfo
     bool                mbLinked;           ///< True = linked OLE object, false = embedded OLE object.
     bool                mbShowAsIcon;       ///< True = show as icon, false = show contents.
     bool                mbAutoUpdate;
+    bool                mbHasPicture;       ///<Ole object requires a picture element according to spec.>
 
     explicit            OleObjectInfo();
 };
diff --git a/oox/source/core/contexthandler2.cxx b/oox/source/core/contexthandler2.cxx
index 8ce9784b99ef..1613a3d330cc 100644
--- a/oox/source/core/contexthandler2.cxx
+++ b/oox/source/core/contexthandler2.cxx
@@ -18,16 +18,20 @@
  */
 
 #include <oox/core/contexthandler2.hxx>
+#include <oox/core/xmlfilterbase.hxx>
 #include <oox/helper/attributelist.hxx>
 #include <oox/token/namespaces.hxx>
 #include <oox/token/tokens.hxx>
 #include <rtl/ustrbuf.hxx>
 #include <o3tl/safeint.hxx>
 #include <osl/diagnose.h>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
 
 namespace oox::core {
 
 using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
 using namespace ::com::sun::star::xml::sax;
 
 /** Information about a processed element. */
@@ -40,10 +44,11 @@ struct ElementInfo
     explicit     ElementInfo() : maChars( 0), mnElement( XML_TOKEN_INVALID ), mbTrimSpaces( false ) {}
 };
 
-ContextHandler2Helper::ContextHandler2Helper( bool bEnableTrimSpace ) :
+ContextHandler2Helper::ContextHandler2Helper( bool bEnableTrimSpace, XmlFilterBase& rFilter ) :
     mxContextStack( std::make_shared<ContextStack>() ),
     mnRootStackSize( 0 ),
-    mbEnableTrimSpace( bEnableTrimSpace )
+    mbEnableTrimSpace( bEnableTrimSpace ),
+    mrFilter( rFilter )
 {
     pushElementInfo( XML_ROOT_CONTEXT );
 }
@@ -51,7 +56,8 @@ ContextHandler2Helper::ContextHandler2Helper( bool bEnableTrimSpace ) :
 ContextHandler2Helper::ContextHandler2Helper( const ContextHandler2Helper& rParent ) :
     mxContextStack( rParent.mxContextStack ),
     mnRootStackSize( rParent.mxContextStack->size() ),
-    mbEnableTrimSpace( rParent.mbEnableTrimSpace )
+    mbEnableTrimSpace( rParent.mbEnableTrimSpace ),
+    mrFilter(rParent.mrFilter)
 {
 }
 
@@ -188,6 +194,13 @@ ContextHandler2::~ContextHandler2()
 Reference< XFastContextHandler > SAL_CALL ContextHandler2::createFastChildContext(
         sal_Int32 nElement, const Reference< XFastAttributeList >& rxAttribs )
 {
+    if( getNamespace( nElement ) == NMSP_mce ) // TODO for checking 'Ignorable'
+    {
+        if( prepareMceContext( nElement, AttributeList( rxAttribs ) ) )
+            return this;
+        return nullptr;
+    }
+
     return implCreateChildContext( nElement, rxAttribs );
 }
 
@@ -207,6 +220,72 @@ void SAL_CALL ContextHandler2::endFastElement( sal_Int32 nElement )
     implEndElement( nElement );
 }
 
+bool ContextHandler2Helper::prepareMceContext( sal_Int32 nElement, const AttributeList& rAttribs )
+{
+    switch( nElement )
+    {
+        case MCE_TOKEN( AlternateContent ):
+            addMCEState( MCE_STATE::Started );
+            break;
+
+        case MCE_TOKEN( Choice ):
+            {
+                if (isMCEStateEmpty() || getMCEState() != MCE_STATE::Started)
+                    return false;
+
+                OUString aRequires = rAttribs.getString( XML_Requires, "none" );
+
+                // At this point we can't access namespaces as the correct xml filter
+                // is long gone. For now let's decide depending on a list of supported
+                // namespaces like we do in writerfilter
+
+                std::vector<OUString> aSupportedNS =
+                {
+                    "a14", // Impress needs this to import math formulas.
+                    "p14",
+                    "p15",
+                    "x12ac",
+                    "v"
+                };
+
+                Reference<XServiceInfo> xModel(getDocFilter().getModel(), UNO_QUERY);
+                if (xModel.is() && xModel->supportsService("com.sun.star.sheet.SpreadsheetDocument"))
+                {
+                    // No a14 for Calc documents, it would cause duplicated shapes as-is.
+                    auto it = std::find(aSupportedNS.begin(), aSupportedNS.end(), "a14");
+                    if (it != aSupportedNS.end())
+                    {
+                        aSupportedNS.erase(it);
+                    }
+                }
+
+                if (std::find(aSupportedNS.begin(), aSupportedNS.end(), aRequires) != aSupportedNS.end())
+                    setMCEState( MCE_STATE::FoundChoice ) ;
+                else
+                    return false;
+            }
+            break;
+
+        case MCE_TOKEN( Fallback ):
+            if( !isMCEStateEmpty() && getMCEState() == MCE_STATE::Started )
+                break;
+            return false;
+        default:
+            {
+                OUString str = rAttribs.getString( MCE_TOKEN( Ignorable ), OUString() );
+                if( !str.isEmpty() )
+                {
+                    // Sequence< css::xml::FastAttribute > attrs = rAttribs.getFastAttributeList()->getFastAttributes();
+                    // printf("MCE: %s\n", OUStringToOString( str, RTL_TEXTENCODING_UTF8 ).getStr() );
+                    // TODO: Check & Get the namespaces in "Ignorable"
+                    // printf("NS: %d : %s\n", attrs.getLength(), OUStringToOString( str, RTL_TEXTENCODING_UTF8 ).getStr() );
+                }
+            }
+            return false;
+    }
+    return true;
+}
+
 // oox.core.RecordContext interface -------------------------------------------
 
 ContextHandlerRef ContextHandler2::createRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm )
diff --git a/oox/source/core/fragmenthandler2.cxx b/oox/source/core/fragmenthandler2.cxx
index 121f3443731f..3ee410fad854 100644
--- a/oox/source/core/fragmenthandler2.cxx
+++ b/oox/source/core/fragmenthandler2.cxx
@@ -34,7 +34,7 @@ using namespace ::com::sun::star::xml::sax;
 
 FragmentHandler2::FragmentHandler2( XmlFilterBase& rFilter, const OUString& rFragmentPath, bool bEnableTrimSpace ) :
     FragmentHandler( rFilter, rFragmentPath ),
-    ContextHandler2Helper( bEnableTrimSpace )
+    ContextHandler2Helper( bEnableTrimSpace, rFilter )
 {
 }
 
@@ -54,72 +54,6 @@ void SAL_CALL FragmentHandler2::endDocument()
     finalizeImport();
 }
 
-bool FragmentHandler2::prepareMceContext( sal_Int32 nElement, const AttributeList& rAttribs )
-{
-    switch( nElement )
-    {
-        case MCE_TOKEN( AlternateContent ):
-            aMceState.push_back( MCE_STATE::Started );
-            break;
-
-        case MCE_TOKEN( Choice ):
-            {
-                if (aMceState.empty() || aMceState.back() != MCE_STATE::Started)
-                    return false;
-
-                OUString aRequires = rAttribs.getString( XML_Requires, "none" );
-
-                // At this point we can't access namespaces as the correct xml filter
-                // is long gone. For now let's decide depending on a list of supported
-                // namespaces like we do in writerfilter
-
-                std::vector<OUString> aSupportedNS =
-                {
-                    "a14", // Impress needs this to import math formulas.
-                    "p14",
-                    "p15",
-                    "x12ac",
-                    "v",
-                };
-
-                uno::Reference<lang::XServiceInfo> xModel(getFilter().getModel(), uno::UNO_QUERY);
-                if (xModel.is() && xModel->supportsService("com.sun.star.sheet.SpreadsheetDocument"))
-                {
-                    // No a14 for Calc documents, it would cause duplicated shapes as-is.
-                    auto it = std::find(aSupportedNS.begin(), aSupportedNS.end(), "a14");
-                    if (it != aSupportedNS.end())
-                    {
-                        aSupportedNS.erase(it);
-                    }
-                }
-
-                if (std::find(aSupportedNS.begin(), aSupportedNS.end(), aRequires) != aSupportedNS.end())
-                    aMceState.back() = MCE_STATE::FoundChoice;
-                else
-                    return false;
-            }
-            break;
-
-        case MCE_TOKEN( Fallback ):
-            if( !aMceState.empty() && aMceState.back() == MCE_STATE::Started )
-                break;
-            return false;
-        default:
-            {
-                OUString str = rAttribs.getString( MCE_TOKEN( Ignorable ), OUString() );
-                if( !str.isEmpty() )
-                {
-                    // Sequence< css::xml::FastAttribute > attrs = rAttribs.getFastAttributeList()->getFastAttributes();
-                    // printf("MCE: %s\n", OUStringToOString( str, RTL_TEXTENCODING_UTF8 ).getStr() );
-                    // TODO: Check & Get the namespaces in "Ignorable"
-                    // printf("NS: %d : %s\n", attrs.getLength(), OUStringToOString( str, RTL_TEXTENCODING_UTF8 ).getStr() );
-                }
-            }
-            return false;
-    }
-    return true;
-}
-
 // com.sun.star.xml.sax.XFastContextHandler interface -------------------------
 
 Reference< XFastContextHandler > SAL_CALL FragmentHandler2::createFastChildContext(
@@ -151,7 +85,7 @@ void SAL_CALL FragmentHandler2::endFastElement( sal_Int32 nElement )
     switch( nElement )
     {
         case MCE_TOKEN( AlternateContent ):
-            aMceState.pop_back();
+            removeMCEState();
             break;
     }
 
diff --git a/oox/source/drawingml/graphicshapecontext.cxx b/oox/source/drawingml/graphicshapecontext.cxx
index 113e5490c51d..3ed00edfd28c 100644
--- a/oox/source/drawingml/graphicshapecontext.cxx
+++ b/oox/source/drawingml/graphicshapecontext.cxx
@@ -214,6 +214,7 @@ ContextHandlerRef OleObjectGraphicDataContext::onCreateContext( sal_Int32 nEleme
             mrOleObjectInfo.maName = rAttribs.getXString( XML_name, OUString() );
             mrOleObjectInfo.maProgId = rAttribs.getXString( XML_progId, OUString() );
             mrOleObjectInfo.mbShowAsIcon = rAttribs.getBool( XML_showAsIcon, false );
+            mrOleObjectInfo.mbHasPicture = false; // Initialize as false
             return this;
         }
         break;
@@ -227,6 +228,7 @@ ContextHandlerRef OleObjectGraphicDataContext::onCreateContext( sal_Int32 nEleme
             mrOleObjectInfo.mbAutoUpdate = rAttribs.getBool( XML_updateAutomatic, false );
         break;
         case PPT_TOKEN( pic ):
+            mrOleObjectInfo.mbHasPicture = true; // Set true if ole object has picture element.
             return new GraphicShapeContext( *this, mpMasterShapePtr, mpShapePtr );
     }
     SAL_WARN("oox", "OleObjectGraphicDataContext::onCreateContext: unhandled element: "
@@ -234,6 +236,15 @@ ContextHandlerRef OleObjectGraphicDataContext::onCreateContext( sal_Int32 nEleme
     return nullptr;
 }
 
+void OleObjectGraphicDataContext::onEndElement()
+{
+    if( getCurrentElement() == PPT_TOKEN( oleObj ) && !isMCEStateEmpty() )
+    {
+        if( getMCEState() == MCE_STATE::FoundChoice && !mrOleObjectInfo.mbHasPicture )
+            setMCEState( MCE_STATE::Started );
+    }
+}
+
 DiagramGraphicDataContext::DiagramGraphicDataContext( ContextHandler2Helper const & rParent, const ShapePtr& pShapePtr )
 : ShapeContext( rParent, ShapePtr(), pShapePtr )
 {
diff --git a/sc/source/filter/oox/worksheetfragment.cxx b/sc/source/filter/oox/worksheetfragment.cxx
index 20e802d96224..a0e01c915dcf 100644
--- a/sc/source/filter/oox/worksheetfragment.cxx
+++ b/sc/source/filter/oox/worksheetfragment.cxx
@@ -466,17 +466,17 @@ ContextHandlerRef WorksheetFragment::onCreateContext( sal_Int32 nElement, const
         case XLS_TOKEN( oleObjects ):
             if ( getCurrentElement() == XLS_TOKEN( controls ) )
             {
-                if( aMceState.empty() || aMceState.back() == MCE_STATE::Started )
+                if( isMCEStateEmpty() || getMCEState() == MCE_STATE::Started )
                 {
                     if ( getCurrentElement() == XLS_TOKEN( oleObjects ) ) importOleObject( rAttribs );
                     else
                         importControl( rAttribs );
                 }
-                else if ( !aMceState.empty() && aMceState.back() == MCE_STATE::FoundChoice )
+                else if ( !isMCEStateEmpty() && getMCEState() == MCE_STATE::FoundChoice )
                 {
                     // reset the handling within 'Choice'
                     // this will force attempted handling in Fallback
-                    aMceState.back() = MCE_STATE::Started;
+                    setMCEState( MCE_STATE::Started );
                 }
             }
         break;
diff --git a/sd/qa/unit/data/pptx/tdf143222.pptx b/sd/qa/unit/data/pptx/tdf143222.pptx
new file mode 100644
index 000000000000..63938d1bdc71
Binary files /dev/null and b/sd/qa/unit/data/pptx/tdf143222.pptx differ
diff --git a/sd/qa/unit/export-tests-ooxml3.cxx b/sd/qa/unit/export-tests-ooxml3.cxx
index 6632934e430e..f773c364f395 100644
--- a/sd/qa/unit/export-tests-ooxml3.cxx
+++ b/sd/qa/unit/export-tests-ooxml3.cxx
@@ -22,6 +22,7 @@
 #include <svx/svdotable.hxx>
 #include <svx/xlineit0.hxx>
 #include <svx/xlndsit.hxx>
+#include <svx/svdoole2.hxx>
 #include <rtl/ustring.hxx>
 
 #include <com/sun/star/drawing/XDrawPage.hpp>
@@ -116,6 +117,7 @@ public:
     void testTdf125560_textDeflate();
     void testTdf125560_textInflateTop();
     void testTdf96061_textHighlight();
+    void testTdf143222_embeddedWorksheet();
     void testTdf142235_TestPlaceholderTextAlignment();
 
     CPPUNIT_TEST_SUITE(SdOOXMLExportTest3);
@@ -185,6 +187,7 @@ public:
     CPPUNIT_TEST(testTdf125560_textDeflate);
     CPPUNIT_TEST(testTdf125560_textInflateTop);
     CPPUNIT_TEST(testTdf96061_textHighlight);
+    CPPUNIT_TEST(testTdf143222_embeddedWorksheet);
     CPPUNIT_TEST(testTdf142235_TestPlaceholderTextAlignment);
     CPPUNIT_TEST_SUITE_END();
 
@@ -1743,6 +1746,33 @@ void SdOOXMLExportTest3::testTdf96061_textHighlight()
     CPPUNIT_ASSERT_EQUAL(sal_Int32(-1), aColor);
 }
 
+void SdOOXMLExportTest3::testTdf143222_embeddedWorksheet()
+{
+    // Check import of embedded worksheet in slide.
+    ::sd::DrawDocShellRef xDocShRef
+        = loadURL(m_directories.getURLFromSrc(u"sd/qa/unit/data/pptx/tdf143222.pptx"), PPTX);
+
+    const SdrPage* pPage = GetPage(1, xDocShRef.get());
+    const SdrOle2Obj* pOleObj = static_cast<SdrOle2Obj*>(pPage->GetObj(0));
+    CPPUNIT_ASSERT_MESSAGE("no object", pOleObj != nullptr);
+
+    // Without the fix we lost the graphic of ole object.
+    const Graphic* pGraphic = pOleObj->GetGraphic();
+    CPPUNIT_ASSERT_MESSAGE("no graphic", pGraphic != nullptr);
+
+    // Check export of embedded worksheet in slide.
+    xDocShRef = saveAndReload(xDocShRef.get(), PPTX);
+
+    pPage = GetPage(1, xDocShRef.get());
+    pOleObj = static_cast<SdrOle2Obj*>(pPage->GetObj(0));
+    CPPUNIT_ASSERT_MESSAGE("no object after the export", pOleObj != nullptr);
+
+    pGraphic = pOleObj->GetGraphic();
+    CPPUNIT_ASSERT_MESSAGE("no graphic after the export", pGraphic != nullptr);
+
+    xDocShRef->DoClose();
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(SdOOXMLExportTest3);
 
 CPPUNIT_PLUGIN_IMPLEMENT();


More information about the Libreoffice-commits mailing list