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