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