1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <canvas/debug.hxx>
21 #include <canvas/canvastools.hxx>
22 #include <tools/diagnose_ex.h>
24 #include "cairo_canvasbitmap.hxx"
26 #include <vcl/bmpacc.hxx>
27 #include <vcl/bitmapex.hxx>
29 #ifdef CAIRO_HAS_XLIB_SURFACE
30 # include "cairo_xlib_cairo.hxx"
31 #elif defined CAIRO_HAS_QUARTZ_SURFACE
32 # include "cairo_quartz_cairo.hxx"
33 #elif defined CAIRO_HAS_WIN32_SURFACE
34 # include "cairo_win32_cairo.hxx"
35 # include <cairo-win32.h>
37 # error Native API needed.
40 using namespace ::cairo
;
41 using namespace ::com::sun::star
;
43 #ifdef CAIRO_HAS_WIN32_SURFACE
46 HBITMAP
surface2HBitmap( const SurfaceSharedPtr
& rSurface
, const basegfx::B2ISize
& rSize
)
48 // cant seem to retrieve HBITMAP from cairo. copy content then
49 HDC hScreenDC
=GetDC(NULL
);
50 HBITMAP hBmpBitmap
= CreateCompatibleBitmap( hScreenDC
,
54 HDC hBmpDC
= CreateCompatibleDC( 0 );
55 HBITMAP hBmpOld
= (HBITMAP
) SelectObject( hBmpDC
, hBmpBitmap
);
57 BitBlt( hBmpDC
, 0, 0, rSize
.getX(), rSize
.getX(),
58 cairo_win32_surface_get_dc(rSurface
->getCairoSurface().get()),
61 SelectObject( hBmpDC
, hBmpOld
);
71 CanvasBitmap::CanvasBitmap( const ::basegfx::B2ISize
& rSize
,
72 const SurfaceProviderRef
& rSurfaceProvider
,
73 rendering::XGraphicDevice
* pDevice
,
75 mpSurfaceProvider( rSurfaceProvider
),
81 ENSURE_OR_THROW( mpSurfaceProvider
.is(),
82 "CanvasBitmap::CanvasBitmap(): Invalid surface or device" );
84 OSL_TRACE( "bitmap size: %dx%d", rSize
.getX(), rSize
.getY() );
86 mpBufferSurface
= mpSurfaceProvider
->createSurface( rSize
, bHasAlpha
? CAIRO_CONTENT_COLOR_ALPHA
: CAIRO_CONTENT_COLOR
);
87 mpBufferCairo
= mpBufferSurface
->getCairo();
89 maCanvasHelper
.init( rSize
, *mpSurfaceProvider
, pDevice
);
90 maCanvasHelper
.setSurface( mpBufferSurface
, bHasAlpha
);
92 // clear bitmap to 100% transparent
93 maCanvasHelper
.clear();
96 void CanvasBitmap::disposeThis()
98 mpSurfaceProvider
.clear();
100 mpBufferCairo
.reset();
101 mpBufferSurface
.reset();
104 CanvasBitmap_Base::disposeThis();
107 SurfaceSharedPtr
CanvasBitmap::getSurface()
109 return mpBufferSurface
;
112 SurfaceSharedPtr
CanvasBitmap::createSurface( const ::basegfx::B2ISize
& rSize
, Content aContent
)
114 return mpSurfaceProvider
->createSurface(rSize
,aContent
);
117 SurfaceSharedPtr
CanvasBitmap::createSurface( ::Bitmap
& rBitmap
)
119 return mpSurfaceProvider
->createSurface(rBitmap
);
122 SurfaceSharedPtr
CanvasBitmap::changeSurface( bool, bool )
124 // non-modifiable surface here
125 return SurfaceSharedPtr();
128 OutputDevice
* CanvasBitmap::getOutputDevice()
130 return mpSurfaceProvider
->getOutputDevice();
133 bool CanvasBitmap::repaint( const SurfaceSharedPtr
& pSurface
,
134 const rendering::ViewState
& viewState
,
135 const rendering::RenderState
& renderState
)
137 return maCanvasHelper
.repaint( pSurface
, viewState
, renderState
);
140 uno::Any SAL_CALL
CanvasBitmap::getFastPropertyValue( sal_Int32 nHandle
) throw (uno::RuntimeException
)
142 uno::Any
aRV( sal_Int32(0) );
143 // 0 ... get BitmapEx
144 // 1 ... get Pixbuf with bitmap RGB content
145 // 2 ... get Pixbuf with bitmap alpha mask
150 aRV
= uno::Any( reinterpret_cast<sal_Int64
>( (BitmapEx
*) NULL
) );
154 ::Size
aSize( maSize
.getX(), maSize
.getY() );
155 // FIXME: if we could teach VCL/ about cairo handles, life could
156 // be significantly better here perhaps.
157 cairo_surface_t
*pPixels
;
158 pPixels
= cairo_image_surface_create( CAIRO_FORMAT_ARGB32
,
159 aSize
.Width(), aSize
.Height() );
160 cairo_t
*pCairo
= cairo_create( pPixels
);
161 if( !pPixels
|| !pCairo
)
164 // suck ourselves from the X server to this buffer so then we can fiddle with
165 // Alpha to turn it into the ultra-lame vcl required format and then push it
166 // all back again later at vast expense [ urgh ]
167 cairo_set_source_surface( pCairo
, getSurface()->getCairoSurface().get(), 0, 0 );
168 cairo_set_operator( pCairo
, CAIRO_OPERATOR_SOURCE
);
169 cairo_paint( pCairo
);
171 ::Bitmap
aRGB( aSize
, 24 );
172 ::AlphaMask
aMask( aSize
);
174 BitmapWriteAccess
*pRGBWrite( aRGB
.AcquireWriteAccess() );
175 BitmapWriteAccess
*pMaskWrite( aMask
.AcquireWriteAccess() );
177 unsigned char *pSrc
= cairo_image_surface_get_data( pPixels
);
178 unsigned int nStride
= cairo_image_surface_get_stride( pPixels
);
179 for( unsigned long y
= 0; y
< (unsigned long) aSize
.Height(); y
++ )
181 sal_uInt32
*pPix
= (sal_uInt32
*)(pSrc
+ nStride
* y
);
182 for( unsigned long x
= 0; x
< (unsigned long) aSize
.Width(); x
++ )
184 sal_uInt8 nAlpha
= (*pPix
>> 24);
185 sal_uInt8 nR
= (*pPix
>> 16) & 0xff;
186 sal_uInt8 nG
= (*pPix
>> 8) & 0xff;
187 sal_uInt8 nB
= *pPix
& 0xff;
188 if( nAlpha
!= 0 && nAlpha
!= 255 )
190 // fprintf (stderr, "From A(0x%.2x) 0x%.2x 0x%.2x 0x%.2x -> ",
191 // nAlpha, nR, nG, nB );
192 // Cairo uses pre-multiplied alpha - we do not => re-multiply
193 nR
= (sal_uInt8
) MinMax( ((sal_uInt32
)nR
* 255) / nAlpha
, 0, 255 );
194 nG
= (sal_uInt8
) MinMax( ((sal_uInt32
)nG
* 255) / nAlpha
, 0, 255 );
195 nB
= (sal_uInt8
) MinMax( ((sal_uInt32
)nB
* 255) / nAlpha
, 0, 255 );
196 // fprintf (stderr, "0x%.2x 0x%.2x 0x%.2x\n", nR, nG, nB );
198 pRGBWrite
->SetPixel( y
, x
, BitmapColor( nR
, nG
, nB
) );
199 pMaskWrite
->SetPixelIndex( y
, x
, 255 - nAlpha
);
203 aMask
.ReleaseAccess( pMaskWrite
);
204 aRGB
.ReleaseAccess( pRGBWrite
);
206 ::BitmapEx
*pBitmapEx
= new ::BitmapEx( aRGB
, aMask
);
208 cairo_surface_destroy( pPixels
);
210 aRV
= uno::Any( reinterpret_cast<sal_Int64
>( pBitmapEx
) );
215 #ifdef CAIRO_HAS_XLIB_SURFACE
216 X11Surface
* pXlibSurface
=dynamic_cast<X11Surface
*>(mpBufferSurface
.get());
217 OSL_ASSERT(pXlibSurface
);
218 uno::Sequence
< uno::Any
> args( 3 );
219 args
[0] = uno::Any( false ); // do not call XFreePixmap on it
220 args
[1] = uno::Any( pXlibSurface
->getPixmap()->mhDrawable
);
221 args
[2] = uno::Any( sal_Int32( pXlibSurface
->getDepth() ) );
223 aRV
= uno::Any( args
);
224 #elif defined CAIRO_HAS_QUARTZ_SURFACE
225 QuartzSurface
* pQuartzSurface
= dynamic_cast<QuartzSurface
*>(mpBufferSurface
.get());
226 OSL_ASSERT(pQuartzSurface
);
227 uno::Sequence
< uno::Any
> args( 1 );
228 args
[0] = uno::Any( sal_IntPtr (pQuartzSurface
->getCGContext()) );
229 aRV
= uno::Any( args
);
230 #elif defined CAIRO_HAS_WIN32_SURFACE
231 // TODO(F2): check whether under all circumstances,
232 // the alpha channel is ignored here.
233 uno::Sequence
< uno::Any
> args( 1 );
234 args
[1] = uno::Any( sal_Int64(surface2HBitmap(mpBufferSurface
,maSize
)) );
236 aRV
= uno::Any( args
);
237 // caller frees the bitmap
239 # error Please define fast prop retrieval for your platform!
245 // Always return nothing - for the RGB surface support.
246 // Alpha code paths go via the above case 0.
255 #define IMPLEMENTATION_NAME "CairoCanvas.CanvasBitmap"
256 #define SERVICE_NAME "com.sun.star.rendering.CanvasBitmap"
258 OUString SAL_CALL
CanvasBitmap::getImplementationName( ) throw (uno::RuntimeException
)
260 return OUString( IMPLEMENTATION_NAME
);
263 sal_Bool SAL_CALL
CanvasBitmap::supportsService( const OUString
& ServiceName
) throw (uno::RuntimeException
)
265 return ServiceName
== SERVICE_NAME
;
268 uno::Sequence
< OUString
> SAL_CALL
CanvasBitmap::getSupportedServiceNames( ) throw (uno::RuntimeException
)
270 uno::Sequence
< OUString
> aRet(1);
271 aRet
[0] = SERVICE_NAME
;
278 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */