drawinglayer/source/primitive2d/shadowprimitive2d.cxx | 71 +++------------ drawinglayer/source/processor2d/vclpixelprocessor2d.cxx | 12 -- drawinglayer/source/tools/primitive2dxmldump.cxx | 4 include/drawinglayer/primitive2d/baseprimitive2d.hxx | 12 +- include/drawinglayer/primitive2d/shadowprimitive2d.hxx | 8 - svx/qa/unit/table.cxx | 12 +- svx/source/sdr/primitive2d/sdrdecompositiontools.cxx | 72 ++++++++++++---- svx/source/table/viewcontactoftableobj.cxx | 15 ++- vcl/source/bitmap/bitmapfilter.cxx | 5 + 9 files changed, 106 insertions(+), 105 deletions(-)
New commits: commit 839dd79505f5e02248835a89d053337f7a04b529 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Thu Sep 23 16:55:19 2021 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Wed Sep 29 13:15:33 2021 +0200 Related: tdf#144091 svx: fix interaction of transp cell fill and transp shadow This is a follow-up to commit 37a52d30bbfcf1d073779b50139c4dafa507be4b (tdf#144091 svx: fix unwanted blur of shadow from table cell fill, 2021-09-20), where it turned out that the original bugdoc was just a special case of almost full transparency (80%), that's why avoiding the blur fixed the problem. A more general approach instead is to multiply the alpha or the cell fill of table shapes and the alpha of the shadow itself. The end result is the same (80% transparency) for the first bugdoc, but this gives back the blur on the second bugdoc. (cherry picked from commit 00fa364a2403dc23a786d3f91fde06e10b3a4a9a) Conflicts: drawinglayer/source/primitive2d/shadowprimitive2d.cxx drawinglayer/source/processor2d/vclpixelprocessor2d.cxx include/drawinglayer/primitive2d/BufferedDecompositionPrimitive2D.hxx svx/source/sdr/primitive2d/sdrdecompositiontools.cxx svx/source/table/viewcontactoftableobj.cxx Change-Id: I63560e3a73473c70157ecee8365ec7154217f269 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/122680 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/122802 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Miklos Vajna <vmik...@collabora.com> diff --git a/drawinglayer/source/primitive2d/shadowprimitive2d.cxx b/drawinglayer/source/primitive2d/shadowprimitive2d.cxx index 516cc0c0bd4a..f0efd64c7bdc 100644 --- a/drawinglayer/source/primitive2d/shadowprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/shadowprimitive2d.cxx @@ -30,27 +30,6 @@ using namespace com::sun::star; namespace drawinglayer::primitive2d { -namespace -{ -void get2DDecompositionOfChildren(const ShadowPrimitive2D& rPrimitive, - Primitive2DDecompositionVisitor& rVisitor, - const Primitive2DContainer& rChildren) -{ - if (rChildren.empty()) - return; - - // create a modifiedColorPrimitive containing the shadow color and the content - const basegfx::BColorModifierSharedPtr aBColorModifier - = std::make_shared<basegfx::BColorModifier_replace>(rPrimitive.getShadowColor()); - const Primitive2DReference xRefA(new ModifiedColorPrimitive2D(rChildren, aBColorModifier)); - Primitive2DContainer aSequenceB{ xRefA }; - - // build transformed primitiveVector with shadow offset and add to target - rVisitor.append( - new TransformPrimitive2D(rPrimitive.getShadowTransform(), std::move(aSequenceB))); -} -} - ShadowPrimitive2D::ShadowPrimitive2D( const basegfx::B2DHomMatrix& rShadowTransform, const basegfx::BColor& rShadowColor, @@ -87,41 +66,21 @@ void get2DDecompositionOfChildren(const ShadowPrimitive2D& rPrimitive, void ShadowPrimitive2D::get2DDecomposition(Primitive2DDecompositionVisitor& rVisitor, const geometry::ViewInformation2D& /*rViewInformation*/) const { - get2DDecompositionOfChildren(*this, rVisitor, getChildren()); - } - - void ShadowPrimitive2D::get2DDecompositionWithoutBlur( - Primitive2DDecompositionVisitor& rVisitor, - const geometry::ViewInformation2D& /*rViewInformation*/) const - { - Primitive2DContainer aChildren; - // Only decompose children which are not blurred (they opted in for this). - std::copy_if(getChildren().begin(), getChildren().end(), std::back_inserter(aChildren), - [](const Primitive2DReference& xChild) { - auto pChild - = dynamic_cast<primitive2d::BufferedDecompositionPrimitive2D*>( - xChild.get()); - return pChild && pChild->getExcludeFromBlur(); - }); - - get2DDecompositionOfChildren(*this, rVisitor, aChildren); - } - - void ShadowPrimitive2D::get2DDecompositionWithBlur( - Primitive2DDecompositionVisitor& rVisitor, - const geometry::ViewInformation2D& /*rViewInformation*/) const - { - // Only decompose children which are blurred (which is the default). - Primitive2DContainer aChildren; - std::copy_if(getChildren().begin(), getChildren().end(), std::back_inserter(aChildren), - [](const Primitive2DReference& xChild) { - auto pChild - = dynamic_cast<primitive2d::BufferedDecompositionPrimitive2D*>( - xChild.get()); - return !pChild || !pChild->getExcludeFromBlur(); - }); - - get2DDecompositionOfChildren(*this, rVisitor, aChildren); + if(getChildren().empty()) + return; + + // create a modifiedColorPrimitive containing the shadow color and the content + const basegfx::BColorModifierSharedPtr aBColorModifier = + std::make_shared<basegfx::BColorModifier_replace>( + getShadowColor()); + const Primitive2DReference xRefA( + new ModifiedColorPrimitive2D( + getChildren(), + aBColorModifier)); + const Primitive2DContainer aSequenceB { xRefA }; + + // build transformed primitiveVector with shadow offset and add to target + rVisitor.append(new TransformPrimitive2D(getShadowTransform(), aSequenceB)); } // provide unique ID diff --git a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx index 393c40c90842..10845409b9ec 100644 --- a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx +++ b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx @@ -1037,7 +1037,7 @@ void VclPixelProcessor2D::processGlowPrimitive2D(const primitive2d::GlowPrimitiv const sal_uInt8 nTransparency = rCandidate.getGlowColor().GetTransparency(); impBufferDevice aBufferDevice(*mpOutputDevice, aRange); - if (aBufferDevice.isVisible()) + if (aBufferDevice.isVisible() && !aRange.isEmpty()) { // remember last OutDev and set to content OutputDevice* pLastOutputDevice = mpOutputDevice; @@ -1160,18 +1160,10 @@ void VclPixelProcessor2D::processShadowPrimitive2D(const primitive2d::ShadowPrim impBufferDevice aBufferDevice(*mpOutputDevice, aRange); if (aBufferDevice.isVisible()) { - // Process children which don't want blur. - primitive2d::Primitive2DContainer aContainer; - rCandidate.get2DDecompositionWithoutBlur(aContainer, getViewInformation2D()); - process(aContainer); - - // Process children which want blur. OutputDevice* pLastOutputDevice = mpOutputDevice; mpOutputDevice = &aBufferDevice.getContent(); - aContainer.clear(); - rCandidate.get2DDecompositionWithBlur(aContainer, getViewInformation2D()); - process(aContainer); + process(rCandidate); const tools::Rectangle aRect(static_cast<tools::Long>(std::floor(aRange.getMinX())), static_cast<tools::Long>(std::floor(aRange.getMinY())), diff --git a/drawinglayer/source/tools/primitive2dxmldump.cxx b/drawinglayer/source/tools/primitive2dxmldump.cxx index 1342fd39354f..5fe1eb41fead 100644 --- a/drawinglayer/source/tools/primitive2dxmldump.cxx +++ b/drawinglayer/source/tools/primitive2dxmldump.cxx @@ -549,8 +549,8 @@ void Primitive2dXmlDump::decomposeAndWrite( if (pBufferedDecomposition) { rWriter.attribute( - "excludeFromBlur", - OString::boolean(pBufferedDecomposition->getExcludeFromBlur())); + "transparenceForShadow", + OString::number(pBufferedDecomposition->getTransparenceForShadow())); } drawinglayer::primitive2d::Primitive2DContainer aPrimitiveContainer; diff --git a/include/drawinglayer/primitive2d/baseprimitive2d.hxx b/include/drawinglayer/primitive2d/baseprimitive2d.hxx index b94218b07111..c5d947c8b1de 100644 --- a/include/drawinglayer/primitive2d/baseprimitive2d.hxx +++ b/include/drawinglayer/primitive2d/baseprimitive2d.hxx @@ -204,8 +204,9 @@ private: /// a sequence used for buffering the last create2DDecomposition() result Primitive2DContainer maBuffered2DDecomposition; - /// When blur is invoked on a list of primitives, exclude this primitive from the blur effect. - bool mbExcludeFromBlur = false; + /// When a shadow wraps a list of primitives, this primitive wants to influence the transparency + /// of the shadow. + sal_uInt16 mnTransparenceForShadow = 0; protected: /** access methods to maBuffered2DDecomposition. The usage of this methods may allow @@ -241,9 +242,12 @@ public: get2DDecomposition(Primitive2DDecompositionVisitor& rVisitor, const geometry::ViewInformation2D& rViewInformation) const override; - void setExcludeFromBlur(bool bExcludeFromBlur) { mbExcludeFromBlur = bExcludeFromBlur; } + void setTransparenceForShadow(sal_uInt16 nTransparenceForShadow) + { + mnTransparenceForShadow = nTransparenceForShadow; + } - bool getExcludeFromBlur() const { return mbExcludeFromBlur; } + sal_uInt16 getTransparenceForShadow() const { return mnTransparenceForShadow; } }; } // end of namespace drawinglayer::primitive2d diff --git a/include/drawinglayer/primitive2d/shadowprimitive2d.hxx b/include/drawinglayer/primitive2d/shadowprimitive2d.hxx index 7bd223847f8d..37258d8f34ed 100644 --- a/include/drawinglayer/primitive2d/shadowprimitive2d.hxx +++ b/include/drawinglayer/primitive2d/shadowprimitive2d.hxx @@ -76,14 +76,6 @@ namespace drawinglayer::primitive2d /// create decomposition virtual void get2DDecomposition(Primitive2DDecompositionVisitor& rVisitor, const geometry::ViewInformation2D& rViewInformation) const override; - void get2DDecompositionWithoutBlur( - Primitive2DDecompositionVisitor& rVisitor, - const geometry::ViewInformation2D& rViewInformation) const; - - void - get2DDecompositionWithBlur(Primitive2DDecompositionVisitor& rVisitor, - const geometry::ViewInformation2D& rViewInformation) const; - /// provide unique ID virtual sal_uInt32 getPrimitive2DID() const override; }; diff --git a/svx/qa/unit/table.cxx b/svx/qa/unit/table.cxx index 4419892a42ba..f65118e536c6 100644 --- a/svx/qa/unit/table.cxx +++ b/svx/qa/unit/table.cxx @@ -89,11 +89,13 @@ CPPUNIT_TEST_FIXTURE(Test, testTableShadowBlur) drawinglayer::Primitive2dXmlDump aDumper; xmlDocUniquePtr pDocument = aDumper.dumpAndParse(xPrimitiveSequence); // Without the accompanying fix in place, this test would have failed with: - // - Expected: true - // - Actual : false - // i.e. blur was applied on both the cell fill and the cell border. - assertXPath(pDocument, "//shadow/transform/modifiedColor/sdrCell[1]", "excludeFromBlur", - "true"); + // - number of nodes is incorrect + // - Expected: 1 + // - Actual : 0 + // i.e. the shadow itself was not transparent and that resulted in a non-transparent rendering + // as well, while the rendering transparency should be based on the transparency of the shadow + // itself and the transparency of the cell fill. + assertXPath(pDocument, "//objectinfo/unifiedtransparence[1]", "transparence", "0.8"); } } diff --git a/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx b/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx index 07a53a0f55d2..a941c0cc1021 100644 --- a/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx +++ b/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx @@ -549,7 +549,6 @@ basegfx::B2DRange getTextAnchorRange(const attribute::SdrTextAttribute& rText, { if(!rContent.empty()) { - Primitive2DContainer aRetval(2); basegfx::B2DHomMatrix aShadowOffset; { @@ -580,25 +579,66 @@ basegfx::B2DRange getTextAnchorRange(const attribute::SdrTextAttribute& rText, } // create shadow primitive and add content - aRetval[0] = Primitive2DReference( - new ShadowPrimitive2D( - aShadowOffset, - rShadow.getColor(), - rShadow.getBlur(), - (pContentForShadow ? *pContentForShadow : rContent))); - - if(0.0 != rShadow.getTransparence()) + const Primitive2DContainer& rContentForShadow + = pContentForShadow ? *pContentForShadow : rContent; + int nContentWithTransparence = std::count_if( + rContentForShadow.begin(), rContentForShadow.end(), + [](const Primitive2DReference& xChild) { + auto pChild = dynamic_cast<BufferedDecompositionPrimitive2D*>(xChild.get()); + return pChild && pChild->getTransparenceForShadow() != 0; + }); + if (nContentWithTransparence == 0) { - // create SimpleTransparencePrimitive2D - const Primitive2DContainer aTempContent { aRetval[0] }; - + Primitive2DContainer aRetval(2); aRetval[0] = Primitive2DReference( - new UnifiedTransparencePrimitive2D( - aTempContent, - rShadow.getTransparence())); + new ShadowPrimitive2D( + aShadowOffset, + rShadow.getColor(), + rShadow.getBlur(), + (pContentForShadow ? *pContentForShadow : rContent))); + + if(0.0 != rShadow.getTransparence()) + { + // create SimpleTransparencePrimitive2D + const Primitive2DContainer aTempContent { aRetval[0] }; + + aRetval[0] = Primitive2DReference( + new UnifiedTransparencePrimitive2D( + aTempContent, + rShadow.getTransparence())); + } + + aRetval[1] = Primitive2DReference(new GroupPrimitive2D(rContent)); + return aRetval; + } + + Primitive2DContainer aRetval; + for (const auto& xChild : rContentForShadow) + { + double fChildTransparence = 0.0; + auto pChild = dynamic_cast<BufferedDecompositionPrimitive2D*>(xChild.get()); + if (pChild) + { + fChildTransparence = pChild->getTransparenceForShadow(); + fChildTransparence /= 100; + } + aRetval.push_back(Primitive2DReference( + new ShadowPrimitive2D(aShadowOffset, rShadow.getColor(), rShadow.getBlur(), + { xChild }))); + if (rShadow.getTransparence() != 0.0 || fChildTransparence != 0.0) + { + Primitive2DContainer aTempContent{ aRetval.back() }; + + double fChildAlpha = 1.0 - fChildTransparence; + double fShadowAlpha = 1.0 - rShadow.getTransparence(); + double fTransparence = 1.0 - fChildAlpha * fShadowAlpha; + aRetval.back() = Primitive2DReference(new UnifiedTransparencePrimitive2D( + std::move(aTempContent), fTransparence)); + } } - aRetval[1] = Primitive2DReference(new GroupPrimitive2D(rContent)); + aRetval.push_back( + Primitive2DReference(new GroupPrimitive2D(rContent))); return aRetval; } else diff --git a/svx/source/table/viewcontactoftableobj.cxx b/svx/source/table/viewcontactoftableobj.cxx index 409e099ae3e5..6262c7a54d1c 100644 --- a/svx/source/table/viewcontactoftableobj.cxx +++ b/svx/source/table/viewcontactoftableobj.cxx @@ -38,6 +38,7 @@ #include <svx/framelinkarray.hxx> #include <svx/sdooitm.hxx> #include <vcl/canvastools.hxx> +#include <svx/xfltrit.hxx> #include <cell.hxx> #include "tablelayouter.hxx" @@ -320,14 +321,21 @@ namespace sdr::contact aRetval.append(xCellReference); } - // Create cell primitive without text and blur. + // Create cell primitive without text. aAttribute = drawinglayer::primitive2d::createNewSdrFillTextAttribute( rCellItemSet, nullptr); rtl::Reference pCellReference = new drawinglayer::primitive2d::SdrCellPrimitive2D( aCellMatrix, aAttribute); - pCellReference->setExcludeFromBlur(true); + + sal_uInt16 nTransparence( + rCellItemSet.Get(XATTR_FILLTRANSPARENCE).GetValue()); + if (nTransparence != 0) + { + pCellReference->setTransparenceForShadow(nTransparence); + } + const drawinglayer::primitive2d::Primitive2DReference xCellReference(pCellReference.get()); aRetvalForShadow.append(xCellReference); @@ -379,8 +387,7 @@ namespace sdr::contact aTransform, aCellBorderPrimitives)); - // Borders are always the same for shadow as well, and implicitly included - // in blur. + // Borders are always the same for shadow as well. aRetvalForShadow.append(new drawinglayer::primitive2d::TransformPrimitive2D( aTransform, aCellBorderPrimitives)); } diff --git a/vcl/source/bitmap/bitmapfilter.cxx b/vcl/source/bitmap/bitmapfilter.cxx index 70d9cdd62dc1..67744e71aa05 100644 --- a/vcl/source/bitmap/bitmapfilter.cxx +++ b/vcl/source/bitmap/bitmapfilter.cxx @@ -19,6 +19,11 @@ BitmapFilter::~BitmapFilter() {} bool BitmapFilter::Filter(BitmapEx& rBmpEx, BitmapFilter const& rFilter) { + if (rBmpEx.IsEmpty()) + { + return true; + } + BitmapEx aTmpBmpEx(rFilter.execute(rBmpEx)); if (aTmpBmpEx.IsEmpty())