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_vcl.hxx" 30 31 #include "vcl/svapp.hxx" 32 #include "vcl/sysdata.hxx" 33 34 #include "aqua/salvd.h" 35 #include "aqua/salinst.h" 36 #include "aqua/salgdi.h" 37 #include "aqua/saldata.hxx" 38 #include "aqua/salframe.h" 39 40 // ----------------------------------------------------------------------- 41 42 SalVirtualDevice* AquaSalInstance::CreateVirtualDevice( SalGraphics* pGraphics, 43 long nDX, long nDY, sal_uInt16 nBitCount, const SystemGraphicsData *pData ) 44 { 45 // #i92075# can be called first in a thread 46 SalData::ensureThreadAutoreleasePool(); 47 48 return new AquaSalVirtualDevice( static_cast< AquaSalGraphics* >( pGraphics ), nDX, nDY, nBitCount, pData ); 49 } 50 51 // ----------------------------------------------------------------------- 52 53 void AquaSalInstance::DestroyVirtualDevice( SalVirtualDevice* pDevice ) 54 { 55 delete pDevice; 56 } 57 58 // ======================================================================= 59 60 AquaSalVirtualDevice::AquaSalVirtualDevice( AquaSalGraphics* pGraphic, long nDX, long nDY, sal_uInt16 nBitCount, const SystemGraphicsData *pData ) 61 : mbGraphicsUsed( false ) 62 , mxBitmapContext( NULL ) 63 , mnBitmapDepth( 0 ) 64 , mxLayer( NULL ) 65 { 66 if( pGraphic && pData && pData->rCGContext ) 67 { 68 // Create virtual device based on existing SystemGraphicsData 69 // We ignore nDx and nDY, as the desired size comes from the SystemGraphicsData 70 mbForeignContext = true; // the mxContext is from pData 71 mpGraphics = new AquaSalGraphics( /*pGraphic*/ ); 72 mpGraphics->SetVirDevGraphics( mxLayer, pData->rCGContext ); 73 } 74 else 75 { 76 // create empty new virtual device 77 mbForeignContext = false; // the mxContext is created within VCL 78 mpGraphics = new AquaSalGraphics(); // never fails 79 mnBitmapDepth = nBitCount; 80 81 // inherit resolution from reference device 82 if( pGraphic ) 83 { 84 AquaSalFrame* pFrame = pGraphic->getGraphicsFrame(); 85 if( pFrame && AquaSalFrame::isAlive( pFrame ) ) 86 { 87 mpGraphics->setGraphicsFrame( pFrame ); 88 mpGraphics->copyResolution( *pGraphic ); 89 } 90 } 91 92 if( nDX && nDY ) 93 SetSize( nDX, nDY ); 94 95 // NOTE: if SetSize does not succeed, we just ignore the nDX and nDY 96 } 97 } 98 99 // ----------------------------------------------------------------------- 100 101 AquaSalVirtualDevice::~AquaSalVirtualDevice() 102 { 103 if( mpGraphics ) 104 { 105 mpGraphics->SetVirDevGraphics( NULL, NULL ); 106 delete mpGraphics; 107 mpGraphics = 0; 108 } 109 Destroy(); 110 } 111 112 // ----------------------------------------------------------------------- 113 114 void AquaSalVirtualDevice::Destroy() 115 { 116 if( mbForeignContext ) { 117 // Do not delete mxContext that we have received from outside VCL 118 mxLayer = NULL; 119 return; 120 } 121 122 if( mxLayer ) 123 { 124 if( mpGraphics ) 125 mpGraphics->SetVirDevGraphics( NULL, NULL ); 126 CGLayerRelease( mxLayer ); 127 mxLayer = NULL; 128 } 129 130 if( mxBitmapContext ) 131 { 132 void* pRawData = CGBitmapContextGetData( mxBitmapContext ); 133 rtl_freeMemory( pRawData ); 134 CGContextRelease( mxBitmapContext ); 135 mxBitmapContext = NULL; 136 } 137 } 138 139 // ----------------------------------------------------------------------- 140 141 SalGraphics* AquaSalVirtualDevice::GetGraphics() 142 { 143 if( mbGraphicsUsed || !mpGraphics ) 144 return 0; 145 146 mbGraphicsUsed = true; 147 return mpGraphics; 148 } 149 150 // ----------------------------------------------------------------------- 151 152 void AquaSalVirtualDevice::ReleaseGraphics( SalGraphics* ) 153 { 154 mbGraphicsUsed = false; 155 } 156 157 // ----------------------------------------------------------------------- 158 159 sal_Bool AquaSalVirtualDevice::SetSize( long nDX, long nDY ) 160 { 161 if( mbForeignContext ) 162 { 163 // Do not delete/resize mxContext that we have received from outside VCL 164 return true; 165 } 166 167 if( mxLayer ) 168 { 169 const CGSize aSize = CGLayerGetSize( mxLayer ); 170 if( (nDX == aSize.width) && (nDY == aSize.height) ) 171 { 172 // Yay, we do not have to do anything :) 173 return true; 174 } 175 } 176 177 Destroy(); 178 179 // create a Quartz layer matching to the intended virdev usage 180 CGContextRef xCGContext = NULL; 181 if( mnBitmapDepth && (mnBitmapDepth < 16) ) 182 { 183 mnBitmapDepth = 8; // TODO: are 1bit vdevs worth it? 184 const CGColorSpaceRef aCGColorSpace = GetSalData()->mxGraySpace; 185 const CGBitmapInfo aCGBmpInfo = kCGImageAlphaNone; 186 const int nBytesPerRow = (mnBitmapDepth * nDX + 7) / 8; 187 188 void* pRawData = rtl_allocateMemory( nBytesPerRow * nDY ); 189 mxBitmapContext = ::CGBitmapContextCreate( pRawData, nDX, nDY, 190 mnBitmapDepth, nBytesPerRow, aCGColorSpace, aCGBmpInfo ); 191 xCGContext = mxBitmapContext; 192 } 193 else 194 { 195 // default to a NSView target context 196 AquaSalFrame* pSalFrame = mpGraphics->getGraphicsFrame(); 197 if( !pSalFrame && !GetSalData()->maFrames.empty() ) 198 pSalFrame = *GetSalData()->maFrames.begin(); 199 if( pSalFrame ) 200 { 201 // #i91990# 202 NSWindow* pWindow = pSalFrame->getWindow(); 203 if ( pWindow ) 204 { 205 NSGraphicsContext* pNSContext = [NSGraphicsContext graphicsContextWithWindow: pWindow]; 206 if( pNSContext ) 207 xCGContext = reinterpret_cast<CGContextRef>([pNSContext graphicsPort]); 208 } 209 else 210 { 211 // fall back to a bitmap context 212 mnBitmapDepth = 32; 213 const CGColorSpaceRef aCGColorSpace = GetSalData()->mxRGBSpace; 214 const CGBitmapInfo aCGBmpInfo = kCGImageAlphaNoneSkipFirst; 215 const int nBytesPerRow = (mnBitmapDepth * nDX) / 8; 216 217 void* pRawData = rtl_allocateMemory( nBytesPerRow * nDY ); 218 mxBitmapContext = ::CGBitmapContextCreate( pRawData, nDX, nDY, 219 8, nBytesPerRow, aCGColorSpace, aCGBmpInfo ); 220 xCGContext = mxBitmapContext; 221 } 222 } 223 } 224 225 DBG_ASSERT( xCGContext, "no context" ); 226 227 const CGSize aNewSize = { nDX, nDY }; 228 mxLayer = CGLayerCreateWithContext( xCGContext, aNewSize, NULL ); 229 230 if( mxLayer && mpGraphics ) 231 { 232 // get the matching Quartz context 233 CGContextRef xDrawContext = CGLayerGetContext( mxLayer ); 234 mpGraphics->SetVirDevGraphics( mxLayer, xDrawContext, mnBitmapDepth ); 235 } 236 237 return (mxLayer != NULL); 238 } 239 240 // ----------------------------------------------------------------------- 241 242 void AquaSalVirtualDevice::GetSize( long& rWidth, long& rHeight ) 243 { 244 if( mxLayer ) 245 { 246 const CGSize aSize = CGLayerGetSize( mxLayer ); 247 rWidth = static_cast<long>(aSize.width); 248 rHeight = static_cast<long>(aSize.height); 249 } 250 else 251 { 252 rWidth = 0; 253 rHeight = 0; 254 } 255 } 256