1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "vcl/svapp.hxx"
21 #include "vcl/sysdata.hxx"
23 #include "quartz/salvd.h"
25 #include "osx/salinst.h"
26 #include "osx/saldata.hxx"
27 #include "osx/salframe.h"
29 #include "headless/svpframe.hxx"
30 #include "headless/svpgdi.hxx"
31 #include "headless/svpinst.hxx"
32 #include "headless/svpvd.hxx"
34 #include "quartz/salgdi.h"
35 #include "quartz/utils.h"
37 SalVirtualDevice
* AquaSalInstance::CreateVirtualDevice( SalGraphics
* pGraphics
,
38 long &nDX
, long &nDY
, sal_uInt16 nBitCount
, const SystemGraphicsData
*pData
)
40 // #i92075# can be called first in a thread
41 SalData::ensureThreadAutoreleasePool();
45 return new AquaSalVirtualDevice( static_cast< AquaSalGraphics
* >( pGraphics
), nDX
, nDY
, nBitCount
, pData
);
48 AquaSalVirtualDevice
* pNew
= new AquaSalVirtualDevice( NULL
, nDX
, nDY
, nBitCount
, NULL
);
49 pNew
->SetSize( nDX
, nDY
);
53 return new AquaSalVirtualDevice( static_cast< AquaSalGraphics
* >( pGraphics
), nDX
, nDY
, nBitCount
, pData
);
57 AquaSalVirtualDevice::AquaSalVirtualDevice( AquaSalGraphics
* pGraphic
, long &nDX
, long &nDY
, sal_uInt16 nBitCount
, const SystemGraphicsData
*pData
)
58 : mbGraphicsUsed( false )
59 , mxBitmapContext( NULL
)
63 SAL_INFO( "vcl.virdev", "AquaSalVirtualDevice::AquaSalVirtualDevice() this=" << this << " size=(" << nDX
<< "x" << nDY
<< ") bitcount=" << nBitCount
<< " pData=" << pData
<< " context=" << (pData
? pData
->rCGContext
: 0) );
64 if( pGraphic
&& pData
&& pData
->rCGContext
)
66 // Create virtual device based on existing SystemGraphicsData
67 // We ignore nDx and nDY, as the desired size comes from the SystemGraphicsData.
68 mbForeignContext
= true; // the mxContext is from pData (what "mxContext"? there is no such field anywhere in vcl;)
69 mpGraphics
= new AquaSalGraphics( /*pGraphic*/ );
74 mxLayer
= CGLayerCreateWithContext( pData
->rCGContext
, CGSizeMake( nDX
, nDY
), NULL
);
75 // Interrogate the context as to its real size
78 const CGSize aSize
= CGLayerGetSize( mxLayer
);
79 nDX
= static_cast<long>(aSize
.width
);
80 nDY
= static_cast<long>(aSize
.height
);
87 CG_TRACE( "CGLayerCreateWithContext(" << pData
->rCGContext
<< "," << CGSizeMake( nDX
, nDY
) << ",NULL) = " << mxLayer
);
88 mpGraphics
->SetVirDevGraphics( mxLayer
, pData
->rCGContext
);
92 // create empty new virtual device
93 mbForeignContext
= false; // the mxContext is created within VCL
94 mpGraphics
= new AquaSalGraphics(); // never fails
95 mnBitmapDepth
= nBitCount
;
97 // inherit resolution from reference device
100 AquaSalFrame
* pFrame
= pGraphic
->getGraphicsFrame();
101 if( pFrame
&& AquaSalFrame::isAlive( pFrame
) )
103 mpGraphics
->setGraphicsFrame( pFrame
);
104 mpGraphics
->copyResolution( *pGraphic
);
111 // NOTE: if SetSize does not succeed, we just ignore the nDX and nDY
115 AquaSalVirtualDevice::~AquaSalVirtualDevice()
117 SAL_INFO( "vcl.virdev", "AquaSalVirtualDevice::~AquaSalVirtualDevice() this=" << this );
120 mpGraphics
->SetVirDevGraphics( NULL
, NULL
);
127 void AquaSalVirtualDevice::Destroy()
129 SAL_INFO( "vcl.virdev", "AquaSalVirtualDevice::Destroy() this=" << this << " mbForeignContext=" << mbForeignContext
);
131 if( mbForeignContext
) {
132 // Do not delete mxContext that we have received from outside VCL
140 mpGraphics
->SetVirDevGraphics( NULL
, NULL
);
141 CG_TRACE( "CGLayerRelease(" << mxLayer
<< ")" );
142 CGLayerRelease( mxLayer
);
146 if( mxBitmapContext
)
148 void* pRawData
= CGBitmapContextGetData( mxBitmapContext
);
149 rtl_freeMemory( pRawData
);
150 CG_TRACE( "CGContextRelease(" << mxBitmapContext
<< ")" );
151 CGContextRelease( mxBitmapContext
);
152 mxBitmapContext
= NULL
;
156 SalGraphics
* AquaSalVirtualDevice::AcquireGraphics()
158 if( mbGraphicsUsed
|| !mpGraphics
)
161 mbGraphicsUsed
= true;
165 void AquaSalVirtualDevice::ReleaseGraphics( SalGraphics
* )
167 mbGraphicsUsed
= false;
170 bool AquaSalVirtualDevice::SetSize( long nDX
, long nDY
)
172 SAL_INFO( "vcl.virdev", "AquaSalVirtualDevice::SetSize() this=" << this << " (" << nDX
<< "x" << nDY
<< ") mbForeignContext=" << mbForeignContext
);
174 if( mbForeignContext
)
176 // Do not delete/resize mxContext that we have received from outside VCL
182 const CGSize aSize
= CGLayerGetSize( mxLayer
);
183 CG_TRACE( "CGlayerGetSize(" << mxLayer
<< ") = " << aSize
);
184 if( (nDX
== aSize
.width
) && (nDY
== aSize
.height
) )
186 // Yay, we do not have to do anything :)
193 // create a Quartz layer matching to the intended virdev usage
194 CGContextRef xCGContext
= NULL
;
195 if( mnBitmapDepth
&& (mnBitmapDepth
< 16) )
197 mnBitmapDepth
= 8; // TODO: are 1bit vdevs worth it?
198 const int nBytesPerRow
= (mnBitmapDepth
* nDX
+ 7) / 8;
200 void* pRawData
= rtl_allocateMemory( nBytesPerRow
* nDY
);
202 for (ssize_t i
= 0; i
< nBytesPerRow
* nDY
; i
++)
203 static_cast<sal_uInt8
*>(pRawData
)[i
] = (i
& 0xFF);
205 mxBitmapContext
= CGBitmapContextCreate( pRawData
, nDX
, nDY
,
206 mnBitmapDepth
, nBytesPerRow
, GetSalData()->mxGraySpace
, kCGImageAlphaNone
);
207 CG_TRACE( "CGBitmapContextCreate(" << nDX
<< "x" << nDY
<< "x" << mnBitmapDepth
<< ") = " << mxBitmapContext
);
208 xCGContext
= mxBitmapContext
;
213 // default to a NSView target context
214 AquaSalFrame
* pSalFrame
= mpGraphics
->getGraphicsFrame();
215 if( !pSalFrame
|| !AquaSalFrame::isAlive( pSalFrame
))
217 if( !GetSalData()->maFrames
.empty() )
219 // get the first matching frame
220 pSalFrame
= *GetSalData()->maFrames
.begin();
224 // ensure we don't reuse a dead AquaSalFrame on the very
225 // unlikely case of no other frame to use
228 // update the frame reference
229 mpGraphics
->setGraphicsFrame( pSalFrame
);
234 NSWindow
* pNSWindow
= pSalFrame
->getNSWindow();
237 NSGraphicsContext
* pNSContext
= [NSGraphicsContext graphicsContextWithWindow
: pNSWindow
];
239 xCGContext
= static_cast<CGContextRef
>([pNSContext graphicsPort
]);
243 // fall back to a bitmap context
245 const int nBytesPerRow
= (mnBitmapDepth
* nDX
) / 8;
247 void* pRawData
= rtl_allocateMemory( nBytesPerRow
* nDY
);
249 for (ssize_t i
= 0; i
< nBytesPerRow
* nDY
; i
++)
250 static_cast<sal_uInt8
*>(pRawData
)[i
] = (i
& 0xFF);
252 mxBitmapContext
= CGBitmapContextCreate( pRawData
, nDX
, nDY
,
253 8, nBytesPerRow
, GetSalData()->mxRGBSpace
, kCGImageAlphaNoneSkipFirst
);
254 CG_TRACE( "CGBitmapContextCreate(" << nDX
<< "x" << nDY
<< "x32) = " << mxBitmapContext
);
255 xCGContext
= mxBitmapContext
;
260 const int nBytesPerRow
= (mnBitmapDepth
* nDX
) / 8;
262 void* pRawData
= rtl_allocateMemory( nBytesPerRow
* nDY
);
264 for (ssize_t i
= 0; i
< nBytesPerRow
* nDY
; i
++)
265 ((sal_uInt8
*)pRawData
)[i
] = (i
& 0xFF);
267 mxBitmapContext
= CGBitmapContextCreate( pRawData
, nDX
, nDY
,
268 8, nBytesPerRow
, GetSalData()->mxRGBSpace
, kCGImageAlphaNoneSkipFirst
);
269 CG_TRACE( "CGBitmapContextCreate(" << nDX
<< "x" << nDY
<< "x32) = " << mxBitmapContext
);
270 xCGContext
= mxBitmapContext
;
274 SAL_WARN_IF( !xCGContext
, "vcl.quartz", "No context" );
276 const CGSize aNewSize
= { static_cast<CGFloat
>(nDX
), static_cast<CGFloat
>(nDY
) };
277 mxLayer
= CGLayerCreateWithContext( xCGContext
, aNewSize
, NULL
);
278 CG_TRACE( "CGLayerCreateWithContext(" << xCGContext
<< "," << aNewSize
<< ",NULL) = " << mxLayer
);
280 if( mxLayer
&& mpGraphics
)
282 // get the matching Quartz context
283 CGContextRef xDrawContext
= CGLayerGetContext( mxLayer
);
284 CG_TRACE( "CGLayerGetContext(" << mxLayer
<< ") = " << xDrawContext
);
285 mpGraphics
->SetVirDevGraphics( mxLayer
, xDrawContext
, mnBitmapDepth
);
288 return (mxLayer
!= NULL
);
291 long AquaSalVirtualDevice::GetWidth() const
293 const CGSize aSize
= CGLayerGetSize( mxLayer
);
297 long AquaSalVirtualDevice::GetHeight() const
299 const CGSize aSize
= CGLayerGetSize( mxLayer
);
303 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */