summaryrefslogtreecommitdiff
path: root/svx
diff options
context:
space:
mode:
authorArmin Le Grand (allotropia) <armin.le.grand.extern@allotropia.de>2022-11-17 18:57:34 +0100
committerMichael Stahl <michael.stahl@allotropia.de>2022-11-22 13:04:00 +0100
commit87383b341a6bf515a209ad2e7a2a1289059b781e (patch)
tree8557d8a3b8c22272df2a46f4ab57752c80e583ed /svx
parent81791adc414adcaa9f43b5f449ad0f6752e01df7 (diff)
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.Grand@me.com> Reviewed-by: Michael Stahl <michael.stahl@allotropia.de>
Diffstat (limited to 'svx')
-rw-r--r--svx/inc/sdr/contact/objectcontactofobjlistpainter.hxx1
-rw-r--r--svx/source/sdr/contact/objectcontact.cxx5
-rw-r--r--svx/source/sdr/contact/objectcontactofobjlistpainter.cxx16
-rw-r--r--svx/source/sdr/contact/objectcontactofpageview.cxx16
-rw-r--r--svx/source/sdr/contact/viewobjectcontact.cxx123
5 files changed, 120 insertions, 41 deletions
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