diff options
author | Armin Le Grand (allotropia) <armin.le.grand.extern@allotropia.de> | 2022-09-13 13:42:54 +0200 |
---|---|---|
committer | Armin Le Grand <Armin.Le.Grand@me.com> | 2022-09-14 09:54:18 +0200 |
commit | e735ad1c57cddaf17d6ffc0cf15b5e14fa63c4ad (patch) | |
tree | 194e32decaaf2aa96a12169ea3dacd749b8dffd9 /drawinglayer | |
parent | 80d3fb7ef721b5aa2de1095249557a19e3697b3b (diff) |
Rework of ShadowPrimitive2D
This is pretty much the same for ShadowPrimitive2D as the
change for GlowPrimitive2D and SoftEdgePrimitive2D, so for
more comments please refer to those commits:
c2d1458723c66c2fd717a112f89f773226adc841
707b0c328a282d993fa33b618083d20b6c521de6
There are some needed differences due to ShadowPrimitive2D
having existed longer and is used for non-blurred shadow
for a long time and is used as unchanged as possible.
Only for active glow of shadow is a buffering and local
decompose used.
Change-Id: I55e6516f59390079356ac16f24743b474e53fb05
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/139858
Tested-by: Jenkins
Reviewed-by: Armin Le Grand <Armin.Le.Grand@me.com>
Diffstat (limited to 'drawinglayer')
9 files changed, 400 insertions, 211 deletions
diff --git a/drawinglayer/source/primitive2d/GlowSoftEgdeShadowTools.cxx b/drawinglayer/source/primitive2d/GlowSoftEgdeShadowTools.cxx index da3621aa189c..0a3249399a44 100644 --- a/drawinglayer/source/primitive2d/GlowSoftEgdeShadowTools.cxx +++ b/drawinglayer/source/primitive2d/GlowSoftEgdeShadowTools.cxx @@ -17,7 +17,7 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ -#include <drawinglayer/primitive2d/GlowSoftEgdeShadowTools.hxx> +#include "GlowSoftEgdeShadowTools.hxx" #include <vcl/bitmapex.hxx> #include <vcl/BitmapFilter.hxx> #include <vcl/BitmapBasicMorphologyFilter.hxx> diff --git a/drawinglayer/source/primitive2d/GlowSoftEgdeShadowTools.hxx b/drawinglayer/source/primitive2d/GlowSoftEgdeShadowTools.hxx new file mode 100644 index 000000000000..61079728d841 --- /dev/null +++ b/drawinglayer/source/primitive2d/GlowSoftEgdeShadowTools.hxx @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <vcl/alpha.hxx> +#include <drawinglayer/geometry/viewinformation2d.hxx> + +namespace drawinglayer::primitive2d +{ +/* Returns 8-bit alpha mask created from passed mask. + + Negative fErodeDilateRadius values mean erode, positive - dilate. + nTransparency defines minimal transparency level. +*/ +AlphaMask ProcessAndBlurAlphaMask(const Bitmap& rMask, double fErodeDilateRadius, + double fBlurRadius, sal_uInt8 nTransparency, + bool bConvertTo1Bit = true); + +drawinglayer::geometry::ViewInformation2D +expandB2DRangeAtViewInformation2D(const drawinglayer::geometry::ViewInformation2D& rViewInfo, + double nAmount); + +} // end of namespace drawinglayer::primitive2d + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/drawinglayer/source/primitive2d/glowprimitive2d.cxx b/drawinglayer/source/primitive2d/glowprimitive2d.cxx index f8c503759e7d..44a97c536fb2 100644 --- a/drawinglayer/source/primitive2d/glowprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/glowprimitive2d.cxx @@ -24,7 +24,7 @@ #include <basegfx/matrix/b2dhommatrixtools.hxx> #include <toolkit/helper/vclunohelper.hxx> #include <drawinglayer/converters.hxx> -#include <drawinglayer/primitive2d/GlowSoftEgdeShadowTools.hxx> +#include "GlowSoftEgdeShadowTools.hxx" #ifdef DBG_UTIL #include <tools/stream.hxx> diff --git a/drawinglayer/source/primitive2d/shadowprimitive2d.cxx b/drawinglayer/source/primitive2d/shadowprimitive2d.cxx index 15deebfb2a1e..0702c6c011f1 100644 --- a/drawinglayer/source/primitive2d/shadowprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/shadowprimitive2d.cxx @@ -22,73 +22,383 @@ #include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx> #include <drawinglayer/primitive2d/transformprimitive2d.hxx> #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> +#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <drawinglayer/converters.hxx> +#include "GlowSoftEgdeShadowTools.hxx" + +#ifdef DBG_UTIL +#include <tools/stream.hxx> +#include <vcl/filter/PngImageWriter.hxx> +#endif #include <memory> #include <utility> using namespace com::sun::star; - namespace drawinglayer::primitive2d { - ShadowPrimitive2D::ShadowPrimitive2D( - basegfx::B2DHomMatrix aShadowTransform, - const basegfx::BColor& rShadowColor, - double fShadowBlur, - Primitive2DContainer&& aChildren) - : GroupPrimitive2D(std::move(aChildren)), - maShadowTransform(std::move(aShadowTransform)), - maShadowColor(rShadowColor), - mfShadowBlur(fShadowBlur) +ShadowPrimitive2D::ShadowPrimitive2D(basegfx::B2DHomMatrix aShadowTransform, + const basegfx::BColor& rShadowColor, double fShadowBlur, + Primitive2DContainer&& aChildren) + : BufferedDecompositionGroupPrimitive2D(std::move(aChildren)) + , maShadowTransform(std::move(aShadowTransform)) + , maShadowColor(rShadowColor) + , mfShadowBlur(fShadowBlur) + , mfLastDiscreteBlurRadius(0.0) + , maLastClippedRange() +{ +} + +bool ShadowPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const +{ + if (BufferedDecompositionGroupPrimitive2D::operator==(rPrimitive)) + { + const ShadowPrimitive2D& rCompare = static_cast<const ShadowPrimitive2D&>(rPrimitive); + + return (getShadowTransform() == rCompare.getShadowTransform() + && getShadowColor() == rCompare.getShadowColor() + && getShadowBlur() == rCompare.getShadowBlur()); + } + + return false; +} + +// Helper to get the to-be-shadowed geometry completely embedded to +// a ModifiedColorPrimitive2D (change to ShadowColor) and TransformPrimitive2D +// (direction/offset/transformation of shadow). Since this is used pretty +// often, pack into a helper +void ShadowPrimitive2D::getFullyEmbeddedShadowPrimitives(Primitive2DContainer& rContainer) const +{ + 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 + rContainer.visit(new TransformPrimitive2D(getShadowTransform(), std::move(aSequenceB))); +} + +bool ShadowPrimitive2D::prepareValuesAndcheckValidity( + basegfx::B2DRange& rBlurRange, basegfx::B2DRange& rClippedRange, + basegfx::B2DVector& rDiscreteBlurSize, double& rfDiscreteBlurRadius, + const geometry::ViewInformation2D& rViewInformation) const +{ + // no BlurRadius defined, done + if (getShadowBlur() <= 0.0) + return false; + + // no geometry, done + if (getChildren().empty()) + return false; + + // no pixel target, done + if (rViewInformation.getObjectToViewTransformation().isIdentity()) + return false; + + // get fully embedded ShadowPrimitive + Primitive2DContainer aEmbedded; + getFullyEmbeddedShadowPrimitives(aEmbedded); + + // get geometry range that defines area that needs to be pixelated + rBlurRange = aEmbedded.getB2DRange(rViewInformation); + + // no range of geometry, done + if (rBlurRange.isEmpty()) + return false; + + // extend range by BlurRadius in all directions + rBlurRange.grow(getShadowBlur()); + + // initialize ClippedRange to full BlurRange -> all is visible + rClippedRange = rBlurRange; + + // get Viewport and check if used. If empty, all is visible (see + // ViewInformation2D definition in viewinformation2d.hxx) + if (!rViewInformation.getViewport().isEmpty()) + { + // if used, extend by BlurRadius to ensure needed parts are included + basegfx::B2DRange aVisibleArea(rViewInformation.getViewport()); + aVisibleArea.grow(getShadowBlur()); + + // calculate ClippedRange + rClippedRange.intersect(aVisibleArea); + + // if BlurRange is completely outside of VisibleArea, ClippedRange + // will be empty and we are done + if (rClippedRange.isEmpty()) + return false; + } + + // calculate discrete pixel size of BlurRange. If it's too small to visualize, we are done + rDiscreteBlurSize = rViewInformation.getObjectToViewTransformation() * rBlurRange.getRange(); + if (ceil(rDiscreteBlurSize.getX()) < 2.0 || ceil(rDiscreteBlurSize.getY()) < 2.0) + return false; + + // calculate discrete pixel size of BlurRadius. If it's too small to visualize, we are done + rfDiscreteBlurRadius = ceil( + (rViewInformation.getObjectToViewTransformation() * basegfx::B2DVector(getShadowBlur(), 0)) + .getLength()); + if (rfDiscreteBlurRadius < 1.0) + return false; + + return true; +} + +void ShadowPrimitive2D::create2DDecomposition( + Primitive2DContainer& rContainer, const geometry::ViewInformation2D& rViewInformation) const +{ + if (getShadowBlur() <= 0.0) + { + // Normal (non-blurred) shadow is already completely + // handled by get2DDecomposition and not buffered. It + // does not need to be since it's a simple embedding + // to a ModifiedColorPrimitive2D and TransformPrimitive2D + return; + } + + // from here on we process a blurrred shadow + basegfx::B2DRange aBlurRange; + basegfx::B2DRange aClippedRange; + basegfx::B2DVector aDiscreteBlurSize; + double fDiscreteBlurRadius(0.0); + + // Check various validity details and calculate/prepare values. If false, we are done + if (!prepareValuesAndcheckValidity(aBlurRange, aClippedRange, aDiscreteBlurSize, + fDiscreteBlurRadius, rViewInformation)) + return; + + // Create embedding transformation from object to top-left zero-aligned + // target pixel geometry (discrete form of ClippedRange) + // First, move to top-left of BlurRange + const sal_uInt32 nDiscreteBlurWidth(ceil(aDiscreteBlurSize.getX())); + const sal_uInt32 nDiscreteBlurHeight(ceil(aDiscreteBlurSize.getY())); + basegfx::B2DHomMatrix aEmbedding(basegfx::utils::createTranslateB2DHomMatrix( + -aClippedRange.getMinX(), -aClippedRange.getMinY())); + // Second, scale to discrete bitmap size + // Even when using the offset from ClippedRange, we need to use the + // scaling from the full representation, thus from BlurRange + aEmbedding.scale(nDiscreteBlurWidth / aBlurRange.getWidth(), + nDiscreteBlurHeight / aBlurRange.getHeight()); + + // Get fully embedded ShadowPrimitives. This will also embed to + // ModifiedColorPrimitive2D (what is not urgently needed) to create + // the alpha channel, but a paint with all colors set to a single + // one (like shadowColor here) is often less expensive due to possible + // simplifications painting the primitves (e.g. gradient) + Primitive2DContainer aEmbedded; + getFullyEmbeddedShadowPrimitives(aEmbedded); + + // Embed content graphics to TransformPrimitive2D + const primitive2d::Primitive2DReference xEmbedRef( + new primitive2d::TransformPrimitive2D(aEmbedding, std::move(aEmbedded))); + primitive2d::Primitive2DContainer xEmbedSeq{ xEmbedRef }; + + // Create BitmapEx using drawinglayer tooling, including a MaximumQuadraticPixel + // limitation to be safe and not go runtime/memory havoc. Use a pretty small + // limit due to this is Blurred Shadow functionality and will look good with bitmap + // scaling anyways. The value of 250.000 square pixels below maybe adapted as needed. + // NOTE: This may be further optimized. Only the alpha channel is needed, so + // convertToBitmapEx may be split in tooling to have a version that only + // creates the alpha channel. Potential win is >50% for the alpha pixel + // creation step ('>' because alpha painting uses a ColorStack and thus + // often can used simplified rendering) + const basegfx::B2DVector aDiscreteClippedSize(rViewInformation.getObjectToViewTransformation() + * aClippedRange.getRange()); + const sal_uInt32 nDiscreteClippedWidth(ceil(aDiscreteClippedSize.getX())); + const sal_uInt32 nDiscreteClippedHeight(ceil(aDiscreteClippedSize.getY())); + const geometry::ViewInformation2D aViewInformation2D; + const sal_uInt32 nMaximumQuadraticPixels(250000); + const BitmapEx aBitmapEx(::drawinglayer::convertToBitmapEx( + std::move(xEmbedSeq), aViewInformation2D, nDiscreteClippedWidth, nDiscreteClippedHeight, + nMaximumQuadraticPixels)); + + // if we have no shadow, we are done + if (aBitmapEx.IsEmpty()) + return; + + const Size& rBitmapExSizePixel(aBitmapEx.GetSizePixel()); + if (!(rBitmapExSizePixel.Width() > 0 && rBitmapExSizePixel.Height() > 0)) + return; + + // We may have to take a corrective scaling into account when the + // MaximumQuadraticPixel limit was used/triggered + double fScale(1.0); + + if (static_cast<sal_uInt32>(rBitmapExSizePixel.Width()) != nDiscreteClippedWidth + || static_cast<sal_uInt32>(rBitmapExSizePixel.Height()) != nDiscreteClippedHeight) + { + // scale in X and Y should be the same (see fReduceFactor in convertToBitmapEx), + // so adapt numerically to a single scale value, they are integer rounded values + const double fScaleX(static_cast<double>(rBitmapExSizePixel.Width()) + / static_cast<double>(nDiscreteClippedWidth)); + const double fScaleY(static_cast<double>(rBitmapExSizePixel.Height()) + / static_cast<double>(nDiscreteClippedHeight)); + + fScale = (fScaleX + fScaleY) * 0.5; + } + + // Get the Alpha and use as base to blur and apply the effect + const AlphaMask mask(drawinglayer::primitive2d::ProcessAndBlurAlphaMask( + aBitmapEx.GetAlpha(), 0, fDiscreteBlurRadius * fScale, 0, false)); + + // The end result is the bitmap filled with blur color and blurred 8-bit alpha mask + Bitmap bmp = aBitmapEx.GetBitmap(); + bmp.Erase(Color(getShadowColor())); + BitmapEx result(bmp, mask); + +#ifdef DBG_UTIL + static bool bDoSaveForVisualControl(false); // loplugin:constvars:ignore + if (bDoSaveForVisualControl) + { + // VCL_DUMP_BMP_PATH should be like C:/path/ or ~/path/ + static const OUString sDumpPath( + OUString::createFromAscii(std::getenv("VCL_DUMP_BMP_PATH"))); + if (!sDumpPath.isEmpty()) { + SvFileStream aNew(sDumpPath + "test_shadowblur.png", + StreamMode::WRITE | StreamMode::TRUNC); + vcl::PngImageWriter aPNGWriter(aNew); + aPNGWriter.write(result); } + } +#endif + + // Independent from discrete sizes of blur alpha creation, always + // map and project blur result to geometry range extended by blur + // radius, but to the eventually clipped instance (ClippedRange) + const primitive2d::Primitive2DReference xEmbedRefBitmap( + new BitmapPrimitive2D(VCLUnoHelper::CreateVCLXBitmap(result), + basegfx::utils::createScaleTranslateB2DHomMatrix( + aClippedRange.getWidth(), aClippedRange.getHeight(), + aClippedRange.getMinX(), aClippedRange.getMinY()))); + + rContainer = primitive2d::Primitive2DContainer{ xEmbedRefBitmap }; +} + +void ShadowPrimitive2D::get2DDecomposition( + Primitive2DDecompositionVisitor& rVisitor, + const geometry::ViewInformation2D& rViewInformation) const +{ + if (getShadowBlur() <= 0.0) + { + // normal (non-blurred) shadow + if (getChildren().empty()) + return; + + // get fully embedded ShadowPrimitives + Primitive2DContainer aEmbedded; + getFullyEmbeddedShadowPrimitives(aEmbedded); + + rVisitor.visit(aEmbedded); + return; + } + + // here we have a blurrred shadow, check conditions of last + // buffered decompose and decide re-use or re-create by using + // setBuffered2DDecomposition to reset local buffered version + basegfx::B2DRange aBlurRange; + basegfx::B2DRange aClippedRange; + basegfx::B2DVector aDiscreteBlurSize; + double fDiscreteBlurRadius(0.0); - bool ShadowPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const + // Check various validity details and calculate/prepare values. If false, we are done + if (!prepareValuesAndcheckValidity(aBlurRange, aClippedRange, aDiscreteBlurSize, + fDiscreteBlurRadius, rViewInformation)) + return; + + if (!getBuffered2DDecomposition().empty()) + { + // First check is to detect if the last created decompose is capable + // to represent the now requested visualization (see similar + // implementation at GlowPrimitive2D). + if (!maLastClippedRange.isEmpty() && !maLastClippedRange.isInside(aClippedRange)) { - if(BasePrimitive2D::operator==(rPrimitive)) - { - const ShadowPrimitive2D& rCompare = static_cast< const ShadowPrimitive2D& >(rPrimitive); + basegfx::B2DRange aLastClippedRangeAndHairline(maLastClippedRange); - return (getShadowTransform() == rCompare.getShadowTransform() - && getShadowColor() == rCompare.getShadowColor() - && getShadowBlur() == rCompare.getShadowBlur()); + if (!rViewInformation.getObjectToViewTransformation().isIdentity()) + { + // Grow by view-dependent size of 1/2 pixel + const double fHalfPixel((rViewInformation.getInverseObjectToViewTransformation() + * basegfx::B2DVector(0.5, 0)) + .getLength()); + aLastClippedRangeAndHairline.grow(fHalfPixel); } - return false; + if (!aLastClippedRangeAndHairline.isInside(aClippedRange)) + { + // Conditions of last local decomposition have changed, delete + const_cast<ShadowPrimitive2D*>(this)->setBuffered2DDecomposition( + Primitive2DContainer()); + } } + } - basegfx::B2DRange ShadowPrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const - { - basegfx::B2DRange aRetval(getChildren().getB2DRange(rViewInformation)); - aRetval.grow(getShadowBlur()); - aRetval.transform(getShadowTransform()); - return aRetval; - } + if (!getBuffered2DDecomposition().empty()) + { + // Second check is to react on changes of the DiscreteSoftRadius when + // zooming in/out (see similar implementation at ShadowPrimitive2D). + bool bFree(mfLastDiscreteBlurRadius <= 0.0 || fDiscreteBlurRadius <= 0.0); - void ShadowPrimitive2D::get2DDecomposition(Primitive2DDecompositionVisitor& rVisitor, const geometry::ViewInformation2D& /*rViewInformation*/) const + if (!bFree) { - 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.visit(new TransformPrimitive2D(getShadowTransform(), std::move(aSequenceB))); + const double fDiff(fabs(mfLastDiscreteBlurRadius - fDiscreteBlurRadius)); + const double fLen(fabs(mfLastDiscreteBlurRadius) + fabs(fDiscreteBlurRadius)); + const double fRelativeChange(fDiff / fLen); + + // Use lower fixed values here to change more often, higher to change less often. + // Value is in the range of ]0.0 .. 1.0] + bFree = fRelativeChange >= 0.15; } - // provide unique ID - sal_uInt32 ShadowPrimitive2D::getPrimitive2DID() const + if (bFree) { - return PRIMITIVE2D_ID_SHADOWPRIMITIVE2D; + // Conditions of last local decomposition have changed, delete + const_cast<ShadowPrimitive2D*>(this)->setBuffered2DDecomposition( + Primitive2DContainer()); } + } + + if (getBuffered2DDecomposition().empty()) + { + // refresh last used DiscreteBlurRadius and ClippedRange to new remembered values + const_cast<ShadowPrimitive2D*>(this)->mfLastDiscreteBlurRadius = fDiscreteBlurRadius; + const_cast<ShadowPrimitive2D*>(this)->maLastClippedRange = aClippedRange; + } + + // call parent, that will check for empty, call create2DDecomposition and + // set as decomposition + BufferedDecompositionGroupPrimitive2D::get2DDecomposition(rVisitor, rViewInformation); +} + +basegfx::B2DRange +ShadowPrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const +{ + // Hint: Do *not* use GroupPrimitive2D::getB2DRange, that will (unnecessarily) + // use the decompose - what works, but is not needed here. + // We know the to-be-visualized geometry and the radius it needs to be extended, + // so simply calculate the exact needed range. + basegfx::B2DRange aRetval(getChildren().getB2DRange(rViewInformation)); + + if (getShadowBlur() > 0.0) + { + // blurred shadow, that extends the geometry + aRetval.grow(getShadowBlur()); + } + + aRetval.transform(getShadowTransform()); + return aRetval; +} + +// provide unique ID +sal_uInt32 ShadowPrimitive2D::getPrimitive2DID() const { return PRIMITIVE2D_ID_SHADOWPRIMITIVE2D; } } // end of namespace diff --git a/drawinglayer/source/primitive2d/softedgeprimitive2d.cxx b/drawinglayer/source/primitive2d/softedgeprimitive2d.cxx index 55cddb919aa6..f01b6759c7f2 100644 --- a/drawinglayer/source/primitive2d/softedgeprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/softedgeprimitive2d.cxx @@ -24,7 +24,7 @@ #include <basegfx/matrix/b2dhommatrixtools.hxx> #include <toolkit/helper/vclunohelper.hxx> #include <drawinglayer/converters.hxx> -#include <drawinglayer/primitive2d/GlowSoftEgdeShadowTools.hxx> +#include "GlowSoftEgdeShadowTools.hxx" #ifdef DBG_UTIL #include <tools/stream.hxx> @@ -196,7 +196,7 @@ void SoftEdgePrimitive2D::create2DDecomposition( BitmapEx result(aBitmapEx.GetBitmap(), aMask); #ifdef DBG_UTIL - static bool bDoSaveForVisualControl(true); // loplugin:constvars:ignore + static bool bDoSaveForVisualControl(false); // loplugin:constvars:ignore if (bDoSaveForVisualControl) { // VCL_DUMP_BMP_PATH should be like C:/path/ or ~/path/ diff --git a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx index 926835788383..8e221affe978 100644 --- a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx +++ b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx @@ -928,11 +928,6 @@ void VclMetafileProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimi static_cast<const primitive2d::ObjectInfoPrimitive2D&>(rCandidate)); break; } - case PRIMITIVE2D_ID_SHADOWPRIMITIVE2D: - { - processPrimitive2DOnPixelProcessor(rCandidate); - break; - } default: { // process recursively @@ -2368,103 +2363,6 @@ void VclMetafileProcessor2D::processStructureTagPrimitive2D( } } -VclPtr<VirtualDevice> -VclMetafileProcessor2D::CreateBufferDevice(const basegfx::B2DRange& rCandidateRange, - geometry::ViewInformation2D& rViewInfo, - tools::Rectangle& rRectLogic, Size& rSizePixel) const -{ - constexpr double fMaxSquarePixels = 500000; - basegfx::B2DRange aViewRange(rCandidateRange); - aViewRange.transform(maCurrentTransformation); - rRectLogic = tools::Rectangle(static_cast<tools::Long>(std::floor(aViewRange.getMinX())), - static_cast<tools::Long>(std::floor(aViewRange.getMinY())), - static_cast<tools::Long>(std::ceil(aViewRange.getMaxX())), - static_cast<tools::Long>(std::ceil(aViewRange.getMaxY()))); - const tools::Rectangle aRectPixel(mpOutputDevice->LogicToPixel(rRectLogic)); - rSizePixel = aRectPixel.GetSize(); - const double fViewVisibleArea(rSizePixel.getWidth() * rSizePixel.getHeight()); - double fReduceFactor(1.0); - - if (fViewVisibleArea > fMaxSquarePixels) - { - // reduce render size - fReduceFactor = sqrt(fMaxSquarePixels / fViewVisibleArea); - rSizePixel = Size(basegfx::fround(rSizePixel.getWidth() * fReduceFactor), - basegfx::fround(rSizePixel.getHeight() * fReduceFactor)); - } - - VclPtrInstance<VirtualDevice> pBufferDevice(DeviceFormat::DEFAULT, DeviceFormat::DEFAULT); - if (pBufferDevice->SetOutputSizePixel(rSizePixel)) - { - // create and set MapModes for target devices - MapMode aNewMapMode(mpOutputDevice->GetMapMode()); - aNewMapMode.SetOrigin(Point(-rRectLogic.Left(), -rRectLogic.Top())); - pBufferDevice->SetMapMode(aNewMapMode); - - // prepare view transformation for target renderers - // ATTENTION! Need to apply another scaling because of the potential DPI differences - // between Printer and VDev (mpOutputDevice and pBufferDevice here). - // To get the DPI, LogicToPixel from (1,1) from MapUnit::MapInch needs to be used. - basegfx::B2DHomMatrix aViewTransform(pBufferDevice->GetViewTransformation()); - const Size aDPIOld(mpOutputDevice->LogicToPixel(Size(1, 1), MapMode(MapUnit::MapInch))); - const Size aDPINew(pBufferDevice->LogicToPixel(Size(1, 1), MapMode(MapUnit::MapInch))); - const double fDPIXChange(static_cast<double>(aDPIOld.getWidth()) - / static_cast<double>(aDPINew.getWidth())); - const double fDPIYChange(static_cast<double>(aDPIOld.getHeight()) - / static_cast<double>(aDPINew.getHeight())); - - if (!basegfx::fTools::equal(fDPIXChange, 1.0) || !basegfx::fTools::equal(fDPIYChange, 1.0)) - { - aViewTransform.scale(fDPIXChange, fDPIYChange); - } - - // also take scaling from Size reduction into account - if (!basegfx::fTools::equal(fReduceFactor, 1.0)) - { - aViewTransform.scale(fReduceFactor, fReduceFactor); - } - - // create view information and pixel renderer. Reuse known ViewInformation - // except new transformation and range - rViewInfo = geometry::ViewInformation2D( - getViewInformation2D().getObjectTransformation(), aViewTransform, aViewRange, - getViewInformation2D().getVisualizedPage(), getViewInformation2D().getViewTime()); - } - else - pBufferDevice.disposeAndClear(); - -#if HAVE_P1155R3 - return pBufferDevice; -#else - return std::move(pBufferDevice); -#endif -} - -void VclMetafileProcessor2D::processPrimitive2DOnPixelProcessor( - const primitive2d::BasePrimitive2D& rCandidate) -{ - basegfx::B2DRange aViewRange(rCandidate.getB2DRange(getViewInformation2D())); - geometry::ViewInformation2D aViewInfo; - tools::Rectangle aRectLogic; - Size aSizePixel; - auto pBufferDevice(CreateBufferDevice(aViewRange, aViewInfo, aRectLogic, aSizePixel)); - if (pBufferDevice) - { - VclPixelProcessor2D aBufferProcessor(aViewInfo, *pBufferDevice, maBColorModifierStack); - - // draw content using pixel renderer - primitive2d::Primitive2DReference aRef( - &const_cast<primitive2d::BasePrimitive2D&>(rCandidate)); - aBufferProcessor.process({ aRef }); - const BitmapEx aBmContent(pBufferDevice->GetBitmapEx(Point(), aSizePixel)); - mpOutputDevice->DrawBitmapEx(aRectLogic.TopLeft(), aRectLogic.GetSize(), aBmContent); - - // aBufferProcessor dtor pops state off pBufferDevice pushed on by its ctor, let - // pBufferDevice live past aBufferProcessor scope to avoid warnings - } - pBufferDevice.disposeAndClear(); -} - } // end of namespace /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/drawinglayer/source/processor2d/vclmetafileprocessor2d.hxx b/drawinglayer/source/processor2d/vclmetafileprocessor2d.hxx index 06fd61e18309..0393039f4455 100644 --- a/drawinglayer/source/processor2d/vclmetafileprocessor2d.hxx +++ b/drawinglayer/source/processor2d/vclmetafileprocessor2d.hxx @@ -144,10 +144,6 @@ private: const primitive2d::TransparencePrimitive2D& rTransparenceCandidate); void processStructureTagPrimitive2D( const primitive2d::StructureTagPrimitive2D& rStructureTagCandidate); - void processPrimitive2DOnPixelProcessor(const primitive2d::BasePrimitive2D& rCandidate); - VclPtr<VirtualDevice> CreateBufferDevice(const basegfx::B2DRange& rCandidateRange, - geometry::ViewInformation2D& rViewInfo, - tools::Rectangle& rRectLogic, Size& rSizePixel) const; /// Convert the fWidth to the same space as its coordinates. double getTransformedLineWidth(double fWidth) const; diff --git a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx index 12e044959b31..cf8d7dcd3ac0 100644 --- a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx +++ b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx @@ -58,7 +58,6 @@ #include <drawinglayer/primitive2d/epsprimitive2d.hxx> #include <drawinglayer/primitive2d/shadowprimitive2d.hxx> #include <drawinglayer/primitive2d/patternfillprimitive2d.hxx> -#include <drawinglayer/primitive2d/GlowSoftEgdeShadowTools.hxx> #include <com/sun/star/awt/XWindow2.hpp> #include <com/sun/star/awt/XControl.hpp> @@ -395,12 +394,6 @@ void VclPixelProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitiv static_cast<const drawinglayer::primitive2d::BorderLinePrimitive2D&>(rCandidate)); break; } - case PRIMITIVE2D_ID_SHADOWPRIMITIVE2D: - { - processShadowPrimitive2D( - static_cast<const drawinglayer::primitive2d::ShadowPrimitive2D&>(rCandidate)); - break; - } case PRIMITIVE2D_ID_FILLGRADIENTPRIMITIVE2D: { processFillGradientPrimitive2D( @@ -949,52 +942,6 @@ void VclPixelProcessor2D::processMetaFilePrimitive2D(const primitive2d::BasePrim } } -void VclPixelProcessor2D::processShadowPrimitive2D(const primitive2d::ShadowPrimitive2D& rCandidate) -{ - if (rCandidate.getShadowBlur() == 0) - { - process(rCandidate); - return; - } - - basegfx::B2DRange aRange(rCandidate.getB2DRange(getViewInformation2D())); - aRange.transform(maCurrentTransformation); - basegfx::B2DVector aBlurRadiusVector(rCandidate.getShadowBlur(), 0); - aBlurRadiusVector *= maCurrentTransformation; - const double fBlurRadius = aBlurRadiusVector.getLength(); - - impBufferDevice aBufferDevice(*mpOutputDevice, aRange); - if (aBufferDevice.isVisible() && !aRange.isEmpty()) - { - OutputDevice* pLastOutputDevice = mpOutputDevice; - mpOutputDevice = &aBufferDevice.getContent(); - - process(rCandidate); - - const tools::Rectangle aRect(static_cast<tools::Long>(std::floor(aRange.getMinX())), - static_cast<tools::Long>(std::floor(aRange.getMinY())), - static_cast<tools::Long>(std::ceil(aRange.getMaxX())), - static_cast<tools::Long>(std::ceil(aRange.getMaxY()))); - - BitmapEx bitmapEx = mpOutputDevice->GetBitmapEx(aRect.TopLeft(), aRect.GetSize()); - - AlphaMask mask = drawinglayer::primitive2d::ProcessAndBlurAlphaMask(bitmapEx.GetAlpha(), 0, - fBlurRadius, 0, false); - - const basegfx::BColor aShadowColor( - maBColorModifierStack.getModifiedColor(rCandidate.getShadowColor())); - - Bitmap bitmap = bitmapEx.GetBitmap(); - bitmap.Erase(Color(aShadowColor)); - BitmapEx result(bitmap, mask); - - mpOutputDevice = pLastOutputDevice; - mpOutputDevice->DrawBitmapEx(aRect.TopLeft(), result); - } - else - SAL_WARN("drawinglayer", "Temporary buffered virtual device is not visible"); -} - void VclPixelProcessor2D::processFillGradientPrimitive2D( const primitive2d::FillGradientPrimitive2D& rPrimitive) { diff --git a/drawinglayer/source/processor2d/vclpixelprocessor2d.hxx b/drawinglayer/source/processor2d/vclpixelprocessor2d.hxx index 9f1e11cb9110..c144ba9647eb 100644 --- a/drawinglayer/source/processor2d/vclpixelprocessor2d.hxx +++ b/drawinglayer/source/processor2d/vclpixelprocessor2d.hxx @@ -39,9 +39,6 @@ class PolygonStrokePrimitive2D; class FillHatchPrimitive2D; class BackgroundColorPrimitive2D; class BorderLinePrimitive2D; -class GlowPrimitive2D; -class ShadowPrimitive2D; -class SoftEdgePrimitive2D; class FillGradientPrimitive2D; class PatternFillPrimitive2D; } @@ -97,7 +94,6 @@ class VclPixelProcessor2D final : public VclProcessor2D processBorderLinePrimitive2D(const drawinglayer::primitive2d::BorderLinePrimitive2D& rBorder); void processInvertPrimitive2D(const primitive2d::BasePrimitive2D& rCandidate); void processMetaFilePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate); - void processShadowPrimitive2D(const primitive2d::ShadowPrimitive2D& rCandidate); void processFillGradientPrimitive2D(const primitive2d::FillGradientPrimitive2D& rPrimitive); void processPatternFillPrimitive2D(const primitive2d::PatternFillPrimitive2D& rPrimitive); |