diff options
author | Michael Meeks <michael.meeks@suse.com> | 2011-09-29 16:14:34 +0100 |
---|---|---|
committer | Michael Meeks <michael.meeks@suse.com> | 2011-10-25 13:41:48 +0100 |
commit | 46ef233ba8b7372796f5f3e6044d0d12193dfcc8 (patch) | |
tree | 4db3de84fa8f07c5a109134b581c666ce2b813fc /vcl/headless | |
parent | b26a596c5b43834f90de7fb5c6bed824c8d2b2ba (diff) |
headless: move backend to top-level, and enable for all platforms
Diffstat (limited to 'vcl/headless')
-rw-r--r-- | vcl/headless/svpbmp.cxx | 330 | ||||
-rw-r--r-- | vcl/headless/svpdummies.cxx | 119 | ||||
-rw-r--r-- | vcl/headless/svpelement.cxx | 294 | ||||
-rw-r--r-- | vcl/headless/svpframe.cxx | 462 | ||||
-rw-r--r-- | vcl/headless/svpgdi.cxx | 702 | ||||
-rw-r--r-- | vcl/headless/svpinst.cxx | 542 | ||||
-rw-r--r-- | vcl/headless/svpprn.cxx | 322 | ||||
-rw-r--r-- | vcl/headless/svppspgraphics.cxx | 1302 | ||||
-rw-r--r-- | vcl/headless/svptext.cxx | 544 | ||||
-rw-r--r-- | vcl/headless/svpvd.cxx | 112 |
10 files changed, 4729 insertions, 0 deletions
diff --git a/vcl/headless/svpbmp.cxx b/vcl/headless/svpbmp.cxx new file mode 100644 index 000000000000..f385682afada --- /dev/null +++ b/vcl/headless/svpbmp.cxx @@ -0,0 +1,330 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "headless/svpbmp.hxx" + +#include <basegfx/vector/b2ivector.hxx> +#include <basegfx/range/b2irange.hxx> +#include <basebmp/scanlineformats.hxx> +#include <basebmp/color.hxx> + +#include <vcl/salbtype.hxx> +#include <vcl/bitmap.hxx> + +using namespace basebmp; +using namespace basegfx; + +SvpSalBitmap::~SvpSalBitmap() +{ +} + +bool SvpSalBitmap::Create( const Size& rSize, + sal_uInt16 nBitCount, + const BitmapPalette& rPalette ) +{ + sal_uInt32 nFormat = SVP_DEFAULT_BITMAP_FORMAT; + switch( nBitCount ) + { + case 1: nFormat = Format::ONE_BIT_MSB_PAL; break; + case 4: nFormat = Format::FOUR_BIT_MSB_PAL; break; + case 8: nFormat = Format::EIGHT_BIT_PAL; break; +#ifdef OSL_BIGENDIAN + case 16: nFormat = Format::SIXTEEN_BIT_MSB_TC_MASK; break; +#else + case 16: nFormat = Format::SIXTEEN_BIT_LSB_TC_MASK; break; +#endif + case 24: nFormat = Format::TWENTYFOUR_BIT_TC_MASK; break; + case 32: nFormat = Format::THIRTYTWO_BIT_TC_MASK; break; + } + B2IVector aSize( rSize.Width(), rSize.Height() ); + if( aSize.getX() == 0 ) + aSize.setX( 1 ); + if( aSize.getY() == 0 ) + aSize.setY( 1 ); + if( nBitCount > 8 ) + m_aBitmap = createBitmapDevice( aSize, false, nFormat ); + else + { + // prepare palette + unsigned int nEntries = 1U << nBitCount; + std::vector<basebmp::Color>* pPalette = + new std::vector<basebmp::Color>( nEntries, basebmp::Color(COL_WHITE) ); + unsigned int nColors = rPalette.GetEntryCount(); + for( unsigned int i = 0; i < nColors; i++ ) + { + const BitmapColor& rCol = rPalette[i]; + (*pPalette)[i] = basebmp::Color( rCol.GetRed(), rCol.GetGreen(), rCol.GetBlue() ); + } + m_aBitmap = createBitmapDevice( aSize, false, nFormat, + basebmp::RawMemorySharedArray(), + basebmp::PaletteMemorySharedVector( pPalette ) + ); + } + return true; +} + +bool SvpSalBitmap::Create( const SalBitmap& rSalBmp ) +{ + const SvpSalBitmap& rSrc = static_cast<const SvpSalBitmap&>(rSalBmp); + const BitmapDeviceSharedPtr& rSrcBmp = rSrc.getBitmap(); + if( rSrcBmp.get() ) + { + B2IVector aSize = rSrcBmp->getSize(); + m_aBitmap = cloneBitmapDevice( aSize, rSrcBmp ); + B2IRange aRect( 0, 0, aSize.getX(), aSize.getY() ); + m_aBitmap->drawBitmap( rSrcBmp, aRect, aRect, DrawMode_PAINT ); + } + else + m_aBitmap.reset(); + + return true; +} + +bool SvpSalBitmap::Create( const SalBitmap& /*rSalBmp*/, + SalGraphics* /*pGraphics*/ ) +{ + return false; +} + +bool SvpSalBitmap::Create( const SalBitmap& /*rSalBmp*/, + sal_uInt16 /*nNewBitCount*/ ) +{ + return false; +} + +bool SvpSalBitmap::Create( const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XBitmapCanvas > /*xBitmapCanvas*/, Size& /*rSize*/, bool /*bMask*/ ) +{ + return false; +} + +void SvpSalBitmap::Destroy() +{ + m_aBitmap.reset(); +} + +Size SvpSalBitmap::GetSize() const +{ + Size aSize; + if( m_aBitmap.get() ) + { + B2IVector aVec( m_aBitmap->getSize() ); + aSize = Size( aVec.getX(), aVec.getY() ); + } + + return aSize; +} + +sal_uInt16 SvpSalBitmap::GetBitCount() const +{ + sal_uInt16 nDepth = 0; + if( m_aBitmap.get() ) + nDepth = getBitCountFromScanlineFormat( m_aBitmap->getScanlineFormat() ); + return nDepth; +} + +BitmapBuffer* SvpSalBitmap::AcquireBuffer( bool ) +{ + BitmapBuffer* pBuf = NULL; + if( m_aBitmap.get() ) + { + pBuf = new BitmapBuffer(); + sal_uInt16 nBitCount = 1; + switch( m_aBitmap->getScanlineFormat() ) + { + case Format::ONE_BIT_MSB_GREY: + case Format::ONE_BIT_MSB_PAL: + nBitCount = 1; + pBuf->mnFormat = BMP_FORMAT_1BIT_MSB_PAL; + break; + case Format::ONE_BIT_LSB_GREY: + case Format::ONE_BIT_LSB_PAL: + nBitCount = 1; + pBuf->mnFormat = BMP_FORMAT_1BIT_LSB_PAL; + break; + case Format::FOUR_BIT_MSB_GREY: + case Format::FOUR_BIT_MSB_PAL: + nBitCount = 4; + pBuf->mnFormat = BMP_FORMAT_4BIT_MSN_PAL; + break; + case Format::FOUR_BIT_LSB_GREY: + case Format::FOUR_BIT_LSB_PAL: + nBitCount = 4; + pBuf->mnFormat = BMP_FORMAT_4BIT_LSN_PAL; + break; + case Format::EIGHT_BIT_PAL: + nBitCount = 8; + pBuf->mnFormat = BMP_FORMAT_8BIT_PAL; + break; + case Format::EIGHT_BIT_GREY: + nBitCount = 8; + pBuf->mnFormat = BMP_FORMAT_8BIT_PAL; + break; + case Format::SIXTEEN_BIT_LSB_TC_MASK: + nBitCount = 16; + pBuf->mnFormat = BMP_FORMAT_16BIT_TC_LSB_MASK; + pBuf->maColorMask = ColorMask( 0xf800, 0x07e0, 0x001f ); + break; + case Format::SIXTEEN_BIT_MSB_TC_MASK: + nBitCount = 16; + pBuf->mnFormat = BMP_FORMAT_16BIT_TC_MSB_MASK; + pBuf->maColorMask = ColorMask( 0xf800, 0x07e0, 0x001f ); + break; + case Format::TWENTYFOUR_BIT_TC_MASK: + nBitCount = 24; + pBuf->mnFormat = BMP_FORMAT_24BIT_TC_BGR; + break; + case Format::THIRTYTWO_BIT_TC_MASK: + nBitCount = 32; + pBuf->mnFormat = BMP_FORMAT_32BIT_TC_MASK; +#ifdef OSL_BIGENDIAN + pBuf->maColorMask = ColorMask( 0x0000ff, 0x00ff00, 0xff0000 ); +#else + pBuf->maColorMask = ColorMask( 0xff0000, 0x00ff00, 0x0000ff ); +#endif + break; + + default: + // this is an error case !!!!! + nBitCount = 1; + pBuf->mnFormat = BMP_FORMAT_1BIT_MSB_PAL; + break; + } + if( m_aBitmap->isTopDown() ) + pBuf->mnFormat |= BMP_FORMAT_TOP_DOWN; + + B2IVector aSize = m_aBitmap->getSize(); + pBuf->mnWidth = aSize.getX(); + pBuf->mnHeight = aSize.getY(); + pBuf->mnScanlineSize = m_aBitmap->getScanlineStride(); + pBuf->mnBitCount = nBitCount; + pBuf->mpBits = (sal_uInt8*)m_aBitmap->getBuffer().get(); + if( nBitCount <= 8 ) + { + if( m_aBitmap->getScanlineFormat() == Format::EIGHT_BIT_GREY || + m_aBitmap->getScanlineFormat() == Format::FOUR_BIT_LSB_GREY || + m_aBitmap->getScanlineFormat() == Format::FOUR_BIT_MSB_GREY || + m_aBitmap->getScanlineFormat() == Format::ONE_BIT_LSB_GREY || + m_aBitmap->getScanlineFormat() == Format::ONE_BIT_MSB_GREY + ) + pBuf->maPalette = Bitmap::GetGreyPalette( 1U << nBitCount ); + else + { + basebmp::PaletteMemorySharedVector aPalette = m_aBitmap->getPalette(); + if( aPalette.get() ) + { + unsigned int nColors = aPalette->size(); + if( nColors > 0 ) + { + pBuf->maPalette.SetEntryCount( nColors ); + for( unsigned int i = 0; i < nColors; i++ ) + { + const basebmp::Color& rCol = (*aPalette)[i]; + pBuf->maPalette[i] = BitmapColor( rCol.getRed(), rCol.getGreen(), rCol.getBlue() ); + } + } + } + } + } + } + + return pBuf; +} + +void SvpSalBitmap::ReleaseBuffer( BitmapBuffer* pBuffer, bool bReadOnly ) +{ + if( !bReadOnly && pBuffer->maPalette.GetEntryCount() ) + { + // palette might have changed, clone device (but recycle + // memory) + sal_uInt16 nBitCount = 0; + switch( m_aBitmap->getScanlineFormat() ) + { + case Format::ONE_BIT_MSB_GREY: + // FALLTHROUGH intended + case Format::ONE_BIT_MSB_PAL: + // FALLTHROUGH intended + case Format::ONE_BIT_LSB_GREY: + // FALLTHROUGH intended + case Format::ONE_BIT_LSB_PAL: + nBitCount = 1; + break; + + case Format::FOUR_BIT_MSB_GREY: + // FALLTHROUGH intended + case Format::FOUR_BIT_MSB_PAL: + // FALLTHROUGH intended + case Format::FOUR_BIT_LSB_GREY: + // FALLTHROUGH intended + case Format::FOUR_BIT_LSB_PAL: + nBitCount = 4; + break; + + case Format::EIGHT_BIT_PAL: + // FALLTHROUGH intended + case Format::EIGHT_BIT_GREY: + nBitCount = 8; + break; + + default: + break; + } + + if( nBitCount ) + { + sal_uInt32 nEntries = 1U << nBitCount; + + boost::shared_ptr< std::vector<basebmp::Color> > pPal( + new std::vector<basebmp::Color>( nEntries, + basebmp::Color(COL_WHITE))); + const sal_uInt32 nColors = std::min( + (sal_uInt32)pBuffer->maPalette.GetEntryCount(), + nEntries); + for( sal_uInt32 i = 0; i < nColors; i++ ) + { + const BitmapColor& rCol = pBuffer->maPalette[i]; + (*pPal)[i] = basebmp::Color( rCol.GetRed(), rCol.GetGreen(), rCol.GetBlue() ); + } + + m_aBitmap = basebmp::createBitmapDevice( m_aBitmap->getSize(), + m_aBitmap->isTopDown(), + m_aBitmap->getScanlineFormat(), + m_aBitmap->getBuffer(), + pPal ); + } + } + + delete pBuffer; +} + +bool SvpSalBitmap::GetSystemData( BitmapSystemData& ) +{ + return false; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/headless/svpdummies.cxx b/vcl/headless/svpdummies.cxx new file mode 100644 index 000000000000..272f06c7030a --- /dev/null +++ b/vcl/headless/svpdummies.cxx @@ -0,0 +1,119 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "headless/svpdummies.hxx" +#include "headless/svpinst.hxx" +#include <rtl/ustrbuf.hxx> + +// SalObject +SvpSalObject::SvpSalObject() +{ + m_aSystemChildData.nSize = sizeof( SystemChildData ); + m_aSystemChildData.pDisplay = NULL; + m_aSystemChildData.aWindow = 0; + m_aSystemChildData.pSalFrame = 0; + m_aSystemChildData.pWidget = 0; + m_aSystemChildData.pVisual = 0; + m_aSystemChildData.nDepth = 0; + m_aSystemChildData.aColormap = 0; + m_aSystemChildData.pAppContext = NULL; + m_aSystemChildData.aShellWindow = 0; + m_aSystemChildData.pShellWidget = NULL; +} + +SvpSalObject::~SvpSalObject() +{ +} + +void SvpSalObject::ResetClipRegion() {} +sal_uInt16 SvpSalObject::GetClipRegionType() { return 0; } +void SvpSalObject::BeginSetClipRegion( sal_uLong ) {} +void SvpSalObject::UnionClipRegion( long, long, long, long ) {} +void SvpSalObject::EndSetClipRegion() {} +void SvpSalObject::SetPosSize( long, long, long, long ) {} +void SvpSalObject::Show( sal_Bool ) {} +void SvpSalObject::Enable( sal_Bool ) {} +void SvpSalObject::GrabFocus() {} +void SvpSalObject::SetBackground() {} +void SvpSalObject::SetBackground( SalColor ) {} +const SystemEnvData* SvpSalObject::GetSystemData() const { return &m_aSystemChildData; } +void SvpSalObject::InterceptChildWindowKeyDown( sal_Bool ) {} + +// SalI18NImeStatus +SvpImeStatus::~SvpImeStatus() {} +bool SvpImeStatus::canToggle() { return false; } +void SvpImeStatus::toggle() {} + +// SalSystem +SvpSalSystem::~SvpSalSystem() {} + +unsigned int SvpSalSystem::GetDisplayScreenCount() +{ + return 1; +} + +unsigned int SvpSalSystem::GetDefaultDisplayNumber() +{ + return 0; +} + +bool SvpSalSystem::IsMultiDisplay() +{ + return false; +} + +Rectangle SvpSalSystem::GetDisplayScreenPosSizePixel( unsigned int nScreen ) +{ + Rectangle aRect; + if( nScreen == 0 ) + aRect = Rectangle( Point(0,0), Size(VIRTUAL_DESKTOP_WIDTH,VIRTUAL_DESKTOP_HEIGHT) ); + return aRect; +} + +Rectangle SvpSalSystem::GetDisplayWorkAreaPosSizePixel( unsigned int nScreen ) +{ + return GetDisplayScreenPosSizePixel( nScreen ); +} + +rtl::OUString SvpSalSystem::GetScreenName( unsigned int nScreen ) +{ + rtl::OUStringBuffer aBuf( 32 ); + aBuf.appendAscii( "VirtualScreen " ); + aBuf.append( sal_Int32(nScreen) ); + return aBuf.makeStringAndClear(); +} + +int SvpSalSystem::ShowNativeMessageBox( const String&, + const String&, + int, + int ) +{ + return 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/headless/svpelement.cxx b/vcl/headless/svpelement.cxx new file mode 100644 index 000000000000..fb0447224773 --- /dev/null +++ b/vcl/headless/svpelement.cxx @@ -0,0 +1,294 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "headless/svpelement.hxx" + +#include <basebmp/scanlineformats.hxx> +#include <tools/debug.hxx> +#include <osl/diagnose.h> + +#if defined WITH_SVP_LISTENING +#include <osl/thread.h> +#include <vcl/svapp.hxx> +#include <rtl/strbuf.hxx> +#include <vcl/bitmap.hxx> +#include <tools/stream.hxx> + +#include "headless/svpvd.hxx" +#include "headless/svpbmp.hxx" +#include "headless/svpframe.hxx" + +#include <list> +#include <boost/unordered_map.hpp> + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/ip.h> +#include <stdio.h> +#include <errno.h> + +using namespace basegfx; + +class SvpElementContainer +{ + std::list< SvpElement* > m_aElements; + int m_nSocket; + oslThread m_aThread; + + SvpElementContainer(); + ~SvpElementContainer(); + public: + void registerElement( SvpElement* pElement ) { m_aElements.push_back(pElement); } + void deregisterElement( SvpElement* pElement ) { m_aElements.remove(pElement); } + + void run(); + DECL_LINK(processRequest,void*); + + static SvpElementContainer& get(); +}; + +extern "C" void SAL_CALL SvpContainerThread( void* ); + +SvpElementContainer& SvpElementContainer::get() +{ + static SvpElementContainer* pInstance = new SvpElementContainer(); + return *pInstance; +} + +SvpElementContainer::SvpElementContainer() +{ + static const char* pEnv = getenv("SVP_LISTENER_PORT"); + int nPort = (pEnv && *pEnv) ? atoi(pEnv) : 8000; + m_nSocket = socket( PF_INET, SOCK_STREAM, 0 ); + if( m_nSocket >= 0) + { + int nOn = 1; + if( setsockopt(m_nSocket, SOL_SOCKET, SO_REUSEADDR, + (char*)&nOn, sizeof(nOn)) ) + { + perror( "SvpElementContainer: changing socket options failed" ); + close( m_nSocket ); + } + else + { + struct sockaddr_in addr; + memset(&addr, 0, sizeof(struct sockaddr_in)); + addr.sin_family = AF_INET; + addr.sin_port = htons(nPort); + addr.sin_addr.s_addr = INADDR_ANY; + if( bind(m_nSocket,(struct sockaddr*)&addr,sizeof(addr)) ) + { + perror( "SvpElementContainer: bind() failed" ); + close( m_nSocket ); + } + else + { + if( listen( m_nSocket, 0 ) ) + { + perror( "SvpElementContainer: listen() failed" ); + close(m_nSocket); + } + else + { + m_aThread = osl_createThread( SvpContainerThread, this ); + } + } + } + } + else + perror( "SvpElementContainer: socket() failed\n" ); +} + +SvpElementContainer::~SvpElementContainer() +{ +} + +void SAL_CALL SvpContainerThread(void* pSvpContainer) +{ + ((SvpElementContainer*)pSvpContainer)->run(); +} + +void SvpElementContainer::run() +{ + bool bRun = m_nSocket != 0; + while( bRun ) + { + int nLocalSocket = accept( m_nSocket, NULL, NULL ); + if( nLocalSocket < 0 ) + { + bRun = false; + perror( "accept() failed" ); + } + else + { + Application::PostUserEvent( LINK( this, SvpElementContainer, processRequest ), (void*)nLocalSocket ); + } + } + if( m_nSocket ) + close( m_nSocket ); +} + +static const char* matchType( SvpElement* pEle ) +{ + if( dynamic_cast<SvpSalBitmap*>(pEle) ) + return "Bitmap"; + else if( dynamic_cast<SvpSalFrame*>(pEle) ) + return "Frame"; + else if( dynamic_cast<SvpSalVirtualDevice*>(pEle) ) + return "VirtualDevice"; + return typeid(*pEle).name(); +} + +IMPL_LINK( SvpElementContainer, processRequest, void*, pSocket ) +{ + int nFile = (int)pSocket; + + rtl::OStringBuffer aBuf( 256 ), aAnswer( 256 ); + char c; + while( read( nFile, &c, 1 ) && c != '\n' ) + aBuf.append( sal_Char(c) ); + rtl::OString aCommand( aBuf.makeStringAndClear() ); + if( aCommand.compareTo( "list", 4 ) == 0 ) + { + boost::unordered_map< rtl::OString, std::list<SvpElement*>, rtl::OStringHash > aMap; + for( std::list< SvpElement* >::const_iterator it = m_aElements.begin(); + it != m_aElements.end(); ++it ) + { + std::list<SvpElement*>& rList = aMap[matchType(*it)]; + rList.push_back( *it ); + } + for( boost::unordered_map< rtl::OString, std::list<SvpElement*>, rtl::OStringHash>::const_iterator hash_it = aMap.begin(); + hash_it != aMap.end(); ++hash_it ) + { + aAnswer.append( "ElementType: " ); + aAnswer.append( hash_it->first ); + aAnswer.append( '\n' ); + for( std::list<SvpElement*>::const_iterator it = hash_it->second.begin(); + it != hash_it->second.end(); ++it ) + { + aAnswer.append( sal_Int64(reinterpret_cast<sal_uInt32>(*it)), 16 ); + aAnswer.append( '\n' ); + } + } + } + else if( aCommand.compareTo( "get", 3 ) == 0 ) + { + sal_IntPtr aId = aCommand.copy( 3 ).toInt64( 16 ); + SvpElement* pElement = reinterpret_cast<SvpElement*>(aId); + for( std::list< SvpElement* >::const_iterator it = m_aElements.begin(); + it != m_aElements.end(); ++it ) + { + if( *it == pElement ) + { + const basebmp::BitmapDeviceSharedPtr& rDevice = pElement->getDevice(); + if( rDevice.get() ) + { + SvpSalBitmap* pSalBitmap = new SvpSalBitmap(); + pSalBitmap->setBitmap( rDevice ); + Bitmap aBitmap( pSalBitmap ); + SvMemoryStream aStream( 256, 256 ); + aStream << aBitmap; + aStream.Seek( STREAM_SEEK_TO_END ); + int nBytes = aStream.Tell(); + aStream.Seek( STREAM_SEEK_TO_BEGIN ); + aAnswer.append( (const sal_Char*)aStream.GetData(), nBytes ); + } + break; + } + } + } + else if( aCommand.compareTo( "quit", 4 ) == 0 ) + { + Application::Quit(); + close( m_nSocket ); + m_nSocket = 0; + } + write( nFile, aAnswer.getStr(), aAnswer.getLength() ); + close( nFile ); + + return 0; +} + +#endif + +using namespace basebmp; + +SvpElement::SvpElement() +{ + #if defined WITH_SVP_LISTENING + SvpElementContainer::get().registerElement( this ); + #endif +} + +SvpElement::~SvpElement() +{ + #if defined WITH_SVP_LISTENING + SvpElementContainer::get().deregisterElement( this ); + #endif +} + +sal_uInt32 SvpElement::getBitCountFromScanlineFormat( sal_Int32 nFormat ) +{ + sal_uInt32 nBitCount = 1; + switch( nFormat ) + { + case Format::ONE_BIT_MSB_GREY: + case Format::ONE_BIT_LSB_GREY: + case Format::ONE_BIT_MSB_PAL: + case Format::ONE_BIT_LSB_PAL: + nBitCount = 1; + break; + case Format::FOUR_BIT_MSB_GREY: + case Format::FOUR_BIT_LSB_GREY: + case Format::FOUR_BIT_MSB_PAL: + case Format::FOUR_BIT_LSB_PAL: + nBitCount = 4; + break; + case Format::EIGHT_BIT_PAL: + case Format::EIGHT_BIT_GREY: + nBitCount = 8; + break; + case Format::SIXTEEN_BIT_LSB_TC_MASK: + case Format::SIXTEEN_BIT_MSB_TC_MASK: + nBitCount = 16; + break; + case Format::TWENTYFOUR_BIT_TC_MASK: + nBitCount = 24; + break; + case Format::THIRTYTWO_BIT_TC_MASK: + nBitCount = 32; + break; + default: + OSL_FAIL( "unsupported basebmp format" ); + break; + } + return nBitCount; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/headless/svpframe.cxx b/vcl/headless/svpframe.cxx new file mode 100644 index 000000000000..8ff0e5ecf377 --- /dev/null +++ b/vcl/headless/svpframe.cxx @@ -0,0 +1,462 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "headless/svpframe.hxx" +#include "headless/svpinst.hxx" +#include "headless/svpgdi.hxx" + +#include <basebmp/scanlineformats.hxx> +#include <basegfx/vector/b2ivector.hxx> + +using namespace basebmp; +using namespace basegfx; + +SvpSalFrame* SvpSalFrame::s_pFocusFrame = NULL; + +SvpSalFrame::SvpSalFrame( SvpSalInstance* pInstance, + SalFrame* pParent, + sal_uLong nSalFrameStyle, + SystemParentData* ) : + m_pInstance( pInstance ), + m_pParent( static_cast<SvpSalFrame*>(pParent) ), + m_nStyle( nSalFrameStyle ), + m_bVisible( false ), + m_nMinWidth( 0 ), + m_nMinHeight( 0 ), + m_nMaxWidth( 0 ), + m_nMaxHeight( 0 ) +{ + m_aSystemChildData.nSize = sizeof( SystemChildData ); + m_aSystemChildData.pDisplay = NULL; + m_aSystemChildData.aWindow = 0; + m_aSystemChildData.pSalFrame = this; + m_aSystemChildData.pWidget = NULL; + m_aSystemChildData.pVisual = NULL; + m_aSystemChildData.nDepth = 24; + m_aSystemChildData.aColormap = 0; + m_aSystemChildData.pAppContext = NULL; + m_aSystemChildData.aShellWindow = 0; + m_aSystemChildData.pShellWidget = NULL; + + if( m_pParent ) + m_pParent->m_aChildren.push_back( this ); + + if( m_pInstance ) + m_pInstance->registerFrame( this ); + + SetPosSize( 0, 0, 800, 600, SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT ); +} + +SvpSalFrame::~SvpSalFrame() +{ + if( m_pInstance ) + m_pInstance->deregisterFrame( this ); + + std::list<SvpSalFrame*> Children = m_aChildren; + for( std::list<SvpSalFrame*>::iterator it = Children.begin(); + it != Children.end(); ++it ) + (*it)->SetParent( m_pParent ); + if( m_pParent ) + m_pParent->m_aChildren.remove( this ); + + if( s_pFocusFrame == this ) + { + s_pFocusFrame = NULL; + // call directly here, else an event for a destroyed frame would be dispatched + CallCallback( SALEVENT_LOSEFOCUS, NULL ); + // if the handler has not set a new focus frame + // pass focus to another frame, preferably a document style window + if( s_pFocusFrame == NULL ) + { + const std::list< SalFrame* >& rFrames( m_pInstance->getFrames() ); + for( std::list< SalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end(); ++it ) + { + SvpSalFrame* pFrame = const_cast<SvpSalFrame*>(static_cast<const SvpSalFrame*>(*it)); + if( pFrame->m_bVisible && + pFrame->m_pParent == NULL && + (pFrame->m_nStyle & (SAL_FRAME_STYLE_MOVEABLE | + SAL_FRAME_STYLE_SIZEABLE | + SAL_FRAME_STYLE_CLOSEABLE) ) != 0 + ) + { + pFrame->GetFocus(); + break; + } + } + } + } +} + +void SvpSalFrame::GetFocus() +{ + if( (m_nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION | SAL_FRAME_STYLE_FLOAT)) == 0 ) + { + if( s_pFocusFrame ) + s_pFocusFrame->LoseFocus(); + s_pFocusFrame = this; + m_pInstance->PostEvent( this, NULL, SALEVENT_GETFOCUS ); + } +} + +void SvpSalFrame::LoseFocus() +{ + if( s_pFocusFrame == this ) + { + m_pInstance->PostEvent( this, NULL, SALEVENT_LOSEFOCUS ); + s_pFocusFrame = NULL; + } +} + +SalGraphics* SvpSalFrame::GetGraphics() +{ + SvpSalGraphics* pGraphics = new SvpSalGraphics(); + pGraphics->setDevice( m_aFrame ); + m_aGraphics.push_back( pGraphics ); + return pGraphics; +} + +void SvpSalFrame::ReleaseGraphics( SalGraphics* pGraphics ) +{ + SvpSalGraphics* pSvpGraphics = dynamic_cast<SvpSalGraphics*>(pGraphics); + m_aGraphics.remove( pSvpGraphics ); + delete pSvpGraphics; +} + +sal_Bool SvpSalFrame::PostEvent( void* pData ) +{ + m_pInstance->PostEvent( this, pData, SALEVENT_USEREVENT ); + return sal_True; +} + +void SvpSalFrame::PostPaint() const +{ + if( m_bVisible ) + { + SalPaintEvent aPEvt(0, 0, maGeometry.nWidth, maGeometry.nHeight); + CallCallback( SALEVENT_PAINT, &aPEvt ); + } +} + +void SvpSalFrame::SetTitle( const XubString& ) +{ +} + +void SvpSalFrame::SetIcon( sal_uInt16 ) +{ +} + +void SvpSalFrame::SetMenu( SalMenu* ) +{ +} + +void SvpSalFrame::DrawMenuBar() +{ +} + +void SvpSalFrame::SetExtendedFrameStyle( SalExtStyle ) +{ +} + +void SvpSalFrame::Show( sal_Bool bVisible, sal_Bool bNoActivate ) +{ + if( bVisible && ! m_bVisible ) + { + m_bVisible = true; + m_pInstance->PostEvent( this, NULL, SALEVENT_RESIZE ); + if( ! bNoActivate ) + GetFocus(); + } + else if( ! bVisible && m_bVisible ) + { + m_bVisible = false; + m_pInstance->PostEvent( this, NULL, SALEVENT_RESIZE ); + LoseFocus(); + } +} + +void SvpSalFrame::Enable( sal_Bool ) +{ +} + +void SvpSalFrame::SetMinClientSize( long nWidth, long nHeight ) +{ + m_nMinWidth = nWidth; + m_nMinHeight = nHeight; +} + +void SvpSalFrame::SetMaxClientSize( long nWidth, long nHeight ) +{ + m_nMaxWidth = nWidth; + m_nMaxHeight = nHeight; +} + +void SvpSalFrame::SetPosSize( long nX, long nY, long nWidth, long nHeight, sal_uInt16 nFlags ) +{ + if( (nFlags & SAL_FRAME_POSSIZE_X) != 0 ) + maGeometry.nX = nX; + if( (nFlags & SAL_FRAME_POSSIZE_Y) != 0 ) + maGeometry.nY = nY; + if( (nFlags & SAL_FRAME_POSSIZE_WIDTH) != 0 ) + { + maGeometry.nWidth = nWidth; + if( m_nMaxWidth > 0 && maGeometry.nWidth > (unsigned int)m_nMaxWidth ) + maGeometry.nWidth = m_nMaxWidth; + if( m_nMinWidth > 0 && maGeometry.nWidth < (unsigned int)m_nMinWidth ) + maGeometry.nWidth = m_nMinWidth; + } + if( (nFlags & SAL_FRAME_POSSIZE_HEIGHT) != 0 ) + { + maGeometry.nHeight = nHeight; + if( m_nMaxHeight > 0 && maGeometry.nHeight > (unsigned int)m_nMaxHeight ) + maGeometry.nHeight = m_nMaxHeight; + if( m_nMinHeight > 0 && maGeometry.nHeight < (unsigned int)m_nMinHeight ) + maGeometry.nHeight = m_nMinHeight; + } + B2IVector aFrameSize( maGeometry.nWidth, maGeometry.nHeight ); + if( ! m_aFrame.get() || m_aFrame->getSize() != aFrameSize ) + { + if( aFrameSize.getX() == 0 ) + aFrameSize.setX( 1 ); + if( aFrameSize.getY() == 0 ) + aFrameSize.setY( 1 ); + m_aFrame = createBitmapDevice( aFrameSize, false, SVP_DEFAULT_BITMAP_FORMAT ); + // update device in existing graphics + for( std::list< SvpSalGraphics* >::iterator it = m_aGraphics.begin(); + it != m_aGraphics.end(); ++it ) + (*it)->setDevice( m_aFrame ); + } + if( m_bVisible ) + m_pInstance->PostEvent( this, NULL, SALEVENT_RESIZE ); +} + +void SvpSalFrame::GetClientSize( long& rWidth, long& rHeight ) +{ + if( m_bVisible ) + { + rWidth = maGeometry.nWidth; + rHeight = maGeometry.nHeight; + } + else + rWidth = rHeight = 0; +} + +void SvpSalFrame::GetWorkArea( Rectangle& rRect ) +{ + rRect = Rectangle( Point( 0, 0 ), + Size( VIRTUAL_DESKTOP_WIDTH, VIRTUAL_DESKTOP_HEIGHT ) ); +} + +SalFrame* SvpSalFrame::GetParent() const +{ + return m_pParent; +} + +#define _FRAMESTATE_MASK_GEOMETRY \ + (SAL_FRAMESTATE_MASK_X | SAL_FRAMESTATE_MASK_Y | \ + SAL_FRAMESTATE_MASK_WIDTH | SAL_FRAMESTATE_MASK_HEIGHT) +#define _FRAMESTATE_MASK_MAXIMIZED_GEOMETRY \ + (SAL_FRAMESTATE_MASK_MAXIMIZED_X | SAL_FRAMESTATE_MASK_MAXIMIZED_Y | \ + SAL_FRAMESTATE_MASK_MAXIMIZED_WIDTH | SAL_FRAMESTATE_MASK_MAXIMIZED_HEIGHT) + +void SvpSalFrame::SetWindowState( const SalFrameState *pState ) +{ + if (pState == NULL) + return; + + // Request for position or size change + if (pState->mnMask & _FRAMESTATE_MASK_GEOMETRY) + { + long nX = maGeometry.nX; + long nY = maGeometry.nY; + long nWidth = maGeometry.nWidth; + long nHeight = maGeometry.nHeight; + + // change requested properties + if (pState->mnMask & SAL_FRAMESTATE_MASK_X) + nX = pState->mnX; + if (pState->mnMask & SAL_FRAMESTATE_MASK_Y) + nY = pState->mnY; + if (pState->mnMask & SAL_FRAMESTATE_MASK_WIDTH) + nWidth = pState->mnWidth; + if (pState->mnMask & SAL_FRAMESTATE_MASK_HEIGHT) + nHeight = pState->mnHeight; + + SetPosSize( nX, nY, nWidth, nHeight, + SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y | + SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT ); + } +} + +sal_Bool SvpSalFrame::GetWindowState( SalFrameState* pState ) +{ + pState->mnState = SAL_FRAMESTATE_NORMAL; + pState->mnX = maGeometry.nX; + pState->mnY = maGeometry.nY; + pState->mnWidth = maGeometry.nWidth; + pState->mnHeight = maGeometry.nHeight; + pState->mnMask = _FRAMESTATE_MASK_GEOMETRY | SAL_FRAMESTATE_MASK_STATE; + + return sal_True; +} + +void SvpSalFrame::ShowFullScreen( sal_Bool, sal_Int32 ) +{ + SetPosSize( 0, 0, VIRTUAL_DESKTOP_WIDTH, VIRTUAL_DESKTOP_HEIGHT, + SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT ); +} + +void SvpSalFrame::StartPresentation( sal_Bool ) +{ +} + +void SvpSalFrame::SetAlwaysOnTop( sal_Bool ) +{ +} + +void SvpSalFrame::ToTop( sal_uInt16 ) +{ + GetFocus(); +} + +void SvpSalFrame::SetPointer( PointerStyle ) +{ +} + +void SvpSalFrame::CaptureMouse( sal_Bool ) +{ +} + +void SvpSalFrame::SetPointerPos( long, long ) +{ +} + +void SvpSalFrame::Flush() +{ +} + +void SvpSalFrame::Sync() +{ +} + +void SvpSalFrame::SetInputContext( SalInputContext* ) +{ +} + +void SvpSalFrame::EndExtTextInput( sal_uInt16 ) +{ +} + +String SvpSalFrame::GetKeyName( sal_uInt16 ) +{ + return String(); +} + +String SvpSalFrame::GetSymbolKeyName( const XubString&, sal_uInt16 ) +{ + return String(); +} + +sal_Bool SvpSalFrame::MapUnicodeToKeyCode( sal_Unicode, LanguageType, KeyCode& ) +{ + return sal_False; +} + +LanguageType SvpSalFrame::GetInputLanguage() +{ + return LANGUAGE_DONTKNOW; +} + +SalBitmap* SvpSalFrame::SnapShot() +{ + return NULL; +} + +void SvpSalFrame::UpdateSettings( AllSettings& ) +{ +} + +void SvpSalFrame::Beep( SoundType ) +{ +} + +const SystemEnvData* SvpSalFrame::GetSystemData() const +{ + return &m_aSystemChildData; +} + +SalFrame::SalPointerState SvpSalFrame::GetPointerState() +{ + SalPointerState aState; + aState.mnState = 0; + return aState; +} + +SalFrame::SalIndicatorState SvpSalFrame::GetIndicatorState() +{ + SalIndicatorState aState; + aState.mnState = 0; + return aState; +} + +void SvpSalFrame::SimulateKeyPress( sal_uInt16 /*nKeyCode*/ ) +{ +} + +void SvpSalFrame::SetParent( SalFrame* pNewParent ) +{ + if( m_pParent ) + m_pParent->m_aChildren.remove( this ); + m_pParent = static_cast<SvpSalFrame*>(pNewParent); +} + +bool SvpSalFrame::SetPluginParent( SystemParentData* ) +{ + return true; +} + +void SvpSalFrame::SetBackgroundBitmap( SalBitmap* ) +{ +} + +void SvpSalFrame::ResetClipRegion() +{ +} + +void SvpSalFrame::BeginSetClipRegion( sal_uLong ) +{ +} + +void SvpSalFrame::UnionClipRegion( long, long, long, long ) +{ +} + +void SvpSalFrame::EndSetClipRegion() +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/headless/svpgdi.cxx b/vcl/headless/svpgdi.cxx new file mode 100644 index 000000000000..c415774d1bb5 --- /dev/null +++ b/vcl/headless/svpgdi.cxx @@ -0,0 +1,702 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "headless/svpgdi.hxx" +#include "headless/svpbmp.hxx" + +#include <vcl/sysdata.hxx> +#include <basegfx/range/b2drange.hxx> +#include <basegfx/range/b2irange.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basebmp/scanlineformats.hxx> + +#include <tools/debug.hxx> + +#if OSL_DEBUG_LEVEL > 2 +#include <basebmp/debug.hxx> +#include <fstream> +#include <rtl/strbuf.hxx> +#include <sys/stat.h> +#endif + +#include "headless/svppspgraphics.hxx" +#include <region.h> + +using namespace basegfx; +using namespace basebmp; + +inline void dbgOut( const BitmapDeviceSharedPtr& +#if OSL_DEBUG_LEVEL > 2 +rDevice +#endif +) +{ + #if OSL_DEBUG_LEVEL > 2 + static int dbgStreamNum = 0; + rtl::OStringBuffer aBuf( 256 ); + aBuf.append( "debug" ); + mkdir( aBuf.getStr(), 0777 ); + aBuf.append( "/" ); + aBuf.append( sal_Int64(reinterpret_cast<sal_IntPtr>(rDevice.get())), 16 ); + mkdir( aBuf.getStr(), 0777 ); + aBuf.append( "/bmp" ); + aBuf.append( sal_Int32(dbgStreamNum++) ); + std::fstream bmpstream( aBuf.getStr(), std::ios::out ); + debugDump( rDevice, bmpstream ); + #endif +} + +// =========================================================================== + +bool SvpSalGraphics::drawAlphaBitmap( const SalTwoRect&, const SalBitmap& /*rSourceBitmap*/, const SalBitmap& /*rAlphaBitmap*/ ) +{ + // TODO(P3) implement alpha blending + return false; +} + +bool SvpSalGraphics::drawAlphaRect( long /*nX*/, long /*nY*/, long /*nWidth*/, long /*nHeight*/, sal_uInt8 /*nTransparency*/ ) +{ + // TODO(P3) implement alpha blending + return false; +} + +SvpSalGraphics::SvpSalGraphics() : + m_bUseLineColor( true ), + m_aLineColor( COL_BLACK ), + m_bUseFillColor( false ), + m_aFillColor( COL_WHITE ), + m_aTextColor( COL_BLACK ), + m_aDrawMode( DrawMode_PAINT ), + m_eTextFmt( Format::EIGHT_BIT_GREY ), + m_bClipSetup( false ) +{ + for( int i = 0; i < MAX_FALLBACK; ++i ) + m_pServerFont[i] = NULL; +} + +SvpSalGraphics::~SvpSalGraphics() +{ +} + +void SvpSalGraphics::setDevice( BitmapDeviceSharedPtr& rDevice ) +{ + m_aOrigDevice = rDevice; + ResetClipRegion(); + + // determine matching bitmap format for masks + sal_uInt32 nDeviceFmt = m_aDevice->getScanlineFormat(); + DBG_ASSERT( (nDeviceFmt <= (sal_uInt32)Format::MAX), "SVP::setDevice() with invalid bitmap format" ); + switch( nDeviceFmt ) + { + case Format::EIGHT_BIT_GREY: + case Format::SIXTEEN_BIT_LSB_TC_MASK: + case Format::SIXTEEN_BIT_MSB_TC_MASK: + case Format::TWENTYFOUR_BIT_TC_MASK: + case Format::THIRTYTWO_BIT_TC_MASK: + m_eTextFmt = Format::EIGHT_BIT_GREY; + break; + default: + m_eTextFmt = Format::ONE_BIT_LSB_GREY; + break; + } +} + +void SvpSalGraphics::GetResolution( sal_Int32& rDPIX, sal_Int32& rDPIY ) +{ + rDPIX = rDPIY = 96; +} + +sal_uInt16 SvpSalGraphics::GetBitCount() const +{ + return SvpElement::getBitCountFromScanlineFormat( m_aDevice->getScanlineFormat() ); +} + +long SvpSalGraphics::GetGraphicsWidth() const +{ + if( m_aDevice.get() ) + { + B2IVector aSize = m_aOrigDevice->getSize(); + return aSize.getX(); + } + return 0; +} + +void SvpSalGraphics::ResetClipRegion() +{ + m_aDevice = m_aOrigDevice; + m_aClipMap.reset(); + m_bClipSetup = true; + m_aClipRegion.SetNull(); +} + + +// verify clip for the whole area is setup +void SvpSalGraphics::ensureClip() +{ + if (m_bClipSetup) + return; + + m_aDevice = m_aOrigDevice; + B2IVector aSize = m_aDevice->getSize(); + m_aClipMap = createBitmapDevice( aSize, false, Format::ONE_BIT_MSB_GREY ); + m_aClipMap->clear( basebmp::Color(0xFFFFFFFF) ); + + // fprintf( stderr, "non rect clip region set with %d rects:\n", + // (int)m_aClipRegion.GetRectCount() ); + ImplRegionInfo aInfo; + long nX, nY, nW, nH; + bool bRegionRect = m_aClipRegion.ImplGetFirstRect(aInfo, nX, nY, nW, nH ); + while( bRegionRect ) + { + if ( nW && nH ) + { + B2DPolyPolygon aFull; + aFull.append( tools::createPolygonFromRect( B2DRectangle( nX, nY, nX+nW, nY+nH ) ) ); + m_aClipMap->fillPolyPolygon( aFull, basebmp::Color(0), DrawMode_PAINT ); + } + // fprintf( stderr, "\t %ld,%ld %ldx%ld\n", nX, nY, nW, nH ); + bRegionRect = m_aClipRegion.ImplGetNextRect( aInfo, nX, nY, nW, nH ); + } + m_bClipSetup = true; +} + +SvpSalGraphics::ClipUndoHandle::~ClipUndoHandle() +{ + if( m_aDevice.get() ) + m_rGfx.m_aDevice = m_aDevice; +} + +// setup a clip rectangle -only- iff we have to; if aRange +// is entirely contained inside an existing clip frame, we +// will avoid setting up the clip bitmap. +SvpSalGraphics::ClipUndoHandle SvpSalGraphics::ensureClipFor( const basegfx::B2IRange &aRange ) +{ + ClipUndoHandle aRet(this); + + if (m_bClipSetup) + return aRet; + + // fprintf( stderr, "ensureClipFor: %d, %d %dx%d\n", + // aRange.getMinX(), aRange.getMinY(), + // (int)aRange.getWidth(), (int)aRange.getHeight() ); + + // first see if aRange is purely internal to one of the clip regions + Rectangle aRect( Point( aRange.getMinX(), aRange.getMinY() ), + Size( aRange.getWidth(), aRange.getHeight() ) ); + + // then see if we are overlapping with just one + int nHit = 0; + Rectangle aIterRect, aHitRect; + RegionHandle aHnd = m_aClipRegion.BeginEnumRects(); + while( m_aClipRegion.GetNextEnumRect( aHnd, aIterRect ) ) + { + if( aIterRect.IsOver( aRect ) ) + { + aHitRect = aIterRect; + nHit++; + } + } + m_aClipRegion.EndEnumRects (aHnd); + + if( nHit == 0 ) + { + // degenerate case - we're all clipped ... hmm. + fprintf (stderr, "FIXME: denegerate case detected ...\n"); + } + else if( nHit == 1 ) + { + if( aIterRect.IsInside( aRect ) ) + { + // fprintf (stderr, " is inside ! avoid deeper clip ...\n"); + return aRet; + } + // fprintf (stderr, " operation only overlaps with a single clip zone\n" ); + aRet.m_aDevice = m_aDevice; + m_aDevice = basebmp::subsetBitmapDevice( m_aOrigDevice, + basegfx::B2IRange (aHitRect.Left(), + aHitRect.Top(), + aHitRect.Right(), + aHitRect.Bottom()) ); + return aRet; + } + // else + // fprintf (stderr, "URK: complex & slow clipping case\n" ); + + ensureClip(); + return aRet; +} + + +// Clipping by creating unconditional mask bitmaps is horribly +// slow so defer it, as much as possible. It is common to get +// 3 rectangles pushed, and have to create a vast off-screen +// mask only to destroy it shortly afterwards. That is +// particularly galling if we render only to a small, +// well defined rectangular area inside one of these clip +// rectangles. +// +// ensureClipFor() or ensureClip() need to be called before +// real rendering. FIXME: we should prolly push this down to +// bitmapdevice instead. +bool SvpSalGraphics::setClipRegion( const Region& i_rClip ) +{ + m_aClipRegion = i_rClip; + if( i_rClip.IsEmpty() ) + { + m_aClipMap.reset(); + m_bClipSetup = true; + } + else if( i_rClip.GetRectCount() == 1 ) + { + m_aClipMap.reset(); + Rectangle aBoundRect( i_rClip.GetBoundRect() ); + m_aDevice = basebmp::subsetBitmapDevice( m_aOrigDevice, + basegfx::B2IRange(aBoundRect.Left(),aBoundRect.Top(),aBoundRect.Right(),aBoundRect.Bottom()) ); + m_bClipSetup = true; + } + else + m_bClipSetup = false; + return true; +} + +void SvpSalGraphics::SetLineColor() +{ + m_bUseLineColor = false; +} + +void SvpSalGraphics::SetLineColor( SalColor nSalColor ) +{ + m_bUseLineColor = true; + m_aLineColor = basebmp::Color( nSalColor ); +} + +void SvpSalGraphics::SetFillColor() +{ + m_bUseFillColor = false; +} + +void SvpSalGraphics::SetFillColor( SalColor nSalColor ) +{ + m_bUseFillColor = true; + m_aFillColor = basebmp::Color( nSalColor ); +} + +void SvpSalGraphics::SetXORMode( bool bSet, bool ) +{ + m_aDrawMode = bSet ? DrawMode_XOR : DrawMode_PAINT; +} + +void SvpSalGraphics::SetROPLineColor( SalROPColor nROPColor ) +{ + m_bUseLineColor = true; + switch( nROPColor ) + { + case SAL_ROP_0: + m_aLineColor = basebmp::Color( 0 ); + break; + case SAL_ROP_1: + m_aLineColor = basebmp::Color( 0xffffff ); + break; + case SAL_ROP_INVERT: + m_aLineColor = basebmp::Color( 0xffffff ); + break; + } +} + +void SvpSalGraphics::SetROPFillColor( SalROPColor nROPColor ) +{ + m_bUseFillColor = true; + switch( nROPColor ) + { + case SAL_ROP_0: + m_aFillColor = basebmp::Color( 0 ); + break; + case SAL_ROP_1: + m_aFillColor = basebmp::Color( 0xffffff ); + break; + case SAL_ROP_INVERT: + m_aFillColor = basebmp::Color( 0xffffff ); + break; + } +} + +void SvpSalGraphics::SetTextColor( SalColor nSalColor ) +{ + m_aTextColor = basebmp::Color( nSalColor ); +} + +void SvpSalGraphics::drawPixel( long nX, long nY ) +{ + if( m_bUseLineColor ) + { + ensureClip(); + m_aDevice->setPixel( B2IPoint( nX, nY ), + m_aLineColor, + m_aDrawMode, + m_aClipMap + ); + } + dbgOut( m_aDevice ); +} + +void SvpSalGraphics::drawPixel( long nX, long nY, SalColor nSalColor ) +{ + basebmp::Color aColor( nSalColor ); + ensureClip(); + m_aDevice->setPixel( B2IPoint( nX, nY ), + aColor, + m_aDrawMode, + m_aClipMap + ); + dbgOut( m_aDevice ); +} + +void SvpSalGraphics::drawLine( long nX1, long nY1, long nX2, long nY2 ) +{ + if( m_bUseLineColor ) + { + ensureClip(); // FIXME: for ... + m_aDevice->drawLine( B2IPoint( nX1, nY1 ), + B2IPoint( nX2, nY2 ), + m_aLineColor, + m_aDrawMode, + m_aClipMap ); + } + dbgOut( m_aDevice ); +} + +void SvpSalGraphics::drawRect( long nX, long nY, long nWidth, long nHeight ) +{ + if( m_bUseLineColor || m_bUseFillColor ) + { + B2DPolygon aRect = tools::createPolygonFromRect( B2DRectangle( nX, nY, nX+nWidth, nY+nHeight ) ); + ensureClip(); // FIXME: for ... + if( m_bUseFillColor ) + { + B2DPolyPolygon aPolyPoly( aRect ); + m_aDevice->fillPolyPolygon( aPolyPoly, m_aFillColor, m_aDrawMode, m_aClipMap ); + } + if( m_bUseLineColor ) + m_aDevice->drawPolygon( aRect, m_aLineColor, m_aDrawMode, m_aClipMap ); + } + dbgOut( m_aDevice ); +} + +void SvpSalGraphics::drawPolyLine( sal_uLong nPoints, const SalPoint* pPtAry ) +{ + if( m_bUseLineColor && nPoints ) + { + B2DPolygon aPoly; + aPoly.append( B2DPoint( pPtAry->mnX, pPtAry->mnY ), nPoints ); + for( sal_uLong i = 1; i < nPoints; i++ ) + aPoly.setB2DPoint( i, B2DPoint( pPtAry[i].mnX, pPtAry[i].mnY ) ); + aPoly.setClosed( false ); + ensureClip(); // FIXME: for ... + m_aDevice->drawPolygon( aPoly, m_aLineColor, m_aDrawMode, m_aClipMap ); + } + dbgOut( m_aDevice ); +} + +void SvpSalGraphics::drawPolygon( sal_uLong nPoints, const SalPoint* pPtAry ) +{ + if( ( m_bUseLineColor || m_bUseFillColor ) && nPoints ) + { + B2DPolygon aPoly; + aPoly.append( B2DPoint( pPtAry->mnX, pPtAry->mnY ), nPoints ); + for( sal_uLong i = 1; i < nPoints; i++ ) + aPoly.setB2DPoint( i, B2DPoint( pPtAry[i].mnX, pPtAry[i].mnY ) ); + ensureClip(); // FIXME: for ... + if( m_bUseFillColor ) + { + aPoly.setClosed( true ); + m_aDevice->fillPolyPolygon( B2DPolyPolygon(aPoly), m_aFillColor, m_aDrawMode, m_aClipMap ); + } + if( m_bUseLineColor ) + { + aPoly.setClosed( false ); + m_aDevice->drawPolygon( aPoly, m_aLineColor, m_aDrawMode, m_aClipMap ); + } + } + dbgOut( m_aDevice ); +} + +void SvpSalGraphics::drawPolyPolygon( sal_uInt32 nPoly, + const sal_uInt32* pPointCounts, + PCONSTSALPOINT* pPtAry ) +{ + if( ( m_bUseLineColor || m_bUseFillColor ) && nPoly ) + { + B2DPolyPolygon aPolyPoly; + for( sal_uInt32 nPolygon = 0; nPolygon < nPoly; nPolygon++ ) + { + sal_uInt32 nPoints = pPointCounts[nPolygon]; + if( nPoints ) + { + PCONSTSALPOINT pPoints = pPtAry[nPolygon]; + B2DPolygon aPoly; + aPoly.append( B2DPoint( pPoints->mnX, pPoints->mnY ), nPoints ); + for( sal_uInt32 i = 1; i < nPoints; i++ ) + aPoly.setB2DPoint( i, B2DPoint( pPoints[i].mnX, pPoints[i].mnY ) ); + + aPolyPoly.append( aPoly ); + } + } + ensureClip(); // FIXME: for ... + if( m_bUseFillColor ) + { + aPolyPoly.setClosed( true ); + m_aDevice->fillPolyPolygon( aPolyPoly, m_aFillColor, m_aDrawMode, m_aClipMap ); + } + if( m_bUseLineColor ) + { + aPolyPoly.setClosed( false ); + nPoly = aPolyPoly.count(); + for( sal_uInt32 i = 0; i < nPoly; i++ ) + m_aDevice->drawPolygon( aPolyPoly.getB2DPolygon(i), m_aLineColor, m_aDrawMode, m_aClipMap ); + } + } + dbgOut( m_aDevice ); +} + +bool SvpSalGraphics::drawPolyLine( const ::basegfx::B2DPolygon&, double /*fTransparency*/, const ::basegfx::B2DVector& /*rLineWidths*/, basegfx::B2DLineJoin /*eJoin*/ ) +{ + // TODO: implement and advertise OutDevSupport_B2DDraw support + return false; +} + +sal_Bool SvpSalGraphics::drawPolyLineBezier( sal_uLong, + const SalPoint*, + const sal_uInt8* ) +{ + return sal_False; +} + +sal_Bool SvpSalGraphics::drawPolygonBezier( sal_uLong, + const SalPoint*, + const sal_uInt8* ) +{ + return sal_False; +} + +sal_Bool SvpSalGraphics::drawPolyPolygonBezier( sal_uInt32, + const sal_uInt32*, + const SalPoint* const*, + const sal_uInt8* const* ) +{ + return sal_False; +} + +bool SvpSalGraphics::drawPolyPolygon( const basegfx::B2DPolyPolygon&, double /*fTransparency*/ ) +{ + // TODO: maybe BaseBmp can draw B2DPolyPolygons directly + return false; +} + +void SvpSalGraphics::copyArea( long nDestX, + long nDestY, + long nSrcX, + long nSrcY, + long nSrcWidth, + long nSrcHeight, + sal_uInt16 /*nFlags*/ ) +{ + B2IRange aSrcRect( nSrcX, nSrcY, nSrcX+nSrcWidth, nSrcY+nSrcHeight ); + B2IRange aDestRect( nDestX, nDestY, nDestX+nSrcWidth, nDestY+nSrcHeight ); + // fprintf( stderr, "copyArea %ld pixels - clip region %d\n", + // (long)(nSrcWidth * nSrcHeight), m_aClipMap.get() != NULL ); + SvpSalGraphics::ClipUndoHandle aUndo = ensureClipFor( aDestRect ); + m_aDevice->drawBitmap( m_aOrigDevice, aSrcRect, aDestRect, DrawMode_PAINT, m_aClipMap ); + dbgOut( m_aDevice ); +} + +void SvpSalGraphics::copyBits( const SalTwoRect* pPosAry, + SalGraphics* pSrcGraphics ) +{ + SvpSalGraphics* pSrc = pSrcGraphics ? + static_cast<SvpSalGraphics*>(pSrcGraphics) : this; + B2IRange aSrcRect( pPosAry->mnSrcX, pPosAry->mnSrcY, + pPosAry->mnSrcX+pPosAry->mnSrcWidth, + pPosAry->mnSrcY+pPosAry->mnSrcHeight ); + B2IRange aDestRect( pPosAry->mnDestX, pPosAry->mnDestY, + pPosAry->mnDestX+pPosAry->mnDestWidth, + pPosAry->mnDestY+pPosAry->mnDestHeight ); + SvpSalGraphics::ClipUndoHandle aUndo = ensureClipFor( aDestRect ); + m_aDevice->drawBitmap( pSrc->m_aOrigDevice, aSrcRect, aDestRect, DrawMode_PAINT, m_aClipMap ); + dbgOut( m_aDevice ); +} + +void SvpSalGraphics::drawBitmap( const SalTwoRect* pPosAry, + const SalBitmap& rSalBitmap ) +{ + const SvpSalBitmap& rSrc = static_cast<const SvpSalBitmap&>(rSalBitmap); + B2IRange aSrcRect( pPosAry->mnSrcX, pPosAry->mnSrcY, + pPosAry->mnSrcX+pPosAry->mnSrcWidth, + pPosAry->mnSrcY+pPosAry->mnSrcHeight ); + B2IRange aDestRect( pPosAry->mnDestX, pPosAry->mnDestY, + pPosAry->mnDestX+pPosAry->mnDestWidth, + pPosAry->mnDestY+pPosAry->mnDestHeight ); + SvpSalGraphics::ClipUndoHandle aUndo = ensureClipFor( aDestRect ); + m_aDevice->drawBitmap( rSrc.getBitmap(), aSrcRect, aDestRect, DrawMode_PAINT, m_aClipMap ); + dbgOut( m_aDevice ); +} + +void SvpSalGraphics::drawBitmap( const SalTwoRect*, + const SalBitmap&, + SalColor ) +{ + // SNI, as in X11 plugin +} + +void SvpSalGraphics::drawBitmap( const SalTwoRect* pPosAry, + const SalBitmap& rSalBitmap, + const SalBitmap& rTransparentBitmap ) +{ + const SvpSalBitmap& rSrc = static_cast<const SvpSalBitmap&>(rSalBitmap); + const SvpSalBitmap& rSrcTrans = static_cast<const SvpSalBitmap&>(rTransparentBitmap); + B2IRange aSrcRect( pPosAry->mnSrcX, pPosAry->mnSrcY, + pPosAry->mnSrcX+pPosAry->mnSrcWidth, + pPosAry->mnSrcY+pPosAry->mnSrcHeight ); + B2IRange aDestRect( pPosAry->mnDestX, pPosAry->mnDestY, + pPosAry->mnDestX+pPosAry->mnDestWidth, + pPosAry->mnDestY+pPosAry->mnDestHeight ); + SvpSalGraphics::ClipUndoHandle aUndo = ensureClipFor( aDestRect ); + m_aDevice->drawMaskedBitmap( rSrc.getBitmap(), rSrcTrans.getBitmap(), aSrcRect, aDestRect, DrawMode_PAINT, m_aClipMap ); + dbgOut( m_aDevice ); +} + +void SvpSalGraphics::drawMask( const SalTwoRect* pPosAry, + const SalBitmap& rSalBitmap, + SalColor nMaskColor ) +{ + const SvpSalBitmap& rSrc = static_cast<const SvpSalBitmap&>(rSalBitmap); + B2IRange aSrcRect( pPosAry->mnSrcX, pPosAry->mnSrcY, + pPosAry->mnSrcX+pPosAry->mnSrcWidth, + pPosAry->mnSrcY+pPosAry->mnSrcHeight ); + B2IPoint aDestPoint( pPosAry->mnDestX, pPosAry->mnDestY ); + + // BitmapDevice::drawMaskedColor works with 0==transparent, + // 255==opaque. drawMask() semantic is the other way + // around. Therefore, invert mask. + BitmapDeviceSharedPtr aCopy = + cloneBitmapDevice( B2IVector( pPosAry->mnSrcWidth, pPosAry->mnSrcHeight ), + rSrc.getBitmap() ); + basebmp::Color aBgColor( COL_WHITE ); + aCopy->clear(aBgColor); + basebmp::Color aFgColor( COL_BLACK ); + aCopy->drawMaskedColor( aFgColor, rSrc.getBitmap(), aSrcRect, B2IPoint() ); + + basebmp::Color aColor( nMaskColor ); + B2IRange aSrcRect2( 0, 0, pPosAry->mnSrcWidth, pPosAry->mnSrcHeight ); + const B2IRange aClipRect( aDestPoint, B2ITuple( aSrcRect.getWidth(), aSrcRect.getHeight() ) ); + SvpSalGraphics::ClipUndoHandle aUndo = ensureClipFor( aClipRect ); + m_aDevice->drawMaskedColor( aColor, aCopy, aSrcRect, aDestPoint, m_aClipMap ); + dbgOut( m_aDevice ); +} + +SalBitmap* SvpSalGraphics::getBitmap( long nX, long nY, long nWidth, long nHeight ) +{ + BitmapDeviceSharedPtr aCopy = + cloneBitmapDevice( B2IVector( nWidth, nHeight ), + m_aDevice ); + B2IRange aSrcRect( nX, nY, nX+nWidth, nY+nHeight ); + B2IRange aDestRect( 0, 0, nWidth, nHeight ); + SvpSalGraphics::ClipUndoHandle aUndo = ensureClipFor( aDestRect ); + aCopy->drawBitmap( m_aOrigDevice, aSrcRect, aDestRect, DrawMode_PAINT ); + + SvpSalBitmap* pBitmap = new SvpSalBitmap(); + pBitmap->setBitmap( aCopy ); + return pBitmap; +} + +SalColor SvpSalGraphics::getPixel( long nX, long nY ) +{ + basebmp::Color aColor( m_aOrigDevice->getPixel( B2IPoint( nX, nY ) ) ); + return aColor.toInt32(); +} + +void SvpSalGraphics::invert( long nX, long nY, long nWidth, long nHeight, SalInvert /*nFlags*/ ) +{ + // FIXME: handle SAL_INVERT_50 and SAL_INVERT_TRACKFRAME + B2DPolygon aRect = tools::createPolygonFromRect( B2DRectangle( nX, nY, nX+nWidth, nY+nHeight ) ); + B2DPolyPolygon aPolyPoly( aRect ); + ensureClip(); // FIXME for ... + m_aDevice->fillPolyPolygon( aPolyPoly, basebmp::Color( 0xffffff ), DrawMode_XOR, m_aClipMap ); + dbgOut( m_aDevice ); +} + +void SvpSalGraphics::invert( sal_uLong nPoints, const SalPoint* pPtAry, SalInvert /*nFlags*/ ) +{ + // FIXME: handle SAL_INVERT_50 and SAL_INVERT_TRACKFRAME + B2DPolygon aPoly; + aPoly.append( B2DPoint( pPtAry->mnX, pPtAry->mnY ), nPoints ); + for( sal_uLong i = 1; i < nPoints; i++ ) + aPoly.setB2DPoint( i, B2DPoint( pPtAry[i].mnX, pPtAry[i].mnY ) ); + aPoly.setClosed( true ); + ensureClip(); // FIXME for ... + m_aDevice->fillPolyPolygon( B2DPolyPolygon(aPoly), basebmp::Color( 0xffffff ), DrawMode_XOR, m_aClipMap ); + dbgOut( m_aDevice ); +} + +sal_Bool SvpSalGraphics::drawEPS( long, long, long, long, void*, sal_uLong ) +{ + return sal_False; +} + +SystemFontData SvpSalGraphics::GetSysFontData( int nFallbacklevel ) const +{ + SystemFontData aSysFontData; + + if (nFallbacklevel >= MAX_FALLBACK) nFallbacklevel = MAX_FALLBACK - 1; + if (nFallbacklevel < 0 ) nFallbacklevel = 0; + + aSysFontData.nSize = sizeof( SystemFontData ); + aSysFontData.nFontId = 0; + aSysFontData.nFontFlags = 0; + aSysFontData.bFakeBold = false; + aSysFontData.bFakeItalic = false; + aSysFontData.bAntialias = true; + return aSysFontData; +} + +SystemGraphicsData SvpSalGraphics::GetGraphicsData() const +{ + SystemGraphicsData aRes; + aRes.nSize = sizeof(aRes); + aRes.hDrawable = 0; + aRes.pXRenderFormat = 0; + return aRes; +} + +bool SvpSalGraphics::supportsOperation( OutDevSupportType ) const +{ + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/headless/svpinst.cxx b/vcl/headless/svpinst.cxx new file mode 100644 index 000000000000..182cf867529e --- /dev/null +++ b/vcl/headless/svpinst.cxx @@ -0,0 +1,542 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <unistd.h> +#include <fcntl.h> +#include <sys/time.h> +#include <sys/poll.h> + +#include <sal/types.h> + +#include <vcl/apptypes.hxx> + +#include "headless/svpinst.hxx" +#include "headless/svpframe.hxx" +#include "headless/svpdummies.hxx" +#include "headless/svpvd.hxx" +#include "headless/svpbmp.hxx" + +#include <salframe.hxx> +#include <svdata.hxx> +#include <saldatabasic.hxx> +#include <vcl/solarmutex.hxx> + +// FIXME: split off into a separate, standalone module to aid linking +#ifndef GTK3_INCLUDED +// plugin factory function +extern "C" +{ + SAL_DLLPUBLIC_EXPORT SalInstance* create_SalInstance() + { + SvpSalInstance* pInstance = new SvpSalInstance(); + SalData* pSalData = new SalData(); + pSalData->m_pInstance = pInstance; + SetSalData( pSalData ); + return pInstance; + } +} +#endif + +bool SvpSalInstance::isFrameAlive( const SalFrame* pFrame ) const +{ + for( std::list< SalFrame* >::const_iterator it = m_aFrames.begin(); + it != m_aFrames.end(); ++it ) + { + if( *it == pFrame ) + { + return true; + } + } + return false; +} + +SvpSalInstance* SvpSalInstance::s_pDefaultInstance = NULL; + +SvpSalInstance::SvpSalInstance() : + SalGenericInstance( new SalYieldMutex() ) +{ + m_aTimeout.tv_sec = 0; + m_aTimeout.tv_usec = 0; + m_nTimeoutMS = 0; + + m_pTimeoutFDS[0] = m_pTimeoutFDS[1] = -1; + if (pipe (m_pTimeoutFDS) != -1) + { + // initialize 'wakeup' pipe. + int flags; + + // set close-on-exec descriptor flag. + if ((flags = fcntl (m_pTimeoutFDS[0], F_GETFD)) != -1) + { + flags |= FD_CLOEXEC; + fcntl (m_pTimeoutFDS[0], F_SETFD, flags); + } + if ((flags = fcntl (m_pTimeoutFDS[1], F_GETFD)) != -1) + { + flags |= FD_CLOEXEC; + fcntl (m_pTimeoutFDS[1], F_SETFD, flags); + } + + // set non-blocking I/O flag. + if ((flags = fcntl (m_pTimeoutFDS[0], F_GETFL)) != -1) + { + flags |= O_NONBLOCK; + fcntl (m_pTimeoutFDS[0], F_SETFL, flags); + } + if ((flags = fcntl (m_pTimeoutFDS[1], F_GETFL)) != -1) + { + flags |= O_NONBLOCK; + fcntl (m_pTimeoutFDS[1], F_SETFL, flags); + } + } + m_aEventGuard = osl_createMutex(); + if( s_pDefaultInstance == NULL ) + s_pDefaultInstance = this; +} + +SvpSalInstance::~SvpSalInstance() +{ + if( s_pDefaultInstance == this ) + s_pDefaultInstance = NULL; + + // close 'wakeup' pipe. + close (m_pTimeoutFDS[0]); + close (m_pTimeoutFDS[1]); + osl_destroyMutex( m_aEventGuard ); +} + +void SvpSalInstance::PostEvent( const SalFrame* pFrame, void* pData, sal_uInt16 nEvent ) +{ + if( osl_acquireMutex( m_aEventGuard ) ) + { + m_aUserEvents.push_back( SalUserEvent( pFrame, pData, nEvent ) ); + osl_releaseMutex( m_aEventGuard ); + } + Wakeup(); +} + +void SvpSalInstance::CancelEvent( const SalFrame* pFrame, void* pData, sal_uInt16 nEvent ) +{ + if( osl_acquireMutex( m_aEventGuard ) ) + { + if( ! m_aUserEvents.empty() ) + { + std::list< SalUserEvent >::iterator it = m_aUserEvents.begin(); + do + { + if( it->m_pFrame == pFrame && + it->m_pData == pData && + it->m_nEvent == nEvent ) + { + it = m_aUserEvents.erase( it ); + } + else + ++it; + } while( it != m_aUserEvents.end() ); + } + osl_releaseMutex( m_aEventGuard ); + } +} + +void SvpSalInstance::deregisterFrame( SalFrame* pFrame ) +{ + m_aFrames.remove( pFrame ); + + if( osl_acquireMutex( m_aEventGuard ) ) + { + // cancel outstanding events for this frame + if( ! m_aUserEvents.empty() ) + { + std::list< SalUserEvent >::iterator it = m_aUserEvents.begin(); + do + { + if( it->m_pFrame == pFrame ) + { + it = m_aUserEvents.erase( it ); + } + else + ++it; + } while( it != m_aUserEvents.end() ); + } + osl_releaseMutex( m_aEventGuard ); + } +} + +void SvpSalInstance::Wakeup() +{ + OSL_VERIFY(write (m_pTimeoutFDS[1], "", 1) == 1); +} + +// FIXME: share this with unx/generic [!] .... +#ifndef GTK3_INCLUDED +// -=-= timeval =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +inline int operator >= ( const timeval &t1, const timeval &t2 ) +{ + if( t1.tv_sec == t2.tv_sec ) + return t1.tv_usec >= t2.tv_usec; + return t1.tv_sec > t2.tv_sec; +} +inline timeval &operator += ( timeval &t1, sal_uLong t2 ) +{ + t1.tv_sec += t2 / 1000; + t1.tv_usec += t2 ? (t2 % 1000) * 1000 : 500; + if( t1.tv_usec > 1000000 ) + { + t1.tv_sec++; + t1.tv_usec -= 1000000; + } + return t1; +} +inline int operator > ( const timeval &t1, const timeval &t2 ) +{ + if( t1.tv_sec == t2.tv_sec ) + return t1.tv_usec > t2.tv_usec; + return t1.tv_sec > t2.tv_sec; +} +#endif + +bool SvpSalInstance::CheckTimeout( bool bExecuteTimers ) +{ + bool bRet = false; + if( m_aTimeout.tv_sec ) // timer is started + { + timeval aTimeOfDay; + gettimeofday( &aTimeOfDay, 0 ); + if( aTimeOfDay >= m_aTimeout ) + { + bRet = true; + if( bExecuteTimers ) + { + // timed out, update timeout + m_aTimeout = aTimeOfDay; + m_aTimeout += m_nTimeoutMS; + // notify + ImplSVData* pSVData = ImplGetSVData(); + if( pSVData->mpSalTimer ) + pSVData->mpSalTimer->CallCallback(); + } + } + } + return bRet; +} + +SalFrame* SvpSalInstance::CreateChildFrame( SystemParentData* pParent, sal_uLong nStyle ) +{ + return new SvpSalFrame( this, NULL, nStyle, pParent ); +} + +SalFrame* SvpSalInstance::CreateFrame( SalFrame* pParent, sal_uLong nStyle ) +{ + return new SvpSalFrame( this, pParent, nStyle ); +} + +void SvpSalInstance::DestroyFrame( SalFrame* pFrame ) +{ + delete pFrame; +} + +SalObject* SvpSalInstance::CreateObject( SalFrame*, SystemWindowData*, sal_Bool ) +{ + return new SvpSalObject(); +} + +void SvpSalInstance::DestroyObject( SalObject* pObject ) +{ + delete pObject; +} + +SalVirtualDevice* SvpSalInstance::CreateVirtualDevice( SalGraphics*, + long nDX, long nDY, + sal_uInt16 nBitCount, const SystemGraphicsData* ) +{ + SvpSalVirtualDevice* pNew = new SvpSalVirtualDevice( nBitCount ); + pNew->SetSize( nDX, nDY ); + return pNew; +} + +void SvpSalInstance::DestroyVirtualDevice( SalVirtualDevice* pDevice ) +{ + delete pDevice; +} + +SalTimer* SvpSalInstance::CreateSalTimer() +{ + return new SvpSalTimer( this ); +} + +SalI18NImeStatus* SvpSalInstance::CreateI18NImeStatus() +{ + return new SvpImeStatus(); +} + +SalSystem* SvpSalInstance::CreateSalSystem() +{ + return new SvpSalSystem(); +} + +SalBitmap* SvpSalInstance::CreateSalBitmap() +{ + return new SvpSalBitmap(); +} + +osl::SolarMutex* SvpSalInstance::GetYieldMutex() +{ + return &m_aYieldMutex; +} + +sal_uLong SvpSalInstance::ReleaseYieldMutex() +{ + if ( m_aYieldMutex.GetThreadId() == + osl::Thread::getCurrentIdentifier() ) + { + sal_uLong nCount = m_aYieldMutex.GetAcquireCount(); + sal_uLong n = nCount; + while ( n ) + { + m_aYieldMutex.release(); + n--; + } + + return nCount; + } + else + return 0; +} + +void SvpSalInstance::AcquireYieldMutex( sal_uLong nCount ) +{ + while ( nCount ) + { + m_aYieldMutex.acquire(); + nCount--; + } +} + +bool SvpSalInstance::CheckYieldMutex() +{ + bool bRet = true; + + if ( m_aYieldMutex.GetThreadId() != ::osl::Thread::getCurrentIdentifier() ) + { + bRet = false; + } + + return bRet; +} + +void SvpSalInstance::Yield( bool bWait, bool bHandleAllCurrentEvents ) +{ + // first, check for already queued events. + + // release yield mutex + std::list< SalUserEvent > aEvents; + sal_uLong nAcquireCount = ReleaseYieldMutex(); + if( osl_acquireMutex( m_aEventGuard ) ) + { + if( ! m_aUserEvents.empty() ) + { + if( bHandleAllCurrentEvents ) + { + aEvents = m_aUserEvents; + m_aUserEvents.clear(); + } + else + { + aEvents.push_back( m_aUserEvents.front() ); + m_aUserEvents.pop_front(); + } + } + osl_releaseMutex( m_aEventGuard ); + } + // acquire yield mutex again + AcquireYieldMutex( nAcquireCount ); + + bool bEvent = !aEvents.empty(); + if( bEvent ) + { + for( std::list<SalUserEvent>::const_iterator it = aEvents.begin(); it != aEvents.end(); ++it ) + { + if ( isFrameAlive( it->m_pFrame ) ) + { + it->m_pFrame->CallCallback( it->m_nEvent, it->m_pData ); + if( it->m_nEvent == SALEVENT_RESIZE ) + { + // this would be a good time to post a paint + const SvpSalFrame* pSvpFrame = static_cast<const SvpSalFrame*>(it->m_pFrame); + pSvpFrame->PostPaint(); + } + } + } + } + + bEvent = CheckTimeout() || bEvent; + + if (bWait && ! bEvent ) + { + int nTimeoutMS = 0; + if (m_aTimeout.tv_sec) // Timer is started. + { + timeval Timeout; + // determine remaining timeout. + gettimeofday (&Timeout, 0); + nTimeoutMS = m_aTimeout.tv_sec*1000 + m_aTimeout.tv_usec/1000 + - Timeout.tv_sec*1000 - Timeout.tv_usec/1000; + if( nTimeoutMS < 0 ) + nTimeoutMS = 0; + } + else + nTimeoutMS = -1; // wait until something happens + + // release yield mutex + nAcquireCount = ReleaseYieldMutex(); + // poll + struct pollfd aPoll; + aPoll.fd = m_pTimeoutFDS[0]; + aPoll.events = POLLIN; + aPoll.revents = 0; + poll( &aPoll, 1, nTimeoutMS ); + + // acquire yield mutex again + AcquireYieldMutex( nAcquireCount ); + + // clean up pipe + if( (aPoll.revents & POLLIN) != 0 ) + { + int buffer; + while (read (m_pTimeoutFDS[0], &buffer, sizeof(buffer)) > 0) + continue; + } + } +} + +bool SvpSalInstance::AnyInput( sal_uInt16 nType ) +{ + if( (nType & INPUT_TIMER) != 0 ) + return CheckTimeout( false ); + return false; +} + +SalSession* SvpSalInstance::CreateSalSession() +{ + return NULL; +} + +void* SvpSalInstance::GetConnectionIdentifier( ConnectionIdentifierType& rReturnedType, int& rReturnedBytes ) +{ + rReturnedBytes = 1; + rReturnedType = AsciiCString; + return const_cast<char*>(""); +} + +// ------------------------------------------------------------------------- +// +// SalYieldMutex +// +// ------------------------------------------------------------------------- + +SvpSalYieldMutex::SvpSalYieldMutex() +{ + mnCount = 0; + mnThreadId = 0; +} + +void SvpSalYieldMutex::acquire() +{ + SolarMutexObject::acquire(); + mnThreadId = osl::Thread::getCurrentIdentifier(); + mnCount++; +} + +void SvpSalYieldMutex::release() +{ + if ( mnThreadId == osl::Thread::getCurrentIdentifier() ) + { + if ( mnCount == 1 ) + mnThreadId = 0; + mnCount--; + } + SolarMutexObject::release(); +} + +sal_Bool SvpSalYieldMutex::tryToAcquire() +{ + if ( SolarMutexObject::tryToAcquire() ) + { + mnThreadId = osl::Thread::getCurrentIdentifier(); + mnCount++; + return sal_True; + } + else + return sal_False; +} + +// --------------- +// - SalTimer - +// --------------- + +void SvpSalInstance::StopTimer() +{ + m_aTimeout.tv_sec = 0; + m_aTimeout.tv_usec = 0; + m_nTimeoutMS = 0; +} + +void SvpSalInstance::StartTimer( sal_uLong nMS ) +{ + timeval Timeout (m_aTimeout); // previous timeout. + gettimeofday (&m_aTimeout, 0); + + m_nTimeoutMS = nMS; + m_aTimeout += m_nTimeoutMS; + + if ((Timeout > m_aTimeout) || (Timeout.tv_sec == 0)) + { + // Wakeup from previous timeout (or stopped timer). + Wakeup(); + } +} + +void SvpSalInstance::AddToRecentDocumentList(const rtl::OUString&, const rtl::OUString&) +{ +} + +SvpSalTimer::~SvpSalTimer() +{ +} + +void SvpSalTimer::Stop() +{ + m_pInstance->StopTimer(); +} + +void SvpSalTimer::Start( sal_uLong nMS ) +{ + m_pInstance->StartTimer( nMS ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/headless/svpprn.cxx b/vcl/headless/svpprn.cxx new file mode 100644 index 000000000000..452f8ab2f940 --- /dev/null +++ b/vcl/headless/svpprn.cxx @@ -0,0 +1,322 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" + +#include <unistd.h> +#include <sys/stat.h> +#include <sys/wait.h> + +#include "vcl/svapp.hxx" +#include "vcl/timer.hxx" +#include "vcl/printerinfomanager.hxx" + +#include "jobset.h" +#include "print.h" +#include "salptype.hxx" +#include "saldatabasic.hxx" + +#include "headless/svpprn.hxx" +#include "headless/svppspgraphics.hxx" +#include "headless/svpinst.hxx" + +using namespace psp; + +using ::rtl::OUString; +using ::rtl::OUStringToOString; + +/* + * static helpers + */ + +static String getPdfDir( const PrinterInfo& rInfo ) +{ + String aDir; + sal_Int32 nIndex = 0; + while( nIndex != -1 ) + { + OUString aToken( rInfo.m_aFeatures.getToken( 0, ',', nIndex ) ); + if( ! aToken.compareToAscii( "pdf=", 4 ) ) + { + sal_Int32 nPos = 0; + aDir = aToken.getToken( 1, '=', nPos ); + if( ! aDir.Len() ) + aDir = String( ByteString( getenv( "HOME" ) ), osl_getThreadTextEncoding() ); + break; + } + } + return aDir; +} + +inline int PtTo10Mu( int nPoints ) { return (int)((((double)nPoints)*35.27777778)+0.5); } + +inline int TenMuToPt( int nUnits ) { return (int)((((double)nUnits)/35.27777778)+0.5); } + +static void copyJobDataToJobSetup( ImplJobSetup* pJobSetup, JobData& rData ) +{ + pJobSetup->meOrientation = (Orientation)(rData.m_eOrientation == orientation::Landscape ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT); + + // copy page size + String aPaper; + int width, height; + + rData.m_aContext.getPageSize( aPaper, width, height ); + pJobSetup->mePaperFormat = PaperInfo::fromPSName(OUStringToOString( aPaper, RTL_TEXTENCODING_ISO_8859_1 )); + pJobSetup->mnPaperWidth = 0; + pJobSetup->mnPaperHeight = 0; + if( pJobSetup->mePaperFormat == PAPER_USER ) + { + // transform to 100dth mm + width = PtTo10Mu( width ); + height = PtTo10Mu( height ); + + if( rData.m_eOrientation == psp::orientation::Portrait ) + { + pJobSetup->mnPaperWidth = width; + pJobSetup->mnPaperHeight= height; + } + else + { + pJobSetup->mnPaperWidth = height; + pJobSetup->mnPaperHeight= width; + } + } + + // copy input slot + const PPDKey* pKey = NULL; + const PPDValue* pValue = NULL; + + pJobSetup->mnPaperBin = 0xffff; + if( rData.m_pParser ) + pKey = rData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) ); + if( pKey ) + pValue = rData.m_aContext.getValue( pKey ); + if( pKey && pValue ) + { + for( pJobSetup->mnPaperBin = 0; + pValue != pKey->getValue( pJobSetup->mnPaperBin ) && + pJobSetup->mnPaperBin < pKey->countValues(); + pJobSetup->mnPaperBin++ ) + ; + if( pJobSetup->mnPaperBin >= pKey->countValues() || pValue == pKey->getDefaultValue() ) + pJobSetup->mnPaperBin = 0xffff; + } + + // copy duplex + pKey = NULL; + pValue = NULL; + + pJobSetup->meDuplexMode = DUPLEX_UNKNOWN; + if( rData.m_pParser ) + pKey = rData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Duplex" ) ) ); + if( pKey ) + pValue = rData.m_aContext.getValue( pKey ); + if( pKey && pValue ) + { + if( pValue->m_aOption.EqualsIgnoreCaseAscii( "None" ) || + pValue->m_aOption.EqualsIgnoreCaseAscii( "Simplex", 0, 7 ) + ) + { + pJobSetup->meDuplexMode = DUPLEX_OFF; + } + else if( pValue->m_aOption.EqualsIgnoreCaseAscii( "DuplexNoTumble" ) ) + { + pJobSetup->meDuplexMode = DUPLEX_LONGEDGE; + } + else if( pValue->m_aOption.EqualsIgnoreCaseAscii( "DuplexTumble" ) ) + { + pJobSetup->meDuplexMode = DUPLEX_SHORTEDGE; + } + } + + // copy the whole context + if( pJobSetup->mpDriverData ) + rtl_freeMemory( pJobSetup->mpDriverData ); + + int nBytes; + void* pBuffer = NULL; + if( rData.getStreamBuffer( pBuffer, nBytes ) ) + { + pJobSetup->mnDriverDataLen = nBytes; + pJobSetup->mpDriverData = (sal_uInt8*)pBuffer; + } + else + { + pJobSetup->mnDriverDataLen = 0; + pJobSetup->mpDriverData = NULL; + } +} + +/* + * SalInstance + */ + +// ----------------------------------------------------------------------- + +SalInfoPrinter* SvpSalInstance::CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo, + ImplJobSetup* pJobSetup ) +{ + // create and initialize SalInfoPrinter + SvpSalInfoPrinter* pPrinter = new SvpSalInfoPrinter; + + if( pJobSetup ) + { + PrinterInfoManager& rManager( PrinterInfoManager::get() ); + PrinterInfo aInfo( rManager.getPrinterInfo( pQueueInfo->maPrinterName ) ); + pPrinter->m_aJobData = aInfo; + pPrinter->m_aPrinterGfx.Init( pPrinter->m_aJobData ); + + if( pJobSetup->mpDriverData ) + JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aInfo ); + + pJobSetup->mnSystem = JOBSETUP_SYSTEM_UNIX; + pJobSetup->maPrinterName = pQueueInfo->maPrinterName; + pJobSetup->maDriver = aInfo.m_aDriverName; + copyJobDataToJobSetup( pJobSetup, aInfo ); + + // set/clear backwards compatibility flag + bool bStrictSO52Compatibility = false; + boost::unordered_map<rtl::OUString, rtl::OUString, rtl::OUStringHash >::const_iterator compat_it = + pJobSetup->maValueMap.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StrictSO52Compatibility" ) ) ); + if( compat_it != pJobSetup->maValueMap.end() ) + { + if( compat_it->second.equalsIgnoreAsciiCaseAscii( "true" ) ) + bStrictSO52Compatibility = true; + } + pPrinter->m_aPrinterGfx.setStrictSO52Compatibility( bStrictSO52Compatibility ); + } + + + return pPrinter; +} + +// ----------------------------------------------------------------------- + +void SvpSalInstance::DestroyInfoPrinter( SalInfoPrinter* pPrinter ) +{ + delete pPrinter; +} + +// ----------------------------------------------------------------------- + +SalPrinter* SvpSalInstance::CreatePrinter( SalInfoPrinter* pInfoPrinter ) +{ + // create and initialize SalPrinter + SvpSalPrinter* pPrinter = new SvpSalPrinter( pInfoPrinter ); + pPrinter->m_aJobData = static_cast<SvpSalInfoPrinter*>(pInfoPrinter)->m_aJobData; + + return pPrinter; +} + +// ----------------------------------------------------------------------- + +void SvpSalInstance::DestroyPrinter( SalPrinter* pPrinter ) +{ + delete pPrinter; +} + +// ----------------------------------------------------------------------- + +void SvpSalInstance::GetPrinterQueueInfo( ImplPrnQueueList* pList ) +{ + PrinterInfoManager& rManager( PrinterInfoManager::get() ); + static const char* pNoSyncDetection = getenv( "SAL_DISABLE_SYNCHRONOUS_PRINTER_DETECTION" ); + if( ! pNoSyncDetection || ! *pNoSyncDetection ) + { + // #i62663# synchronize possible asynchronouse printer detection now + rManager.checkPrintersChanged( true ); + } + ::std::list< OUString > aPrinters; + rManager.listPrinters( aPrinters ); + + for( ::std::list< OUString >::iterator it = aPrinters.begin(); it != aPrinters.end(); ++it ) + { + const PrinterInfo& rInfo( rManager.getPrinterInfo( *it ) ); + // Neuen Eintrag anlegen + SalPrinterQueueInfo* pInfo = new SalPrinterQueueInfo; + pInfo->maPrinterName = *it; + pInfo->maDriver = rInfo.m_aDriverName; + pInfo->maLocation = rInfo.m_aLocation; + pInfo->maComment = rInfo.m_aComment; + pInfo->mpSysData = NULL; + + sal_Int32 nIndex = 0; + while( nIndex != -1 ) + { + String aToken( rInfo.m_aFeatures.getToken( 0, ',', nIndex ) ); + if( aToken.CompareToAscii( "pdf=", 4 ) == COMPARE_EQUAL ) + { + pInfo->maLocation = getPdfDir( rInfo ); + break; + } + } + + pList->Add( pInfo ); + } +} + +// ----------------------------------------------------------------------- + +void SvpSalInstance::DeletePrinterQueueInfo( SalPrinterQueueInfo* pInfo ) +{ + delete pInfo; +} + +// ----------------------------------------------------------------------- + +void SvpSalInstance::GetPrinterQueueState( SalPrinterQueueInfo* ) +{ +} + +// ----------------------------------------------------------------------- + +String SvpSalInstance::GetDefaultPrinter() +{ + PrinterInfoManager& rManager( PrinterInfoManager::get() ); + return rManager.getDefaultPrinter(); +} + +// ----------------------------------------------------------------------- + +void SvpSalInstance::PostPrintersChanged() +{ + const std::list< SalFrame* >& rList = SvpSalInstance::s_pDefaultInstance->getFrames(); + for( std::list< SalFrame* >::const_iterator it = rList.begin(); + it != rList.end(); ++it ) + SvpSalInstance::s_pDefaultInstance->PostEvent( *it, NULL, SALEVENT_PRINTERCHANGED ); +} + +// ----------------------------------------------------------------------- + +sal_Bool SvpSalInfoPrinter::Setup( SalFrame*, ImplJobSetup* ) +{ + return sal_False; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/headless/svppspgraphics.cxx b/vcl/headless/svppspgraphics.cxx new file mode 100644 index 000000000000..5a792538948b --- /dev/null +++ b/vcl/headless/svppspgraphics.cxx @@ -0,0 +1,1302 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" + +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include "basegfx/vector/b2ivector.hxx" +#include "basegfx/point/b2ipoint.hxx" + +#include "basebmp/color.hxx" + +#include "vcl/jobdata.hxx" +#include "vcl/printerinfomanager.hxx" +#include "vcl/bmpacc.hxx" +#include "vcl/svapp.hxx" +#include "vcl/sysdata.hxx" + +#include "salprn.hxx" +#include "salbmp.hxx" +#include "impfont.hxx" +#include "outfont.hxx" +#include "fontsubset.hxx" +#include "generic/printergfx.hxx" +#include "headless/svppspgraphics.hxx" +#include "headless/svpbmp.hxx" +#include "generic/glyphcache.hxx" +#include "region.h" + +using namespace psp; +using namespace basebmp; +using namespace basegfx; +using ::rtl::OUString; +using ::rtl::OString; +// ----- Implementation of PrinterBmp by means of SalBitmap/BitmapBuffer --------------- + +class SalPrinterBmp : public psp::PrinterBmp +{ + private: + SalPrinterBmp (); + + BitmapDeviceSharedPtr m_aBitmap; + public: + + SalPrinterBmp (const BitmapDeviceSharedPtr& rDevice); + virtual ~SalPrinterBmp (); + virtual sal_uInt32 GetPaletteColor (sal_uInt32 nIdx) const; + virtual sal_uInt32 GetPaletteEntryCount () const; + virtual sal_uInt32 GetPixelRGB (sal_uInt32 nRow, sal_uInt32 nColumn) const; + virtual sal_uInt8 GetPixelGray (sal_uInt32 nRow, sal_uInt32 nColumn) const; + virtual sal_uInt8 GetPixelIdx (sal_uInt32 nRow, sal_uInt32 nColumn) const; + virtual sal_uInt32 GetWidth () const; + virtual sal_uInt32 GetHeight() const; + virtual sal_uInt32 GetDepth () const; + + static sal_uInt32 getRGBFromColor( const basebmp::Color& rCol ) + { + return ((rCol.getBlue()) & 0x000000ff) + | ((rCol.getGreen() << 8) & 0x0000ff00) + | ((rCol.getRed() << 16) & 0x00ff0000); + } +}; + +SalPrinterBmp::SalPrinterBmp(const BitmapDeviceSharedPtr& rDevice) : + m_aBitmap( rDevice ) +{ +} + +SalPrinterBmp::~SalPrinterBmp () +{ +} + +sal_uInt32 +SalPrinterBmp::GetWidth () const +{ + return m_aBitmap.get() ? m_aBitmap->getSize().getX() : 0; +} + +sal_uInt32 +SalPrinterBmp::GetHeight () const +{ + return m_aBitmap.get() ? m_aBitmap->getSize().getY() : 0; +} + +sal_uInt32 +SalPrinterBmp::GetDepth () const +{ + return m_aBitmap.get() ? + SvpElement::getBitCountFromScanlineFormat( m_aBitmap->getScanlineFormat() ) + : 0; +} + + +sal_uInt32 +SalPrinterBmp::GetPaletteEntryCount () const +{ + return m_aBitmap.get() ? m_aBitmap->getPaletteEntryCount() : 0; +} + +sal_uInt32 +SalPrinterBmp::GetPaletteColor (sal_uInt32 nIdx) const +{ + sal_uInt32 nCol = 0; + if( m_aBitmap.get() && nIdx < static_cast<sal_uInt32>(m_aBitmap->getPaletteEntryCount()) ) + { + const basebmp::Color& rColor = (*m_aBitmap->getPalette().get())[ nIdx ]; + nCol = getRGBFromColor( rColor ); + } + return nCol; +} + +sal_uInt32 +SalPrinterBmp::GetPixelRGB (sal_uInt32 nRow, sal_uInt32 nColumn) const +{ + sal_uInt32 nCol = 0; + if( m_aBitmap.get() ) + nCol = getRGBFromColor( m_aBitmap->getPixel( B2IPoint( nColumn, nRow ) ) ); + return nCol; +} + +sal_uInt8 +SalPrinterBmp::GetPixelGray (sal_uInt32 nRow, sal_uInt32 nColumn) const +{ + sal_uInt8 nGray = 0; + if( m_aBitmap.get() ) + { + // TODO: don't use tools color + basebmp::Color aCol = m_aBitmap->getPixel( B2IPoint( nColumn, nRow ) ); + ::Color aColor( aCol.getRed(), aCol.getGreen(), aCol.getBlue() ); + nGray = aColor.GetLuminance(); + } + return nGray; +} + +sal_uInt8 +SalPrinterBmp::GetPixelIdx (sal_uInt32 nRow, sal_uInt32 nColumn) const +{ + sal_uInt8 nIdx = 0; + if( m_aBitmap.get() ) + nIdx = static_cast<sal_uInt8>(m_aBitmap->getPixelData( B2IPoint( nColumn, nRow ) )); + return nIdx; +} + +/******************************************************* + * PspGraphics * + *******************************************************/ + +bool PspGraphics::drawAlphaBitmap( const SalTwoRect&, const SalBitmap& /*rSourceBitmap*/, const SalBitmap& /*rAlphaBitmap*/ ) +{ + return false; +} + +bool PspGraphics::drawAlphaRect( long /*nX*/, long /*nY*/, long /*nWidth*/, long /*nHeight*/, sal_uInt8 /*nTransparency*/ ) +{ + return false; +} + +bool PspGraphics::supportsOperation( OutDevSupportType ) const +{ + return false; +} + +PspGraphics::~PspGraphics() +{ + ReleaseFonts(); +} + +void PspGraphics::GetResolution( sal_Int32 &rDPIX, sal_Int32 &rDPIY ) +{ + if (m_pJobData != NULL) + { + int x = m_pJobData->m_aContext.getRenderResolution(); + + rDPIX = x; + rDPIY = x; + } +} + +sal_uInt16 PspGraphics::GetBitCount() const +{ + return m_pPrinterGfx->GetBitCount(); +} + +long PspGraphics::GetGraphicsWidth() const +{ + return 0; +} + +void PspGraphics::ResetClipRegion() +{ + m_pPrinterGfx->ResetClipRegion(); +} + +bool PspGraphics::setClipRegion( const Region& i_rClip ) +{ + // TODO: support polygonal clipregions here + m_pPrinterGfx->BeginSetClipRegion( i_rClip.GetRectCount() ); + + ImplRegionInfo aInfo; + long nX, nY, nW, nH; + bool bRegionRect = i_rClip.ImplGetFirstRect(aInfo, nX, nY, nW, nH ); + while( bRegionRect ) + { + if ( nW && nH ) + { + m_pPrinterGfx->UnionClipRegion( nX, nY, nW, nH ); + } + bRegionRect = i_rClip.ImplGetNextRect( aInfo, nX, nY, nW, nH ); + } + m_pPrinterGfx->EndSetClipRegion(); + return true; +} + +void PspGraphics::SetLineColor() +{ + m_pPrinterGfx->SetLineColor (); +} + +void PspGraphics::SetLineColor( SalColor nSalColor ) +{ + psp::PrinterColor aColor (SALCOLOR_RED (nSalColor), + SALCOLOR_GREEN (nSalColor), + SALCOLOR_BLUE (nSalColor)); + m_pPrinterGfx->SetLineColor (aColor); +} + +void PspGraphics::SetFillColor() +{ + m_pPrinterGfx->SetFillColor (); +} + +void PspGraphics::SetFillColor( SalColor nSalColor ) +{ + psp::PrinterColor aColor (SALCOLOR_RED (nSalColor), + SALCOLOR_GREEN (nSalColor), + SALCOLOR_BLUE (nSalColor)); + m_pPrinterGfx->SetFillColor (aColor); +} + +void PspGraphics::SetROPLineColor( SalROPColor ) +{ + DBG_ASSERT( 0, "Error: PrinterGfx::SetROPLineColor() not implemented" ); +} + +void PspGraphics::SetROPFillColor( SalROPColor ) +{ + DBG_ASSERT( 0, "Error: PrinterGfx::SetROPFillColor() not implemented" ); +} + +void PspGraphics::SetXORMode( bool bSet, bool ) +{ + (void)bSet; + DBG_ASSERT( !bSet, "Error: PrinterGfx::SetXORMode() not implemented" ); +} + +void PspGraphics::drawPixel( long nX, long nY ) +{ + m_pPrinterGfx->DrawPixel (Point(nX, nY)); +} + +void PspGraphics::drawPixel( long nX, long nY, SalColor nSalColor ) +{ + psp::PrinterColor aColor (SALCOLOR_RED (nSalColor), + SALCOLOR_GREEN (nSalColor), + SALCOLOR_BLUE (nSalColor)); + m_pPrinterGfx->DrawPixel (Point(nX, nY), aColor); +} + +void PspGraphics::drawLine( long nX1, long nY1, long nX2, long nY2 ) +{ + m_pPrinterGfx->DrawLine (Point(nX1, nY1), Point(nX2, nY2)); +} + +void PspGraphics::drawRect( long nX, long nY, long nDX, long nDY ) +{ + m_pPrinterGfx->DrawRect (Rectangle(Point(nX, nY), Size(nDX, nDY))); +} + +void PspGraphics::drawPolyLine( sal_uLong nPoints, const SalPoint *pPtAry ) +{ + m_pPrinterGfx->DrawPolyLine (nPoints, (Point*)pPtAry); +} + +void PspGraphics::drawPolygon( sal_uLong nPoints, const SalPoint* pPtAry ) +{ + // Point must be equal to SalPoint! see vcl/inc/salgtype.hxx + m_pPrinterGfx->DrawPolygon (nPoints, (Point*)pPtAry); +} + +void PspGraphics::drawPolyPolygon( sal_uInt32 nPoly, + const sal_uInt32 *pPoints, + PCONSTSALPOINT *pPtAry ) +{ + m_pPrinterGfx->DrawPolyPolygon (nPoly, pPoints, (const Point**)pPtAry); +} + +bool PspGraphics::drawPolyLine( const ::basegfx::B2DPolygon&, double /*fTransparency*/, const ::basegfx::B2DVector& /*rLineWidths*/, basegfx::B2DLineJoin /*eJoin*/ ) +{ + // TODO: implement and advertise OutDevSupport_B2DDraw support + return false; +} + +sal_Bool PspGraphics::drawPolyLineBezier( sal_uLong nPoints, const SalPoint* pPtAry, const sal_uInt8* pFlgAry ) +{ + m_pPrinterGfx->DrawPolyLineBezier (nPoints, (Point*)pPtAry, pFlgAry); + return sal_True; +} + +sal_Bool PspGraphics::drawPolygonBezier( sal_uLong nPoints, const SalPoint* pPtAry, const sal_uInt8* pFlgAry ) +{ + m_pPrinterGfx->DrawPolygonBezier (nPoints, (Point*)pPtAry, pFlgAry); + return sal_True; +} + +sal_Bool PspGraphics::drawPolyPolygonBezier( sal_uInt32 nPoly, + const sal_uInt32* pPoints, + const SalPoint* const* pPtAry, + const sal_uInt8* const* pFlgAry ) +{ + // Point must be equal to SalPoint! see vcl/inc/salgtype.hxx + m_pPrinterGfx->DrawPolyPolygonBezier (nPoly, pPoints, (Point**)pPtAry, (sal_uInt8**)pFlgAry); + return sal_True; +} + +bool PspGraphics::drawPolyPolygon( const basegfx::B2DPolyPolygon&, double /*fTransparency*/ ) +{ + // TODO: implement and advertise OutDevSupport_B2DDraw support + return false; +} + +void PspGraphics::invert( sal_uLong /*nPoints*/, + const SalPoint* /*pPtAry*/, + SalInvert /*nFlags*/ ) +{ + DBG_ASSERT( 0, "Error: PrinterGfx::Invert() not implemented" ); +} +sal_Bool PspGraphics::drawEPS( long nX, long nY, long nWidth, long nHeight, void* pPtr, sal_uLong nSize ) +{ + return m_pPrinterGfx->DrawEPS( Rectangle( Point( nX, nY ), Size( nWidth, nHeight ) ), pPtr, nSize ); +} + +void PspGraphics::copyBits( const SalTwoRect* /*pPosAry*/, + SalGraphics* /*pSSrcGraphics*/ ) +{ + OSL_FAIL( "Error: PrinterGfx::CopyBits() not implemented" ); +} + +void PspGraphics::copyArea ( long /*nDestX*/, long /*nDestY*/, + long /*nSrcX*/, long /*nSrcY*/, + long /*nSrcWidth*/, long /*nSrcHeight*/, + sal_uInt16 /*nFlags*/ ) +{ + OSL_FAIL( "Error: PrinterGfx::CopyArea() not implemented" ); +} + +void PspGraphics::drawBitmap( const SalTwoRect* pPosAry, const SalBitmap& rSalBitmap ) +{ + Rectangle aSrc (Point(pPosAry->mnSrcX, pPosAry->mnSrcY), + Size(pPosAry->mnSrcWidth, pPosAry->mnSrcHeight)); + Rectangle aDst (Point(pPosAry->mnDestX, pPosAry->mnDestY), + Size(pPosAry->mnDestWidth, pPosAry->mnDestHeight)); + + const SvpSalBitmap* pBmp = dynamic_cast<const SvpSalBitmap*>(&rSalBitmap); + if( pBmp ) + { + SalPrinterBmp aBmp(pBmp->getBitmap()); + m_pPrinterGfx->DrawBitmap(aDst, aSrc, aBmp); + } +} + +void PspGraphics::drawBitmap( const SalTwoRect* /*pPosAry*/, + const SalBitmap& /*rSalBitmap*/, + const SalBitmap& /*rTransBitmap*/ ) +{ + OSL_FAIL("Error: no PrinterGfx::DrawBitmap() for transparent bitmap"); +} + +void PspGraphics::drawBitmap( const SalTwoRect* /*pPosAry*/, + const SalBitmap& /*rSalBitmap*/, + SalColor /*nTransparentColor*/ ) +{ + OSL_FAIL("Error: no PrinterGfx::DrawBitmap() for transparent color"); +} + +void PspGraphics::drawMask( const SalTwoRect* /*pPosAry*/, + const SalBitmap& /*rSalBitmap*/, + SalColor /*nMaskColor*/ ) +{ + OSL_FAIL("Error: PrinterGfx::DrawMask() not implemented"); +} + +SalBitmap* PspGraphics::getBitmap( long /*nX*/, long /*nY*/, long /*nDX*/, long /*nDY*/ ) +{ + DBG_WARNING ("Warning: PrinterGfx::GetBitmap() not implemented"); + return NULL; +} + +SalColor PspGraphics::getPixel( long /*nX*/, long /*nY*/ ) +{ + OSL_FAIL("Warning: PrinterGfx::GetPixel() not implemented"); + return 0; +} + +void PspGraphics::invert( + long /*nX*/, + long /*nY*/, + long /*nDX*/, + long /*nDY*/, + SalInvert /*nFlags*/ ) +{ + OSL_FAIL("Warning: PrinterGfx::Invert() not implemented"); +} + +//========================================================================== + +class ImplPspFontData : public ImplFontData +{ +private: + enum { PSPFD_MAGIC = 0xb5bf01f0 }; + sal_IntPtr mnFontId; + +public: + ImplPspFontData( const psp::FastPrintFontInfo& ); + virtual sal_IntPtr GetFontId() const { return mnFontId; } + virtual ImplFontData* Clone() const { return new ImplPspFontData( *this ); } + virtual ImplFontEntry* CreateFontInstance( ImplFontSelectData& ) const; + static bool CheckFontData( const ImplFontData& r ) { return r.CheckMagic( PSPFD_MAGIC ); } +}; + +//-------------------------------------------------------------------------- + +ImplPspFontData::ImplPspFontData( const psp::FastPrintFontInfo& rInfo ) +: ImplFontData( PspGraphics::Info2DevFontAttributes(rInfo), PSPFD_MAGIC ), + mnFontId( rInfo.m_nID ) +{} + +//-------------------------------------------------------------------------- + +ImplFontEntry* ImplPspFontData::CreateFontInstance( ImplFontSelectData& rFSD ) const +{ + ImplServerFontEntry* pEntry = new ImplServerFontEntry( rFSD ); + return pEntry; +} + +//========================================================================== + +class PspFontLayout : public GenericSalLayout +{ +public: + PspFontLayout( ::psp::PrinterGfx& ); + virtual bool LayoutText( ImplLayoutArgs& ); + virtual void InitFont() const; + virtual void DrawText( SalGraphics& ) const; +private: + ::psp::PrinterGfx& mrPrinterGfx; + sal_IntPtr mnFontID; + int mnFontHeight; + int mnFontWidth; + bool mbVertical; + bool mbArtItalic; + bool mbArtBold; +}; + +//-------------------------------------------------------------------------- + +PspFontLayout::PspFontLayout( ::psp::PrinterGfx& rGfx ) +: mrPrinterGfx( rGfx ) +{ + mnFontID = mrPrinterGfx.GetFontID(); + mnFontHeight = mrPrinterGfx.GetFontHeight(); + mnFontWidth = mrPrinterGfx.GetFontWidth(); + mbVertical = mrPrinterGfx.GetFontVertical(); + mbArtItalic = mrPrinterGfx.GetArtificialItalic(); + mbArtBold = mrPrinterGfx.GetArtificialBold(); +} + +//-------------------------------------------------------------------------- + +bool PspFontLayout::LayoutText( ImplLayoutArgs& rArgs ) +{ + mbVertical = ((rArgs.mnFlags & SAL_LAYOUT_VERTICAL) != 0); + + long nUnitsPerPixel = 1; + int nOldGlyphId = -1; + long nGlyphWidth = 0; + int nCharPos = -1; + Point aNewPos( 0, 0 ); + GlyphItem aPrevItem; + rtl_TextEncoding aFontEnc = mrPrinterGfx.GetFontMgr().getFontEncoding( mnFontID ); + for(;;) + { + bool bRightToLeft; + if( !rArgs.GetNextPos( &nCharPos, &bRightToLeft ) ) + break; + + sal_UCS4 cChar = rArgs.mpStr[ nCharPos ]; + if( bRightToLeft ) + cChar = GetMirroredChar( cChar ); + // symbol font aliasing: 0x0020-0x00ff -> 0xf020 -> 0xf0ff + if( aFontEnc == RTL_TEXTENCODING_SYMBOL ) + if( cChar < 256 ) + cChar += 0xf000; + int nGlyphIndex = cChar; // printer glyphs = unicode + + // update fallback_runs if needed + psp::CharacterMetric aMetric; + mrPrinterGfx.GetFontMgr().getMetrics( mnFontID, cChar, cChar, &aMetric, mbVertical ); + if( aMetric.width == -1 && aMetric.height == -1 ) + rArgs.NeedFallback( nCharPos, bRightToLeft ); + + // apply pair kerning to prev glyph if requested + if( SAL_LAYOUT_KERNING_PAIRS & rArgs.mnFlags ) + { + if( nOldGlyphId > 0 ) + { + const std::list< KernPair >& rKernPairs = mrPrinterGfx.getKernPairs(mbVertical); + for( std::list< KernPair >::const_iterator it = rKernPairs.begin(); + it != rKernPairs.end(); ++it ) + { + if( it->first == nOldGlyphId && it->second == nGlyphIndex ) + { + int nTextScale = mrPrinterGfx.GetFontWidth(); + if( ! nTextScale ) + nTextScale = mrPrinterGfx.GetFontHeight(); + int nKern = (mbVertical ? it->kern_y : it->kern_x) * nTextScale; + nGlyphWidth += nKern; + aPrevItem.mnNewWidth = nGlyphWidth; + break; + } + } + } + } + + // finish previous glyph + if( nOldGlyphId >= 0 ) + AppendGlyph( aPrevItem ); + nOldGlyphId = nGlyphIndex; + aNewPos.X() += nGlyphWidth; + + // prepare GlyphItem for appending it in next round + nUnitsPerPixel = mrPrinterGfx.GetCharWidth( cChar, cChar, &nGlyphWidth ); + int nGlyphFlags = bRightToLeft ? GlyphItem::IS_RTL_GLYPH : 0; + nGlyphIndex |= GF_ISCHAR; + aPrevItem = GlyphItem( nCharPos, nGlyphIndex, aNewPos, nGlyphFlags, nGlyphWidth ); + } + + // append last glyph item if any + if( nOldGlyphId >= 0 ) + AppendGlyph( aPrevItem ); + + SetOrientation( mrPrinterGfx.GetFontAngle() ); + SetUnitsPerPixel( nUnitsPerPixel ); + return (nOldGlyphId >= 0); +} + +class PspServerFontLayout : public ServerFontLayout +{ +public: + PspServerFontLayout( psp::PrinterGfx&, ServerFont& rFont, const ImplLayoutArgs& rArgs ); + + virtual void InitFont() const; + const sal_Unicode* getTextPtr() const { return maText.getStr() - mnMinCharPos; } + int getMinCharPos() const { return mnMinCharPos; } + int getMaxCharPos() const { return mnMinCharPos+maText.getLength()-1; } +private: + ::psp::PrinterGfx& mrPrinterGfx; + sal_IntPtr mnFontID; + int mnFontHeight; + int mnFontWidth; + bool mbVertical; + bool mbArtItalic; + bool mbArtBold; + rtl::OUString maText; + int mnMinCharPos; +}; + +PspServerFontLayout::PspServerFontLayout( ::psp::PrinterGfx& rGfx, ServerFont& rFont, const ImplLayoutArgs& rArgs ) + : ServerFontLayout( rFont ), + mrPrinterGfx( rGfx ) +{ + mnFontID = mrPrinterGfx.GetFontID(); + mnFontHeight = mrPrinterGfx.GetFontHeight(); + mnFontWidth = mrPrinterGfx.GetFontWidth(); + mbVertical = mrPrinterGfx.GetFontVertical(); + mbArtItalic = mrPrinterGfx.GetArtificialItalic(); + mbArtBold = mrPrinterGfx.GetArtificialBold(); + maText = OUString( rArgs.mpStr + rArgs.mnMinCharPos, rArgs.mnEndCharPos - rArgs.mnMinCharPos+1 ); + mnMinCharPos = rArgs.mnMinCharPos; +} + +void PspServerFontLayout::InitFont() const +{ + mrPrinterGfx.SetFont( mnFontID, mnFontHeight, mnFontWidth, + mnOrientation, mbVertical, mbArtItalic, mbArtBold ); +} + +//-------------------------------------------------------------------------- + +static void DrawPrinterLayout( const SalLayout& rLayout, ::psp::PrinterGfx& rGfx, bool bIsPspServerFontLayout ) +{ + const int nMaxGlyphs = 200; + sal_GlyphId aGlyphAry[ nMaxGlyphs ]; + sal_Int32 aWidthAry[ nMaxGlyphs ]; + sal_Int32 aIdxAry [ nMaxGlyphs ]; + sal_Ucs aUnicodes[ nMaxGlyphs ]; + int aCharPosAry [ nMaxGlyphs ]; + + Point aPos; + long nUnitsPerPixel = rLayout.GetUnitsPerPixel(); + const sal_Unicode* pText = bIsPspServerFontLayout ? static_cast<const PspServerFontLayout&>(rLayout).getTextPtr() : NULL; + int nMinCharPos = bIsPspServerFontLayout ? static_cast<const PspServerFontLayout&>(rLayout).getMinCharPos() : 0; + int nMaxCharPos = bIsPspServerFontLayout ? static_cast<const PspServerFontLayout&>(rLayout).getMaxCharPos() : 0; + for( int nStart = 0;; ) + { + int nGlyphCount = rLayout.GetNextGlyphs( nMaxGlyphs, aGlyphAry, aPos, nStart, aWidthAry, bIsPspServerFontLayout ? aCharPosAry : NULL ); + if( !nGlyphCount ) + break; + + sal_Int32 nXOffset = 0; + for( int i = 0; i < nGlyphCount; ++i ) + { + nXOffset += aWidthAry[ i ]; + aIdxAry[ i ] = nXOffset / nUnitsPerPixel; + sal_Int32 nGlyphIdx = aGlyphAry[i] & (GF_IDXMASK | GF_ROTMASK); + if( bIsPspServerFontLayout ) + aUnicodes[i] = (aCharPosAry[i] >= nMinCharPos && aCharPosAry[i] <= nMaxCharPos) ? pText[ aCharPosAry[i] ] : 0; + else + aUnicodes[i] = (aGlyphAry[i] & GF_ISCHAR) ? nGlyphIdx : 0; + aGlyphAry[i] = nGlyphIdx; + } + + rGfx.DrawGlyphs( aPos, (sal_uInt32 *)aGlyphAry, aUnicodes, nGlyphCount, aIdxAry ); + } +} + +//-------------------------------------------------------------------------- + +void PspFontLayout::InitFont() const +{ + mrPrinterGfx.SetFont( mnFontID, mnFontHeight, mnFontWidth, + mnOrientation, mbVertical, mbArtItalic, mbArtBold ); +} + +//-------------------------------------------------------------------------- + +void PspFontLayout::DrawText( SalGraphics& ) const +{ + DrawPrinterLayout( *this, mrPrinterGfx, false ); +} + +void PspGraphics::DrawServerFontLayout( const ServerFontLayout& rLayout ) +{ + // print complex text + DrawPrinterLayout( rLayout, *m_pPrinterGfx, true ); +} + +const ImplFontCharMap* PspGraphics::GetImplFontCharMap() const +{ + if( !m_pServerFont[0] ) + return NULL; + + const ImplFontCharMap* pIFCMap = m_pServerFont[0]->GetImplFontCharMap(); + return pIFCMap; +} + +bool PspGraphics::GetImplFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const +{ + if (!m_pServerFont[0]) + return false; + return m_pServerFont[0]->GetFontCapabilities(rFontCapabilities); +} + +sal_uInt16 PspGraphics::SetFont( ImplFontSelectData *pEntry, int nFallbackLevel ) +{ + // release all fonts that are to be overridden + for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i ) + { + if( m_pServerFont[i] != NULL ) + { + // old server side font is no longer referenced + GlyphCache::GetInstance().UncacheFont( *m_pServerFont[i] ); + m_pServerFont[i] = NULL; + } + } + + // return early if there is no new font + if( !pEntry ) + return 0; + + sal_IntPtr nID = pEntry->mpFontData ? pEntry->mpFontData->GetFontId() : 0; + + // determine which font attributes need to be emulated + bool bArtItalic = false; + bool bArtBold = false; + if( pEntry->meItalic == ITALIC_OBLIQUE || pEntry->meItalic == ITALIC_NORMAL ) + { + FontItalic eItalic = m_pPrinterGfx->GetFontMgr().getFontItalic( nID ); + if( eItalic != ITALIC_NORMAL && eItalic != ITALIC_OBLIQUE ) + bArtItalic = true; + } + int nWeight = (int)pEntry->meWeight; + int nRealWeight = (int)m_pPrinterGfx->GetFontMgr().getFontWeight( nID ); + if( nRealWeight <= (int)WEIGHT_MEDIUM && nWeight > (int)WEIGHT_MEDIUM ) + { + bArtBold = true; + } + + // also set the serverside font for layouting + m_bFontVertical = pEntry->mbVertical; + if( pEntry->mpFontData ) + { + // requesting a font provided by builtin rasterizer + ServerFont* pServerFont = GlyphCache::GetInstance().CacheFont( *pEntry ); + if( pServerFont != NULL ) + { + if( pServerFont->TestFont() ) + m_pServerFont[ nFallbackLevel ] = pServerFont; + else + GlyphCache::GetInstance().UncacheFont( *pServerFont ); + } + } + + // set the printer font + return m_pPrinterGfx->SetFont( nID, + pEntry->mnHeight, + pEntry->mnWidth, + pEntry->mnOrientation, + pEntry->mbVertical, + bArtItalic, + bArtBold + ); +} + +void PspGraphics::SetTextColor( SalColor nSalColor ) +{ + psp::PrinterColor aColor (SALCOLOR_RED (nSalColor), + SALCOLOR_GREEN (nSalColor), + SALCOLOR_BLUE (nSalColor)); + m_pPrinterGfx->SetTextColor (aColor); +} + +bool PspGraphics::AddTempDevFont( ImplDevFontList*, const String&, const String& ) +{ + return false; +} + +void PspGraphics::GetDevFontList( ImplDevFontList *pList ) +{ + ::std::list< psp::fontID > aList; + psp::PrintFontManager& rMgr = psp::PrintFontManager::get(); + rMgr.getFontList( aList, m_pJobData->m_pParser, m_pInfoPrinter->m_bCompatMetrics ); + + ::std::list< psp::fontID >::iterator it; + psp::FastPrintFontInfo aInfo; + for (it = aList.begin(); it != aList.end(); ++it) + if (rMgr.getFontFastInfo (*it, aInfo)) + AnnounceFonts( pList, aInfo ); +} + +void PspGraphics::GetDevFontSubstList( OutputDevice* pOutDev ) +{ + const psp::PrinterInfo& rInfo = psp::PrinterInfoManager::get().getPrinterInfo( m_pJobData->m_aPrinterName ); + if( rInfo.m_bPerformFontSubstitution ) + { + for( boost::unordered_map< rtl::OUString, rtl::OUString, rtl::OUStringHash >::const_iterator it = rInfo.m_aFontSubstitutes.begin(); it != rInfo.m_aFontSubstitutes.end(); ++it ) + AddDevFontSubstitute( pOutDev, it->first, it->second, FONT_SUBSTITUTE_ALWAYS ); + } +} + +void PspGraphics::GetFontMetric( ImplFontMetricData *pMetric, int ) +{ + const psp::PrintFontManager& rMgr = psp::PrintFontManager::get(); + psp::PrintFontInfo aInfo; + + if (rMgr.getFontInfo (m_pPrinterGfx->GetFontID(), aInfo)) + { + ImplDevFontAttributes aDFA = Info2DevFontAttributes( aInfo ); + static_cast<ImplFontAttributes&>(*pMetric) = aDFA; + pMetric->mbDevice = aDFA.mbDevice; + pMetric->mbScalableFont = true; + + pMetric->mnOrientation = m_pPrinterGfx->GetFontAngle(); + pMetric->mnSlant = 0; + + sal_Int32 nTextHeight = m_pPrinterGfx->GetFontHeight(); + sal_Int32 nTextWidth = m_pPrinterGfx->GetFontWidth(); + if( ! nTextWidth ) + nTextWidth = nTextHeight; + + pMetric->mnWidth = nTextWidth; + pMetric->mnAscent = ( aInfo.m_nAscend * nTextHeight + 500 ) / 1000; + pMetric->mnDescent = ( aInfo.m_nDescend * nTextHeight + 500 ) / 1000; + pMetric->mnIntLeading = ( aInfo.m_nLeading * nTextHeight + 500 ) / 1000; + pMetric->mnExtLeading = 0; + } +} + +sal_uLong PspGraphics::GetKernPairs( sal_uLong nPairs, ImplKernPairData *pKernPairs ) +{ + const ::std::list< ::psp::KernPair >& rPairs( m_pPrinterGfx->getKernPairs() ); + sal_uLong nHavePairs = rPairs.size(); + if( pKernPairs && nPairs ) + { + ::std::list< ::psp::KernPair >::const_iterator it; + unsigned int i; + int nTextScale = m_pPrinterGfx->GetFontWidth(); + if( ! nTextScale ) + nTextScale = m_pPrinterGfx->GetFontHeight(); + for( i = 0, it = rPairs.begin(); i < nPairs && i < nHavePairs; i++, ++it ) + { + pKernPairs[i].mnChar1 = it->first; + pKernPairs[i].mnChar2 = it->second; + pKernPairs[i].mnKern = it->kern_x * nTextScale / 1000; + } + + } + return nHavePairs; +} + +sal_Bool PspGraphics::GetGlyphBoundRect( sal_GlyphId nGlyphIndex, Rectangle& rRect ) +{ + int nLevel = nGlyphIndex >> GF_FONTSHIFT; + if( nLevel >= MAX_FALLBACK ) + return sal_False; + + ServerFont* pSF = m_pServerFont[ nLevel ]; + if( !pSF ) + return sal_False; + + nGlyphIndex &= GF_IDXMASK; + const GlyphMetric& rGM = pSF->GetGlyphMetric( nGlyphIndex ); + rRect = Rectangle( rGM.GetOffset(), rGM.GetSize() ); + return sal_True; +} + +sal_Bool PspGraphics::GetGlyphOutline( sal_GlyphId nGlyphIndex, + ::basegfx::B2DPolyPolygon& rB2DPolyPoly ) +{ + int nLevel = nGlyphIndex >> GF_FONTSHIFT; + if( nLevel >= MAX_FALLBACK ) + return sal_False; + + ServerFont* pSF = m_pServerFont[ nLevel ]; + if( !pSF ) + return sal_False; + + nGlyphIndex &= GF_IDXMASK; + if( pSF->GetGlyphOutline( nGlyphIndex, rB2DPolyPoly ) ) + return sal_True; + + return sal_False; +} + +SalLayout* PspGraphics::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLevel ) +{ + // workaround for printers not handling glyph indexing for non-TT fonts + int nFontId = m_pPrinterGfx->GetFontID(); + if( psp::fonttype::TrueType != psp::PrintFontManager::get().getFontType( nFontId ) ) + rArgs.mnFlags |= SAL_LAYOUT_DISABLE_GLYPH_PROCESSING; + else if( nFallbackLevel > 0 ) + rArgs.mnFlags &= ~SAL_LAYOUT_DISABLE_GLYPH_PROCESSING; + + GenericSalLayout* pLayout = NULL; + + if( m_pServerFont[ nFallbackLevel ] + && !(rArgs.mnFlags & SAL_LAYOUT_DISABLE_GLYPH_PROCESSING) ) + pLayout = new PspServerFontLayout( *m_pPrinterGfx, *m_pServerFont[nFallbackLevel], rArgs ); + else + pLayout = new PspFontLayout( *m_pPrinterGfx ); + + return pLayout; +} + +//-------------------------------------------------------------------------- + +sal_Bool PspGraphics::CreateFontSubset( + const rtl::OUString& rToFile, + const ImplFontData* pFont, + sal_Int32* pGlyphIDs, + sal_uInt8* pEncoding, + sal_Int32* pWidths, + int nGlyphCount, + FontSubsetInfo& rInfo + ) +{ + // in this context the pFont->GetFontId() is a valid PSP + // font since they are the only ones left after the PDF + // export has filtered its list of subsettable fonts (for + // which this method was created). The correct way would + // be to have the GlyphCache search for the ImplFontData pFont + psp::fontID aFont = pFont->GetFontId(); + + psp::PrintFontManager& rMgr = psp::PrintFontManager::get(); + bool bSuccess = rMgr.createFontSubset( rInfo, + aFont, + rToFile, + pGlyphIDs, + pEncoding, + pWidths, + nGlyphCount ); + return bSuccess; +} + +//-------------------------------------------------------------------------- + +const void* PspGraphics::GetEmbedFontData( const ImplFontData* pFont, const sal_Ucs* pUnicodes, sal_Int32* pWidths, FontSubsetInfo& rInfo, long* pDataLen ) +{ + // in this context the pFont->GetFontId() is a valid PSP + // font since they are the only ones left after the PDF + // export has filtered its list of subsettable fonts (for + // which this method was created). The correct way would + // be to have the GlyphCache search for the ImplFontData pFont + psp::fontID aFont = pFont->GetFontId(); + return PspGraphics::DoGetEmbedFontData( aFont, pUnicodes, pWidths, rInfo, pDataLen ); +} + +//-------------------------------------------------------------------------- + +void PspGraphics::FreeEmbedFontData( const void* pData, long nLen ) +{ + PspGraphics::DoFreeEmbedFontData( pData, nLen ); +} + +//-------------------------------------------------------------------------- + +const Ucs2SIntMap* PspGraphics::GetFontEncodingVector( const ImplFontData* pFont, const Ucs2OStrMap** pNonEncoded ) +{ + // in this context the pFont->GetFontId() is a valid PSP + // font since they are the only ones left after the PDF + // export has filtered its list of subsettable fonts (for + // which this method was created). The correct way would + // be to have the GlyphCache search for the ImplFontData pFont + psp::fontID aFont = pFont->GetFontId(); + return PspGraphics::DoGetFontEncodingVector( aFont, pNonEncoded ); +} + +//-------------------------------------------------------------------------- + +void PspGraphics::GetGlyphWidths( const ImplFontData* pFont, + bool bVertical, + Int32Vector& rWidths, + Ucs2UIntMap& rUnicodeEnc ) +{ + // in this context the pFont->GetFontId() is a valid PSP + // font since they are the only ones left after the PDF + // export has filtered its list of subsettable fonts (for + // which this method was created). The correct way would + // be to have the GlyphCache search for the ImplFontData pFont + psp::fontID aFont = pFont->GetFontId(); + PspGraphics::DoGetGlyphWidths( aFont, bVertical, rWidths, rUnicodeEnc ); +} + +// static helpers of PspGraphics + +const void* PspGraphics::DoGetEmbedFontData( fontID aFont, const sal_Ucs* pUnicodes, sal_Int32* pWidths, FontSubsetInfo& rInfo, long* pDataLen ) +{ + psp::PrintFontManager& rMgr = psp::PrintFontManager::get(); + + psp::PrintFontInfo aFontInfo; + if( ! rMgr.getFontInfo( aFont, aFontInfo ) ) + return NULL; + + // fill in font info + rInfo.m_nAscent = aFontInfo.m_nAscend; + rInfo.m_nDescent = aFontInfo.m_nDescend; + rInfo.m_aPSName = rMgr.getPSName( aFont ); + + int xMin, yMin, xMax, yMax; + rMgr.getFontBoundingBox( aFont, xMin, yMin, xMax, yMax ); + + psp::CharacterMetric aMetrics[256]; + sal_Ucs aUnicodes[256]; + if( aFontInfo.m_aEncoding == RTL_TEXTENCODING_SYMBOL && aFontInfo.m_eType == psp::fonttype::Type1 ) + { + for( int i = 0; i < 256; i++ ) + aUnicodes[i] = pUnicodes[i] < 0x0100 ? pUnicodes[i] + 0xf000 : pUnicodes[i]; + pUnicodes = aUnicodes; + } + if( ! rMgr.getMetrics( aFont, pUnicodes, 256, aMetrics ) ) + return NULL; + + OString aSysPath = rMgr.getFontFileSysPath( aFont ); + struct stat aStat; + if( stat( aSysPath.getStr(), &aStat ) ) + return NULL; + int fd = open( aSysPath.getStr(), O_RDONLY ); + if( fd < 0 ) + return NULL; + void* pFile = mmap( NULL, aStat.st_size, PROT_READ, MAP_SHARED, fd, 0 ); + close( fd ); + if( pFile == MAP_FAILED ) + return NULL; + + *pDataLen = aStat.st_size; + + rInfo.m_aFontBBox = Rectangle( Point( xMin, yMin ), Size( xMax-xMin, yMax-yMin ) ); + rInfo.m_nCapHeight = yMax; // Well ... + + for( int i = 0; i < 256; i++ ) + pWidths[i] = (aMetrics[i].width > 0 ? aMetrics[i].width : 0); + + switch( aFontInfo.m_eType ) + { + case psp::fonttype::TrueType: + rInfo.m_nFontType = FontSubsetInfo::SFNT_TTF; + break; + case psp::fonttype::Type1: { + const bool bPFA = ((*(unsigned char*)pFile) < 0x80); + rInfo.m_nFontType = bPFA ? FontSubsetInfo::TYPE1_PFA : FontSubsetInfo::TYPE1_PFB; + } + break; + default: + return NULL; + } + + return pFile; +} + +void PspGraphics::DoFreeEmbedFontData( const void* pData, long nLen ) +{ + if( pData ) + munmap( (char*)pData, nLen ); +} + +const Ucs2SIntMap* PspGraphics::DoGetFontEncodingVector( fontID aFont, const Ucs2OStrMap** pNonEncoded ) +{ + psp::PrintFontManager& rMgr = psp::PrintFontManager::get(); + + psp::PrintFontInfo aFontInfo; + if( ! rMgr.getFontInfo( aFont, aFontInfo ) ) + { + if( pNonEncoded ) + *pNonEncoded = NULL; + return NULL; + } + + return rMgr.getEncodingMap( aFont, pNonEncoded ); +} + +void PspGraphics::DoGetGlyphWidths( psp::fontID aFont, + bool bVertical, + Int32Vector& rWidths, + Ucs2UIntMap& rUnicodeEnc ) +{ + psp::PrintFontManager& rMgr = psp::PrintFontManager::get(); + rMgr.getGlyphWidths( aFont, bVertical, rWidths, rUnicodeEnc ); +} + +// ---------------------------------------------------------------------------- + +ImplDevFontAttributes PspGraphics::Info2DevFontAttributes( const psp::FastPrintFontInfo& rInfo ) +{ + ImplDevFontAttributes aDFA; + aDFA.maName = rInfo.m_aFamilyName; + aDFA.maStyleName = rInfo.m_aStyleName; + aDFA.meFamily = rInfo.m_eFamilyStyle; + aDFA.meWeight = rInfo.m_eWeight; + aDFA.meItalic = rInfo.m_eItalic; + aDFA.meWidthType = rInfo.m_eWidth; + aDFA.mePitch = rInfo.m_ePitch; + aDFA.mbSymbolFlag = (rInfo.m_aEncoding == RTL_TEXTENCODING_SYMBOL); + + switch( rInfo.m_eType ) + { + case psp::fonttype::Builtin: + aDFA.mnQuality = 1024; + aDFA.mbDevice = true; + aDFA.mbSubsettable = false; + aDFA.mbEmbeddable = false; + break; + case psp::fonttype::TrueType: + aDFA.mnQuality = 512; + aDFA.mbDevice = false; + aDFA.mbSubsettable = true; + aDFA.mbEmbeddable = false; + break; + case psp::fonttype::Type1: + aDFA.mnQuality = 0; + aDFA.mbDevice = false; + aDFA.mbSubsettable = false; + aDFA.mbEmbeddable = true; + break; + default: + aDFA.mnQuality = 0; + aDFA.mbDevice = false; + aDFA.mbSubsettable = false; + aDFA.mbEmbeddable = false; + break; + } + + aDFA.mbOrientation = true; + + // add font family name aliases + ::std::list< OUString >::const_iterator it = rInfo.m_aAliases.begin(); + bool bHasMapNames = false; + for(; it != rInfo.m_aAliases.end(); ++it ) + { + if( bHasMapNames ) + aDFA.maMapNames.Append( ';' ); + aDFA.maMapNames.Append( (*it).getStr() ); + bHasMapNames = true; + } + +#if OSL_DEBUG_LEVEL > 2 + if( bHasMapNames ) + { + rtl::OString aOrigName(rtl::OUStringToOString(aDFA.maName, + osl_getThreadTextEncoding())); + rtl::OString aAliasNames(rtl::OUStringToOString(aDFA.maMapNames, + osl_getThreadTextEncoding())); + fprintf( stderr, "using alias names \"%s\" for font family \"%s\"\n", + aAliasNames.getStr(), aOrigName.getStr() ); + } +#endif + + return aDFA; +} + +// ----------------------------------------------------------------------- + +void PspGraphics::AnnounceFonts( ImplDevFontList* pFontList, const psp::FastPrintFontInfo& aInfo ) +{ + int nQuality = 0; + + if( aInfo.m_eType == psp::fonttype::TrueType ) + { + // asian type 1 fonts are not known + psp::PrintFontManager& rMgr = psp::PrintFontManager::get(); + ByteString aFileName( rMgr.getFontFileSysPath( aInfo.m_nID ) ); + int nPos = aFileName.SearchBackward( '_' ); + if( nPos == STRING_NOTFOUND || aFileName.GetChar( nPos+1 ) == '.' ) + nQuality += 5; + else + { + static const char* pLangBoost = NULL; + static bool bOnce = true; + if( bOnce ) + { + bOnce = false; + const LanguageType aLang = Application::GetSettings().GetUILanguage(); + switch( aLang ) + { + case LANGUAGE_JAPANESE: + pLangBoost = "jan"; + break; + case LANGUAGE_CHINESE: + case LANGUAGE_CHINESE_SIMPLIFIED: + case LANGUAGE_CHINESE_SINGAPORE: + pLangBoost = "zhs"; + break; + case LANGUAGE_CHINESE_TRADITIONAL: + case LANGUAGE_CHINESE_HONGKONG: + case LANGUAGE_CHINESE_MACAU: + pLangBoost = "zht"; + break; + case LANGUAGE_KOREAN: + case LANGUAGE_KOREAN_JOHAB: + pLangBoost = "kor"; + break; + } + } + + if( pLangBoost ) + if( aFileName.Copy( nPos+1, 3 ).EqualsIgnoreCaseAscii( pLangBoost ) ) + nQuality += 10; + } + } + + ImplPspFontData* pFD = new ImplPspFontData( aInfo ); + pFD->mnQuality += nQuality; + pFontList->Add( pFD ); +} + +bool PspGraphics::filterText( const String& rOrig, String& rNewText, xub_StrLen nIndex, xub_StrLen& rLen, xub_StrLen& rCutStart, xub_StrLen& rCutStop ) +{ + if( ! m_pPhoneNr ) + return false; + + rCutStop = rCutStart = STRING_NOTFOUND; + +#define FAX_PHONE_TOKEN "@@#" +#define FAX_PHONE_TOKEN_LENGTH 3 +#define FAX_END_TOKEN "@@" +#define FAX_END_TOKEN_LENGTH 2 + + bool bRet = false; + bool bStarted = false; + bool bStopped = false; + sal_uInt16 nPos; + sal_uInt16 nStart = 0; + sal_uInt16 nStop = rLen; + String aPhone = rOrig.Copy( nIndex, rLen ); + + if( ! m_bPhoneCollectionActive ) + { + if( ( nPos = aPhone.SearchAscii( FAX_PHONE_TOKEN ) ) != STRING_NOTFOUND ) + { + nStart = nPos; + m_bPhoneCollectionActive = true; + m_aPhoneCollection.Erase(); + bRet = true; + bStarted = true; + } + } + if( m_bPhoneCollectionActive ) + { + bRet = true; + nPos = bStarted ? nStart + FAX_PHONE_TOKEN_LENGTH : 0; + if( ( nPos = aPhone.SearchAscii( FAX_END_TOKEN, nPos ) ) != STRING_NOTFOUND ) + { + m_bPhoneCollectionActive = false; + nStop = nPos + FAX_END_TOKEN_LENGTH; + bStopped = true; + } + int nTokenStart = nStart + (bStarted ? FAX_PHONE_TOKEN_LENGTH : 0); + int nTokenStop = nStop - (bStopped ? FAX_END_TOKEN_LENGTH : 0); + m_aPhoneCollection += aPhone.Copy( nTokenStart, nTokenStop - nTokenStart ); + if( ! m_bPhoneCollectionActive ) + { + m_pPhoneNr->AppendAscii( "<Fax#>" ); + m_pPhoneNr->Append( m_aPhoneCollection ); + m_pPhoneNr->AppendAscii( "</Fax#>" ); + m_aPhoneCollection.Erase(); + } + } + if( m_aPhoneCollection.Len() > 1024 ) + { + m_bPhoneCollectionActive = false; + m_aPhoneCollection.Erase(); + bRet = false; + } + + if( bRet && m_bSwallowFaxNo ) + { + rLen -= nStop - nStart; + rCutStart = nStart+nIndex; + rCutStop = nStop+nIndex; + if( rCutStart ) + rNewText = rOrig.Copy( 0, rCutStart ); + rNewText += rOrig.Copy( rCutStop ); + } + + return bRet && m_bSwallowFaxNo; +} + +SystemFontData PspGraphics::GetSysFontData( int nFallbacklevel ) const +{ + SystemFontData aSysFontData; + + if (nFallbacklevel >= MAX_FALLBACK) nFallbacklevel = MAX_FALLBACK - 1; + if (nFallbacklevel < 0 ) nFallbacklevel = 0; + + aSysFontData.nSize = sizeof( SystemFontData ); + aSysFontData.nFontId = 0; + aSysFontData.nFontFlags = 0; + aSysFontData.bFakeBold = false; + aSysFontData.bFakeItalic = false; + aSysFontData.bAntialias = true; + return aSysFontData; +} + +SystemGraphicsData PspGraphics::GetGraphicsData() const +{ + SystemGraphicsData aRes; + aRes.nSize = sizeof(aRes); + aRes.hDrawable = 0; + aRes.pXRenderFormat = 0; + return aRes; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/headless/svptext.cxx b/vcl/headless/svptext.cxx new file mode 100644 index 000000000000..64367063fa9b --- /dev/null +++ b/vcl/headless/svptext.cxx @@ -0,0 +1,544 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <basegfx/range/b2drange.hxx> +#include <basegfx/range/b2irange.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> + +#include <basebmp/scanlineformats.hxx> + +#include <tools/debug.hxx> + +#if OSL_DEBUG_LEVEL > 2 +#include <basebmp/debug.hxx> +#endif + +#include <outfont.hxx> +#include <impfont.hxx> +#include <rtl/instance.hxx> + +#include "generic/glyphcache.hxx" +#include "headless/svpgdi.hxx" +#include "headless/svpbmp.hxx" +#include "headless/svppspgraphics.hxx" + +using namespace basegfx; +using namespace basebmp; + +// =========================================================================== + +class SvpGlyphPeer +: public GlyphCachePeer +{ +public: + SvpGlyphPeer() {} + + BitmapDeviceSharedPtr GetGlyphBmp( ServerFont&, int nGlyphIndex, + sal_uInt32 nBmpFormat, B2IPoint& rTargetPos ); + +protected: + virtual void RemovingFont( ServerFont& ); + virtual void RemovingGlyph( ServerFont&, GlyphData&, int nGlyphIndex ); + + class SvpGcpHelper + { + public: + RawBitmap maRawBitmap; + BitmapDeviceSharedPtr maBitmapDev; + }; +}; + +// =========================================================================== + +class SvpGlyphCache : public GlyphCache +{ +public: + SvpGlyphCache( SvpGlyphPeer& rPeer ) : GlyphCache( rPeer) {} + SvpGlyphPeer& GetPeer() { return reinterpret_cast<SvpGlyphPeer&>( mrPeer ); } + static SvpGlyphCache& GetInstance(); +}; + +namespace +{ + struct GlyphCacheHolder + { + private: + SvpGlyphPeer* m_pSvpGlyphPeer; + SvpGlyphCache* m_pSvpGlyphCache; + public: + GlyphCacheHolder() + { + m_pSvpGlyphPeer = new SvpGlyphPeer(); + m_pSvpGlyphCache = new SvpGlyphCache( *m_pSvpGlyphPeer ); + } + void release() + { + delete m_pSvpGlyphCache; + delete m_pSvpGlyphPeer; + m_pSvpGlyphCache = NULL; + m_pSvpGlyphPeer = NULL; + } + SvpGlyphCache& getGlyphCache() + { + return *m_pSvpGlyphCache; + } + ~GlyphCacheHolder() + { + release(); + } + }; + + struct theGlyphCacheHolder : + public rtl::Static<GlyphCacheHolder, theGlyphCacheHolder> + {}; +} + +SvpGlyphCache& SvpGlyphCache::GetInstance() +{ + return theGlyphCacheHolder::get().getGlyphCache(); +} + +// =========================================================================== + +BitmapDeviceSharedPtr SvpGlyphPeer::GetGlyphBmp( ServerFont& rServerFont, + int nGlyphIndex, sal_uInt32 nBmpFormat, B2IPoint& rTargetPos ) +{ + GlyphData& rGlyphData = rServerFont.GetGlyphData( nGlyphIndex ); + SvpGcpHelper* pGcpHelper = (SvpGcpHelper*)rGlyphData.ExtDataRef().mpData; + + // nothing to do if the GlyphPeer hasn't allocated resources for the glyph + if( rGlyphData.ExtDataRef().meInfo != sal::static_int_cast<int>(nBmpFormat) ) + { + if( rGlyphData.ExtDataRef().meInfo == Format::NONE ) + pGcpHelper = new SvpGcpHelper; + RawBitmap& rRawBitmap = pGcpHelper->maRawBitmap; + + // get glyph bitmap in matching format + bool bFound = false; + switch( nBmpFormat ) + { + case Format::ONE_BIT_LSB_GREY: + bFound = rServerFont.GetGlyphBitmap1( nGlyphIndex, pGcpHelper->maRawBitmap ); + break; + case Format::EIGHT_BIT_GREY: + bFound = rServerFont.GetGlyphBitmap8( nGlyphIndex, pGcpHelper->maRawBitmap ); + break; + default: + OSL_FAIL( "SVP GCP::GetGlyphBmp(): illegal scanline format"); + // fall back to black&white mask + nBmpFormat = Format::ONE_BIT_LSB_GREY; + bFound = false; + break; + } + + // return .notdef glyph if needed + if( !bFound && (nGlyphIndex != 0) ) + { + delete pGcpHelper; + return GetGlyphBmp( rServerFont, 0, nBmpFormat, rTargetPos ); + } + + // construct alpha mask from raw bitmap + const B2IVector aSize( rRawBitmap.mnScanlineSize, rRawBitmap.mnHeight ); + if( aSize.getX() && aSize.getY() ) + { + static PaletteMemorySharedVector aDummyPAL; + RawMemorySharedArray aRawPtr( rRawBitmap.mpBits ); + pGcpHelper->maBitmapDev = createBitmapDevice( aSize, true, nBmpFormat, aRawPtr, aDummyPAL ); + } + + rServerFont.SetExtended( nBmpFormat, (void*)pGcpHelper ); + } + + rTargetPos += B2IPoint( pGcpHelper->maRawBitmap.mnXOffset, pGcpHelper->maRawBitmap.mnYOffset ); + return pGcpHelper->maBitmapDev; +} + +//-------------------------------------------------------------------------- + +void SvpGlyphPeer::RemovingFont( ServerFont& ) +{ + // nothing to do: no font resources held in SvpGlyphPeer +} + +//-------------------------------------------------------------------------- + +void SvpGlyphPeer::RemovingGlyph( ServerFont&, GlyphData& rGlyphData, int /*nGlyphIndex*/ ) +{ + if( rGlyphData.ExtDataRef().mpData != Format::NONE ) + { + // release the glyph related resources + DBG_ASSERT( (rGlyphData.ExtDataRef().meInfo <= Format::MAX), "SVP::RG() invalid alpha format" ); + SvpGcpHelper* pGcpHelper = (SvpGcpHelper*)rGlyphData.ExtDataRef().mpData; + delete[] pGcpHelper->maRawBitmap.mpBits; + delete pGcpHelper; + } +} + +// =========================================================================== + +// PspKernInfo allows on-demand-querying of psprint provided kerning info (#i29881#) +class PspKernInfo : public ExtraKernInfo +{ +public: + PspKernInfo( int nFontId ) : ExtraKernInfo(nFontId) {} +protected: + virtual void Initialize() const; +}; + +//-------------------------------------------------------------------------- + +void PspKernInfo::Initialize() const +{ + mbInitialized = true; + + // get the kerning pairs from psprint + const psp::PrintFontManager& rMgr = psp::PrintFontManager::get(); + typedef std::list< psp::KernPair > PspKernPairs; + const PspKernPairs& rKernPairs = rMgr.getKernPairs( mnFontId ); + if( rKernPairs.empty() ) + return; + + PspKernPairs::const_iterator it = rKernPairs.begin(); + for(; it != rKernPairs.end(); ++it ) + { + ImplKernPairData aKernPair = { it->first, it->second, it->kern_x }; + maUnicodeKernPairs.insert( aKernPair ); + } +} + +// =========================================================================== + +sal_uInt16 SvpSalGraphics::SetFont( ImplFontSelectData* pIFSD, int nFallbackLevel ) +{ + // release all no longer needed font resources + for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i ) + { + if( m_pServerFont[i] != NULL ) + { + // old server side font is no longer referenced + SvpGlyphCache::GetInstance().UncacheFont( *m_pServerFont[i] ); + m_pServerFont[i] = NULL; + } + } + + // return early if there is no new font + if( !pIFSD ) + return 0; + + // handle the request for a non-native X11-font => use the GlyphCache + ServerFont* pServerFont = SvpGlyphCache::GetInstance().CacheFont( *pIFSD ); + if( !pServerFont ) + return SAL_SETFONT_BADFONT; + + // check selected font + if( !pServerFont->TestFont() ) + { + SvpGlyphCache::GetInstance().UncacheFont( *pServerFont ); + return SAL_SETFONT_BADFONT; + } + + // update SalGraphics font settings + m_pServerFont[ nFallbackLevel ] = pServerFont; + return SAL_SETFONT_USEDRAWTEXTARRAY; +} + +// --------------------------------------------------------------------------- + +void SvpSalGraphics::GetFontMetric( ImplFontMetricData* pMetric, int nFallbackLevel ) +{ + if( nFallbackLevel >= MAX_FALLBACK ) + return; + + if( m_pServerFont[nFallbackLevel] != NULL ) + { + long rDummyFactor; + m_pServerFont[nFallbackLevel]->FetchFontMetric( *pMetric, rDummyFactor ); + } +} + +// --------------------------------------------------------------------------- + +sal_uLong SvpSalGraphics::GetKernPairs( sal_uLong nPairs, ImplKernPairData* pKernPairs ) +{ + sal_uLong nGotPairs = 0; + + if( m_pServerFont[0] != NULL ) + { + ImplKernPairData* pTmpKernPairs = NULL; + nGotPairs = m_pServerFont[0]->GetKernPairs( &pTmpKernPairs ); + for( sal_uLong i = 0; i < nPairs && i < nGotPairs; ++i ) + pKernPairs[ i ] = pTmpKernPairs[ i ]; + delete[] pTmpKernPairs; + } + + return nGotPairs; +} + +// --------------------------------------------------------------------------- + +const ImplFontCharMap* SvpSalGraphics::GetImplFontCharMap() const +{ + if( !m_pServerFont[0] ) + return NULL; + + const ImplFontCharMap* pIFCMap = m_pServerFont[0]->GetImplFontCharMap(); + return pIFCMap; +} + +bool SvpSalGraphics::GetImplFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const +{ + if (!m_pServerFont[0]) + return false; + + return m_pServerFont[0]->GetFontCapabilities(rFontCapabilities); +} + +// --------------------------------------------------------------------------- + +void SvpSalGraphics::GetDevFontList( ImplDevFontList* pDevFontList ) +{ + GlyphCache& rGC = SvpGlyphCache::GetInstance(); + + psp::PrintFontManager& rMgr = psp::PrintFontManager::get(); + psp::FastPrintFontInfo aInfo; + ::std::list< psp::fontID > aList; + rMgr.getFontList( aList ); + ::std::list< psp::fontID >::iterator it; + for( it = aList.begin(); it != aList.end(); ++it ) + { + if( !rMgr.getFontFastInfo( *it, aInfo ) ) + continue; + + // the GlyphCache must not bother with builtin fonts because + // it cannot access or use them anyway + if( aInfo.m_eType == psp::fonttype::Builtin ) + continue; + + // normalize face number to the GlyphCache + int nFaceNum = rMgr.getFontFaceNumber( aInfo.m_nID ); + if( nFaceNum < 0 ) + nFaceNum = 0; + + // for fonts where extra kerning info can be provided on demand + // an ExtraKernInfo object is supplied + const ExtraKernInfo* pExtraKernInfo = NULL; + if( aInfo.m_eType == psp::fonttype::Type1 ) + pExtraKernInfo = new PspKernInfo( *it ); + + // inform GlyphCache about this font provided by the PsPrint subsystem + ImplDevFontAttributes aDFA = PspGraphics::Info2DevFontAttributes( aInfo ); + aDFA.mnQuality += 4096; + const rtl::OString& rFileName = rMgr.getFontFileSysPath( aInfo.m_nID ); + rGC.AddFontFile( rFileName, nFaceNum, aInfo.m_nID, aDFA, pExtraKernInfo ); + } + + // announce glyphcache fonts + rGC.AnnounceFonts( pDevFontList ); +} + +// --------------------------------------------------------------------------- + +void SvpSalGraphics::GetDevFontSubstList( OutputDevice* ) +{} + +// --------------------------------------------------------------------------- + +bool SvpSalGraphics::AddTempDevFont( ImplDevFontList*, + const String&, const String& ) +{ + return false; +} + +// --------------------------------------------------------------------------- + +sal_Bool SvpSalGraphics::CreateFontSubset( + const rtl::OUString& rToFile, + const ImplFontData* pFont, + sal_Int32* pGlyphIDs, + sal_uInt8* pEncoding, + sal_Int32* pWidths, + int nGlyphCount, + FontSubsetInfo& rInfo + ) +{ + // in this context the pFont->GetFontId() is a valid PSP + // font since they are the only ones left after the PDF + // export has filtered its list of subsettable fonts (for + // which this method was created). The correct way would + // be to have the GlyphCache search for the ImplFontData pFont + psp::fontID aFont = pFont->GetFontId(); + + psp::PrintFontManager& rMgr = psp::PrintFontManager::get(); + bool bSuccess = rMgr.createFontSubset( rInfo, + aFont, + rToFile, + pGlyphIDs, + pEncoding, + pWidths, + nGlyphCount ); + return bSuccess; +} + +// --------------------------------------------------------------------------- + +const Ucs2SIntMap* SvpSalGraphics::GetFontEncodingVector( const ImplFontData* pFont, const Ucs2OStrMap** pNonEncoded ) +{ + // in this context the pFont->GetFontId() is a valid PSP + // font since they are the only ones left after the PDF + // export has filtered its list of subsettable fonts (for + // which this method was created). The correct way would + // be to have the GlyphCache search for the ImplFontData pFont + psp::fontID aFont = pFont->GetFontId(); + return PspGraphics::DoGetFontEncodingVector( aFont, pNonEncoded ); +} + +// --------------------------------------------------------------------------- + +const void* SvpSalGraphics::GetEmbedFontData( + const ImplFontData* pFont, + const sal_Ucs* pUnicodes, + sal_Int32* pWidths, + FontSubsetInfo& rInfo, + long* pDataLen + ) +{ + // in this context the pFont->GetFontId() is a valid PSP + // font since they are the only ones left after the PDF + // export has filtered its list of subsettable fonts (for + // which this method was created). The correct way would + // be to have the GlyphCache search for the ImplFontData pFont + psp::fontID aFont = pFont->GetFontId(); + return PspGraphics::DoGetEmbedFontData( aFont, pUnicodes, pWidths, rInfo, pDataLen ); +} + +// --------------------------------------------------------------------------- + +void SvpSalGraphics::FreeEmbedFontData( const void* pData, long nLen ) +{ + PspGraphics::DoFreeEmbedFontData( pData, nLen ); +} + +void SvpSalGraphics::GetGlyphWidths( const ImplFontData* pFont, + bool bVertical, + Int32Vector& rWidths, + Ucs2UIntMap& rUnicodeEnc ) +{ + // in this context the pFont->GetFontId() is a valid PSP + // font since they are the only ones left after the PDF + // export has filtered its list of subsettable fonts (for + // which this method was created). The correct way would + // be to have the GlyphCache search for the ImplFontData pFont + psp::fontID aFont = pFont->GetFontId(); + PspGraphics::DoGetGlyphWidths( aFont, bVertical, rWidths, rUnicodeEnc ); +} + +// --------------------------------------------------------------------------- + +sal_Bool SvpSalGraphics::GetGlyphBoundRect( sal_GlyphId nGlyphIndex, Rectangle& rRect ) +{ + int nLevel = nGlyphIndex >> GF_FONTSHIFT; + if( nLevel >= MAX_FALLBACK ) + return sal_False; + + ServerFont* pSF = m_pServerFont[ nLevel ]; + if( !pSF ) + return sal_False; + + nGlyphIndex &= GF_IDXMASK; + const GlyphMetric& rGM = pSF->GetGlyphMetric( nGlyphIndex ); + rRect = Rectangle( rGM.GetOffset(), rGM.GetSize() ); + return sal_True; +} + +// --------------------------------------------------------------------------- + +sal_Bool SvpSalGraphics::GetGlyphOutline( sal_GlyphId nGlyphIndex, B2DPolyPolygon& rPolyPoly ) +{ + int nLevel = nGlyphIndex >> GF_FONTSHIFT; + if( nLevel >= MAX_FALLBACK ) + return sal_False; + + const ServerFont* pSF = m_pServerFont[ nLevel ]; + if( !pSF ) + return sal_False; + + nGlyphIndex &= GF_IDXMASK; + if( pSF->GetGlyphOutline( nGlyphIndex, rPolyPoly ) ) + return sal_True; + + return sal_False; +} + +// --------------------------------------------------------------------------- + +SalLayout* SvpSalGraphics::GetTextLayout( ImplLayoutArgs&, int nFallbackLevel ) +{ + GenericSalLayout* pLayout = NULL; + + if( m_pServerFont[ nFallbackLevel ] ) + pLayout = new ServerFontLayout( *m_pServerFont[ nFallbackLevel ] ); + + return pLayout; +} + +// --------------------------------------------------------------------------- + +void SvpSalGraphics::DrawServerFontLayout( const ServerFontLayout& rSalLayout ) +{ + // iterate over all glyphs in the layout + Point aPos; + sal_GlyphId nGlyphIndex; + SvpGlyphPeer& rGlyphPeer = SvpGlyphCache::GetInstance().GetPeer(); + for( int nStart = 0; rSalLayout.GetNextGlyphs( 1, &nGlyphIndex, aPos, nStart ); ) + { + int nLevel = nGlyphIndex >> GF_FONTSHIFT; + DBG_ASSERT( nLevel < MAX_FALLBACK, "SvpGDI: invalid glyph fallback level" ); + ServerFont* pSF = m_pServerFont[ nLevel ]; + if( !pSF ) + continue; + + // get the glyph's alpha mask and adjust the drawing position + nGlyphIndex &= GF_IDXMASK; + B2IPoint aDstPoint( aPos.X(), aPos.Y() ); + BitmapDeviceSharedPtr aAlphaMask + = rGlyphPeer.GetGlyphBmp( *pSF, nGlyphIndex, m_eTextFmt, aDstPoint ); + if( !aAlphaMask ) // ignore empty glyphs + continue; + + // blend text color into target using the glyph's mask + const B2IRange aSrcRect( B2ITuple(0,0), aAlphaMask->getSize() ); + const B2IRange aClipRect( aDstPoint, aAlphaMask->getSize() ); + SvpSalGraphics::ClipUndoHandle aUndo = ensureClipFor( aClipRect ); + m_aDevice->drawMaskedColor( m_aTextColor, aAlphaMask, aSrcRect, aDstPoint, m_aClipMap ); + } +} + +// =========================================================================== + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/headless/svpvd.cxx b/vcl/headless/svpvd.cxx new file mode 100644 index 000000000000..8b90d648d5d5 --- /dev/null +++ b/vcl/headless/svpvd.cxx @@ -0,0 +1,112 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "headless/svpvd.hxx" +#include "headless/svpgdi.hxx" + +#include <basegfx/vector/b2ivector.hxx> +#include <basebmp/scanlineformats.hxx> + +#include "stdio.h" + +using namespace basegfx; +using namespace basebmp; + +SvpSalVirtualDevice::~SvpSalVirtualDevice() +{ +} + +SalGraphics* SvpSalVirtualDevice::GetGraphics() +{ + SvpSalGraphics* pGraphics = new SvpSalGraphics(); + pGraphics->setDevice( m_aDevice ); + m_aGraphics.push_back( pGraphics ); + return pGraphics; +} + +void SvpSalVirtualDevice::ReleaseGraphics( SalGraphics* pGraphics ) +{ + m_aGraphics.remove( dynamic_cast<SvpSalGraphics*>(pGraphics) ); + delete pGraphics; +} + +sal_Bool SvpSalVirtualDevice::SetSize( long nNewDX, long nNewDY ) +{ + B2IVector aDevSize( nNewDX, nNewDY ); + if( aDevSize.getX() == 0 ) + aDevSize.setX( 1 ); + if( aDevSize.getY() == 0 ) + aDevSize.setY( 1 ); + if( ! m_aDevice.get() || m_aDevice->getSize() != aDevSize ) + { + sal_uInt32 nFormat = SVP_DEFAULT_BITMAP_FORMAT; + std::vector< basebmp::Color > aDevPal; + switch( m_nBitCount ) + { + case 1: nFormat = Format::ONE_BIT_MSB_PAL; + aDevPal.reserve(2); + aDevPal.push_back( basebmp::Color( 0, 0, 0 ) ); + aDevPal.push_back( basebmp::Color( 0xff, 0xff, 0xff ) ); + break; + case 4: nFormat = Format::FOUR_BIT_MSB_PAL; break; + case 8: nFormat = Format::EIGHT_BIT_PAL; break; +#ifdef OSL_BIGENDIAN + case 16: nFormat = Format::SIXTEEN_BIT_MSB_TC_MASK; break; +#else + case 16: nFormat = Format::SIXTEEN_BIT_LSB_TC_MASK; break; +#endif + case 0: + case 24: nFormat = Format::TWENTYFOUR_BIT_TC_MASK; break; + case 32: nFormat = Format::THIRTYTWO_BIT_TC_MASK; break; + } + m_aDevice = aDevPal.empty() + ? createBitmapDevice( aDevSize, false, nFormat ) + : createBitmapDevice( aDevSize, false, nFormat, PaletteMemorySharedVector( new std::vector< basebmp::Color >(aDevPal) ) ); + + // update device in existing graphics + for( std::list< SvpSalGraphics* >::iterator it = m_aGraphics.begin(); + it != m_aGraphics.end(); ++it ) + (*it)->setDevice( m_aDevice ); + + } + return true; +} + +void SvpSalVirtualDevice::GetSize( long& rWidth, long& rHeight ) +{ + if( m_aDevice.get() ) + { + B2IVector aDevSize( m_aDevice->getSize() ); + rWidth = aDevSize.getX(); + rHeight = aDevSize.getY(); + } + else + rWidth = rHeight = 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |