[Libreoffice-commits] core.git: Branch 'aoo/trunk' - vcl/inc vcl/source

Armin Le Grand alg at apache.org
Tue Aug 27 07:07:43 PDT 2013


 vcl/inc/vcl/bitmapex.hxx    |   23 +++++
 vcl/inc/vcl/bmpacc.hxx      |   10 ++
 vcl/source/gdi/bitmapex.cxx |  176 ++++++++++++--------------------------------
 vcl/source/gdi/bmpacc.cxx   |  120 ++++++++++++++++++++++++++++++
 vcl/source/gdi/outdev2.cxx  |  125 ++++++++++++++++++++++++++++---
 5 files changed, 313 insertions(+), 141 deletions(-)

New commits:
commit 75e9010730525ed6122655ac3c3899359c305104
Author: Armin Le Grand <alg at apache.org>
Date:   Tue Aug 27 12:46:41 2013 +0000

    i122778 Enhanced own transformer for drawing transformed bitmaps which is used in the cases where no fallback for direct system support is there (Linux)

diff --git a/vcl/inc/vcl/bitmapex.hxx b/vcl/inc/vcl/bitmapex.hxx
index a7663bd..cfc7a8f 100644
--- a/vcl/inc/vcl/bitmapex.hxx
+++ b/vcl/inc/vcl/bitmapex.hxx
@@ -393,25 +393,42 @@ public:
         @param rTransformation
         The back transformation for each pixel in (0 .. fWidth),(0 .. fHeight) to
         local pixel coordiantes
+
+        @param bSmooth
+        Defines if pixel interpolation is to be used to create the result
     */
     BitmapEx TransformBitmapEx(
         double fWidth,
         double fHeight,
-        const basegfx::B2DHomMatrix& rTransformation) const;
+        const basegfx::B2DHomMatrix& rTransformation,
+        bool bSmooth = true) const;
 
     /** Create transformed Bitmap
 
         @param rTransformation
-        The transformation from unit coordinates to target
+        The transformation from unit coordinates to the unit range
+
+        @param rVisibleRange
+        The relative visible range in unit coordinates, relative to (0,0,1,1) which
+        defines the whole target area
 
         @param fMaximumArea
         A limitation for the maximum size of pixels to use for the result
 
+        @param bSmooth
+        Defines if pixel interpolation is to be used to create the result
+
+        The traget size of the result bitmap is defined by transforming the given
+        rTargetRange with the given rTransformation; the area of the result is
+        linearly scaled to not exceed the given fMaximumArea
+
         @return The transformed bitmap
     */
     BitmapEx getTransformed(
         const basegfx::B2DHomMatrix& rTransformation,
-        double fMaximumArea = 500000.0) const;
+        const basegfx::B2DRange& rVisibleRange,
+        double fMaximumArea = 500000.0,
+        bool bSmooth = true) const;
 
     /** Create ColorStack-modified version of this BitmapEx
 
diff --git a/vcl/inc/vcl/bmpacc.hxx b/vcl/inc/vcl/bmpacc.hxx
index c22e865..2a51304 100644
--- a/vcl/inc/vcl/bmpacc.hxx
+++ b/vcl/inc/vcl/bmpacc.hxx
@@ -171,6 +171,16 @@ public:
     inline BitmapColor          GetColor( long nY, long nX ) const;
     inline sal_uInt8            GetPixelIndex( long nY, long nX ) const;
     inline sal_uInt8            GetLuminance( long nY, long nX ) const;
+
+    /** Get the interpolated color at coordinates fY, fX; if outside, return rFallback */
+    BitmapColor GetInterpolatedColorWithFallback( double fY, double fX, const BitmapColor& rFallback ) const;
+
+    /** Get the color at coordinates fY, fX; if outside, return rFallback. Automatically does the correct
+        inside/outside checks, e.g. static_cast< sal_uInt32 >(-0.25) *is* 0, not -1 and has to be outside */
+    BitmapColor GetColorWithFallback( double fY, double fX, const BitmapColor& rFallback ) const;
+
+    /** Get the color at coordinates nY, nX; if outside, return rFallback */
+    BitmapColor GetColorWithFallback( long nY, long nX, const BitmapColor& rFallback ) const;
 };
 
 // ---------------------
diff --git a/vcl/source/gdi/bitmapex.cxx b/vcl/source/gdi/bitmapex.cxx
index 6925142..5e34624b 100644
--- a/vcl/source/gdi/bitmapex.cxx
+++ b/vcl/source/gdi/bitmapex.cxx
@@ -837,87 +837,6 @@ sal_uInt8 BitmapEx::GetTransparency(sal_Int32 nX, sal_Int32 nY) const
 
 namespace
 {
-    void impSmoothPoint(BitmapColor& rValue, const basegfx::B2DPoint& rSource, sal_Int32 nIntX, sal_Int32 nIntY, BitmapReadAccess& rRead)
-    {
-        double fDeltaX(rSource.getX() - nIntX);
-        double fDeltaY(rSource.getY() - nIntY);
-        sal_Int32 nIndX(0L);
-        sal_Int32 nIndY(0L);
-
-        if(fDeltaX > 0.0 && nIntX + 1L < rRead.Width())
-        {
-            nIndX++;
-        }
-        else if(fDeltaX < 0.0 && nIntX >= 1L)
-        {
-            fDeltaX = -fDeltaX;
-            nIndX--;
-        }
-
-        if(fDeltaY > 0.0 && nIntY + 1L < rRead.Height())
-        {
-            nIndY++;
-        }
-        else if(fDeltaY < 0.0 && nIntY >= 1L)
-        {
-            fDeltaY = -fDeltaY;
-            nIndY--;
-        }
-
-        if(nIndX || nIndY)
-        {
-            const double fColorToReal(1.0 / 255.0);
-            double fR(rValue.GetRed() * fColorToReal);
-            double fG(rValue.GetGreen() * fColorToReal);
-            double fB(rValue.GetBlue() * fColorToReal);
-            double fRBottom(0.0), fGBottom(0.0), fBBottom(0.0);
-
-            if(nIndX)
-            {
-                const double fMulA(fDeltaX * fColorToReal);
-                double fMulB(1.0 - fDeltaX);
-                const BitmapColor aTopPartner(rRead.GetColor(nIntY, nIntX + nIndX));
-
-                fR = (fR * fMulB) + (aTopPartner.GetRed() * fMulA);
-                fG = (fG * fMulB) + (aTopPartner.GetGreen() * fMulA);
-                fB = (fB * fMulB) + (aTopPartner.GetBlue() * fMulA);
-
-                if(nIndY)
-                {
-                    fMulB *= fColorToReal;
-                    const BitmapColor aBottom(rRead.GetColor(nIntY + nIndY, nIntX));
-                    const BitmapColor aBottomPartner(rRead.GetColor(nIntY + nIndY, nIntX + nIndX));
-
-                    fRBottom = (aBottom.GetRed() * fMulB) + (aBottomPartner.GetRed() * fMulA);
-                    fGBottom = (aBottom.GetGreen() * fMulB) + (aBottomPartner.GetGreen() * fMulA);
-                    fBBottom = (aBottom.GetBlue() * fMulB) + (aBottomPartner.GetBlue() * fMulA);
-                }
-            }
-
-            if(nIndY)
-            {
-                if(!nIndX)
-                {
-                    const BitmapColor aBottom(rRead.GetColor(nIntY + nIndY, nIntX));
-
-                    fRBottom = aBottom.GetRed() * fColorToReal;
-                    fGBottom = aBottom.GetGreen() * fColorToReal;
-                    fBBottom = aBottom.GetBlue() * fColorToReal;
-                }
-
-                const double fMulB(1.0 - fDeltaY);
-
-                fR = (fR * fMulB) + (fRBottom * fDeltaY);
-                fG = (fG * fMulB) + (fGBottom * fDeltaY);
-                fB = (fB * fMulB) + (fBBottom * fDeltaY);
-            }
-
-            rValue.SetRed((sal_uInt8)(fR * 255.0));
-            rValue.SetGreen((sal_uInt8)(fG * 255.0));
-            rValue.SetBlue((sal_uInt8)(fB * 255.0));
-        }
-    }
-
     Bitmap impTransformBitmap(
         const Bitmap& rSource,
         const Size aDestinationSize,
@@ -929,54 +848,41 @@ namespace
 
         if(pWrite)
         {
-            const Size aContentSizePixel(rSource.GetSizePixel());
+            //const Size aContentSizePixel(rSource.GetSizePixel());
             BitmapReadAccess* pRead = (const_cast< Bitmap& >(rSource)).AcquireReadAccess();
 
             if(pRead)
             {
                 const Size aDestinationSizePixel(aDestination.GetSizePixel());
-                bool bWorkWithIndex(rSource.GetBitCount() <= 8);
-                BitmapColor aOutside(BitmapColor(0xff, 0xff, 0xff));
+                const BitmapColor aOutside(BitmapColor(0xff, 0xff, 0xff));
 
                 for(sal_Int32 y(0L); y < aDestinationSizePixel.getHeight(); y++)
                 {
                     for(sal_Int32 x(0L); x < aDestinationSizePixel.getWidth(); x++)
                     {
                         const basegfx::B2DPoint aSourceCoor(rTransform * basegfx::B2DPoint(x, y));
-                        const sal_Int32 nIntX(basegfx::fround(aSourceCoor.getX()));
 
-                        if(nIntX >= 0L && nIntX < aContentSizePixel.getWidth())
+                        if(bSmooth)
                         {
-                            const sal_Int32 nIntY(basegfx::fround(aSourceCoor.getY()));
-
-                            if(nIntY >= 0L && nIntY < aContentSizePixel.getHeight())
-                            {
-                                // inside pixel
-                                BitmapColor aValue;
-
-                                if(bWorkWithIndex)
-                                {
-                                    aValue = pRead->GetPaletteColor(pRead->GetPixelIndex(nIntY, nIntX));
-                                }
-                                else
-                                {
-                                    aValue = pRead->GetPixel(nIntY, nIntX);
-                                }
-
-                                if(bSmooth)
-                                {
-                                    impSmoothPoint(aValue, aSourceCoor, nIntX, nIntY, *pRead);
-                                }
-
-                                pWrite->SetPixel(y, x, aValue);
-                                continue;
-                            }
+                            pWrite->SetPixel(
+                                y,
+                                x,
+                                pRead->GetInterpolatedColorWithFallback(
+                                    aSourceCoor.getY(),
+                                    aSourceCoor.getX(),
+                                    aOutside));
                         }
-
-                        // here are outside pixels. Complete mask
-                        if(bWorkWithIndex)
+                        else
                         {
-                            pWrite->SetPixel(y, x, aOutside);
+                            // this version does the correct <= 0.0 checks, so no need
+                            // to do the static_cast< sal_Int32 > self and make an error
+                            pWrite->SetPixel(
+                                y,
+                                x,
+                                pRead->GetColorWithFallback(
+                                    aSourceCoor.getY(),
+                                    aSourceCoor.getX(),
+                                    aOutside));
                         }
                     }
                 }
@@ -992,25 +898,26 @@ namespace
         return aDestination;
     }
 } // end of anonymous namespace
+
 BitmapEx BitmapEx::TransformBitmapEx(
     double fWidth,
     double fHeight,
-    const basegfx::B2DHomMatrix& rTransformation) const
+    const basegfx::B2DHomMatrix& rTransformation,
+    bool bSmooth) const
 {
     if(fWidth <= 1 || fHeight <= 1)
         return BitmapEx();
 
     // force destination to 24 bit, we want to smooth output
     const Size aDestinationSize(basegfx::fround(fWidth), basegfx::fround(fHeight));
-    static bool bDoSmoothAtAll(true);
-    const Bitmap aDestination(impTransformBitmap(GetBitmap(), aDestinationSize, rTransformation, bDoSmoothAtAll));
+    const Bitmap aDestination(impTransformBitmap(GetBitmap(), aDestinationSize, rTransformation, bSmooth));
 
     // create mask
     if(IsTransparent())
     {
         if(IsAlpha())
         {
-            const Bitmap aAlpha(impTransformBitmap(GetAlpha().GetBitmap(), aDestinationSize, rTransformation, bDoSmoothAtAll));
+            const Bitmap aAlpha(impTransformBitmap(GetAlpha().GetBitmap(), aDestinationSize, rTransformation, bSmooth));
             return BitmapEx(aDestination, AlphaMask(aAlpha));
         }
         else
@@ -1027,7 +934,9 @@ BitmapEx BitmapEx::TransformBitmapEx(
 
 BitmapEx BitmapEx::getTransformed(
     const basegfx::B2DHomMatrix& rTransformation,
-    double fMaximumArea) const
+    const basegfx::B2DRange& rVisibleRange,
+    double fMaximumArea,
+    bool bSmooth) const
 {
     BitmapEx aRetval;
 
@@ -1040,20 +949,31 @@ BitmapEx BitmapEx::getTransformed(
     if(!nSourceWidth || !nSourceHeight)
         return aRetval;
 
-    // Get dest range
+    // Get aOutlineRange
     basegfx::B2DRange aOutlineRange(0.0, 0.0, 1.0, 1.0);
+
     aOutlineRange.transform(rTransformation);
 
-    // get target size
-    double fWidth(aOutlineRange.getWidth());
-    double fHeight(aOutlineRange.getHeight());
+    // create visible range from it by moving from relative to absolute
+    basegfx::B2DRange aVisibleRange(rVisibleRange);
+
+    aVisibleRange.transform(
+        basegfx::tools::createScaleTranslateB2DHomMatrix(
+            aOutlineRange.getRange(),
+            aOutlineRange.getMinimum()));
+
+    // get target size (which is visible range's size)
+    double fWidth(aVisibleRange.getWidth());
+    double fHeight(aVisibleRange.getHeight());
 
     if(fWidth < 1.0 || fHeight < 1.0)
+    {
         return aRetval;
+    }
 
     // test if discrete size (pixel) maybe too big and limit it
     const double fArea(fWidth * fHeight);
-    const bool bNeedToReduce(fArea > fMaximumArea);
+    const bool bNeedToReduce(basegfx::fTools::more(fArea, fMaximumArea));
     double fReduceFactor(1.0);
 
     if(bNeedToReduce)
@@ -1074,8 +994,10 @@ BitmapEx BitmapEx::getTransformed(
     // aOutlineRange
     aTransform = rTransformation * aTransform;
 
-    // substract top-left of aOutlineRange
-    aTransform.translate(-aOutlineRange.getMinX(), -aOutlineRange.getMinY());
+    // substract top-left of absolute VisibleRange
+    aTransform.translate(
+        -aVisibleRange.getMinX(),
+        -aVisibleRange.getMinY());
 
     // scale to target pixels (if needed)
     if(bNeedToReduce)
@@ -1087,7 +1009,7 @@ BitmapEx BitmapEx::getTransformed(
     aTransform.invert();
 
     // create bitmap using source, destination and linear back-transformation
-    aRetval = TransformBitmapEx(fWidth, fHeight, aTransform);
+    aRetval = TransformBitmapEx(fWidth, fHeight, aTransform, bSmooth);
 
     return aRetval;
 }
diff --git a/vcl/source/gdi/bmpacc.cxx b/vcl/source/gdi/bmpacc.cxx
index ae41737..9e2ab2d 100644
--- a/vcl/source/gdi/bmpacc.cxx
+++ b/vcl/source/gdi/bmpacc.cxx
@@ -324,6 +324,126 @@ sal_uInt16 BitmapReadAccess::GetBestPaletteIndex( const BitmapColor& rBitmapColo
     return( HasPalette() ? mpBuffer->maPalette.GetBestIndex( rBitmapColor ) : 0 );
 }
 
+BitmapColor BitmapReadAccess::GetInterpolatedColorWithFallback( double fY, double fX, const BitmapColor& rFallback ) const
+{
+    // ask directly doubles >= 0.0 here to avoid rounded values of 0 at small negative
+    // double values, e.g. static_cast< sal_Int32 >(-0.25) is 0, not -1, but *has* to be outside (!)
+    if(mpBuffer && fX >= 0.0 && fY >= 0.0)
+    {
+        const sal_Int32 nX(static_cast< sal_Int32 >(fX));
+        const sal_Int32 nY(static_cast< sal_Int32 >(fY));
+
+        if(nX < mpBuffer->mnWidth && nY < mpBuffer->mnHeight)
+        {
+            // get base-return value from inside pixel
+            BitmapColor aRetval(GetColor(nY, nX));
+
+            // calculate deltas and indices for neighbour accesses
+            sal_Int16 nDeltaX((fX - (nX + 0.5)) * 255.0); // [-255 .. 255]
+            sal_Int16 nDeltaY((fY - (nY + 0.5)) * 255.0); // [-255 .. 255]
+            sal_Int16 nIndX(0);
+            sal_Int16 nIndY(0);
+
+            if(nDeltaX > 0)
+            {
+                nIndX = nX + 1;
+            }
+            else
+            {
+                nIndX = nX - 1;
+                nDeltaX = -nDeltaX;
+            }
+
+            if(nDeltaY > 0)
+            {
+                nIndY = nY + 1;
+            }
+            else
+            {
+                nIndY = nY - 1;
+                nDeltaY = -nDeltaY;
+            }
+
+            // get right/left neighbour
+            BitmapColor aXCol(rFallback);
+
+            if(nDeltaX && nIndX >= 0 && nIndX < mpBuffer->mnWidth)
+            {
+                aXCol = GetColor(nY, nIndX);
+            }
+
+            // get top/bottom neighbour
+            BitmapColor aYCol(rFallback);
+
+            if(nDeltaY && nIndY >= 0 && nIndY < mpBuffer->mnHeight)
+            {
+                aYCol = GetColor(nIndY, nX);
+            }
+
+            // get one of four edge neighbours
+            BitmapColor aXYCol(rFallback);
+
+            if(nDeltaX && nDeltaY && nIndX >=0 && nIndY >= 0 && nIndX < mpBuffer->mnWidth && nIndY < mpBuffer->mnHeight)
+            {
+                aXYCol = GetColor(nIndY, nIndX);
+            }
+
+            // merge return value with right/left neighbour
+            if(aXCol != aRetval)
+            {
+                aRetval.Merge(aXCol, 255 - nDeltaX);
+            }
+
+            // merge top/bottom neighbour with edge
+            if(aYCol != aXYCol)
+            {
+                aYCol.Merge(aXYCol, 255 - nDeltaX);
+            }
+
+            // merge return value with already merged top/bottom neighbour
+            if(aRetval != aYCol)
+            {
+                aRetval.Merge(aYCol, 255 - nDeltaY);
+            }
+
+            return aRetval;
+        }
+    }
+
+    return rFallback;
+}
+
+BitmapColor BitmapReadAccess::GetColorWithFallback( double fY, double fX, const BitmapColor& rFallback ) const
+{
+    // ask directly doubles >= 0.0 here to avoid rounded values of 0 at small negative
+    // double values, e.g. static_cast< sal_Int32 >(-0.25) is 0, not -1, but *has* to be outside (!)
+    if(mpBuffer && fX >= 0.0 && fY >= 0.0)
+    {
+        const sal_Int32 nX(static_cast< sal_Int32 >(fX));
+        const sal_Int32 nY(static_cast< sal_Int32 >(fY));
+
+        if(nX < mpBuffer->mnWidth && nY < mpBuffer->mnHeight)
+        {
+            return GetColor(nY, nX);
+        }
+    }
+
+    return rFallback;
+}
+
+BitmapColor BitmapReadAccess::GetColorWithFallback( long nY, long nX, const BitmapColor& rFallback ) const
+{
+    if(mpBuffer)
+    {
+        if(nX >= 0 && nY >= 0 && nX < mpBuffer->mnWidth && nY < mpBuffer->mnHeight)
+        {
+            return GetColor(nY, nX);
+        }
+    }
+
+    return rFallback;
+}
+
 // ---------------------
 // - BitmapWriteAccess -
 // ---------------------
diff --git a/vcl/source/gdi/outdev2.cxx b/vcl/source/gdi/outdev2.cxx
index 1ec5f75..cbec937 100644
--- a/vcl/source/gdi/outdev2.cxx
+++ b/vcl/source/gdi/outdev2.cxx
@@ -43,6 +43,7 @@
 #include <window.h>
 #include <outdata.hxx>
 #include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
 
 #define BAND_MAX_SIZE 512000
 
@@ -818,8 +819,9 @@ void OutputDevice::DrawTransformedBitmapEx(
     const bool bSheared(!basegfx::fTools::equalZero(fShearX));
     const bool bMirroredX(basegfx::fTools::less(aScale.getX(), 0.0));
     const bool bMirroredY(basegfx::fTools::less(aScale.getY(), 0.0));
+    static bool bForceToOwnTransformer(false);
 
-    if(!bRotated && !bSheared && !bMirroredX && !bMirroredY)
+    if(!bForceToOwnTransformer && !bRotated && !bSheared && !bMirroredX && !bMirroredY)
     {
         // with no rotation, shear or mirroring it can be mapped to DrawBitmapEx
         // do *not* execute the mirroring here, it's done in the fallback
@@ -840,7 +842,7 @@ void OutputDevice::DrawTransformedBitmapEx(
     const basegfx::B2DHomMatrix aFullTransform(GetViewTransformation() * rTransformation);
     const bool bTryDirectPaint(!bInvert && !bBitmapChangedColor && !bMetafile && !bPrinter);
 
-    if(bTryDirectPaint)
+    if(!bForceToOwnTransformer && bTryDirectPaint)
     {
         // try to paint directly
         const basegfx::B2DPoint aNull(aFullTransform * basegfx::B2DPoint(0.0, 0.0));
@@ -873,7 +875,7 @@ void OutputDevice::DrawTransformedBitmapEx(
     if(!bDone)
     {
         // take the fallback when no rotate and shear, but mirror (else we would have done this above)
-        if(!bRotated && !bSheared)
+        if(!bForceToOwnTransformer && !bRotated && !bSheared)
         {
             // with no rotation or shear it can be mapped to DrawBitmapEx
             // do *not* execute the mirroring here, it's done in the fallback
@@ -886,14 +888,115 @@ void OutputDevice::DrawTransformedBitmapEx(
 
         // fallback; create transformed bitmap the hard way (back-transform
         // the pixels) and paint
-        basegfx::B2DRange aTargetRange(0.0, 0.0, 1.0, 1.0);
-        const double fMaximumArea(bMetafile ? 800000.0 : 200000.0);
-        const BitmapEx aTransformed(rBitmapEx.getTransformed(aFullTransform, fMaximumArea));
-        aTargetRange.transform(rTransformation);
-        const Point aDestPt(basegfx::fround(aTargetRange.getMinX()), basegfx::fround(aTargetRange.getMinY()));
-        const Size aDestSize(basegfx::fround(aTargetRange.getWidth()), basegfx::fround(aTargetRange.getHeight()));
-
-        DrawBitmapEx(aDestPt, aDestSize, aTransformed);
+        basegfx::B2DRange aVisibleRange(0.0, 0.0, 1.0, 1.0);
+
+        // limit maximum area to something looking good for non-pixel-based targets (metafile, printer)
+        double fMaximumArea(1000000.0);
+
+        if(!bMetafile && !bPrinter)
+        {
+            // limit TargetRange to existing pixels (if pixel device)
+            // first get discrete range of object
+            basegfx::B2DRange aFullPixelRange(aVisibleRange);
+
+            aFullPixelRange.transform(aFullTransform);
+
+            if(basegfx::fTools::equalZero(aFullPixelRange.getWidth()) || basegfx::fTools::equalZero(aFullPixelRange.getHeight()))
+            {
+                // object is outside of visible area
+                return;
+            }
+
+            // now get discrete target pixels; start with OutDev pixel size and evtl.
+            // intersect with active clipping area
+            basegfx::B2DRange aOutPixel(
+                0.0,
+                0.0,
+                GetOutputSizePixel().Width(),
+                GetOutputSizePixel().Height());
+
+            if(IsClipRegion())
+            {
+                const Rectangle aRegionRectangle(GetActiveClipRegion().GetBoundRect());
+
+                aOutPixel.intersect( // caution! Range from rectangle, one too much (!)
+                    basegfx::B2DRange(
+                        aRegionRectangle.Left(),
+                        aRegionRectangle.Top(),
+                        aRegionRectangle.Right() + 1,
+                        aRegionRectangle.Bottom() + 1));
+            }
+
+            if(aOutPixel.isEmpty())
+            {
+                // no active output area
+                return;
+            }
+
+            // if aFullPixelRange is not completely inside of aOutPixel,
+            // reduction of target pixels is possible
+            basegfx::B2DRange aVisiblePixelRange(aFullPixelRange);
+
+            if(!aOutPixel.isInside(aFullPixelRange))
+            {
+                aVisiblePixelRange.intersect(aOutPixel);
+
+                if(aVisiblePixelRange.isEmpty())
+                {
+                    // nothing in visible part, reduces to nothing
+                    return;
+                }
+
+                // aVisiblePixelRange contains the reduced output area in
+                // discrete coordinates. To make it useful everywhere, make it relative to
+                // the object range
+                basegfx::B2DHomMatrix aMakeVisibleRangeRelative;
+
+                aVisibleRange = aVisiblePixelRange;
+                aMakeVisibleRangeRelative.translate(
+                    -aFullPixelRange.getMinX(),
+                    -aFullPixelRange.getMinY());
+                aMakeVisibleRangeRelative.scale(
+                    1.0 / aFullPixelRange.getWidth(),
+                    1.0 / aFullPixelRange.getHeight());
+                aVisibleRange.transform(aMakeVisibleRangeRelative);
+            }
+
+            // for pixel devices, do *not* limit size, else OutputDevice::ImplDrawAlpha
+            // will create another, badly scaled bitmap to do the job. Nonetheless, do a
+            // maximum clipping of something big (1600x1280x2). Add 1.0 to avoid rounding
+            // errors in rough estimations
+            const double fNewMaxArea(aVisiblePixelRange.getWidth() * aVisiblePixelRange.getHeight());
+
+            fMaximumArea = std::min(4096000.0, fNewMaxArea + 1.0);
+        }
+
+        if(!aVisibleRange.isEmpty())
+        {
+            static bool bDoSmoothAtAll(true);
+            const BitmapEx aTransformed(
+                rBitmapEx.getTransformed(
+                    aFullTransform,
+                    aVisibleRange,
+                    fMaximumArea,
+                    bDoSmoothAtAll));
+            basegfx::B2DRange aTargetRange(0.0, 0.0, 1.0, 1.0);
+
+            // get logic object target range
+            aTargetRange.transform(rTransformation);
+
+            // get from unified/relative VisibleRange to logoc one
+            aVisibleRange.transform(
+                basegfx::tools::createScaleTranslateB2DHomMatrix(
+                    aTargetRange.getRange(),
+                    aTargetRange.getMinimum()));
+
+            // extract point and size; do not remove size, the bitmap may have been prepared reduced by purpose
+            const Point aDestPt(basegfx::fround(aVisibleRange.getMinX()), basegfx::fround(aVisibleRange.getMinY()));
+            const Size aDestSize(basegfx::fround(aVisibleRange.getWidth()), basegfx::fround(aVisibleRange.getHeight()));
+
+            DrawBitmapEx(aDestPt, aDestSize, aTransformed);
+        }
     }
 }
 


More information about the Libreoffice-commits mailing list