blob: 69556cbfe65133d8e2b10d93bed34ed9fc1613b3 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_vcl.hxx"
#include "vcl/svapp.hxx"
#include "vcl/sysdata.hxx"
#include "aqua/salvd.h"
#include "aqua/salinst.h"
#include "aqua/salgdi.h"
#include "aqua/saldata.hxx"
#include "aqua/salframe.h"
// -----------------------------------------------------------------------
SalVirtualDevice* AquaSalInstance::CreateVirtualDevice( SalGraphics* pGraphics,
long nDX, long nDY, sal_uInt16 nBitCount, const SystemGraphicsData *pData )
{
// #i92075# can be called first in a thread
SalData::ensureThreadAutoreleasePool();
return new AquaSalVirtualDevice( static_cast< AquaSalGraphics* >( pGraphics ), nDX, nDY, nBitCount, pData );
}
// -----------------------------------------------------------------------
void AquaSalInstance::DestroyVirtualDevice( SalVirtualDevice* pDevice )
{
delete pDevice;
}
// =======================================================================
AquaSalVirtualDevice::AquaSalVirtualDevice( AquaSalGraphics* pGraphic, long nDX, long nDY, sal_uInt16 nBitCount, const SystemGraphicsData *pData )
: mbGraphicsUsed( false )
, mxBitmapContext( NULL )
, mnBitmapDepth( 0 )
, mxLayer( NULL )
{
if( pGraphic && pData && pData->rCGContext )
{
// Create virtual device based on existing SystemGraphicsData
// We ignore nDx and nDY, as the desired size comes from the SystemGraphicsData
mbForeignContext = true; // the mxContext is from pData
mpGraphics = new AquaSalGraphics( /*pGraphic*/ );
mpGraphics->SetVirDevGraphics( mxLayer, pData->rCGContext );
}
else
{
// create empty new virtual device
mbForeignContext = false; // the mxContext is created within VCL
mpGraphics = new AquaSalGraphics(); // never fails
mnBitmapDepth = nBitCount;
// inherit resolution from reference device
if( pGraphic )
{
AquaSalFrame* pFrame = pGraphic->getGraphicsFrame();
if( pFrame && AquaSalFrame::isAlive( pFrame ) )
{
mpGraphics->setGraphicsFrame( pFrame );
mpGraphics->copyResolution( *pGraphic );
}
}
if( nDX && nDY )
SetSize( nDX, nDY );
// NOTE: if SetSize does not succeed, we just ignore the nDX and nDY
}
}
// -----------------------------------------------------------------------
AquaSalVirtualDevice::~AquaSalVirtualDevice()
{
if( mpGraphics )
{
mpGraphics->SetVirDevGraphics( NULL, NULL );
delete mpGraphics;
mpGraphics = 0;
}
Destroy();
}
// -----------------------------------------------------------------------
void AquaSalVirtualDevice::Destroy()
{
if( mbForeignContext ) {
// Do not delete mxContext that we have received from outside VCL
mxLayer = NULL;
return;
}
if( mxLayer )
{
if( mpGraphics )
mpGraphics->SetVirDevGraphics( NULL, NULL );
CGLayerRelease( mxLayer );
mxLayer = NULL;
}
if( mxBitmapContext )
{
void* pRawData = CGBitmapContextGetData( mxBitmapContext );
rtl_freeMemory( pRawData );
CGContextRelease( mxBitmapContext );
mxBitmapContext = NULL;
}
}
// -----------------------------------------------------------------------
SalGraphics* AquaSalVirtualDevice::GetGraphics()
{
if( mbGraphicsUsed || !mpGraphics )
return 0;
mbGraphicsUsed = true;
return mpGraphics;
}
// -----------------------------------------------------------------------
void AquaSalVirtualDevice::ReleaseGraphics( SalGraphics* )
{
mbGraphicsUsed = false;
}
// -----------------------------------------------------------------------
sal_Bool AquaSalVirtualDevice::SetSize( long nDX, long nDY )
{
if( mbForeignContext )
{
// Do not delete/resize mxContext that we have received from outside VCL
return true;
}
if( mxLayer )
{
const CGSize aSize = CGLayerGetSize( mxLayer );
if( (nDX == aSize.width) && (nDY == aSize.height) )
{
// Yay, we do not have to do anything :)
return true;
}
}
Destroy();
// create a Quartz layer matching to the intended virdev usage
CGContextRef xCGContext = NULL;
if( mnBitmapDepth && (mnBitmapDepth < 16) )
{
mnBitmapDepth = 8; // TODO: are 1bit vdevs worth it?
const CGColorSpaceRef aCGColorSpace = GetSalData()->mxGraySpace;
const CGBitmapInfo aCGBmpInfo = kCGImageAlphaNone;
const int nBytesPerRow = (mnBitmapDepth * nDX + 7) / 8;
void* pRawData = rtl_allocateMemory( nBytesPerRow * nDY );
mxBitmapContext = ::CGBitmapContextCreate( pRawData, nDX, nDY,
mnBitmapDepth, nBytesPerRow, aCGColorSpace, aCGBmpInfo );
xCGContext = mxBitmapContext;
}
else
{
// default to a NSView target context
AquaSalFrame* pSalFrame = mpGraphics->getGraphicsFrame();
if( !pSalFrame || !AquaSalFrame::isAlive( pSalFrame ))
{
if( !GetSalData()->maFrames.empty() )
{
// get the first matching frame
pSalFrame = *GetSalData()->maFrames.begin();
// update the frame reference
mpGraphics->setGraphicsFrame( pSalFrame );
}
}
if( pSalFrame )
{
// #i91990#
NSWindow* pNSWindow = pSalFrame->getNSWindow();
if ( pNSWindow )
{
NSGraphicsContext* pNSContext = [NSGraphicsContext graphicsContextWithWindow: pNSWindow];
if( pNSContext )
xCGContext = reinterpret_cast<CGContextRef>([pNSContext graphicsPort]);
}
else
{
// fall back to a bitmap context
mnBitmapDepth = 32;
const CGColorSpaceRef aCGColorSpace = GetSalData()->mxRGBSpace;
const CGBitmapInfo aCGBmpInfo = kCGImageAlphaNoneSkipFirst;
const int nBytesPerRow = (mnBitmapDepth * nDX) / 8;
void* pRawData = rtl_allocateMemory( nBytesPerRow * nDY );
mxBitmapContext = ::CGBitmapContextCreate( pRawData, nDX, nDY,
8, nBytesPerRow, aCGColorSpace, aCGBmpInfo );
xCGContext = mxBitmapContext;
}
}
}
DBG_ASSERT( xCGContext, "no context" );
const CGSize aNewSize = CGSizeMake( nDX, nDY);
mxLayer = CGLayerCreateWithContext( xCGContext, aNewSize, NULL );
if( mxLayer && mpGraphics )
{
// get the matching Quartz context
CGContextRef xDrawContext = CGLayerGetContext( mxLayer );
mpGraphics->SetVirDevGraphics( mxLayer, xDrawContext, mnBitmapDepth );
}
return (mxLayer != NULL);
}
// -----------------------------------------------------------------------
void AquaSalVirtualDevice::GetSize( long& rWidth, long& rHeight )
{
if( mxLayer )
{
const CGSize aSize = CGLayerGetSize( mxLayer );
rWidth = static_cast<long>(aSize.width);
rHeight = static_cast<long>(aSize.height);
}
else
{
rWidth = 0;
rHeight = 0;
}
}