...following up on 314f15bff0
"Extend
loplugin:external to warn about enums".
Cases where free functions were moved into an unnamed namespace along with a
class, to not break ADL, are in:
filter/source/svg/svgexport.cxx
sc/source/filter/excel/xelink.cxx
sc/source/filter/excel/xilink.cxx
svx/source/sdr/contact/viewobjectcontactofunocontrol.cxx
All other free functions mentioning moved classes appear to be harmless and not
give rise to (silent, even) ADL breakage. (One remaining TODO in
compilerplugins/clang/external.cxx is that derived classes are not covered by
computeAffectedTypes, even though they could also be affected by ADL-breakage---
but don't seem to be in any acutal case across the code base.)
For friend declarations using elaborate type specifiers, like
class C1 {};
class C2 { friend class C1; };
* If C2 (but not C1) is moved into an unnamed namespace, the friend declaration
must be changed to not use an elaborate type specifier (i.e., "friend C1;"; see
C++17 [namespace.memdef]/3: "If the name in a friend declaration is neither
qualified nor a template-id and the declaration is a function or an
elaborated-type-specifier, the lookup to determine whether the entity has been
previously declared shall not consider any scopes outside the innermost
enclosing namespace.")
* If C1 (but not C2) is moved into an unnamed namespace, the friend declaration
must be changed too, see <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71882>
"elaborated-type-specifier friend not looked up in unnamed namespace".
Apart from that, to keep changes simple and mostly mechanical (which should help
avoid regressions), out-of-line definitions of class members have been left in
the enclosing (named) namespace. But explicit specializations of class
templates had to be moved into the unnamed namespace to appease
<https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92598> "explicit specialization of
template from unnamed namespace using unqualified-id in enclosing namespace".
Also, accompanying declarations (of e.g. typedefs or static variables) that
could arguably be moved into the unnamed namespace too have been left alone.
And in some cases, mention of affected types in blacklists in other loplugins
needed to be adapted.
And sc/qa/unit/mark_test.cxx uses a hack of including other .cxx, one of which
is sc/source/core/data/segmenttree.cxx where e.g. ScFlatUInt16SegmentsImpl is
not moved into an unnamed namespace (because it is declared in
sc/inc/segmenttree.hxx), but its base ScFlatSegmentsImpl is. GCC warns about
such combinations with enabled-by-default -Wsubobject-linkage, but "The compiler
doesn’t give this warning for types defined in the main .C file, as those are
unlikely to have multiple definitions."
(<https://gcc.gnu.org/onlinedocs/gcc-9.2.0/gcc/Warning-Options.html>) The
warned-about classes also don't have multiple definitions in the given test, so
disable the warning when including the .cxx.
Change-Id: Ib694094c0d8168be68f8fe90dfd0acbb66a3f1e4
Reviewed-on: https://gerrit.libreoffice.org/83239
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
891 lines
35 KiB
C++
891 lines
35 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 <vcl/canvastools.hxx>
|
|
#include <vcl/pdfextoutdevdata.hxx>
|
|
#include <vcl/graph.hxx>
|
|
#include <vcl/outdev.hxx>
|
|
#include <vcl/gfxlink.hxx>
|
|
#include <vcl/metaact.hxx>
|
|
#include <vcl/graphicfilter.hxx>
|
|
#include <basegfx/polygon/b2dpolygon.hxx>
|
|
#include <basegfx/polygon/b2dpolygontools.hxx>
|
|
#include <sal/log.hxx>
|
|
#include <osl/diagnose.h>
|
|
#include <tools/stream.hxx>
|
|
|
|
#include <memory>
|
|
#include <map>
|
|
|
|
namespace vcl
|
|
{
|
|
namespace {
|
|
|
|
struct PDFExtOutDevDataSync
|
|
{
|
|
enum Action{ CreateNamedDest,
|
|
CreateDest,
|
|
CreateLink,
|
|
CreateScreen,
|
|
SetLinkDest,
|
|
SetLinkURL,
|
|
SetScreenURL,
|
|
SetScreenStream,
|
|
RegisterDest,
|
|
CreateOutlineItem,
|
|
CreateNote,
|
|
SetPageTransition,
|
|
|
|
BeginStructureElement,
|
|
EndStructureElement,
|
|
SetCurrentStructureElement,
|
|
SetStructureAttribute,
|
|
SetStructureAttributeNumerical,
|
|
SetStructureBoundingBox,
|
|
SetActualText,
|
|
SetAlternateText,
|
|
CreateControl,
|
|
BeginGroup,
|
|
EndGroupGfxLink
|
|
};
|
|
|
|
sal_uInt32 nIdx;
|
|
Action eAct;
|
|
};
|
|
|
|
struct PDFLinkDestination
|
|
{
|
|
tools::Rectangle mRect;
|
|
MapMode mMapMode;
|
|
sal_Int32 mPageNr;
|
|
PDFWriter::DestAreaType mAreaType;
|
|
};
|
|
|
|
}
|
|
|
|
struct GlobalSyncData
|
|
{
|
|
std::deque< PDFExtOutDevDataSync::Action > mActions;
|
|
std::deque< MapMode > mParaMapModes;
|
|
std::deque< tools::Rectangle > mParaRects;
|
|
std::deque< sal_Int32 > mParaInts;
|
|
std::deque< sal_uInt32 > mParauInts;
|
|
std::deque< OUString > mParaOUStrings;
|
|
std::deque< PDFWriter::DestAreaType > mParaDestAreaTypes;
|
|
std::deque< PDFNote > mParaPDFNotes;
|
|
std::deque< PDFWriter::PageTransition > mParaPageTransitions;
|
|
::std::map< sal_Int32, PDFLinkDestination > mFutureDestinations;
|
|
|
|
sal_Int32 GetMappedId();
|
|
sal_Int32 GetMappedStructId( sal_Int32 );
|
|
|
|
sal_Int32 mCurId;
|
|
std::vector< sal_Int32 > mParaIds;
|
|
std::vector< sal_Int32 > mStructIdMap;
|
|
|
|
sal_Int32 mCurrentStructElement;
|
|
std::vector< sal_Int32 > mStructParents;
|
|
GlobalSyncData() :
|
|
mCurId ( 0 ),
|
|
mCurrentStructElement( 0 )
|
|
{
|
|
mStructParents.push_back( 0 );
|
|
mStructIdMap.push_back( 0 );
|
|
}
|
|
void PlayGlobalActions( PDFWriter& rWriter );
|
|
};
|
|
|
|
sal_Int32 GlobalSyncData::GetMappedId()
|
|
{
|
|
sal_Int32 nLinkId = mParaInts.front();
|
|
mParaInts.pop_front();
|
|
|
|
/* negative values are intentionally passed as invalid IDs
|
|
* e.g. to create a new top level outline item
|
|
*/
|
|
if( nLinkId >= 0 )
|
|
{
|
|
if ( static_cast<sal_uInt32>(nLinkId) < mParaIds.size() )
|
|
nLinkId = mParaIds[ nLinkId ];
|
|
else
|
|
nLinkId = -1;
|
|
|
|
SAL_WARN_IF( nLinkId < 0, "vcl", "unmapped id in GlobalSyncData" );
|
|
}
|
|
|
|
return nLinkId;
|
|
}
|
|
|
|
sal_Int32 GlobalSyncData::GetMappedStructId( sal_Int32 nStructId )
|
|
{
|
|
if ( static_cast<sal_uInt32>(nStructId) < mStructIdMap.size() )
|
|
nStructId = mStructIdMap[ nStructId ];
|
|
else
|
|
nStructId = -1;
|
|
|
|
SAL_WARN_IF( nStructId < 0, "vcl", "unmapped structure id in GlobalSyncData" );
|
|
|
|
return nStructId;
|
|
}
|
|
|
|
void GlobalSyncData::PlayGlobalActions( PDFWriter& rWriter )
|
|
{
|
|
for (auto const& action : mActions)
|
|
{
|
|
switch (action)
|
|
{
|
|
case PDFExtOutDevDataSync::CreateNamedDest : //i56629
|
|
{
|
|
rWriter.Push( PushFlags::MAPMODE );
|
|
rWriter.SetMapMode( mParaMapModes.front() );
|
|
mParaMapModes.pop_front();
|
|
mParaIds.push_back( rWriter.CreateNamedDest( mParaOUStrings.front(), mParaRects.front(), mParaInts.front(), mParaDestAreaTypes.front() ) );
|
|
mParaOUStrings.pop_front();
|
|
mParaRects.pop_front();
|
|
mParaInts.pop_front();
|
|
mParaDestAreaTypes.pop_front();
|
|
rWriter.Pop();
|
|
}
|
|
break;
|
|
case PDFExtOutDevDataSync::CreateDest :
|
|
{
|
|
rWriter.Push( PushFlags::MAPMODE );
|
|
rWriter.SetMapMode( mParaMapModes.front() );
|
|
mParaMapModes.pop_front();
|
|
mParaIds.push_back( rWriter.CreateDest( mParaRects.front(), mParaInts.front(), mParaDestAreaTypes.front() ) );
|
|
mParaRects.pop_front();
|
|
mParaInts.pop_front();
|
|
mParaDestAreaTypes.pop_front();
|
|
rWriter.Pop();
|
|
}
|
|
break;
|
|
case PDFExtOutDevDataSync::CreateLink :
|
|
{
|
|
rWriter.Push( PushFlags::MAPMODE );
|
|
rWriter.SetMapMode( mParaMapModes.front() );
|
|
mParaMapModes.pop_front();
|
|
mParaIds.push_back( rWriter.CreateLink( mParaRects.front(), mParaInts.front() ) );
|
|
// resolve LinkAnnotation structural attribute
|
|
rWriter.SetLinkPropertyID( mParaIds.back(), sal_Int32(mParaIds.size()-1) );
|
|
mParaRects.pop_front();
|
|
mParaInts.pop_front();
|
|
rWriter.Pop();
|
|
}
|
|
break;
|
|
case PDFExtOutDevDataSync::CreateScreen:
|
|
{
|
|
rWriter.Push(PushFlags::MAPMODE);
|
|
rWriter.SetMapMode(mParaMapModes.front());
|
|
mParaMapModes.pop_front();
|
|
mParaIds.push_back(rWriter.CreateScreen(mParaRects.front(), mParaInts.front()));
|
|
mParaRects.pop_front();
|
|
mParaInts.pop_front();
|
|
rWriter.Pop();
|
|
}
|
|
break;
|
|
case PDFExtOutDevDataSync::SetLinkDest :
|
|
{
|
|
sal_Int32 nLinkId = GetMappedId();
|
|
sal_Int32 nDestId = GetMappedId();
|
|
rWriter.SetLinkDest( nLinkId, nDestId );
|
|
}
|
|
break;
|
|
case PDFExtOutDevDataSync::SetLinkURL :
|
|
{
|
|
sal_Int32 nLinkId = GetMappedId();
|
|
rWriter.SetLinkURL( nLinkId, mParaOUStrings.front() );
|
|
mParaOUStrings.pop_front();
|
|
}
|
|
break;
|
|
case PDFExtOutDevDataSync::SetScreenURL:
|
|
{
|
|
sal_Int32 nScreenId = GetMappedId();
|
|
rWriter.SetScreenURL(nScreenId, mParaOUStrings.front());
|
|
mParaOUStrings.pop_front();
|
|
}
|
|
break;
|
|
case PDFExtOutDevDataSync::SetScreenStream:
|
|
{
|
|
sal_Int32 nScreenId = GetMappedId();
|
|
rWriter.SetScreenStream(nScreenId, mParaOUStrings.front());
|
|
mParaOUStrings.pop_front();
|
|
}
|
|
break;
|
|
case PDFExtOutDevDataSync::RegisterDest :
|
|
{
|
|
const sal_Int32 nDestId = mParaInts.front();
|
|
mParaInts.pop_front();
|
|
OSL_ENSURE( mFutureDestinations.find( nDestId ) != mFutureDestinations.end(),
|
|
"GlobalSyncData::PlayGlobalActions: DescribeRegisteredRequest has not been called for that destination!" );
|
|
|
|
PDFLinkDestination& rDest = mFutureDestinations[ nDestId ];
|
|
|
|
rWriter.Push( PushFlags::MAPMODE );
|
|
rWriter.SetMapMode( rDest.mMapMode );
|
|
mParaIds.push_back( rWriter.RegisterDestReference( nDestId, rDest.mRect, rDest.mPageNr, rDest.mAreaType ) );
|
|
rWriter.Pop();
|
|
}
|
|
break;
|
|
case PDFExtOutDevDataSync::CreateOutlineItem :
|
|
{
|
|
sal_Int32 nParent = GetMappedId();
|
|
sal_Int32 nLinkId = GetMappedId();
|
|
mParaIds.push_back( rWriter.CreateOutlineItem( nParent, mParaOUStrings.front(), nLinkId ) );
|
|
mParaOUStrings.pop_front();
|
|
}
|
|
break;
|
|
case PDFExtOutDevDataSync::CreateNote :
|
|
{
|
|
rWriter.Push( PushFlags::MAPMODE );
|
|
rWriter.SetMapMode( mParaMapModes.front() );
|
|
rWriter.CreateNote( mParaRects.front(), mParaPDFNotes.front(), mParaInts.front() );
|
|
mParaMapModes.pop_front();
|
|
mParaRects.pop_front();
|
|
mParaPDFNotes.pop_front();
|
|
mParaInts.pop_front();
|
|
}
|
|
break;
|
|
case PDFExtOutDevDataSync::SetPageTransition :
|
|
{
|
|
rWriter.SetPageTransition( mParaPageTransitions.front(), mParauInts.front(), mParaInts.front() );
|
|
mParaPageTransitions.pop_front();
|
|
mParauInts.pop_front();
|
|
mParaInts.pop_front();
|
|
}
|
|
break;
|
|
case PDFExtOutDevDataSync::BeginStructureElement:
|
|
case PDFExtOutDevDataSync::EndStructureElement:
|
|
case PDFExtOutDevDataSync::SetCurrentStructureElement:
|
|
case PDFExtOutDevDataSync::SetStructureAttribute:
|
|
case PDFExtOutDevDataSync::SetStructureAttributeNumerical:
|
|
case PDFExtOutDevDataSync::SetStructureBoundingBox:
|
|
case PDFExtOutDevDataSync::SetActualText:
|
|
case PDFExtOutDevDataSync::SetAlternateText:
|
|
case PDFExtOutDevDataSync::CreateControl:
|
|
case PDFExtOutDevDataSync::BeginGroup:
|
|
case PDFExtOutDevDataSync::EndGroupGfxLink:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
struct PageSyncData
|
|
{
|
|
std::deque< PDFExtOutDevDataSync > mActions;
|
|
std::deque< tools::Rectangle > mParaRects;
|
|
std::deque< sal_Int32 > mParaInts;
|
|
std::deque< OUString > mParaOUStrings;
|
|
std::deque< PDFWriter::StructElement > mParaStructElements;
|
|
std::deque< PDFWriter::StructAttribute > mParaStructAttributes;
|
|
std::deque< PDFWriter::StructAttributeValue > mParaStructAttributeValues;
|
|
std::deque< Graphic > mGraphics;
|
|
Graphic mCurrentGraphic;
|
|
std::deque< std::shared_ptr< PDFWriter::AnyWidget > >
|
|
mControls;
|
|
GlobalSyncData* mpGlobalData;
|
|
|
|
bool mbGroupIgnoreGDIMtfActions;
|
|
|
|
|
|
explicit PageSyncData( GlobalSyncData* pGlobal )
|
|
: mbGroupIgnoreGDIMtfActions ( false )
|
|
{ mpGlobalData = pGlobal; }
|
|
|
|
void PushAction( const OutputDevice& rOutDev, const PDFExtOutDevDataSync::Action eAct );
|
|
bool PlaySyncPageAct( PDFWriter& rWriter, sal_uInt32& rCurGDIMtfAction, const GDIMetaFile& rMtf, const PDFExtOutDevData& rOutDevData );
|
|
};
|
|
|
|
void PageSyncData::PushAction( const OutputDevice& rOutDev, const PDFExtOutDevDataSync::Action eAct )
|
|
{
|
|
GDIMetaFile* pMtf = rOutDev.GetConnectMetaFile();
|
|
SAL_WARN_IF( !pMtf, "vcl", "PageSyncData::PushAction -> no ConnectMetaFile !!!" );
|
|
|
|
PDFExtOutDevDataSync aSync;
|
|
aSync.eAct = eAct;
|
|
if ( pMtf )
|
|
aSync.nIdx = pMtf->GetActionSize();
|
|
else
|
|
aSync.nIdx = 0x7fffffff; // sync not possible
|
|
mActions.push_back( aSync );
|
|
}
|
|
bool PageSyncData::PlaySyncPageAct( PDFWriter& rWriter, sal_uInt32& rCurGDIMtfAction, const GDIMetaFile& rMtf, const PDFExtOutDevData& rOutDevData )
|
|
{
|
|
bool bRet = false;
|
|
if ( !mActions.empty() && ( mActions.front().nIdx == rCurGDIMtfAction ) )
|
|
{
|
|
bRet = true;
|
|
PDFExtOutDevDataSync aDataSync = mActions.front();
|
|
mActions.pop_front();
|
|
switch( aDataSync.eAct )
|
|
{
|
|
case PDFExtOutDevDataSync::BeginStructureElement :
|
|
{
|
|
sal_Int32 nNewEl = rWriter.BeginStructureElement( mParaStructElements.front(), mParaOUStrings.front() ) ;
|
|
mParaStructElements.pop_front();
|
|
mParaOUStrings.pop_front();
|
|
mpGlobalData->mStructIdMap.push_back( nNewEl );
|
|
}
|
|
break;
|
|
case PDFExtOutDevDataSync::EndStructureElement :
|
|
{
|
|
rWriter.EndStructureElement();
|
|
}
|
|
break;
|
|
case PDFExtOutDevDataSync::SetCurrentStructureElement:
|
|
{
|
|
rWriter.SetCurrentStructureElement( mpGlobalData->GetMappedStructId( mParaInts.front() ) );
|
|
mParaInts.pop_front();
|
|
}
|
|
break;
|
|
case PDFExtOutDevDataSync::SetStructureAttribute :
|
|
{
|
|
rWriter.SetStructureAttribute( mParaStructAttributes.front(), mParaStructAttributeValues.front() );
|
|
mParaStructAttributeValues.pop_front();
|
|
mParaStructAttributes.pop_front();
|
|
}
|
|
break;
|
|
case PDFExtOutDevDataSync::SetStructureAttributeNumerical :
|
|
{
|
|
rWriter.SetStructureAttributeNumerical( mParaStructAttributes.front(), mParaInts.front() );
|
|
mParaStructAttributes.pop_front();
|
|
mParaInts.pop_front();
|
|
}
|
|
break;
|
|
case PDFExtOutDevDataSync::SetStructureBoundingBox :
|
|
{
|
|
rWriter.SetStructureBoundingBox( mParaRects.front() );
|
|
mParaRects.pop_front();
|
|
}
|
|
break;
|
|
case PDFExtOutDevDataSync::SetActualText :
|
|
{
|
|
rWriter.SetActualText( mParaOUStrings.front() );
|
|
mParaOUStrings.pop_front();
|
|
}
|
|
break;
|
|
case PDFExtOutDevDataSync::SetAlternateText :
|
|
{
|
|
rWriter.SetAlternateText( mParaOUStrings.front() );
|
|
mParaOUStrings.pop_front();
|
|
}
|
|
break;
|
|
case PDFExtOutDevDataSync::CreateControl:
|
|
{
|
|
std::shared_ptr< PDFWriter::AnyWidget > pControl( mControls.front() );
|
|
SAL_WARN_IF( !pControl.get(), "vcl", "PageSyncData::PlaySyncPageAct: invalid widget!" );
|
|
if ( pControl.get() )
|
|
rWriter.CreateControl( *pControl );
|
|
mControls.pop_front();
|
|
}
|
|
break;
|
|
case PDFExtOutDevDataSync::BeginGroup :
|
|
{
|
|
/* first determining if this BeginGroup is starting a GfxLink,
|
|
by searching for an EndGroup or an EndGroupGfxLink */
|
|
mbGroupIgnoreGDIMtfActions = false;
|
|
auto isStartingGfxLink = std::any_of(mActions.begin(), mActions.end(),
|
|
[](const PDFExtOutDevDataSync& rAction) { return rAction.eAct == PDFExtOutDevDataSync::EndGroupGfxLink; });
|
|
if ( isStartingGfxLink )
|
|
{
|
|
Graphic& rGraphic = mGraphics.front();
|
|
if ( rGraphic.IsGfxLink() && mParaRects.size() >= 2 )
|
|
{
|
|
GfxLinkType eType = rGraphic.GetGfxLink().GetType();
|
|
if ( eType == GfxLinkType::NativeJpg )
|
|
{
|
|
mbGroupIgnoreGDIMtfActions = rOutDevData.HasAdequateCompression(rGraphic, mParaRects[0], mParaRects[1]);
|
|
if ( !mbGroupIgnoreGDIMtfActions )
|
|
mCurrentGraphic = rGraphic;
|
|
}
|
|
else if ( eType == GfxLinkType::NativePng || eType == GfxLinkType::NativePdf )
|
|
{
|
|
if ( eType == GfxLinkType::NativePdf || rOutDevData.HasAdequateCompression(rGraphic, mParaRects[0], mParaRects[1]) )
|
|
mCurrentGraphic = rGraphic;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case PDFExtOutDevDataSync::EndGroupGfxLink :
|
|
{
|
|
tools::Rectangle aOutputRect, aVisibleOutputRect;
|
|
Graphic aGraphic( mGraphics.front() );
|
|
|
|
mGraphics.pop_front();
|
|
sal_Int32 nTransparency = mParaInts.front();
|
|
mParaInts.pop_front();
|
|
aOutputRect = mParaRects.front();
|
|
mParaRects.pop_front();
|
|
aVisibleOutputRect = mParaRects.front();
|
|
mParaRects.pop_front();
|
|
|
|
if ( mbGroupIgnoreGDIMtfActions )
|
|
{
|
|
bool bClippingNeeded = ( aOutputRect != aVisibleOutputRect ) && !aVisibleOutputRect.IsEmpty();
|
|
|
|
GfxLink aGfxLink( aGraphic.GetGfxLink() );
|
|
if ( aGfxLink.GetType() == GfxLinkType::NativeJpg )
|
|
{
|
|
if ( bClippingNeeded )
|
|
{
|
|
rWriter.Push();
|
|
basegfx::B2DPolyPolygon aRect( basegfx::utils::createPolygonFromRect(
|
|
vcl::unotools::b2DRectangleFromRectangle(aVisibleOutputRect) ) );
|
|
rWriter.SetClipRegion( aRect);
|
|
}
|
|
|
|
Bitmap aMask;
|
|
if (nTransparency)
|
|
{
|
|
AlphaMask aAlphaMask(aGraphic.GetSizePixel());
|
|
aAlphaMask.Erase(nTransparency);
|
|
aMask = aAlphaMask.GetBitmap();
|
|
}
|
|
|
|
SvMemoryStream aTmp;
|
|
const sal_uInt8* pData = aGfxLink.GetData();
|
|
sal_uInt32 nBytes = aGfxLink.GetDataSize();
|
|
if( pData && nBytes )
|
|
{
|
|
aTmp.WriteBytes( pData, nBytes );
|
|
|
|
// Look up the output rectangle from the previous
|
|
// bitmap scale action if possible. This has the
|
|
// correct position and size for images with a
|
|
// custom translation (Writer header) or scaling
|
|
// (Impress notes page).
|
|
if (rCurGDIMtfAction > 0)
|
|
{
|
|
const MetaAction* pAction = rMtf.GetAction(rCurGDIMtfAction - 1);
|
|
if (pAction && pAction->GetType() == MetaActionType::BMPSCALE)
|
|
{
|
|
const MetaBmpScaleAction* pA
|
|
= static_cast<const MetaBmpScaleAction*>(pAction);
|
|
aOutputRect.SetPos(pA->GetPoint());
|
|
aOutputRect.SetSize(pA->GetSize());
|
|
}
|
|
}
|
|
|
|
rWriter.DrawJPGBitmap( aTmp, aGraphic.GetBitmapEx().GetBitCount() > 8, aGraphic.GetSizePixel(), aOutputRect, aMask, aGraphic );
|
|
}
|
|
|
|
if ( bClippingNeeded )
|
|
rWriter.Pop();
|
|
}
|
|
mbGroupIgnoreGDIMtfActions = false;
|
|
}
|
|
mCurrentGraphic.Clear();
|
|
}
|
|
break;
|
|
case PDFExtOutDevDataSync::CreateNamedDest:
|
|
case PDFExtOutDevDataSync::CreateDest:
|
|
case PDFExtOutDevDataSync::CreateLink:
|
|
case PDFExtOutDevDataSync::CreateScreen:
|
|
case PDFExtOutDevDataSync::SetLinkDest:
|
|
case PDFExtOutDevDataSync::SetLinkURL:
|
|
case PDFExtOutDevDataSync::SetScreenURL:
|
|
case PDFExtOutDevDataSync::SetScreenStream:
|
|
case PDFExtOutDevDataSync::RegisterDest:
|
|
case PDFExtOutDevDataSync::CreateOutlineItem:
|
|
case PDFExtOutDevDataSync::CreateNote:
|
|
case PDFExtOutDevDataSync::SetPageTransition:
|
|
break;
|
|
}
|
|
}
|
|
else if ( mbGroupIgnoreGDIMtfActions )
|
|
{
|
|
rCurGDIMtfAction++;
|
|
bRet = true;
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
PDFExtOutDevData::PDFExtOutDevData( const OutputDevice& rOutDev ) :
|
|
mrOutDev ( rOutDev ),
|
|
mbTaggedPDF ( false ),
|
|
mbExportNotes ( true ),
|
|
mbExportNotesPages ( false ),
|
|
mbTransitionEffects ( true ),
|
|
mbUseLosslessCompression( true ),
|
|
mbReduceImageResolution ( false ),
|
|
mbExportFormFields ( false ),
|
|
mbExportBookmarks ( false ),
|
|
mbExportHiddenSlides ( false ),
|
|
mbSinglePageSheets ( false ),
|
|
mbExportNDests ( false ),
|
|
mnPage ( -1 ),
|
|
mnCompressionQuality ( 90 ),
|
|
mpGlobalSyncData ( new GlobalSyncData() )
|
|
{
|
|
mpPageSyncData.reset( new PageSyncData( mpGlobalSyncData.get() ) );
|
|
}
|
|
|
|
PDFExtOutDevData::~PDFExtOutDevData()
|
|
{
|
|
mpPageSyncData.reset();
|
|
mpGlobalSyncData.reset();
|
|
}
|
|
|
|
const Graphic& PDFExtOutDevData::GetCurrentGraphic() const
|
|
{
|
|
return mpPageSyncData->mCurrentGraphic;
|
|
}
|
|
|
|
void PDFExtOutDevData::SetDocumentLocale( const css::lang::Locale& rLoc )
|
|
{
|
|
maDocLocale = rLoc;
|
|
}
|
|
void PDFExtOutDevData::SetCurrentPageNumber( const sal_Int32 nPage )
|
|
{
|
|
mnPage = nPage;
|
|
}
|
|
void PDFExtOutDevData::SetIsLosslessCompression( const bool bUseLosslessCompression )
|
|
{
|
|
mbUseLosslessCompression = bUseLosslessCompression;
|
|
}
|
|
void PDFExtOutDevData::SetCompressionQuality( const sal_Int32 nQuality )
|
|
{
|
|
mnCompressionQuality = nQuality;
|
|
}
|
|
void PDFExtOutDevData::SetIsReduceImageResolution( const bool bReduceImageResolution )
|
|
{
|
|
mbReduceImageResolution = bReduceImageResolution;
|
|
}
|
|
void PDFExtOutDevData::SetIsExportNotes( const bool bExportNotes )
|
|
{
|
|
mbExportNotes = bExportNotes;
|
|
}
|
|
void PDFExtOutDevData::SetIsExportNotesPages( const bool bExportNotesPages )
|
|
{
|
|
mbExportNotesPages = bExportNotesPages;
|
|
}
|
|
void PDFExtOutDevData::SetIsExportTaggedPDF( const bool bTaggedPDF )
|
|
{
|
|
mbTaggedPDF = bTaggedPDF;
|
|
}
|
|
void PDFExtOutDevData::SetIsExportTransitionEffects( const bool bTransitionEffects )
|
|
{
|
|
mbTransitionEffects = bTransitionEffects;
|
|
}
|
|
void PDFExtOutDevData::SetIsExportFormFields( const bool bExportFomtFields )
|
|
{
|
|
mbExportFormFields = bExportFomtFields;
|
|
}
|
|
void PDFExtOutDevData::SetIsExportBookmarks( const bool bExportBookmarks )
|
|
{
|
|
mbExportBookmarks = bExportBookmarks;
|
|
}
|
|
void PDFExtOutDevData::SetIsExportHiddenSlides( const bool bExportHiddenSlides )
|
|
{
|
|
mbExportHiddenSlides = bExportHiddenSlides;
|
|
}
|
|
void PDFExtOutDevData::SetIsSinglePageSheets( const bool bSinglePageSheets )
|
|
{
|
|
mbSinglePageSheets = bSinglePageSheets;
|
|
}
|
|
void PDFExtOutDevData::SetIsExportNamedDestinations( const bool bExportNDests )
|
|
{
|
|
mbExportNDests = bExportNDests;
|
|
}
|
|
void PDFExtOutDevData::ResetSyncData()
|
|
{
|
|
*mpPageSyncData = PageSyncData( mpGlobalSyncData.get() );
|
|
}
|
|
bool PDFExtOutDevData::PlaySyncPageAct( PDFWriter& rWriter, sal_uInt32& rIdx, const GDIMetaFile& rMtf )
|
|
{
|
|
return mpPageSyncData->PlaySyncPageAct( rWriter, rIdx, rMtf, *this );
|
|
}
|
|
void PDFExtOutDevData::PlayGlobalActions( PDFWriter& rWriter )
|
|
{
|
|
mpGlobalSyncData->PlayGlobalActions( rWriter );
|
|
}
|
|
|
|
/* global actions, synchronisation to the recorded metafile isn't needed,
|
|
all actions will be played after the last page was recorded
|
|
*/
|
|
//--->i56629
|
|
sal_Int32 PDFExtOutDevData::CreateNamedDest(const OUString& sDestName, const tools::Rectangle& rRect, sal_Int32 nPageNr )
|
|
{
|
|
mpGlobalSyncData->mActions.push_back( PDFExtOutDevDataSync::CreateNamedDest );
|
|
mpGlobalSyncData->mParaOUStrings.push_back( sDestName );
|
|
mpGlobalSyncData->mParaRects.push_back( rRect );
|
|
mpGlobalSyncData->mParaMapModes.push_back( mrOutDev.GetMapMode() );
|
|
mpGlobalSyncData->mParaInts.push_back( nPageNr == -1 ? mnPage : nPageNr );
|
|
mpGlobalSyncData->mParaDestAreaTypes.push_back( PDFWriter::DestAreaType::XYZ );
|
|
|
|
return mpGlobalSyncData->mCurId++;
|
|
}
|
|
//<---i56629
|
|
sal_Int32 PDFExtOutDevData::RegisterDest()
|
|
{
|
|
const sal_Int32 nLinkDestID = mpGlobalSyncData->mCurId++;
|
|
mpGlobalSyncData->mActions.push_back( PDFExtOutDevDataSync::RegisterDest );
|
|
mpGlobalSyncData->mParaInts.push_back( nLinkDestID );
|
|
|
|
return nLinkDestID;
|
|
}
|
|
void PDFExtOutDevData::DescribeRegisteredDest( sal_Int32 nDestId, const tools::Rectangle& rRect, sal_Int32 nPageNr, PDFWriter::DestAreaType eType )
|
|
{
|
|
OSL_PRECOND( nDestId != -1, "PDFExtOutDevData::DescribeRegisteredDest: invalid destination Id!" );
|
|
PDFLinkDestination aLinkDestination;
|
|
aLinkDestination.mRect = rRect;
|
|
aLinkDestination.mMapMode = mrOutDev.GetMapMode();
|
|
aLinkDestination.mPageNr = nPageNr == -1 ? mnPage : nPageNr;
|
|
aLinkDestination.mAreaType = eType;
|
|
mpGlobalSyncData->mFutureDestinations[ nDestId ] = aLinkDestination;
|
|
}
|
|
sal_Int32 PDFExtOutDevData::CreateDest( const tools::Rectangle& rRect, sal_Int32 nPageNr, PDFWriter::DestAreaType eType )
|
|
{
|
|
mpGlobalSyncData->mActions.push_back( PDFExtOutDevDataSync::CreateDest );
|
|
mpGlobalSyncData->mParaRects.push_back( rRect );
|
|
mpGlobalSyncData->mParaMapModes.push_back( mrOutDev.GetMapMode() );
|
|
mpGlobalSyncData->mParaInts.push_back( nPageNr == -1 ? mnPage : nPageNr );
|
|
mpGlobalSyncData->mParaDestAreaTypes.push_back( eType );
|
|
return mpGlobalSyncData->mCurId++;
|
|
}
|
|
sal_Int32 PDFExtOutDevData::CreateLink( const tools::Rectangle& rRect, sal_Int32 nPageNr )
|
|
{
|
|
mpGlobalSyncData->mActions.push_back( PDFExtOutDevDataSync::CreateLink );
|
|
mpGlobalSyncData->mParaRects.push_back( rRect );
|
|
mpGlobalSyncData->mParaMapModes.push_back( mrOutDev.GetMapMode() );
|
|
mpGlobalSyncData->mParaInts.push_back( nPageNr == -1 ? mnPage : nPageNr );
|
|
return mpGlobalSyncData->mCurId++;
|
|
}
|
|
|
|
sal_Int32 PDFExtOutDevData::CreateScreen(const tools::Rectangle& rRect, sal_Int32 nPageNr)
|
|
{
|
|
mpGlobalSyncData->mActions.push_back(PDFExtOutDevDataSync::CreateScreen);
|
|
mpGlobalSyncData->mParaRects.push_back(rRect);
|
|
mpGlobalSyncData->mParaMapModes.push_back(mrOutDev.GetMapMode());
|
|
mpGlobalSyncData->mParaInts.push_back(nPageNr);
|
|
return mpGlobalSyncData->mCurId++;
|
|
}
|
|
|
|
void PDFExtOutDevData::SetLinkDest( sal_Int32 nLinkId, sal_Int32 nDestId )
|
|
{
|
|
mpGlobalSyncData->mActions.push_back( PDFExtOutDevDataSync::SetLinkDest );
|
|
mpGlobalSyncData->mParaInts.push_back( nLinkId );
|
|
mpGlobalSyncData->mParaInts.push_back( nDestId );
|
|
}
|
|
void PDFExtOutDevData::SetLinkURL( sal_Int32 nLinkId, const OUString& rURL )
|
|
{
|
|
mpGlobalSyncData->mActions.push_back( PDFExtOutDevDataSync::SetLinkURL );
|
|
mpGlobalSyncData->mParaInts.push_back( nLinkId );
|
|
mpGlobalSyncData->mParaOUStrings.push_back( rURL );
|
|
}
|
|
|
|
void PDFExtOutDevData::SetScreenURL(sal_Int32 nScreenId, const OUString& rURL)
|
|
{
|
|
mpGlobalSyncData->mActions.push_back(PDFExtOutDevDataSync::SetScreenURL);
|
|
mpGlobalSyncData->mParaInts.push_back(nScreenId);
|
|
mpGlobalSyncData->mParaOUStrings.push_back(rURL);
|
|
}
|
|
|
|
void PDFExtOutDevData::SetScreenStream(sal_Int32 nScreenId, const OUString& rURL)
|
|
{
|
|
mpGlobalSyncData->mActions.push_back(PDFExtOutDevDataSync::SetScreenStream);
|
|
mpGlobalSyncData->mParaInts.push_back(nScreenId);
|
|
mpGlobalSyncData->mParaOUStrings.push_back(rURL);
|
|
}
|
|
|
|
sal_Int32 PDFExtOutDevData::CreateOutlineItem( sal_Int32 nParent, const OUString& rText, sal_Int32 nDestID )
|
|
{
|
|
if (nParent == -1)
|
|
// Has no parent, it's a chapter / heading 1.
|
|
maChapterNames.push_back(rText);
|
|
|
|
mpGlobalSyncData->mActions.push_back( PDFExtOutDevDataSync::CreateOutlineItem );
|
|
mpGlobalSyncData->mParaInts.push_back( nParent );
|
|
mpGlobalSyncData->mParaOUStrings.push_back( rText );
|
|
mpGlobalSyncData->mParaInts.push_back( nDestID );
|
|
return mpGlobalSyncData->mCurId++;
|
|
}
|
|
void PDFExtOutDevData::CreateNote( const tools::Rectangle& rRect, const PDFNote& rNote, sal_Int32 nPageNr )
|
|
{
|
|
mpGlobalSyncData->mActions.push_back( PDFExtOutDevDataSync::CreateNote );
|
|
mpGlobalSyncData->mParaRects.push_back( rRect );
|
|
mpGlobalSyncData->mParaMapModes.push_back( mrOutDev.GetMapMode() );
|
|
mpGlobalSyncData->mParaPDFNotes.push_back( rNote );
|
|
mpGlobalSyncData->mParaInts.push_back( nPageNr == -1 ? mnPage : nPageNr );
|
|
}
|
|
void PDFExtOutDevData::SetPageTransition( PDFWriter::PageTransition eType, sal_uInt32 nMilliSec )
|
|
{
|
|
mpGlobalSyncData->mActions.push_back( PDFExtOutDevDataSync::SetPageTransition );
|
|
mpGlobalSyncData->mParaPageTransitions.push_back( eType );
|
|
mpGlobalSyncData->mParauInts.push_back( nMilliSec );
|
|
mpGlobalSyncData->mParaInts.push_back( mnPage );
|
|
}
|
|
|
|
/* local (page), actions have to be played synchronously to the actions of
|
|
of the recorded metafile (created by each xRenderable->render()) */
|
|
sal_Int32 PDFExtOutDevData::BeginStructureElement( PDFWriter::StructElement eType, const OUString& rAlias )
|
|
{
|
|
mpPageSyncData->PushAction( mrOutDev, PDFExtOutDevDataSync::BeginStructureElement );
|
|
mpPageSyncData->mParaStructElements.push_back( eType );
|
|
mpPageSyncData->mParaOUStrings.push_back( rAlias );
|
|
// need a global id
|
|
sal_Int32 nNewId = mpGlobalSyncData->mStructParents.size();
|
|
mpGlobalSyncData->mStructParents.push_back( mpGlobalSyncData->mCurrentStructElement );
|
|
mpGlobalSyncData->mCurrentStructElement = nNewId;
|
|
return nNewId;
|
|
}
|
|
void PDFExtOutDevData::EndStructureElement()
|
|
{
|
|
mpPageSyncData->PushAction( mrOutDev, PDFExtOutDevDataSync::EndStructureElement );
|
|
mpGlobalSyncData->mCurrentStructElement = mpGlobalSyncData->mStructParents[ mpGlobalSyncData->mCurrentStructElement ];
|
|
}
|
|
bool PDFExtOutDevData::SetCurrentStructureElement( sal_Int32 nStructId )
|
|
{
|
|
bool bSuccess = false;
|
|
if( sal_uInt32(nStructId) < mpGlobalSyncData->mStructParents.size() )
|
|
{
|
|
mpGlobalSyncData->mCurrentStructElement = nStructId;
|
|
mpPageSyncData->PushAction( mrOutDev, PDFExtOutDevDataSync::SetCurrentStructureElement );
|
|
mpPageSyncData->mParaInts.push_back( nStructId );
|
|
bSuccess = true;
|
|
}
|
|
return bSuccess;
|
|
}
|
|
sal_Int32 PDFExtOutDevData::GetCurrentStructureElement() const
|
|
{
|
|
return mpGlobalSyncData->mCurrentStructElement;
|
|
}
|
|
void PDFExtOutDevData::SetStructureAttribute( PDFWriter::StructAttribute eAttr, PDFWriter::StructAttributeValue eVal )
|
|
{
|
|
mpPageSyncData->PushAction( mrOutDev, PDFExtOutDevDataSync::SetStructureAttribute );
|
|
mpPageSyncData->mParaStructAttributes.push_back( eAttr );
|
|
mpPageSyncData->mParaStructAttributeValues.push_back( eVal );
|
|
}
|
|
void PDFExtOutDevData::SetStructureAttributeNumerical( PDFWriter::StructAttribute eAttr, sal_Int32 nValue )
|
|
{
|
|
mpPageSyncData->PushAction( mrOutDev, PDFExtOutDevDataSync::SetStructureAttributeNumerical );
|
|
mpPageSyncData->mParaStructAttributes.push_back( eAttr );
|
|
mpPageSyncData->mParaInts.push_back( nValue );
|
|
}
|
|
void PDFExtOutDevData::SetStructureBoundingBox( const tools::Rectangle& rRect )
|
|
{
|
|
mpPageSyncData->PushAction( mrOutDev, PDFExtOutDevDataSync::SetStructureBoundingBox );
|
|
mpPageSyncData->mParaRects.push_back( rRect );
|
|
}
|
|
void PDFExtOutDevData::SetActualText( const OUString& rText )
|
|
{
|
|
mpPageSyncData->PushAction( mrOutDev, PDFExtOutDevDataSync::SetActualText );
|
|
mpPageSyncData->mParaOUStrings.push_back( rText );
|
|
}
|
|
void PDFExtOutDevData::SetAlternateText( const OUString& rText )
|
|
{
|
|
mpPageSyncData->PushAction( mrOutDev, PDFExtOutDevDataSync::SetAlternateText );
|
|
mpPageSyncData->mParaOUStrings.push_back( rText );
|
|
}
|
|
|
|
void PDFExtOutDevData::CreateControl( const PDFWriter::AnyWidget& rControlType )
|
|
{
|
|
mpPageSyncData->PushAction( mrOutDev, PDFExtOutDevDataSync::CreateControl );
|
|
|
|
std::shared_ptr< PDFWriter::AnyWidget > pClone( rControlType.Clone() );
|
|
mpPageSyncData->mControls.push_back( pClone );
|
|
}
|
|
|
|
void PDFExtOutDevData::BeginGroup()
|
|
{
|
|
mpPageSyncData->PushAction( mrOutDev, PDFExtOutDevDataSync::BeginGroup );
|
|
}
|
|
|
|
void PDFExtOutDevData::EndGroup( const Graphic& rGraphic,
|
|
sal_uInt8 nTransparency,
|
|
const tools::Rectangle& rOutputRect,
|
|
const tools::Rectangle& rVisibleOutputRect )
|
|
{
|
|
mpPageSyncData->PushAction( mrOutDev, PDFExtOutDevDataSync::EndGroupGfxLink );
|
|
mpPageSyncData->mGraphics.push_back( rGraphic );
|
|
mpPageSyncData->mParaInts.push_back( nTransparency );
|
|
mpPageSyncData->mParaRects.push_back( rOutputRect );
|
|
mpPageSyncData->mParaRects.push_back( rVisibleOutputRect );
|
|
}
|
|
|
|
// Avoids expensive de-compression and re-compression of large images.
|
|
bool PDFExtOutDevData::HasAdequateCompression( const Graphic &rGraphic,
|
|
const tools::Rectangle & rOutputRect,
|
|
const tools::Rectangle & rVisibleOutputRect ) const
|
|
{
|
|
assert(rGraphic.IsGfxLink() &&
|
|
(rGraphic.GetGfxLink().GetType() == GfxLinkType::NativeJpg ||
|
|
rGraphic.GetGfxLink().GetType() == GfxLinkType::NativePng ||
|
|
rGraphic.GetGfxLink().GetType() == GfxLinkType::NativePdf));
|
|
|
|
if (rOutputRect != rVisibleOutputRect)
|
|
// rOutputRect is the crop rectangle, re-compress cropped image.
|
|
return false;
|
|
|
|
if (mbReduceImageResolution)
|
|
// Reducing resolution was requested, implies that re-compressing is
|
|
// wanted.
|
|
return false;
|
|
|
|
if (rGraphic.GetGfxLink().GetDataSize() == 0)
|
|
return false;
|
|
|
|
GfxLink aLink = rGraphic.GetGfxLink();
|
|
SvMemoryStream aMemoryStream(const_cast<sal_uInt8*>(aLink.GetData()), aLink.GetDataSize(),
|
|
StreamMode::READ | StreamMode::WRITE);
|
|
GraphicDescriptor aDescriptor(aMemoryStream, nullptr);
|
|
if (aDescriptor.Detect(true) && aDescriptor.GetNumberOfImageComponents() == 4)
|
|
// 4 means CMYK, which is not handled.
|
|
return false;
|
|
|
|
const Size aSize = rGraphic.GetSizePixel();
|
|
|
|
// small items better off as PNG anyway
|
|
if ( aSize.Width() < 32 &&
|
|
aSize.Height() < 32 )
|
|
return false;
|
|
|
|
if (GetIsLosslessCompression())
|
|
return !GetIsReduceImageResolution();
|
|
|
|
// FIXME: ideally we'd also pre-empt the DPI related scaling too.
|
|
sal_Int32 nCurrentRatio = (100 * aSize.Width() * aSize.Height() * 4) /
|
|
rGraphic.GetGfxLink().GetDataSize();
|
|
|
|
static const struct {
|
|
sal_Int32 const mnQuality;
|
|
sal_Int32 const mnRatio;
|
|
} aRatios[] = { // minimum tolerable compression ratios
|
|
{ 100, 400 }, { 95, 700 }, { 90, 1000 }, { 85, 1200 },
|
|
{ 80, 1500 }, { 75, 1700 }
|
|
};
|
|
sal_Int32 nTargetRatio = 10000;
|
|
bool bIsTargetRatioReached = false;
|
|
for (auto & rRatio : aRatios)
|
|
{
|
|
if ( mnCompressionQuality > rRatio.mnQuality )
|
|
{
|
|
bIsTargetRatioReached = true;
|
|
break;
|
|
}
|
|
nTargetRatio = rRatio.mnRatio;
|
|
}
|
|
|
|
return ((nCurrentRatio > nTargetRatio) && bIsTargetRatioReached);
|
|
}
|
|
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|