diff options
author | Mike Kaganski <mike.kaganski@collabora.com> | 2020-05-01 01:05:24 +0300 |
---|---|---|
committer | Mike Kaganski <mike.kaganski@collabora.com> | 2020-05-07 21:57:37 +0200 |
commit | 08ebcff89f56bec3b0f9b346504748e4eb1687af (patch) | |
tree | d511115b648fd5f2340fd88eacc4ad9971ad7348 /drawinglayer/source/primitive2d | |
parent | a98bdbae459ad7341bf7f484c402e77e4062cd16 (diff) |
tdf#101181: improve glow effect
The shadow of objects must not be scaled: this displaces any internal
areas that need blur, e.g. holes. Instead, it needs to dilate the
shadow using kernel with radius equal to blur radius: this allows the
borders of dilated objects to be in the middle of the blur area. The
following blur makes those new margin points to have 50% intensity,
and full glow intensity at the point of old object margins. This also
removed artifacts when moving objects with glow effect caused by
mismatch between scaling and D2D range calculation.
The D2D range therefore is not calculated by scaling, but using grow.
Blur filter's "extend bitmap by blur radius" option got obsoleted and
removed.
There's no need to blur the glow color (24-bit RGB). Instead, glow
bitmap must be filled by glow color, and have an alpha mask that is
blurred accordingly. This makes the glow properly transparent, and
also reduces the blur complexity which now only needs to process 8
bits of alpha channel.
The object shadow is created using basegfx::BColorModifier_replace
inserted into the 2d decomposition of the effect, as before. To make
sure that any non-fully-transparent pixel will become black pixel in
the shadow, black color is used, and the result is further processed
in VclPixelProcessor2D::processGlowPrimitive2D with monochrome filter
using threshold 255.
Glow transparency attribute is taken into account: the initial value
at the margins of the objects. Color replacement filter is used to
replace the object shadow with the attribute value before blur pass.
Correct blur radius is used, calculated from glow effect radius,
instead of hardcoded value of 5 pixels. This makes the glow to fade
gradually along the full width of the effect, instead of only fading
in narrow outer border previously.
Since blur filter is only implemented for radius up to 254 pixels,
and since downsampling the shadow before blur increases performance
without noticeable quality loss, the image is downsampled before
filtering.
It should be noted that the glow effect is almost identical to soft
shadow effect, likely with the only difference of using dilation in
the former, but not in the latter. The code might be reused later to
implement soft shadow as well.
Change-Id: I728c532f9df7ccf85f353c23c6c7d8352d7b2086
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/93235
Tested-by: Jenkins
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
Diffstat (limited to 'drawinglayer/source/primitive2d')
-rw-r--r-- | drawinglayer/source/primitive2d/glowprimitive2d.cxx | 24 |
1 files changed, 11 insertions, 13 deletions
diff --git a/drawinglayer/source/primitive2d/glowprimitive2d.cxx b/drawinglayer/source/primitive2d/glowprimitive2d.cxx index 7d6c23a322ad..bf49b8e215b5 100644 --- a/drawinglayer/source/primitive2d/glowprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/glowprimitive2d.cxx @@ -30,12 +30,11 @@ using namespace com::sun::star; namespace drawinglayer::primitive2d { -GlowPrimitive2D::GlowPrimitive2D(const basegfx::B2DHomMatrix& rGlowTransform, - const basegfx::BColor& rGlowColor, +GlowPrimitive2D::GlowPrimitive2D(const Color& rGlowColor, double fRadius, const Primitive2DContainer& rChildren) : GroupPrimitive2D(rChildren) - , maGlowTransform(rGlowTransform) , maGlowColor(rGlowColor) + , mfGlowRadius(fRadius) { } @@ -45,7 +44,7 @@ bool GlowPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const { const GlowPrimitive2D& rCompare = static_cast<const GlowPrimitive2D&>(rPrimitive); - return (getGlowTransform() == rCompare.getGlowTransform() + return (getGlowRadius() == rCompare.getGlowRadius() && getGlowColor() == rCompare.getGlowColor()); } @@ -55,8 +54,9 @@ bool GlowPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const basegfx::B2DRange GlowPrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const { - basegfx::B2DRange aRetval(getChildren().getB2DRange(rViewInformation)); - aRetval.transform(getGlowTransform()); + basegfx::B2DRange aRetval(GroupPrimitive2D::getB2DRange(rViewInformation)); + // We need additional space for the glow from all sides + aRetval.grow(getGlowRadius()); return aRetval; } @@ -67,15 +67,13 @@ void GlowPrimitive2D::get2DDecomposition( if (getChildren().empty()) return; - // create a modifiedColorPrimitive containing the Glow color and the content + // create a modifiedColorPrimitive containing the *black* color and the content. Using black + // on white allows creating useful mask in VclPixelProcessor2D::processGlowPrimitive2D. basegfx::BColorModifierSharedPtr aBColorModifier - = std::make_shared<basegfx::BColorModifier_replace>(getGlowColor()); + = std::make_shared<basegfx::BColorModifier_replace>(basegfx::BColor()); - const Primitive2DReference xRefA(new ModifiedColorPrimitive2D(getChildren(), aBColorModifier)); - const Primitive2DContainer aSequenceB{ xRefA }; - - // build transformed primitiveVector with Glow offset and add to target - rVisitor.append(new TransformPrimitive2D(getGlowTransform(), aSequenceB)); + const Primitive2DReference xRef(new ModifiedColorPrimitive2D(getChildren(), aBColorModifier)); + rVisitor.append(xRef); } // provide unique ID |