xref: /aoo41x/main/vcl/aqua/source/gdi/salvd.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_vcl.hxx"
30 
31 #include "vcl/svapp.hxx"
32 #include "vcl/sysdata.hxx"
33 
34 #include "aqua/salvd.h"
35 #include "aqua/salinst.h"
36 #include "aqua/salgdi.h"
37 #include "aqua/saldata.hxx"
38 #include "aqua/salframe.h"
39 
40 // -----------------------------------------------------------------------
41 
42 SalVirtualDevice* AquaSalInstance::CreateVirtualDevice( SalGraphics* pGraphics,
43 	long nDX, long nDY, sal_uInt16 nBitCount, const SystemGraphicsData *pData )
44 {
45     // #i92075# can be called first in a thread
46     SalData::ensureThreadAutoreleasePool();
47 
48 	return new AquaSalVirtualDevice( static_cast< AquaSalGraphics* >( pGraphics ), nDX, nDY, nBitCount, pData );
49 }
50 
51 // -----------------------------------------------------------------------
52 
53 void AquaSalInstance::DestroyVirtualDevice( SalVirtualDevice* pDevice )
54 {
55 	delete pDevice;
56 }
57 
58 // =======================================================================
59 
60 AquaSalVirtualDevice::AquaSalVirtualDevice( AquaSalGraphics* pGraphic, long nDX, long nDY, sal_uInt16 nBitCount, const SystemGraphicsData *pData )
61 :	mbGraphicsUsed( false )
62 ,	mxBitmapContext( NULL )
63 ,	mnBitmapDepth( 0 )
64 ,	mxLayer( NULL )
65 {
66     if( pGraphic && pData && pData->rCGContext )
67 	{
68 	    // Create virtual device based on existing SystemGraphicsData
69         // We ignore nDx and nDY, as the desired size comes from the SystemGraphicsData
70         mbForeignContext = true;        // the mxContext is from pData
71 	    mpGraphics = new AquaSalGraphics( /*pGraphic*/ );
72 	    mpGraphics->SetVirDevGraphics( mxLayer, pData->rCGContext );
73 	}
74 	else
75 	{
76 	    // create empty new virtual device
77         mbForeignContext = false;           // the mxContext is created within VCL
78         mpGraphics = new AquaSalGraphics(); // never fails
79 		mnBitmapDepth = nBitCount;
80 
81         // inherit resolution from reference device
82         if( pGraphic )
83         {
84             AquaSalFrame* pFrame = pGraphic->getGraphicsFrame();
85             if( pFrame && AquaSalFrame::isAlive( pFrame ) )
86             {
87                 mpGraphics->setGraphicsFrame( pFrame );
88                 mpGraphics->copyResolution( *pGraphic );
89             }
90         }
91 
92         if( nDX && nDY )
93             SetSize( nDX, nDY );
94 
95         // NOTE: if SetSize does not succeed, we just ignore the nDX and nDY
96 	}
97 }
98 
99 // -----------------------------------------------------------------------
100 
101 AquaSalVirtualDevice::~AquaSalVirtualDevice()
102 {
103 	if( mpGraphics )
104 	{
105 		mpGraphics->SetVirDevGraphics( NULL, NULL );
106 		delete mpGraphics;
107 		mpGraphics = 0;
108 	}
109 	Destroy();
110 }
111 
112 // -----------------------------------------------------------------------
113 
114 void AquaSalVirtualDevice::Destroy()
115 {
116     if( mbForeignContext ) {
117         // Do not delete mxContext that we have received from outside VCL
118 		mxLayer = NULL;
119         return;
120     }
121 
122 	if( mxLayer )
123 	{
124 		if( mpGraphics )
125 			mpGraphics->SetVirDevGraphics( NULL, NULL );
126 		CGLayerRelease( mxLayer );
127 		mxLayer = NULL;
128 	}
129 
130 	if( mxBitmapContext )
131 	{
132 		void* pRawData = CGBitmapContextGetData( mxBitmapContext );
133 		rtl_freeMemory( pRawData );
134 		CGContextRelease( mxBitmapContext );
135 		mxBitmapContext = NULL;
136 	}
137 }
138 
139 // -----------------------------------------------------------------------
140 
141 SalGraphics* AquaSalVirtualDevice::GetGraphics()
142 {
143 	if( mbGraphicsUsed || !mpGraphics )
144 		return 0;
145 
146 	mbGraphicsUsed = true;
147 	return mpGraphics;
148 }
149 
150 // -----------------------------------------------------------------------
151 
152 void AquaSalVirtualDevice::ReleaseGraphics( SalGraphics* )
153 {
154 	mbGraphicsUsed = false;
155 }
156 
157 // -----------------------------------------------------------------------
158 
159 sal_Bool AquaSalVirtualDevice::SetSize( long nDX, long nDY )
160 {
161     if( mbForeignContext )
162     {
163         // Do not delete/resize mxContext that we have received from outside VCL
164         return true;
165     }
166 
167     if( mxLayer )
168     {
169     	const CGSize aSize = CGLayerGetSize( mxLayer );
170         if( (nDX == aSize.width) && (nDY == aSize.height) )
171 	    {
172 	        // Yay, we do not have to do anything :)
173 			return true;
174 	    }
175     }
176 
177     Destroy();
178 
179 	// create a Quartz layer matching to the intended virdev usage
180 	CGContextRef xCGContext = NULL;
181 	if( mnBitmapDepth && (mnBitmapDepth < 16) )
182 	{
183 		mnBitmapDepth = 8;  // TODO: are 1bit vdevs worth it?
184 		const CGColorSpaceRef aCGColorSpace = GetSalData()->mxGraySpace;
185 		const CGBitmapInfo aCGBmpInfo = kCGImageAlphaNone;
186 		const int nBytesPerRow = (mnBitmapDepth * nDX + 7) / 8;
187 
188 		void* pRawData = rtl_allocateMemory( nBytesPerRow * nDY );
189 		mxBitmapContext = ::CGBitmapContextCreate( pRawData, nDX, nDY,
190 			mnBitmapDepth, nBytesPerRow, aCGColorSpace, aCGBmpInfo );
191 		xCGContext = mxBitmapContext;
192 	}
193 	else
194 	{
195 		// default to a NSView target context
196         AquaSalFrame* pSalFrame = mpGraphics->getGraphicsFrame();
197         if( !pSalFrame && !GetSalData()->maFrames.empty() )
198             pSalFrame = *GetSalData()->maFrames.begin();
199         if( pSalFrame )
200         {
201             // #i91990#
202             NSWindow* pWindow = pSalFrame->getWindow();
203             if ( pWindow )
204             {
205                 NSGraphicsContext* pNSContext = [NSGraphicsContext graphicsContextWithWindow: pWindow];
206                 if( pNSContext )
207                     xCGContext = reinterpret_cast<CGContextRef>([pNSContext graphicsPort]);
208             }
209             else
210             {
211                 // fall back to a bitmap context
212                 mnBitmapDepth = 32;
213                 const CGColorSpaceRef aCGColorSpace = GetSalData()->mxRGBSpace;
214                 const CGBitmapInfo aCGBmpInfo = kCGImageAlphaNoneSkipFirst;
215                 const int nBytesPerRow = (mnBitmapDepth * nDX) / 8;
216 
217                 void* pRawData = rtl_allocateMemory( nBytesPerRow * nDY );
218                 mxBitmapContext = ::CGBitmapContextCreate( pRawData, nDX, nDY,
219                                                            8, nBytesPerRow, aCGColorSpace, aCGBmpInfo );
220                 xCGContext = mxBitmapContext;
221             }
222         }
223 	}
224 
225 	DBG_ASSERT( xCGContext, "no context" );
226 
227 	const CGSize aNewSize = { nDX, nDY };
228 	mxLayer = CGLayerCreateWithContext( xCGContext, aNewSize, NULL );
229 
230 	if( mxLayer && mpGraphics )
231 	{
232 		// get the matching Quartz context
233 		CGContextRef xDrawContext = CGLayerGetContext( mxLayer );
234 		mpGraphics->SetVirDevGraphics( mxLayer, xDrawContext, mnBitmapDepth );
235 	}
236 
237 	return (mxLayer != NULL);
238 }
239 
240 // -----------------------------------------------------------------------
241 
242 void AquaSalVirtualDevice::GetSize( long& rWidth, long& rHeight )
243 {
244 	if( mxLayer )
245 	{
246     	const CGSize aSize = CGLayerGetSize( mxLayer );
247 		rWidth = static_cast<long>(aSize.width);
248 		rHeight = static_cast<long>(aSize.height);
249 	}
250 	else
251 	{
252 		rWidth = 0;
253 		rHeight = 0;
254 	}
255 }
256