xref: /AOO41X/main/vcl/aqua/source/gdi/salvd.cxx (revision 83137a03adbb58b5b3bdafefefa1e93de35e0011)
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* 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 
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