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 <tools/prex.h>
28 #include <X11/extensions/Xrender.h>
29 #include <X11/Xlib.h>
30 #include <tools/postx.h>
31 
32 #include "cairo_xlib_cairo.hxx"
33 
34 #include <vcl/sysdata.hxx>
35 #include <vcl/bitmap.hxx>
36 #include <vcl/virdev.hxx>
37 #include <basegfx/vector/b2isize.hxx>
38 
39 namespace cairo
40 {
41 
42 #include <cairo-xlib.h>
43 #include <cairo-xlib-xrender.h>
44 
45     // TODO(F3): svp headless case!
46 
47     bool IsCairoWorking( OutputDevice* pOutDev )
48     {
49         if( !pOutDev )
50             return false;
51 
52         Display* pDisplay = (Display*)pOutDev->GetSystemGfxData().pDisplay;
53         int nDummy;
54         return XQueryExtension( pDisplay, "RENDER", &nDummy, &nDummy, &nDummy );
55 	}
56 
57     X11SysData::X11SysData() :
58         pDisplay(NULL),
59         hDrawable(0),
60         pVisual(NULL),
61         nScreen(0),
62         nDepth(-1),
63         aColormap(-1),
64         pRenderFormat(NULL)
65     {}
66 
67     X11SysData::X11SysData( const SystemGraphicsData& pSysDat ) :
68         pDisplay(pSysDat.pDisplay),
69         hDrawable(pSysDat.hDrawable),
70         pVisual(pSysDat.pVisual),
71         nScreen(pSysDat.nScreen),
72         nDepth(pSysDat.nDepth),
73         aColormap(pSysDat.aColormap),
74         pRenderFormat(pSysDat.pRenderFormat)
75     {}
76 
77     X11SysData::X11SysData( const SystemEnvData& pSysDat ) :
78         pDisplay(pSysDat.pDisplay),
79         hDrawable(pSysDat.aWindow),
80         pVisual(pSysDat.pVisual),
81         nScreen(pSysDat.nScreen),
82         nDepth(pSysDat.nDepth),
83         aColormap(pSysDat.aColormap),
84         pRenderFormat(NULL)
85     {}
86 
87     X11Pixmap::~X11Pixmap()
88     {
89         if( mpDisplay && mhDrawable )
90             XFreePixmap( (Display*)mpDisplay, mhDrawable );
91     }
92 
93     /**
94      * Surface::Surface:   Create Canvas surface with existing data
95      * @param pSysData Platform native system environment data (struct SystemEnvData in vcl/inc/sysdata.hxx)
96      * @param pSurface Cairo surface
97      *
98      * pSysData contains the platform native Drawable reference
99      * This constructor only stores data, it does no processing.
100      * It is used by e.g. Surface::getSimilar()
101      *
102      * Set the mpSurface as pSurface
103      **/
104     X11Surface::X11Surface( const X11SysData&            rSysData,
105                             const X11PixmapSharedPtr&    rPixmap,
106                             const CairoSurfaceSharedPtr& pSurface ) :
107         maSysData(rSysData),
108         mpPixmap(rPixmap),
109         mpSurface(pSurface)
110     {}
111 
112     /**
113      * Surface::Surface:     Create generic Canvas surface using given Cairo Surface
114      *
115      * @param pSurface Cairo Surface
116      *
117      * This constructor only stores data, it does no processing.
118      * It is used with e.g. cairo_image_surface_create_for_data()
119      * Unlike other constructors, mpSysData is set to NULL
120      *
121      * Set the mpSurface as pSurface
122      **/
123     X11Surface::X11Surface( const CairoSurfaceSharedPtr& pSurface ) :
124         maSysData(),
125         mpPixmap(),
126         mpSurface(pSurface)
127     {}
128 
129     /**
130      * Surface::Surface:   Create Canvas surface from Window reference.
131      * @param pSysData Platform native system environment data (struct SystemEnvData in vcl/inc/sysdata.hxx)
132      * @param x horizontal location of the new surface
133      * @param y vertical location of the new surface
134      * @param width width of the new surface
135      * @param height height of the new surface
136      *
137      * pSysData contains the platform native Window reference.
138      *
139      * pSysData is used to create a surface on the Window
140      *
141      * Set the mpSurface to the new surface or NULL
142      **/
143 	X11Surface::X11Surface( const X11SysData& rSysData, int x, int y, int width, int height ) :
144         maSysData(rSysData),
145         mpPixmap(),
146         mpSurface(
147             cairo_xlib_surface_create( (Display*)rSysData.pDisplay,
148                                        rSysData.hDrawable,
149                                        (Visual*)rSysData.pVisual,
150                                        width + x, height + y ),
151             &cairo_surface_destroy)
152 	{
153         cairo_surface_set_device_offset(mpSurface.get(), x, y );
154     }
155 
156     /**
157      * Surface::Surface:   Create platfrom native Canvas surface from BitmapSystemData
158      * @param pSysData Platform native system environment data (struct SystemEnvData in vcl/inc/sysdata.hxx)
159      * @param pBmpData Platform native image data (struct BitmapSystemData in vcl/inc/bitmap.hxx)
160      * @param width width of the new surface
161      * @param height height of the new surface
162      *
163      * The pBmpData provides the imagedata that the created surface should contain.
164      *
165      * Set the mpSurface to the new surface or NULL
166      **/
167 	X11Surface::X11Surface( const X11SysData&       rSysData,
168                             const BitmapSystemData& rData ) :
169         maSysData( rSysData ),
170         mpPixmap(),
171         mpSurface(
172             cairo_xlib_surface_create( (Display*)rSysData.pDisplay,
173                                        (Drawable)rData.aPixmap,
174                                        (Visual*) rSysData.pVisual,
175                                        rData.mnWidth, rData.mnHeight ),
176             &cairo_surface_destroy)
177 	{
178     }
179 
180     /**
181      * Surface::getCairo:  Create Cairo (drawing object) for the Canvas surface
182      *
183      * @return new Cairo or NULL
184      **/
185 	CairoSharedPtr X11Surface::getCairo() const
186     {
187         return CairoSharedPtr( cairo_create(mpSurface.get()),
188                                &cairo_destroy );
189     }
190 
191     /**
192      * Surface::getSimilar:  Create new similar Canvas surface
193      * @param aContent format of the new surface (cairo_content_t from cairo/src/cairo.h)
194      * @param width width of the new surface
195      * @param height height of the new surface
196      *
197      * Creates a new Canvas surface. This normally creates platform native surface, even though
198      * generic function is used.
199      *
200      * Cairo surface from aContent (cairo_content_t)
201      *
202      * @return new surface or NULL
203      **/
204 	SurfaceSharedPtr X11Surface::getSimilar( Content aContent, int width, int height ) const
205 	{
206 		Pixmap hPixmap;
207 
208 		if( maSysData.pDisplay && maSysData.hDrawable )
209         {
210 			XRenderPictFormat* pFormat;
211 			int	nFormat;
212 
213 			switch (aContent)
214             {
215                 case CAIRO_CONTENT_ALPHA:
216                     nFormat = PictStandardA8;
217                     break;
218                 case CAIRO_CONTENT_COLOR:
219                     nFormat = PictStandardRGB24;
220                     break;
221                 case CAIRO_CONTENT_COLOR_ALPHA:
222                 default:
223                     nFormat = PictStandardARGB32;
224                     break;
225 			}
226 
227 			pFormat = XRenderFindStandardFormat( (Display*)maSysData.pDisplay, nFormat );
228 			hPixmap = XCreatePixmap( (Display*)maSysData.pDisplay, maSysData.hDrawable,
229 									 width > 0 ? width : 1, height > 0 ? height : 1,
230 									 pFormat->depth );
231 
232             X11SysData aSysData(maSysData);
233             aSysData.pRenderFormat = pFormat;
234             return SurfaceSharedPtr(
235                 new X11Surface( aSysData,
236                                 X11PixmapSharedPtr(
237                                     new X11Pixmap(hPixmap, maSysData.pDisplay)),
238                                 CairoSurfaceSharedPtr(
239                                     cairo_xlib_surface_create_with_xrender_format(
240                                         (Display*)maSysData.pDisplay,
241                                         hPixmap,
242                                         ScreenOfDisplay((Display *)maSysData.pDisplay, maSysData.nScreen),
243                                         pFormat, width, height ),
244                                     &cairo_surface_destroy) ));
245 		}
246         else
247 			return SurfaceSharedPtr(
248                 new X11Surface( maSysData,
249                                 X11PixmapSharedPtr(),
250                                 CairoSurfaceSharedPtr(
251                                     cairo_surface_create_similar( mpSurface.get(), aContent, width, height ),
252                                     &cairo_surface_destroy )));
253 	}
254 
255     boost::shared_ptr<VirtualDevice> X11Surface::createVirtualDevice() const
256     {
257 		SystemGraphicsData aSystemGraphicsData;
258 
259 		aSystemGraphicsData.nSize = sizeof(SystemGraphicsData);
260 		aSystemGraphicsData.hDrawable = getDrawable();
261 		aSystemGraphicsData.pRenderFormat = getRenderFormat();
262 
263 		return boost::shared_ptr<VirtualDevice>(
264             new VirtualDevice( &aSystemGraphicsData, getDepth() ));
265     }
266 
267     /**
268      * Surface::Resize:  Resizes the Canvas surface.
269      * @param width new width of the surface
270      * @param height new height of the surface
271      *
272      * Only used on X11.
273      *
274      * @return The new surface or NULL
275      **/
276 	void X11Surface::Resize( int width, int height )
277 	{
278 		cairo_xlib_surface_set_size( mpSurface.get(), width, height );
279 	}
280 
281     void X11Surface::flush() const
282     {
283         XSync( (Display*)maSysData.pDisplay, false );
284     }
285 
286     /**
287      * Surface::getDepth:  Get the color depth of the Canvas surface.
288      *
289      * @return color depth
290      **/
291 	int X11Surface::getDepth() const
292 	{
293 		if( maSysData.pRenderFormat )
294 			return ((XRenderPictFormat*) maSysData.pRenderFormat)->depth;
295 
296 		return -1;
297 	}
298 
299     SurfaceSharedPtr createSurface( const CairoSurfaceSharedPtr& rSurface )
300     {
301         return SurfaceSharedPtr(new X11Surface(rSurface));
302     }
303 
304     static X11SysData getSysData( const Window& rWindow )
305     {
306         const SystemEnvData* pSysData = GetSysData(&rWindow);
307 
308         if( !pSysData )
309             return X11SysData();
310         else
311             return X11SysData(*pSysData);
312     }
313 
314     static X11SysData getSysData( const VirtualDevice& rVirDev )
315     {
316         return X11SysData( rVirDev.GetSystemGfxData() );
317     }
318 
319     SurfaceSharedPtr createSurface( const OutputDevice& rRefDevice,
320                                     int x, int y, int width, int height )
321     {
322         if( rRefDevice.GetOutDevType() == OUTDEV_WINDOW )
323             return SurfaceSharedPtr(new X11Surface(getSysData((const Window&)rRefDevice),
324                                                    x,y,width,height));
325         else if( rRefDevice.GetOutDevType() == OUTDEV_VIRDEV )
326             return SurfaceSharedPtr(new X11Surface(getSysData((const VirtualDevice&)rRefDevice),
327                                                    x,y,width,height));
328         else
329             return SurfaceSharedPtr();
330     }
331 
332     SurfaceSharedPtr createBitmapSurface( const OutputDevice&     rRefDevice,
333                                           const BitmapSystemData& rData,
334                                           const Size&             rSize )
335     {
336         OSL_TRACE( "requested size: %d x %d available size: %d x %d",
337                    rSize.Width(), rSize.Height(), rData.mnWidth, rData.mnHeight );
338         if ( rData.mnWidth == rSize.Width() && rData.mnHeight == rSize.Height() )
339         {
340             if( rRefDevice.GetOutDevType() == OUTDEV_WINDOW )
341                 return SurfaceSharedPtr(new X11Surface(getSysData((const Window&)rRefDevice), rData ));
342             else if( rRefDevice.GetOutDevType() == OUTDEV_VIRDEV )
343                 return SurfaceSharedPtr(new X11Surface(getSysData((const VirtualDevice&)rRefDevice), rData ));
344         }
345 
346         return SurfaceSharedPtr();
347     }
348 }
349