[Libreoffice-commits] core.git: 2 commits - include/vcl vcl/source

Tomaž Vajngerl tomaz.vajngerl at collabora.co.uk
Sun Jan 18 07:09:38 PST 2015


 include/vcl/outdev.hxx       |    6 
 vcl/source/outdev/bitmap.cxx |  438 +++++++++++++++++++++++++++----------------
 2 files changed, 289 insertions(+), 155 deletions(-)

New commits:
commit d53103dd83bf20ac63485e229069f145e35b3009
Author: Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
Date:   Sun Jan 18 23:51:14 2015 +0900

    fdo#74124 bilinear scaling with blending for some formats
    
    The DrawDeviceAlphaBitmapSlowPath used fast/ugly scaling with
    blending. With this a bilinear scaling is used which should
    improve quality for downscaling (less than 50% should start to
    degrade in quality as only 2 samples are always used) and
    upscaling.
    
    Change-Id: I56cdf2b5761687be891387343a773b6fefac03e2

diff --git a/vcl/source/outdev/bitmap.cxx b/vcl/source/outdev/bitmap.cxx
index 50877be..1ee1eef 100644
--- a/vcl/source/outdev/bitmap.cxx
+++ b/vcl/source/outdev/bitmap.cxx
@@ -673,6 +673,179 @@ void OutputDevice::DrawDeviceAlphaBitmap( const Bitmap& rBmp, const AlphaMask& r
     }
 }
 
+namespace
+{
+
+struct ScaleContext
+{
+    boost::scoped_array<long> mpMapX;
+    boost::scoped_array<long> mpMapY;
+
+    boost::scoped_array<long> mpMapXOffset;
+    boost::scoped_array<long> mpMapYOffset;
+
+    ScaleContext(Rectangle& aDstRect, Rectangle& aBitmapRect,
+                 Size& aOutSize, long nOffX, long nOffY)
+
+        : mpMapX(new long[aDstRect.GetWidth()])
+        , mpMapY(new long[aDstRect.GetHeight()])
+        , mpMapXOffset(new long[aDstRect.GetWidth()])
+        , mpMapYOffset(new long[aDstRect.GetHeight()])
+    {
+        const long nSrcWidth = aBitmapRect.GetWidth();
+        const long nSrcHeight = aBitmapRect.GetHeight();
+
+        const bool bHMirr = aOutSize.Width() < 0;
+        const bool bVMirr = aOutSize.Height() < 0;
+
+        generateSimpleMap(
+            nSrcWidth,  aDstRect.GetWidth(), aBitmapRect.Left(),
+            aOutSize.Width(),  nOffX, bHMirr, mpMapX.get(), mpMapXOffset.get());
+
+        generateSimpleMap(
+            nSrcHeight, aDstRect.GetHeight(), aBitmapRect.Top(),
+            aOutSize.Height(), nOffY, bVMirr, mpMapY.get(), mpMapYOffset.get());
+    }
+
+private:
+
+    static void generateSimpleMap(long nSrcDimension, long nDstDimension, long nDstLocation,
+                                  long nOutDimention, long nOffset, bool bMirror, long* pMap, long* pMapOffset)
+    {
+        long nMirrorOffset = 0;
+
+        if (bMirror)
+            nMirrorOffset = (nDstLocation << 1) + nSrcDimension - 1L;
+
+        double fReverseScale = (nSrcDimension - 1L) / double(nOutDimention - 1L);
+
+        for (long i = 0L; i < nDstDimension; i++)
+        {
+            double fTemp = ((nOffset + i) * fReverseScale);
+            if (bMirror)
+                fTemp = nMirrorOffset - fTemp - 1L;
+
+            pMap[i] = MinMax(nDstLocation + long(fTemp), 0, nSrcDimension - 2L);
+            pMapOffset[i] = (long) ((fTemp - pMap[i]) * 128.0);
+        }
+    }
+
+public:
+    void blendBitmap(
+            const BitmapWriteAccess* pDestination,
+            const BitmapReadAccess*  pSource,
+            const BitmapReadAccess*  pSourceAlpha,
+            const long nDstWidth,
+            const long nDstHeight)
+    {
+        if (pSource && pSourceAlpha && pDestination)
+        {
+            unsigned long nSourceFormat = pSource->GetScanlineFormat();
+            unsigned long nDestinationFormat = pDestination->GetScanlineFormat();
+
+            switch (nSourceFormat)
+            {
+                case BMP_FORMAT_24BIT_TC_RGB:
+                case BMP_FORMAT_24BIT_TC_BGR:
+                {
+                    if ( (nSourceFormat == BMP_FORMAT_24BIT_TC_BGR && nDestinationFormat == BMP_FORMAT_32BIT_TC_BGRA)
+                      || (nSourceFormat == BMP_FORMAT_24BIT_TC_RGB && nDestinationFormat == BMP_FORMAT_32BIT_TC_RGBA))
+                    {
+                        blendBitmap24(pDestination, pSource, pSourceAlpha, nDstWidth, nDstHeight);
+                    }
+                }
+            }
+        }
+    }
+
+    void blendBitmap24(
+            const BitmapWriteAccess*  pDestination,
+            const BitmapReadAccess*   pSource,
+            const BitmapReadAccess*   pSourceAlpha,
+            const long nDstWidth,
+            const long nDstHeight)
+    {
+        Scanline pLine0, pLine1;
+        Scanline pLineAlpha0, pLineAlpha1;
+        Scanline pColorSample1, pColorSample2;
+        Scanline pDestScanline;
+
+        long nColor1Line1, nColor2Line1, nColor3Line1;
+        long nColor1Line2, nColor2Line2, nColor3Line2;
+        long nAlphaLine1, nAlphaLine2;
+
+        sal_uInt8 nColor1, nColor2, nColor3, nAlpha;
+
+        for (long nY = 0L; nY < nDstHeight; nY++)
+        {
+            const long nMapY  = mpMapY[nY];
+            const long nMapFY = mpMapYOffset[nY];
+
+            pLine0 = pSource->GetScanline(nMapY);
+            pLine1 = pSource->GetScanline(nMapY + 1);
+
+            pLineAlpha0 = pSourceAlpha->GetScanline(nMapY);
+            pLineAlpha1 = pSourceAlpha->GetScanline(nMapY + 1);
+
+            pDestScanline = pDestination->GetScanline(nY);
+
+            for (long nX = 0L; nX < nDstWidth; nX++)
+            {
+                const long nMapX = mpMapX[nX];
+                const long nMapFX = mpMapXOffset[nX];
+
+                pColorSample1 = pLine0 + 3L * nMapX;
+                pColorSample2 = pColorSample1  + 3L;
+                nColor1Line1 = (static_cast<long>(*pColorSample1) << 7) + nMapFX * (static_cast<long>(*pColorSample2) - *pColorSample1);
+
+                pColorSample1++;
+                pColorSample2++;
+                nColor2Line1 = (static_cast<long>(*pColorSample1) << 7) + nMapFX * (static_cast<long>(*pColorSample2) - *pColorSample1);
+
+                pColorSample1++;
+                pColorSample2++;
+                nColor3Line1 = (static_cast<long>(*pColorSample1) << 7) + nMapFX * (static_cast<long>(*pColorSample2) - *pColorSample1);
+
+                pColorSample1 = pLine1 + 3L * nMapX;
+                pColorSample2 = pColorSample1  + 3L;
+                nColor1Line2 = (static_cast<long>(*pColorSample1) << 7) + nMapFX * (static_cast<long>(*pColorSample2) - *pColorSample1);
+
+                pColorSample1++;
+                pColorSample2++;
+                nColor2Line2 = (static_cast<long>(*pColorSample1) << 7) + nMapFX * (static_cast<long>(*pColorSample2) - *pColorSample1);
+
+                pColorSample1++;
+                pColorSample2++;
+                nColor3Line2 = (static_cast<long>(*pColorSample1) << 7) + nMapFX * (static_cast<long>(*pColorSample2) - *pColorSample1);
+
+                pColorSample1 = pLineAlpha0 + nMapX;
+                pColorSample2 = pColorSample1  + 1L;
+                nAlphaLine1 = (static_cast<long>(*pColorSample1) << 7) + nMapFX * (static_cast<long>(*pColorSample2) - *pColorSample1);
+
+                pColorSample1 = pLineAlpha1 + nMapX;
+                pColorSample2 = pColorSample1  + 1L;
+                nAlphaLine2 = (static_cast<long>(*pColorSample1) << 7) + nMapFX * (static_cast<long>(*pColorSample2) - *pColorSample1);
+
+                nColor1 = (nColor1Line1 + nMapFY * ((nColor1Line2 >> 7) - (nColor1Line1 >> 7))) >> 7;
+                nColor2 = (nColor2Line1 + nMapFY * ((nColor2Line2 >> 7) - (nColor2Line1 >> 7))) >> 7;
+                nColor3 = (nColor3Line1 + nMapFY * ((nColor3Line2 >> 7) - (nColor3Line1 >> 7))) >> 7;
+
+                nAlpha  = (nAlphaLine1  + nMapFY * ((nAlphaLine2  >> 7) - (nAlphaLine1 >> 7))) >> 7;
+
+                *pDestScanline = COLOR_CHANNEL_MERGE(*pDestScanline, nColor1, nAlpha);
+                pDestScanline++;
+                *pDestScanline = COLOR_CHANNEL_MERGE(*pDestScanline, nColor2, nAlpha);
+                pDestScanline++;
+                *pDestScanline = COLOR_CHANNEL_MERGE(*pDestScanline, nColor3, nAlpha);
+                pDestScanline++;
+                pDestScanline++;
+            }
+        }
+    }
+};
+
+} // end anonymous namespace
+
 void OutputDevice::DrawDeviceAlphaBitmapSlowPath(const Bitmap& rBitmap, const AlphaMask& rAlpha, Rectangle aDstRect, Rectangle aBmpRect, Size& aOutSize, Point& aOutPoint)
 {
     VirtualDevice* pOldVDev = mpAlphaVDev;
@@ -701,16 +874,9 @@ void OutputDevice::DrawDeviceAlphaBitmapSlowPath(const Bitmap& rBitmap, const Al
         aDstRect.SetSize(aBmp.GetSizePixel());
     }
 
-    BitmapColor aDstCol;
-    const long nSrcWidth = aBmpRect.GetWidth();
-    const long nSrcHeight = aBmpRect.GetHeight();
-
     const long nDstWidth = aDstRect.GetWidth();
     const long nDstHeight = aDstRect.GetHeight();
 
-    const long nOutWidth = aOutSize.Width();
-    const long nOutHeight = aOutSize.Height();
-
     // calculate offset in original bitmap
     // in RTL case this is a little more complicated since the contents of the
     // bitmap is not mirrored (it never is), however the paint region and bmp region
@@ -722,45 +888,13 @@ void OutputDevice::DrawDeviceAlphaBitmapSlowPath(const Bitmap& rBitmap, const Al
 
     const long nOffY = aDstRect.Top() - aOutPoint.Y();
 
-    long nX, nOutX, nY, nOutY;
-    long nMirrOffX = 0;
-    long nMirrOffY = 0;
-
-    boost::scoped_array<long> pMapX(new long[nDstWidth]);
-    boost::scoped_array<long> pMapY(new long[nDstHeight]);
-
-    // create horizontal mapping table
-    if (bHMirr)
-    {
-        nMirrOffX = (aBmpRect.Left() << 1) + nSrcWidth - 1;
-    }
-
-    for (nX = 0L, nOutX = nOffX; nX < nDstWidth; nX++, nOutX++)
-    {
-        pMapX[nX] = aBmpRect.Left() + nOutX * nSrcWidth / nOutWidth;
-        if(bHMirr)
-            pMapX[nX] = nMirrOffX - pMapX[nX];
-    }
-
-    // create vertical mapping table
-    if (bVMirr)
-    {
-        nMirrOffY = (aBmpRect.Top() << 1) + nSrcHeight - 1;
-    }
-
-    for(nY = 0L, nOutY = nOffY; nY < nDstHeight; nY++, nOutY++)
-    {
-        pMapY[nY] = aBmpRect.Top() + nOutY * nSrcHeight / nOutHeight;
-
-        if (bVMirr)
-            pMapY[nY] = nMirrOffY - pMapY[nY];
-    }
+    ScaleContext aContext(aDstRect, aBmpRect, aOutSize, nOffX, nOffY);
 
     Bitmap::ScopedReadAccess pBitmapReadAccess(const_cast<Bitmap&>(rBitmap));
     AlphaMask::ScopedReadAccess pAlphaReadAccess(const_cast<AlphaMask&>(rAlpha));
 
     DBG_ASSERT( pAlphaReadAccess->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL ||
-                pAlphaReadAccess->GetScanlineFormat()  == BMP_FORMAT_8BIT_TC_MASK,
+                pAlphaReadAccess->GetScanlineFormat() == BMP_FORMAT_8BIT_TC_MASK,
                 "OutputDevice::ImplDrawAlpha(): non-8bit alpha no longer supported!" );
 
     // #i38887# reading from screen may sometimes fail
@@ -775,17 +909,31 @@ void OutputDevice::DrawDeviceAlphaBitmapSlowPath(const Bitmap& rBitmap, const Al
                             aDstRect,
                             nOffY, nDstHeight,
                             nOffX, nDstWidth,
-                            pMapX.get(), pMapY.get() );
+                            aContext.mpMapX.get(), aContext.mpMapY.get() );
         }
         else
         {
-            aNewBitmap = BlendBitmap(
+            bool isBitmap24bitRGB = (pBitmapReadAccess->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB ||
+                                     pBitmapReadAccess->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR);
+
+            if (GetBitCount() <= 8 && !isBitmap24bitRGB)
+            {
+                aNewBitmap = BlendBitmap(
                             aBmp, pBitmapReadAccess.get(), pAlphaReadAccess.get(),
                             nOffY, nDstHeight,
                             nOffX, nDstWidth,
                             aBmpRect, aOutSize,
                             bHMirr, bVMirr,
-                            pMapX.get(), pMapY.get() );
+                            aContext.mpMapX.get(), aContext.mpMapY.get() );
+            }
+            else
+            {
+                Bitmap::ScopedWriteAccess pDestination(aBmp);
+                aContext.blendBitmap(
+                    pDestination.get(), pBitmapReadAccess.get(), pAlphaReadAccess.get(),
+                    nDstWidth, nDstHeight);
+                aNewBitmap = aBmp;
+            }
         }
 
         // #110958# Disable alpha VDev, we're doing the necessary
@@ -957,6 +1105,7 @@ 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(!bForceToOwnTransformer && !bRotated && !bSheared && !bMirroredX && !bMirroredY)
@@ -1409,48 +1558,6 @@ Bitmap OutputDevice::BlendBitmap(
                     }
                     break;
 
-                case( BMP_FORMAT_24BIT_TC_BGR ):
-                    {
-                        for( nY = 0; nY < nDstHeight; nY++ )
-                        {
-                            const long  nMapY = pMapY[ nY ];
-                            Scanline    pPScan = pP->GetScanline( nMapY );
-                            Scanline    pAScan = pA->GetScanline( nMapY );
-
-                            for( nX = 0; nX < nDstWidth; nX++ )
-                            {
-                                const long  nMapX = pMapX[ nX ];
-                                Scanline    pTmp = pPScan + nMapX * 3;
-
-                                aDstCol = pB->GetPixel( nY, nX );
-                                pB->SetPixel( nY, nX, aDstCol.Merge( pTmp[ 2 ], pTmp[ 1 ], pTmp[ 0 ],
-                                                                     pAScan[ nMapX ] ) );
-                            }
-                        }
-                    }
-                    break;
-
-                case( BMP_FORMAT_24BIT_TC_RGB ):
-                    {
-                        for( nY = 0; nY < nDstHeight; nY++ )
-                        {
-                            const long  nMapY = pMapY[ nY ];
-                            Scanline    pPScan = pP->GetScanline( nMapY );
-                            Scanline    pAScan = pA->GetScanline( nMapY );
-
-                            for( nX = 0; nX < nDstWidth; nX++ )
-                            {
-                                const long  nMapX = pMapX[ nX ];
-                                Scanline    pTmp = pPScan + nMapX * 3;
-
-                                aDstCol = pB->GetPixel( nY, nX );
-                                pB->SetPixel( nY, nX, aDstCol.Merge( pTmp[ 0 ], pTmp[ 1 ], pTmp[ 2 ],
-                                                                     pAScan[ nMapX ] ) );
-                            }
-                        }
-                    }
-                    break;
-
                 default:
                 {
                     for( nY = 0; nY < nDstHeight; nY++ )
commit 009c1752b1eff36827dae4fa9bd394c5089dcc55
Author: Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
Date:   Sat Jan 3 13:14:55 2015 +0900

    Extract slow path of DrawDeviceAlphaBitmap into its own method
    
    Additioanlly cleanup and use ScopedReadAccess
    
    Change-Id: Ia3365f4dc968368bdd90d4398188bffe2d56e89b

diff --git a/include/vcl/outdev.hxx b/include/vcl/outdev.hxx
index 5ce1a27..f8fd837 100644
--- a/include/vcl/outdev.hxx
+++ b/include/vcl/outdev.hxx
@@ -1406,6 +1406,12 @@ private:
                                     const Point& rSrcPtPixel,
                                     const Size& rSrcSizePixel );
 
+    SAL_DLLPRIVATE void DrawDeviceAlphaBitmapSlowPath(
+                                const Bitmap& rBitmap, const AlphaMask& rAlpha,
+                                Rectangle aDstRect, Rectangle aBmpRect,
+                                Size& aOutSz, Point& aOutPt);
+
+
     SAL_DLLPRIVATE bool         BlendBitmap(
                                     const SalTwoRect&   rPosAry,
                                     const Bitmap&       rBmp );
diff --git a/vcl/source/outdev/bitmap.cxx b/vcl/source/outdev/bitmap.cxx
index 680f362..50877be 100644
--- a/vcl/source/outdev/bitmap.cxx
+++ b/vcl/source/outdev/bitmap.cxx
@@ -604,36 +604,37 @@ void OutputDevice::DrawDeviceAlphaBitmap( const Bitmap& rBmp, const AlphaMask& r
                                     const Point& rDestPt, const Size& rDestSize,
                                     const Point& rSrcPtPixel, const Size& rSrcSizePixel )
 {
-    Point       aOutPt( LogicToPixel( rDestPt ) );
-    Size        aOutSz( LogicToPixel( rDestSize ) );
-    Rectangle   aDstRect( Point(), GetOutputSizePixel() );
-    const bool  bHMirr = aOutSz.Width() < 0;
-    const bool  bVMirr = aOutSz.Height() < 0;
+    Point     aOutPt(LogicToPixel(rDestPt));
+    Size      aOutSz(LogicToPixel(rDestSize));
+    Rectangle aDstRect(Point(), GetOutputSizePixel());
+
+    const bool bHMirr = aOutSz.Width() < 0;
+    const bool bVMirr = aOutSz.Height() < 0;
 
     ClipToPaintRegion(aDstRect);
 
-    if( bHMirr )
+    if (bHMirr)
     {
         aOutSz.Width() = -aOutSz.Width();
-        aOutPt.X() -= ( aOutSz.Width() - 1L );
+        aOutPt.X() -= aOutSz.Width() - 1L;
     }
 
-    if( bVMirr )
+    if (bVMirr)
     {
         aOutSz.Height() = -aOutSz.Height();
-        aOutPt.Y() -= ( aOutSz.Height() - 1L );
+        aOutPt.Y() -= aOutSz.Height() - 1L;
     }
 
-    if( !aDstRect.Intersection( Rectangle( aOutPt, aOutSz ) ).IsEmpty() )
+    if (!aDstRect.Intersection(Rectangle(aOutPt, aOutSz)).IsEmpty())
     {
         static const char* pDisableNative = getenv( "SAL_DISABLE_NATIVE_ALPHA");
         // #i83087# Naturally, system alpha blending cannot work with
         // separate alpha VDev
         bool bTryDirectPaint(!pDisableNative && !bHMirr && !bVMirr);
 
-        if(bTryDirectPaint)
+        if (bTryDirectPaint)
         {
-            Point aRelPt = aOutPt + Point( mnOutOffX, mnOutOffY );
+            Point aRelPt = aOutPt + Point(mnOutOffX, mnOutOffY);
             SalTwoRect aTR(
                 rSrcPtPixel.X(), rSrcPtPixel.Y(),
                 rSrcSizePixel.Width(), rSrcSizePixel.Height(),
@@ -644,19 +645,19 @@ void OutputDevice::DrawDeviceAlphaBitmap( const Bitmap& rBmp, const AlphaMask& r
             SalBitmap* pSalAlphaBmp = rAlpha.ImplGetImpBitmap()->ImplGetSalBitmap();
 
             // try the blen the alpha bitmap with the alpha virtual device
-            if( mpAlphaVDev )
+            if (mpAlphaVDev)
             {
                 Bitmap aAlphaBitmap( mpAlphaVDev->GetBitmap( aRelPt, aOutSz ) );
                 SalBitmap* pSalAlphaBmp2 = aAlphaBitmap.ImplGetImpBitmap()->ImplGetSalBitmap();
-                if( mpGraphics->BlendAlphaBitmap( aTR, *pSalSrcBmp, *pSalAlphaBmp, *pSalAlphaBmp2, this ) )
+                if (mpGraphics->BlendAlphaBitmap(aTR, *pSalSrcBmp, *pSalAlphaBmp, *pSalAlphaBmp2, this))
                 {
-                    mpAlphaVDev->BlendBitmap( aTR, rAlpha );
+                    mpAlphaVDev->BlendBitmap(aTR, rAlpha);
                     return;
                 }
             }
             else
             {
-                if (mpGraphics->DrawAlphaBitmap( aTR, *pSalSrcBmp, *pSalAlphaBmp, this ))
+                if (mpGraphics->DrawAlphaBitmap(aTR, *pSalSrcBmp, *pSalAlphaBmp, this))
                     return;
             }
         }
@@ -664,122 +665,142 @@ void OutputDevice::DrawDeviceAlphaBitmap( const Bitmap& rBmp, const AlphaMask& r
         // we need to make sure OpenGL never reaches this slow code path
         assert(!OpenGLHelper::isVCLOpenGLEnabled());
 
-        VirtualDevice* pOldVDev = mpAlphaVDev;
-
-        Rectangle aBmpRect( Point(), rBmp.GetSizePixel() );
+        Rectangle aBmpRect(Point(), rBmp.GetSizePixel());
         if (!aBmpRect.Intersection(Rectangle(rSrcPtPixel, rSrcSizePixel)).IsEmpty())
         {
-            // The scaling in this code path produces really ugly results - it
-            // does the most trivial scaling with no smoothing.
-
-            GDIMetaFile*    pOldMetaFile = mpMetaFile;
-            const bool      bOldMap = mbMap;
-            mpMetaFile = NULL; // fdo#55044 reset before GetBitmap!
-            mbMap = false;
-            Bitmap          aBmp( GetBitmap( aDstRect.TopLeft(), aDstRect.GetSize() ) );
-
-            // #109044# The generated bitmap need not necessarily be
-            // of aDstRect dimensions, it's internally clipped to
-            // window bounds. Thus, we correct the dest size here,
-            // since we later use it (in nDstWidth/Height) for pixel
-            // access)
-            // #i38887# reading from screen may sometimes fail
-            if( aBmp.ImplGetImpBitmap() )
-                aDstRect.SetSize( aBmp.GetSizePixel() );
-
-            BitmapColor     aDstCol;
-            const long      nSrcWidth = aBmpRect.GetWidth(), nSrcHeight = aBmpRect.GetHeight();
-            const long      nDstWidth = aDstRect.GetWidth(), nDstHeight = aDstRect.GetHeight();
-            const long      nOutWidth = aOutSz.Width(), nOutHeight = aOutSz.Height();
-            // calculate offset in original bitmap
-            // in RTL case this is a little more complicated since the contents of the
-            // bitmap is not mirrored (it never is), however the paint region and bmp region
-            // are in mirrored coordinates, so the intersection of (aOutPt,aOutSz) with these
-            // is content wise somewhere else and needs to take mirroring into account
-            const long      nOffX = IsRTLEnabled()
-                                    ? aOutSz.Width() - aDstRect.GetWidth() - (aDstRect.Left() - aOutPt.X())
-                                    : aDstRect.Left() - aOutPt.X(),
-                            nOffY = aDstRect.Top() - aOutPt.Y();
-            long            nX, nOutX, nY, nOutY;
-            long            nMirrOffX = 0;
-            long            nMirrOffY = 0;
-            boost::scoped_array<long> pMapX(new long[ nDstWidth ]);
-            boost::scoped_array<long> pMapY(new long[ nDstHeight ]);
-
-            // create horizontal mapping table
-            if( bHMirr )
-                nMirrOffX = ( aBmpRect.Left() << 1 ) + nSrcWidth - 1;
-
-            for( nX = 0L, nOutX = nOffX; nX < nDstWidth; nX++, nOutX++ )
-            {
-                pMapX[ nX ] = aBmpRect.Left() + nOutX * nSrcWidth / nOutWidth;
-                if( bHMirr )
-                    pMapX[ nX ] = nMirrOffX - pMapX[ nX ];
-            }
+            DrawDeviceAlphaBitmapSlowPath(rBmp, rAlpha, aDstRect, aBmpRect, aOutSz, aOutPt);
+        }
+    }
+}
 
-            // create vertical mapping table
-            if( bVMirr )
-                nMirrOffY = ( aBmpRect.Top() << 1 ) + nSrcHeight - 1;
+void OutputDevice::DrawDeviceAlphaBitmapSlowPath(const Bitmap& rBitmap, const AlphaMask& rAlpha, Rectangle aDstRect, Rectangle aBmpRect, Size& aOutSize, Point& aOutPoint)
+{
+    VirtualDevice* pOldVDev = mpAlphaVDev;
 
-            for( nY = 0L, nOutY = nOffY; nY < nDstHeight; nY++, nOutY++ )
-            {
-                pMapY[ nY ] = aBmpRect.Top() + nOutY * nSrcHeight / nOutHeight;
+    const bool  bHMirr = aOutSize.Width() < 0;
+    const bool  bVMirr = aOutSize.Height() < 0;
 
-                if( bVMirr )
-                    pMapY[ nY ] = nMirrOffY - pMapY[ nY ];
-            }
+    // The scaling in this code path produces really ugly results - it
+    // does the most trivial scaling with no smoothing.
+    GDIMetaFile* pOldMetaFile = mpMetaFile;
+    const bool   bOldMap = mbMap;
 
-            BitmapReadAccess*   pP = ( (Bitmap&) rBmp ).AcquireReadAccess();
-            BitmapReadAccess*   pA = ( (AlphaMask&) rAlpha ).AcquireReadAccess();
+    mpMetaFile = NULL; // fdo#55044 reset before GetBitmap!
+    mbMap = false;
 
-            DBG_ASSERT( pA->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL ||
-                        pA->GetScanlineFormat() == BMP_FORMAT_8BIT_TC_MASK,
-                        "OutputDevice::ImplDrawAlpha(): non-8bit alpha no longer supported!" );
+    Bitmap aBmp(GetBitmap(aDstRect.TopLeft(), aDstRect.GetSize()));
 
-            // #i38887# reading from screen may sometimes fail
-            if( aBmp.ImplGetImpBitmap() )
-            {
-                Bitmap aTmp;
+    // #109044# The generated bitmap need not necessarily be
+    // of aDstRect dimensions, it's internally clipped to
+    // window bounds. Thus, we correct the dest size here,
+    // since we later use it (in nDstWidth/Height) for pixel
+    // access)
+    // #i38887# reading from screen may sometimes fail
+    if (aBmp.ImplGetImpBitmap())
+    {
+        aDstRect.SetSize(aBmp.GetSizePixel());
+    }
 
-                if( mpAlphaVDev )
-                {
-                    aTmp = BlendBitmapWithAlpha(
-                        aBmp,pP,pA,
-                        aDstRect,
-                        nOffY,nDstHeight,
-                        nOffX,nDstWidth,
-                        pMapX.get(),pMapY.get() );
-                }
-                else
-                {
-                    aTmp = BlendBitmap(
-                        aBmp,pP,pA,
-                        nOffY,nDstHeight,
-                        nOffX,nDstWidth,
-                        aBmpRect,aOutSz,
-                        bHMirr,bVMirr,
-                        pMapX.get(),pMapY.get() );
-                }
+    BitmapColor aDstCol;
+    const long nSrcWidth = aBmpRect.GetWidth();
+    const long nSrcHeight = aBmpRect.GetHeight();
 
-                // #110958# Disable alpha VDev, we're doing the necessary
-                // stuff explicitly furher below
-                if( mpAlphaVDev )
-                    mpAlphaVDev = NULL;
+    const long nDstWidth = aDstRect.GetWidth();
+    const long nDstHeight = aDstRect.GetHeight();
 
-                DrawBitmap( aDstRect.TopLeft(),
-                            aTmp );
+    const long nOutWidth = aOutSize.Width();
+    const long nOutHeight = aOutSize.Height();
 
-                // #110958# Enable alpha VDev again
-                mpAlphaVDev = pOldVDev;
-            }
+    // calculate offset in original bitmap
+    // in RTL case this is a little more complicated since the contents of the
+    // bitmap is not mirrored (it never is), however the paint region and bmp region
+    // are in mirrored coordinates, so the intersection of (aOutPt,aOutSz) with these
+    // is content wise somewhere else and needs to take mirroring into account
+    const long nOffX = IsRTLEnabled()
+                            ? aOutSize.Width() - aDstRect.GetWidth() - (aDstRect.Left() - aOutPoint.X())
+                            : aDstRect.Left() - aOutPoint.X();
+
+    const long nOffY = aDstRect.Top() - aOutPoint.Y();
 
-            ( (Bitmap&) rBmp ).ReleaseAccess( pP );
-            ( (AlphaMask&) rAlpha ).ReleaseAccess( pA );
+    long nX, nOutX, nY, nOutY;
+    long nMirrOffX = 0;
+    long nMirrOffY = 0;
 
-            mbMap = bOldMap;
-            mpMetaFile = pOldMetaFile;
+    boost::scoped_array<long> pMapX(new long[nDstWidth]);
+    boost::scoped_array<long> pMapY(new long[nDstHeight]);
+
+    // create horizontal mapping table
+    if (bHMirr)
+    {
+        nMirrOffX = (aBmpRect.Left() << 1) + nSrcWidth - 1;
+    }
+
+    for (nX = 0L, nOutX = nOffX; nX < nDstWidth; nX++, nOutX++)
+    {
+        pMapX[nX] = aBmpRect.Left() + nOutX * nSrcWidth / nOutWidth;
+        if(bHMirr)
+            pMapX[nX] = nMirrOffX - pMapX[nX];
+    }
+
+    // create vertical mapping table
+    if (bVMirr)
+    {
+        nMirrOffY = (aBmpRect.Top() << 1) + nSrcHeight - 1;
+    }
+
+    for(nY = 0L, nOutY = nOffY; nY < nDstHeight; nY++, nOutY++)
+    {
+        pMapY[nY] = aBmpRect.Top() + nOutY * nSrcHeight / nOutHeight;
+
+        if (bVMirr)
+            pMapY[nY] = nMirrOffY - pMapY[nY];
+    }
+
+    Bitmap::ScopedReadAccess pBitmapReadAccess(const_cast<Bitmap&>(rBitmap));
+    AlphaMask::ScopedReadAccess pAlphaReadAccess(const_cast<AlphaMask&>(rAlpha));
+
+    DBG_ASSERT( pAlphaReadAccess->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL ||
+                pAlphaReadAccess->GetScanlineFormat()  == BMP_FORMAT_8BIT_TC_MASK,
+                "OutputDevice::ImplDrawAlpha(): non-8bit alpha no longer supported!" );
+
+    // #i38887# reading from screen may sometimes fail
+    if (aBmp.ImplGetImpBitmap())
+    {
+        Bitmap aNewBitmap;
+
+        if (mpAlphaVDev)
+        {
+            aNewBitmap = BlendBitmapWithAlpha(
+                            aBmp, pBitmapReadAccess.get(), pAlphaReadAccess.get(),
+                            aDstRect,
+                            nOffY, nDstHeight,
+                            nOffX, nDstWidth,
+                            pMapX.get(), pMapY.get() );
         }
+        else
+        {
+            aNewBitmap = BlendBitmap(
+                            aBmp, pBitmapReadAccess.get(), pAlphaReadAccess.get(),
+                            nOffY, nDstHeight,
+                            nOffX, nDstWidth,
+                            aBmpRect, aOutSize,
+                            bHMirr, bVMirr,
+                            pMapX.get(), pMapY.get() );
+        }
+
+        // #110958# Disable alpha VDev, we're doing the necessary
+        // stuff explicitly furher below
+        if (mpAlphaVDev)
+            mpAlphaVDev = NULL;
+
+        DrawBitmap(aDstRect.TopLeft(), aNewBitmap);
+
+        // #110958# Enable alpha VDev again
+        mpAlphaVDev = pOldVDev;
     }
+
+    mbMap = bOldMap;
+    mpMetaFile = pOldMetaFile;
 }
 
 void OutputDevice::ScaleBitmap (Bitmap &rBmp, SalTwoRect &rPosAry)


More information about the Libreoffice-commits mailing list