xref: /AOO41X/main/canvas/source/cairo/cairo_quartz_cairo.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1*cdf0e10cSrcweir /*************************************************************************
2*cdf0e10cSrcweir  *
3*cdf0e10cSrcweir  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4*cdf0e10cSrcweir  *
5*cdf0e10cSrcweir  * Copyright 2000, 2010 Oracle and/or its affiliates.
6*cdf0e10cSrcweir  *
7*cdf0e10cSrcweir  * OpenOffice.org - a multi-platform office productivity suite
8*cdf0e10cSrcweir  *
9*cdf0e10cSrcweir  * This file is part of OpenOffice.org.
10*cdf0e10cSrcweir  *
11*cdf0e10cSrcweir  * OpenOffice.org is free software: you can redistribute it and/or modify
12*cdf0e10cSrcweir  * it under the terms of the GNU Lesser General Public License version 3
13*cdf0e10cSrcweir  * only, as published by the Free Software Foundation.
14*cdf0e10cSrcweir  *
15*cdf0e10cSrcweir  * OpenOffice.org is distributed in the hope that it will be useful,
16*cdf0e10cSrcweir  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17*cdf0e10cSrcweir  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18*cdf0e10cSrcweir  * GNU Lesser General Public License version 3 for more details
19*cdf0e10cSrcweir  * (a copy is included in the LICENSE file that accompanied this code).
20*cdf0e10cSrcweir  *
21*cdf0e10cSrcweir  * You should have received a copy of the GNU Lesser General Public License
22*cdf0e10cSrcweir  * version 3 along with OpenOffice.org.  If not, see
23*cdf0e10cSrcweir  * <http://www.openoffice.org/license.html>
24*cdf0e10cSrcweir  * for a copy of the LGPLv3 License.
25*cdf0e10cSrcweir  *
26*cdf0e10cSrcweir  ************************************************************************/
27*cdf0e10cSrcweir 
28*cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
29*cdf0e10cSrcweir #include "precompiled_canvas.hxx"
30*cdf0e10cSrcweir 
31*cdf0e10cSrcweir #ifdef QUARTZ
32*cdf0e10cSrcweir /************************************************************************
33*cdf0e10cSrcweir  * Mac OS X/Quartz surface backend for OpenOffice.org Cairo Canvas      *
34*cdf0e10cSrcweir  ************************************************************************/
35*cdf0e10cSrcweir 
36*cdf0e10cSrcweir #include <osl/diagnose.h>
37*cdf0e10cSrcweir #include <vcl/sysdata.hxx>
38*cdf0e10cSrcweir #include <vcl/bitmap.hxx>
39*cdf0e10cSrcweir #include <vcl/virdev.hxx>
40*cdf0e10cSrcweir 
41*cdf0e10cSrcweir #include "cairo_cairo.hxx"
42*cdf0e10cSrcweir 
43*cdf0e10cSrcweir #if defined CAIRO_HAS_QUARTZ_SURFACE
44*cdf0e10cSrcweir 
45*cdf0e10cSrcweir #include "cairo_quartz_cairo.hxx"
46*cdf0e10cSrcweir 
47*cdf0e10cSrcweir namespace cairo
48*cdf0e10cSrcweir {
49*cdf0e10cSrcweir     bool IsCairoWorking( OutputDevice* )
50*cdf0e10cSrcweir     {
51*cdf0e10cSrcweir         // trivially true for Mac
52*cdf0e10cSrcweir         return true;
53*cdf0e10cSrcweir     }
54*cdf0e10cSrcweir 
55*cdf0e10cSrcweir     /**
56*cdf0e10cSrcweir      * QuartzSurface::Surface:     Create generic Canvas surface using given Cairo Surface
57*cdf0e10cSrcweir      *
58*cdf0e10cSrcweir      * @param pSurface Cairo Surface
59*cdf0e10cSrcweir      *
60*cdf0e10cSrcweir      * This constructor only stores data, it does no processing.
61*cdf0e10cSrcweir      * It is used with e.g. cairo_image_surface_create_for_data()
62*cdf0e10cSrcweir      * and QuartzSurface::getSimilar()
63*cdf0e10cSrcweir      *
64*cdf0e10cSrcweir      * Set the mpSurface to the new surface or NULL
65*cdf0e10cSrcweir      **/
66*cdf0e10cSrcweir     QuartzSurface::QuartzSurface( const CairoSurfaceSharedPtr& pSurface ) :
67*cdf0e10cSrcweir             mpView(NULL),
68*cdf0e10cSrcweir             mpSurface( pSurface )
69*cdf0e10cSrcweir     {
70*cdf0e10cSrcweir         // Necessary, context is lost otherwise
71*cdf0e10cSrcweir         CGContextRetain( getCGContext() ); //  == NULL for non-native surfaces
72*cdf0e10cSrcweir     }
73*cdf0e10cSrcweir 
74*cdf0e10cSrcweir     /**
75*cdf0e10cSrcweir      * QuartzSurface::Surface:   Create Canvas surface from Window reference.
76*cdf0e10cSrcweir      * @param NSView
77*cdf0e10cSrcweir      * @param x horizontal location of the new surface
78*cdf0e10cSrcweir      * @param y vertical location of the new surface
79*cdf0e10cSrcweir      * @param width width of the new surface
80*cdf0e10cSrcweir      * @param height height of the new surface
81*cdf0e10cSrcweir      *
82*cdf0e10cSrcweir      * pSysData contains the platform native Window reference.
83*cdf0e10cSrcweir      * pSysData is used to create a surface on the Window
84*cdf0e10cSrcweir      *
85*cdf0e10cSrcweir      * Set the mpSurface to the new surface or NULL
86*cdf0e10cSrcweir      **/
87*cdf0e10cSrcweir     QuartzSurface::QuartzSurface( NSView* pView, int x, int y, int width, int height ) :
88*cdf0e10cSrcweir             mpView(pView),
89*cdf0e10cSrcweir             mpSurface()
90*cdf0e10cSrcweir     {
91*cdf0e10cSrcweir         OSL_TRACE("Canvas::cairo::Surface(NSView*, x:%d, y:%d, w:%d, h:%d): New Surface for window", x, y, width, height);
92*cdf0e10cSrcweir 
93*cdf0e10cSrcweir         // on Mac OS X / Quartz we are not drawing directly to the screen, but via regular CGContextRef.
94*cdf0e10cSrcweir         // The actual drawing to NSView (i.e. screen) is done in QuartzSurface::flush()
95*cdf0e10cSrcweir 
96*cdf0e10cSrcweir         // HACK: currently initial size for windowsurface is 0x0, which is not possible for us.
97*cdf0e10cSrcweir         if (width == 0 || height == 0) {
98*cdf0e10cSrcweir             width = [mpView bounds].size.width;
99*cdf0e10cSrcweir             height = [mpView bounds].size.height;
100*cdf0e10cSrcweir             OSL_TRACE("Canvas::cairo::Surface(): BUG!! size is ZERO! fixing to %d x %d...", width, height);
101*cdf0e10cSrcweir         }
102*cdf0e10cSrcweir 
103*cdf0e10cSrcweir         // create a generic surface, NSView/Window is ARGB32.
104*cdf0e10cSrcweir         mpSurface.reset(
105*cdf0e10cSrcweir             cairo_quartz_surface_create(CAIRO_FORMAT_ARGB32, width, height),
106*cdf0e10cSrcweir             &cairo_surface_destroy);
107*cdf0e10cSrcweir 
108*cdf0e10cSrcweir         cairo_surface_set_device_offset( mpSurface.get(), x, y );
109*cdf0e10cSrcweir 	}
110*cdf0e10cSrcweir 
111*cdf0e10cSrcweir     /**
112*cdf0e10cSrcweir      * QuartzSurface::Surface:   Create Canvas surface from CGContextRef.
113*cdf0e10cSrcweir      * @param CGContext Native graphics context
114*cdf0e10cSrcweir      * @param x horizontal location of the new surface
115*cdf0e10cSrcweir      * @param y vertical location of the new surface
116*cdf0e10cSrcweir      * @param width width of the new surface
117*cdf0e10cSrcweir      * @param height height of the new surface
118*cdf0e10cSrcweir      *
119*cdf0e10cSrcweir      * Set the mpSurface to the new surface or NULL
120*cdf0e10cSrcweir      **/
121*cdf0e10cSrcweir     QuartzSurface::QuartzSurface( CGContextRef rContext, int x, int y, int width, int height ) :
122*cdf0e10cSrcweir             mpView(NULL),
123*cdf0e10cSrcweir             mpSurface()
124*cdf0e10cSrcweir     {
125*cdf0e10cSrcweir         OSL_TRACE("Canvas::cairo::Surface(CGContext:%p, x:%d, y:%d, w:%d, h:%d): New Surface.", rContext, x, y, width, height);
126*cdf0e10cSrcweir         // create surface based on CGContext
127*cdf0e10cSrcweir 
128*cdf0e10cSrcweir         // ensure kCGBitmapByteOrder32Host flag, otherwise Cairo breaks (we are practically always using CGBitmapContext)
129*cdf0e10cSrcweir         OSL_ASSERT ((CGBitmapContextGetBitsPerPixel(rContext) != 32) ||
130*cdf0e10cSrcweir                     (CGBitmapContextGetBitmapInfo(rContext) & kCGBitmapByteOrderMask) == kCGBitmapByteOrder32Host);
131*cdf0e10cSrcweir 
132*cdf0e10cSrcweir         mpSurface.reset(cairo_quartz_surface_create_for_cg_context(rContext, width, height),
133*cdf0e10cSrcweir                         &cairo_surface_destroy);
134*cdf0e10cSrcweir 
135*cdf0e10cSrcweir         cairo_surface_set_device_offset( mpSurface.get(), x, y );
136*cdf0e10cSrcweir 
137*cdf0e10cSrcweir         // Necessary, context is lost otherwise
138*cdf0e10cSrcweir         CGContextRetain(rContext);
139*cdf0e10cSrcweir 	}
140*cdf0e10cSrcweir 
141*cdf0e10cSrcweir 
142*cdf0e10cSrcweir     /**
143*cdf0e10cSrcweir      * QuartzSurface::getCairo:  Create Cairo (drawing object) for the Canvas surface
144*cdf0e10cSrcweir      *
145*cdf0e10cSrcweir      * @return new Cairo or NULL
146*cdf0e10cSrcweir      **/
147*cdf0e10cSrcweir 	CairoSharedPtr QuartzSurface::getCairo() const
148*cdf0e10cSrcweir     {
149*cdf0e10cSrcweir         if (mpSurface.get()){
150*cdf0e10cSrcweir             return CairoSharedPtr( cairo_create(mpSurface.get()),
151*cdf0e10cSrcweir                                    &cairo_destroy );
152*cdf0e10cSrcweir         } else {
153*cdf0e10cSrcweir             return CairoSharedPtr();
154*cdf0e10cSrcweir         }
155*cdf0e10cSrcweir     }
156*cdf0e10cSrcweir 
157*cdf0e10cSrcweir     /**
158*cdf0e10cSrcweir      * QuartzSurface::getSimilar:  Create new similar Canvas surface
159*cdf0e10cSrcweir      * @param aContent format of the new surface (cairo_content_t from cairo/src/cairo.h)
160*cdf0e10cSrcweir      * @param width width of the new surface
161*cdf0e10cSrcweir      * @param height height of the new surface
162*cdf0e10cSrcweir      *
163*cdf0e10cSrcweir      * Creates a new Canvas surface. This normally creates platform native surface, even though
164*cdf0e10cSrcweir      * generic function is used.
165*cdf0e10cSrcweir      *
166*cdf0e10cSrcweir      * Cairo surface from aContent (cairo_content_t)
167*cdf0e10cSrcweir      *
168*cdf0e10cSrcweir      * @return new surface or NULL
169*cdf0e10cSrcweir      **/
170*cdf0e10cSrcweir 	SurfaceSharedPtr QuartzSurface::getSimilar( Content aContent, int width, int height ) const
171*cdf0e10cSrcweir 	{
172*cdf0e10cSrcweir         return SurfaceSharedPtr(
173*cdf0e10cSrcweir             new QuartzSurface(
174*cdf0e10cSrcweir                 CairoSurfaceSharedPtr(
175*cdf0e10cSrcweir                     cairo_surface_create_similar( mpSurface.get(), aContent, width, height ),
176*cdf0e10cSrcweir                     &cairo_surface_destroy )));
177*cdf0e10cSrcweir 	}
178*cdf0e10cSrcweir 
179*cdf0e10cSrcweir     /**
180*cdf0e10cSrcweir      * QuartzSurface::Resize:  Resizes the Canvas surface.
181*cdf0e10cSrcweir      * @param width new width of the surface
182*cdf0e10cSrcweir      * @param height new height of the surface
183*cdf0e10cSrcweir      *
184*cdf0e10cSrcweir      * Only used on X11.
185*cdf0e10cSrcweir      *
186*cdf0e10cSrcweir      * @return The new surface or NULL
187*cdf0e10cSrcweir      **/
188*cdf0e10cSrcweir 	void QuartzSurface::Resize( int width, int height )
189*cdf0e10cSrcweir 	{
190*cdf0e10cSrcweir         OSL_ENSURE(false,"not supposed to be called!");
191*cdf0e10cSrcweir 	}
192*cdf0e10cSrcweir 
193*cdf0e10cSrcweir 
194*cdf0e10cSrcweir     /**
195*cdf0e10cSrcweir      * QuartzSurface::flush:  Draw the data to screen
196*cdf0e10cSrcweir      **/
197*cdf0e10cSrcweir     void QuartzSurface::flush() const
198*cdf0e10cSrcweir     {
199*cdf0e10cSrcweir         // can only flush surfaces with NSView
200*cdf0e10cSrcweir         if( !mpView ) return;
201*cdf0e10cSrcweir 
202*cdf0e10cSrcweir         OSL_TRACE("Canvas::cairo::QuartzSurface::flush(): flush to NSView");
203*cdf0e10cSrcweir 
204*cdf0e10cSrcweir         CGContextRef mrContext = getCGContext();
205*cdf0e10cSrcweir 
206*cdf0e10cSrcweir         if (!mrContext) return;
207*cdf0e10cSrcweir 
208*cdf0e10cSrcweir         [mpView lockFocus];
209*cdf0e10cSrcweir 
210*cdf0e10cSrcweir         /**
211*cdf0e10cSrcweir          * This code is using same screen update code as in VCL (esp. AquaSalGraphics::UpdateWindow() )
212*cdf0e10cSrcweir          */
213*cdf0e10cSrcweir         CGContextRef rViewContext = reinterpret_cast<CGContextRef>([[NSGraphicsContext currentContext] graphicsPort]);
214*cdf0e10cSrcweir         CGImageRef xImage = CGBitmapContextCreateImage(mrContext);
215*cdf0e10cSrcweir         CGContextDrawImage(rViewContext,
216*cdf0e10cSrcweir                            CGRectMake( 0, 0,
217*cdf0e10cSrcweir                                        CGImageGetWidth(xImage),
218*cdf0e10cSrcweir                                        CGImageGetHeight(xImage)),
219*cdf0e10cSrcweir                            xImage);
220*cdf0e10cSrcweir         CGImageRelease( xImage );
221*cdf0e10cSrcweir         CGContextFlush( rViewContext );
222*cdf0e10cSrcweir 
223*cdf0e10cSrcweir         [mpView unlockFocus];
224*cdf0e10cSrcweir     }
225*cdf0e10cSrcweir 
226*cdf0e10cSrcweir     /**
227*cdf0e10cSrcweir      * QuartzSurface::getDepth:  Get the color depth of the Canvas surface.
228*cdf0e10cSrcweir      *
229*cdf0e10cSrcweir      * @return color depth
230*cdf0e10cSrcweir      **/
231*cdf0e10cSrcweir 	int QuartzSurface::getDepth() const
232*cdf0e10cSrcweir 	{
233*cdf0e10cSrcweir         if (mpSurface.get()) {
234*cdf0e10cSrcweir             switch (cairo_surface_get_content (mpSurface.get())) {
235*cdf0e10cSrcweir                 case CAIRO_CONTENT_ALPHA:       return 8;  break;
236*cdf0e10cSrcweir                 case CAIRO_CONTENT_COLOR:       return 24; break;
237*cdf0e10cSrcweir                 case CAIRO_CONTENT_COLOR_ALPHA: return 32; break;
238*cdf0e10cSrcweir             }
239*cdf0e10cSrcweir         }
240*cdf0e10cSrcweir         OSL_TRACE("Canvas::cairo::QuartzSurface::getDepth(): ERROR - depth unspecified!");
241*cdf0e10cSrcweir 
242*cdf0e10cSrcweir 		return -1;
243*cdf0e10cSrcweir 	}
244*cdf0e10cSrcweir 
245*cdf0e10cSrcweir     /**
246*cdf0e10cSrcweir      * QuartzSurface::getCGContext: Get the native CGContextRef of the Canvas's cairo surface
247*cdf0e10cSrcweir      *
248*cdf0e10cSrcweir      * @return graphics context
249*cdf0e10cSrcweir      **/
250*cdf0e10cSrcweir     CGContextRef QuartzSurface::getCGContext() const
251*cdf0e10cSrcweir     {
252*cdf0e10cSrcweir         if (mpSurface.get())
253*cdf0e10cSrcweir             return cairo_quartz_surface_get_cg_context(mpSurface.get());
254*cdf0e10cSrcweir         else
255*cdf0e10cSrcweir             return NULL;
256*cdf0e10cSrcweir     }
257*cdf0e10cSrcweir 
258*cdf0e10cSrcweir     /**
259*cdf0e10cSrcweir      * cairo::createVirtualDevice:  Create a VCL virtual device for the CGContext in the cairo Surface
260*cdf0e10cSrcweir      *
261*cdf0e10cSrcweir      * @return The new virtual device
262*cdf0e10cSrcweir      **/
263*cdf0e10cSrcweir     boost::shared_ptr<VirtualDevice> QuartzSurface::createVirtualDevice() const
264*cdf0e10cSrcweir     {
265*cdf0e10cSrcweir         SystemGraphicsData aSystemGraphicsData;
266*cdf0e10cSrcweir         aSystemGraphicsData.nSize = sizeof(SystemGraphicsData);
267*cdf0e10cSrcweir         aSystemGraphicsData.rCGContext = getCGContext();
268*cdf0e10cSrcweir         return boost::shared_ptr<VirtualDevice>(
269*cdf0e10cSrcweir             new VirtualDevice( &aSystemGraphicsData, getDepth() ));
270*cdf0e10cSrcweir     }
271*cdf0e10cSrcweir 
272*cdf0e10cSrcweir     /**
273*cdf0e10cSrcweir      * cairo::createSurface:     Create generic Canvas surface using given Cairo Surface
274*cdf0e10cSrcweir      *
275*cdf0e10cSrcweir      * @param rSurface Cairo Surface
276*cdf0e10cSrcweir      *
277*cdf0e10cSrcweir      * @return new Surface
278*cdf0e10cSrcweir      */
279*cdf0e10cSrcweir     SurfaceSharedPtr createSurface( const CairoSurfaceSharedPtr& rSurface )
280*cdf0e10cSrcweir     {
281*cdf0e10cSrcweir         return SurfaceSharedPtr(new QuartzSurface(rSurface));
282*cdf0e10cSrcweir     }
283*cdf0e10cSrcweir 
284*cdf0e10cSrcweir     /**
285*cdf0e10cSrcweir      * cairo::createSurface:     Create Canvas surface using given VCL Window or Virtualdevice
286*cdf0e10cSrcweir      *
287*cdf0e10cSrcweir      * @param rSurface Cairo Surface
288*cdf0e10cSrcweir      *
289*cdf0e10cSrcweir      *  For VCL Window, use platform native system environment data (struct SystemEnvData in vcl/inc/sysdata.hxx)
290*cdf0e10cSrcweir      *  For VCL Virtualdevice, use platform native system graphics data (struct SystemGraphicsData in vcl/inc/sysdata.hxx)
291*cdf0e10cSrcweir      *
292*cdf0e10cSrcweir      * @return new Surface
293*cdf0e10cSrcweir      */
294*cdf0e10cSrcweir     SurfaceSharedPtr createSurface( const OutputDevice& rRefDevice,
295*cdf0e10cSrcweir                                     int x, int y, int width, int height )
296*cdf0e10cSrcweir     {
297*cdf0e10cSrcweir         SurfaceSharedPtr surf;
298*cdf0e10cSrcweir 
299*cdf0e10cSrcweir         if( rRefDevice.GetOutDevType() == OUTDEV_WINDOW )
300*cdf0e10cSrcweir         {
301*cdf0e10cSrcweir             const Window &rWindow = (const Window &) rRefDevice;
302*cdf0e10cSrcweir             const SystemEnvData* pSysData = GetSysData(&rWindow);
303*cdf0e10cSrcweir             if (pSysData)
304*cdf0e10cSrcweir                 surf = SurfaceSharedPtr(new QuartzSurface(pSysData->pView, x, y, width, height));
305*cdf0e10cSrcweir         }
306*cdf0e10cSrcweir         else if( rRefDevice.GetOutDevType() == OUTDEV_VIRDEV )
307*cdf0e10cSrcweir         {
308*cdf0e10cSrcweir             SystemGraphicsData aSysData = ((const VirtualDevice&) rRefDevice).GetSystemGfxData();
309*cdf0e10cSrcweir 
310*cdf0e10cSrcweir             if (aSysData.rCGContext)
311*cdf0e10cSrcweir                 surf =  SurfaceSharedPtr(new QuartzSurface(aSysData.rCGContext, x, y, width, height));
312*cdf0e10cSrcweir         }
313*cdf0e10cSrcweir         return surf;
314*cdf0e10cSrcweir     }
315*cdf0e10cSrcweir 
316*cdf0e10cSrcweir     /**
317*cdf0e10cSrcweir      * cairo::createBitmapSurface:   Create platfrom native Canvas surface from BitmapSystemData
318*cdf0e10cSrcweir      * @param OutputDevice (not used)
319*cdf0e10cSrcweir      * @param rData Platform native image data (struct BitmapSystemData in vcl/inc/bitmap.hxx)
320*cdf0e10cSrcweir      * @param rSize width and height of the new surface
321*cdf0e10cSrcweir      *
322*cdf0e10cSrcweir      * Create a surface based on image data on rData
323*cdf0e10cSrcweir      *
324*cdf0e10cSrcweir      * @return new surface or empty surface
325*cdf0e10cSrcweir      **/
326*cdf0e10cSrcweir     SurfaceSharedPtr createBitmapSurface( const OutputDevice&     /* rRefDevice */,
327*cdf0e10cSrcweir                                           const BitmapSystemData& rData,
328*cdf0e10cSrcweir                                           const Size&             rSize )
329*cdf0e10cSrcweir     {
330*cdf0e10cSrcweir         OSL_TRACE( "requested size: %d x %d available size: %d x %d",
331*cdf0e10cSrcweir                    rSize.Width(), rSize.Height(), rData.mnWidth, rData.mnHeight );
332*cdf0e10cSrcweir 
333*cdf0e10cSrcweir         if ( rData.mnWidth == rSize.Width() && rData.mnHeight == rSize.Height() )
334*cdf0e10cSrcweir         {
335*cdf0e10cSrcweir             CGContextRef rContext = (CGContextRef)rData.rImageContext;
336*cdf0e10cSrcweir             OSL_TRACE("Canvas::cairo::createBitmapSurface(): New native image surface, context = %p.", rData.rImageContext);
337*cdf0e10cSrcweir 
338*cdf0e10cSrcweir             return SurfaceSharedPtr(new QuartzSurface(rContext, 0, 0, rData.mnWidth, rData.mnHeight));
339*cdf0e10cSrcweir         }
340*cdf0e10cSrcweir         return SurfaceSharedPtr();
341*cdf0e10cSrcweir     }
342*cdf0e10cSrcweir 
343*cdf0e10cSrcweir }  // namespace cairo
344*cdf0e10cSrcweir 
345*cdf0e10cSrcweir #endif   // CAIRO_HAS_QUARTZ_SURFACE
346*cdf0e10cSrcweir 
347*cdf0e10cSrcweir #endif   // QUARTZ
348