CairoSDPR: Support direct transparency for gradients
FillGradientPrimitive2D/ and PolyPolygonGradientPrimitive2D now support both alphas, a gradientAlpha and a unified one. This allows a processor to directly handle a gradient with a unifiedAlpha if he wants. Adapted other places accordingly. NOTE: In VclMetafileProcessor2D handling of the primitive PolyPolygonGradientPrimitive2D has to do a local compromize, see comment there. Change-Id: I536f4935dafde0369f768dbd281d547b7bb08eb4 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/171052 Reviewed-by: Armin Le Grand <Armin.Le.Grand@me.com> Tested-by: Jenkins
This commit is contained in:
committed by
Armin Le Grand
parent
2a9ae69483
commit
4461173a4d
@@ -40,7 +40,7 @@ Primitive2DReference PolyPolygonGradientPrimitive2D::create2DDecomposition(
|
||||
const basegfx::B2DRange aPolyPolygonRange(getB2DPolyPolygon().getB2DRange());
|
||||
rtl::Reference<FillGradientPrimitive2D> pNewGradient = new FillGradientPrimitive2D(
|
||||
aPolyPolygonRange, getDefinitionRange(), getFillGradient(),
|
||||
hasAlphaGradient() ? &getAlphaGradient() : nullptr);
|
||||
hasAlphaGradient() ? &getAlphaGradient() : nullptr, getTransparency());
|
||||
Primitive2DContainer aSubSequence{ pNewGradient };
|
||||
|
||||
// create mask primitive
|
||||
@@ -56,17 +56,19 @@ PolyPolygonGradientPrimitive2D::PolyPolygonGradientPrimitive2D(
|
||||
, maDefinitionRange(rPolyPolygon.getB2DRange())
|
||||
, maFillGradient(rFillGradient)
|
||||
, maAlphaGradient()
|
||||
, mfTransparency(0.0)
|
||||
{
|
||||
}
|
||||
|
||||
PolyPolygonGradientPrimitive2D::PolyPolygonGradientPrimitive2D(
|
||||
basegfx::B2DPolyPolygon aPolyPolygon, const basegfx::B2DRange& rDefinitionRange,
|
||||
const attribute::FillGradientAttribute& rFillGradient,
|
||||
const attribute::FillGradientAttribute* pAlphaGradient)
|
||||
const attribute::FillGradientAttribute* pAlphaGradient, double fTransparency)
|
||||
: maPolyPolygon(std::move(aPolyPolygon))
|
||||
, maDefinitionRange(rDefinitionRange)
|
||||
, maFillGradient(rFillGradient)
|
||||
, maAlphaGradient()
|
||||
, mfTransparency(fTransparency)
|
||||
{
|
||||
// copy alpha gradient if we got one
|
||||
if (nullptr != pAlphaGradient)
|
||||
@@ -93,6 +95,9 @@ bool PolyPolygonGradientPrimitive2D::operator==(const BasePrimitive2D& rPrimitiv
|
||||
if (maAlphaGradient != rCompare.maAlphaGradient)
|
||||
return false;
|
||||
|
||||
if (!basegfx::fTools::equal(getTransparency(), rCompare.getTransparency()))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
|
||||
#include <drawinglayer/primitive2d/groupprimitive2d.hxx>
|
||||
#include <drawinglayer/primitive2d/transparenceprimitive2d.hxx>
|
||||
#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
|
||||
#include <utility>
|
||||
#include <algorithm>
|
||||
|
||||
@@ -264,22 +265,33 @@ namespace drawinglayer::primitive2d
|
||||
// SDPR: support alpha directly now. If a primitive processor
|
||||
// cannot deal with it, use it's decomposition. For that purpose
|
||||
// this decomposition has two stages now: This 1st one will
|
||||
// separate content and alpha into a TransparencePrimitive2D,
|
||||
// (if needed) separate content and alpha into a TransparencePrimitive2D
|
||||
// and (if needed) embed that to a UnifiedTransparencePrimitive2D,
|
||||
// so all processors can work as before
|
||||
if (hasAlphaGradient())
|
||||
if (hasAlphaGradient() || hasTransparency())
|
||||
{
|
||||
Primitive2DContainer aContent{ new FillGradientPrimitive2D(
|
||||
getOutputRange(),
|
||||
getDefinitionRange(),
|
||||
getFillGradient()) };
|
||||
Primitive2DReference aRetval(
|
||||
new FillGradientPrimitive2D(
|
||||
getOutputRange(),
|
||||
getDefinitionRange(),
|
||||
getFillGradient()));
|
||||
|
||||
Primitive2DContainer aAlpha{ new FillGradientPrimitive2D(
|
||||
getOutputRange(),
|
||||
getDefinitionRange(),
|
||||
getAlphaGradient()) };
|
||||
if (hasAlphaGradient())
|
||||
{
|
||||
Primitive2DContainer aAlpha{ new FillGradientPrimitive2D(
|
||||
getOutputRange(),
|
||||
getDefinitionRange(),
|
||||
getAlphaGradient()) };
|
||||
|
||||
return Primitive2DReference{ new TransparencePrimitive2D(std::move(aContent),
|
||||
std::move(aAlpha)) };
|
||||
aRetval = new TransparencePrimitive2D(Primitive2DContainer{ aRetval }, std::move(aAlpha));
|
||||
}
|
||||
|
||||
if (hasTransparency())
|
||||
{
|
||||
aRetval = new UnifiedTransparencePrimitive2D(Primitive2DContainer{ aRetval }, getTransparency());
|
||||
}
|
||||
|
||||
return aRetval;
|
||||
}
|
||||
|
||||
// default creates overlapping fill which works with AntiAliasing and without.
|
||||
@@ -303,6 +315,7 @@ namespace drawinglayer::primitive2d
|
||||
, maDefinitionRange(rOutputRange)
|
||||
, maFillGradient(rFillGradient)
|
||||
, maAlphaGradient()
|
||||
, mfTransparency(0.0)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -310,11 +323,13 @@ namespace drawinglayer::primitive2d
|
||||
const basegfx::B2DRange& rOutputRange,
|
||||
const basegfx::B2DRange& rDefinitionRange,
|
||||
const attribute::FillGradientAttribute& rFillGradient,
|
||||
const attribute::FillGradientAttribute* pAlphaGradient)
|
||||
const attribute::FillGradientAttribute* pAlphaGradient,
|
||||
double fTransparency)
|
||||
: maOutputRange(rOutputRange)
|
||||
, maDefinitionRange(rDefinitionRange)
|
||||
, maFillGradient(rFillGradient)
|
||||
, maAlphaGradient()
|
||||
, mfTransparency(fTransparency)
|
||||
{
|
||||
// copy alpha gradient if we got one
|
||||
if (nullptr != pAlphaGradient)
|
||||
@@ -340,6 +355,9 @@ namespace drawinglayer::primitive2d
|
||||
if (maAlphaGradient != rCompare.maAlphaGradient)
|
||||
return false;
|
||||
|
||||
if (!basegfx::fTools::equal(getTransparency(), rCompare.getTransparency()))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -2151,8 +2151,17 @@ void CairoPixelProcessor2D::processFillGradientPrimitive2D_linear_axial(
|
||||
}
|
||||
else
|
||||
{
|
||||
cairo_pattern_add_color_stop_rgb(pPattern, rStop.getStopOffset(), aColor.getRed(),
|
||||
aColor.getGreen(), aColor.getBlue());
|
||||
if (rFillGradientPrimitive2D.hasTransparency())
|
||||
{
|
||||
cairo_pattern_add_color_stop_rgba(pPattern, rStop.getStopOffset(), aColor.getRed(),
|
||||
aColor.getGreen(), aColor.getBlue(),
|
||||
1.0 - rFillGradientPrimitive2D.getTransparency());
|
||||
}
|
||||
else
|
||||
{
|
||||
cairo_pattern_add_color_stop_rgb(pPattern, rStop.getStopOffset(), aColor.getRed(),
|
||||
aColor.getGreen(), aColor.getBlue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2177,9 +2186,12 @@ void CairoPixelProcessor2D::processFillGradientPrimitive2D_linear_axial(
|
||||
void CairoPixelProcessor2D::processFillGradientPrimitive2D_square_rect(
|
||||
const primitive2d::FillGradientPrimitive2D& rFillGradientPrimitive2D)
|
||||
{
|
||||
if (rFillGradientPrimitive2D.hasAlphaGradient())
|
||||
if (rFillGradientPrimitive2D.hasAlphaGradient() || rFillGradientPrimitive2D.hasTransparency())
|
||||
{
|
||||
// process recursively
|
||||
// Do not use direct alpha for this: It paints using four trapez that
|
||||
// do not add up at edges due to being painted AntiAliased; that means
|
||||
// common pixels do not add up, but blend by transparency, so leaving
|
||||
// visual traces -> process recursively
|
||||
process(rFillGradientPrimitive2D);
|
||||
return;
|
||||
}
|
||||
@@ -2542,8 +2554,17 @@ void CairoPixelProcessor2D::processFillGradientPrimitive2D_radial_elliptical(
|
||||
}
|
||||
else
|
||||
{
|
||||
cairo_pattern_add_color_stop_rgb(pPattern, rStop.getStopOffset(), aColor.getRed(),
|
||||
aColor.getGreen(), aColor.getBlue());
|
||||
if (rFillGradientPrimitive2D.hasTransparency())
|
||||
{
|
||||
cairo_pattern_add_color_stop_rgba(pPattern, rStop.getStopOffset(), aColor.getRed(),
|
||||
aColor.getGreen(), aColor.getBlue(),
|
||||
1.0 - rFillGradientPrimitive2D.getTransparency());
|
||||
}
|
||||
else
|
||||
{
|
||||
cairo_pattern_add_color_stop_rgb(pPattern, rStop.getStopOffset(), aColor.getRed(),
|
||||
aColor.getGreen(), aColor.getBlue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1940,7 +1940,7 @@ void D2DPixelProcessor2D::processFillGraphicPrimitive2D(
|
||||
void D2DPixelProcessor2D::processFillGradientPrimitive2D(
|
||||
const primitive2d::FillGradientPrimitive2D& rFillGradientPrimitive2D)
|
||||
{
|
||||
if (rFillGradientPrimitive2D.hasAlphaGradient())
|
||||
if (rFillGradientPrimitive2D.hasAlphaGradient() || rFillGradientPrimitive2D.hasTransparency())
|
||||
{
|
||||
// SDPR: As long as direct alpha is not supported by this
|
||||
// renderer we need to work on the decomposition, so call it
|
||||
|
||||
@@ -1984,15 +1984,45 @@ void VclMetafileProcessor2D::processPolyPolygonHatchPrimitive2D(
|
||||
void VclMetafileProcessor2D::processPolyPolygonGradientPrimitive2D(
|
||||
const primitive2d::PolyPolygonGradientPrimitive2D& rGradientCandidate)
|
||||
{
|
||||
bool useDecompose(false);
|
||||
|
||||
// SDPR: Caution: metafile export cannot handle added TransparencyGradient
|
||||
if (rGradientCandidate.hasAlphaGradient())
|
||||
if (rGradientCandidate.hasAlphaGradient() || rGradientCandidate.hasTransparency())
|
||||
{
|
||||
// SDPR: metafile cannot handle this, use decompose
|
||||
useDecompose = true;
|
||||
// if it has alpha added directly we need to use the decomposition.
|
||||
// unfortunately VclMetafileProcessor2D does *not* support the
|
||||
// primitive created in the decomposition, the FillGradientPrimitive2D.
|
||||
// at the same time extra stuff like adding gradient info to the
|
||||
// metafile (BGRAD_SEQ_BEGIN) only is done HERE. To solve that and to
|
||||
// not add PRIMITIVE2D_ID_FILLGRADIENTPRIMITIVE2D now, create a temporary
|
||||
// decomposition to again get a PolyPolygonGradientPrimitive2D, but
|
||||
// *without* directly added alpha
|
||||
primitive2d::Primitive2DReference aRetval(new primitive2d::PolyPolygonGradientPrimitive2D(
|
||||
rGradientCandidate.getB2DPolyPolygon(), rGradientCandidate.getDefinitionRange(),
|
||||
rGradientCandidate.getFillGradient()));
|
||||
|
||||
if (rGradientCandidate.hasAlphaGradient())
|
||||
{
|
||||
const basegfx::B2DRange aPolyPolygonRange(
|
||||
rGradientCandidate.getB2DPolyPolygon().getB2DRange());
|
||||
primitive2d::Primitive2DContainer aAlpha{ new primitive2d::FillGradientPrimitive2D(
|
||||
aPolyPolygonRange, rGradientCandidate.getDefinitionRange(),
|
||||
rGradientCandidate.getAlphaGradient()) };
|
||||
|
||||
aRetval = new primitive2d::TransparencePrimitive2D(
|
||||
primitive2d::Primitive2DContainer{ aRetval }, std::move(aAlpha));
|
||||
}
|
||||
|
||||
if (rGradientCandidate.hasTransparency())
|
||||
{
|
||||
aRetval = new primitive2d::UnifiedTransparencePrimitive2D(
|
||||
primitive2d::Primitive2DContainer{ aRetval }, rGradientCandidate.getTransparency());
|
||||
}
|
||||
|
||||
process(primitive2d::Primitive2DContainer{ aRetval });
|
||||
return;
|
||||
}
|
||||
|
||||
bool useDecompose(false);
|
||||
|
||||
if (!useDecompose)
|
||||
{
|
||||
basegfx::B2DVector aScale, aTranslate;
|
||||
|
||||
@@ -930,7 +930,7 @@ void VclPixelProcessor2D::processMetaFilePrimitive2D(const primitive2d::BasePrim
|
||||
void VclPixelProcessor2D::processFillGradientPrimitive2D(
|
||||
const primitive2d::FillGradientPrimitive2D& rPrimitive)
|
||||
{
|
||||
if (rPrimitive.hasAlphaGradient())
|
||||
if (rPrimitive.hasAlphaGradient() || rPrimitive.hasTransparency())
|
||||
{
|
||||
// SDPR: As long as direct alpha is not supported by this
|
||||
// renderer we need to work on the decomposition, so call it
|
||||
|
||||
@@ -49,6 +49,9 @@ private:
|
||||
/// evtl. fitting alphaGradient definition
|
||||
attribute::FillGradientAttribute maAlphaGradient;
|
||||
|
||||
/// the transparency in range [0.0 .. 1.0]
|
||||
double mfTransparency;
|
||||
|
||||
/// local decomposition.
|
||||
virtual Primitive2DReference
|
||||
create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const override;
|
||||
@@ -60,16 +63,20 @@ public:
|
||||
PolyPolygonGradientPrimitive2D(basegfx::B2DPolyPolygon aPolyPolygon,
|
||||
const basegfx::B2DRange& rDefinitionRange,
|
||||
const attribute::FillGradientAttribute& rFillGradient,
|
||||
const attribute::FillGradientAttribute* pAlphaGradient
|
||||
= nullptr);
|
||||
const attribute::FillGradientAttribute* pAlphaGradient = nullptr,
|
||||
double fTransparency = 0.0);
|
||||
|
||||
/// data read access
|
||||
const basegfx::B2DPolyPolygon& getB2DPolyPolygon() const { return maPolyPolygon; }
|
||||
const basegfx::B2DRange& getDefinitionRange() const { return maDefinitionRange; }
|
||||
const attribute::FillGradientAttribute& getFillGradient() const { return maFillGradient; }
|
||||
|
||||
const attribute::FillGradientAttribute& getAlphaGradient() const { return maAlphaGradient; }
|
||||
bool hasAlphaGradient() const { return !maAlphaGradient.isDefault(); }
|
||||
|
||||
double getTransparency() const { return mfTransparency; }
|
||||
bool hasTransparency() const { return !basegfx::fTools::equalZero(mfTransparency); }
|
||||
|
||||
/// compare operator
|
||||
virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
|
||||
|
||||
|
||||
@@ -70,6 +70,8 @@ namespace drawinglayer::primitive2d
|
||||
/// evtl. fitting alphaGradient definition
|
||||
attribute::FillGradientAttribute maAlphaGradient;
|
||||
|
||||
/// the transparency in range [0.0 .. 1.0]
|
||||
double mfTransparency;
|
||||
|
||||
protected:
|
||||
/// local helper
|
||||
@@ -93,15 +95,20 @@ namespace drawinglayer::primitive2d
|
||||
const basegfx::B2DRange& rOutputRange,
|
||||
const basegfx::B2DRange& rDefinitionRange,
|
||||
const attribute::FillGradientAttribute& rFillGradient,
|
||||
const attribute::FillGradientAttribute* pAlphaGradient = nullptr);
|
||||
const attribute::FillGradientAttribute* pAlphaGradient = nullptr,
|
||||
double fTransparency = 0.0);
|
||||
|
||||
/// data read access
|
||||
const basegfx::B2DRange& getOutputRange() const { return maOutputRange; }
|
||||
const basegfx::B2DRange& getDefinitionRange() const { return maDefinitionRange; }
|
||||
const attribute::FillGradientAttribute& getFillGradient() const { return maFillGradient; }
|
||||
|
||||
const attribute::FillGradientAttribute& getAlphaGradient() const { return maAlphaGradient; }
|
||||
bool hasAlphaGradient() const { return !maAlphaGradient.isDefault(); }
|
||||
|
||||
double getTransparency() const { return mfTransparency; }
|
||||
bool hasTransparency() const { return !basegfx::fTools::equalZero(mfTransparency); }
|
||||
|
||||
/// compare operator
|
||||
virtual bool operator==(const BasePrimitive2D& rPrimitive) const override final;
|
||||
|
||||
|
||||
@@ -404,25 +404,34 @@ sal_uInt32 SlideBackgroundFillPrimitive2D::getPrimitive2DID() const
|
||||
|
||||
if(!rFillGradient.isDefault())
|
||||
{
|
||||
// SDPR: check early if we have a gradient and an alpha
|
||||
// gradient that 'fits' in its geometric definition
|
||||
// so that it can be rendered as RGBA directly. If yes,
|
||||
// create it and return early
|
||||
const bool bIncludeAlpha(
|
||||
0.0 == rFill.getTransparence()
|
||||
const bool bHasTransparency(!basegfx::fTools::equalZero(rFill.getTransparence()));
|
||||
// note: need to use !bHasTransparency to do the same as below
|
||||
// where embedding to transparency is done. There, simple transparency
|
||||
// gets priority over gradient transparency (and none). Thus here only one
|
||||
// option is used. Note that the implementation of FillGradientPrimitive2D
|
||||
// and PolyPolygonGradientPrimitive2D do support both alphas being used
|
||||
const bool bHasAlphaGradient(!bHasTransparency
|
||||
&& !rAlphaGradient.isDefault()
|
||||
&& rFillGradient.sameDefinitionThanAlpha(rAlphaGradient));
|
||||
|
||||
if(bHasTransparency || bHasAlphaGradient)
|
||||
{
|
||||
// SDPR: check early if we have a gradient and an alpha
|
||||
// gradient that 'fits' in its geometric definition
|
||||
// so that it can be rendered as RGBA directly. If yes,
|
||||
// create it and return early
|
||||
return new PolyPolygonGradientPrimitive2D(
|
||||
rPolyPolygon,
|
||||
rDefinitionRange,
|
||||
rFillGradient,
|
||||
bHasAlphaGradient ? &rAlphaGradient : nullptr,
|
||||
bHasTransparency ? rFill.getTransparence() : 0.0);
|
||||
}
|
||||
|
||||
pNewFillPrimitive = new PolyPolygonGradientPrimitive2D(
|
||||
rPolyPolygon,
|
||||
rDefinitionRange,
|
||||
rFillGradient,
|
||||
bIncludeAlpha ? &rAlphaGradient : nullptr);
|
||||
|
||||
if (bIncludeAlpha)
|
||||
{
|
||||
return pNewFillPrimitive;
|
||||
}
|
||||
rFillGradient);
|
||||
}
|
||||
else if(!rFill.getHatch().isDefault())
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user