1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_canvas.hxx"
30 
31 #include <canvas/debug.hxx>
32 #include <canvas/canvastools.hxx>
33 #include <tools/diagnose_ex.h>
34 
35 #include "cairo_canvasbitmap.hxx"
36 
37 #ifdef CAIRO_HAS_XLIB_SURFACE
38 # include "cairo_xlib_cairo.hxx"
39 #elif defined CAIRO_HAS_QUARTZ_SURFACE
40 # include "cairo_quartz_cairo.hxx"
41 #elif defined CAIRO_HAS_WIN32_SURFACE
42 # include "cairo_win32_cairo.hxx"
43 # include <cairo-win32.h>
44 #else
45 # error Native API needed.
46 #endif
47 
48 using namespace ::cairo;
49 using namespace ::com::sun::star;
50 
51 #ifdef CAIRO_HAS_WIN32_SURFACE
52 namespace
53 {
54     HBITMAP surface2HBitmap( const SurfaceSharedPtr& rSurface, const basegfx::B2ISize& rSize )
55     {
56         // cant seem to retrieve HBITMAP from cairo. copy content then
57         HDC hScreenDC=GetDC(NULL);
58         HBITMAP hBmpBitmap = CreateCompatibleBitmap( hScreenDC,
59                                                      rSize.getX(),
60                                                      rSize.getY() );
61 
62         HDC 	hBmpDC = CreateCompatibleDC( 0 );
63         HBITMAP hBmpOld = (HBITMAP) SelectObject( hBmpDC, hBmpBitmap );
64 
65         BitBlt( hBmpDC, 0, 0, rSize.getX(), rSize.getX(),
66                 cairo_win32_surface_get_dc(rSurface->getCairoSurface().get()),
67                 0, 0, SRCCOPY );
68 
69         SelectObject( hBmpDC, hBmpOld );
70         DeleteDC( hBmpDC );
71 
72         return hBmpBitmap;
73     }
74 }
75 #endif
76 
77 namespace cairocanvas
78 {
79     CanvasBitmap::CanvasBitmap( const ::basegfx::B2ISize&  rSize,
80                                 const SurfaceProviderRef&  rSurfaceProvider,
81                                 rendering::XGraphicDevice* pDevice,
82                                 bool                       bHasAlpha ) :
83         mpSurfaceProvider( rSurfaceProvider ),
84         mpBufferSurface(),
85         mpBufferCairo(),
86         maSize(rSize),
87         mbHasAlpha(bHasAlpha)
88     {
89         ENSURE_OR_THROW( mpSurfaceProvider.is(),
90                           "CanvasBitmap::CanvasBitmap(): Invalid surface or device" );
91 
92 		OSL_TRACE( "bitmap size: %dx%d", rSize.getX(), rSize.getY() );
93 
94 		mpBufferSurface = mpSurfaceProvider->createSurface( rSize, bHasAlpha ? CAIRO_CONTENT_COLOR_ALPHA : CAIRO_CONTENT_COLOR );
95 		mpBufferCairo = mpBufferSurface->getCairo();
96 
97         maCanvasHelper.init( rSize, *mpSurfaceProvider, pDevice );
98 		maCanvasHelper.setSurface( mpBufferSurface, bHasAlpha );
99 
100         // clear bitmap to 100% transparent
101         maCanvasHelper.clear();
102     }
103 
104     void SAL_CALL CanvasBitmap::disposing()
105     {
106         mpSurfaceProvider.clear();
107 
108 		mpBufferCairo.reset();
109 		mpBufferSurface.reset();
110 
111         // forward to parent
112         CanvasBitmap_Base::disposing();
113     }
114 
115     SurfaceSharedPtr CanvasBitmap::getSurface()
116     {
117         return mpBufferSurface;
118     }
119 
120     SurfaceSharedPtr CanvasBitmap::createSurface( const ::basegfx::B2ISize& rSize, Content aContent )
121     {
122         return mpSurfaceProvider->createSurface(rSize,aContent);
123     }
124 
125     SurfaceSharedPtr CanvasBitmap::createSurface( ::Bitmap& rBitmap )
126     {
127         return mpSurfaceProvider->createSurface(rBitmap);
128     }
129 
130     SurfaceSharedPtr CanvasBitmap::changeSurface( bool, bool )
131     {
132         // non-modifiable surface here
133         return SurfaceSharedPtr();
134     }
135 
136     OutputDevice* CanvasBitmap::getOutputDevice()
137     {
138         return mpSurfaceProvider->getOutputDevice();
139     }
140 
141     bool CanvasBitmap::repaint( const SurfaceSharedPtr&       pSurface,
142 								const rendering::ViewState&	  viewState,
143 								const rendering::RenderState& renderState )
144     {
145 		return maCanvasHelper.repaint( pSurface, viewState, renderState );
146     }
147 
148     uno::Any SAL_CALL CanvasBitmap::getFastPropertyValue( sal_Int32 nHandle )  throw (uno::RuntimeException)
149     {
150         uno::Any aRV( sal_Int32(0) );
151         // 0 ... get BitmapEx
152         // 1 ... get Pixbuf with bitmap RGB content
153         // 2 ... get Pixbuf with bitmap alpha mask
154         switch( nHandle )
155         {
156             case 0:
157             {
158                 aRV = uno::Any( reinterpret_cast<sal_Int64>( (BitmapEx*) NULL ) );
159                 break;
160             }
161             case 1:
162             {
163 #ifdef CAIRO_HAS_XLIB_SURFACE
164                 X11Surface* pXlibSurface=dynamic_cast<X11Surface*>(mpBufferSurface.get());
165                 OSL_ASSERT(pXlibSurface);
166                 uno::Sequence< uno::Any > args( 3 );
167                 args[0] = uno::Any( false );  // do not call XFreePixmap on it
168                 args[1] = uno::Any( pXlibSurface->getPixmap()->mhDrawable );
169                 args[2] = uno::Any( sal_Int32( pXlibSurface->getDepth() ) );
170 
171                 aRV = uno::Any( args );
172 #elif defined CAIRO_HAS_QUARTZ_SURFACE
173                 QuartzSurface* pQuartzSurface = dynamic_cast<QuartzSurface*>(mpBufferSurface.get());
174                 OSL_ASSERT(pQuartzSurface);
175                 uno::Sequence< uno::Any > args( 1 );
176                 args[0] = uno::Any( sal_IntPtr (pQuartzSurface->getCGContext()) );
177                 aRV = uno::Any( args );
178 #elif defined CAIRO_HAS_WIN32_SURFACE
179                 // TODO(F2): check whether under all circumstances,
180                 // the alpha channel is ignored here.
181                 uno::Sequence< uno::Any > args( 1 );
182                 args[1] = uno::Any( sal_Int64(surface2HBitmap(mpBufferSurface,maSize)) );
183 
184                 aRV = uno::Any( args );
185                 // caller frees the bitmap
186 #else
187 # error Please define fast prop retrieval for your platform!
188 #endif
189                 break;
190             }
191             case 2:
192             {
193 #ifdef CAIRO_HAS_XLIB_SURFACE
194                 uno::Sequence< uno::Any > args( 3 );
195                 SurfaceSharedPtr pAlphaSurface = mpSurfaceProvider->createSurface( maSize, CAIRO_CONTENT_COLOR );
196                 CairoSharedPtr   pAlphaCairo = pAlphaSurface->getCairo();
197                 X11Surface* pXlibSurface=dynamic_cast<X11Surface*>(pAlphaSurface.get());
198                 OSL_ASSERT(pXlibSurface);
199 
200                 // create RGB image (levels of gray) of alpha channel of original picture
201                 cairo_set_source_rgba( pAlphaCairo.get(), 1, 1, 1, 1 );
202                 cairo_set_operator( pAlphaCairo.get(), CAIRO_OPERATOR_SOURCE );
203                 cairo_paint( pAlphaCairo.get() );
204                 cairo_set_source_surface( pAlphaCairo.get(), mpBufferSurface->getCairoSurface().get(), 0, 0 );
205                 cairo_set_operator( pAlphaCairo.get(), CAIRO_OPERATOR_XOR );
206                 cairo_paint( pAlphaCairo.get() );
207                 pAlphaCairo.reset();
208 
209                 X11PixmapSharedPtr pPixmap = pXlibSurface->getPixmap();
210                 args[0] = uno::Any( true );
211                 args[1] = ::com::sun::star::uno::Any( pPixmap->mhDrawable );
212                 args[2] = ::com::sun::star::uno::Any( sal_Int32( pXlibSurface->getDepth () ) );
213                 pPixmap->clear(); // caller takes ownership of pixmap
214 
215                 // return pixmap and alphachannel pixmap - it will be used in BitmapEx
216                 aRV = uno::Any( args );
217 #elif defined CAIRO_HAS_QUARTZ_SURFACE
218                 SurfaceSharedPtr pAlphaSurface = mpSurfaceProvider->createSurface( maSize, CAIRO_CONTENT_COLOR );
219                 CairoSharedPtr   pAlphaCairo = pAlphaSurface->getCairo();
220                 QuartzSurface* pQuartzSurface=dynamic_cast<QuartzSurface*>(pAlphaSurface.get());
221                 OSL_ASSERT(pQuartzSurface);
222 
223                 // create RGB image (levels of gray) of alpha channel of original picture
224                 cairo_set_source_rgba( pAlphaCairo.get(), 1, 1, 1, 1 );
225                 cairo_set_operator( pAlphaCairo.get(), CAIRO_OPERATOR_SOURCE );
226                 cairo_paint( pAlphaCairo.get() );
227                 cairo_set_source_surface( pAlphaCairo.get(), mpBufferSurface->getCairoSurface().get(), 0, 0 );
228                 cairo_set_operator( pAlphaCairo.get(), CAIRO_OPERATOR_XOR );
229                 cairo_paint( pAlphaCairo.get() );
230                 pAlphaCairo.reset();
231 
232                 uno::Sequence< uno::Any > args( 1 );
233                 args[0] = uno::Any( sal_IntPtr (pQuartzSurface->getCGContext()) );
234                 // return ??? and alphachannel ??? - it will be used in BitmapEx
235                 aRV = uno::Any( args );
236 #elif defined CAIRO_HAS_WIN32_SURFACE
237                 SurfaceSharedPtr pAlphaSurface = mpSurfaceProvider->createSurface( maSize, CAIRO_CONTENT_COLOR );
238                 CairoSharedPtr   pAlphaCairo = pAlphaSurface->getCairo();
239 
240                 // create RGB image (levels of gray) of alpha channel of original picture
241                 cairo_set_source_rgba( pAlphaCairo.get(), 1, 1, 1, 1 );
242                 cairo_set_operator( pAlphaCairo.get(), CAIRO_OPERATOR_SOURCE );
243                 cairo_paint( pAlphaCairo.get() );
244                 cairo_set_source_surface( pAlphaCairo.get(), mpBufferSurface->getCairoSurface().get(), 0, 0 );
245                 cairo_set_operator( pAlphaCairo.get(), CAIRO_OPERATOR_XOR );
246                 cairo_paint( pAlphaCairo.get() );
247                 pAlphaCairo.reset();
248 
249                 // cant seem to retrieve HBITMAP from cairo. copy content then
250                 uno::Sequence< uno::Any > args( 1 );
251                 args[1] = uno::Any( sal_Int64(surface2HBitmap(pAlphaSurface,maSize)) );
252 
253                 aRV = uno::Any( args );
254                 // caller frees the bitmap
255 #else
256 # error Please define fast prop retrieval for your platform!
257 #endif
258                 break;
259             }
260         }
261 
262         return aRV;
263     }
264 
265 #define IMPLEMENTATION_NAME "CairoCanvas.CanvasBitmap"
266 #define SERVICE_NAME "com.sun.star.rendering.CanvasBitmap"
267 
268     ::rtl::OUString SAL_CALL CanvasBitmap::getImplementationName(  ) throw (uno::RuntimeException)
269     {
270         return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( IMPLEMENTATION_NAME ) );
271     }
272 
273     sal_Bool SAL_CALL CanvasBitmap::supportsService( const ::rtl::OUString& ServiceName ) throw (uno::RuntimeException)
274     {
275         return ServiceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( SERVICE_NAME ) );
276     }
277 
278     uno::Sequence< ::rtl::OUString > SAL_CALL CanvasBitmap::getSupportedServiceNames(  ) throw (uno::RuntimeException)
279     {
280         uno::Sequence< ::rtl::OUString > aRet(1);
281         aRet[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( SERVICE_NAME ) );
282 
283         return aRet;
284     }
285 
286 }
287