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
CreateVirtualDevice(SalGraphics * pGraphics,long nDX,long nDY,sal_uInt16 nBitCount,const SystemGraphicsData * pData)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
DestroyVirtualDevice(SalVirtualDevice * pDevice)49 void AquaSalInstance::DestroyVirtualDevice( SalVirtualDevice* pDevice )
50 {
51 delete pDevice;
52 }
53
54 // =======================================================================
55
AquaSalVirtualDevice(AquaSalGraphics * pGraphic,long nDX,long nDY,sal_uInt16 nBitCount,const SystemGraphicsData * pData)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
~AquaSalVirtualDevice()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
Destroy()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
GetGraphics()137 SalGraphics* AquaSalVirtualDevice::GetGraphics()
138 {
139 if( mbGraphicsUsed || !mpGraphics )
140 return 0;
141
142 mbGraphicsUsed = true;
143 return mpGraphics;
144 }
145
146 // -----------------------------------------------------------------------
147
ReleaseGraphics(SalGraphics *)148 void AquaSalVirtualDevice::ReleaseGraphics( SalGraphics* )
149 {
150 mbGraphicsUsed = false;
151 }
152
153 // -----------------------------------------------------------------------
154
SetSize(long nDX,long nDY)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* pNSWindow = pSalFrame->getNSWindow();
207 if ( pNSWindow )
208 {
209 NSGraphicsContext* pNSContext = [NSGraphicsContext graphicsContextWithWindow: pNSWindow];
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
GetSize(long & rWidth,long & rHeight)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