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 && !GetSalData()->maFrames.empty() ) 194 pSalFrame = *GetSalData()->maFrames.begin(); 195 if( pSalFrame ) 196 { 197 // #i91990# 198 NSWindow* pWindow = pSalFrame->getWindow(); 199 if ( pWindow ) 200 { 201 NSGraphicsContext* pNSContext = [NSGraphicsContext graphicsContextWithWindow: pWindow]; 202 if( pNSContext ) 203 xCGContext = reinterpret_cast<CGContextRef>([pNSContext graphicsPort]); 204 } 205 else 206 { 207 // fall back to a bitmap context 208 mnBitmapDepth = 32; 209 const CGColorSpaceRef aCGColorSpace = GetSalData()->mxRGBSpace; 210 const CGBitmapInfo aCGBmpInfo = kCGImageAlphaNoneSkipFirst; 211 const int nBytesPerRow = (mnBitmapDepth * nDX) / 8; 212 213 void* pRawData = rtl_allocateMemory( nBytesPerRow * nDY ); 214 mxBitmapContext = ::CGBitmapContextCreate( pRawData, nDX, nDY, 215 8, nBytesPerRow, aCGColorSpace, aCGBmpInfo ); 216 xCGContext = mxBitmapContext; 217 } 218 } 219 } 220 221 DBG_ASSERT( xCGContext, "no context" ); 222 223 const CGSize aNewSize = { nDX, nDY }; 224 mxLayer = CGLayerCreateWithContext( xCGContext, aNewSize, NULL ); 225 226 if( mxLayer && mpGraphics ) 227 { 228 // get the matching Quartz context 229 CGContextRef xDrawContext = CGLayerGetContext( mxLayer ); 230 mpGraphics->SetVirDevGraphics( mxLayer, xDrawContext, mnBitmapDepth ); 231 } 232 233 return (mxLayer != NULL); 234 } 235 236 // ----------------------------------------------------------------------- 237 238 void AquaSalVirtualDevice::GetSize( long& rWidth, long& rHeight ) 239 { 240 if( mxLayer ) 241 { 242 const CGSize aSize = CGLayerGetSize( mxLayer ); 243 rWidth = static_cast<long>(aSize.width); 244 rHeight = static_cast<long>(aSize.height); 245 } 246 else 247 { 248 rWidth = 0; 249 rHeight = 0; 250 } 251 } 252