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