sdext/source/pdfimport/inc/genericelements.hxx     |   14 +++++++
 sdext/source/pdfimport/inc/treevisiting.hxx        |    2 +
 sdext/source/pdfimport/tree/drawtreevisiting.cxx   |   37 +++++++++++++++++++++
 sdext/source/pdfimport/tree/drawtreevisiting.hxx   |    3 +
 sdext/source/pdfimport/tree/genericelements.cxx    |    6 +++
 sdext/source/pdfimport/tree/pdfiprocessor.cxx      |   17 +++++++++
 sdext/source/pdfimport/tree/writertreevisiting.cxx |   36 ++++++++++++++++++++
 sdext/source/pdfimport/tree/writertreevisiting.hxx |    3 +
 8 files changed, 117 insertions(+), 1 deletion(-)

New commits:
commit 2383fae366c787bc6e08cf5439521674d52fd8c1
Author:     Dr. David Alan Gilbert <[email protected]>
AuthorDate: Sun Jul 27 21:41:14 2025 +0100
Commit:     David Gilbert <[email protected]>
CommitDate: Sat Aug 9 15:54:58 2025 +0200

    tdf#44729 sdext,pdfimport: Hide transparency groups 'for soft mask'
    
    In PDF, 'Transparency groups' are used to group objects for compositing.
    One variant of those is a transparency group that doesn't actually
    get directly composited, but is used as a 'soft mask' to modulate
    the effects of another group when the other group is composited.
    
    So far we've not done anything for transparency groups, where
    softmasks are used that means the softmask gets rendered as a visible
    object - often a big semi-transparent polygon covering the rest.
    
    Add 'group' elements into the tree for Transparency Groups and mark
    them.
    During tree walks skip the 'for soft mask' transparency groups.
    
    This improves tdf#44729 which prior to this patch is mostly
    seen as a big black page because it's covered with the soft mask
    misrendering.
    
    Since it also stored the transparency group it also means we can
    attack the real rendering of those later.
    
    Change-Id: Ieb1eb56b15d8def5c842c1d84349173ccca630dd
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/188455
    Reviewed-by: David Gilbert <[email protected]>
    Tested-by: Jenkins

diff --git a/sdext/source/pdfimport/inc/genericelements.hxx 
b/sdext/source/pdfimport/inc/genericelements.hxx
index d861617fc6a4..2f624c388562 100644
--- a/sdext/source/pdfimport/inc/genericelements.hxx
+++ b/sdext/source/pdfimport/inc/genericelements.hxx
@@ -178,6 +178,8 @@ namespace pdfi
 
     public:
         virtual void visitedBy( ElementTreeVisitor&, const std::list< 
std::unique_ptr<Element> >::const_iterator& ) override;
+        bool isTransparencyGroup;
+        bool isForSoftMask;
     };
 
     struct TextElement final : public GraphicalElement
diff --git a/sdext/source/pdfimport/tree/drawtreevisiting.cxx 
b/sdext/source/pdfimport/tree/drawtreevisiting.cxx
index f9cf67bf179c..0abf16067849 100644
--- a/sdext/source/pdfimport/tree/drawtreevisiting.cxx
+++ b/sdext/source/pdfimport/tree/drawtreevisiting.cxx
@@ -279,6 +279,14 @@ void DrawXmlEmitter::visit( FrameElement& elem, const 
std::list< std::unique_ptr
 
 void DrawXmlEmitter::visit(GroupElement& elem, const std::list< 
std::unique_ptr<Element> >::const_iterator&)
 {
+    if (elem.isTransparencyGroup && elem.isForSoftMask)
+    {
+        // Hack: We don't have a way to do TG or SoftMask yet, but avoiding
+        // rendering the geometry that's only used for generating the soft
+        // mask generally gives us better results
+        return;
+    }
+
     elem.applyToChildren(*this);
 }
 
@@ -411,6 +419,13 @@ void DrawXmlOptimizer::visit( FrameElement& elem, const 
std::list< std::unique_p
 
 void DrawXmlOptimizer::visit(GroupElement& elem, const std::list< 
std::unique_ptr<Element> >::const_iterator&)
 {
+    if (elem.isTransparencyGroup && elem.isForSoftMask)
+    {
+        // Hack: We don't have a way to do TG or SoftMask yet, but avoiding
+        // rendering the geometry that's only used for generating the soft
+        // mask generally gives us better results
+        return;
+    }
     elem.applyToChildren(*this);
 }
 
@@ -1018,6 +1033,13 @@ void DrawXmlFinalizer::visit( FrameElement& elem, const 
std::list< std::unique_p
 
 void DrawXmlFinalizer::visit(GroupElement& elem, const std::list< 
std::unique_ptr<Element> >::const_iterator&)
 {
+    if (elem.isTransparencyGroup && elem.isForSoftMask)
+    {
+        // Hack: We don't have a way to do TG or SoftMask yet, but avoiding
+        // rendering the geometry that's only used for generating the soft
+        // mask generally gives us better results
+        return;
+    }
     elem.applyToChildren(*this);
 }
 
diff --git a/sdext/source/pdfimport/tree/pdfiprocessor.cxx 
b/sdext/source/pdfimport/tree/pdfiprocessor.cxx
index a28b51c37564..3e5bd4215f86 100644
--- a/sdext/source/pdfimport/tree/pdfiprocessor.cxx
+++ b/sdext/source/pdfimport/tree/pdfiprocessor.cxx
@@ -585,12 +585,27 @@ void PDFIProcessor::intersectClipToStroke(const 
uno::Reference< rendering::XPoly
     getCurrentContext().Clip = std::move(aNewClip);
 }
 
-void PDFIProcessor::beginTransparencyGroup(const bool /*bForSoftMask*/)
+void PDFIProcessor::beginTransparencyGroup(const bool bForSoftMask)
 {
+    const GraphicsContext& rGC(getCurrentContext());
+    const sal_Int32 nGCId = getGCId(rGC);
+    GroupElement* pGroup = ElementFactory::createGroupElement( m_pCurElement, 
nGCId );
+    pGroup->ZOrder = m_nNextZOrder++;
+    pGroup->isTransparencyGroup = true;
+    pGroup->isForSoftMask = bForSoftMask;
+    pGroup->w = 0;
+    pGroup->h = 0;
+    m_pCurElement = pGroup;
+
 }
 
 void PDFIProcessor::endTransparencyGroup()
 {
+    GroupElement* pGroup = dynamic_cast<GroupElement*>(m_pCurElement);
+    if( pGroup )
+    {
+        m_pCurElement = pGroup->Parent;
+    }
 }
 
 void PDFIProcessor::hyperLink( const geometry::RealRectangle2D& rBounds,
diff --git a/sdext/source/pdfimport/tree/writertreevisiting.cxx 
b/sdext/source/pdfimport/tree/writertreevisiting.cxx
index cdd9b0cac27e..e267a562c83d 100644
--- a/sdext/source/pdfimport/tree/writertreevisiting.cxx
+++ b/sdext/source/pdfimport/tree/writertreevisiting.cxx
@@ -304,6 +304,13 @@ void WriterXmlEmitter::visit( FrameElement& elem, const 
std::list< std::unique_p
 
 void WriterXmlEmitter::visit(GroupElement& elem, const std::list< 
std::unique_ptr<Element> >::const_iterator&)
 {
+    if (elem.isTransparencyGroup && elem.isForSoftMask)
+    {
+        // Hack: We don't have a way to do TG or SoftMask yet, but avoiding
+        // rendering the geometry that's only used for generating the soft
+        // mask generally gives us better results
+        return;
+    }
     elem.applyToChildren(*this);
 }
 
@@ -442,6 +449,13 @@ void WriterXmlOptimizer::visit( FrameElement& elem, const 
std::list< std::unique
 
 void WriterXmlOptimizer::visit(GroupElement& elem, const std::list< 
std::unique_ptr<Element> >::const_iterator&)
 {
+    if (elem.isTransparencyGroup && elem.isForSoftMask)
+    {
+        // Hack: We don't have a way to do TG or SoftMask yet, but avoiding
+        // rendering the geometry that's only used for generating the soft
+        // mask generally gives us better results
+        return;
+    }
     elem.applyToChildren(*this);
 }
 
@@ -1201,6 +1215,13 @@ void WriterXmlFinalizer::visit( FrameElement& elem, 
const std::list< std::unique
 
 void WriterXmlFinalizer::visit(GroupElement& elem, const std::list< 
std::unique_ptr<Element> >::const_iterator&)
 {
+    if (elem.isTransparencyGroup && elem.isForSoftMask)
+    {
+        // Hack: We don't have a way to do TG or SoftMask yet, but avoiding
+        // rendering the geometry that's only used for generating the soft
+        // mask generally gives us better results
+        return;
+    }
     elem.applyToChildren(*this);
 }
 
commit e7503531396fd7d47eae4887422a61bb4da5d58e
Author:     Dr. David Alan Gilbert <[email protected]>
AuthorDate: Sun Jul 27 21:36:25 2025 +0100
Commit:     David Gilbert <[email protected]>
CommitDate: Sat Aug 9 15:54:49 2025 +0200

    tdf#44729 sdext,pdfimport: Add Group elements
    
    Add a new tree element 'group' which represents a collection of other
    elements but doesn't necessarily give a specific output node.
    Later patches will add some flags and use those to change the output.
    
    Change-Id: I981d345873436f6f9ffc9de67123f38de1e3d86a
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/188454
    Tested-by: Jenkins
    Reviewed-by: David Gilbert <[email protected]>

diff --git a/sdext/source/pdfimport/inc/genericelements.hxx 
b/sdext/source/pdfimport/inc/genericelements.hxx
index 13350df21796..d861617fc6a4 100644
--- a/sdext/source/pdfimport/inc/genericelements.hxx
+++ b/sdext/source/pdfimport/inc/genericelements.hxx
@@ -170,6 +170,16 @@ namespace pdfi
         virtual void visitedBy( ElementTreeVisitor&, const std::list< 
std::unique_ptr<Element> >::const_iterator& ) override;
     };
 
+    struct GroupElement final : public DrawElement
+    {
+        friend class ElementFactory;
+        GroupElement( Element* pParent, sal_Int32 nGCId )
+        : DrawElement( pParent, nGCId ) {}
+
+    public:
+        virtual void visitedBy( ElementTreeVisitor&, const std::list< 
std::unique_ptr<Element> >::const_iterator& ) override;
+    };
+
     struct TextElement final : public GraphicalElement
     {
         friend class ElementFactory;
@@ -298,6 +308,8 @@ namespace pdfi
 
         static FrameElement* createFrameElement( Element* pParent, sal_Int32 
nGCId )
         { return new FrameElement( pParent, nGCId ); }
+        static GroupElement* createGroupElement( Element* pParent, sal_Int32 
nGCId )
+        { return new GroupElement( pParent, nGCId ); }
         static PolyPolyElement*
             createPolyPolyElement( Element* pParent,
                                    sal_Int32 nGCId,
diff --git a/sdext/source/pdfimport/inc/treevisiting.hxx 
b/sdext/source/pdfimport/inc/treevisiting.hxx
index 120166594af3..45407dfea789 100644
--- a/sdext/source/pdfimport/inc/treevisiting.hxx
+++ b/sdext/source/pdfimport/inc/treevisiting.hxx
@@ -30,6 +30,7 @@ namespace pdfi
     struct TextElement;
     struct ParagraphElement;
     struct FrameElement;
+    struct GroupElement;
     struct PolyPolyElement;
     struct ImageElement;
     struct PageElement;
@@ -47,6 +48,7 @@ namespace pdfi
         virtual void visit( TextElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) = 0;
         virtual void visit( ParagraphElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) = 0;
         virtual void visit( FrameElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) = 0;
+        virtual void visit( GroupElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) = 0;
         virtual void visit( PolyPolyElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) = 0;
         virtual void visit( ImageElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) = 0;
         virtual void visit( PageElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) = 0;
diff --git a/sdext/source/pdfimport/tree/drawtreevisiting.cxx 
b/sdext/source/pdfimport/tree/drawtreevisiting.cxx
index d99d32bbfa50..f9cf67bf179c 100644
--- a/sdext/source/pdfimport/tree/drawtreevisiting.cxx
+++ b/sdext/source/pdfimport/tree/drawtreevisiting.cxx
@@ -277,6 +277,11 @@ void DrawXmlEmitter::visit( FrameElement& elem, const 
std::list< std::unique_ptr
     m_rEmitContext.rEmitter.endTag( "draw:frame" );
 }
 
+void DrawXmlEmitter::visit(GroupElement& elem, const std::list< 
std::unique_ptr<Element> >::const_iterator&)
+{
+    elem.applyToChildren(*this);
+}
+
 void DrawXmlEmitter::visit( PolyPolyElement& elem, const std::list< 
std::unique_ptr<Element> >::const_iterator& )
 {
     elem.updateGeometry();
@@ -404,6 +409,11 @@ void DrawXmlOptimizer::visit( FrameElement& elem, const 
std::list< std::unique_p
     elem.applyToChildren(*this);
 }
 
+void DrawXmlOptimizer::visit(GroupElement& elem, const std::list< 
std::unique_ptr<Element> >::const_iterator&)
+{
+    elem.applyToChildren(*this);
+}
+
 void DrawXmlOptimizer::visit( ImageElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator& )
 {
 }
@@ -1006,6 +1016,11 @@ void DrawXmlFinalizer::visit( FrameElement& elem, const 
std::list< std::unique_p
     elem.applyToChildren(*this);
 }
 
+void DrawXmlFinalizer::visit(GroupElement& elem, const std::list< 
std::unique_ptr<Element> >::const_iterator&)
+{
+    elem.applyToChildren(*this);
+}
+
 void DrawXmlFinalizer::visit( ImageElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator& )
 {
 }
diff --git a/sdext/source/pdfimport/tree/drawtreevisiting.hxx 
b/sdext/source/pdfimport/tree/drawtreevisiting.hxx
index e3ea8e537ff5..9230d8cfedc5 100644
--- a/sdext/source/pdfimport/tree/drawtreevisiting.hxx
+++ b/sdext/source/pdfimport/tree/drawtreevisiting.hxx
@@ -47,6 +47,7 @@ namespace pdfi
         virtual void visit( TextElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) override;
         virtual void visit( ParagraphElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) override;
         virtual void visit( FrameElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) override;
+        virtual void visit( GroupElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) override;
         virtual void visit( PolyPolyElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) override;
         virtual void visit( ImageElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) override;
         virtual void visit( PageElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) override;
@@ -70,6 +71,7 @@ namespace pdfi
         virtual void visit( TextElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) override;
         virtual void visit( ParagraphElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) override;
         virtual void visit( FrameElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) override;
+        virtual void visit( GroupElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) override;
         virtual void visit( PolyPolyElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) override;
         virtual void visit( ImageElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) override;
         virtual void visit( PageElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) override;
@@ -103,6 +105,7 @@ namespace pdfi
         virtual void visit( TextElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) override;
         virtual void visit( ParagraphElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) override;
         virtual void visit( FrameElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) override;
+        virtual void visit( GroupElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) override;
         virtual void visit( PolyPolyElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) override;
         virtual void visit( ImageElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) override;
         virtual void visit( PageElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) override;
diff --git a/sdext/source/pdfimport/tree/genericelements.cxx 
b/sdext/source/pdfimport/tree/genericelements.cxx
index 4f9d52706884..fa6d951e5da2 100644
--- a/sdext/source/pdfimport/tree/genericelements.cxx
+++ b/sdext/source/pdfimport/tree/genericelements.cxx
@@ -115,6 +115,12 @@ void FrameElement::visitedBy( ElementTreeVisitor&          
                rVisi
     rVisitor.visit(*this,rParentIt);
 }
 
+void GroupElement::visitedBy( ElementTreeVisitor&                          
rVisitor,
+                              const std::list< std::unique_ptr<Element> 
>::const_iterator& rParentIt )
+{
+    rVisitor.visit(*this,rParentIt);
+}
+
 void ImageElement::visitedBy( ElementTreeVisitor&                          
rVisitor,
                               const std::list< std::unique_ptr<Element> 
>::const_iterator& rParentIt)
 {
diff --git a/sdext/source/pdfimport/tree/writertreevisiting.cxx 
b/sdext/source/pdfimport/tree/writertreevisiting.cxx
index 1c5e4c903dce..cdd9b0cac27e 100644
--- a/sdext/source/pdfimport/tree/writertreevisiting.cxx
+++ b/sdext/source/pdfimport/tree/writertreevisiting.cxx
@@ -302,6 +302,11 @@ void WriterXmlEmitter::visit( FrameElement& elem, const 
std::list< std::unique_p
     m_rEmitContext.rEmitter.endTag( "draw:frame" );
 }
 
+void WriterXmlEmitter::visit(GroupElement& elem, const std::list< 
std::unique_ptr<Element> >::const_iterator&)
+{
+    elem.applyToChildren(*this);
+}
+
 void WriterXmlEmitter::visit( PolyPolyElement& elem, const std::list< 
std::unique_ptr<Element> >::const_iterator& )
 {
     elem.updateGeometry();
@@ -435,6 +440,11 @@ void WriterXmlOptimizer::visit( FrameElement& elem, const 
std::list< std::unique
     elem.applyToChildren(*this);
 }
 
+void WriterXmlOptimizer::visit(GroupElement& elem, const std::list< 
std::unique_ptr<Element> >::const_iterator&)
+{
+    elem.applyToChildren(*this);
+}
+
 void WriterXmlOptimizer::visit( ImageElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator& )
 {
 }
@@ -1189,6 +1199,11 @@ void WriterXmlFinalizer::visit( FrameElement& elem, 
const std::list< std::unique
     elem.applyToChildren(*this);
 }
 
+void WriterXmlFinalizer::visit(GroupElement& elem, const std::list< 
std::unique_ptr<Element> >::const_iterator&)
+{
+    elem.applyToChildren(*this);
+}
+
 void WriterXmlFinalizer::visit( ImageElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator& )
 {
 }
diff --git a/sdext/source/pdfimport/tree/writertreevisiting.hxx 
b/sdext/source/pdfimport/tree/writertreevisiting.hxx
index b0644dd48154..e24d4f329007 100644
--- a/sdext/source/pdfimport/tree/writertreevisiting.hxx
+++ b/sdext/source/pdfimport/tree/writertreevisiting.hxx
@@ -49,6 +49,7 @@ namespace pdfi
         virtual void visit( TextElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) override;
         virtual void visit( ParagraphElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) override;
         virtual void visit( FrameElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) override;
+        virtual void visit( GroupElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) override;
         virtual void visit( PolyPolyElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) override;
         virtual void visit( ImageElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) override;
         virtual void visit( PageElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) override;
@@ -76,6 +77,7 @@ namespace pdfi
         virtual void visit( TextElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) override;
         virtual void visit( ParagraphElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) override;
         virtual void visit( FrameElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) override;
+        virtual void visit( GroupElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) override;
         virtual void visit( PolyPolyElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) override;
         virtual void visit( ImageElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) override;
         virtual void visit( PageElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) override;
@@ -101,6 +103,7 @@ namespace pdfi
         virtual void visit( TextElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) override;
         virtual void visit( ParagraphElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) override;
         virtual void visit( FrameElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) override;
+        virtual void visit( GroupElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) override;
         virtual void visit( PolyPolyElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) override;
         virtual void visit( ImageElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) override;
         virtual void visit( PageElement&, const std::list< 
std::unique_ptr<Element> >::const_iterator&  ) override;

Reply via email to