| /************************************************************** |
| * |
| * 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; |
| } |
| } |