drawinglayer/source/processor2d/cairopixelprocessor2d.cxx |  148 +++++++++++++-
 include/vcl/BitmapTools.hxx                               |    4 
 vcl/headless/CairoCommon.cxx                              |    6 
 3 files changed, 145 insertions(+), 13 deletions(-)

New commits:
commit 7c3a255e42f17c312af26684c2aed567c1c5a5a3
Author:     Caolán McNamara <[email protected]>
AuthorDate: Thu Dec 22 14:41:37 2022 +0000
Commit:     Caolán McNamara <[email protected]>
CommitDate: Fri Dec 23 10:20:45 2022 +0000

    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 <[email protected]>

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);
 
commit 376c561922875df5712742c8cbd19a8c39495a21
Author:     Caolán McNamara <[email protected]>
AuthorDate: Thu Dec 22 18:48:49 2022 +0000
Commit:     Caolán McNamara <[email protected]>
CommitDate: Fri Dec 23 10:20:38 2022 +0000

    can improve scope
    
    Change-Id: Ied189c410b21272b5fad47c3d4b11e85a534cc38
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/144773
    Tested-by: Jenkins
    Reviewed-by: Caolán McNamara <[email protected]>

diff --git a/vcl/headless/CairoCommon.cxx b/vcl/headless/CairoCommon.cxx
index 4f3a4e869746..511799dff9ce 100644
--- a/vcl/headless/CairoCommon.cxx
+++ b/vcl/headless/CairoCommon.cxx
@@ -899,12 +899,10 @@ basegfx::B2DRange renderWithOperator(cairo_t* cr, const 
SalTwoRect& rTR, cairo_s
     cairo_clip(cr);
 
     cairo_translate(cr, rTR.mnDestX, rTR.mnDestY);
-    double fXScale = 1.0f;
-    double fYScale = 1.0f;
     if (rTR.mnSrcWidth != 0 && rTR.mnSrcHeight != 0)
     {
-        fXScale = static_cast<double>(rTR.mnDestWidth) / rTR.mnSrcWidth;
-        fYScale = static_cast<double>(rTR.mnDestHeight) / rTR.mnSrcHeight;
+        double fXScale = static_cast<double>(rTR.mnDestWidth) / rTR.mnSrcWidth;
+        double fYScale = static_cast<double>(rTR.mnDestHeight) / 
rTR.mnSrcHeight;
         cairo_scale(cr, fXScale, fYScale);
     }
 

Reply via email to