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