drawinglayer/source/processor2d/vclhelperbufferdevice.cxx | 13 +--- drawinglayer/source/processor2d/vclhelperbufferdevice.hxx | 2 drawinglayer/source/processor2d/vclpixelprocessor2d.cxx | 44 +++++++++----- 3 files changed, 35 insertions(+), 24 deletions(-)
New commits: commit 7d74030da5b20d8f379544bdb56b26a316801c51 Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Thu Jul 21 14:40:54 2022 +0300 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Fri Jul 22 13:26:58 2022 +0200 tdf#144916: expand range to avoid unwanted effects on viewport edges This also allows to avoid clipping of impBufferDevice to the passed OutputDevice, because the expanded range couldn't otherwise be processed on the buffer device. Change-Id: I0d778365b09937c1a2ecee06477b0b17efcce44b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/137296 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> (cherry picked from commit 8c15835762f2b16e7c8f5acd2d52f562c7dec9a4) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/137322 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/137339 Reviewed-by: Miklos Vajna <vmik...@collabora.com> diff --git a/drawinglayer/source/processor2d/vclhelperbufferdevice.cxx b/drawinglayer/source/processor2d/vclhelperbufferdevice.cxx index 927dacd12b65..d3b4ff10bc49 100644 --- a/drawinglayer/source/processor2d/vclhelperbufferdevice.cxx +++ b/drawinglayer/source/processor2d/vclhelperbufferdevice.cxx @@ -269,7 +269,7 @@ VDevBuffer& getVDevBuffer() return *aVDevBuffer.get(); } -impBufferDevice::impBufferDevice(OutputDevice& rOutDev, const basegfx::B2DRange& rRange) +impBufferDevice::impBufferDevice(OutputDevice& rOutDev, const basegfx::B2DRange& rRange, bool bCrop) : mrOutDev(rOutDev) , mpContent(nullptr) , mpMask(nullptr) @@ -277,13 +277,10 @@ impBufferDevice::impBufferDevice(OutputDevice& rOutDev, const basegfx::B2DRange& { basegfx::B2DRange aRangePixel(rRange); aRangePixel.transform(mrOutDev.GetViewTransformation()); - const ::tools::Rectangle aRectPixel(static_cast<sal_Int32>(floor(aRangePixel.getMinX())), - static_cast<sal_Int32>(floor(aRangePixel.getMinY())), - static_cast<sal_Int32>(ceil(aRangePixel.getMaxX())), - static_cast<sal_Int32>(ceil(aRangePixel.getMaxY()))); - const Point aEmptyPoint; - maDestPixel = ::tools::Rectangle(aEmptyPoint, mrOutDev.GetOutputSizePixel()); - maDestPixel.Intersection(aRectPixel); + maDestPixel = tools::Rectangle(floor(aRangePixel.getMinX()), floor(aRangePixel.getMinY()), + ceil(aRangePixel.getMaxX()), ceil(aRangePixel.getMaxY())); + if (bCrop) + maDestPixel.Intersection({ {}, mrOutDev.GetOutputSizePixel() }); if (!isVisible()) return; diff --git a/drawinglayer/source/processor2d/vclhelperbufferdevice.hxx b/drawinglayer/source/processor2d/vclhelperbufferdevice.hxx index 90d351eac50f..1002a930681a 100644 --- a/drawinglayer/source/processor2d/vclhelperbufferdevice.hxx +++ b/drawinglayer/source/processor2d/vclhelperbufferdevice.hxx @@ -39,7 +39,7 @@ class impBufferDevice tools::Rectangle maDestPixel; public: - impBufferDevice(OutputDevice& rOutDev, const basegfx::B2DRange& rRange); + impBufferDevice(OutputDevice& rOutDev, const basegfx::B2DRange& rRange, bool bCrop = true); ~impBufferDevice(); void paint(double fTrans = 0.0); diff --git a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx index 10845409b9ec..ba187de18cd8 100644 --- a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx +++ b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx @@ -1019,13 +1019,29 @@ AlphaMask ProcessAndBlurAlphaMask(const Bitmap& rMask, double fErodeDilateRadius return AlphaMask(mask.GetBitmap()); } + +drawinglayer::geometry::ViewInformation2D +expandRange(const drawinglayer::geometry::ViewInformation2D& rViewInfo, double nAmount) +{ + basegfx::B2DRange viewport(rViewInfo.getViewport()); + viewport.grow(nAmount); + return { rViewInfo.getObjectTransformation(), + rViewInfo.getViewTransformation(), + viewport, + rViewInfo.getVisualizedPage(), + rViewInfo.getViewTime(), + rViewInfo.getExtendedInformationSequence() }; +} } void VclPixelProcessor2D::processGlowPrimitive2D(const primitive2d::GlowPrimitive2D& rCandidate) { - basegfx::B2DRange aRange(rCandidate.getB2DRange(getViewInformation2D())); + const double nGlowRadius(rCandidate.getGlowRadius()); + // Avoid wrong effect on the cut-off side; so expand by radius + const auto aExpandedViewInfo(expandRange(getViewInformation2D(), nGlowRadius)); + basegfx::B2DRange aRange(rCandidate.getB2DRange(aExpandedViewInfo)); aRange.transform(maCurrentTransformation); - basegfx::B2DVector aGlowRadiusVector(rCandidate.getGlowRadius(), 0); + basegfx::B2DVector aGlowRadiusVector(nGlowRadius, 0); // Calculate the pixel size of glow radius in current transformation aGlowRadiusVector *= maCurrentTransformation; // Glow radius is the size of the halo from each side of the object. The halo is the @@ -1036,8 +1052,8 @@ void VclPixelProcessor2D::processGlowPrimitive2D(const primitive2d::GlowPrimitiv // Consider glow transparency (initial transparency near the object edge) const sal_uInt8 nTransparency = rCandidate.getGlowColor().GetTransparency(); - impBufferDevice aBufferDevice(*mpOutputDevice, aRange); - if (aBufferDevice.isVisible() && !aRange.isEmpty()) + impBufferDevice aBufferDevice(*mpOutputDevice, aRange, false); + if (aBufferDevice.isVisible()) { // remember last OutDev and set to content OutputDevice* pLastOutputDevice = mpOutputDevice; @@ -1048,9 +1064,8 @@ void VclPixelProcessor2D::processGlowPrimitive2D(const primitive2d::GlowPrimitiv process(rCandidate); // Limit the bitmap size to the visible area. - basegfx::B2DRange viewRange(getViewInformation2D().getDiscreteViewport()); basegfx::B2DRange bitmapRange(aRange); - bitmapRange.intersect(viewRange); + bitmapRange.intersect(aExpandedViewInfo.getDiscreteViewport()); if (!bitmapRange.isEmpty()) { const tools::Rectangle aRect( @@ -1087,19 +1102,19 @@ void VclPixelProcessor2D::processGlowPrimitive2D(const primitive2d::GlowPrimitiv void VclPixelProcessor2D::processSoftEdgePrimitive2D( const primitive2d::SoftEdgePrimitive2D& rCandidate) { - // TODO: don't limit the object at view range. This is needed to not blur objects at window - // borders, where they don't end. Ideally, process the full object once at maximal reasonable - // resolution, and store the resulting alpha mask in primitive's cache; then reuse it later, - // applying the transform. - basegfx::B2DRange aRange(rCandidate.getB2DRange(getViewInformation2D())); + const double nRadius(rCandidate.getRadius()); + // Avoid wrong effect on the cut-off side; so expand by diameter + const auto aExpandedViewInfo(expandRange(getViewInformation2D(), nRadius * 2)); + + basegfx::B2DRange aRange(rCandidate.getB2DRange(aExpandedViewInfo)); aRange.transform(maCurrentTransformation); - basegfx::B2DVector aRadiusVector(rCandidate.getRadius(), 0); + basegfx::B2DVector aRadiusVector(nRadius, 0); // Calculate the pixel size of soft edge radius in current transformation aRadiusVector *= maCurrentTransformation; // Blur radius is equal to soft edge radius const double fBlurRadius = aRadiusVector.getLength(); - impBufferDevice aBufferDevice(*mpOutputDevice, aRange); + impBufferDevice aBufferDevice(*mpOutputDevice, aRange, false); if (aBufferDevice.isVisible()) { // remember last OutDev and set to content @@ -1110,9 +1125,8 @@ void VclPixelProcessor2D::processSoftEdgePrimitive2D( process(rCandidate); // Limit the bitmap size to the visible area. - basegfx::B2DRange viewRange(getViewInformation2D().getDiscreteViewport()); basegfx::B2DRange bitmapRange(aRange); - bitmapRange.intersect(viewRange); + bitmapRange.intersect(aExpandedViewInfo.getDiscreteViewport()); if (!bitmapRange.isEmpty()) { const tools::Rectangle aRect(