include/svx/sdr/contact/objectcontact.hxx                |    1 
 include/svx/sdr/contact/objectcontactofpageview.hxx      |    1 
 sd/source/ui/unoidl/unomodel.cxx                         |   68 --------
 svx/inc/sdr/contact/objectcontactofobjlistpainter.hxx    |    1 
 svx/source/sdr/contact/objectcontact.cxx                 |    5 
 svx/source/sdr/contact/objectcontactofobjlistpainter.cxx |   16 +
 svx/source/sdr/contact/objectcontactofpageview.cxx       |   16 +
 svx/source/sdr/contact/viewobjectcontact.cxx             |  123 ++++++++++-----
 sw/source/core/text/EnhancedPDFExportHelper.cxx          |    2 
 9 files changed, 130 insertions(+), 103 deletions(-)

New commits:
commit 87383b341a6bf515a209ad2e7a2a1289059b781e
Author:     Armin Le Grand (allotropia) <armin.le.grand.ext...@allotropia.de>
AuthorDate: Thu Nov 17 18:57:34 2022 +0100
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Tue Nov 22 13:04:00 2022 +0100

    tdf#135638 svx,sd: PDF/UA export: tag SdrObject shapes as Figure etc.
    
    Move the code that already exists in sd class ImplRenderPaintProc
    to ViewObjectContact::getPrimitive2DSequence(), where it is used by all
    applications, and take into account the caching there, which matters for
    performance.
    
    Change-Id: Iabc00b7c894f042673c7217199236a05a5d67959
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/142901
    Tested-by: Jenkins
    Reviewed-by: Armin Le Grand <armin.le.gr...@me.com>
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>

diff --git a/include/svx/sdr/contact/objectcontact.hxx 
b/include/svx/sdr/contact/objectcontact.hxx
index 6d5d63a27b1c..3e9b1b76d05d 100644
--- a/include/svx/sdr/contact/objectcontact.hxx
+++ b/include/svx/sdr/contact/objectcontact.hxx
@@ -137,6 +137,7 @@ public:
 
     // pdf export? Default is false
     virtual bool isOutputToPDFFile() const;
+    virtual bool isExportTaggedPDF() const;
 
     // gray display mode
     virtual bool isDrawModeGray() const;
diff --git a/include/svx/sdr/contact/objectcontactofpageview.hxx 
b/include/svx/sdr/contact/objectcontactofpageview.hxx
index 6ff7761326c1..8d18083b99b8 100644
--- a/include/svx/sdr/contact/objectcontactofpageview.hxx
+++ b/include/svx/sdr/contact/objectcontactofpageview.hxx
@@ -92,6 +92,7 @@ namespace sdr::contact
 
             // pdf export? Default is false
             virtual bool isOutputToPDFFile() const override;
+            virtual bool isExportTaggedPDF() const override;
 
             // gray display mode
             virtual bool isDrawModeGray() const override;
diff --git a/sd/source/ui/unoidl/unomodel.cxx b/sd/source/ui/unoidl/unomodel.cxx
index 36688e31640b..2deb5d296c22 100644
--- a/sd/source/ui/unoidl/unomodel.cxx
+++ b/sd/source/ui/unoidl/unomodel.cxx
@@ -1534,15 +1534,12 @@ class ImplRenderPaintProc : public 
sdr::contact::ViewObjectContactRedirector
 {
     const SdrLayerAdmin&    rLayerAdmin;
     SdrPageView*            pSdrPageView;
-    vcl::PDFExtOutDevData*  pPDFExtOutDevData;
-
-    vcl::PDFWriter::StructElement ImplBegStructureTag( const SdrObject& 
rObject );
 
 public:
     bool IsVisible  ( const SdrObject* pObj ) const;
     bool IsPrintable( const SdrObject* pObj ) const;
 
-    ImplRenderPaintProc( const SdrLayerAdmin& rLA, SdrPageView* pView, 
vcl::PDFExtOutDevData* pData );
+    ImplRenderPaintProc(const SdrLayerAdmin& rLA, SdrPageView* pView);
 
     // all default implementations just call the same methods at the original. 
To do something
     // different, override the method and at least do what the method does.
@@ -1554,10 +1551,9 @@ public:
 
 }
 
-ImplRenderPaintProc::ImplRenderPaintProc( const SdrLayerAdmin& rLA, 
SdrPageView* pView, vcl::PDFExtOutDevData* pData )
-:   rLayerAdmin         ( rLA ),
-    pSdrPageView        ( pView ),
-    pPDFExtOutDevData   ( pData )
+ImplRenderPaintProc::ImplRenderPaintProc(const SdrLayerAdmin& rLA, SdrPageView 
*const pView)
+    : rLayerAdmin(rLA)
+    , pSdrPageView(pView)
 {
 }
 
@@ -1755,32 +1751,6 @@ static void ImplPDFExportShapeInteraction( const 
uno::Reference< drawing::XShape
     }
 }
 
-vcl::PDFWriter::StructElement ImplRenderPaintProc::ImplBegStructureTag( const 
SdrObject& rObject )
-{
-    vcl::PDFWriter::StructElement eElement(vcl::PDFWriter::NonStructElement);
-
-    if ( pPDFExtOutDevData && pPDFExtOutDevData->GetIsExportTaggedPDF() )
-    {
-        SdrInventor nInventor   = rObject.GetObjInventor();
-        SdrObjKind  nIdentifier = rObject.GetObjIdentifier();
-        bool        bIsTextObj  = DynCastSdrTextObj( &rObject ) !=  nullptr;
-
-        if ( nInventor == SdrInventor::Default )
-        {
-            if ( nIdentifier == SdrObjKind::Group )
-                eElement = vcl::PDFWriter::Section;
-            else if ( nIdentifier == SdrObjKind::TitleText )
-                eElement = vcl::PDFWriter::Heading;
-            else if ( nIdentifier == SdrObjKind::OutlineText )
-                eElement = vcl::PDFWriter::Division;
-            else if ( !bIsTextObj || !static_cast<const 
SdrTextObj&>(rObject).HasText() )
-                eElement = vcl::PDFWriter::Figure;
-        }
-    }
-
-    return eElement;
-}
-
 void ImplRenderPaintProc::createRedirectedPrimitive2DSequence(
     const sdr::contact::ViewObjectContact& rOriginal,
     const sdr::contact::DisplayInfo& rDisplayInfo,
@@ -1801,31 +1771,7 @@ void 
ImplRenderPaintProc::createRedirectedPrimitive2DSequence(
     if(!IsVisible(pObject) || !IsPrintable(pObject))
         return;
 
-    const vcl::PDFWriter::StructElement eElement(ImplBegStructureTag( *pObject 
));
-    const bool bTagUsed(vcl::PDFWriter::NonStructElement != eElement);
-
-    drawinglayer::primitive2d::Primitive2DContainer xRetval;
-    
sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence(rOriginal,
 rDisplayInfo, xRetval);
-
-    if(!xRetval.empty() && bTagUsed)
-    {
-        // embed Primitive2DSequence in a structure tag element for
-        // exactly this purpose (StructureTagPrimitive2D)
-
-        const bool bBackground(pSdrPage->IsMasterPage());
-        const bool bImage(pObject->GetObjIdentifier() == SdrObjKind::Graphic);
-
-        drawinglayer::primitive2d::Primitive2DReference xReference(
-            new drawinglayer::primitive2d::StructureTagPrimitive2D(
-                eElement,
-                bBackground,
-                bImage,
-                std::move(xRetval)));
-
-        xRetval = drawinglayer::primitive2d::Primitive2DContainer { xReference 
};
-    }
-
-    rVisitor.visit(xRetval);
+    
sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence(rOriginal,
 rDisplayInfo, rVisitor);
 }
 
 bool ImplRenderPaintProc::IsVisible( const SdrObject* pObj ) const
@@ -1959,7 +1905,7 @@ void SAL_CALL SdXImpressDocument::render( sal_Int32 
nRenderer, const uno::Any& r
         }
 
         ImplRenderPaintProc aImplRenderPaintProc( mpDoc->GetLayerAdmin(),
-            pPV, pPDFExtOutDevData );
+            pPV);
 
         // background color for outliner :o
         SdPage* pPage = pPV ? static_cast<SdPage*>(pPV->GetPage()) : nullptr;
@@ -2192,7 +2138,7 @@ void SAL_CALL SdXImpressDocument::render( sal_Int32 
nRenderer, const uno::Any& r
             SdrPageView* pPV = nullptr;
 
             ImplRenderPaintProc  aImplRenderPaintProc( mpDoc->GetLayerAdmin(),
-                                pOldSdView ? pOldSdView->GetSdrPageView() : 
nullptr, pPDFExtOutDevData );
+                            pOldSdView ? pOldSdView->GetSdrPageView() : 
nullptr);
 
             for( sal_uInt32 i = 0, nCount = xShapes->getCount(); i < nCount; 
i++ )
             {
diff --git a/svx/inc/sdr/contact/objectcontactofobjlistpainter.hxx 
b/svx/inc/sdr/contact/objectcontactofobjlistpainter.hxx
index fcfe510845b7..af72593adef2 100644
--- a/svx/inc/sdr/contact/objectcontactofobjlistpainter.hxx
+++ b/svx/inc/sdr/contact/objectcontactofobjlistpainter.hxx
@@ -77,6 +77,7 @@ public:
 
     // pdf export? Default is false
     virtual bool isOutputToPDFFile() const override;
+    virtual bool isExportTaggedPDF() const override;
 
     virtual OutputDevice* TryToGetOutputDevice() const override;
 };
diff --git a/svx/source/sdr/contact/objectcontact.cxx 
b/svx/source/sdr/contact/objectcontact.cxx
index c76288d6cac6..d135a2a29336 100644
--- a/svx/source/sdr/contact/objectcontact.cxx
+++ b/svx/source/sdr/contact/objectcontact.cxx
@@ -171,6 +171,11 @@ bool ObjectContact::isOutputToPDFFile() const
     return false;
 }
 
+bool ObjectContact::isExportTaggedPDF() const
+{
+    return false;
+}
+
 // gray display mode
 bool ObjectContact::isDrawModeGray() const
 {
diff --git a/svx/source/sdr/contact/objectcontactofobjlistpainter.cxx 
b/svx/source/sdr/contact/objectcontactofobjlistpainter.cxx
index cef1cbc1f289..b4727ce30b12 100644
--- a/svx/source/sdr/contact/objectcontactofobjlistpainter.cxx
+++ b/svx/source/sdr/contact/objectcontactofobjlistpainter.cxx
@@ -29,6 +29,7 @@
 #include <svx/unoapi.hxx>
 #include <tools/debug.hxx>
 #include <vcl/gdimtf.hxx>
+#include <vcl/pdfextoutdevdata.hxx>
 #include <memory>
 
 namespace sdr::contact {
@@ -136,6 +137,21 @@ bool ObjectContactOfObjListPainter::isOutputToPDFFile() 
const
     return OUTDEV_PDF == mrTargetOutputDevice.GetOutDevType();
 }
 
+bool ObjectContactOfObjListPainter::isExportTaggedPDF() const
+{
+    if (isOutputToPDFFile())
+    {
+        vcl::PDFExtOutDevData* 
pPDFExtOutDevData(dynamic_cast<vcl::PDFExtOutDevData*>(
+            mrTargetOutputDevice.GetExtOutDevData()));
+
+        if (nullptr != pPDFExtOutDevData)
+        {
+            return pPDFExtOutDevData->GetIsExportTaggedPDF();
+        }
+    }
+    return false;
+}
+
 OutputDevice* ObjectContactOfObjListPainter::TryToGetOutputDevice() const
 {
     return &mrTargetOutputDevice;
diff --git a/svx/source/sdr/contact/objectcontactofpageview.cxx 
b/svx/source/sdr/contact/objectcontactofpageview.cxx
index 9d0918a5d22a..e4cec99e5e53 100644
--- a/svx/source/sdr/contact/objectcontactofpageview.cxx
+++ b/svx/source/sdr/contact/objectcontactofpageview.cxx
@@ -37,6 +37,7 @@
 #include <svx/unoapi.hxx>
 #include <unotools/configmgr.hxx>
 #include <vcl/canvastools.hxx>
+#include <vcl/pdfextoutdevdata.hxx>
 #include <comphelper/lok.hxx>
 
 #include <memory>
@@ -372,6 +373,21 @@ namespace sdr::contact
             return OUTDEV_PDF == 
mrPageWindow.GetPaintWindow().GetOutputDevice().GetOutDevType();
         }
 
+        bool ObjectContactOfPageView::isExportTaggedPDF() const
+        {
+            if (isOutputToPDFFile())
+            {
+                vcl::PDFExtOutDevData* 
pPDFExtOutDevData(dynamic_cast<vcl::PDFExtOutDevData*>(
+                    
mrPageWindow.GetPaintWindow().GetOutputDevice().GetExtOutDevData()));
+
+                if (nullptr != pPDFExtOutDevData)
+                {
+                    return pPDFExtOutDevData->GetIsExportTaggedPDF();
+                }
+            }
+            return false;
+        }
+
         // gray display mode
         bool ObjectContactOfPageView::isDrawModeGray() const
         {
diff --git a/svx/source/sdr/contact/viewobjectcontact.cxx 
b/svx/source/sdr/contact/viewobjectcontact.cxx
index 9adc4e713b22..15dea8262a5b 100644
--- a/svx/source/sdr/contact/viewobjectcontact.cxx
+++ b/svx/source/sdr/contact/viewobjectcontact.cxx
@@ -29,8 +29,12 @@
 #include <drawinglayer/processor2d/baseprocessor2d.hxx>
 #include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
 #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#include <drawinglayer/primitive2d/structuretagprimitive2d.hxx>
 #include <svx/svdobj.hxx>
 #include <svx/svdmodel.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdotext.hxx>
+#include <vcl/pdfwriter.hxx>
 
 using namespace com::sun::star;
 
@@ -338,19 +342,15 @@ void ViewObjectContact::createPrimitive2DSequence(const 
DisplayInfo& rDisplayInf
 drawinglayer::primitive2d::Primitive2DContainer const & 
ViewObjectContact::getPrimitive2DSequence(const DisplayInfo& rDisplayInfo) const
 {
     // only some of the top-level apps are any good at reliably invalidating 
us (e.g. writer is not)
-    if (SdrObject* pSdrObj = mrViewContact.TryToGetSdrObject())
-        if (pSdrObj->getSdrModelFromSdrObject().IsVOCInvalidationIsReliable())
-        {
-            if (!mxPrimitive2DSequence.empty())
-                return mxPrimitive2DSequence;
-        }
+    SdrObject* pSdrObj(mrViewContact.TryToGetSdrObject());
 
-    /**
-    This method is weird because
-    (1) we have to re-walk the primitive tree because the flushing is 
unreliable
-    (2) we cannot just always use the new data because the old data has cached 
bitmaps in it e.g. see the documents in tdf#104878
-    */
+    if (nullptr != pSdrObj && 
pSdrObj->getSdrModelFromSdrObject().IsVOCInvalidationIsReliable())
+    {
+        if (!mxPrimitive2DSequence.empty())
+            return mxPrimitive2DSequence;
+    }
 
+    // prepare new representation
     drawinglayer::primitive2d::Primitive2DContainer xNewPrimitiveSequence;
 
     // take care of redirectors and create new list
@@ -365,22 +365,8 @@ drawinglayer::primitive2d::Primitive2DContainer const & 
ViewObjectContact::getPr
         createPrimitive2DSequence(rDisplayInfo, xNewPrimitiveSequence);
     }
 
-    // local up-to-date checks. New list different from local one?
-    if(mxPrimitive2DSequence == xNewPrimitiveSequence)
-        return mxPrimitive2DSequence;
-
-    // has changed, copy content
-    const_cast< ViewObjectContact* >(this)->mxPrimitive2DSequence = 
std::move(xNewPrimitiveSequence);
-
-    // check for animated stuff
-    const_cast< ViewObjectContact* >(this)->checkForPrimitive2DAnimations();
-
-    // always update object range when PrimitiveSequence changes
-    const drawinglayer::geometry::ViewInformation2D& 
rViewInformation2D(GetObjectContact().getViewInformation2D());
-    const_cast< ViewObjectContact* >(this)->maObjectRange = 
mxPrimitive2DSequence.getB2DRange(rViewInformation2D);
-
-    // check and eventually embed to GridOffset transform primitive
-    if(GetObjectContact().supportsGridOffsets())
+    // check and eventually embed to GridOffset transform primitive (calc only)
+    if(!xNewPrimitiveSequence.empty() && 
GetObjectContact().supportsGridOffsets())
     {
         const basegfx::B2DVector& rGridOffset(getGridOffset());
 
@@ -390,22 +376,77 @@ drawinglayer::primitive2d::Primitive2DContainer const & 
ViewObjectContact::getPr
                 basegfx::utils::createTranslateB2DHomMatrix(
                     rGridOffset));
             drawinglayer::primitive2d::Primitive2DReference aEmbed(
-                 new drawinglayer::primitive2d::TransformPrimitive2D(
+                new drawinglayer::primitive2d::TransformPrimitive2D(
                     aTranslateGridOffset,
-                    std::move(const_cast< ViewObjectContact* 
>(this)->mxPrimitive2DSequence)));
-
-            // Set values at local data. So for now, the mechanism is to reset 
some of the
-            // defining things (mxPrimitive2DSequence, maGridOffset) and 
re-create the
-            // buffered data (including maObjectRange). It *could* be changed 
to keep
-            // the unmodified PrimitiveSequence and only update the 
GridOffset, but this
-            // would require a 2nd instance of maObjectRange and 
mxPrimitive2DSequence. I
-            // started doing so, but it just makes the code more complicated. 
For now,
-            // just allow re-creation of the PrimitiveSequence (and removing 
buffered
-            // decomposed content of it). May be optimized, though. OTOH it 
only happens
-            // in calc which traditionally does not have a huge amount of 
DrawObjects anyways.
-            const_cast< ViewObjectContact* >(this)->mxPrimitive2DSequence = 
drawinglayer::primitive2d::Primitive2DContainer { aEmbed };
-            const_cast< ViewObjectContact* 
>(this)->maObjectRange.transform(aTranslateGridOffset);
+                    std::move(xNewPrimitiveSequence)));
+            xNewPrimitiveSequence = 
drawinglayer::primitive2d::Primitive2DContainer { aEmbed };
+        }
+    }
+
+    // Check if we need to embed to a StructureTagPrimitive2D, too. This
+    // was done at ImplRenderPaintProc::createRedirectedPrimitive2DSequence 
before
+    if(!xNewPrimitiveSequence.empty() && nullptr != pSdrObj && 
GetObjectContact().isExportTaggedPDF())
+    {
+        vcl::PDFWriter::StructElement 
eElement(vcl::PDFWriter::NonStructElement);
+        const SdrInventor nInventor(pSdrObj->GetObjInventor());
+        const SdrObjKind nIdentifier(pSdrObj->GetObjIdentifier());
+        const bool bIsTextObj(nullptr != DynCastSdrTextObj(pSdrObj));
+
+        if ( nInventor == SdrInventor::Default )
+        {
+            if ( nIdentifier == SdrObjKind::Group )
+                eElement = vcl::PDFWriter::Section;
+            else if ( nIdentifier == SdrObjKind::TitleText )
+                eElement = vcl::PDFWriter::Heading;
+            else if ( nIdentifier == SdrObjKind::OutlineText )
+                eElement = vcl::PDFWriter::Division;
+            else if ( !bIsTextObj || !static_cast<const 
SdrTextObj&>(*pSdrObj).HasText() )
+                eElement = vcl::PDFWriter::Figure;
         }
+
+        if(vcl::PDFWriter::NonStructElement != eElement)
+        {
+            SdrPage* pSdrPage(pSdrObj->getSdrPageFromSdrObject());
+
+            if(pSdrPage)
+            {
+                const bool bBackground(pSdrPage->IsMasterPage());
+                const bool bImage(SdrObjKind::Graphic == 
pSdrObj->GetObjIdentifier());
+
+                drawinglayer::primitive2d::Primitive2DReference xReference(
+                    new drawinglayer::primitive2d::StructureTagPrimitive2D(
+                        eElement,
+                        bBackground,
+                        bImage,
+                        std::move(xNewPrimitiveSequence)));
+                xNewPrimitiveSequence = 
drawinglayer::primitive2d::Primitive2DContainer { xReference };
+            }
+        }
+    }
+
+    // Local up-to-date checks. New list different from local one?
+    // This is the important point where it gets decided if the current or the 
new
+    // representation gets used. This is important for performance, since the
+    // current representation contains possible precious decompositions. That
+    // comparisons triggers exactly if something in the object visualization
+    // has changed.
+    // Note: That is the main reason for BasePrimitive2D::operator== at all. I
+    // have alternatively tried to invalidate the local representation on 
object
+    // change, but that is simply not reliable.
+    // Note2: I did that once in aw080, the lost CWS, and it worked well enough
+    // so that I could remove *all* operator== from all derivations of
+    // BasePrimitive2D, so it can be done again (with the needed ressources)
+    if(mxPrimitive2DSequence != xNewPrimitiveSequence)
+    {
+        // has changed, copy content
+        const_cast< ViewObjectContact* >(this)->mxPrimitive2DSequence = 
std::move(xNewPrimitiveSequence);
+
+        // check for animated stuff
+        const_cast< ViewObjectContact* 
>(this)->checkForPrimitive2DAnimations();
+
+        // always update object range when PrimitiveSequence changes
+        const drawinglayer::geometry::ViewInformation2D& 
rViewInformation2D(GetObjectContact().getViewInformation2D());
+        const_cast< ViewObjectContact* >(this)->maObjectRange = 
mxPrimitive2DSequence.getB2DRange(rViewInformation2D);
     }
 
     // return current Primitive2DContainer
diff --git a/sw/source/core/text/EnhancedPDFExportHelper.cxx 
b/sw/source/core/text/EnhancedPDFExportHelper.cxx
index 0f5f13c05966..8ed9392bdb48 100644
--- a/sw/source/core/text/EnhancedPDFExportHelper.cxx
+++ b/sw/source/core/text/EnhancedPDFExportHelper.cxx
@@ -661,7 +661,7 @@ void SwTaggedPDFHelper::SetAttributes( 
vcl::PDFWriter::StructElement eType )
             }
         }
 
-        // Formally here bAlternateText was triggered for PDF export, but this
+        // Formerly here bAlternateText was triggered for PDF export, but this
         // was moved for more general use to primitives and usage in
         // VclMetafileProcessor2D (see processGraphicPrimitive2D).
 

Reply via email to