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