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 <[email protected]> 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 <[email protected]> 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)
_______________________________________________ Libreoffice-commits mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits
