xref: /aoo41x/main/vcl/aqua/source/gdi/salvd.cxx (revision cd426cce)
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