diff options
Diffstat (limited to 'drawinglayer/source/processor2d/vclpixelprocessor2d.cxx')
-rw-r--r-- | drawinglayer/source/processor2d/vclpixelprocessor2d.cxx | 450 |
1 files changed, 140 insertions, 310 deletions
diff --git a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx index 70b5331f1f79..754b8cef2592 100644 --- a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx +++ b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx @@ -23,13 +23,12 @@ #include <comphelper/lok.hxx> #include <sal/log.hxx> -#include <vcl/BitmapBasicMorphologyFilter.hxx> -#include <vcl/BitmapFilterStackBlur.hxx> #include <vcl/outdev.hxx> #include <vcl/hatch.hxx> #include <vcl/canvastools.hxx> #include <basegfx/polygon/b2dpolygontools.hxx> #include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <basegfx/utils/gradienttools.hxx> #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> #include <drawinglayer/primitive2d/Tools.hxx> @@ -58,35 +57,28 @@ #include <drawinglayer/primitive2d/pointarrayprimitive2d.hxx> #include <drawinglayer/primitive2d/fillhatchprimitive2d.hxx> #include <drawinglayer/primitive2d/epsprimitive2d.hxx> -#include <drawinglayer/primitive2d/softedgeprimitive2d.hxx> #include <drawinglayer/primitive2d/shadowprimitive2d.hxx> #include <drawinglayer/primitive2d/patternfillprimitive2d.hxx> #include <com/sun/star/awt/XWindow2.hpp> #include <com/sun/star/awt/XControl.hpp> -#include <svtools/optionsdrawinglayer.hxx> +#include <officecfg/Office/Common.hxx> #include <vcl/gradient.hxx> using namespace com::sun::star; namespace drawinglayer::processor2d { -struct VclPixelProcessor2D::Impl -{ - AntialiasingFlags m_nOrigAntiAliasing; - - explicit Impl(OutputDevice const& rOutDev) - : m_nOrigAntiAliasing(rOutDev.GetAntialiasing()) - { - } -}; - VclPixelProcessor2D::VclPixelProcessor2D(const geometry::ViewInformation2D& rViewInformation, OutputDevice& rOutDev, const basegfx::BColorModifierStack& rInitStack) : VclProcessor2D(rViewInformation, rOutDev, rInitStack) - , m_pImpl(new Impl(rOutDev)) + , m_nOrigAntiAliasing(rOutDev.GetAntialiasing()) + , m_bRenderSimpleTextDirect( + officecfg::Office::Common::Drawinglayer::RenderSimpleTextDirect::get()) + , m_bRenderDecoratedTextDirect( + officecfg::Office::Common::Drawinglayer::RenderDecoratedTextDirect::get()) { // prepare maCurrentTransformation matrix with viewTransformation to target directly to pixels maCurrentTransformation = rViewInformation.getObjectToViewTransformation(); @@ -96,13 +88,13 @@ VclPixelProcessor2D::VclPixelProcessor2D(const geometry::ViewInformation2D& rVie mpOutputDevice->SetMapMode(); // react on AntiAliasing settings - if (SvtOptionsDrawinglayer::IsAntiAliasing()) + if (rViewInformation.getUseAntiAliasing()) { - mpOutputDevice->SetAntialiasing(m_pImpl->m_nOrigAntiAliasing | AntialiasingFlags::Enable); + mpOutputDevice->SetAntialiasing(m_nOrigAntiAliasing | AntialiasingFlags::Enable); } else { - mpOutputDevice->SetAntialiasing(m_pImpl->m_nOrigAntiAliasing & ~AntialiasingFlags::Enable); + mpOutputDevice->SetAntialiasing(m_nOrigAntiAliasing & ~AntialiasingFlags::Enable); } } @@ -112,7 +104,7 @@ VclPixelProcessor2D::~VclPixelProcessor2D() mpOutputDevice->Pop(); // restore AntiAliasing - mpOutputDevice->SetAntialiasing(m_pImpl->m_nOrigAntiAliasing); + mpOutputDevice->SetAntialiasing(m_nOrigAntiAliasing); } void VclPixelProcessor2D::tryDrawPolyPolygonColorPrimitive2DDirect( @@ -127,7 +119,11 @@ void VclPixelProcessor2D::tryDrawPolyPolygonColorPrimitive2DDirect( const basegfx::BColor aPolygonColor( maBColorModifierStack.getModifiedColor(rSource.getBColor())); - mpOutputDevice->SetFillColor(Color(aPolygonColor)); + if (comphelper::LibreOfficeKit::isActive() && aPolygonColor.isAutomatic()) + mpOutputDevice->SetFillColor(getViewInformation2D().getAutoColor()); + else + mpOutputDevice->SetFillColor(Color(aPolygonColor)); + mpOutputDevice->SetLineColor(); mpOutputDevice->DrawTransparent(maCurrentTransformation, rSource.getB2DPolyPolygon(), fTransparency); @@ -197,32 +193,6 @@ bool VclPixelProcessor2D::tryDrawPolygonStrokePrimitive2DDirect( rSource.getLineAttribute().getMiterMinimumAngle()); } -namespace -{ -GradientStyle convertGradientStyle(drawinglayer::attribute::GradientStyle eGradientStyle) -{ - switch (eGradientStyle) - { - case drawinglayer::attribute::GradientStyle::Axial: - return GradientStyle::Axial; - case drawinglayer::attribute::GradientStyle::Radial: - return GradientStyle::Radial; - case drawinglayer::attribute::GradientStyle::Elliptical: - return GradientStyle::Elliptical; - case drawinglayer::attribute::GradientStyle::Square: - return GradientStyle::Square; - case drawinglayer::attribute::GradientStyle::Rect: - return GradientStyle::Rect; - case drawinglayer::attribute::GradientStyle::Linear: - return GradientStyle::Linear; - default: - assert(false); - return GradientStyle::Linear; - } -} - -} // end anonymous namespace - void VclPixelProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate) { switch (rCandidate.getPrimitive2DID()) @@ -368,17 +338,6 @@ void VclPixelProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitiv static_cast<const primitive2d::BackgroundColorPrimitive2D&>(rCandidate)); break; } - case PRIMITIVE2D_ID_TEXTHIERARCHYEDITPRIMITIVE2D: - { - // #i97628# - // This primitive means that the content is derived from an active text edit, - // not from model data itself. Some renderers need to suppress this content, e.g. - // the pixel renderer used for displaying the edit view (like this one). It's - // not to be suppressed by the MetaFile renderers, so that the edited text is - // part of the MetaFile, e.g. needed for presentation previews. - // Action: Ignore here, do nothing. - break; - } case PRIMITIVE2D_ID_INVERTPRIMITIVE2D: { processInvertPrimitive2D(rCandidate); @@ -407,24 +366,6 @@ void VclPixelProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitiv static_cast<const drawinglayer::primitive2d::BorderLinePrimitive2D&>(rCandidate)); break; } - case PRIMITIVE2D_ID_GLOWPRIMITIVE2D: - { - processGlowPrimitive2D( - static_cast<const drawinglayer::primitive2d::GlowPrimitive2D&>(rCandidate)); - break; - } - case PRIMITIVE2D_ID_SOFTEDGEPRIMITIVE2D: - { - processSoftEdgePrimitive2D( - static_cast<const drawinglayer::primitive2d::SoftEdgePrimitive2D&>(rCandidate)); - break; - } - case PRIMITIVE2D_ID_SHADOWPRIMITIVE2D: - { - processShadowPrimitive2D( - static_cast<const drawinglayer::primitive2d::ShadowPrimitive2D&>(rCandidate)); - break; - } case PRIMITIVE2D_ID_FILLGRADIENTPRIMITIVE2D: { processFillGradientPrimitive2D( @@ -466,7 +407,7 @@ void VclPixelProcessor2D::processTextSimplePortionPrimitive2D( const DrawModeFlags nOriginalDrawMode(mpOutputDevice->GetDrawMode()); adaptTextToFillDrawMode(); - if (SvtOptionsDrawinglayer::IsRenderSimpleTextDirect()) + if (SAL_LIKELY(m_bRenderSimpleTextDirect)) { RenderTextSimpleOrDecoratedPortionPrimitive2D(rCandidate); } @@ -486,7 +427,7 @@ void VclPixelProcessor2D::processTextDecoratedPortionPrimitive2D( const DrawModeFlags nOriginalDrawMode(mpOutputDevice->GetDrawMode()); adaptTextToFillDrawMode(); - if (SvtOptionsDrawinglayer::IsRenderDecoratedTextDirect()) + if (SAL_LIKELY(m_bRenderDecoratedTextDirect)) { RenderTextSimpleOrDecoratedPortionPrimitive2D(rCandidate); } @@ -538,15 +479,31 @@ void VclPixelProcessor2D::processBitmapPrimitive2D( void VclPixelProcessor2D::processPolyPolygonGradientPrimitive2D( const primitive2d::PolyPolygonGradientPrimitive2D& rPolygonCandidate) { - // direct draw of gradient - const attribute::FillGradientAttribute& rGradient(rPolygonCandidate.getFillGradient()); - basegfx::BColor aStartColor(maBColorModifierStack.getModifiedColor(rGradient.getStartColor())); - basegfx::BColor aEndColor(maBColorModifierStack.getModifiedColor(rGradient.getEndColor())); basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon()); + // no geometry, no need to render, done if (!aLocalPolyPolygon.count()) return; + // *try* direct draw (AKA using old VCL stuff) to render gradient + const attribute::FillGradientAttribute& rGradient(rPolygonCandidate.getFillGradient()); + + // MCGR: *many* - and not only GradientStops - cases cannot be handled by VCL + // so use decomposition + // NOTE: There may be even more reasons to detect, e.g. a ViewTransformation + // that uses shear/rotate/mirror (what VCL cannot handle at all), see + // other checks already in processFillGradientPrimitive2D + if (rGradient.cannotBeHandledByVCL()) + { + process(rPolygonCandidate); + return; + } + + basegfx::BColor aStartColor( + maBColorModifierStack.getModifiedColor(rGradient.getColorStops().front().getStopColor())); + basegfx::BColor aEndColor( + maBColorModifierStack.getModifiedColor(rGradient.getColorStops().back().getStopColor())); + if (aStartColor == aEndColor) { // no gradient at all, draw as polygon in AA and non-AA case @@ -554,12 +511,11 @@ void VclPixelProcessor2D::processPolyPolygonGradientPrimitive2D( mpOutputDevice->SetLineColor(); mpOutputDevice->SetFillColor(Color(aStartColor)); mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon); + return; } - else - { - // use the primitive decomposition of the metafile - process(rPolygonCandidate); - } + + // use the primitive decomposition + process(rPolygonCandidate); } void VclPixelProcessor2D::processPolyPolygonColorPrimitive2D( @@ -574,7 +530,7 @@ void VclPixelProcessor2D::processPolyPolygonColorPrimitive2D( // when AA is on and this filled polygons are the result of stroked line geometry, // draw the geometry once extra as lines to avoid AA 'gaps' between partial polygons // Caution: This is needed in both cases (!) - if (!(mnPolygonStrokePrimitive2D && SvtOptionsDrawinglayer::IsAntiAliasing() + if (!(mnPolygonStrokePrimitive2D && getViewInformation2D().getUseAntiAliasing() && (mpOutputDevice->GetAntialiasing() & AntialiasingFlags::Enable))) return; @@ -620,7 +576,7 @@ void VclPixelProcessor2D::processUnifiedTransparencePrimitive2D( if (1 == rContent.size()) { - const primitive2d::BasePrimitive2D* pBasePrimitive = rContent[0].get(); + const primitive2d::BasePrimitive2D* pBasePrimitive = rContent.front().get(); switch (pBasePrimitive->getPrimitive2DID()) { @@ -789,7 +745,7 @@ void VclPixelProcessor2D::processPolygonStrokePrimitive2D( void VclPixelProcessor2D::processFillHatchPrimitive2D( const primitive2d::FillHatchPrimitive2D& rFillHatchPrimitive) { - if (SvtOptionsDrawinglayer::IsAntiAliasing()) + if (getViewInformation2D().getUseAntiAliasing()) { // if AA is used (or ignore smoothing is on), there is no need to smooth // hatch painting, use decomposition @@ -956,8 +912,7 @@ void VclPixelProcessor2D::processInvertPrimitive2D(const primitive2d::BasePrimit void VclPixelProcessor2D::processMetaFilePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate) { // #i98289# - const bool bForceLineSnap(SvtOptionsDrawinglayer::IsAntiAliasing() - && SvtOptionsDrawinglayer::IsSnapHorVerLinesToDiscrete()); + const bool bForceLineSnap(getViewInformation2D().getPixelSnapHairline()); const AntialiasingFlags nOldAntiAliase(mpOutputDevice->GetAntialiasing()); if (bForceLineSnap) @@ -973,247 +928,116 @@ void VclPixelProcessor2D::processMetaFilePrimitive2D(const primitive2d::BasePrim } } -namespace +void VclPixelProcessor2D::processFillGradientPrimitive2D( + const primitive2d::FillGradientPrimitive2D& rPrimitive) { -/* Returns 8-bit alpha mask created from passed mask. + const attribute::FillGradientAttribute& rFillGradient = rPrimitive.getFillGradient(); + bool useDecompose(false); - Negative fErodeDilateRadius values mean erode, positive - dilate. - nTransparency defines minimal transparency level. -*/ -AlphaMask ProcessAndBlurAlphaMask(const Bitmap& rMask, double fErodeDilateRadius, - double fBlurRadius, sal_uInt8 nTransparency) -{ - // Only completely white pixels on the initial mask must be considered for transparency. Any - // other color must be treated as black. This creates 1-bit B&W bitmap. - BitmapEx mask(rMask.CreateMask(COL_WHITE)); - - // Scaling down increases performance without noticeable quality loss. Additionally, - // current blur implementation can only handle blur radius between 2 and 254. - Size aSize = mask.GetSizePixel(); - double fScale = 1.0; - while (fBlurRadius > 254 || aSize.Height() > 1000 || aSize.Width() > 1000) + // MCGR: *many* - and not only GradientStops - cases cannot be handled by VCL + // so use decomposition + if (rFillGradient.cannotBeHandledByVCL()) { - fScale /= 2; - fBlurRadius /= 2; - fErodeDilateRadius /= 2; - aSize.setHeight(aSize.Height() / 2); - aSize.setWidth(aSize.Width() / 2); + useDecompose = true; } - // BmpScaleFlag::Fast is important for following color replacement - mask.Scale(fScale, fScale, BmpScaleFlag::Fast); - - if (fErodeDilateRadius > 0) - BitmapFilter::Filter(mask, BitmapDilateFilter(fErodeDilateRadius)); - else if (fErodeDilateRadius < 0) - BitmapFilter::Filter(mask, BitmapErodeFilter(-fErodeDilateRadius, 0xFF)); - - if (nTransparency) + // tdf#149754 VCL gradient draw is not capable to handle all primitive gradient definitions, + // what should be clear due to being developed to extend/replace them in + // capabilities & precision. + // It is e.g. not capable to correctly paint if the OutputRange is not completely + // inside the DefinitionRange, thus forcing to paint gradient parts *outside* the + // DefinitionRange. + // This happens for Writer with Frames anchored in Frames (and was broken due to + // falling back to VCL Gradient paint here), and for the new SlideBackgroundFill + // Fill mode for objects using it that reach outside the page (which is the + // DefinitionRange in that case). + // I see no real reason to fallback here to OutputDevice::DrawGradient and VCL + // gradient paint at all (system-dependent renderers wouldn't in the future), but + // will for convenience only add that needed additional correcting case + if (!useDecompose && !rPrimitive.getDefinitionRange().isInside(rPrimitive.getOutputRange())) { - const Color aTransparency(nTransparency, nTransparency, nTransparency); - mask.Replace(COL_BLACK, aTransparency); + useDecompose = true; } - // We need 8-bit grey mask for blurring - mask.Convert(BmpConversion::N8BitGreys); - - // calculate blurry effect - BitmapFilter::Filter(mask, BitmapFilterStackBlur(fBlurRadius)); - - mask.Scale(rMask.GetSizePixel()); - - return AlphaMask(mask.GetBitmap()); -} -} - -void VclPixelProcessor2D::processGlowPrimitive2D(const primitive2d::GlowPrimitive2D& rCandidate) -{ - basegfx::B2DRange aRange(rCandidate.getB2DRange(getViewInformation2D())); - aRange.transform(maCurrentTransformation); - basegfx::B2DVector aGlowRadiusVector(rCandidate.getGlowRadius(), 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 - // border of glow color that fades from glow transparency level to fully transparent - // When blurring a sharp boundary (our case), it gets 50% of original intensity, and - // fades to both sides by the blur radius; thus blur radius is half of glow radius. - const double fBlurRadius = aGlowRadiusVector.getLength() / 2; - // Consider glow transparency (initial transparency near the object edge) - const sal_uInt8 nAlpha = rCandidate.getGlowColor().GetAlpha(); - - impBufferDevice aBufferDevice(*mpOutputDevice, aRange); - if (aBufferDevice.isVisible()) + // tdf#151081 need to use regular primitive decomposition when the gradient + // is transformed in any other way then just translate & scale + if (!useDecompose) { - // remember last OutDev and set to content - OutputDevice* pLastOutputDevice = mpOutputDevice; - mpOutputDevice = &aBufferDevice.getContent(); - // We don't need antialiased mask here, which would only make effect thicker - const auto aPrevAA = mpOutputDevice->GetAntialiasing(); - mpOutputDevice->SetAntialiasing(AntialiasingFlags::NONE); - process(rCandidate); + basegfx::B2DVector aScale, aTranslate; + double fRotate, fShearX; - // Limit the bitmap size to the visible area. - basegfx::B2DRange viewRange(getViewInformation2D().getDiscreteViewport()); - basegfx::B2DRange bitmapRange(aRange); - bitmapRange.intersect(viewRange); - if (!bitmapRange.isEmpty()) - { - const tools::Rectangle aRect( - static_cast<tools::Long>(std::floor(bitmapRange.getMinX())), - static_cast<tools::Long>(std::floor(bitmapRange.getMinY())), - static_cast<tools::Long>(std::ceil(bitmapRange.getMaxX())), - static_cast<tools::Long>(std::ceil(bitmapRange.getMaxY()))); - BitmapEx bmpEx = mpOutputDevice->GetBitmapEx(aRect.TopLeft(), aRect.GetSize()); - mpOutputDevice->SetAntialiasing(aPrevAA); - - AlphaMask mask - = ProcessAndBlurAlphaMask(bmpEx.GetAlpha(), fBlurRadius, fBlurRadius, 255 - nAlpha); - - // The end result is the bitmap filled with glow color and blurred 8-bit alpha mask - const basegfx::BColor aGlowColor( - maBColorModifierStack.getModifiedColor(rCandidate.getGlowColor().getBColor())); - Bitmap bmp = bmpEx.GetBitmap(); - bmp.Erase(Color(aGlowColor)); - BitmapEx result(bmp, mask); - - // back to old OutDev - mpOutputDevice = pLastOutputDevice; - mpOutputDevice->DrawBitmapEx(aRect.TopLeft(), result); - } - else + maCurrentTransformation.decompose(aScale, aTranslate, fRotate, fShearX); + + // detect if transformation is rotated, sheared or mirrored in X and/or Y + if (!basegfx::fTools::equalZero(fRotate) || !basegfx::fTools::equalZero(fShearX) + || aScale.getX() < 0.0 || aScale.getY() < 0.0) { - mpOutputDevice = pLastOutputDevice; + useDecompose = true; } } - else - SAL_WARN("drawinglayer", "Temporary buffered virtual device is not visible"); -} -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())); - aRange.transform(maCurrentTransformation); - basegfx::B2DVector aRadiusVector(rCandidate.getRadius(), 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); - if (aBufferDevice.isVisible()) + if (useDecompose) { - // remember last OutDev and set to content - OutputDevice* pLastOutputDevice = mpOutputDevice; - mpOutputDevice = &aBufferDevice.getContent(); - // Since the effect converts all children to bitmap, we can't disable antialiasing here, - // because it would result in poor quality in areas not affected by the effect - process(rCandidate); + // default is to use the direct render below. For security, + // keep the (simple) fallback to decompose in place here + static bool bTryDirectRender(true); - // Limit the bitmap size to the visible area. - basegfx::B2DRange viewRange(getViewInformation2D().getDiscreteViewport()); - basegfx::B2DRange bitmapRange(aRange); - bitmapRange.intersect(viewRange); - if (!bitmapRange.isEmpty()) + if (bTryDirectRender) { - const tools::Rectangle aRect( - static_cast<tools::Long>(std::floor(bitmapRange.getMinX())), - static_cast<tools::Long>(std::floor(bitmapRange.getMinY())), - static_cast<tools::Long>(std::ceil(bitmapRange.getMaxX())), - static_cast<tools::Long>(std::ceil(bitmapRange.getMaxY()))); - BitmapEx bitmap = mpOutputDevice->GetBitmapEx(aRect.TopLeft(), aRect.GetSize()); - - AlphaMask aMask = bitmap.GetAlpha(); - AlphaMask blurMask = ProcessAndBlurAlphaMask(aMask, -fBlurRadius, fBlurRadius, 0); - - aMask.BlendWith(blurMask); - - // The end result is the original bitmap with blurred 8-bit alpha mask - BitmapEx result(bitmap.GetBitmap(), aMask); - - // back to old OutDev - mpOutputDevice = pLastOutputDevice; - mpOutputDevice->DrawBitmapEx(aRect.TopLeft(), result); + // MCGR: Avoid one level of primitive creation, use FillGradientPrimitive2D + // tooling to directly create needed geometry & color for getting better + // performance (partially compensate for potentially more expensive multi + // color gradients). + // To handle a primitive that needs paint, either use decompose, or - when you + // do not want that for any reason, e.g. extra primitives created - implement + // a direct handling in your primitive renderer. This is always possible + // since primitives by definition are self-contained what means they have all + // needed data locally available to do so. + // The question is the complexity to invest - the implemented decompose + // is always a good hint of what is needed to do this. In this case I decided + // to add some tooling methods to the primitive itself to support this. These + // are used in decompose and can be used - as here now - for direct handling, + // too. This is always a possibility in primitive handling - you can, but do not + // have to. + mpOutputDevice->SetFillColor( + Color(maBColorModifierStack.getModifiedColor(rPrimitive.getOuterColor()))); + mpOutputDevice->SetLineColor(); + mpOutputDevice->DrawTransparent( + maCurrentTransformation, + basegfx::B2DPolyPolygon( + basegfx::utils::createPolygonFromRect(rPrimitive.getOutputRange())), + 0.0); + + // paint solid fill steps by providing callback as lambda + auto aCallback([&rPrimitive, this](const basegfx::B2DHomMatrix& rMatrix, + const basegfx::BColor& rColor) { + // create part polygon + basegfx::B2DPolygon aNewPoly(rPrimitive.getUnitPolygon()); + aNewPoly.transform(rMatrix); + + // create solid fill + mpOutputDevice->SetFillColor(Color(maBColorModifierStack.getModifiedColor(rColor))); + mpOutputDevice->DrawTransparent(maCurrentTransformation, + basegfx::B2DPolyPolygon(aNewPoly), 0.0); + }); + + // call value generator to trigger callbacks + rPrimitive.generateMatricesAndColors(aCallback); } else { - mpOutputDevice = pLastOutputDevice; + // use the decompose + process(rPrimitive); } - } - else - SAL_WARN("drawinglayer", "Temporary buffered virtual device is not visible"); -} - -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 = ProcessAndBlurAlphaMask(bitmapEx.GetAlpha(), 0, fBlurRadius, 0); - - 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) -{ - const attribute::FillGradientAttribute& rFillGradient = rPrimitive.getFillGradient(); - - // VCL should be able to handle all styles, but for tdf#133477 the VCL result - // is different from processing the gradient manually by drawinglayer - // (and the Writer unittest for it fails). Keep using the drawinglayer code - // until somebody founds out what's wrong and fixes it. - if (rFillGradient.getStyle() != drawinglayer::attribute::GradientStyle::Linear - && rFillGradient.getStyle() != drawinglayer::attribute::GradientStyle::Axial - && rFillGradient.getStyle() != drawinglayer::attribute::GradientStyle::Radial) - { - process(rPrimitive); return; } - GradientStyle eGradientStyle = convertGradientStyle(rFillGradient.getStyle()); - - Gradient aGradient(eGradientStyle, Color(rFillGradient.getStartColor()), - Color(rFillGradient.getEndColor())); + // try to use vcl - since vcl uses the old gradient paint mechanisms this may + // create wrong geometries. If so, add another case above for useDecompose + Gradient aGradient(rFillGradient.getStyle(), + Color(rFillGradient.getColorStops().front().getStopColor()), + Color(rFillGradient.getColorStops().back().getStopColor())); aGradient.SetAngle(Degree10(static_cast<int>(basegfx::rad2deg<10>(rFillGradient.getAngle())))); aGradient.SetBorder(rFillGradient.getBorder() * 100); @@ -1262,11 +1086,13 @@ void VclPixelProcessor2D::processPatternFillPrimitive2D( tools::Rectangle aMaskRect = vcl::unotools::rectangleFromB2DRectangle(aMaskRange); // Unless smooth edges are needed, simply use clipping. - if (basegfx::utils::isRectangle(aMask) || !SvtOptionsDrawinglayer::IsAntiAliasing()) + if (basegfx::utils::isRectangle(aMask) || !getViewInformation2D().getUseAntiAliasing()) { mpOutputDevice->Push(vcl::PushFlags::CLIPREGION); mpOutputDevice->IntersectClipRegion(vcl::Region(aMask)); - mpOutputDevice->DrawWallpaper(aMaskRect, Wallpaper(aTileImage)); + Wallpaper aWallpaper(aTileImage); + aWallpaper.SetColor(COL_TRANSPARENT); + mpOutputDevice->DrawWallpaper(aMaskRect, aWallpaper); mpOutputDevice->Pop(); return; } @@ -1289,7 +1115,11 @@ void VclPixelProcessor2D::processPatternFillPrimitive2D( mpOutputDevice->DrawRect(aMaskRect); } else - mpOutputDevice->DrawWallpaper(aMaskRect, Wallpaper(aTileImage)); + { + Wallpaper aWallpaper(aTileImage); + aWallpaper.SetColor(COL_TRANSPARENT); + mpOutputDevice->DrawWallpaper(aMaskRect, aWallpaper); + } // back to old OutDev mpOutputDevice = pLastOutputDevice; |