Kaydet (Commit) a5351434 authored tarafından tsahi glik's avatar tsahi glik

fix rendering issues in iOS with aqua

üst 2646b159
......@@ -47,7 +47,7 @@ namespace
VDevBuffer();
virtual ~VDevBuffer();
VirtualDevice* alloc(OutputDevice& rOutDev, const Size& rSizePixel, bool bClear, bool bMono);
VirtualDevice* alloc(OutputDevice& rOutDev, const Size& rSizePixel, bool bClear, sal_Int32 nBits);
void free(VirtualDevice& rDevice);
// Timer virtuals
......@@ -80,7 +80,7 @@ namespace
}
}
VirtualDevice* VDevBuffer::alloc(OutputDevice& rOutDev, const Size& rSizePixel, bool bClear, bool bMono)
VirtualDevice* VDevBuffer::alloc(OutputDevice& rOutDev, const Size& rSizePixel, bool bClear, sal_Int32 nBits)
{
::osl::MutexGuard aGuard(m_aMutex);
VirtualDevice* pRetval = 0;
......@@ -94,7 +94,7 @@ namespace
{
OSL_ENSURE(*a, "Empty pointer in VDevBuffer (!)");
if((bMono && 1 == (*a)->GetBitCount()) || (!bMono && (*a)->GetBitCount() > 1))
if(nBits == (*a)->GetBitCount())
{
// candidate is valid due to bit depth
if(aFound != maFreeBuffers.end())
......@@ -160,7 +160,7 @@ namespace
// no success yet, create new buffer
if(!pRetval)
{
pRetval = (bMono) ? new VirtualDevice(rOutDev, 1) : new VirtualDevice(rOutDev);
pRetval = new VirtualDevice(rOutDev, nBits);
pRetval->SetOutputSizePixel(rSizePixel, bClear);
}
else
......@@ -233,7 +233,7 @@ namespace drawinglayer
if(isVisible())
{
mpContent = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), false, false);
mpContent = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), false, 0);
// #i93485# assert when copying from window to VDev is used
OSL_ENSURE(mrOutDev.GetOutDevType() != OUTDEV_WINDOW,
......@@ -348,7 +348,7 @@ namespace drawinglayer
OSL_ENSURE(mpContent, "impBufferDevice: No content, check isVisible() before accessing (!)");
if(!mpMask)
{
mpMask = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), true, true);
mpMask = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), true, 1);
mpMask->SetMapMode(mpContent->GetMapMode());
// do NOT copy AA flag for mask!
......@@ -362,7 +362,7 @@ namespace drawinglayer
OSL_ENSURE(mpContent, "impBufferDevice: No content, check isVisible() before accessing (!)");
if(!mpAlpha)
{
mpAlpha = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), true, false);
mpAlpha = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), true, 8);
mpAlpha->SetMapMode(mpContent->GetMapMode());
// copy AA flag for new target; masking needs to be smooth
......
......@@ -55,6 +55,7 @@ public:
int mnWidth;
int mnHeight;
sal_uInt32 mnBytesPerRow;
void* maExternalData;
public:
QuartzSalBitmap();
......@@ -70,6 +71,8 @@ public:
virtual bool Create( const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XBitmapCanvas > xBitmapCanvas,
Size& rSize,
bool bMask = false );
// creating quartz wrapper from existing buffer
bool Create( BitmapBuffer& buffer);
void Destroy();
......@@ -93,6 +96,7 @@ private:
public:
bool Create( CGLayerRef xLayer, int nBitCount, int nX, int nY, int nWidth, int nHeight );
bool Create( CGImageRef xImage, int nBitCount, int nX, int nY, int nWidth, int nHeight );
public:
CGImageRef CreateWithMask( const QuartzSalBitmap& rMask, int nX, int nY, int nWidth, int nHeight ) const;
......
......@@ -62,6 +62,7 @@ QuartzSalBitmap::QuartzSalBitmap()
, mnWidth(0)
, mnHeight(0)
, mnBytesPerRow(0)
, maExternalData(NULL)
{
}
......@@ -102,12 +103,68 @@ bool QuartzSalBitmap::Create( CGLayerRef xLayer, int nBitmapBits,
// copy layer content into the bitmap buffer
const CGPoint aSrcPoint = { static_cast<CGFloat>(-nX), static_cast<CGFloat>(-nY) };
if(mxGraphicContext) // remove warning
CGContextDrawLayerAtPoint( mxGraphicContext, aSrcPoint, xLayer );
return true;
}
// ------------------------------------------------------------------
bool QuartzSalBitmap::Create( CGImageRef xImage, int nBitmapBits,
int nX, int nY, int nWidth, int nHeight )
{
DBG_ASSERT( xImage, "QuartzSalBitmap::Create() from null image" );
// sanitize input parameters
if( nX < 0 )
nWidth += nX, nX = 0;
if( nY < 0 )
nHeight += nY, nY = 0;
const CGSize aLayerSize = CGSizeMake(CGImageGetWidth(xImage), CGImageGetHeight(xImage));
if( nWidth >= (int)aLayerSize.width - nX )
nWidth = (int)aLayerSize.width - nX;
if( nHeight >= (int)aLayerSize.height - nY )
nHeight = (int)aLayerSize.height - nY;
if( (nWidth < 0) || (nHeight < 0) )
nWidth = nHeight = 0;
// initialize properties
mnWidth = nWidth;
mnHeight = nHeight;
mnBits = nBitmapBits ? nBitmapBits : 32;
// initialize drawing context
CreateContext();
// copy layer content into the bitmap buffer
if(mxGraphicContext) // remove warning
CGContextDrawImage( mxGraphicContext,
CGRectMake(static_cast<CGFloat>(-nX),
static_cast<CGFloat>(-nY),
aLayerSize.width,
aLayerSize.height),
xImage );
return true;
}
bool QuartzSalBitmap::Create( BitmapBuffer& buffer)
{
// initialize properties
mnWidth = buffer.mnWidth;
mnHeight = buffer.mnHeight;
mnBits = buffer.mnBitCount;
mnBytesPerRow = buffer.mnScanlineSize;
maExternalData = buffer.mpBits;
maPalette = buffer.maPalette;
// initialize drawing context
CreateContext();
return true;
}
// ------------------------------------------------------------------
bool QuartzSalBitmap::Create( const Size& rSize, sal_uInt16 nBits, const BitmapPalette& rBitmapPalette )
{
if( !isValidBitCount( nBits ) )
......@@ -168,6 +225,7 @@ void QuartzSalBitmap::Destroy()
{
DestroyContext();
maUserBuffer.reset();
maExternalData = NULL;
}
// ------------------------------------------------------------------
......@@ -193,27 +251,45 @@ bool QuartzSalBitmap::CreateContext()
// prepare graphics context
// convert image from user input if available
const bool bSkipConversion = !maUserBuffer;
const bool bSkipConversion = !maUserBuffer && !maExternalData;
if( bSkipConversion )
AllocateUserData();
// default to RGBA color space
#ifdef IOS
CGColorSpaceRef aCGColorSpace = CGColorSpaceCreateDeviceRGB();
#else
CGColorSpaceRef aCGColorSpace = GetSalData()->mxRGBSpace;
#endif
CGBitmapInfo aCGBmpInfo = kCGImageAlphaNoneSkipFirst;
// convert data into something accepted by CGBitmapContextCreate()
size_t bitsPerComponent = (mnBits == 16) ? 5 : 8;
sal_uInt32 nContextBytesPerRow = mnBytesPerRow;
if( (mnBits == 16) || (mnBits == 32) )
{
if (!maExternalData)
{
// no conversion needed for truecolor
maContextBuffer = maUserBuffer;
}
else if( (mnBits == 8) && maPalette.IsGreyPalette() )
}
else if( mnBits == 8
#ifndef IOS
&& maPalette.IsGreyPalette()
#endif
)
{
// no conversion needed for grayscale
if (!maExternalData)
{
maContextBuffer = maUserBuffer;
}
#ifdef IOS
aCGColorSpace = CGColorSpaceCreateDeviceGray();
#else
aCGColorSpace = GetSalData()->mxGraySpace;
#endif
aCGBmpInfo = kCGImageAlphaNone;
bitsPerComponent = mnBits;
}
......@@ -237,9 +313,14 @@ bool QuartzSalBitmap::CreateContext()
}
}
if( maContextBuffer.get() )
if(maExternalData)
{
mxGraphicContext = ::CGBitmapContextCreate( maExternalData, mnWidth, mnHeight,
bitsPerComponent, nContextBytesPerRow, aCGColorSpace, aCGBmpInfo );
}
else if( maContextBuffer.get() )
{
mxGraphicContext = CGBitmapContextCreate( maContextBuffer.get(), mnWidth, mnHeight,
mxGraphicContext = ::CGBitmapContextCreate( maContextBuffer.get(), mnWidth, mnHeight,
bitsPerComponent, nContextBytesPerRow, aCGColorSpace, aCGBmpInfo );
}
......@@ -280,7 +361,7 @@ bool QuartzSalBitmap::AllocateUserData()
catch( const std::bad_alloc& )
{
OSL_FAIL( "vcl::QuartzSalBitmap::AllocateUserData: bad alloc" );
maUserBuffer.reset();
maUserBuffer.reset( static_cast<sal_uInt8*>(NULL) );
mnBytesPerRow = 0;
}
......@@ -771,7 +852,7 @@ CGImageRef QuartzSalBitmap::CreateWithMask( const QuartzSalBitmap& rMask,
// CGImageCreateWithMask() only likes masks or greyscale images => convert if needed
// TODO: isolate in an extra method?
if( !CGImageIsMask(xMask) || (CGImageGetColorSpace(xMask) != GetSalData()->mxGraySpace) )
if( !CGImageIsMask(xMask) || rMask.GetBitCount() != 8)//(CGImageGetColorSpace(xMask) != GetSalData()->mxGraySpace) )
{
const CGRect xImageRect=CGRectMake( 0, 0, nWidth, nHeight );//the rect has no offset
......
......@@ -806,6 +806,8 @@ bool SvpSalGraphics::CheckContext()
{
if (mbForeignContext)
return true;
if(m_aDevice == NULL) // fix tiledrendering crash when changing content size
return false;
const basegfx::B2IVector size = m_aDevice->getSize();
const basegfx::B2IVector bufferSize = m_aDevice->getBufferSize();
......@@ -829,32 +831,14 @@ bool SvpSalGraphics::CheckContext()
kCGImageAlphaNone);
break;
case basebmp::FORMAT_THIRTYTWO_BIT_TC_MASK_RGBA:
mrContext = CGBitmapContextCreate(pixelBuffer.get(),
bufferSize.getX(), bufferSize.getY(),
8, scanlineStride,
CGColorSpaceCreateDeviceRGB(),
kCGImageAlphaNoneSkipLast);
break;
case basebmp::FORMAT_THIRTYTWO_BIT_TC_MASK_ARGB:
mrContext = CGBitmapContextCreate(pixelBuffer.get(),
bufferSize.getX(), bufferSize.getY(),
8, scanlineStride,
CGColorSpaceCreateDeviceRGB(),
kCGImageAlphaNoneSkipFirst);
break;
case basebmp::FORMAT_THIRTYTWO_BIT_TC_MASK_BGRA:
mrContext = CGBitmapContextCreate(pixelBuffer.get(),
bufferSize.getX(), bufferSize.getY(),
8, scanlineStride,
CGColorSpaceCreateDeviceRGB(),
kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little);
break;
case basebmp::FORMAT_THIRTYTWO_BIT_TC_MASK_ABGR:
case basebmp::FORMAT_THIRTYTWO_BIT_TC_MASK_BGRA:
mrContext = CGBitmapContextCreate(pixelBuffer.get(),
bufferSize.getX(), bufferSize.getY(),
8, scanlineStride,
CGColorSpaceCreateDeviceRGB(),
kCGImageAlphaNoneSkipLast | kCGBitmapByteOrder32Little);
kCGImageAlphaNoneSkipFirst);//kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little);
break;
default:
SAL_WARN( "vcl.ios", "CheckContext: unsupported color format " << basebmp::formatName( m_aDevice->getScanlineFormat() ) );
......
......@@ -35,6 +35,8 @@
#ifdef IOS
#include "saldatabasic.hxx"
#include "headless/svpbmp.hxx"
#include <basegfx/range/b2ibox.hxx>
#endif
using namespace vcl;
......@@ -285,12 +287,6 @@ static inline void alignLinePoint( const SalPoint* i_pIn, float& o_fX, float& o_
void AquaSalGraphics::copyBits( const SalTwoRect& rPosAry, SalGraphics *pSrcGraphics )
{
#ifdef IOS
// Horrible horrible this is all crack, mxLayer is always NULL on iOS,
// all this stuff should be rewritten anyway for iOS
if( !mxLayer )
return;
#endif
if( !pSrcGraphics )
{
......@@ -335,12 +331,9 @@ void AquaSalGraphics::copyBits( const SalTwoRect& rPosAry, SalGraphics *pSrcGrap
const CGPoint aDstPoint = CGPointMake(+rPosAry.mnDestX - rPosAry.mnSrcX, rPosAry.mnDestY - rPosAry.mnSrcY);
if( (rPosAry.mnSrcWidth == rPosAry.mnDestWidth &&
rPosAry.mnSrcHeight == rPosAry.mnDestHeight) &&
(!mnBitmapDepth || (aDstPoint.x + pSrc->mnWidth) <= mnWidth) ) // workaround a Quartz crasher
(!mnBitmapDepth || (aDstPoint.x + pSrc->mnWidth) <= mnWidth)
&& pSrc->mxLayer ) // workaround a Quartz crasher
{
#ifdef IOS
if( !CheckContext() )
return;
#endif
// in XOR mode the drawing context is redirected to the XOR mask
// if source and target are identical then copyBits() paints onto the target context though
CGContextRef xCopyContext = mrContext;
......@@ -895,6 +888,25 @@ bool AquaSalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPol
// #i97317# workaround for Quartz having problems with drawing small polygons
if( ! ((aRefreshRect.size.width <= 0.125) && (aRefreshRect.size.height <= 0.125)) )
{
// prepare drawing mode
CGPathDrawingMode eMode;
if( IsBrushVisible() && IsPenVisible() )
{
eMode = kCGPathEOFillStroke;
}
else if( IsPenVisible() )
{
eMode = kCGPathStroke;
}
else if( IsBrushVisible() )
{
eMode = kCGPathEOFill;
}
else
{
return true;
}
// use the path to prepare the graphics context
CGContextSaveGState( mrContext );
CGContextBeginPath( mrContext );
......@@ -903,7 +915,7 @@ bool AquaSalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPol
// draw path with antialiased polygon
CGContextSetShouldAntialias( mrContext, true );
CGContextSetAlpha( mrContext, 1.0 - fTransparency );
CGContextDrawPath( mrContext, kCGPathEOFillStroke );
CGContextDrawPath( mrContext, eMode );
CGContextRestoreGState( mrContext );
// mark modified rectangle as updated
......@@ -1145,6 +1157,44 @@ sal_uInt16 AquaSalGraphics::GetBitCount() const
SalBitmap* AquaSalGraphics::getBitmap( long nX, long nY, long nDX, long nDY )
{
if (!mbForeignContext && m_aDevice != NULL)
{
// on ios virtual device are Svp so use Svp bitmap to get the content
basegfx::B2IBox aRect( nX, nY, nX+nDX, nY+nDY );
basebmp::BitmapDeviceSharedPtr aSubSet = basebmp::subsetBitmapDevice(m_aDevice , aRect );
SvpSalBitmap* pSalBitmap = new SvpSalBitmap;
pSalBitmap->setBitmap(aSubSet);
BitmapBuffer* pBuffer = pSalBitmap->AcquireBuffer(true);
QuartzSalBitmap* pBitmap = new QuartzSalBitmap;
if( !pBitmap->Create(*pBuffer))
{
delete pBitmap;
pBitmap = NULL;
}
pSalBitmap->ReleaseBuffer(pBuffer, true);
delete pSalBitmap;
return pBitmap;
}
else if (mbForeignContext)
{
//if using external context like on ios, check if we can get a backing image and copy it
CGImageRef backImage = CGBitmapContextCreateImage(mrContext);
if (backImage)
{
QuartzSalBitmap* pBitmap = new QuartzSalBitmap;
if( !pBitmap->Create(backImage, mnBitmapDepth, nX, nY, nDX, nDY))
{
delete pBitmap;
pBitmap = NULL;
}
CGImageRelease(backImage);
return pBitmap;
}
return NULL;
}
else
{
DBG_ASSERT( mxLayer, "AquaSalGraphics::getBitmap() with no layer" );
ApplyXorContext();
......@@ -1155,8 +1205,8 @@ SalBitmap* AquaSalGraphics::getBitmap( long nX, long nY, long nDX, long nDY
delete pBitmap;
pBitmap = NULL;
}
return pBitmap;
}
}
#ifndef IOS
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment