summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCaolán McNamara <caolanm@redhat.com>2022-12-22 14:41:37 +0000
committerCaolán McNamara <caolanm@redhat.com>2022-12-23 10:20:45 +0000
commit7c3a255e42f17c312af26684c2aed567c1c5a5a3 (patch)
tree7aac9a13c0bd3bccadfc5b847236d5760dd9c3e2
parent376c561922875df5712742c8cbd19a8c39495a21 (diff)
SDPR: Add rendering of BitmapPrimitive2D for Cairo
pretty nasty copy of bitmap data for split alpha and so on, head scratching for a while to figure out to scale the pattern matrix, but it seems to render ok Change-Id: I6c82953e3646556ece6b1a5a6b12b7f76b0d41c6 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/144774 Tested-by: Jenkins Reviewed-by: Caolán McNamara <caolanm@redhat.com>
-rw-r--r--drawinglayer/source/processor2d/cairopixelprocessor2d.cxx148
-rw-r--r--include/vcl/BitmapTools.hxx4
2 files changed, 143 insertions, 9 deletions
diff --git a/drawinglayer/source/processor2d/cairopixelprocessor2d.cxx b/drawinglayer/source/processor2d/cairopixelprocessor2d.cxx
index 278b55f86723..9235bc095c81 100644
--- a/drawinglayer/source/processor2d/cairopixelprocessor2d.cxx
+++ b/drawinglayer/source/processor2d/cairopixelprocessor2d.cxx
@@ -11,6 +11,7 @@
#include <drawinglayer/processor2d/cairopixelprocessor2d.hxx>
#include <sal/log.hxx>
+#include <vcl/BitmapTools.hxx>
#include <vcl/cairo.hxx>
#include <vcl/outdev.hxx>
#include <vcl/svapp.hxx>
@@ -160,6 +161,65 @@ void addB2DPolygonToPathGeometry(cairo_t* cr, const basegfx::B2DPolygon& rPolygo
cairo_close_path(cr);
}
}
+
+// split alpha remains as a constant irritant
+std::vector<sal_uInt8> createBitmapData(const BitmapEx& rBitmapEx)
+{
+ const Size& rSizePixel(rBitmapEx.GetSizePixel());
+ const bool bAlpha(rBitmapEx.IsAlpha());
+ const sal_uInt32 nStride
+ = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, rSizePixel.Width());
+ std::vector<sal_uInt8> aData(nStride * rSizePixel.Height());
+
+ if (bAlpha)
+ {
+ Bitmap aSrcAlpha(rBitmapEx.GetAlpha().GetBitmap());
+ Bitmap::ScopedReadAccess pReadAccess(const_cast<Bitmap&>(rBitmapEx.GetBitmap()));
+ Bitmap::ScopedReadAccess pAlphaReadAccess(bAlpha ? aSrcAlpha.AcquireReadAccess() : nullptr,
+ aSrcAlpha);
+ const tools::Long nHeight(pReadAccess->Height());
+ const tools::Long nWidth(pReadAccess->Width());
+
+ for (tools::Long y = 0; y < nHeight; ++y)
+ {
+ unsigned char* pPixelData = aData.data() + (nStride * y);
+ for (tools::Long x = 0; x < nWidth; ++x)
+ {
+ const BitmapColor aColor(pReadAccess->GetColor(y, x));
+ const BitmapColor aAlpha(pAlphaReadAccess->GetColor(y, x));
+ const sal_uInt16 nAlpha(255 - aAlpha.GetRed());
+
+ pPixelData[SVP_CAIRO_RED] = vcl::bitmap::premultiply(nAlpha, aColor.GetRed());
+ pPixelData[SVP_CAIRO_GREEN] = vcl::bitmap::premultiply(nAlpha, aColor.GetGreen());
+ pPixelData[SVP_CAIRO_BLUE] = vcl::bitmap::premultiply(nAlpha, aColor.GetBlue());
+ pPixelData[SVP_CAIRO_ALPHA] = nAlpha;
+ pPixelData += 4;
+ }
+ }
+ }
+ else
+ {
+ Bitmap::ScopedReadAccess pReadAccess(const_cast<Bitmap&>(rBitmapEx.GetBitmap()));
+ const tools::Long nHeight(pReadAccess->Height());
+ const tools::Long nWidth(pReadAccess->Width());
+
+ for (tools::Long y = 0; y < nHeight; ++y)
+ {
+ unsigned char* pPixelData = aData.data() + (nStride * y);
+ for (tools::Long x = 0; x < nWidth; ++x)
+ {
+ const BitmapColor aColor(pReadAccess->GetColor(y, x));
+ pPixelData[SVP_CAIRO_RED] = aColor.GetRed();
+ pPixelData[SVP_CAIRO_GREEN] = aColor.GetGreen();
+ pPixelData[SVP_CAIRO_BLUE] = aColor.GetBlue();
+ pPixelData[SVP_CAIRO_ALPHA] = 255;
+ pPixelData += 4;
+ }
+ }
+ }
+
+ return aData;
+}
}
namespace drawinglayer::processor2d
@@ -267,15 +327,91 @@ void CairoPixelProcessor2D::processPolyPolygonColorPrimitive2D(
cairo_restore(mpRT);
}
-#if 0
-
void CairoPixelProcessor2D::processBitmapPrimitive2D(
const primitive2d::BitmapPrimitive2D& rBitmapCandidate)
{
- // TODO: All the smarts to get/make a cairo_surface_t from a BitmapEx is internal to vcl at the moment
-}
+ // check if graphic content is inside discrete local ViewPort
+ const basegfx::B2DRange& rDiscreteViewPort(getViewInformation2D().getDiscreteViewport());
+ const basegfx::B2DHomMatrix aLocalTransform(
+ getViewInformation2D().getObjectToViewTransformation() * rBitmapCandidate.getTransform());
-#endif
+ if (!rDiscreteViewPort.isEmpty())
+ {
+ basegfx::B2DRange aUnitRange(0.0, 0.0, 1.0, 1.0);
+
+ aUnitRange.transform(aLocalTransform);
+
+ if (!aUnitRange.overlaps(rDiscreteViewPort))
+ {
+ // content is outside discrete local ViewPort
+ return;
+ }
+ }
+
+ BitmapEx aBitmapEx(rBitmapCandidate.getBitmap());
+
+ if (aBitmapEx.IsEmpty() || aBitmapEx.GetSizePixel().IsEmpty())
+ {
+ return;
+ }
+
+ if (maBColorModifierStack.count())
+ {
+ aBitmapEx = aBitmapEx.ModifyBitmapEx(maBColorModifierStack);
+
+ if (aBitmapEx.IsEmpty())
+ {
+ // color gets completely replaced, get it
+ const basegfx::BColor aModifiedColor(
+ maBColorModifierStack.getModifiedColor(basegfx::BColor()));
+ basegfx::B2DPolygon aPolygon(basegfx::utils::createUnitPolygon());
+ aPolygon.transform(aLocalTransform);
+
+ // shortcut with local temporary instance
+ rtl::Reference<primitive2d::PolyPolygonColorPrimitive2D> xTemp(
+ new primitive2d::PolyPolygonColorPrimitive2D(basegfx::B2DPolyPolygon(aPolygon),
+ aModifiedColor));
+ processPolyPolygonColorPrimitive2D(*xTemp);
+ return;
+ }
+ }
+
+ // nasty copy of bitmap data
+ std::vector<sal_uInt8> aPixelData(createBitmapData(aBitmapEx));
+ const Size& rSizePixel(aBitmapEx.GetSizePixel());
+ cairo_surface_t* pBitmapSurface = cairo_image_surface_create_for_data(
+ aPixelData.data(), CAIRO_FORMAT_ARGB32, rSizePixel.Width(), rSizePixel.Height(),
+ cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, rSizePixel.Width()));
+
+ cairo_save(mpRT);
+
+ cairo_matrix_t aMatrix;
+ const double fAAOffset(getViewInformation2D().getUseAntiAliasing() ? 0.5 : 0.0);
+ cairo_matrix_init(&aMatrix, aLocalTransform.a(), aLocalTransform.b(), aLocalTransform.c(),
+ aLocalTransform.d(), aLocalTransform.e() + fAAOffset,
+ aLocalTransform.f() + fAAOffset);
+
+ // set linear transformation
+ cairo_set_matrix(mpRT, &aMatrix);
+
+ // destinationRectangle is part of transformation above, so use UnitRange
+ cairo_rectangle(mpRT, 0, 0, 1, 1);
+ cairo_clip(mpRT);
+
+ cairo_set_source_surface(mpRT, pBitmapSurface, 0, 0);
+ // get the pattern created by cairo_set_source_surface
+ cairo_pattern_t* sourcepattern = cairo_get_source(mpRT);
+ cairo_pattern_get_matrix(sourcepattern, &aMatrix);
+ // scale to match the current transformation
+ cairo_matrix_scale(&aMatrix, rSizePixel.Width(), rSizePixel.Height());
+ cairo_pattern_set_matrix(sourcepattern, &aMatrix);
+
+ cairo_paint(mpRT);
+
+ cairo_surface_destroy(pBitmapSurface);
+
+ cairo_restore(mpRT);
+}
namespace
{
@@ -717,7 +853,6 @@ void CairoPixelProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimit
{
switch (rCandidate.getPrimitive2DID())
{
-#if 0
// geometry that *has* to be processed
case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D:
{
@@ -725,7 +860,6 @@ void CairoPixelProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimit
static_cast<const primitive2d::BitmapPrimitive2D&>(rCandidate));
break;
}
-#endif
case PRIMITIVE2D_ID_POINTARRAYPRIMITIVE2D:
{
processPointArrayPrimitive2D(
diff --git a/include/vcl/BitmapTools.hxx b/include/vcl/BitmapTools.hxx
index 36ccd707a62d..d43e9dc7a692 100644
--- a/include/vcl/BitmapTools.hxx
+++ b/include/vcl/BitmapTools.hxx
@@ -35,8 +35,8 @@ VCL_DLLPUBLIC lookup_table const & get_premultiply_table();
VCL_DLLPUBLIC lookup_table const & get_unpremultiply_table();
#endif
-sal_uInt8 unpremultiply(sal_uInt8 c, sal_uInt8 a);
-sal_uInt8 premultiply(sal_uInt8 c, sal_uInt8 a);
+VCL_DLLPUBLIC sal_uInt8 unpremultiply(sal_uInt8 c, sal_uInt8 a);
+VCL_DLLPUBLIC sal_uInt8 premultiply(sal_uInt8 c, sal_uInt8 a);
BitmapEx VCL_DLLPUBLIC loadFromName(const OUString& rFileName, const ImageLoadFlags eFlags = ImageLoadFlags::NONE);