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