bump product version to 7.2.5.1
[LibreOffice.git] / vcl / quartz / salbmp.cxx
blob8fadba1b509e9cdc169c669169a9c7f7db8226c7
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
21 #include <sal/log.hxx>
22 #include <osl/diagnose.h>
24 #include <cstddef>
25 #include <limits>
27 #include <o3tl/make_shared.hxx>
28 #include <tools/color.hxx>
29 #include <vcl/bitmap.hxx>
30 #include <vcl/BitmapAccessMode.hxx>
31 #include <vcl/BitmapBuffer.hxx>
32 #include <vcl/BitmapColor.hxx>
33 #include <vcl/BitmapPalette.hxx>
34 #include <vcl/ColorMask.hxx>
35 #include <vcl/Scanline.hxx>
37 #include <bitmap/bmpfast.hxx>
38 #include <quartz/salbmp.h>
39 #include <quartz/utils.h>
40 #include <bitmap/ScanlineTools.hxx>
42 #ifdef MACOSX
43 #include <osx/saldata.hxx>
44 #else
45 #include "saldatabasic.hxx"
46 #endif
48 const unsigned long k32BitRedColorMask = 0x00ff0000;
49 const unsigned long k32BitGreenColorMask = 0x0000ff00;
50 const unsigned long k32BitBlueColorMask = 0x000000ff;
52 QuartzSalBitmap::QuartzSalBitmap()
53 : mxCachedImage( nullptr )
54 , mnBits(0)
55 , mnWidth(0)
56 , mnHeight(0)
57 , mnBytesPerRow(0)
61 QuartzSalBitmap::~QuartzSalBitmap()
63 doDestroy();
66 bool QuartzSalBitmap::Create( const Size& rSize, vcl::PixelFormat ePixelFormat, const BitmapPalette& rBitmapPalette )
68 if (ePixelFormat == vcl::PixelFormat::INVALID)
69 return false;
71 maPalette = rBitmapPalette;
72 mnBits = vcl::pixelFormatBitCount(ePixelFormat);
73 mnWidth = rSize.Width();
74 mnHeight = rSize.Height();
75 return AllocateUserData();
78 bool QuartzSalBitmap::Create( const SalBitmap& rSalBmp )
80 vcl::PixelFormat ePixelFormat = vcl::bitDepthToPixelFormat(rSalBmp.GetBitCount());
81 return Create( rSalBmp, ePixelFormat);
84 bool QuartzSalBitmap::Create( const SalBitmap& rSalBmp, SalGraphics* pGraphics )
86 vcl::PixelFormat ePixelFormat = vcl::PixelFormat::INVALID;
87 if (pGraphics)
88 ePixelFormat = vcl::bitDepthToPixelFormat(pGraphics->GetBitCount());
89 else
90 ePixelFormat = vcl::bitDepthToPixelFormat(rSalBmp.GetBitCount());
92 return Create( rSalBmp, ePixelFormat);
95 bool QuartzSalBitmap::Create( const SalBitmap& rSalBmp, vcl::PixelFormat eNewPixelFormat )
97 const QuartzSalBitmap& rSourceBitmap = static_cast<const QuartzSalBitmap&>(rSalBmp);
99 if (eNewPixelFormat != vcl::PixelFormat::INVALID && rSourceBitmap.m_pUserBuffer)
101 mnBits = vcl::pixelFormatBitCount(eNewPixelFormat);
102 mnWidth = rSourceBitmap.mnWidth;
103 mnHeight = rSourceBitmap.mnHeight;
104 maPalette = rSourceBitmap.maPalette;
106 if( AllocateUserData() )
108 ConvertBitmapData( mnWidth, mnHeight, mnBits, mnBytesPerRow, maPalette,
109 m_pUserBuffer.get(), rSourceBitmap.mnBits,
110 rSourceBitmap.mnBytesPerRow, rSourceBitmap.maPalette,
111 rSourceBitmap.m_pUserBuffer.get() );
112 return true;
115 return false;
118 bool QuartzSalBitmap::Create( const css::uno::Reference< css::rendering::XBitmapCanvas >& /*xBitmapCanvas*/,
119 Size& /*rSize*/, bool /*bMask*/ )
121 return false;
124 void QuartzSalBitmap::Destroy()
126 doDestroy();
129 void QuartzSalBitmap::doDestroy()
131 DestroyContext();
132 m_pUserBuffer.reset();
135 void QuartzSalBitmap::DestroyContext()
137 if( mxCachedImage )
139 CGImageRelease( mxCachedImage );
140 mxCachedImage = nullptr;
143 if (maGraphicContext.isSet())
145 CGContextRelease(maGraphicContext.get());
146 maGraphicContext.set(nullptr);
147 m_pContextBuffer.reset();
151 bool QuartzSalBitmap::CreateContext()
153 DestroyContext();
155 // prepare graphics context
156 // convert image from user input if available
157 const bool bSkipConversion = !m_pUserBuffer;
158 if( bSkipConversion )
159 AllocateUserData();
161 // default to RGBA color space
162 CGColorSpaceRef aCGColorSpace = GetSalData()->mxRGBSpace;
163 CGBitmapInfo aCGBmpInfo = kCGImageAlphaNoneSkipFirst;
165 // convert data into something accepted by CGBitmapContextCreate()
166 size_t bitsPerComponent = 8;
167 sal_uInt32 nContextBytesPerRow = mnBytesPerRow;
168 if( mnBits == 32 )
170 // no conversion needed for truecolor
171 m_pContextBuffer = m_pUserBuffer;
173 else if( mnBits == 8 && maPalette.IsGreyPalette8Bit() )
175 // no conversion needed for grayscale
176 m_pContextBuffer = m_pUserBuffer;
177 aCGColorSpace = GetSalData()->mxGraySpace;
178 aCGBmpInfo = kCGImageAlphaNone;
179 bitsPerComponent = mnBits;
181 // TODO: is special handling for 1bit input buffers worth it?
182 else
184 // convert user data to 32 bit
185 nContextBytesPerRow = mnWidth << 2;
188 m_pContextBuffer = o3tl::make_shared_array<sal_uInt8>(mnHeight * nContextBytesPerRow);
190 if( !bSkipConversion )
192 ConvertBitmapData( mnWidth, mnHeight,
193 32, nContextBytesPerRow, maPalette, m_pContextBuffer.get(),
194 mnBits, mnBytesPerRow, maPalette, m_pUserBuffer.get() );
197 catch( const std::bad_alloc& )
199 maGraphicContext.set(nullptr);
203 if (m_pContextBuffer)
205 maGraphicContext.set(CGBitmapContextCreate(m_pContextBuffer.get(), mnWidth, mnHeight,
206 bitsPerComponent, nContextBytesPerRow,
207 aCGColorSpace, aCGBmpInfo));
210 if (!maGraphicContext.isSet())
211 m_pContextBuffer.reset();
213 return maGraphicContext.isSet();
216 bool QuartzSalBitmap::AllocateUserData()
218 Destroy();
220 if( mnWidth && mnHeight )
222 mnBytesPerRow = 0;
224 switch( mnBits )
226 case 1: mnBytesPerRow = (mnWidth + 7) >> 3; break;
227 case 4: mnBytesPerRow = (mnWidth + 1) >> 1; break;
228 case 8: mnBytesPerRow = mnWidth; break;
229 case 24: mnBytesPerRow = (mnWidth << 1) + mnWidth; break;
230 case 32: mnBytesPerRow = mnWidth << 2; break;
231 default:
232 assert(false && "vcl::QuartzSalBitmap::AllocateUserData(), illegal bitcount!");
236 bool alloc = false;
237 if (mnBytesPerRow != 0 &&
238 mnBytesPerRow <= std::numeric_limits<sal_uInt32>::max() / mnHeight)
242 m_pUserBuffer = o3tl::make_shared_array<sal_uInt8>(mnBytesPerRow * mnHeight);
243 alloc = true;
245 catch (std::bad_alloc &) {}
247 if (!alloc)
249 SAL_WARN( "vcl.quartz", "bad_alloc: " << mnWidth << "x" << mnHeight << " (" << mnBytesPerRow * mnHeight << " bytes)");
250 m_pUserBuffer.reset();
251 mnBytesPerRow = 0;
254 return bool(m_pUserBuffer);
257 void QuartzSalBitmap::ConvertBitmapData( sal_uInt32 nWidth, sal_uInt32 nHeight,
258 sal_uInt16 nDestBits, sal_uInt32 nDestBytesPerRow,
259 const BitmapPalette& rDestPalette, sal_uInt8* pDestData,
260 sal_uInt16 nSrcBits, sal_uInt32 nSrcBytesPerRow,
261 const BitmapPalette& rSrcPalette, sal_uInt8* pSrcData )
264 if( (nDestBytesPerRow == nSrcBytesPerRow) &&
265 (nDestBits == nSrcBits) && ((nSrcBits != 8) || (rDestPalette.operator==( rSrcPalette ))) )
267 // simple case, same format, so just copy
268 memcpy( pDestData, pSrcData, nHeight * nDestBytesPerRow );
269 return;
272 // try accelerated conversion if possible
273 // TODO: are other truecolor conversions except BGR->ARGB worth it?
274 bool bConverted = false;
275 if( (nSrcBits == 24) && (nDestBits == 32) )
277 // TODO: extend bmpfast.cxx with a method that can be directly used here
278 BitmapBuffer aSrcBuf;
279 aSrcBuf.mnFormat = ScanlineFormat::N24BitTcBgr;
280 aSrcBuf.mpBits = pSrcData;
281 aSrcBuf.mnBitCount = nSrcBits;
282 aSrcBuf.mnScanlineSize = nSrcBytesPerRow;
283 BitmapBuffer aDstBuf;
284 aDstBuf.mnFormat = ScanlineFormat::N32BitTcArgb;
285 aDstBuf.mpBits = pDestData;
286 aDstBuf.mnBitCount = nDestBits;
287 aDstBuf.mnScanlineSize = nDestBytesPerRow;
289 aSrcBuf.mnWidth = aDstBuf.mnWidth = nWidth;
290 aSrcBuf.mnHeight = aDstBuf.mnHeight = nHeight;
292 SalTwoRect aTwoRects(0, 0, mnWidth, mnHeight, 0, 0, mnWidth, mnHeight);
293 bConverted = ::ImplFastBitmapConversion( aDstBuf, aSrcBuf, aTwoRects );
296 if( !bConverted )
298 // TODO: this implementation is for clarity, not for speed
300 auto pTarget = vcl::bitmap::getScanlineTransformer(nDestBits, rDestPalette);
301 auto pSource = vcl::bitmap::getScanlineTransformer(nSrcBits, rSrcPalette);
303 if (pTarget && pSource)
305 sal_uInt32 nY = nHeight;
306 while( nY-- )
308 pTarget->startLine(pDestData);
309 pSource->startLine(pSrcData);
311 sal_uInt32 nX = nWidth;
312 while( nX-- )
314 pTarget->writePixel(pSource->readPixel());
316 pSrcData += nSrcBytesPerRow;
317 pDestData += nDestBytesPerRow;
323 Size QuartzSalBitmap::GetSize() const
325 return Size( mnWidth, mnHeight );
328 sal_uInt16 QuartzSalBitmap::GetBitCount() const
330 return mnBits;
333 namespace {
335 struct pal_entry
337 sal_uInt8 mnRed;
338 sal_uInt8 mnGreen;
339 sal_uInt8 mnBlue;
344 pal_entry const aImplSalSysPalEntryAry[ 16 ] =
346 { 0, 0, 0 },
347 { 0, 0, 0x80 },
348 { 0, 0x80, 0 },
349 { 0, 0x80, 0x80 },
350 { 0x80, 0, 0 },
351 { 0x80, 0, 0x80 },
352 { 0x80, 0x80, 0 },
353 { 0x80, 0x80, 0x80 },
354 { 0xC0, 0xC0, 0xC0 },
355 { 0, 0, 0xFF },
356 { 0, 0xFF, 0 },
357 { 0, 0xFF, 0xFF },
358 { 0xFF, 0, 0 },
359 { 0xFF, 0, 0xFF },
360 { 0xFF, 0xFF, 0 },
361 { 0xFF, 0xFF, 0xFF }
364 static const BitmapPalette& GetDefaultPalette( int mnBits, bool bMonochrome )
366 if( bMonochrome )
367 return Bitmap::GetGreyPalette( 1U << mnBits );
369 // at this point we should provide some kind of default palette
370 // since all other platforms do so, too.
371 static bool bDefPalInit = false;
372 static BitmapPalette aDefPalette256;
373 static BitmapPalette aDefPalette16;
374 static BitmapPalette aDefPalette2;
375 if( ! bDefPalInit )
377 bDefPalInit = true;
378 aDefPalette256.SetEntryCount( 256 );
379 aDefPalette16.SetEntryCount( 16 );
380 aDefPalette2.SetEntryCount( 2 );
382 // Standard colors
383 unsigned int i;
384 for( i = 0; i < 16; i++ )
386 aDefPalette16[i] =
387 aDefPalette256[i] = BitmapColor( aImplSalSysPalEntryAry[i].mnRed,
388 aImplSalSysPalEntryAry[i].mnGreen,
389 aImplSalSysPalEntryAry[i].mnBlue );
392 aDefPalette2[0] = BitmapColor( 0, 0, 0 );
393 aDefPalette2[1] = BitmapColor( 0xff, 0xff, 0xff );
395 // own palette (6/6/6)
396 const int DITHER_PAL_STEPS = 6;
397 const sal_uInt8 DITHER_PAL_DELTA = 51;
398 int nB, nG, nR;
399 sal_uInt8 nRed, nGreen, nBlue;
400 for( nB=0, nBlue=0; nB < DITHER_PAL_STEPS; nB++, nBlue += DITHER_PAL_DELTA )
402 for( nG=0, nGreen=0; nG < DITHER_PAL_STEPS; nG++, nGreen += DITHER_PAL_DELTA )
404 for( nR=0, nRed=0; nR < DITHER_PAL_STEPS; nR++, nRed += DITHER_PAL_DELTA )
406 aDefPalette256[ i ] = BitmapColor( nRed, nGreen, nBlue );
407 i++;
413 // now fill in appropriate palette
414 switch( mnBits )
416 case 1: return aDefPalette2;
417 case 4: return aDefPalette16;
418 case 8: return aDefPalette256;
419 default: break;
422 const static BitmapPalette aEmptyPalette;
423 return aEmptyPalette;
426 BitmapBuffer* QuartzSalBitmap::AcquireBuffer( BitmapAccessMode /*nMode*/ )
428 // TODO: AllocateUserData();
429 if (!m_pUserBuffer)
430 return nullptr;
432 BitmapBuffer* pBuffer = new BitmapBuffer;
433 pBuffer->mnWidth = mnWidth;
434 pBuffer->mnHeight = mnHeight;
435 pBuffer->maPalette = maPalette;
436 pBuffer->mnScanlineSize = mnBytesPerRow;
437 pBuffer->mpBits = m_pUserBuffer.get();
438 pBuffer->mnBitCount = mnBits;
439 switch( mnBits )
441 case 1:
442 pBuffer->mnFormat = ScanlineFormat::N1BitMsbPal;
443 break;
444 case 8:
445 pBuffer->mnFormat = ScanlineFormat::N8BitPal;
446 break;
447 case 24:
448 pBuffer->mnFormat = ScanlineFormat::N24BitTcBgr;
449 break;
450 case 32:
452 pBuffer->mnFormat = ScanlineFormat::N32BitTcArgb;
453 ColorMaskElement aRedMask(k32BitRedColorMask);
454 aRedMask.CalcMaskShift();
455 ColorMaskElement aGreenMask(k32BitGreenColorMask);
456 aGreenMask.CalcMaskShift();
457 ColorMaskElement aBlueMask(k32BitBlueColorMask);
458 aBlueMask.CalcMaskShift();
459 pBuffer->maColorMask = ColorMask(aRedMask, aGreenMask, aBlueMask);
460 break;
462 default: assert(false);
465 // some BitmapBuffer users depend on a complete palette
466 if( (mnBits <= 8) && !maPalette )
467 pBuffer->maPalette = GetDefaultPalette( mnBits, true );
469 return pBuffer;
472 void QuartzSalBitmap::ReleaseBuffer( BitmapBuffer* pBuffer, BitmapAccessMode nMode )
474 // invalidate graphic context if we have different data
475 if( nMode == BitmapAccessMode::Write )
477 maPalette = pBuffer->maPalette;
478 if (maGraphicContext.isSet())
480 DestroyContext();
482 InvalidateChecksum();
485 delete pBuffer;
488 CGImageRef QuartzSalBitmap::CreateCroppedImage( int nX, int nY, int nNewWidth, int nNewHeight ) const
490 if( !mxCachedImage )
492 if (!maGraphicContext.isSet())
494 if( !const_cast<QuartzSalBitmap*>(this)->CreateContext() )
496 return nullptr;
499 mxCachedImage = CGBitmapContextCreateImage(maGraphicContext.get());
502 CGImageRef xCroppedImage = nullptr;
503 // short circuit if there is nothing to crop
504 if( !nX && !nY && (mnWidth == nNewWidth) && (mnHeight == nNewHeight) )
506 xCroppedImage = mxCachedImage;
507 CFRetain( xCroppedImage );
509 else
511 nY = mnHeight - (nY + nNewHeight); // adjust for y-mirrored context
512 const CGRect aCropRect = { { static_cast<CGFloat>(nX), static_cast<CGFloat>(nY) }, { static_cast<CGFloat>(nNewWidth), static_cast<CGFloat>(nNewHeight) } };
513 xCroppedImage = CGImageCreateWithImageInRect( mxCachedImage, aCropRect );
516 return xCroppedImage;
519 static void CFRTLFree(void* /*info*/, const void* data, size_t /*size*/)
521 std::free( const_cast<void*>(data) );
524 CGImageRef QuartzSalBitmap::CreateWithMask( const QuartzSalBitmap& rMask,
525 int nX, int nY, int nWidth, int nHeight ) const
527 CGImageRef xImage( CreateCroppedImage( nX, nY, nWidth, nHeight ) );
528 if( !xImage )
529 return nullptr;
531 CGImageRef xMask = rMask.CreateCroppedImage( nX, nY, nWidth, nHeight );
532 if( !xMask )
533 return xImage;
535 // CGImageCreateWithMask() only likes masks or greyscale images => convert if needed
536 // TODO: isolate in an extra method?
537 if( !CGImageIsMask(xMask) || rMask.GetBitCount() != 8)//(CGImageGetColorSpace(xMask) != GetSalData()->mxGraySpace) )
539 const CGRect xImageRect=CGRectMake( 0, 0, nWidth, nHeight );//the rect has no offset
541 // create the alpha mask image fitting our image
542 // TODO: is caching the full mask or the subimage mask worth it?
543 int nMaskBytesPerRow = ((nWidth + 3) & ~3);
544 void* pMaskMem = std::malloc( nMaskBytesPerRow * nHeight );
545 CGContextRef xMaskContext = CGBitmapContextCreate( pMaskMem,
546 nWidth, nHeight, 8, nMaskBytesPerRow, GetSalData()->mxGraySpace, kCGImageAlphaNone );
547 CGContextDrawImage( xMaskContext, xImageRect, xMask );
548 CFRelease( xMask );
549 CGDataProviderRef xDataProvider( CGDataProviderCreateWithData( nullptr,
550 pMaskMem, nHeight * nMaskBytesPerRow, &CFRTLFree ) );
552 static const CGFloat* pDecode = nullptr;
553 xMask = CGImageMaskCreate( nWidth, nHeight, 8, 8, nMaskBytesPerRow, xDataProvider, pDecode, false );
554 CFRelease( xDataProvider );
555 CFRelease( xMaskContext );
558 if( !xMask )
559 return xImage;
561 // combine image and alpha mask
562 CGImageRef xMaskedImage = CGImageCreateWithMask( xImage, xMask );
563 CFRelease( xMask );
564 CFRelease( xImage );
565 return xMaskedImage;
568 /** creates an image from the given rectangle, replacing all black pixels
569 with nMaskColor and make all other full transparent */
570 CGImageRef QuartzSalBitmap::CreateColorMask( int nX, int nY, int nWidth,
571 int nHeight, Color nMaskColor ) const
573 CGImageRef xMask = nullptr;
574 if (m_pUserBuffer && (nX + nWidth <= mnWidth) && (nY + nHeight <= mnHeight))
576 const sal_uInt32 nDestBytesPerRow = nWidth << 2;
577 std::unique_ptr<sal_uInt32[]> pMaskBuffer(new (std::nothrow) sal_uInt32[ nHeight * nDestBytesPerRow / 4] );
578 sal_uInt32* pDest = pMaskBuffer.get();
580 auto pSourcePixels = vcl::bitmap::getScanlineTransformer(mnBits, maPalette);
582 if( pMaskBuffer && pSourcePixels )
584 sal_uInt32 nColor;
585 reinterpret_cast<sal_uInt8*>(&nColor)[0] = 0xff;
586 reinterpret_cast<sal_uInt8*>(&nColor)[1] = nMaskColor.GetRed();
587 reinterpret_cast<sal_uInt8*>(&nColor)[2] = nMaskColor.GetGreen();
588 reinterpret_cast<sal_uInt8*>(&nColor)[3] = nMaskColor.GetBlue();
590 sal_uInt8* pSource = m_pUserBuffer.get();
591 // First to nY on y-axis, as that is our starting point (sub-image)
592 if( nY )
593 pSource += nY * mnBytesPerRow;
595 int y = nHeight;
596 while( y-- )
598 pSourcePixels->startLine( pSource );
599 pSourcePixels->skipPixel(nX); // Skip on x axis to nX
600 sal_uInt32 x = nWidth;
601 while( x-- )
603 *pDest++ = (pSourcePixels->readPixel() == 0) ? nColor : 0;
605 pSource += mnBytesPerRow;
608 CGDataProviderRef xDataProvider( CGDataProviderCreateWithData(nullptr, pMaskBuffer.release(), nHeight * nDestBytesPerRow, &CFRTLFree) );
609 xMask = CGImageCreate(nWidth, nHeight, 8, 32, nDestBytesPerRow, GetSalData()->mxRGBSpace, kCGImageAlphaPremultipliedFirst, xDataProvider, nullptr, true, kCGRenderingIntentDefault);
610 CFRelease(xDataProvider);
613 return xMask;
616 /** QuartzSalBitmap::GetSystemData Get platform native image data from existing image
618 * @param rData struct BitmapSystemData, defined in vcl/inc/bitmap.hxx
619 * @return true if successful
621 bool QuartzSalBitmap::GetSystemData( BitmapSystemData& rData )
623 bool bRet = false;
625 if (!maGraphicContext.isSet())
626 CreateContext();
628 if (maGraphicContext.isSet())
630 bRet = true;
632 if ((CGBitmapContextGetBitsPerPixel(maGraphicContext.get()) == 32) &&
633 (CGBitmapContextGetBitmapInfo(maGraphicContext.get()) & kCGBitmapByteOrderMask) != kCGBitmapByteOrder32Host)
636 * We need to hack things because VCL does not use kCGBitmapByteOrder32Host, while Cairo requires it.
638 * Not sure what the above comment means. We don't use Cairo on macOS or iOS.
640 * This whole if statement was originally (before 2011) inside #ifdef CAIRO. Did we use Cairo on Mac back then?
641 * Anyway, nowadays (since many years, I think) we don't, so should this if statement be dropped? Fun.
644 CGImageRef xImage = CGBitmapContextCreateImage(maGraphicContext.get());
646 // re-create the context with single change: include kCGBitmapByteOrder32Host flag.
647 CGContextHolder aGraphicContextNew(CGBitmapContextCreate(CGBitmapContextGetData(maGraphicContext.get()),
648 CGBitmapContextGetWidth(maGraphicContext.get()),
649 CGBitmapContextGetHeight(maGraphicContext.get()),
650 CGBitmapContextGetBitsPerComponent(maGraphicContext.get()),
651 CGBitmapContextGetBytesPerRow(maGraphicContext.get()),
652 CGBitmapContextGetColorSpace(maGraphicContext.get()),
653 CGBitmapContextGetBitmapInfo(maGraphicContext.get()) | kCGBitmapByteOrder32Host));
654 CFRelease(maGraphicContext.get());
656 // Needs to be flipped
657 aGraphicContextNew.saveState();
658 CGContextTranslateCTM (aGraphicContextNew.get(), 0, CGBitmapContextGetHeight(aGraphicContextNew.get()));
659 CGContextScaleCTM (aGraphicContextNew.get(), 1.0, -1.0);
661 CGContextDrawImage(aGraphicContextNew.get(), CGRectMake( 0, 0, CGImageGetWidth(xImage), CGImageGetHeight(xImage)), xImage);
663 // Flip back
664 CGContextRestoreGState( aGraphicContextNew.get() );
665 CGImageRelease( xImage );
666 maGraphicContext = aGraphicContextNew;
669 rData.mnWidth = mnWidth;
670 rData.mnHeight = mnHeight;
673 return bRet;
676 bool QuartzSalBitmap::ScalingSupported() const
678 return false;
681 bool QuartzSalBitmap::Scale( const double& /*rScaleX*/, const double& /*rScaleY*/, BmpScaleFlag /*nScaleFlag*/ )
683 return false;
686 bool QuartzSalBitmap::Replace( const Color& /*rSearchColor*/, const Color& /*rReplaceColor*/, sal_uInt8 /*nTol*/ )
688 return false;
691 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */