drawinglayer/source/primitive2d/shadowprimitive2d.cxx | 73 ++-------- drawinglayer/source/processor2d/vclpixelprocessor2d.cxx | 8 - drawinglayer/source/tools/primitive2dxmldump.cxx | 4 include/drawinglayer/primitive2d/BufferedDecompositionPrimitive2D.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 +- 8 files changed, 101 insertions(+), 103 deletions(-)
New commits: commit 00fa364a2403dc23a786d3f91fde06e10b3a4a9a Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Thu Sep 23 16:55:19 2021 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Thu Sep 23 17:48:59 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. Change-Id: I63560e3a73473c70157ecee8365ec7154217f269 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/122532 Reviewed-by: Miklos Vajna <vmik...@collabora.com> Tested-by: Jenkins diff --git a/drawinglayer/source/primitive2d/shadowprimitive2d.cxx b/drawinglayer/source/primitive2d/shadowprimitive2d.cxx index 3d4bbdfecb92..6ea066b35754 100644 --- a/drawinglayer/source/primitive2d/shadowprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/shadowprimitive2d.cxx @@ -22,7 +22,6 @@ #include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx> #include <drawinglayer/primitive2d/transformprimitive2d.hxx> #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> -#include <drawinglayer/primitive2d/BufferedDecompositionPrimitive2D.hxx> #include <memory> @@ -31,28 +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(Primitive2DContainer(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, @@ -89,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( + Primitive2DContainer(getChildren()), + aBColorModifier)); + Primitive2DContainer aSequenceB { xRefA }; + + // build transformed primitiveVector with shadow offset and add to target + rVisitor.append(new TransformPrimitive2D(getShadowTransform(), std::move(aSequenceB))); } // provide unique ID diff --git a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx index be53d4712aa3..27dbd89f1d06 100644 --- a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx +++ b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx @@ -1164,16 +1164,12 @@ void VclPixelProcessor2D::processShadowPrimitive2D(const primitive2d::ShadowPrim const double fBlurRadius = aBlurRadiusVector.getLength(); impBufferDevice aBufferDevice(*mpOutputDevice, aRange); - if (aBufferDevice.isVisible()) + if (aBufferDevice.isVisible() && !aRange.isEmpty()) { - // Process children which don't want blur. - rCandidate.get2DDecompositionWithoutBlur(*this, getViewInformation2D()); - - // Process children which want blur. OutputDevice* pLastOutputDevice = mpOutputDevice; mpOutputDevice = &aBufferDevice.getContent(); - rCandidate.get2DDecompositionWithBlur(*this, getViewInformation2D()); + 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 d0496b482669..17bb707b666e 100644 --- a/drawinglayer/source/tools/primitive2dxmldump.cxx +++ b/drawinglayer/source/tools/primitive2dxmldump.cxx @@ -641,8 +641,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/BufferedDecompositionPrimitive2D.hxx b/include/drawinglayer/primitive2d/BufferedDecompositionPrimitive2D.hxx index c09635c6d60d..c67c3262ec1c 100644 --- a/include/drawinglayer/primitive2d/BufferedDecompositionPrimitive2D.hxx +++ b/include/drawinglayer/primitive2d/BufferedDecompositionPrimitive2D.hxx @@ -67,8 +67,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 @@ -103,9 +104,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 d388eaf1b90d..7df83a395f19 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 d03bac35dba8..c82f331f2d17 100644 --- a/svx/qa/unit/table.cxx +++ b/svx/qa/unit/table.cxx @@ -91,11 +91,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", "80"); } } diff --git a/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx b/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx index bce84bf1eddc..1f74149b0b9a 100644 --- a/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx +++ b/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx @@ -544,7 +544,6 @@ basegfx::B2DRange getTextAnchorRange(const attribute::SdrTextAttribute& rText, { if(!rContent.empty()) { - Primitive2DContainer aRetval(2); basegfx::B2DHomMatrix aShadowOffset; { @@ -575,25 +574,66 @@ basegfx::B2DRange getTextAnchorRange(const attribute::SdrTextAttribute& rText, } // create shadow primitive and add content - aRetval[0] = Primitive2DReference( - new ShadowPrimitive2D( - aShadowOffset, - rShadow.getColor(), - rShadow.getBlur(), - Primitive2DContainer(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 - Primitive2DContainer aTempContent { aRetval[0] }; - + Primitive2DContainer aRetval(2); aRetval[0] = Primitive2DReference( - new UnifiedTransparencePrimitive2D( - std::move(aTempContent), - rShadow.getTransparence())); + new ShadowPrimitive2D( + aShadowOffset, + rShadow.getColor(), + rShadow.getBlur(), + Primitive2DContainer(pContentForShadow ? *pContentForShadow : rContent))); + + if (0.0 != rShadow.getTransparence()) + { + // create SimpleTransparencePrimitive2D + Primitive2DContainer aTempContent{ aRetval[0] }; + + aRetval[0] = Primitive2DReference( + new UnifiedTransparencePrimitive2D( + std::move(aTempContent), + rShadow.getTransparence())); + } + + aRetval[1] = Primitive2DReference(new GroupPrimitive2D(Primitive2DContainer(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(), + Primitive2DContainer({ 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(Primitive2DContainer(rContent))); + aRetval.push_back( + Primitive2DReference(new GroupPrimitive2D(Primitive2DContainer(rContent)))); return aRetval; } else diff --git a/svx/source/table/viewcontactoftableobj.cxx b/svx/source/table/viewcontactoftableobj.cxx index ae5b9ef9313c..39762d727089 100644 --- a/svx/source/table/viewcontactoftableobj.cxx +++ b/svx/source/table/viewcontactoftableobj.cxx @@ -40,6 +40,7 @@ #include <svx/sdooitm.hxx> #include <vcl/canvastools.hxx> #include <o3tl/unit_conversion.hxx> +#include <svx/xfltrit.hxx> #include <cell.hxx> #include "tablelayouter.hxx" @@ -325,14 +326,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); aRetvalForShadow.append(xCellReference); @@ -384,8 +392,7 @@ namespace sdr::contact aTransform, drawinglayer::primitive2d::Primitive2DContainer(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, std::move(aCellBorderPrimitives))); }