summaryrefslogtreecommitdiff
path: root/drawinglayer/source
diff options
context:
space:
mode:
authorArmin Le Grand (Collabora) <Armin.Le.Grand@me.com>2024-07-18 14:08:48 +0200
committerArmin Le Grand <Armin.Le.Grand@me.com>2024-07-19 10:46:34 +0200
commitaac4974f2a50ebd34137d0384a5e21567c6ae646 (patch)
treed432e73d99cc4b3a4eca3d347197b3b4cb8bcef8 /drawinglayer/source
parent27198ec7031e9ef3bbc592423e5c12e333e206ee (diff)
CairoSDPR: Direct support for RGBA Gradients (III)
I thought about this functionality again and decided to change doing it in a way that will support more alpha more directly in existing primitives - that will be better for also supporting e.g. PolyPolys with alpha, etc. Will need checking of existing usages of e.g. FillGradientPrimitive2D, but it's worth it. Note that when your primitive processor (usually a renderer) does *not* support alpha in gradients directly it is now requuired to continue using the decomposition (what renderers do automatically when calling 'BaseProcessor2D::process' in the default case. Checked that for existing processors. Change-Id: I840c9feb8c98549b790ef16285a309b42c4b1b53 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/170687 Tested-by: Jenkins Reviewed-by: Armin Le Grand <Armin.Le.Grand@me.com>
Diffstat (limited to 'drawinglayer/source')
-rw-r--r--drawinglayer/source/primitive2d/PolyPolygonGradientPrimitive2D.cxx87
-rw-r--r--drawinglayer/source/primitive2d/Tools.cxx2
-rw-r--r--drawinglayer/source/primitive2d/fillgradientprimitive2d.cxx70
-rw-r--r--drawinglayer/source/processor2d/cairopixelprocessor2d.cxx205
-rw-r--r--drawinglayer/source/processor2d/d2dpixelprocessor2d.cxx8
-rw-r--r--drawinglayer/source/processor2d/vclpixelprocessor2d.cxx8
6 files changed, 181 insertions, 199 deletions
diff --git a/drawinglayer/source/primitive2d/PolyPolygonGradientPrimitive2D.cxx b/drawinglayer/source/primitive2d/PolyPolygonGradientPrimitive2D.cxx
index 2e6b83ab526f..de114e2fdf53 100644
--- a/drawinglayer/source/primitive2d/PolyPolygonGradientPrimitive2D.cxx
+++ b/drawinglayer/source/primitive2d/PolyPolygonGradientPrimitive2D.cxx
@@ -39,7 +39,8 @@ Primitive2DReference PolyPolygonGradientPrimitive2D::create2DDecomposition(
// create SubSequence with FillGradientPrimitive2D
const basegfx::B2DRange aPolyPolygonRange(getB2DPolyPolygon().getB2DRange());
rtl::Reference<FillGradientPrimitive2D> pNewGradient = new FillGradientPrimitive2D(
- aPolyPolygonRange, getDefinitionRange(), getFillGradient());
+ aPolyPolygonRange, getDefinitionRange(), getFillGradient(),
+ hasAlphaGradient() ? &getAlphaGradient() : nullptr);
Primitive2DContainer aSubSequence{ pNewGradient };
// create mask primitive
@@ -49,87 +50,57 @@ Primitive2DReference PolyPolygonGradientPrimitive2D::create2DDecomposition(
}
PolyPolygonGradientPrimitive2D::PolyPolygonGradientPrimitive2D(
- const basegfx::B2DPolyPolygon& rPolyPolygon, attribute::FillGradientAttribute aFillGradient)
+ const basegfx::B2DPolyPolygon& rPolyPolygon,
+ const attribute::FillGradientAttribute& rFillGradient)
: maPolyPolygon(rPolyPolygon)
, maDefinitionRange(rPolyPolygon.getB2DRange())
- , maFillGradient(std::move(aFillGradient))
+ , maFillGradient(rFillGradient)
+ , maAlphaGradient()
{
}
PolyPolygonGradientPrimitive2D::PolyPolygonGradientPrimitive2D(
basegfx::B2DPolyPolygon aPolyPolygon, const basegfx::B2DRange& rDefinitionRange,
- attribute::FillGradientAttribute aFillGradient)
+ const attribute::FillGradientAttribute& rFillGradient,
+ const attribute::FillGradientAttribute* pAlphaGradient)
: maPolyPolygon(std::move(aPolyPolygon))
, maDefinitionRange(rDefinitionRange)
- , maFillGradient(std::move(aFillGradient))
+ , maFillGradient(rFillGradient)
+ , maAlphaGradient()
{
+ // copy alpha gradient if we got one
+ if (nullptr != pAlphaGradient)
+ maAlphaGradient = *pAlphaGradient;
}
bool PolyPolygonGradientPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
{
- if (BufferedDecompositionPrimitive2D::operator==(rPrimitive))
- {
- const PolyPolygonGradientPrimitive2D& rCompare
- = static_cast<const PolyPolygonGradientPrimitive2D&>(rPrimitive);
+ if (!(BufferedDecompositionPrimitive2D::operator==(rPrimitive)))
+ return false;
- return (getB2DPolyPolygon() == rCompare.getB2DPolyPolygon()
- && getDefinitionRange() == rCompare.getDefinitionRange()
- && getFillGradient() == rCompare.getFillGradient());
- }
+ const PolyPolygonGradientPrimitive2D& rCompare(
+ static_cast<const PolyPolygonGradientPrimitive2D&>(rPrimitive));
- return false;
-}
+ if (getB2DPolyPolygon() != rCompare.getB2DPolyPolygon())
+ return false;
-// provide unique ID
-sal_uInt32 PolyPolygonGradientPrimitive2D::getPrimitive2DID() const
-{
- return PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D;
-}
+ if (getDefinitionRange() != rCompare.getDefinitionRange())
+ return false;
-Primitive2DReference PolyPolygonRGBAGradientPrimitive2D::create2DDecomposition(
- const geometry::ViewInformation2D& /*rViewInformation*/) const
-{
- Primitive2DContainer aContent{ new PolyPolygonGradientPrimitive2D(
- getB2DPolyPolygon(), getDefinitionRange(), getFillGradient()) };
+ if (getFillGradient() != rCompare.getFillGradient())
+ return false;
- Primitive2DContainer aAlpha{ new FillGradientPrimitive2D(
- basegfx::utils::getRange(getB2DPolyPolygon()), getDefinitionRange(),
- getFillGradientAlpha()) };
+ if (maAlphaGradient != rCompare.maAlphaGradient)
+ return false;
- return Primitive2DReference{ new TransparencePrimitive2D(std::move(aContent),
- std::move(aAlpha)) };
+ return true;
}
-PolyPolygonRGBAGradientPrimitive2D::PolyPolygonRGBAGradientPrimitive2D(
- basegfx::B2DPolyPolygon aPolyPolygon, const basegfx::B2DRange& rDefinitionRange,
- attribute::FillGradientAttribute aFillGradient,
- attribute::FillGradientAttribute aFillGradientAlpha)
- : PolyPolygonGradientPrimitive2D(aPolyPolygon, rDefinitionRange, aFillGradient)
- , maFillGradientAlpha(aFillGradientAlpha)
-{
- // assert when the definition is not allowed, it HAS to fulfil the
- // requested preconditions
- assert(aFillGradient.sameDefinitionThanAlpha(aFillGradientAlpha));
-}
-
-bool PolyPolygonRGBAGradientPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
-{
- if (PolyPolygonGradientPrimitive2D::operator==(rPrimitive))
- {
- const PolyPolygonRGBAGradientPrimitive2D& rCompare
- = static_cast<const PolyPolygonRGBAGradientPrimitive2D&>(rPrimitive);
-
- return getFillGradientAlpha() == rCompare.getFillGradientAlpha();
- }
-
- return false;
-}
-
-sal_uInt32 PolyPolygonRGBAGradientPrimitive2D::getPrimitive2DID() const
+// provide unique ID
+sal_uInt32 PolyPolygonGradientPrimitive2D::getPrimitive2DID() const
{
- return PRIMITIVE2D_ID_POLYPOLYGONRGBAGRADIENTPRIMITIVE2D;
+ return PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D;
}
-
} // end drawinglayer::primitive2d namespace
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/Tools.cxx b/drawinglayer/source/primitive2d/Tools.cxx
index 631ec63e52c1..cef1829e1567 100644
--- a/drawinglayer/source/primitive2d/Tools.cxx
+++ b/drawinglayer/source/primitive2d/Tools.cxx
@@ -233,8 +233,6 @@ OUString idToString(sal_uInt32 nId)
return u"SINGLELINEPRIMITIVE"_ustr;
case PRIMITIVE2D_ID_EXCLUSIVEEDITVIEWPRIMITIVE2D:
return u"EXCLUSIVEEDITVIEWPRIMITIVE2D"_ustr;
- case PRIMITIVE2D_ID_POLYPOLYGONRGBAGRADIENTPRIMITIVE2D:
- return u"POLYPOLYGONRGBAGRADIENTPRIMITIVE2D"_ustr;
case PRIMITIVE2D_ID_ANIMATEDGRAPHICPRIMITIVE2D:
return u"ANIMATEDGRAPHICPRIMITIVE2D"_ustr;
default:
diff --git a/drawinglayer/source/primitive2d/fillgradientprimitive2d.cxx b/drawinglayer/source/primitive2d/fillgradientprimitive2d.cxx
index 255d4fb96a3d..19dfe8482430 100644
--- a/drawinglayer/source/primitive2d/fillgradientprimitive2d.cxx
+++ b/drawinglayer/source/primitive2d/fillgradientprimitive2d.cxx
@@ -24,6 +24,7 @@
#include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx>
#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
#include <drawinglayer/primitive2d/groupprimitive2d.hxx>
+#include <drawinglayer/primitive2d/transparenceprimitive2d.hxx>
#include <utility>
#include <algorithm>
@@ -260,51 +261,86 @@ namespace drawinglayer::primitive2d
Primitive2DReference FillGradientPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
{
+ // 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,
+ // so all processors can work as before
+ if (hasAlphaGradient())
+ {
+ Primitive2DContainer aContent{ new FillGradientPrimitive2D(
+ getOutputRange(),
+ getDefinitionRange(),
+ getFillGradient()) };
+
+ Primitive2DContainer aAlpha{ new FillGradientPrimitive2D(
+ getOutputRange(),
+ getDefinitionRange(),
+ getAlphaGradient()) };
+
+ return Primitive2DReference{ new TransparencePrimitive2D(std::move(aContent),
+ std::move(aAlpha)) };
+ }
+
// default creates overlapping fill which works with AntiAliasing and without.
// The non-overlapping version does not create single filled polygons, but
// PolyPolygons where each one describes a 'ring' for the gradient such
// that the rings will not overlap. This is useful for the old XOR-paint
// 'trick' of VCL which is recorded in Metafiles; so this version may be
// used from the MetafilePrimitive2D in its decomposition.
-
if(!getFillGradient().isDefault())
{
return createFill(/*bOverlapping*/true);
}
+
return nullptr;
}
FillGradientPrimitive2D::FillGradientPrimitive2D(
const basegfx::B2DRange& rOutputRange,
- attribute::FillGradientAttribute aFillGradient)
- : maOutputRange(rOutputRange),
- maDefinitionRange(rOutputRange),
- maFillGradient(std::move(aFillGradient))
+ const attribute::FillGradientAttribute& rFillGradient)
+ : maOutputRange(rOutputRange)
+ , maDefinitionRange(rOutputRange)
+ , maFillGradient(rFillGradient)
+ , maAlphaGradient()
{
}
FillGradientPrimitive2D::FillGradientPrimitive2D(
const basegfx::B2DRange& rOutputRange,
const basegfx::B2DRange& rDefinitionRange,
- attribute::FillGradientAttribute aFillGradient)
- : maOutputRange(rOutputRange),
- maDefinitionRange(rDefinitionRange),
- maFillGradient(std::move(aFillGradient))
+ const attribute::FillGradientAttribute& rFillGradient,
+ const attribute::FillGradientAttribute* pAlphaGradient)
+ : maOutputRange(rOutputRange)
+ , maDefinitionRange(rDefinitionRange)
+ , maFillGradient(rFillGradient)
+ , maAlphaGradient()
{
+ // copy alpha gradient if we got one
+ if (nullptr != pAlphaGradient)
+ maAlphaGradient = *pAlphaGradient;
}
bool FillGradientPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
{
- if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
- {
- const FillGradientPrimitive2D& rCompare = static_cast<const FillGradientPrimitive2D&>(rPrimitive);
+ if(!BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ return false;
- return (getOutputRange() == rCompare.getOutputRange()
- && getDefinitionRange() == rCompare.getDefinitionRange()
- && getFillGradient() == rCompare.getFillGradient());
- }
+ const FillGradientPrimitive2D& rCompare(static_cast<const FillGradientPrimitive2D&>(rPrimitive));
+
+ if (getOutputRange() != rCompare.getOutputRange())
+ return false;
+
+ if (getDefinitionRange() != rCompare.getDefinitionRange())
+ return false;
+
+ if (getFillGradient() != rCompare.getFillGradient())
+ return false;
+
+ if (maAlphaGradient != rCompare.maAlphaGradient)
+ return false;
- return false;
+ return true;
}
basegfx::B2DRange FillGradientPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
diff --git a/drawinglayer/source/processor2d/cairopixelprocessor2d.cxx b/drawinglayer/source/processor2d/cairopixelprocessor2d.cxx
index 034e59dceea4..e49ab17931ab 100644
--- a/drawinglayer/source/processor2d/cairopixelprocessor2d.cxx
+++ b/drawinglayer/source/processor2d/cairopixelprocessor2d.cxx
@@ -763,7 +763,7 @@ void LuminanceToAlpha(cairo_surface_t* pMask)
for (sal_uInt32 x(0); x < nWidth; ++x)
{
// do not forget that we have pre-multiplied alpha
- const sal_uInt8 nAlpha(pMaskPixelData[SVP_CAIRO_ALPHA]);
+ sal_uInt8 nAlpha(pMaskPixelData[SVP_CAIRO_ALPHA]);
if (0 != nAlpha)
{
@@ -772,17 +772,30 @@ void LuminanceToAlpha(cairo_surface_t* pMask)
+ pMaskPixelData[SVP_CAIRO_BLUE] * nBlueMul;
if (255 != nAlpha)
- pMaskPixelData[SVP_CAIRO_ALPHA] = fLuminance / nAlpha;
+ nAlpha = fLuminance / nAlpha;
else
- pMaskPixelData[SVP_CAIRO_ALPHA] = 255.0 * fLuminance;
+ nAlpha = 255.0 * fLuminance;
}
+ pMaskPixelData[SVP_CAIRO_ALPHA] = 255 - nAlpha;
pMaskPixelData += 4;
}
}
cairo_surface_mark_dirty(pMask);
}
+
+basegfx::B2DRange getDiscreteViewRange(cairo_t* pRT)
+{
+ double clip_x1, clip_x2, clip_y1, clip_y2;
+ cairo_save(pRT);
+ cairo_identity_matrix(pRT);
+ cairo_clip_extents(pRT, &clip_x1, &clip_y1, &clip_x2, &clip_y2);
+ cairo_restore(pRT);
+
+ return basegfx::B2DRange(basegfx::B2DPoint(clip_x1, clip_y1),
+ basegfx::B2DPoint(clip_x2, clip_y2));
+}
}
namespace drawinglayer::processor2d
@@ -1093,11 +1106,7 @@ void CairoPixelProcessor2D::processTransparencePrimitive2D(
rTransCandidate.getChildren().getB2DRange(getViewInformation2D()));
aDiscreteRange.transform(getViewInformation2D().getObjectToViewTransformation());
basegfx::B2DRange aVisibleRange(aDiscreteRange);
- double clip_x1, clip_x2, clip_y1, clip_y2;
- cairo_clip_extents(mpRT, &clip_x1, &clip_y1, &clip_x2, &clip_y2);
- const basegfx::B2DRange aViewRange(basegfx::B2DPoint(clip_x1, clip_y1),
- basegfx::B2DPoint(clip_x2, clip_y2));
- aVisibleRange.intersect(aViewRange);
+ aVisibleRange.intersect(getDiscreteViewRange(mpRT));
if (aVisibleRange.isEmpty())
{
@@ -1157,11 +1166,7 @@ void CairoPixelProcessor2D::processInvertPrimitive2D(
rInvertCandidate.getChildren().getB2DRange(getViewInformation2D()));
aDiscreteRange.transform(getViewInformation2D().getObjectToViewTransformation());
basegfx::B2DRange aVisibleRange(aDiscreteRange);
- double clip_x1, clip_x2, clip_y1, clip_y2;
- cairo_clip_extents(mpRT, &clip_x1, &clip_y1, &clip_x2, &clip_y2);
- const basegfx::B2DRange aViewRange(basegfx::B2DPoint(clip_x1, clip_y1),
- basegfx::B2DPoint(clip_x2, clip_y2));
- aVisibleRange.intersect(aViewRange);
+ aVisibleRange.intersect(getDiscreteViewRange(mpRT));
if (aVisibleRange.isEmpty())
{
@@ -1265,9 +1270,7 @@ void CairoPixelProcessor2D::processInvertPrimitive2D(
}
void CairoPixelProcessor2D::processMaskPrimitive2D(
- const primitive2d::MaskPrimitive2D& rMaskCandidate,
- const primitive2d::FillGradientPrimitive2D* pFillGradientPrimitive2D,
- const attribute::FillGradientAttribute* pFillGradientAlpha)
+ const primitive2d::MaskPrimitive2D& rMaskCandidate)
{
if (rMaskCandidate.getChildren().empty())
{
@@ -1284,14 +1287,9 @@ void CairoPixelProcessor2D::processMaskPrimitive2D(
}
// calculate visible range
- double clip_x1, clip_x2, clip_y1, clip_y2;
- cairo_clip_extents(mpRT, &clip_x1, &clip_y1, &clip_x2, &clip_y2);
basegfx::B2DRange aMaskRange(aMask.getB2DRange());
aMaskRange.transform(getViewInformation2D().getObjectToViewTransformation());
- const basegfx::B2DRange aViewRange(basegfx::B2DPoint(clip_x1, clip_y1),
- basegfx::B2DPoint(clip_x2, clip_y2));
-
- if (!aViewRange.overlaps(aMaskRange))
+ if (!getDiscreteViewRange(mpRT).overlaps(aMaskRange))
{
// not visible, done
return;
@@ -1317,20 +1315,12 @@ void CairoPixelProcessor2D::processMaskPrimitive2D(
cairo_clip(mpRT);
cairo_new_path(mpRT);
- if (nullptr != pFillGradientPrimitive2D && nullptr != pFillGradientAlpha)
- {
- // special case: render given FillGradientPrimitive2D using
- // FillGradientAlpha as RGBA gradient directly
- // note that calling this method with nullptr != pFillGradientAlpha
- // is only allowed internal from
- // CairoPixelProcessor2D::processPolyPolygonRGBAGradientPrimitive2D
- processFillGradientPrimitive2D(*pFillGradientPrimitive2D, pFillGradientAlpha);
- }
- else
- {
- // process sub-content (that shall be masked)
- process(rMaskCandidate.getChildren());
- }
+ // reset transformation to not have it set when processing
+ // child content below (was only used to set clip path)
+ cairo_identity_matrix(mpRT);
+
+ // process sub-content (that shall be masked)
+ process(rMaskCandidate.getChildren());
cairo_restore(mpRT);
}
@@ -1396,11 +1386,7 @@ void CairoPixelProcessor2D::processUnifiedTransparencePrimitive2D(
rTransCandidate.getChildren().getB2DRange(getViewInformation2D()));
aDiscreteRange.transform(getViewInformation2D().getObjectToViewTransformation());
basegfx::B2DRange aVisibleRange(aDiscreteRange);
- double clip_x1, clip_x2, clip_y1, clip_y2;
- cairo_clip_extents(mpRT, &clip_x1, &clip_y1, &clip_x2, &clip_y2);
- const basegfx::B2DRange aViewRange(basegfx::B2DPoint(clip_x1, clip_y1),
- basegfx::B2DPoint(clip_x2, clip_y2));
- aVisibleRange.intersect(aViewRange);
+ aVisibleRange.intersect(getDiscreteViewRange(mpRT));
if (aVisibleRange.isEmpty())
{
@@ -1900,7 +1886,28 @@ void CairoPixelProcessor2D::processFillGradientPrimitive2D_drawOutputRange(
// fill simple rect with outer color
const basegfx::BColor aColor(
maBColorModifierStack.getModifiedColor(rFillGradientPrimitive2D.getOuterColor()));
- cairo_set_source_rgb(mpRT, aColor.getRed(), aColor.getGreen(), aColor.getBlue());
+
+ if (rFillGradientPrimitive2D.hasAlphaGradient())
+ {
+ const attribute::FillGradientAttribute& rAlphaGradient(
+ rFillGradientPrimitive2D.getAlphaGradient());
+ double fLuminance(0.0);
+
+ if (!rAlphaGradient.getColorStops().empty())
+ {
+ if (css::awt::GradientStyle_AXIAL == rAlphaGradient.getStyle())
+ fLuminance = rAlphaGradient.getColorStops().back().getStopColor().luminance();
+ else
+ fLuminance = rAlphaGradient.getColorStops().front().getStopColor().luminance();
+ }
+
+ cairo_set_source_rgba(mpRT, aColor.getRed(), aColor.getGreen(), aColor.getBlue(),
+ 1.0 - fLuminance);
+ }
+ else
+ {
+ cairo_set_source_rgb(mpRT, aColor.getRed(), aColor.getGreen(), aColor.getBlue());
+ }
const basegfx::B2DHomMatrix aTrans(getViewInformation2D().getObjectToViewTransformation());
cairo_matrix_t aMatrix;
@@ -1937,9 +1944,12 @@ bool CairoPixelProcessor2D::processFillGradientPrimitive2D_isCompletelyBordered(
}
void CairoPixelProcessor2D::processFillGradientPrimitive2D_linear_axial(
- const primitive2d::FillGradientPrimitive2D& rFillGradientPrimitive2D,
- const attribute::FillGradientAttribute* pFillGradientAlpha)
+ const primitive2d::FillGradientPrimitive2D& rFillGradientPrimitive2D)
{
+ const attribute::FillGradientAttribute& rFillGradient(
+ rFillGradientPrimitive2D.getFillGradient());
+ assert(!rFillGradientPrimitive2D.hasAlphaGradient()
+ || rFillGradient.sameDefinitionThanAlpha(rFillGradientPrimitive2D.getAlphaGradient()));
assert(
(css::awt::GradientStyle_LINEAR == rFillGradientPrimitive2D.getFillGradient().getStyle()
|| css::awt::GradientStyle_AXIAL == rFillGradientPrimitive2D.getFillGradient().getStyle())
@@ -1948,8 +1958,6 @@ void CairoPixelProcessor2D::processFillGradientPrimitive2D_linear_axial(
// need to do 'antique' stuff adaptions for rotate/transitionStart in object coordinates
// (DefinitionRange) to have the right 'bending' on rotation
- const attribute::FillGradientAttribute& rFillGradient(
- rFillGradientPrimitive2D.getFillGradient());
basegfx::B2DRange aAdaptedRange(rFillGradientPrimitive2D.getDefinitionRange());
const double fAngle(basegfx::normalizeToRange((2 * M_PI) - rFillGradient.getAngle(), 2 * M_PI));
const bool bAngle(!basegfx::fTools::equalZero(fAngle));
@@ -1981,9 +1989,9 @@ void CairoPixelProcessor2D::processFillGradientPrimitive2D_linear_axial(
// get color stops (make copy, might have to be changed)
basegfx::BColorStops aBColorStops(rFillGradient.getColorStops());
basegfx::BColorStops aBColorStopsAlpha;
- const bool bHasAlpha(nullptr != pFillGradientAlpha);
+ const bool bHasAlpha(rFillGradientPrimitive2D.hasAlphaGradient());
if (bHasAlpha)
- aBColorStopsAlpha = pFillGradientAlpha->getColorStops();
+ aBColorStopsAlpha = rFillGradientPrimitive2D.getAlphaGradient().getColorStops();
const bool bAxial(css::awt::GradientStyle_AXIAL == rFillGradient.getStyle());
// get and apply border - create soace at start in gradient
@@ -2036,7 +2044,7 @@ void CairoPixelProcessor2D::processFillGradientPrimitive2D_linear_axial(
const basegfx::BColor aAlpha(aBColorStopsAlpha[a].getStopColor());
cairo_pattern_add_color_stop_rgba(pPattern, rStop.getStopOffset(), aColor.getRed(),
aColor.getGreen(), aColor.getBlue(),
- aAlpha.luminance());
+ 1.0 - aAlpha.luminance());
}
else
{
@@ -2066,6 +2074,13 @@ void CairoPixelProcessor2D::processFillGradientPrimitive2D_linear_axial(
void CairoPixelProcessor2D::processFillGradientPrimitive2D_square_rect(
const primitive2d::FillGradientPrimitive2D& rFillGradientPrimitive2D)
{
+ if (rFillGradientPrimitive2D.hasAlphaGradient())
+ {
+ // process recursively
+ process(rFillGradientPrimitive2D);
+ return;
+ }
+
assert(
(css::awt::GradientStyle_SQUARE == rFillGradientPrimitive2D.getFillGradient().getStyle()
|| css::awt::GradientStyle_RECT == rFillGradientPrimitive2D.getFillGradient().getStyle())
@@ -2321,9 +2336,12 @@ void CairoPixelProcessor2D::processFillGradientPrimitive2D_square_rect(
}
void CairoPixelProcessor2D::processFillGradientPrimitive2D_radial_elliptical(
- const primitive2d::FillGradientPrimitive2D& rFillGradientPrimitive2D,
- const attribute::FillGradientAttribute* pFillGradientAlpha)
+ const primitive2d::FillGradientPrimitive2D& rFillGradientPrimitive2D)
{
+ const attribute::FillGradientAttribute& rFillGradient(
+ rFillGradientPrimitive2D.getFillGradient());
+ assert(!rFillGradientPrimitive2D.hasAlphaGradient()
+ || rFillGradient.sameDefinitionThanAlpha(rFillGradientPrimitive2D.getAlphaGradient()));
assert((css::awt::GradientStyle_RADIAL == rFillGradientPrimitive2D.getFillGradient().getStyle()
|| css::awt::GradientStyle_ELLIPTICAL
== rFillGradientPrimitive2D.getFillGradient().getStyle())
@@ -2332,8 +2350,6 @@ void CairoPixelProcessor2D::processFillGradientPrimitive2D_radial_elliptical(
// need to do 'antique' stuff adaptions for rotate/transitionStart in object coordinates
// (DefinitionRange) to have the right 'bending' on rotation
- const attribute::FillGradientAttribute& rFillGradient(
- rFillGradientPrimitive2D.getFillGradient());
const basegfx::B2DRange rDefRange(rFillGradientPrimitive2D.getDefinitionRange());
const basegfx::B2DPoint aCenter(rDefRange.getCenter());
double fRadius(1.0);
@@ -2387,9 +2403,9 @@ void CairoPixelProcessor2D::processFillGradientPrimitive2D_radial_elliptical(
// get color stops (make copy, might have to be changed)
basegfx::BColorStops aBColorStops(rFillGradient.getColorStops());
basegfx::BColorStops aBColorStopsAlpha;
- const bool bHasAlpha(nullptr != pFillGradientAlpha);
+ const bool bHasAlpha(rFillGradientPrimitive2D.hasAlphaGradient());
if (bHasAlpha)
- aBColorStopsAlpha = pFillGradientAlpha->getColorStops();
+ aBColorStopsAlpha = rFillGradientPrimitive2D.getAlphaGradient().getColorStops();
// get and apply border - create soace at start in gradient
const double fBorder(std::max(std::min(rFillGradient.getBorder(), 1.0), 0.0));
@@ -2419,7 +2435,7 @@ void CairoPixelProcessor2D::processFillGradientPrimitive2D_radial_elliptical(
const basegfx::BColor aAlpha(aBColorStopsAlpha[a].getStopColor());
cairo_pattern_add_color_stop_rgba(pPattern, rStop.getStopOffset(), aColor.getRed(),
aColor.getGreen(), aColor.getBlue(),
- aAlpha.luminance());
+ 1.0 - aAlpha.luminance());
}
else
{
@@ -2480,6 +2496,13 @@ void CairoPixelProcessor2D::processFillGradientPrimitive2D_radial_elliptical(
void CairoPixelProcessor2D::processFillGradientPrimitive2D_fallback_decompose(
const primitive2d::FillGradientPrimitive2D& rFillGradientPrimitive2D)
{
+ if (rFillGradientPrimitive2D.hasAlphaGradient())
+ {
+ // process recursively to elliminate alpha, cannot be used in decompose fallback
+ process(rFillGradientPrimitive2D);
+ return;
+ }
+
// this helper draws the given gradient using the decompose fallback,
// maybe needed in some cases an can/will be handy
cairo_save(mpRT);
@@ -2515,8 +2538,7 @@ void CairoPixelProcessor2D::processFillGradientPrimitive2D_fallback_decompose(
}
void CairoPixelProcessor2D::processFillGradientPrimitive2D(
- const primitive2d::FillGradientPrimitive2D& rFillGradientPrimitive2D,
- const attribute::FillGradientAttribute* pFillGradientAlpha)
+ const primitive2d::FillGradientPrimitive2D& rFillGradientPrimitive2D)
{
if (rFillGradientPrimitive2D.getDefinitionRange().isEmpty())
{
@@ -2564,21 +2586,13 @@ void CairoPixelProcessor2D::processFillGradientPrimitive2D(
return;
}
- // for direct RGBA gradient render support: assert when the definition
- // is not allowed, it HAS to fulfil the requested preconditions. Note that
- // the form to call this function using nullptr != pFillGradientAlpha is
- // only allowed locally in CairoPixelProcessor2D::processMaskPrimitive2D
- assert(nullptr == pFillGradientAlpha
- || rFillGradient.sameDefinitionThanAlpha(*pFillGradientAlpha));
-
switch (rFillGradient.getStyle())
{
case css::awt::GradientStyle_LINEAR:
case css::awt::GradientStyle_AXIAL:
{
// use specialized renderer for this cases - linear, axial
- processFillGradientPrimitive2D_linear_axial(rFillGradientPrimitive2D,
- pFillGradientAlpha);
+ processFillGradientPrimitive2D_linear_axial(rFillGradientPrimitive2D);
return;
}
case css::awt::GradientStyle_RADIAL:
@@ -2595,8 +2609,7 @@ void CairoPixelProcessor2D::processFillGradientPrimitive2D(
// also rare. IF that should make problems reactivation of that case
// for the default case below is possible. main reason is that speed
// for direct rendering in cairo is much better.
- processFillGradientPrimitive2D_radial_elliptical(rFillGradientPrimitive2D,
- pFillGradientAlpha);
+ processFillGradientPrimitive2D_radial_elliptical(rFillGradientPrimitive2D);
return;
}
case css::awt::GradientStyle_SQUARE:
@@ -2623,53 +2636,6 @@ void CairoPixelProcessor2D::processFillGradientPrimitive2D(
}
}
-void CairoPixelProcessor2D::processPolyPolygonRGBAGradientPrimitive2D(
- const primitive2d::PolyPolygonRGBAGradientPrimitive2D& rPolyPolygonRGBAGradientPrimitive2D)
-{
- const attribute::FillGradientAttribute& rFill(
- rPolyPolygonRGBAGradientPrimitive2D.getFillGradient());
- const attribute::FillGradientAttribute& rAlpha(
- rPolyPolygonRGBAGradientPrimitive2D.getFillGradientAlpha());
-
- if (rFill.isDefault())
- {
- // no gradient definition, done
- return;
- }
-
- // assert when the definition is not allowed, it HAS to fulfil the
- // requested preconditions
- assert(rFill.sameDefinitionThanAlpha(rAlpha));
-
- // the gradient still needs to be masked to getB2DPolyPolygon() at the
- // primitive, see PolyPolygonGradientPrimitive2D::create2DDecomposition.
- // we could repeat here the code inside localprocessMaskPrimitive2D, but
- // it is easier to just locally temporarily create the needed data structure
- // and hand over the needed extra-data
- const basegfx::B2DRange aPolyPolygonRange(
- rPolyPolygonRGBAGradientPrimitive2D.getB2DPolyPolygon().getB2DRange());
- primitive2d::FillGradientPrimitive2D* pFillGradientPrimitive2D(
- new primitive2d::FillGradientPrimitive2D(
- aPolyPolygonRange, rPolyPolygonRGBAGradientPrimitive2D.getDefinitionRange(), rFill));
- primitive2d::Primitive2DContainer aContent{ pFillGradientPrimitive2D };
-
- // NOTE: I had this like
- // const primitive2d::MaskPrimitive2D aMaskPrimitive2D(
- // rPolyPolygonRGBAGradientPrimitive2D.getB2DPolyPolygon(), std::move(aContent));
- // but I got
- // error: salhelper::SimpleReferenceObject subclass being directly stack managed, should
- // be managed via rtl::Reference, const primitive2d::MaskPrimitive2D [loplugin:refcounting]
- // thus I have *no choice* and have to use the heap here (?) It is no problem to use the stack
- // and I wanted to do this here by purpose... sigh
- primitive2d::MaskPrimitive2D* pMaskPrimitive2D(new primitive2d::MaskPrimitive2D(
- rPolyPolygonRGBAGradientPrimitive2D.getB2DPolyPolygon(), std::move(aContent)));
- primitive2d::Primitive2DContainer aMask{ pMaskPrimitive2D };
- (void)aMask;
-
- // render masked RGBA gradient
- processMaskPrimitive2D(*pMaskPrimitive2D, pFillGradientPrimitive2D, &rAlpha);
-}
-
void CairoPixelProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate)
{
switch (rCandidate.getPrimitive2DID())
@@ -2729,6 +2695,7 @@ void CairoPixelProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimit
static_cast<const primitive2d::TransformPrimitive2D&>(rCandidate));
break;
}
+
// geometry that *may* be processed due to being able to do it better
// then using the decomposition
case PRIMITIVE2D_ID_UNIFIEDTRANSPARENCEPRIMITIVE2D:
@@ -2785,12 +2752,6 @@ void CairoPixelProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimit
static_cast<const primitive2d::FillGradientPrimitive2D&>(rCandidate));
break;
}
- case PRIMITIVE2D_ID_POLYPOLYGONRGBAGRADIENTPRIMITIVE2D:
- {
- processPolyPolygonRGBAGradientPrimitive2D(
- static_cast<const primitive2d::PolyPolygonRGBAGradientPrimitive2D&>(rCandidate));
- break;
- }
// continue with decompose
default:
diff --git a/drawinglayer/source/processor2d/d2dpixelprocessor2d.cxx b/drawinglayer/source/processor2d/d2dpixelprocessor2d.cxx
index e9bcc6c10423..7bc422a98f43 100644
--- a/drawinglayer/source/processor2d/d2dpixelprocessor2d.cxx
+++ b/drawinglayer/source/processor2d/d2dpixelprocessor2d.cxx
@@ -1926,6 +1926,14 @@ void D2DPixelProcessor2D::processFillGraphicPrimitive2D(
void D2DPixelProcessor2D::processFillGradientPrimitive2D(
const primitive2d::FillGradientPrimitive2D& rFillGradientPrimitive2D)
{
+ if (rFillGradientPrimitive2D.hasAlphaGradient())
+ {
+ // SDPR: As long as direct alpha is not supported by this
+ // renderer we need to work on the decomposition, so call it
+ process(rFillGradientPrimitive2D);
+ return;
+ }
+
// draw all-covering initial BG polygon 1st
bool bDone(drawPolyPolygonColorTransformed(
basegfx::B2DHomMatrix(),
diff --git a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
index f09131b04c30..ea0bea62b0fa 100644
--- a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
+++ b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
@@ -930,6 +930,14 @@ void VclPixelProcessor2D::processMetaFilePrimitive2D(const primitive2d::BasePrim
void VclPixelProcessor2D::processFillGradientPrimitive2D(
const primitive2d::FillGradientPrimitive2D& rPrimitive)
{
+ if (rPrimitive.hasAlphaGradient())
+ {
+ // SDPR: As long as direct alpha is not supported by this
+ // renderer we need to work on the decomposition, so call it
+ process(rPrimitive);
+ return;
+ }
+
const attribute::FillGradientAttribute& rFillGradient = rPrimitive.getFillGradient();
bool useDecompose(false);