e25334e1c1
Change-Id: Ie624f0d57aea4d72c69f6cd73508d129e53721d1 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/94722 Tested-by: Jenkins Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
2864 lines
107 KiB
C++
2864 lines
107 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
* with this work for additional information regarding copyright
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
*/
|
|
|
|
#include <cstdlib>
|
|
#include <memory>
|
|
#include <sal/log.hxx>
|
|
#include <osl/diagnose.h>
|
|
#include <tools/diagnose_ex.h>
|
|
#include <tools/helpers.hxx>
|
|
#include <tools/stream.hxx>
|
|
#include <tools/vcompat.hxx>
|
|
#include <tools/fract.hxx>
|
|
#include <vcl/BitmapPalette.hxx>
|
|
#include <vcl/metaact.hxx>
|
|
#include <vcl/outdev.hxx>
|
|
#include <vcl/window.hxx>
|
|
#include <vcl/virdev.hxx>
|
|
#include <vcl/svapp.hxx>
|
|
#include <vcl/gdimtf.hxx>
|
|
#include <vcl/graphictools.hxx>
|
|
#include <basegfx/polygon/b2dpolygon.hxx>
|
|
#include <vcl/canvastools.hxx>
|
|
#include <vcl/mtfxmldump.hxx>
|
|
|
|
#include <svmconverter.hxx>
|
|
#include <TypeSerializer.hxx>
|
|
|
|
#include <com/sun/star/beans/XFastPropertySet.hpp>
|
|
#include <com/sun/star/rendering/MtfRenderer.hpp>
|
|
#include <com/sun/star/rendering/XBitmapCanvas.hpp>
|
|
#include <com/sun/star/rendering/XCanvas.hpp>
|
|
#include <comphelper/processfactory.hxx>
|
|
|
|
using namespace com::sun::star;
|
|
|
|
#define GAMMA( _def_cVal, _def_InvGamma ) (static_cast<sal_uInt8>(MinMax(FRound(pow( _def_cVal/255.0,_def_InvGamma)*255.0),0,255)))
|
|
|
|
namespace {
|
|
|
|
struct ImplColAdjustParam
|
|
{
|
|
std::unique_ptr<sal_uInt8[]> pMapR;
|
|
std::unique_ptr<sal_uInt8[]> pMapG;
|
|
std::unique_ptr<sal_uInt8[]> pMapB;
|
|
};
|
|
|
|
struct ImplBmpAdjustParam
|
|
{
|
|
short nLuminancePercent;
|
|
short nContrastPercent;
|
|
short nChannelRPercent;
|
|
short nChannelGPercent;
|
|
short nChannelBPercent;
|
|
double fGamma;
|
|
bool bInvert;
|
|
};
|
|
|
|
struct ImplColConvertParam
|
|
{
|
|
MtfConversion eConversion;
|
|
};
|
|
|
|
struct ImplBmpConvertParam
|
|
{
|
|
BmpConversion eConversion;
|
|
};
|
|
|
|
struct ImplColMonoParam
|
|
{
|
|
Color aColor;
|
|
};
|
|
|
|
struct ImplBmpMonoParam
|
|
{
|
|
Color aColor;
|
|
};
|
|
|
|
struct ImplColReplaceParam
|
|
{
|
|
std::unique_ptr<sal_uLong[]> pMinR;
|
|
std::unique_ptr<sal_uLong[]> pMaxR;
|
|
std::unique_ptr<sal_uLong[]> pMinG;
|
|
std::unique_ptr<sal_uLong[]> pMaxG;
|
|
std::unique_ptr<sal_uLong[]> pMinB;
|
|
std::unique_ptr<sal_uLong[]> pMaxB;
|
|
const Color * pDstCols;
|
|
sal_uLong nCount;
|
|
};
|
|
|
|
struct ImplBmpReplaceParam
|
|
{
|
|
const Color* pSrcCols;
|
|
const Color* pDstCols;
|
|
sal_uLong nCount;
|
|
};
|
|
|
|
}
|
|
|
|
GDIMetaFile::GDIMetaFile() :
|
|
m_nCurrentActionElement( 0 ),
|
|
m_aPrefSize ( 1, 1 ),
|
|
m_pPrev ( nullptr ),
|
|
m_pNext ( nullptr ),
|
|
m_pOutDev ( nullptr ),
|
|
m_bPause ( false ),
|
|
m_bRecord ( false ),
|
|
m_bUseCanvas ( false )
|
|
{
|
|
}
|
|
|
|
GDIMetaFile::GDIMetaFile( const GDIMetaFile& rMtf ) :
|
|
m_nCurrentActionElement( rMtf.m_nCurrentActionElement ),
|
|
m_aPrefMapMode ( rMtf.m_aPrefMapMode ),
|
|
m_aPrefSize ( rMtf.m_aPrefSize ),
|
|
m_pPrev ( rMtf.m_pPrev ),
|
|
m_pNext ( rMtf.m_pNext ),
|
|
m_pOutDev ( nullptr ),
|
|
m_bPause ( false ),
|
|
m_bRecord ( false ),
|
|
m_bUseCanvas ( rMtf.m_bUseCanvas )
|
|
{
|
|
for( size_t i = 0, n = rMtf.GetActionSize(); i < n; ++i )
|
|
{
|
|
m_aList.push_back( rMtf.GetAction( i ) );
|
|
}
|
|
|
|
if( rMtf.m_bRecord )
|
|
{
|
|
Record( rMtf.m_pOutDev );
|
|
|
|
if ( rMtf.m_bPause )
|
|
Pause( true );
|
|
}
|
|
}
|
|
|
|
GDIMetaFile::~GDIMetaFile()
|
|
{
|
|
Clear();
|
|
}
|
|
|
|
bool GDIMetaFile::HasTransparentActions() const
|
|
{
|
|
MetaAction* pCurrAct;
|
|
|
|
// watch for transparent drawing actions
|
|
for(pCurrAct = const_cast<GDIMetaFile*>(this)->FirstAction();
|
|
pCurrAct;
|
|
pCurrAct = const_cast<GDIMetaFile*>(this)->NextAction())
|
|
{
|
|
// #i10613# determine if the action is transparency capable
|
|
|
|
// #107169# Also examine metafiles with masked bitmaps in
|
|
// detail. Further down, this is optimized in such a way
|
|
// that there's no unnecessary painting of masked bitmaps
|
|
// (which are _always_ subdivided into rectangular regions
|
|
// of uniform opacity): if a masked bitmap is printed over
|
|
// empty background, we convert to a plain bitmap with
|
|
// white background.
|
|
if (pCurrAct->IsTransparent())
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
size_t GDIMetaFile::GetActionSize() const
|
|
{
|
|
return m_aList.size();
|
|
}
|
|
|
|
MetaAction* GDIMetaFile::GetAction( size_t nAction ) const
|
|
{
|
|
return (nAction < m_aList.size()) ? m_aList[ nAction ].get() : nullptr;
|
|
}
|
|
|
|
MetaAction* GDIMetaFile::FirstAction()
|
|
{
|
|
m_nCurrentActionElement = 0;
|
|
return m_aList.empty() ? nullptr : m_aList[ 0 ].get();
|
|
}
|
|
|
|
MetaAction* GDIMetaFile::NextAction()
|
|
{
|
|
return ( m_nCurrentActionElement + 1 < m_aList.size() ) ? m_aList[ ++m_nCurrentActionElement ].get() : nullptr;
|
|
}
|
|
|
|
void GDIMetaFile::ReplaceAction( rtl::Reference<MetaAction> pAction, size_t nAction )
|
|
{
|
|
if ( nAction >= m_aList.size() )
|
|
{
|
|
return;
|
|
}
|
|
//fdo#39995 This doesn't increment the incoming action ref-count nor does it
|
|
//decrement the outgoing action ref-count
|
|
std::swap(pAction, m_aList[nAction]);
|
|
}
|
|
|
|
GDIMetaFile& GDIMetaFile::operator=( const GDIMetaFile& rMtf )
|
|
{
|
|
if( this != &rMtf )
|
|
{
|
|
Clear();
|
|
|
|
// Increment RefCount of MetaActions
|
|
for( size_t i = 0, n = rMtf.GetActionSize(); i < n; ++i )
|
|
{
|
|
m_aList.push_back( rMtf.GetAction( i ) );
|
|
}
|
|
|
|
m_aPrefMapMode = rMtf.m_aPrefMapMode;
|
|
m_aPrefSize = rMtf.m_aPrefSize;
|
|
m_pPrev = rMtf.m_pPrev;
|
|
m_pNext = rMtf.m_pNext;
|
|
m_pOutDev = nullptr;
|
|
m_bPause = false;
|
|
m_bRecord = false;
|
|
m_bUseCanvas = rMtf.m_bUseCanvas;
|
|
|
|
if( rMtf.m_bRecord )
|
|
{
|
|
Record( rMtf.m_pOutDev );
|
|
|
|
if( rMtf.m_bPause )
|
|
Pause( true );
|
|
}
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
bool GDIMetaFile::operator==( const GDIMetaFile& rMtf ) const
|
|
{
|
|
const size_t nObjCount = m_aList.size();
|
|
bool bRet = false;
|
|
|
|
if( this == &rMtf )
|
|
bRet = true;
|
|
else if( rMtf.GetActionSize() == nObjCount &&
|
|
rMtf.GetPrefSize() == m_aPrefSize &&
|
|
rMtf.GetPrefMapMode() == m_aPrefMapMode )
|
|
{
|
|
bRet = true;
|
|
|
|
for( size_t n = 0; n < nObjCount; n++ )
|
|
{
|
|
if( m_aList[ n ] != rMtf.GetAction( n ) )
|
|
{
|
|
bRet = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
void GDIMetaFile::Clear()
|
|
{
|
|
if( m_bRecord )
|
|
Stop();
|
|
|
|
m_aList.clear();
|
|
}
|
|
|
|
void GDIMetaFile::Linker( OutputDevice* pOut, bool bLink )
|
|
{
|
|
if( bLink )
|
|
{
|
|
m_pNext = nullptr;
|
|
m_pPrev = pOut->GetConnectMetaFile();
|
|
pOut->SetConnectMetaFile( this );
|
|
|
|
if( m_pPrev )
|
|
m_pPrev->m_pNext = this;
|
|
}
|
|
else
|
|
{
|
|
if( m_pNext )
|
|
{
|
|
m_pNext->m_pPrev = m_pPrev;
|
|
|
|
if( m_pPrev )
|
|
m_pPrev->m_pNext = m_pNext;
|
|
}
|
|
else
|
|
{
|
|
if( m_pPrev )
|
|
m_pPrev->m_pNext = nullptr;
|
|
|
|
pOut->SetConnectMetaFile( m_pPrev );
|
|
}
|
|
|
|
m_pPrev = nullptr;
|
|
m_pNext = nullptr;
|
|
}
|
|
}
|
|
|
|
void GDIMetaFile::Record( OutputDevice* pOut )
|
|
{
|
|
if( m_bRecord )
|
|
Stop();
|
|
|
|
m_nCurrentActionElement = m_aList.empty() ? 0 : (m_aList.size() - 1);
|
|
m_pOutDev = pOut;
|
|
m_bRecord = true;
|
|
Linker( pOut, true );
|
|
}
|
|
|
|
void GDIMetaFile::Play( GDIMetaFile& rMtf )
|
|
{
|
|
if ( !m_bRecord && !rMtf.m_bRecord )
|
|
{
|
|
MetaAction* pAction = GetCurAction();
|
|
const size_t nObjCount = m_aList.size();
|
|
|
|
rMtf.UseCanvas( rMtf.GetUseCanvas() || m_bUseCanvas );
|
|
|
|
for( size_t nCurPos = m_nCurrentActionElement; nCurPos < nObjCount; nCurPos++ )
|
|
{
|
|
if( pAction )
|
|
{
|
|
rMtf.AddAction( pAction );
|
|
}
|
|
|
|
pAction = NextAction();
|
|
}
|
|
}
|
|
}
|
|
|
|
void GDIMetaFile::Play( OutputDevice* pOut, size_t nPos )
|
|
{
|
|
if( !m_bRecord )
|
|
{
|
|
MetaAction* pAction = GetCurAction();
|
|
const size_t nObjCount = m_aList.size();
|
|
size_t nSyncCount = pOut->GetSyncCount();
|
|
|
|
if( nPos > nObjCount )
|
|
nPos = nObjCount;
|
|
|
|
// #i23407# Set backwards-compatible text language and layout mode
|
|
// This is necessary, since old metafiles don't even know of these
|
|
// recent add-ons. Newer metafiles must of course explicitly set
|
|
// those states.
|
|
pOut->Push( PushFlags::TEXTLAYOUTMODE|PushFlags::TEXTLANGUAGE );
|
|
pOut->SetLayoutMode( ComplexTextLayoutFlags::Default );
|
|
pOut->SetDigitLanguage( LANGUAGE_SYSTEM );
|
|
|
|
SAL_INFO( "vcl.gdi", "GDIMetaFile::Play on device of size: " << pOut->GetOutputSizePixel().Width() << " " << pOut->GetOutputSizePixel().Height());
|
|
|
|
if( !ImplPlayWithRenderer( pOut, Point(0,0), pOut->GetOutputSize() ) ) {
|
|
size_t i = 0;
|
|
for( size_t nCurPos = m_nCurrentActionElement; nCurPos < nPos; nCurPos++ )
|
|
{
|
|
if( pAction )
|
|
{
|
|
pAction->Execute( pOut );
|
|
|
|
// flush output from time to time
|
|
if( i++ > nSyncCount )
|
|
{
|
|
static_cast<vcl::Window*>( pOut )->Flush();
|
|
i = 0;
|
|
}
|
|
}
|
|
|
|
pAction = NextAction();
|
|
}
|
|
}
|
|
pOut->Pop();
|
|
}
|
|
}
|
|
|
|
bool GDIMetaFile::ImplPlayWithRenderer( OutputDevice* pOut, const Point& rPos, Size rLogicDestSize )
|
|
{
|
|
if (!m_bUseCanvas)
|
|
return false;
|
|
|
|
Size rDestSize( pOut->LogicToPixel( rLogicDestSize ) );
|
|
|
|
const vcl::Window* win = dynamic_cast <vcl::Window*> ( pOut );
|
|
|
|
if (!win)
|
|
win = Application::GetActiveTopWindow();
|
|
if (!win)
|
|
win = Application::GetFirstTopLevelWindow();
|
|
|
|
if (!win)
|
|
return false;
|
|
|
|
try
|
|
{
|
|
uno::Reference<rendering::XCanvas> xCanvas = win->GetCanvas ();
|
|
|
|
if (!xCanvas.is())
|
|
return false;
|
|
|
|
Size aSize (rDestSize.Width () + 1, rDestSize.Height () + 1);
|
|
uno::Reference<rendering::XBitmap> xBitmap = xCanvas->getDevice ()->createCompatibleAlphaBitmap (vcl::unotools::integerSize2DFromSize( aSize));
|
|
if( xBitmap.is () )
|
|
{
|
|
uno::Reference< rendering::XBitmapCanvas > xBitmapCanvas( xBitmap, uno::UNO_QUERY );
|
|
if( xBitmapCanvas.is() )
|
|
{
|
|
uno::Reference< uno::XComponentContext > xContext = comphelper::getProcessComponentContext();
|
|
uno::Reference< rendering::XMtfRenderer > xMtfRenderer = rendering::MtfRenderer::createWithBitmapCanvas( xContext, xBitmapCanvas );
|
|
|
|
xBitmapCanvas->clear();
|
|
uno::Reference< beans::XFastPropertySet > xMtfFastPropertySet( xMtfRenderer, uno::UNO_QUERY );
|
|
if( xMtfFastPropertySet.is() )
|
|
// set this metafile to the renderer to
|
|
// speedup things (instead of copying data to
|
|
// sequence of bytes passed to renderer)
|
|
xMtfFastPropertySet->setFastPropertyValue( 0, uno::Any( reinterpret_cast<sal_Int64>( this ) ) );
|
|
|
|
xMtfRenderer->draw( rDestSize.Width(), rDestSize.Height() );
|
|
|
|
BitmapEx aBitmapEx;
|
|
if( aBitmapEx.Create( xBitmapCanvas, aSize ) )
|
|
{
|
|
if (pOut->GetMapMode().GetMapUnit() == MapUnit::MapPixel)
|
|
pOut->DrawBitmapEx( rPos, aBitmapEx );
|
|
else
|
|
pOut->DrawBitmapEx( rPos, rLogicDestSize, aBitmapEx );
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (const uno::RuntimeException& )
|
|
{
|
|
throw; // runtime errors are fatal
|
|
}
|
|
catch (const uno::Exception&)
|
|
{
|
|
// ignore errors, no way of reporting them here
|
|
TOOLS_WARN_EXCEPTION("vcl.gdi", "GDIMetaFile::ImplPlayWithRenderer");
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void GDIMetaFile::Play( OutputDevice* pOut, const Point& rPos,
|
|
const Size& rSize )
|
|
{
|
|
MapMode aDrawMap( GetPrefMapMode() );
|
|
Size aDestSize( pOut->LogicToPixel( rSize ) );
|
|
|
|
if( !aDestSize.Width() || !aDestSize.Height() )
|
|
return;
|
|
|
|
GDIMetaFile* pMtf = pOut->GetConnectMetaFile();
|
|
|
|
if( ImplPlayWithRenderer( pOut, rPos, rSize ) )
|
|
return;
|
|
|
|
Size aTmpPrefSize( pOut->LogicToPixel( GetPrefSize(), aDrawMap ) );
|
|
|
|
if( !aTmpPrefSize.Width() )
|
|
aTmpPrefSize.setWidth( aDestSize.Width() );
|
|
|
|
if( !aTmpPrefSize.Height() )
|
|
aTmpPrefSize.setHeight( aDestSize.Height() );
|
|
|
|
Fraction aScaleX( aDestSize.Width(), aTmpPrefSize.Width() );
|
|
Fraction aScaleY( aDestSize.Height(), aTmpPrefSize.Height() );
|
|
|
|
aScaleX *= aDrawMap.GetScaleX(); aDrawMap.SetScaleX( aScaleX );
|
|
aScaleY *= aDrawMap.GetScaleY(); aDrawMap.SetScaleY( aScaleY );
|
|
|
|
// #i47260# Convert logical output position to offset within
|
|
// the metafile's mapmode. Therefore, disable pixel offset on
|
|
// outdev, it's inverse mnOutOffLogicX/Y is calculated for a
|
|
// different mapmode (the one currently set on pOut, that is)
|
|
// - thus, aDrawMap's origin would generally be wrong. And
|
|
// even _if_ aDrawMap is similar to pOutDev's current mapmode,
|
|
// it's _still_ undesirable to have pixel offset unequal zero,
|
|
// because one would still get round-off errors (the
|
|
// round-trip error for LogicToPixel( PixelToLogic() ) was the
|
|
// reason for having pixel offset in the first place).
|
|
const Size& rOldOffset( pOut->GetPixelOffset() );
|
|
const Size aEmptySize;
|
|
pOut->SetPixelOffset( aEmptySize );
|
|
aDrawMap.SetOrigin( pOut->PixelToLogic( pOut->LogicToPixel( rPos ), aDrawMap ) );
|
|
pOut->SetPixelOffset( rOldOffset );
|
|
|
|
pOut->Push();
|
|
|
|
bool bIsRecord = (pMtf && pMtf->IsRecord());
|
|
pOut->SetMetafileMapMode(aDrawMap, bIsRecord);
|
|
|
|
// #i23407# Set backwards-compatible text language and layout mode
|
|
// This is necessary, since old metafiles don't even know of these
|
|
// recent add-ons. Newer metafiles must of course explicitly set
|
|
// those states.
|
|
pOut->SetLayoutMode( ComplexTextLayoutFlags::Default );
|
|
pOut->SetDigitLanguage( LANGUAGE_SYSTEM );
|
|
|
|
Play( pOut );
|
|
|
|
pOut->Pop();
|
|
|
|
}
|
|
|
|
void GDIMetaFile::Pause( bool _bPause )
|
|
{
|
|
if( m_bRecord )
|
|
{
|
|
if( _bPause )
|
|
{
|
|
if( !m_bPause )
|
|
Linker( m_pOutDev, false );
|
|
}
|
|
else
|
|
{
|
|
if( m_bPause )
|
|
Linker( m_pOutDev, true );
|
|
}
|
|
|
|
m_bPause = _bPause;
|
|
}
|
|
}
|
|
|
|
void GDIMetaFile::Stop()
|
|
{
|
|
if( m_bRecord )
|
|
{
|
|
m_bRecord = false;
|
|
|
|
if( !m_bPause )
|
|
Linker( m_pOutDev, false );
|
|
else
|
|
m_bPause = false;
|
|
}
|
|
}
|
|
|
|
void GDIMetaFile::WindStart()
|
|
{
|
|
if( !m_bRecord )
|
|
m_nCurrentActionElement = 0;
|
|
}
|
|
|
|
void GDIMetaFile::WindPrev()
|
|
{
|
|
if( !m_bRecord )
|
|
if ( m_nCurrentActionElement > 0 )
|
|
--m_nCurrentActionElement;
|
|
}
|
|
|
|
void GDIMetaFile::AddAction(const rtl::Reference<MetaAction>& pAction)
|
|
{
|
|
m_aList.push_back( pAction );
|
|
|
|
if( m_pPrev )
|
|
{
|
|
m_pPrev->AddAction( pAction );
|
|
}
|
|
}
|
|
|
|
void GDIMetaFile::AddAction(const rtl::Reference<MetaAction>& pAction, size_t nPos)
|
|
{
|
|
if ( nPos < m_aList.size() )
|
|
{
|
|
m_aList.insert( m_aList.begin() + nPos, pAction );
|
|
}
|
|
else
|
|
{
|
|
m_aList.push_back( pAction );
|
|
}
|
|
|
|
if( m_pPrev )
|
|
{
|
|
m_pPrev->AddAction( pAction, nPos );
|
|
}
|
|
}
|
|
|
|
void GDIMetaFile::push_back(const rtl::Reference<MetaAction>& pAction)
|
|
{
|
|
m_aList.push_back( pAction );
|
|
}
|
|
|
|
void GDIMetaFile::Mirror( BmpMirrorFlags nMirrorFlags )
|
|
{
|
|
const Size aOldPrefSize( GetPrefSize() );
|
|
long nMoveX, nMoveY;
|
|
double fScaleX, fScaleY;
|
|
|
|
if( nMirrorFlags & BmpMirrorFlags::Horizontal )
|
|
{
|
|
nMoveX = std::abs( aOldPrefSize.Width() ) - 1;
|
|
fScaleX = -1.0;
|
|
}
|
|
else
|
|
{
|
|
nMoveX = 0;
|
|
fScaleX = 1.0;
|
|
}
|
|
|
|
if( nMirrorFlags & BmpMirrorFlags::Vertical )
|
|
{
|
|
nMoveY = std::abs( aOldPrefSize.Height() ) - 1;
|
|
fScaleY = -1.0;
|
|
}
|
|
else
|
|
{
|
|
nMoveY = 0;
|
|
fScaleY = 1.0;
|
|
}
|
|
|
|
if( ( fScaleX != 1.0 ) || ( fScaleY != 1.0 ) )
|
|
{
|
|
Scale( fScaleX, fScaleY );
|
|
Move( nMoveX, nMoveY );
|
|
SetPrefSize( aOldPrefSize );
|
|
}
|
|
}
|
|
|
|
void GDIMetaFile::Move( long nX, long nY )
|
|
{
|
|
const Size aBaseOffset( nX, nY );
|
|
Size aOffset( aBaseOffset );
|
|
ScopedVclPtrInstance< VirtualDevice > aMapVDev;
|
|
|
|
aMapVDev->EnableOutput( false );
|
|
aMapVDev->SetMapMode( GetPrefMapMode() );
|
|
|
|
for( MetaAction* pAct = FirstAction(); pAct; pAct = NextAction() )
|
|
{
|
|
const MetaActionType nType = pAct->GetType();
|
|
MetaAction* pModAct;
|
|
|
|
if( pAct->GetRefCount() > 1 )
|
|
{
|
|
m_aList[ m_nCurrentActionElement ] = pAct->Clone();
|
|
pModAct = m_aList[ m_nCurrentActionElement ].get();
|
|
}
|
|
else
|
|
pModAct = pAct;
|
|
|
|
if( ( MetaActionType::MAPMODE == nType ) ||
|
|
( MetaActionType::PUSH == nType ) ||
|
|
( MetaActionType::POP == nType ) )
|
|
{
|
|
pModAct->Execute( aMapVDev.get() );
|
|
aOffset = OutputDevice::LogicToLogic( aBaseOffset, GetPrefMapMode(), aMapVDev->GetMapMode() );
|
|
}
|
|
|
|
pModAct->Move( aOffset.Width(), aOffset.Height() );
|
|
}
|
|
}
|
|
|
|
void GDIMetaFile::Move( long nX, long nY, long nDPIX, long nDPIY )
|
|
{
|
|
const Size aBaseOffset( nX, nY );
|
|
Size aOffset( aBaseOffset );
|
|
ScopedVclPtrInstance< VirtualDevice > aMapVDev;
|
|
|
|
aMapVDev->EnableOutput( false );
|
|
aMapVDev->SetReferenceDevice( nDPIX, nDPIY );
|
|
aMapVDev->SetMapMode( GetPrefMapMode() );
|
|
|
|
for( MetaAction* pAct = FirstAction(); pAct; pAct = NextAction() )
|
|
{
|
|
const MetaActionType nType = pAct->GetType();
|
|
MetaAction* pModAct;
|
|
|
|
if( pAct->GetRefCount() > 1 )
|
|
{
|
|
m_aList[ m_nCurrentActionElement ] = pAct->Clone();
|
|
pModAct = m_aList[ m_nCurrentActionElement ].get();
|
|
}
|
|
else
|
|
pModAct = pAct;
|
|
|
|
if( ( MetaActionType::MAPMODE == nType ) ||
|
|
( MetaActionType::PUSH == nType ) ||
|
|
( MetaActionType::POP == nType ) )
|
|
{
|
|
pModAct->Execute( aMapVDev.get() );
|
|
if( aMapVDev->GetMapMode().GetMapUnit() == MapUnit::MapPixel )
|
|
{
|
|
aOffset = aMapVDev->LogicToPixel( aBaseOffset, GetPrefMapMode() );
|
|
MapMode aMap( aMapVDev->GetMapMode() );
|
|
aOffset.setWidth( static_cast<long>(aOffset.Width() * static_cast<double>(aMap.GetScaleX())) );
|
|
aOffset.setHeight( static_cast<long>(aOffset.Height() * static_cast<double>(aMap.GetScaleY())) );
|
|
}
|
|
else
|
|
aOffset = OutputDevice::LogicToLogic( aBaseOffset, GetPrefMapMode(), aMapVDev->GetMapMode() );
|
|
}
|
|
|
|
pModAct->Move( aOffset.Width(), aOffset.Height() );
|
|
}
|
|
}
|
|
|
|
void GDIMetaFile::Scale( double fScaleX, double fScaleY )
|
|
{
|
|
for( MetaAction* pAct = FirstAction(); pAct; pAct = NextAction() )
|
|
{
|
|
MetaAction* pModAct;
|
|
|
|
if( pAct->GetRefCount() > 1 )
|
|
{
|
|
m_aList[ m_nCurrentActionElement ] = pAct->Clone();
|
|
pModAct = m_aList[ m_nCurrentActionElement ].get();
|
|
}
|
|
else
|
|
pModAct = pAct;
|
|
|
|
pModAct->Scale( fScaleX, fScaleY );
|
|
}
|
|
|
|
m_aPrefSize.setWidth( FRound( m_aPrefSize.Width() * fScaleX ) );
|
|
m_aPrefSize.setHeight( FRound( m_aPrefSize.Height() * fScaleY ) );
|
|
}
|
|
|
|
void GDIMetaFile::Scale( const Fraction& rScaleX, const Fraction& rScaleY )
|
|
{
|
|
Scale( static_cast<double>(rScaleX), static_cast<double>(rScaleY) );
|
|
}
|
|
|
|
void GDIMetaFile::Clip( const tools::Rectangle& i_rClipRect )
|
|
{
|
|
tools::Rectangle aCurRect( i_rClipRect );
|
|
ScopedVclPtrInstance< VirtualDevice > aMapVDev;
|
|
|
|
aMapVDev->EnableOutput( false );
|
|
aMapVDev->SetMapMode( GetPrefMapMode() );
|
|
|
|
for( MetaAction* pAct = FirstAction(); pAct; pAct = NextAction() )
|
|
{
|
|
const MetaActionType nType = pAct->GetType();
|
|
|
|
if( ( MetaActionType::MAPMODE == nType ) ||
|
|
( MetaActionType::PUSH == nType ) ||
|
|
( MetaActionType::POP == nType ) )
|
|
{
|
|
pAct->Execute( aMapVDev.get() );
|
|
aCurRect = OutputDevice::LogicToLogic( i_rClipRect, GetPrefMapMode(), aMapVDev->GetMapMode() );
|
|
}
|
|
else if( nType == MetaActionType::CLIPREGION )
|
|
{
|
|
MetaClipRegionAction* pOldAct = static_cast<MetaClipRegionAction*>(pAct);
|
|
vcl::Region aNewReg( aCurRect );
|
|
if( pOldAct->IsClipping() )
|
|
aNewReg.Intersect( pOldAct->GetRegion() );
|
|
MetaClipRegionAction* pNewAct = new MetaClipRegionAction( aNewReg, true );
|
|
m_aList[ m_nCurrentActionElement ] = pNewAct;
|
|
}
|
|
}
|
|
}
|
|
|
|
Point GDIMetaFile::ImplGetRotatedPoint( const Point& rPt, const Point& rRotatePt,
|
|
const Size& rOffset, double fSin, double fCos )
|
|
{
|
|
const long nX = rPt.X() - rRotatePt.X();
|
|
const long nY = rPt.Y() - rRotatePt.Y();
|
|
|
|
return Point( FRound( fCos * nX + fSin * nY ) + rRotatePt.X() + rOffset.Width(),
|
|
-FRound( fSin * nX - fCos * nY ) + rRotatePt.Y() + rOffset.Height() );
|
|
}
|
|
|
|
tools::Polygon GDIMetaFile::ImplGetRotatedPolygon( const tools::Polygon& rPoly, const Point& rRotatePt,
|
|
const Size& rOffset, double fSin, double fCos )
|
|
{
|
|
tools::Polygon aRet( rPoly );
|
|
|
|
aRet.Rotate( rRotatePt, fSin, fCos );
|
|
aRet.Move( rOffset.Width(), rOffset.Height() );
|
|
|
|
return aRet;
|
|
}
|
|
|
|
tools::PolyPolygon GDIMetaFile::ImplGetRotatedPolyPolygon( const tools::PolyPolygon& rPolyPoly, const Point& rRotatePt,
|
|
const Size& rOffset, double fSin, double fCos )
|
|
{
|
|
tools::PolyPolygon aRet( rPolyPoly );
|
|
|
|
aRet.Rotate( rRotatePt, fSin, fCos );
|
|
aRet.Move( rOffset.Width(), rOffset.Height() );
|
|
|
|
return aRet;
|
|
}
|
|
|
|
void GDIMetaFile::ImplAddGradientEx( GDIMetaFile& rMtf,
|
|
const OutputDevice& rMapDev,
|
|
const tools::PolyPolygon& rPolyPoly,
|
|
const Gradient& rGrad )
|
|
{
|
|
// Generate comment, GradientEx and Gradient actions (within DrawGradient)
|
|
ScopedVclPtrInstance< VirtualDevice > aVDev(rMapDev, DeviceFormat::DEFAULT);
|
|
aVDev->EnableOutput( false );
|
|
GDIMetaFile aGradMtf;
|
|
|
|
aGradMtf.Record( aVDev.get() );
|
|
aVDev->DrawGradient( rPolyPoly, rGrad );
|
|
aGradMtf.Stop();
|
|
|
|
size_t i, nAct( aGradMtf.GetActionSize() );
|
|
for( i=0; i < nAct; ++i )
|
|
{
|
|
MetaAction* pMetaAct = aGradMtf.GetAction( i );
|
|
rMtf.AddAction( pMetaAct );
|
|
}
|
|
}
|
|
|
|
void GDIMetaFile::Rotate( long nAngle10 )
|
|
{
|
|
nAngle10 %= 3600;
|
|
nAngle10 = ( nAngle10 < 0 ) ? ( 3599 + nAngle10 ) : nAngle10;
|
|
|
|
if( !nAngle10 )
|
|
return;
|
|
|
|
GDIMetaFile aMtf;
|
|
ScopedVclPtrInstance< VirtualDevice > aMapVDev;
|
|
const double fAngle = F_PI1800 * nAngle10;
|
|
const double fSin = sin( fAngle );
|
|
const double fCos = cos( fAngle );
|
|
tools::Rectangle aRect( Point(), GetPrefSize() );
|
|
tools::Polygon aPoly( aRect );
|
|
|
|
aPoly.Rotate( Point(), fSin, fCos );
|
|
|
|
aMapVDev->EnableOutput( false );
|
|
aMapVDev->SetMapMode( GetPrefMapMode() );
|
|
|
|
const tools::Rectangle aNewBound( aPoly.GetBoundRect() );
|
|
|
|
const Point aOrigin( GetPrefMapMode().GetOrigin().X(), GetPrefMapMode().GetOrigin().Y() );
|
|
const Size aOffset( -aNewBound.Left(), -aNewBound.Top() );
|
|
|
|
Point aRotAnchor( aOrigin );
|
|
Size aRotOffset( aOffset );
|
|
|
|
for( MetaAction* pAction = FirstAction(); pAction; pAction = NextAction() )
|
|
{
|
|
const MetaActionType nActionType = pAction->GetType();
|
|
|
|
switch( nActionType )
|
|
{
|
|
case MetaActionType::PIXEL:
|
|
{
|
|
MetaPixelAction* pAct = static_cast<MetaPixelAction*>(pAction);
|
|
aMtf.AddAction( new MetaPixelAction( ImplGetRotatedPoint( pAct->GetPoint(), aRotAnchor, aRotOffset, fSin, fCos ),
|
|
pAct->GetColor() ) );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::POINT:
|
|
{
|
|
MetaPointAction* pAct = static_cast<MetaPointAction*>(pAction);
|
|
aMtf.AddAction( new MetaPointAction( ImplGetRotatedPoint( pAct->GetPoint(), aRotAnchor, aRotOffset, fSin, fCos ) ) );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::LINE:
|
|
{
|
|
MetaLineAction* pAct = static_cast<MetaLineAction*>(pAction);
|
|
aMtf.AddAction( new MetaLineAction( ImplGetRotatedPoint( pAct->GetStartPoint(), aRotAnchor, aRotOffset, fSin, fCos ),
|
|
ImplGetRotatedPoint( pAct->GetEndPoint(), aRotAnchor, aRotOffset, fSin, fCos ),
|
|
pAct->GetLineInfo() ) );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::RECT:
|
|
{
|
|
MetaRectAction* pAct = static_cast<MetaRectAction*>(pAction);
|
|
aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( pAct->GetRect(), aRotAnchor, aRotOffset, fSin, fCos ) ) );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::ROUNDRECT:
|
|
{
|
|
MetaRoundRectAction* pAct = static_cast<MetaRoundRectAction*>(pAction);
|
|
const tools::Polygon aRoundRectPoly( pAct->GetRect(), pAct->GetHorzRound(), pAct->GetVertRound() );
|
|
|
|
aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( aRoundRectPoly, aRotAnchor, aRotOffset, fSin, fCos ) ) );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::ELLIPSE:
|
|
{
|
|
MetaEllipseAction* pAct = static_cast<MetaEllipseAction*>(pAction);
|
|
const tools::Polygon aEllipsePoly( pAct->GetRect().Center(), pAct->GetRect().GetWidth() >> 1, pAct->GetRect().GetHeight() >> 1 );
|
|
|
|
aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( aEllipsePoly, aRotAnchor, aRotOffset, fSin, fCos ) ) );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::ARC:
|
|
{
|
|
MetaArcAction* pAct = static_cast<MetaArcAction*>(pAction);
|
|
const tools::Polygon aArcPoly( pAct->GetRect(), pAct->GetStartPoint(), pAct->GetEndPoint(), PolyStyle::Arc );
|
|
|
|
aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( aArcPoly, aRotAnchor, aRotOffset, fSin, fCos ) ) );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::PIE:
|
|
{
|
|
MetaPieAction* pAct = static_cast<MetaPieAction*>(pAction);
|
|
const tools::Polygon aPiePoly( pAct->GetRect(), pAct->GetStartPoint(), pAct->GetEndPoint(), PolyStyle::Pie );
|
|
|
|
aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( aPiePoly, aRotAnchor, aRotOffset, fSin, fCos ) ) );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::CHORD:
|
|
{
|
|
MetaChordAction* pAct = static_cast<MetaChordAction*>(pAction);
|
|
const tools::Polygon aChordPoly( pAct->GetRect(), pAct->GetStartPoint(), pAct->GetEndPoint(), PolyStyle::Chord );
|
|
|
|
aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( aChordPoly, aRotAnchor, aRotOffset, fSin, fCos ) ) );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::POLYLINE:
|
|
{
|
|
MetaPolyLineAction* pAct = static_cast<MetaPolyLineAction*>(pAction);
|
|
aMtf.AddAction( new MetaPolyLineAction( ImplGetRotatedPolygon( pAct->GetPolygon(), aRotAnchor, aRotOffset, fSin, fCos ), pAct->GetLineInfo() ) );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::POLYGON:
|
|
{
|
|
MetaPolygonAction* pAct = static_cast<MetaPolygonAction*>(pAction);
|
|
aMtf.AddAction( new MetaPolygonAction( ImplGetRotatedPolygon( pAct->GetPolygon(), aRotAnchor, aRotOffset, fSin, fCos ) ) );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::POLYPOLYGON:
|
|
{
|
|
MetaPolyPolygonAction* pAct = static_cast<MetaPolyPolygonAction*>(pAction);
|
|
aMtf.AddAction( new MetaPolyPolygonAction( ImplGetRotatedPolyPolygon( pAct->GetPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ) ) );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::TEXT:
|
|
{
|
|
MetaTextAction* pAct = static_cast<MetaTextAction*>(pAction);
|
|
aMtf.AddAction( new MetaTextAction( ImplGetRotatedPoint( pAct->GetPoint(), aRotAnchor, aRotOffset, fSin, fCos ),
|
|
pAct->GetText(), pAct->GetIndex(), pAct->GetLen() ) );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::TEXTARRAY:
|
|
{
|
|
MetaTextArrayAction* pAct = static_cast<MetaTextArrayAction*>(pAction);
|
|
aMtf.AddAction( new MetaTextArrayAction( ImplGetRotatedPoint( pAct->GetPoint(), aRotAnchor, aRotOffset, fSin, fCos ),
|
|
pAct->GetText(), pAct->GetDXArray(), pAct->GetIndex(), pAct->GetLen() ) );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::STRETCHTEXT:
|
|
{
|
|
MetaStretchTextAction* pAct = static_cast<MetaStretchTextAction*>(pAction);
|
|
aMtf.AddAction( new MetaStretchTextAction( ImplGetRotatedPoint( pAct->GetPoint(), aRotAnchor, aRotOffset, fSin, fCos ),
|
|
pAct->GetWidth(), pAct->GetText(), pAct->GetIndex(), pAct->GetLen() ) );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::TEXTLINE:
|
|
{
|
|
MetaTextLineAction* pAct = static_cast<MetaTextLineAction*>(pAction);
|
|
aMtf.AddAction( new MetaTextLineAction( ImplGetRotatedPoint( pAct->GetStartPoint(), aRotAnchor, aRotOffset, fSin, fCos ),
|
|
pAct->GetWidth(), pAct->GetStrikeout(), pAct->GetUnderline(), pAct->GetOverline() ) );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::BMPSCALE:
|
|
{
|
|
MetaBmpScaleAction* pAct = static_cast<MetaBmpScaleAction*>(pAction);
|
|
tools::Polygon aBmpPoly( ImplGetRotatedPolygon( tools::Rectangle( pAct->GetPoint(), pAct->GetSize() ), aRotAnchor, aRotOffset, fSin, fCos ) );
|
|
tools::Rectangle aBmpRect( aBmpPoly.GetBoundRect() );
|
|
BitmapEx aBmpEx( pAct->GetBitmap() );
|
|
|
|
aBmpEx.Rotate( nAngle10, COL_TRANSPARENT );
|
|
aMtf.AddAction( new MetaBmpExScaleAction( aBmpRect.TopLeft(), aBmpRect.GetSize(),
|
|
aBmpEx ) );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::BMPSCALEPART:
|
|
{
|
|
MetaBmpScalePartAction* pAct = static_cast<MetaBmpScalePartAction*>(pAction);
|
|
tools::Polygon aBmpPoly( ImplGetRotatedPolygon( tools::Rectangle( pAct->GetDestPoint(), pAct->GetDestSize() ), aRotAnchor, aRotOffset, fSin, fCos ) );
|
|
tools::Rectangle aBmpRect( aBmpPoly.GetBoundRect() );
|
|
BitmapEx aBmpEx( pAct->GetBitmap() );
|
|
|
|
aBmpEx.Crop( tools::Rectangle( pAct->GetSrcPoint(), pAct->GetSrcSize() ) );
|
|
aBmpEx.Rotate( nAngle10, COL_TRANSPARENT );
|
|
|
|
aMtf.AddAction( new MetaBmpExScaleAction( aBmpRect.TopLeft(), aBmpRect.GetSize(), aBmpEx ) );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::BMPEXSCALE:
|
|
{
|
|
MetaBmpExScaleAction* pAct = static_cast<MetaBmpExScaleAction*>(pAction);
|
|
tools::Polygon aBmpPoly( ImplGetRotatedPolygon( tools::Rectangle( pAct->GetPoint(), pAct->GetSize() ), aRotAnchor, aRotOffset, fSin, fCos ) );
|
|
tools::Rectangle aBmpRect( aBmpPoly.GetBoundRect() );
|
|
BitmapEx aBmpEx( pAct->GetBitmapEx() );
|
|
|
|
aBmpEx.Rotate( nAngle10, COL_TRANSPARENT );
|
|
|
|
aMtf.AddAction( new MetaBmpExScaleAction( aBmpRect.TopLeft(), aBmpRect.GetSize(), aBmpEx ) );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::BMPEXSCALEPART:
|
|
{
|
|
MetaBmpExScalePartAction* pAct = static_cast<MetaBmpExScalePartAction*>(pAction);
|
|
tools::Polygon aBmpPoly( ImplGetRotatedPolygon( tools::Rectangle( pAct->GetDestPoint(), pAct->GetDestSize() ), aRotAnchor, aRotOffset, fSin, fCos ) );
|
|
tools::Rectangle aBmpRect( aBmpPoly.GetBoundRect() );
|
|
BitmapEx aBmpEx( pAct->GetBitmapEx() );
|
|
|
|
aBmpEx.Crop( tools::Rectangle( pAct->GetSrcPoint(), pAct->GetSrcSize() ) );
|
|
aBmpEx.Rotate( nAngle10, COL_TRANSPARENT );
|
|
|
|
aMtf.AddAction( new MetaBmpExScaleAction( aBmpRect.TopLeft(), aBmpRect.GetSize(), aBmpEx ) );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::GRADIENT:
|
|
{
|
|
MetaGradientAction* pAct = static_cast<MetaGradientAction*>(pAction);
|
|
|
|
ImplAddGradientEx( aMtf, *aMapVDev,
|
|
ImplGetRotatedPolygon( pAct->GetRect(), aRotAnchor, aRotOffset, fSin, fCos ),
|
|
pAct->GetGradient() );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::GRADIENTEX:
|
|
{
|
|
MetaGradientExAction* pAct = static_cast<MetaGradientExAction*>(pAction);
|
|
aMtf.AddAction( new MetaGradientExAction( ImplGetRotatedPolyPolygon( pAct->GetPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ),
|
|
pAct->GetGradient() ) );
|
|
}
|
|
break;
|
|
|
|
// Handle gradientex comment block correctly
|
|
case MetaActionType::COMMENT:
|
|
{
|
|
MetaCommentAction* pCommentAct = static_cast<MetaCommentAction*>(pAction);
|
|
if( pCommentAct->GetComment() == "XGRAD_SEQ_BEGIN" )
|
|
{
|
|
int nBeginComments( 1 );
|
|
pAction = NextAction();
|
|
|
|
// skip everything, except gradientex action
|
|
while( pAction )
|
|
{
|
|
const MetaActionType nType = pAction->GetType();
|
|
|
|
if( MetaActionType::GRADIENTEX == nType )
|
|
{
|
|
// Add rotated gradientex
|
|
MetaGradientExAction* pAct = static_cast<MetaGradientExAction*>(pAction);
|
|
ImplAddGradientEx( aMtf, *aMapVDev,
|
|
ImplGetRotatedPolyPolygon( pAct->GetPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ),
|
|
pAct->GetGradient() );
|
|
}
|
|
else if( MetaActionType::COMMENT == nType)
|
|
{
|
|
MetaCommentAction* pAct = static_cast<MetaCommentAction*>(pAction);
|
|
if( pAct->GetComment() == "XGRAD_SEQ_END" )
|
|
{
|
|
// handle nested blocks
|
|
--nBeginComments;
|
|
|
|
// gradientex comment block: end reached, done.
|
|
if( !nBeginComments )
|
|
break;
|
|
}
|
|
else if( pAct->GetComment() == "XGRAD_SEQ_BEGIN" )
|
|
{
|
|
// handle nested blocks
|
|
++nBeginComments;
|
|
}
|
|
|
|
}
|
|
|
|
pAction =NextAction();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bool bPathStroke = (pCommentAct->GetComment() == "XPATHSTROKE_SEQ_BEGIN");
|
|
if ( bPathStroke || pCommentAct->GetComment() == "XPATHFILL_SEQ_BEGIN" )
|
|
{
|
|
if ( pCommentAct->GetDataSize() )
|
|
{
|
|
SvMemoryStream aMemStm( const_cast<sal_uInt8 *>(pCommentAct->GetData()), pCommentAct->GetDataSize(), StreamMode::READ );
|
|
SvMemoryStream aDest;
|
|
if ( bPathStroke )
|
|
{
|
|
SvtGraphicStroke aStroke;
|
|
ReadSvtGraphicStroke( aMemStm, aStroke );
|
|
tools::Polygon aPath;
|
|
aStroke.getPath( aPath );
|
|
aStroke.setPath( ImplGetRotatedPolygon( aPath, aRotAnchor, aRotOffset, fSin, fCos ) );
|
|
WriteSvtGraphicStroke( aDest, aStroke );
|
|
aMtf.AddAction( new MetaCommentAction( "XPATHSTROKE_SEQ_BEGIN", 0,
|
|
static_cast<const sal_uInt8*>( aDest.GetData()), aDest.Tell() ) );
|
|
}
|
|
else
|
|
{
|
|
SvtGraphicFill aFill;
|
|
ReadSvtGraphicFill( aMemStm, aFill );
|
|
tools::PolyPolygon aPath;
|
|
aFill.getPath( aPath );
|
|
aFill.setPath( ImplGetRotatedPolyPolygon( aPath, aRotAnchor, aRotOffset, fSin, fCos ) );
|
|
WriteSvtGraphicFill( aDest, aFill );
|
|
aMtf.AddAction( new MetaCommentAction( "XPATHFILL_SEQ_BEGIN", 0,
|
|
static_cast<const sal_uInt8*>( aDest.GetData()), aDest.Tell() ) );
|
|
}
|
|
}
|
|
}
|
|
else if ( pCommentAct->GetComment() == "XPATHSTROKE_SEQ_END"
|
|
|| pCommentAct->GetComment() == "XPATHFILL_SEQ_END" )
|
|
{
|
|
pAction->Execute( aMapVDev.get() );
|
|
aMtf.AddAction( pAction );
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::HATCH:
|
|
{
|
|
MetaHatchAction* pAct = static_cast<MetaHatchAction*>(pAction);
|
|
Hatch aHatch( pAct->GetHatch() );
|
|
|
|
aHatch.SetAngle( aHatch.GetAngle() + static_cast<sal_uInt16>(nAngle10) );
|
|
aMtf.AddAction( new MetaHatchAction( ImplGetRotatedPolyPolygon( pAct->GetPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ),
|
|
aHatch ) );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::Transparent:
|
|
{
|
|
MetaTransparentAction* pAct = static_cast<MetaTransparentAction*>(pAction);
|
|
aMtf.AddAction( new MetaTransparentAction( ImplGetRotatedPolyPolygon( pAct->GetPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ),
|
|
pAct->GetTransparence() ) );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::FLOATTRANSPARENT:
|
|
{
|
|
MetaFloatTransparentAction* pAct = static_cast<MetaFloatTransparentAction*>(pAction);
|
|
GDIMetaFile aTransMtf( pAct->GetGDIMetaFile() );
|
|
tools::Polygon aMtfPoly( ImplGetRotatedPolygon( tools::Rectangle( pAct->GetPoint(), pAct->GetSize() ), aRotAnchor, aRotOffset, fSin, fCos ) );
|
|
tools::Rectangle aMtfRect( aMtfPoly.GetBoundRect() );
|
|
|
|
aTransMtf.Rotate( nAngle10 );
|
|
aMtf.AddAction( new MetaFloatTransparentAction( aTransMtf, aMtfRect.TopLeft(), aMtfRect.GetSize(),
|
|
pAct->GetGradient() ) );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::EPS:
|
|
{
|
|
MetaEPSAction* pAct = static_cast<MetaEPSAction*>(pAction);
|
|
GDIMetaFile aEPSMtf( pAct->GetSubstitute() );
|
|
tools::Polygon aEPSPoly( ImplGetRotatedPolygon( tools::Rectangle( pAct->GetPoint(), pAct->GetSize() ), aRotAnchor, aRotOffset, fSin, fCos ) );
|
|
tools::Rectangle aEPSRect( aEPSPoly.GetBoundRect() );
|
|
|
|
aEPSMtf.Rotate( nAngle10 );
|
|
aMtf.AddAction( new MetaEPSAction( aEPSRect.TopLeft(), aEPSRect.GetSize(),
|
|
pAct->GetLink(), aEPSMtf ) );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::CLIPREGION:
|
|
{
|
|
MetaClipRegionAction* pAct = static_cast<MetaClipRegionAction*>(pAction);
|
|
|
|
if( pAct->IsClipping() && pAct->GetRegion().HasPolyPolygonOrB2DPolyPolygon() )
|
|
aMtf.AddAction( new MetaClipRegionAction( vcl::Region( ImplGetRotatedPolyPolygon( pAct->GetRegion().GetAsPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ) ), true ) );
|
|
else
|
|
{
|
|
aMtf.AddAction( pAction );
|
|
}
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::ISECTRECTCLIPREGION:
|
|
{
|
|
MetaISectRectClipRegionAction* pAct = static_cast<MetaISectRectClipRegionAction*>(pAction);
|
|
aMtf.AddAction( new MetaISectRegionClipRegionAction(vcl::Region(
|
|
ImplGetRotatedPolygon( pAct->GetRect(), aRotAnchor,
|
|
aRotOffset, fSin, fCos )) ) );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::ISECTREGIONCLIPREGION:
|
|
{
|
|
MetaISectRegionClipRegionAction* pAct = static_cast<MetaISectRegionClipRegionAction*>(pAction);
|
|
const vcl::Region& rRegion = pAct->GetRegion();
|
|
|
|
if( rRegion.HasPolyPolygonOrB2DPolyPolygon() )
|
|
aMtf.AddAction( new MetaISectRegionClipRegionAction( vcl::Region( ImplGetRotatedPolyPolygon( rRegion.GetAsPolyPolygon(), aRotAnchor, aRotOffset, fSin, fCos ) ) ) );
|
|
else
|
|
{
|
|
aMtf.AddAction( pAction );
|
|
}
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::REFPOINT:
|
|
{
|
|
MetaRefPointAction* pAct = static_cast<MetaRefPointAction*>(pAction);
|
|
aMtf.AddAction( new MetaRefPointAction( ImplGetRotatedPoint( pAct->GetRefPoint(), aRotAnchor, aRotOffset, fSin, fCos ), pAct->IsSetting() ) );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::FONT:
|
|
{
|
|
MetaFontAction* pAct = static_cast<MetaFontAction*>(pAction);
|
|
vcl::Font aFont( pAct->GetFont() );
|
|
|
|
aFont.SetOrientation( aFont.GetOrientation() + static_cast<sal_uInt16>(nAngle10) );
|
|
aMtf.AddAction( new MetaFontAction( aFont ) );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::BMP:
|
|
case MetaActionType::BMPEX:
|
|
case MetaActionType::MASK:
|
|
case MetaActionType::MASKSCALE:
|
|
case MetaActionType::MASKSCALEPART:
|
|
case MetaActionType::WALLPAPER:
|
|
case MetaActionType::TEXTRECT:
|
|
case MetaActionType::MOVECLIPREGION:
|
|
{
|
|
OSL_FAIL( "GDIMetaFile::Rotate(): unsupported action" );
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
pAction->Execute( aMapVDev.get() );
|
|
aMtf.AddAction( pAction );
|
|
|
|
// update rotation point and offset, if necessary
|
|
if( ( MetaActionType::MAPMODE == nActionType ) ||
|
|
( MetaActionType::PUSH == nActionType ) ||
|
|
( MetaActionType::POP == nActionType ) )
|
|
{
|
|
aRotAnchor = OutputDevice::LogicToLogic( aOrigin, m_aPrefMapMode, aMapVDev->GetMapMode() );
|
|
aRotOffset = OutputDevice::LogicToLogic( aOffset, m_aPrefMapMode, aMapVDev->GetMapMode() );
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
aMtf.m_aPrefMapMode = m_aPrefMapMode;
|
|
aMtf.m_aPrefSize = aNewBound.GetSize();
|
|
|
|
*this = aMtf;
|
|
|
|
}
|
|
|
|
static void ImplActionBounds( tools::Rectangle& o_rOutBounds,
|
|
const tools::Rectangle& i_rInBounds,
|
|
const std::vector<tools::Rectangle>& i_rClipStack,
|
|
tools::Rectangle* o_pHairline )
|
|
{
|
|
tools::Rectangle aBounds( i_rInBounds );
|
|
if( ! i_rInBounds.IsEmpty() && ! i_rClipStack.empty() && ! i_rClipStack.back().IsEmpty() )
|
|
aBounds.Intersection( i_rClipStack.back() );
|
|
if( ! aBounds.IsEmpty() )
|
|
{
|
|
if( ! o_rOutBounds.IsEmpty() )
|
|
o_rOutBounds.Union( aBounds );
|
|
else
|
|
o_rOutBounds = aBounds;
|
|
|
|
if(o_pHairline)
|
|
{
|
|
if( ! o_pHairline->IsEmpty() )
|
|
o_pHairline->Union( aBounds );
|
|
else
|
|
*o_pHairline = aBounds;
|
|
}
|
|
}
|
|
}
|
|
|
|
tools::Rectangle GDIMetaFile::GetBoundRect( OutputDevice& i_rReference, tools::Rectangle* pHairline ) const
|
|
{
|
|
ScopedVclPtrInstance< VirtualDevice > aMapVDev( i_rReference );
|
|
|
|
aMapVDev->EnableOutput( false );
|
|
aMapVDev->SetMapMode( GetPrefMapMode() );
|
|
|
|
std::vector<tools::Rectangle> aClipStack( 1, tools::Rectangle() );
|
|
std::vector<PushFlags> aPushFlagStack;
|
|
|
|
tools::Rectangle aBound;
|
|
|
|
if(pHairline)
|
|
*pHairline = tools::Rectangle();
|
|
|
|
const sal_uLong nCount(GetActionSize());
|
|
|
|
for(sal_uLong a(0); a < nCount; a++)
|
|
{
|
|
MetaAction* pAction = GetAction(a);
|
|
const MetaActionType nActionType = pAction->GetType();
|
|
tools::Rectangle* pUseHairline = (pHairline && aMapVDev->IsLineColor()) ? pHairline : nullptr;
|
|
|
|
switch( nActionType )
|
|
{
|
|
case MetaActionType::PIXEL:
|
|
{
|
|
MetaPixelAction* pAct = static_cast<MetaPixelAction*>(pAction);
|
|
ImplActionBounds( aBound,
|
|
tools::Rectangle( OutputDevice::LogicToLogic( pAct->GetPoint(), aMapVDev->GetMapMode(), GetPrefMapMode() ),
|
|
aMapVDev->PixelToLogic( Size( 1, 1 ), GetPrefMapMode() ) ),
|
|
aClipStack, pUseHairline );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::POINT:
|
|
{
|
|
MetaPointAction* pAct = static_cast<MetaPointAction*>(pAction);
|
|
ImplActionBounds( aBound,
|
|
tools::Rectangle( OutputDevice::LogicToLogic( pAct->GetPoint(), aMapVDev->GetMapMode(), GetPrefMapMode() ),
|
|
aMapVDev->PixelToLogic( Size( 1, 1 ), GetPrefMapMode() ) ),
|
|
aClipStack, pUseHairline );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::LINE:
|
|
{
|
|
MetaLineAction* pAct = static_cast<MetaLineAction*>(pAction);
|
|
Point aP1( pAct->GetStartPoint() ), aP2( pAct->GetEndPoint() );
|
|
tools::Rectangle aRect( aP1, aP2 );
|
|
aRect.Justify();
|
|
|
|
if(pUseHairline)
|
|
{
|
|
const LineInfo& rLineInfo = pAct->GetLineInfo();
|
|
|
|
if(0 != rLineInfo.GetWidth())
|
|
pUseHairline = nullptr;
|
|
}
|
|
|
|
ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::RECT:
|
|
{
|
|
MetaRectAction* pAct = static_cast<MetaRectAction*>(pAction);
|
|
ImplActionBounds( aBound, OutputDevice::LogicToLogic( pAct->GetRect(), aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::ROUNDRECT:
|
|
{
|
|
MetaRoundRectAction* pAct = static_cast<MetaRoundRectAction*>(pAction);
|
|
ImplActionBounds( aBound, OutputDevice::LogicToLogic( pAct->GetRect(), aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::ELLIPSE:
|
|
{
|
|
MetaEllipseAction* pAct = static_cast<MetaEllipseAction*>(pAction);
|
|
ImplActionBounds( aBound, OutputDevice::LogicToLogic( pAct->GetRect(), aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::ARC:
|
|
{
|
|
MetaArcAction* pAct = static_cast<MetaArcAction*>(pAction);
|
|
// FIXME: this is imprecise
|
|
// e.g. for small arcs the whole rectangle is WAY too large
|
|
ImplActionBounds( aBound, OutputDevice::LogicToLogic( pAct->GetRect(), aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::PIE:
|
|
{
|
|
MetaPieAction* pAct = static_cast<MetaPieAction*>(pAction);
|
|
// FIXME: this is imprecise
|
|
// e.g. for small arcs the whole rectangle is WAY too large
|
|
ImplActionBounds( aBound, OutputDevice::LogicToLogic( pAct->GetRect(), aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::CHORD:
|
|
{
|
|
MetaChordAction* pAct = static_cast<MetaChordAction*>(pAction);
|
|
// FIXME: this is imprecise
|
|
// e.g. for small arcs the whole rectangle is WAY too large
|
|
ImplActionBounds( aBound, OutputDevice::LogicToLogic( pAct->GetRect(), aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::POLYLINE:
|
|
{
|
|
MetaPolyLineAction* pAct = static_cast<MetaPolyLineAction*>(pAction);
|
|
tools::Rectangle aRect( pAct->GetPolygon().GetBoundRect() );
|
|
|
|
if(pUseHairline)
|
|
{
|
|
const LineInfo& rLineInfo = pAct->GetLineInfo();
|
|
|
|
if(0 != rLineInfo.GetWidth())
|
|
pUseHairline = nullptr;
|
|
}
|
|
|
|
ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::POLYGON:
|
|
{
|
|
MetaPolygonAction* pAct = static_cast<MetaPolygonAction*>(pAction);
|
|
tools::Rectangle aRect( pAct->GetPolygon().GetBoundRect() );
|
|
ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::POLYPOLYGON:
|
|
{
|
|
MetaPolyPolygonAction* pAct = static_cast<MetaPolyPolygonAction*>(pAction);
|
|
tools::Rectangle aRect( pAct->GetPolyPolygon().GetBoundRect() );
|
|
ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::TEXT:
|
|
{
|
|
MetaTextAction* pAct = static_cast<MetaTextAction*>(pAction);
|
|
tools::Rectangle aRect;
|
|
// hdu said base = index
|
|
aMapVDev->GetTextBoundRect( aRect, pAct->GetText(), pAct->GetIndex(), pAct->GetIndex(), pAct->GetLen() );
|
|
Point aPt( pAct->GetPoint() );
|
|
aRect.Move( aPt.X(), aPt.Y() );
|
|
ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::TEXTARRAY:
|
|
{
|
|
MetaTextArrayAction* pAct = static_cast<MetaTextArrayAction*>(pAction);
|
|
tools::Rectangle aRect;
|
|
// hdu said base = index
|
|
aMapVDev->GetTextBoundRect( aRect, pAct->GetText(), pAct->GetIndex(), pAct->GetIndex(), pAct->GetLen(),
|
|
0, pAct->GetDXArray() );
|
|
Point aPt( pAct->GetPoint() );
|
|
aRect.Move( aPt.X(), aPt.Y() );
|
|
ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::STRETCHTEXT:
|
|
{
|
|
MetaStretchTextAction* pAct = static_cast<MetaStretchTextAction*>(pAction);
|
|
tools::Rectangle aRect;
|
|
// hdu said base = index
|
|
aMapVDev->GetTextBoundRect( aRect, pAct->GetText(), pAct->GetIndex(), pAct->GetIndex(), pAct->GetLen(),
|
|
pAct->GetWidth() );
|
|
Point aPt( pAct->GetPoint() );
|
|
aRect.Move( aPt.X(), aPt.Y() );
|
|
ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::TEXTLINE:
|
|
{
|
|
MetaTextLineAction* pAct = static_cast<MetaTextLineAction*>(pAction);
|
|
// measure a test string to get ascend and descent right
|
|
static const sal_Unicode pStr[] = { 0xc4, 0x67, 0 };
|
|
OUString aStr( pStr );
|
|
|
|
tools::Rectangle aRect;
|
|
aMapVDev->GetTextBoundRect( aRect, aStr, 0, 0, aStr.getLength() );
|
|
Point aPt( pAct->GetStartPoint() );
|
|
aRect.Move( aPt.X(), aPt.Y() );
|
|
aRect.SetRight( aRect.Left() + pAct->GetWidth() );
|
|
ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::BMPSCALE:
|
|
{
|
|
MetaBmpScaleAction* pAct = static_cast<MetaBmpScaleAction*>(pAction);
|
|
tools::Rectangle aRect( pAct->GetPoint(), pAct->GetSize() );
|
|
ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::BMPSCALEPART:
|
|
{
|
|
MetaBmpScalePartAction* pAct = static_cast<MetaBmpScalePartAction*>(pAction);
|
|
tools::Rectangle aRect( pAct->GetDestPoint(), pAct->GetDestSize() );
|
|
ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::BMPEXSCALE:
|
|
{
|
|
MetaBmpExScaleAction* pAct = static_cast<MetaBmpExScaleAction*>(pAction);
|
|
tools::Rectangle aRect( pAct->GetPoint(), pAct->GetSize() );
|
|
ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::BMPEXSCALEPART:
|
|
{
|
|
MetaBmpExScalePartAction* pAct = static_cast<MetaBmpExScalePartAction*>(pAction);
|
|
tools::Rectangle aRect( pAct->GetDestPoint(), pAct->GetDestSize() );
|
|
ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::GRADIENT:
|
|
{
|
|
MetaGradientAction* pAct = static_cast<MetaGradientAction*>(pAction);
|
|
tools::Rectangle aRect( pAct->GetRect() );
|
|
ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::GRADIENTEX:
|
|
{
|
|
MetaGradientExAction* pAct = static_cast<MetaGradientExAction*>(pAction);
|
|
tools::Rectangle aRect( pAct->GetPolyPolygon().GetBoundRect() );
|
|
ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::COMMENT:
|
|
{
|
|
// nothing to do
|
|
};
|
|
break;
|
|
|
|
case MetaActionType::HATCH:
|
|
{
|
|
MetaHatchAction* pAct = static_cast<MetaHatchAction*>(pAction);
|
|
tools::Rectangle aRect( pAct->GetPolyPolygon().GetBoundRect() );
|
|
ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::Transparent:
|
|
{
|
|
MetaTransparentAction* pAct = static_cast<MetaTransparentAction*>(pAction);
|
|
tools::Rectangle aRect( pAct->GetPolyPolygon().GetBoundRect() );
|
|
ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::FLOATTRANSPARENT:
|
|
{
|
|
MetaFloatTransparentAction* pAct = static_cast<MetaFloatTransparentAction*>(pAction);
|
|
// MetaFloatTransparentAction is defined limiting its content Metafile
|
|
// to its geometry definition(Point, Size), so use these directly
|
|
const tools::Rectangle aRect( pAct->GetPoint(), pAct->GetSize() );
|
|
ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::EPS:
|
|
{
|
|
MetaEPSAction* pAct = static_cast<MetaEPSAction*>(pAction);
|
|
tools::Rectangle aRect( pAct->GetPoint(), pAct->GetSize() );
|
|
ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::CLIPREGION:
|
|
{
|
|
MetaClipRegionAction* pAct = static_cast<MetaClipRegionAction*>(pAction);
|
|
if( pAct->IsClipping() )
|
|
aClipStack.back() = OutputDevice::LogicToLogic( pAct->GetRegion().GetBoundRect(), aMapVDev->GetMapMode(), GetPrefMapMode() );
|
|
else
|
|
aClipStack.back() = tools::Rectangle();
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::ISECTRECTCLIPREGION:
|
|
{
|
|
MetaISectRectClipRegionAction* pAct = static_cast<MetaISectRectClipRegionAction*>(pAction);
|
|
tools::Rectangle aRect( OutputDevice::LogicToLogic( pAct->GetRect(), aMapVDev->GetMapMode(), GetPrefMapMode() ) );
|
|
if( aClipStack.back().IsEmpty() )
|
|
aClipStack.back() = aRect;
|
|
else
|
|
aClipStack.back().Intersection( aRect );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::ISECTREGIONCLIPREGION:
|
|
{
|
|
MetaISectRegionClipRegionAction* pAct = static_cast<MetaISectRegionClipRegionAction*>(pAction);
|
|
tools::Rectangle aRect( OutputDevice::LogicToLogic( pAct->GetRegion().GetBoundRect(), aMapVDev->GetMapMode(), GetPrefMapMode() ) );
|
|
if( aClipStack.back().IsEmpty() )
|
|
aClipStack.back() = aRect;
|
|
else
|
|
aClipStack.back().Intersection( aRect );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::BMP:
|
|
{
|
|
MetaBmpAction* pAct = static_cast<MetaBmpAction*>(pAction);
|
|
tools::Rectangle aRect( pAct->GetPoint(), aMapVDev->PixelToLogic( pAct->GetBitmap().GetSizePixel() ) );
|
|
ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::BMPEX:
|
|
{
|
|
MetaBmpExAction* pAct = static_cast<MetaBmpExAction*>(pAction);
|
|
tools::Rectangle aRect( pAct->GetPoint(), aMapVDev->PixelToLogic( pAct->GetBitmapEx().GetSizePixel() ) );
|
|
ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::MASK:
|
|
{
|
|
MetaMaskAction* pAct = static_cast<MetaMaskAction*>(pAction);
|
|
tools::Rectangle aRect( pAct->GetPoint(), aMapVDev->PixelToLogic( pAct->GetBitmap().GetSizePixel() ) );
|
|
ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::MASKSCALE:
|
|
{
|
|
MetaMaskScalePartAction* pAct = static_cast<MetaMaskScalePartAction*>(pAction);
|
|
tools::Rectangle aRect( pAct->GetDestPoint(), pAct->GetDestSize() );
|
|
ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::MASKSCALEPART:
|
|
{
|
|
MetaMaskScalePartAction* pAct = static_cast<MetaMaskScalePartAction*>(pAction);
|
|
tools::Rectangle aRect( pAct->GetDestPoint(), pAct->GetDestSize() );
|
|
ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::WALLPAPER:
|
|
{
|
|
MetaWallpaperAction* pAct = static_cast<MetaWallpaperAction*>(pAction);
|
|
tools::Rectangle aRect( pAct->GetRect() );
|
|
ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::TEXTRECT:
|
|
{
|
|
MetaTextRectAction* pAct = static_cast<MetaTextRectAction*>(pAction);
|
|
tools::Rectangle aRect( pAct->GetRect() );
|
|
ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::MOVECLIPREGION:
|
|
{
|
|
MetaMoveClipRegionAction* pAct = static_cast<MetaMoveClipRegionAction*>(pAction);
|
|
if( ! aClipStack.back().IsEmpty() )
|
|
{
|
|
Size aDelta( pAct->GetHorzMove(), pAct->GetVertMove() );
|
|
aDelta = OutputDevice::LogicToLogic( aDelta, aMapVDev->GetMapMode(), GetPrefMapMode() );
|
|
aClipStack.back().Move( aDelta.Width(), aDelta.Width() );
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
pAction->Execute( aMapVDev.get() );
|
|
|
|
if( nActionType == MetaActionType::PUSH )
|
|
{
|
|
MetaPushAction* pAct = static_cast<MetaPushAction*>(pAction);
|
|
aPushFlagStack.push_back( pAct->GetFlags() );
|
|
if( aPushFlagStack.back() & PushFlags::CLIPREGION )
|
|
{
|
|
tools::Rectangle aRect( aClipStack.back() );
|
|
aClipStack.push_back( aRect );
|
|
}
|
|
}
|
|
else if( nActionType == MetaActionType::POP )
|
|
{
|
|
// sanity check
|
|
if( ! aPushFlagStack.empty() )
|
|
{
|
|
if( aPushFlagStack.back() & PushFlags::CLIPREGION )
|
|
{
|
|
if( aClipStack.size() > 1 )
|
|
aClipStack.pop_back();
|
|
}
|
|
aPushFlagStack.pop_back();
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return aBound;
|
|
}
|
|
|
|
Color GDIMetaFile::ImplColAdjustFnc( const Color& rColor, const void* pColParam )
|
|
{
|
|
return Color( rColor.GetTransparency(),
|
|
static_cast<const ImplColAdjustParam*>(pColParam)->pMapR[ rColor.GetRed() ],
|
|
static_cast<const ImplColAdjustParam*>(pColParam)->pMapG[ rColor.GetGreen() ],
|
|
static_cast<const ImplColAdjustParam*>(pColParam)->pMapB[ rColor.GetBlue() ] );
|
|
|
|
}
|
|
|
|
BitmapEx GDIMetaFile::ImplBmpAdjustFnc( const BitmapEx& rBmpEx, const void* pBmpParam )
|
|
{
|
|
const ImplBmpAdjustParam* p = static_cast<const ImplBmpAdjustParam*>(pBmpParam);
|
|
BitmapEx aRet( rBmpEx );
|
|
|
|
aRet.Adjust( p->nLuminancePercent, p->nContrastPercent,
|
|
p->nChannelRPercent, p->nChannelGPercent, p->nChannelBPercent,
|
|
p->fGamma, p->bInvert );
|
|
|
|
return aRet;
|
|
}
|
|
|
|
Color GDIMetaFile::ImplColConvertFnc( const Color& rColor, const void* pColParam )
|
|
{
|
|
sal_uInt8 cLum = rColor.GetLuminance();
|
|
|
|
if( MtfConversion::N1BitThreshold == static_cast<const ImplColConvertParam*>(pColParam)->eConversion )
|
|
cLum = ( cLum < 128 ) ? 0 : 255;
|
|
|
|
return Color( rColor.GetTransparency(), cLum, cLum, cLum );
|
|
}
|
|
|
|
BitmapEx GDIMetaFile::ImplBmpConvertFnc( const BitmapEx& rBmpEx, const void* pBmpParam )
|
|
{
|
|
BitmapEx aRet( rBmpEx );
|
|
|
|
aRet.Convert( static_cast<const ImplBmpConvertParam*>(pBmpParam)->eConversion );
|
|
|
|
return aRet;
|
|
}
|
|
|
|
Color GDIMetaFile::ImplColMonoFnc( const Color&, const void* pColParam )
|
|
{
|
|
return static_cast<const ImplColMonoParam*>(pColParam)->aColor;
|
|
}
|
|
|
|
BitmapEx GDIMetaFile::ImplBmpMonoFnc( const BitmapEx& rBmpEx, const void* pBmpParam )
|
|
{
|
|
BitmapPalette aPal( 3 );
|
|
|
|
aPal[ 0 ] = COL_BLACK;
|
|
aPal[ 1 ] = COL_WHITE;
|
|
aPal[ 2 ] = static_cast<const ImplBmpMonoParam*>(pBmpParam)->aColor;
|
|
|
|
Bitmap aBmp( rBmpEx.GetSizePixel(), 4, &aPal );
|
|
aBmp.Erase( static_cast<const ImplBmpMonoParam*>(pBmpParam)->aColor );
|
|
|
|
if( rBmpEx.IsAlpha() )
|
|
return BitmapEx( aBmp, rBmpEx.GetAlpha() );
|
|
else if( rBmpEx.IsTransparent() )
|
|
return BitmapEx( aBmp, rBmpEx.GetMask() );
|
|
else
|
|
return BitmapEx( aBmp );
|
|
}
|
|
|
|
Color GDIMetaFile::ImplColReplaceFnc( const Color& rColor, const void* pColParam )
|
|
{
|
|
const sal_uLong nR = rColor.GetRed(), nG = rColor.GetGreen(), nB = rColor.GetBlue();
|
|
|
|
for( sal_uLong i = 0; i < static_cast<const ImplColReplaceParam*>(pColParam)->nCount; i++ )
|
|
{
|
|
if( ( static_cast<const ImplColReplaceParam*>(pColParam)->pMinR[ i ] <= nR ) &&
|
|
( static_cast<const ImplColReplaceParam*>(pColParam)->pMaxR[ i ] >= nR ) &&
|
|
( static_cast<const ImplColReplaceParam*>(pColParam)->pMinG[ i ] <= nG ) &&
|
|
( static_cast<const ImplColReplaceParam*>(pColParam)->pMaxG[ i ] >= nG ) &&
|
|
( static_cast<const ImplColReplaceParam*>(pColParam)->pMinB[ i ] <= nB ) &&
|
|
( static_cast<const ImplColReplaceParam*>(pColParam)->pMaxB[ i ] >= nB ) )
|
|
{
|
|
return static_cast<const ImplColReplaceParam*>(pColParam)->pDstCols[ i ];
|
|
}
|
|
}
|
|
|
|
return rColor;
|
|
}
|
|
|
|
BitmapEx GDIMetaFile::ImplBmpReplaceFnc( const BitmapEx& rBmpEx, const void* pBmpParam )
|
|
{
|
|
const ImplBmpReplaceParam* p = static_cast<const ImplBmpReplaceParam*>(pBmpParam);
|
|
BitmapEx aRet( rBmpEx );
|
|
|
|
aRet.Replace( p->pSrcCols, p->pDstCols, p->nCount );
|
|
|
|
return aRet;
|
|
}
|
|
|
|
void GDIMetaFile::ImplExchangeColors( ColorExchangeFnc pFncCol, const void* pColParam,
|
|
BmpExchangeFnc pFncBmp, const void* pBmpParam )
|
|
{
|
|
GDIMetaFile aMtf;
|
|
|
|
aMtf.m_aPrefSize = m_aPrefSize;
|
|
aMtf.m_aPrefMapMode = m_aPrefMapMode;
|
|
aMtf.m_bUseCanvas = m_bUseCanvas;
|
|
|
|
for( MetaAction* pAction = FirstAction(); pAction; pAction = NextAction() )
|
|
{
|
|
const MetaActionType nType = pAction->GetType();
|
|
|
|
switch( nType )
|
|
{
|
|
case MetaActionType::PIXEL:
|
|
{
|
|
MetaPixelAction* pAct = static_cast<MetaPixelAction*>(pAction);
|
|
aMtf.push_back( new MetaPixelAction( pAct->GetPoint(), pFncCol( pAct->GetColor(), pColParam ) ) );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::LINECOLOR:
|
|
{
|
|
MetaLineColorAction* pAct = static_cast<MetaLineColorAction*>(pAction);
|
|
|
|
if( pAct->IsSetting() )
|
|
pAct = new MetaLineColorAction( pFncCol( pAct->GetColor(), pColParam ), true );
|
|
|
|
aMtf.push_back( pAct );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::FILLCOLOR:
|
|
{
|
|
MetaFillColorAction* pAct = static_cast<MetaFillColorAction*>(pAction);
|
|
|
|
if( pAct->IsSetting() )
|
|
pAct = new MetaFillColorAction( pFncCol( pAct->GetColor(), pColParam ), true );
|
|
|
|
aMtf.push_back( pAct );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::TEXTCOLOR:
|
|
{
|
|
MetaTextColorAction* pAct = static_cast<MetaTextColorAction*>(pAction);
|
|
aMtf.push_back( new MetaTextColorAction( pFncCol( pAct->GetColor(), pColParam ) ) );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::TEXTFILLCOLOR:
|
|
{
|
|
MetaTextFillColorAction* pAct = static_cast<MetaTextFillColorAction*>(pAction);
|
|
|
|
if( pAct->IsSetting() )
|
|
pAct = new MetaTextFillColorAction( pFncCol( pAct->GetColor(), pColParam ), true );
|
|
|
|
aMtf.push_back( pAct );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::TEXTLINECOLOR:
|
|
{
|
|
MetaTextLineColorAction* pAct = static_cast<MetaTextLineColorAction*>(pAction);
|
|
|
|
if( pAct->IsSetting() )
|
|
pAct = new MetaTextLineColorAction( pFncCol( pAct->GetColor(), pColParam ), true );
|
|
|
|
aMtf.push_back( pAct );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::OVERLINECOLOR:
|
|
{
|
|
MetaOverlineColorAction* pAct = static_cast<MetaOverlineColorAction*>(pAction);
|
|
|
|
if( pAct->IsSetting() )
|
|
pAct = new MetaOverlineColorAction( pFncCol( pAct->GetColor(), pColParam ), true );
|
|
|
|
aMtf.push_back( pAct );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::FONT:
|
|
{
|
|
MetaFontAction* pAct = static_cast<MetaFontAction*>(pAction);
|
|
vcl::Font aFont( pAct->GetFont() );
|
|
|
|
aFont.SetColor( pFncCol( aFont.GetColor(), pColParam ) );
|
|
aFont.SetFillColor( pFncCol( aFont.GetFillColor(), pColParam ) );
|
|
aMtf.push_back( new MetaFontAction( aFont ) );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::WALLPAPER:
|
|
{
|
|
MetaWallpaperAction* pAct = static_cast<MetaWallpaperAction*>(pAction);
|
|
Wallpaper aWall( pAct->GetWallpaper() );
|
|
const tools::Rectangle& rRect = pAct->GetRect();
|
|
|
|
aWall.SetColor( pFncCol( aWall.GetColor(), pColParam ) );
|
|
|
|
if( aWall.IsBitmap() )
|
|
aWall.SetBitmap( pFncBmp( aWall.GetBitmap(), pBmpParam ) );
|
|
|
|
if( aWall.IsGradient() )
|
|
{
|
|
Gradient aGradient( aWall.GetGradient() );
|
|
|
|
aGradient.SetStartColor( pFncCol( aGradient.GetStartColor(), pColParam ) );
|
|
aGradient.SetEndColor( pFncCol( aGradient.GetEndColor(), pColParam ) );
|
|
aWall.SetGradient( aGradient );
|
|
}
|
|
|
|
aMtf.push_back( new MetaWallpaperAction( rRect, aWall ) );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::BMP:
|
|
case MetaActionType::BMPEX:
|
|
case MetaActionType::MASK:
|
|
{
|
|
OSL_FAIL( "Don't use bitmap actions of this type in metafiles!" );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::BMPSCALE:
|
|
{
|
|
MetaBmpScaleAction* pAct = static_cast<MetaBmpScaleAction*>(pAction);
|
|
aMtf.push_back( new MetaBmpScaleAction( pAct->GetPoint(), pAct->GetSize(),
|
|
pFncBmp( BitmapEx(pAct->GetBitmap()), pBmpParam ).GetBitmap() ) );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::BMPSCALEPART:
|
|
{
|
|
MetaBmpScalePartAction* pAct = static_cast<MetaBmpScalePartAction*>(pAction);
|
|
aMtf.push_back( new MetaBmpScalePartAction( pAct->GetDestPoint(), pAct->GetDestSize(),
|
|
pAct->GetSrcPoint(), pAct->GetSrcSize(),
|
|
pFncBmp( BitmapEx(pAct->GetBitmap()), pBmpParam ).GetBitmap() )
|
|
);
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::BMPEXSCALE:
|
|
{
|
|
MetaBmpExScaleAction* pAct = static_cast<MetaBmpExScaleAction*>(pAction);
|
|
aMtf.push_back( new MetaBmpExScaleAction( pAct->GetPoint(), pAct->GetSize(),
|
|
pFncBmp( pAct->GetBitmapEx(), pBmpParam ) )
|
|
);
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::BMPEXSCALEPART:
|
|
{
|
|
MetaBmpExScalePartAction* pAct = static_cast<MetaBmpExScalePartAction*>(pAction);
|
|
aMtf.push_back( new MetaBmpExScalePartAction( pAct->GetDestPoint(), pAct->GetDestSize(),
|
|
pAct->GetSrcPoint(), pAct->GetSrcSize(),
|
|
pFncBmp( pAct->GetBitmapEx(), pBmpParam ) )
|
|
);
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::MASKSCALE:
|
|
{
|
|
MetaMaskScaleAction* pAct = static_cast<MetaMaskScaleAction*>(pAction);
|
|
aMtf.push_back( new MetaMaskScaleAction( pAct->GetPoint(), pAct->GetSize(),
|
|
pAct->GetBitmap(),
|
|
pFncCol( pAct->GetColor(), pColParam ) )
|
|
);
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::MASKSCALEPART:
|
|
{
|
|
MetaMaskScalePartAction* pAct = static_cast<MetaMaskScalePartAction*>(pAction);
|
|
aMtf.push_back( new MetaMaskScalePartAction( pAct->GetDestPoint(), pAct->GetDestSize(),
|
|
pAct->GetSrcPoint(), pAct->GetSrcSize(),
|
|
pAct->GetBitmap(),
|
|
pFncCol( pAct->GetColor(), pColParam ) )
|
|
);
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::GRADIENT:
|
|
{
|
|
MetaGradientAction* pAct = static_cast<MetaGradientAction*>(pAction);
|
|
Gradient aGradient( pAct->GetGradient() );
|
|
|
|
aGradient.SetStartColor( pFncCol( aGradient.GetStartColor(), pColParam ) );
|
|
aGradient.SetEndColor( pFncCol( aGradient.GetEndColor(), pColParam ) );
|
|
aMtf.push_back( new MetaGradientAction( pAct->GetRect(), aGradient ) );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::GRADIENTEX:
|
|
{
|
|
MetaGradientExAction* pAct = static_cast<MetaGradientExAction*>(pAction);
|
|
Gradient aGradient( pAct->GetGradient() );
|
|
|
|
aGradient.SetStartColor( pFncCol( aGradient.GetStartColor(), pColParam ) );
|
|
aGradient.SetEndColor( pFncCol( aGradient.GetEndColor(), pColParam ) );
|
|
aMtf.push_back( new MetaGradientExAction( pAct->GetPolyPolygon(), aGradient ) );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::HATCH:
|
|
{
|
|
MetaHatchAction* pAct = static_cast<MetaHatchAction*>(pAction);
|
|
Hatch aHatch( pAct->GetHatch() );
|
|
|
|
aHatch.SetColor( pFncCol( aHatch.GetColor(), pColParam ) );
|
|
aMtf.push_back( new MetaHatchAction( pAct->GetPolyPolygon(), aHatch ) );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::FLOATTRANSPARENT:
|
|
{
|
|
MetaFloatTransparentAction* pAct = static_cast<MetaFloatTransparentAction*>(pAction);
|
|
GDIMetaFile aTransMtf( pAct->GetGDIMetaFile() );
|
|
|
|
aTransMtf.ImplExchangeColors( pFncCol, pColParam, pFncBmp, pBmpParam );
|
|
aMtf.push_back( new MetaFloatTransparentAction( aTransMtf,
|
|
pAct->GetPoint(), pAct->GetSize(),
|
|
pAct->GetGradient() )
|
|
);
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::EPS:
|
|
{
|
|
MetaEPSAction* pAct = static_cast<MetaEPSAction*>(pAction);
|
|
GDIMetaFile aSubst( pAct->GetSubstitute() );
|
|
|
|
aSubst.ImplExchangeColors( pFncCol, pColParam, pFncBmp, pBmpParam );
|
|
aMtf.push_back( new MetaEPSAction( pAct->GetPoint(), pAct->GetSize(),
|
|
pAct->GetLink(), aSubst )
|
|
);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
aMtf.push_back( pAction );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
*this = aMtf;
|
|
}
|
|
|
|
void GDIMetaFile::Adjust( short nLuminancePercent, short nContrastPercent,
|
|
short nChannelRPercent, short nChannelGPercent,
|
|
short nChannelBPercent, double fGamma, bool bInvert, bool msoBrightness )
|
|
{
|
|
// nothing to do? => return quickly
|
|
if( !(nLuminancePercent || nContrastPercent ||
|
|
nChannelRPercent || nChannelGPercent || nChannelBPercent ||
|
|
( fGamma != 1.0 ) || bInvert) )
|
|
return;
|
|
|
|
double fM, fROff, fGOff, fBOff, fOff;
|
|
ImplColAdjustParam aColParam;
|
|
ImplBmpAdjustParam aBmpParam;
|
|
|
|
aColParam.pMapR.reset(new sal_uInt8[ 256 ]);
|
|
aColParam.pMapG.reset(new sal_uInt8[ 256 ]);
|
|
aColParam.pMapB.reset(new sal_uInt8[ 256 ]);
|
|
|
|
// calculate slope
|
|
if( nContrastPercent >= 0 )
|
|
fM = 128.0 / ( 128.0 - 1.27 * MinMax( nContrastPercent, 0, 100 ) );
|
|
else
|
|
fM = ( 128.0 + 1.27 * MinMax( nContrastPercent, -100, 0 ) ) / 128.0;
|
|
|
|
if(!msoBrightness)
|
|
// total offset = luminance offset + contrast offset
|
|
fOff = MinMax( nLuminancePercent, -100, 100 ) * 2.55 + 128.0 - fM * 128.0;
|
|
else
|
|
fOff = MinMax( nLuminancePercent, -100, 100 ) * 2.55;
|
|
|
|
// channel offset = channel offset + total offset
|
|
fROff = nChannelRPercent * 2.55 + fOff;
|
|
fGOff = nChannelGPercent * 2.55 + fOff;
|
|
fBOff = nChannelBPercent * 2.55 + fOff;
|
|
|
|
// calculate gamma value
|
|
fGamma = ( fGamma <= 0.0 || fGamma > 10.0 ) ? 1.0 : ( 1.0 / fGamma );
|
|
const bool bGamma = ( fGamma != 1.0 );
|
|
|
|
// create mapping table
|
|
for( long nX = 0; nX < 256; nX++ )
|
|
{
|
|
if(!msoBrightness)
|
|
{
|
|
aColParam.pMapR[ nX ] = static_cast<sal_uInt8>(MinMax( FRound( nX * fM + fROff ), 0, 255 ));
|
|
aColParam.pMapG[ nX ] = static_cast<sal_uInt8>(MinMax( FRound( nX * fM + fGOff ), 0, 255 ));
|
|
aColParam.pMapB[ nX ] = static_cast<sal_uInt8>(MinMax( FRound( nX * fM + fBOff ), 0, 255 ));
|
|
}
|
|
else
|
|
{
|
|
aColParam.pMapR[ nX ] = static_cast<sal_uInt8>(MinMax( FRound( (nX+fROff/2-128) * fM + 128 + fROff/2 ), 0, 255 ));
|
|
aColParam.pMapG[ nX ] = static_cast<sal_uInt8>(MinMax( FRound( (nX+fGOff/2-128) * fM + 128 + fGOff/2 ), 0, 255 ));
|
|
aColParam.pMapB[ nX ] = static_cast<sal_uInt8>(MinMax( FRound( (nX+fBOff/2-128) * fM + 128 + fBOff/2 ), 0, 255 ));
|
|
}
|
|
if( bGamma )
|
|
{
|
|
aColParam.pMapR[ nX ] = GAMMA( aColParam.pMapR[ nX ], fGamma );
|
|
aColParam.pMapG[ nX ] = GAMMA( aColParam.pMapG[ nX ], fGamma );
|
|
aColParam.pMapB[ nX ] = GAMMA( aColParam.pMapB[ nX ], fGamma );
|
|
}
|
|
|
|
if( bInvert )
|
|
{
|
|
aColParam.pMapR[ nX ] = ~aColParam.pMapR[ nX ];
|
|
aColParam.pMapG[ nX ] = ~aColParam.pMapG[ nX ];
|
|
aColParam.pMapB[ nX ] = ~aColParam.pMapB[ nX ];
|
|
}
|
|
}
|
|
|
|
aBmpParam.nLuminancePercent = nLuminancePercent;
|
|
aBmpParam.nContrastPercent = nContrastPercent;
|
|
aBmpParam.nChannelRPercent = nChannelRPercent;
|
|
aBmpParam.nChannelGPercent = nChannelGPercent;
|
|
aBmpParam.nChannelBPercent = nChannelBPercent;
|
|
aBmpParam.fGamma = fGamma;
|
|
aBmpParam.bInvert = bInvert;
|
|
|
|
// do color adjustment
|
|
ImplExchangeColors( ImplColAdjustFnc, &aColParam, ImplBmpAdjustFnc, &aBmpParam );
|
|
}
|
|
|
|
void GDIMetaFile::Convert( MtfConversion eConversion )
|
|
{
|
|
ImplColConvertParam aColParam;
|
|
ImplBmpConvertParam aBmpParam;
|
|
|
|
aColParam.eConversion = eConversion;
|
|
aBmpParam.eConversion = ( MtfConversion::N1BitThreshold == eConversion ) ? BmpConversion::N1BitThreshold : BmpConversion::N8BitGreys;
|
|
|
|
ImplExchangeColors( ImplColConvertFnc, &aColParam, ImplBmpConvertFnc, &aBmpParam );
|
|
}
|
|
|
|
void GDIMetaFile::ReplaceColors( const Color* pSearchColors, const Color* pReplaceColors, sal_uLong nColorCount )
|
|
{
|
|
ImplColReplaceParam aColParam;
|
|
ImplBmpReplaceParam aBmpParam;
|
|
|
|
aColParam.pMinR.reset(new sal_uLong[ nColorCount ]);
|
|
aColParam.pMaxR.reset(new sal_uLong[ nColorCount ]);
|
|
aColParam.pMinG.reset(new sal_uLong[ nColorCount ]);
|
|
aColParam.pMaxG.reset(new sal_uLong[ nColorCount ]);
|
|
aColParam.pMinB.reset(new sal_uLong[ nColorCount ]);
|
|
aColParam.pMaxB.reset(new sal_uLong[ nColorCount ]);
|
|
|
|
for( sal_uLong i = 0; i < nColorCount; i++ )
|
|
{
|
|
long nVal;
|
|
|
|
nVal = pSearchColors[ i ].GetRed();
|
|
aColParam.pMinR[ i ] = static_cast<sal_uLong>(std::max( nVal, 0L ));
|
|
aColParam.pMaxR[ i ] = static_cast<sal_uLong>(std::min( nVal, 255L ));
|
|
|
|
nVal = pSearchColors[ i ].GetGreen();
|
|
aColParam.pMinG[ i ] = static_cast<sal_uLong>(std::max( nVal, 0L ));
|
|
aColParam.pMaxG[ i ] = static_cast<sal_uLong>(std::min( nVal, 255L ));
|
|
|
|
nVal = pSearchColors[ i ].GetBlue();
|
|
aColParam.pMinB[ i ] = static_cast<sal_uLong>(std::max( nVal, 0L ));
|
|
aColParam.pMaxB[ i ] = static_cast<sal_uLong>(std::min( nVal, 255L ));
|
|
}
|
|
|
|
aColParam.pDstCols = pReplaceColors;
|
|
aColParam.nCount = nColorCount;
|
|
|
|
aBmpParam.pSrcCols = pSearchColors;
|
|
aBmpParam.pDstCols = pReplaceColors;
|
|
aBmpParam.nCount = nColorCount;
|
|
|
|
ImplExchangeColors( ImplColReplaceFnc, &aColParam, ImplBmpReplaceFnc, &aBmpParam );
|
|
};
|
|
|
|
GDIMetaFile GDIMetaFile::GetMonochromeMtf( const Color& rColor ) const
|
|
{
|
|
GDIMetaFile aRet( *this );
|
|
|
|
ImplColMonoParam aColParam;
|
|
ImplBmpMonoParam aBmpParam;
|
|
|
|
aColParam.aColor = rColor;
|
|
aBmpParam.aColor = rColor;
|
|
|
|
aRet.ImplExchangeColors( ImplColMonoFnc, &aColParam, ImplBmpMonoFnc, &aBmpParam );
|
|
|
|
return aRet;
|
|
}
|
|
|
|
BitmapChecksum GDIMetaFile::GetChecksum() const
|
|
{
|
|
SvMemoryStream aMemStm( 65535, 65535 );
|
|
ImplMetaWriteData aWriteData;
|
|
SVBT16 aBT16;
|
|
SVBT32 aBT32;
|
|
BitmapChecksumOctetArray aBCOA;
|
|
BitmapChecksum nCrc = 0;
|
|
|
|
aWriteData.meActualCharSet = aMemStm.GetStreamCharSet();
|
|
for( size_t i = 0, nObjCount = GetActionSize(); i < nObjCount; i++ )
|
|
{
|
|
MetaAction* pAction = GetAction( i );
|
|
|
|
switch( pAction->GetType() )
|
|
{
|
|
case MetaActionType::BMP:
|
|
{
|
|
MetaBmpAction* pAct = static_cast<MetaBmpAction*>(pAction);
|
|
|
|
ShortToSVBT16( static_cast<sal_uInt16>(pAct->GetType()), aBT16 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT16, 2 );
|
|
|
|
BCToBCOA( pAct->GetBitmap().GetChecksum(), aBCOA );
|
|
nCrc = vcl_get_checksum( nCrc, aBCOA, BITMAP_CHECKSUM_SIZE );
|
|
|
|
Int32ToSVBT32( pAct->GetPoint().X(), aBT32 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
|
|
|
|
Int32ToSVBT32( pAct->GetPoint().Y(), aBT32 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::BMPSCALE:
|
|
{
|
|
MetaBmpScaleAction* pAct = static_cast<MetaBmpScaleAction*>(pAction);
|
|
|
|
ShortToSVBT16( static_cast<sal_uInt16>(pAct->GetType()), aBT16 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT16, 2 );
|
|
|
|
BCToBCOA( pAct->GetBitmap().GetChecksum(), aBCOA );
|
|
nCrc = vcl_get_checksum( nCrc, aBCOA, BITMAP_CHECKSUM_SIZE );
|
|
|
|
Int32ToSVBT32( pAct->GetPoint().X(), aBT32 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
|
|
|
|
Int32ToSVBT32( pAct->GetPoint().Y(), aBT32 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
|
|
|
|
Int32ToSVBT32( pAct->GetSize().Width(), aBT32 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
|
|
|
|
Int32ToSVBT32( pAct->GetSize().Height(), aBT32 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::BMPSCALEPART:
|
|
{
|
|
MetaBmpScalePartAction* pAct = static_cast<MetaBmpScalePartAction*>(pAction);
|
|
|
|
ShortToSVBT16( static_cast<sal_uInt16>(pAct->GetType()), aBT16 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT16, 2 );
|
|
|
|
BCToBCOA( pAct->GetBitmap().GetChecksum(), aBCOA );
|
|
nCrc = vcl_get_checksum( nCrc, aBCOA, BITMAP_CHECKSUM_SIZE );
|
|
|
|
Int32ToSVBT32( pAct->GetDestPoint().X(), aBT32 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
|
|
|
|
Int32ToSVBT32( pAct->GetDestPoint().Y(), aBT32 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
|
|
|
|
Int32ToSVBT32( pAct->GetDestSize().Width(), aBT32 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
|
|
|
|
Int32ToSVBT32( pAct->GetDestSize().Height(), aBT32 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
|
|
|
|
Int32ToSVBT32( pAct->GetSrcPoint().X(), aBT32 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
|
|
|
|
Int32ToSVBT32( pAct->GetSrcPoint().Y(), aBT32 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
|
|
|
|
Int32ToSVBT32( pAct->GetSrcSize().Width(), aBT32 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
|
|
|
|
Int32ToSVBT32( pAct->GetSrcSize().Height(), aBT32 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::BMPEX:
|
|
{
|
|
MetaBmpExAction* pAct = static_cast<MetaBmpExAction*>(pAction);
|
|
|
|
ShortToSVBT16( static_cast<sal_uInt16>(pAct->GetType()), aBT16 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT16, 2 );
|
|
|
|
BCToBCOA( pAct->GetBitmapEx().GetChecksum(), aBCOA );
|
|
nCrc = vcl_get_checksum( nCrc, aBCOA, BITMAP_CHECKSUM_SIZE );
|
|
|
|
Int32ToSVBT32( pAct->GetPoint().X(), aBT32 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
|
|
|
|
Int32ToSVBT32( pAct->GetPoint().Y(), aBT32 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::BMPEXSCALE:
|
|
{
|
|
MetaBmpExScaleAction* pAct = static_cast<MetaBmpExScaleAction*>(pAction);
|
|
|
|
ShortToSVBT16( static_cast<sal_uInt16>(pAct->GetType()), aBT16 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT16, 2 );
|
|
|
|
BCToBCOA( pAct->GetBitmapEx().GetChecksum(), aBCOA );
|
|
nCrc = vcl_get_checksum( nCrc, aBCOA, BITMAP_CHECKSUM_SIZE );
|
|
|
|
Int32ToSVBT32( pAct->GetPoint().X(), aBT32 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
|
|
|
|
Int32ToSVBT32( pAct->GetPoint().Y(), aBT32 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
|
|
|
|
Int32ToSVBT32( pAct->GetSize().Width(), aBT32 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
|
|
|
|
Int32ToSVBT32( pAct->GetSize().Height(), aBT32 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::BMPEXSCALEPART:
|
|
{
|
|
MetaBmpExScalePartAction* pAct = static_cast<MetaBmpExScalePartAction*>(pAction);
|
|
|
|
ShortToSVBT16( static_cast<sal_uInt16>(pAct->GetType()), aBT16 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT16, 2 );
|
|
|
|
BCToBCOA( pAct->GetBitmapEx().GetChecksum(), aBCOA );
|
|
nCrc = vcl_get_checksum( nCrc, aBCOA, BITMAP_CHECKSUM_SIZE );
|
|
|
|
Int32ToSVBT32( pAct->GetDestPoint().X(), aBT32 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
|
|
|
|
Int32ToSVBT32( pAct->GetDestPoint().Y(), aBT32 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
|
|
|
|
Int32ToSVBT32( pAct->GetDestSize().Width(), aBT32 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
|
|
|
|
Int32ToSVBT32( pAct->GetDestSize().Height(), aBT32 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
|
|
|
|
Int32ToSVBT32( pAct->GetSrcPoint().X(), aBT32 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
|
|
|
|
Int32ToSVBT32( pAct->GetSrcPoint().Y(), aBT32 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
|
|
|
|
Int32ToSVBT32( pAct->GetSrcSize().Width(), aBT32 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
|
|
|
|
Int32ToSVBT32( pAct->GetSrcSize().Height(), aBT32 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::MASK:
|
|
{
|
|
MetaMaskAction* pAct = static_cast<MetaMaskAction*>(pAction);
|
|
|
|
ShortToSVBT16( static_cast<sal_uInt16>(pAct->GetType()), aBT16 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT16, 2 );
|
|
|
|
BCToBCOA( pAct->GetBitmap().GetChecksum(), aBCOA );
|
|
nCrc = vcl_get_checksum( nCrc, aBCOA, BITMAP_CHECKSUM_SIZE );
|
|
|
|
UInt32ToSVBT32( sal_uInt32(pAct->GetColor()), aBT32 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
|
|
|
|
Int32ToSVBT32( pAct->GetPoint().X(), aBT32 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
|
|
|
|
Int32ToSVBT32( pAct->GetPoint().Y(), aBT32 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::MASKSCALE:
|
|
{
|
|
MetaMaskScaleAction* pAct = static_cast<MetaMaskScaleAction*>(pAction);
|
|
|
|
ShortToSVBT16( static_cast<sal_uInt16>(pAct->GetType()), aBT16 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT16, 2 );
|
|
|
|
BCToBCOA( pAct->GetBitmap().GetChecksum(), aBCOA );
|
|
nCrc = vcl_get_checksum( nCrc, aBCOA, BITMAP_CHECKSUM_SIZE );
|
|
|
|
UInt32ToSVBT32( sal_uInt32(pAct->GetColor()), aBT32 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
|
|
|
|
Int32ToSVBT32( pAct->GetPoint().X(), aBT32 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
|
|
|
|
Int32ToSVBT32( pAct->GetPoint().Y(), aBT32 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
|
|
|
|
Int32ToSVBT32( pAct->GetSize().Width(), aBT32 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
|
|
|
|
Int32ToSVBT32( pAct->GetSize().Height(), aBT32 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::MASKSCALEPART:
|
|
{
|
|
MetaMaskScalePartAction* pAct = static_cast<MetaMaskScalePartAction*>(pAction);
|
|
|
|
ShortToSVBT16( static_cast<sal_uInt16>(pAct->GetType()), aBT16 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT16, 2 );
|
|
|
|
BCToBCOA( pAct->GetBitmap().GetChecksum(), aBCOA );
|
|
nCrc = vcl_get_checksum( nCrc, aBCOA, BITMAP_CHECKSUM_SIZE );
|
|
|
|
UInt32ToSVBT32( sal_uInt32(pAct->GetColor()), aBT32 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
|
|
|
|
Int32ToSVBT32( pAct->GetDestPoint().X(), aBT32 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
|
|
|
|
Int32ToSVBT32( pAct->GetDestPoint().Y(), aBT32 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
|
|
|
|
Int32ToSVBT32( pAct->GetDestSize().Width(), aBT32 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
|
|
|
|
Int32ToSVBT32( pAct->GetDestSize().Height(), aBT32 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
|
|
|
|
Int32ToSVBT32( pAct->GetSrcPoint().X(), aBT32 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
|
|
|
|
Int32ToSVBT32( pAct->GetSrcPoint().Y(), aBT32 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
|
|
|
|
Int32ToSVBT32( pAct->GetSrcSize().Width(), aBT32 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
|
|
|
|
Int32ToSVBT32( pAct->GetSrcSize().Height(), aBT32 );
|
|
nCrc = vcl_get_checksum( nCrc, aBT32, 4 );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::EPS :
|
|
{
|
|
MetaEPSAction* pAct = static_cast<MetaEPSAction*>(pAction);
|
|
nCrc = vcl_get_checksum( nCrc, pAct->GetLink().GetData(), pAct->GetLink().GetDataSize() );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::CLIPREGION :
|
|
{
|
|
MetaClipRegionAction& rAct = static_cast<MetaClipRegionAction&>(*pAction);
|
|
const vcl::Region& rRegion = rAct.GetRegion();
|
|
|
|
if(rRegion.HasPolyPolygonOrB2DPolyPolygon())
|
|
{
|
|
// It has shown that this is a possible bottleneck for checksum calculation.
|
|
// In worst case a very expensive RegionHandle representation gets created.
|
|
// In this case it's cheaper to use the PolyPolygon
|
|
const basegfx::B2DPolyPolygon aPolyPolygon(rRegion.GetAsB2DPolyPolygon());
|
|
SVBT64 aSVBT64;
|
|
|
|
for(auto const& rPolygon : aPolyPolygon)
|
|
{
|
|
const sal_uInt32 nPointCount(rPolygon.count());
|
|
const bool bControl(rPolygon.areControlPointsUsed());
|
|
|
|
for(sal_uInt32 b(0); b < nPointCount; b++)
|
|
{
|
|
const basegfx::B2DPoint aPoint(rPolygon.getB2DPoint(b));
|
|
|
|
DoubleToSVBT64(aPoint.getX(), aSVBT64);
|
|
nCrc = vcl_get_checksum(nCrc, aSVBT64, 8);
|
|
DoubleToSVBT64(aPoint.getY(), aSVBT64);
|
|
nCrc = vcl_get_checksum(nCrc, aSVBT64, 8);
|
|
|
|
if(bControl)
|
|
{
|
|
if(rPolygon.isPrevControlPointUsed(b))
|
|
{
|
|
const basegfx::B2DPoint aCtrl(rPolygon.getPrevControlPoint(b));
|
|
|
|
DoubleToSVBT64(aCtrl.getX(), aSVBT64);
|
|
nCrc = vcl_get_checksum(nCrc, aSVBT64, 8);
|
|
DoubleToSVBT64(aCtrl.getY(), aSVBT64);
|
|
nCrc = vcl_get_checksum(nCrc, aSVBT64, 8);
|
|
}
|
|
|
|
if(rPolygon.isNextControlPointUsed(b))
|
|
{
|
|
const basegfx::B2DPoint aCtrl(rPolygon.getNextControlPoint(b));
|
|
|
|
DoubleToSVBT64(aCtrl.getX(), aSVBT64);
|
|
nCrc = vcl_get_checksum(nCrc, aSVBT64, 8);
|
|
DoubleToSVBT64(aCtrl.getY(), aSVBT64);
|
|
nCrc = vcl_get_checksum(nCrc, aSVBT64, 8);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
sal_uInt8 tmp = static_cast<sal_uInt8>(rAct.IsClipping());
|
|
nCrc = vcl_get_checksum(nCrc, &tmp, 1);
|
|
}
|
|
else
|
|
{
|
|
pAction->Write( aMemStm, &aWriteData );
|
|
nCrc = vcl_get_checksum( nCrc, aMemStm.GetData(), aMemStm.Tell() );
|
|
aMemStm.Seek( 0 );
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
pAction->Write( aMemStm, &aWriteData );
|
|
nCrc = vcl_get_checksum( nCrc, aMemStm.GetData(), aMemStm.Tell() );
|
|
aMemStm.Seek( 0 );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return nCrc;
|
|
}
|
|
|
|
sal_uLong GDIMetaFile::GetSizeBytes() const
|
|
{
|
|
sal_uLong nSizeBytes = 0;
|
|
|
|
for( size_t i = 0, nObjCount = GetActionSize(); i < nObjCount; ++i )
|
|
{
|
|
MetaAction* pAction = GetAction( i );
|
|
|
|
// default action size is set to 32 (=> not the exact value)
|
|
nSizeBytes += 32;
|
|
|
|
// add sizes for large action content
|
|
switch( pAction->GetType() )
|
|
{
|
|
case MetaActionType::BMP: nSizeBytes += static_cast<MetaBmpAction*>( pAction )->GetBitmap().GetSizeBytes(); break;
|
|
case MetaActionType::BMPSCALE: nSizeBytes += static_cast<MetaBmpScaleAction*>( pAction )->GetBitmap().GetSizeBytes(); break;
|
|
case MetaActionType::BMPSCALEPART: nSizeBytes += static_cast<MetaBmpScalePartAction*>( pAction )->GetBitmap().GetSizeBytes(); break;
|
|
|
|
case MetaActionType::BMPEX: nSizeBytes += static_cast<MetaBmpExAction*>( pAction )->GetBitmapEx().GetSizeBytes(); break;
|
|
case MetaActionType::BMPEXSCALE: nSizeBytes += static_cast<MetaBmpExScaleAction*>( pAction )->GetBitmapEx().GetSizeBytes(); break;
|
|
case MetaActionType::BMPEXSCALEPART: nSizeBytes += static_cast<MetaBmpExScalePartAction*>( pAction )->GetBitmapEx().GetSizeBytes(); break;
|
|
|
|
case MetaActionType::MASK: nSizeBytes += static_cast<MetaMaskAction*>( pAction )->GetBitmap().GetSizeBytes(); break;
|
|
case MetaActionType::MASKSCALE: nSizeBytes += static_cast<MetaMaskScaleAction*>( pAction )->GetBitmap().GetSizeBytes(); break;
|
|
case MetaActionType::MASKSCALEPART: nSizeBytes += static_cast<MetaMaskScalePartAction*>( pAction )->GetBitmap().GetSizeBytes(); break;
|
|
|
|
case MetaActionType::POLYLINE: nSizeBytes += static_cast<MetaPolyLineAction*>( pAction )->GetPolygon().GetSize() * sizeof( Point ); break;
|
|
case MetaActionType::POLYGON: nSizeBytes += static_cast<MetaPolygonAction*>( pAction )->GetPolygon().GetSize() * sizeof( Point ); break;
|
|
case MetaActionType::POLYPOLYGON:
|
|
{
|
|
const tools::PolyPolygon& rPolyPoly = static_cast<MetaPolyPolygonAction*>( pAction )->GetPolyPolygon();
|
|
|
|
for( sal_uInt16 n = 0; n < rPolyPoly.Count(); ++n )
|
|
nSizeBytes += ( rPolyPoly[ n ].GetSize() * sizeof( Point ) );
|
|
}
|
|
break;
|
|
|
|
case MetaActionType::TEXT: nSizeBytes += static_cast<MetaTextAction*>( pAction )->GetText().getLength() * sizeof( sal_Unicode ); break;
|
|
case MetaActionType::STRETCHTEXT: nSizeBytes += static_cast<MetaStretchTextAction*>( pAction )->GetText().getLength() * sizeof( sal_Unicode ); break;
|
|
case MetaActionType::TEXTRECT: nSizeBytes += static_cast<MetaTextRectAction*>( pAction )->GetText().getLength() * sizeof( sal_Unicode ); break;
|
|
case MetaActionType::TEXTARRAY:
|
|
{
|
|
MetaTextArrayAction* pTextArrayAction = static_cast<MetaTextArrayAction*>(pAction);
|
|
|
|
nSizeBytes += ( pTextArrayAction->GetText().getLength() * sizeof( sal_Unicode ) );
|
|
|
|
if( pTextArrayAction->GetDXArray() )
|
|
nSizeBytes += ( pTextArrayAction->GetLen() << 2 );
|
|
}
|
|
break;
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
return nSizeBytes;
|
|
}
|
|
|
|
namespace
|
|
{
|
|
class DepthGuard
|
|
{
|
|
private:
|
|
ImplMetaReadData& m_rData;
|
|
rtl_TextEncoding m_eOrigCharSet;
|
|
public:
|
|
DepthGuard(ImplMetaReadData& rData, SvStream const & rIStm)
|
|
: m_rData(rData)
|
|
, m_eOrigCharSet(m_rData.meActualCharSet)
|
|
{
|
|
++m_rData.mnParseDepth;
|
|
m_rData.meActualCharSet = rIStm.GetStreamCharSet();
|
|
}
|
|
bool TooDeep() const { return m_rData.mnParseDepth > 1024; }
|
|
~DepthGuard()
|
|
{
|
|
--m_rData.mnParseDepth;
|
|
m_rData.meActualCharSet = m_eOrigCharSet;
|
|
}
|
|
};
|
|
}
|
|
|
|
SvStream& ReadGDIMetaFile(SvStream& rIStm, GDIMetaFile& rGDIMetaFile, ImplMetaReadData* pData)
|
|
{
|
|
if (rIStm.GetError())
|
|
{
|
|
SAL_WARN("vcl.gdi", "Stream error: " << rIStm.GetError());
|
|
return rIStm;
|
|
}
|
|
|
|
sal_uLong nStmPos = rIStm.Tell();
|
|
SvStreamEndian nOldFormat = rIStm.GetEndian();
|
|
|
|
rIStm.SetEndian( SvStreamEndian::LITTLE );
|
|
|
|
try
|
|
{
|
|
char aId[7];
|
|
aId[0] = 0;
|
|
aId[6] = 0;
|
|
rIStm.ReadBytes( aId, 6 );
|
|
|
|
if ( !strcmp( aId, "VCLMTF" ) )
|
|
{
|
|
// new format
|
|
sal_uInt32 nStmCompressMode = 0;
|
|
sal_uInt32 nCount = 0;
|
|
std::unique_ptr<VersionCompat> pCompat(new VersionCompat( rIStm, StreamMode::READ ));
|
|
|
|
rIStm.ReadUInt32( nStmCompressMode );
|
|
ReadMapMode( rIStm, rGDIMetaFile.m_aPrefMapMode );
|
|
TypeSerializer aSerializer(rIStm);
|
|
aSerializer.readSize(rGDIMetaFile.m_aPrefSize);
|
|
rIStm.ReadUInt32( nCount );
|
|
|
|
pCompat.reset(); // destructor writes stuff into the header
|
|
|
|
std::unique_ptr<ImplMetaReadData> xReadData;
|
|
if (!pData)
|
|
{
|
|
xReadData.reset(new ImplMetaReadData);
|
|
pData = xReadData.get();
|
|
}
|
|
DepthGuard aDepthGuard(*pData, rIStm);
|
|
|
|
if (aDepthGuard.TooDeep())
|
|
throw std::runtime_error("too much recursion");
|
|
|
|
for( sal_uInt32 nAction = 0; ( nAction < nCount ) && !rIStm.eof(); nAction++ )
|
|
{
|
|
MetaAction* pAction = MetaAction::ReadMetaAction(rIStm, pData);
|
|
if( pAction )
|
|
{
|
|
if (pAction->GetType() == MetaActionType::COMMENT)
|
|
{
|
|
MetaCommentAction* pCommentAct = static_cast<MetaCommentAction*>(pAction);
|
|
if ( pCommentAct->GetComment() == "EMF_PLUS" )
|
|
rGDIMetaFile.UseCanvas( true );
|
|
}
|
|
rGDIMetaFile.AddAction( pAction );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rIStm.Seek( nStmPos );
|
|
SVMConverter( rIStm, rGDIMetaFile );
|
|
}
|
|
}
|
|
catch (...)
|
|
{
|
|
SAL_WARN("vcl", "GDIMetaFile exception during load");
|
|
rIStm.SetError(SVSTREAM_FILEFORMAT_ERROR);
|
|
};
|
|
|
|
// check for errors
|
|
if( rIStm.GetError() )
|
|
{
|
|
rGDIMetaFile.Clear();
|
|
rIStm.Seek( nStmPos );
|
|
}
|
|
|
|
rIStm.SetEndian( nOldFormat );
|
|
return rIStm;
|
|
}
|
|
|
|
SvStream& WriteGDIMetaFile( SvStream& rOStm, const GDIMetaFile& rGDIMetaFile )
|
|
{
|
|
if( !rOStm.GetError() )
|
|
{
|
|
const_cast< GDIMetaFile& >( rGDIMetaFile ).Write( rOStm );
|
|
}
|
|
return rOStm;
|
|
}
|
|
|
|
SvStream& GDIMetaFile::Read( SvStream& rIStm )
|
|
{
|
|
Clear();
|
|
ReadGDIMetaFile( rIStm, *this );
|
|
|
|
return rIStm;
|
|
}
|
|
|
|
SvStream& GDIMetaFile::Write( SvStream& rOStm )
|
|
{
|
|
VersionCompat* pCompat;
|
|
const SvStreamCompressFlags nStmCompressMode = rOStm.GetCompressMode();
|
|
SvStreamEndian nOldFormat = rOStm.GetEndian();
|
|
|
|
rOStm.SetEndian( SvStreamEndian::LITTLE );
|
|
rOStm.WriteBytes( "VCLMTF", 6 );
|
|
|
|
pCompat = new VersionCompat( rOStm, StreamMode::WRITE, 1 );
|
|
|
|
rOStm.WriteUInt32( static_cast<sal_uInt32>(nStmCompressMode) );
|
|
WriteMapMode( rOStm, m_aPrefMapMode );
|
|
TypeSerializer aSerializer(rOStm);
|
|
aSerializer.writeSize(m_aPrefSize);
|
|
rOStm.WriteUInt32( GetActionSize() );
|
|
|
|
delete pCompat;
|
|
|
|
ImplMetaWriteData aWriteData;
|
|
|
|
aWriteData.meActualCharSet = rOStm.GetStreamCharSet();
|
|
|
|
MetaAction* pAct = FirstAction();
|
|
while ( pAct )
|
|
{
|
|
pAct->Write( rOStm, &aWriteData );
|
|
pAct = NextAction();
|
|
}
|
|
|
|
rOStm.SetEndian( nOldFormat );
|
|
|
|
return rOStm;
|
|
}
|
|
|
|
bool GDIMetaFile::CreateThumbnail(BitmapEx& rBitmapEx, BmpConversion eColorConversion, BmpScaleFlag nScaleFlag) const
|
|
{
|
|
// initialization seems to be complicated but is used to avoid rounding errors
|
|
ScopedVclPtrInstance< VirtualDevice > aVDev;
|
|
const Point aNullPt;
|
|
const Point aTLPix( aVDev->LogicToPixel( aNullPt, GetPrefMapMode() ) );
|
|
const Point aBRPix( aVDev->LogicToPixel( Point( GetPrefSize().Width() - 1, GetPrefSize().Height() - 1 ), GetPrefMapMode() ) );
|
|
Size aDrawSize( aVDev->LogicToPixel( GetPrefSize(), GetPrefMapMode() ) );
|
|
Size aSizePix( labs( aBRPix.X() - aTLPix.X() ) + 1, labs( aBRPix.Y() - aTLPix.Y() ) + 1 );
|
|
sal_uInt32 nMaximumExtent = 256;
|
|
|
|
if (!rBitmapEx.IsEmpty())
|
|
rBitmapEx.SetEmpty();
|
|
|
|
// determine size that has the same aspect ratio as image size and
|
|
// fits into the rectangle determined by nMaximumExtent
|
|
if ( aSizePix.Width() && aSizePix.Height()
|
|
&& ( sal::static_int_cast< unsigned long >(aSizePix.Width()) >
|
|
nMaximumExtent ||
|
|
sal::static_int_cast< unsigned long >(aSizePix.Height()) >
|
|
nMaximumExtent ) )
|
|
{
|
|
const Size aOldSizePix( aSizePix );
|
|
double fWH = static_cast< double >( aSizePix.Width() ) / aSizePix.Height();
|
|
|
|
if ( fWH <= 1.0 )
|
|
{
|
|
aSizePix.setWidth( FRound( nMaximumExtent * fWH ) );
|
|
aSizePix.setHeight( nMaximumExtent );
|
|
}
|
|
else
|
|
{
|
|
aSizePix.setWidth( nMaximumExtent );
|
|
aSizePix.setHeight( FRound( nMaximumExtent / fWH ) );
|
|
}
|
|
|
|
aDrawSize.setWidth( FRound( ( static_cast< double >( aDrawSize.Width() ) * aSizePix.Width() ) / aOldSizePix.Width() ) );
|
|
aDrawSize.setHeight( FRound( ( static_cast< double >( aDrawSize.Height() ) * aSizePix.Height() ) / aOldSizePix.Height() ) );
|
|
}
|
|
|
|
// draw image(s) into VDev and get resulting image
|
|
// do it 4x larger to be able to scale it down & get beautiful antialias
|
|
Size aAntialiasSize(aSizePix.Width() * 4, aSizePix.Height() * 4);
|
|
if (aVDev->SetOutputSizePixel(aAntialiasSize))
|
|
{
|
|
// antialias: provide 4x larger size, and then scale down the result
|
|
Size aAntialias(aDrawSize.Width() * 4, aDrawSize.Height() * 4);
|
|
|
|
// draw metafile into VDev
|
|
const_cast<GDIMetaFile *>(this)->WindStart();
|
|
const_cast<GDIMetaFile *>(this)->Play(aVDev.get(), Point(), aAntialias);
|
|
|
|
// get paint bitmap
|
|
BitmapEx aBitmap( aVDev->GetBitmapEx( aNullPt, aVDev->GetOutputSizePixel() ) );
|
|
|
|
// scale down the image to the desired size - use the input scaler for the scaling operation
|
|
aBitmap.Scale(aDrawSize, nScaleFlag);
|
|
|
|
// convert to desired bitmap color format
|
|
Size aSize(aBitmap.GetSizePixel());
|
|
if (aSize.Width() && aSize.Height())
|
|
aBitmap.Convert(eColorConversion);
|
|
|
|
rBitmapEx = aBitmap;
|
|
}
|
|
|
|
return !rBitmapEx.IsEmpty();
|
|
}
|
|
|
|
void GDIMetaFile::UseCanvas( bool _bUseCanvas )
|
|
{
|
|
m_bUseCanvas = _bUseCanvas;
|
|
}
|
|
|
|
void GDIMetaFile::dumpAsXml(const char* pFileName) const
|
|
{
|
|
SvFileStream aStream(pFileName ? OUString::fromUtf8(pFileName) : OUString("file:///tmp/metafile.xml"),
|
|
StreamMode::STD_READWRITE | StreamMode::TRUNC);
|
|
assert(aStream.good());
|
|
MetafileXmlDump aDumper;
|
|
aDumper.dump(*this, aStream);
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|