xref: /AOO41X/main/vcl/source/gdi/pdfwriter_impl2.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1*cdf0e10cSrcweir /*************************************************************************
2*cdf0e10cSrcweir  *
3*cdf0e10cSrcweir  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4*cdf0e10cSrcweir  *
5*cdf0e10cSrcweir  * Copyright 2000, 2010 Oracle and/or its affiliates.
6*cdf0e10cSrcweir  *
7*cdf0e10cSrcweir  * OpenOffice.org - a multi-platform office productivity suite
8*cdf0e10cSrcweir  *
9*cdf0e10cSrcweir  * This file is part of OpenOffice.org.
10*cdf0e10cSrcweir  *
11*cdf0e10cSrcweir  * OpenOffice.org is free software: you can redistribute it and/or modify
12*cdf0e10cSrcweir  * it under the terms of the GNU Lesser General Public License version 3
13*cdf0e10cSrcweir  * only, as published by the Free Software Foundation.
14*cdf0e10cSrcweir  *
15*cdf0e10cSrcweir  * OpenOffice.org is distributed in the hope that it will be useful,
16*cdf0e10cSrcweir  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17*cdf0e10cSrcweir  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18*cdf0e10cSrcweir  * GNU Lesser General Public License version 3 for more details
19*cdf0e10cSrcweir  * (a copy is included in the LICENSE file that accompanied this code).
20*cdf0e10cSrcweir  *
21*cdf0e10cSrcweir  * You should have received a copy of the GNU Lesser General Public License
22*cdf0e10cSrcweir  * version 3 along with OpenOffice.org.  If not, see
23*cdf0e10cSrcweir  * <http://www.openoffice.org/license.html>
24*cdf0e10cSrcweir  * for a copy of the LGPLv3 License.
25*cdf0e10cSrcweir  *
26*cdf0e10cSrcweir  ************************************************************************/
27*cdf0e10cSrcweir 
28*cdf0e10cSrcweir #include "precompiled_vcl.hxx"
29*cdf0e10cSrcweir 
30*cdf0e10cSrcweir #include "pdfwriter_impl.hxx"
31*cdf0e10cSrcweir 
32*cdf0e10cSrcweir #include "vcl/pdfextoutdevdata.hxx"
33*cdf0e10cSrcweir #include "vcl/virdev.hxx"
34*cdf0e10cSrcweir #include "vcl/gdimtf.hxx"
35*cdf0e10cSrcweir #include "vcl/metaact.hxx"
36*cdf0e10cSrcweir #include "vcl/bmpacc.hxx"
37*cdf0e10cSrcweir #include "vcl/graph.hxx"
38*cdf0e10cSrcweir #include "vcl/rendergraphicrasterizer.hxx"
39*cdf0e10cSrcweir 
40*cdf0e10cSrcweir #include "svdata.hxx"
41*cdf0e10cSrcweir 
42*cdf0e10cSrcweir #include "unotools/streamwrap.hxx"
43*cdf0e10cSrcweir #include "unotools/processfactory.hxx"
44*cdf0e10cSrcweir 
45*cdf0e10cSrcweir #include "comphelper/processfactory.hxx"
46*cdf0e10cSrcweir 
47*cdf0e10cSrcweir #include "com/sun/star/beans/PropertyValue.hpp"
48*cdf0e10cSrcweir #include "com/sun/star/io/XSeekable.hpp"
49*cdf0e10cSrcweir #include "com/sun/star/graphic/XGraphicProvider.hpp"
50*cdf0e10cSrcweir 
51*cdf0e10cSrcweir #include "cppuhelper/implbase1.hxx"
52*cdf0e10cSrcweir 
53*cdf0e10cSrcweir #include <rtl/digest.h>
54*cdf0e10cSrcweir 
55*cdf0e10cSrcweir #undef USE_PDFGRADIENTS
56*cdf0e10cSrcweir 
57*cdf0e10cSrcweir using namespace vcl;
58*cdf0e10cSrcweir using namespace rtl;
59*cdf0e10cSrcweir using namespace com::sun::star;
60*cdf0e10cSrcweir using namespace com::sun::star::uno;
61*cdf0e10cSrcweir using namespace com::sun::star::beans;
62*cdf0e10cSrcweir 
63*cdf0e10cSrcweir // -----------------------------------------------------------------------------
64*cdf0e10cSrcweir 
65*cdf0e10cSrcweir void PDFWriterImpl::implWriteGradient( const PolyPolygon& i_rPolyPoly, const Gradient& i_rGradient,
66*cdf0e10cSrcweir                                        VirtualDevice* i_pDummyVDev, const vcl::PDFWriter::PlayMetafileContext& i_rContext )
67*cdf0e10cSrcweir {
68*cdf0e10cSrcweir     GDIMetaFile        aTmpMtf;
69*cdf0e10cSrcweir 
70*cdf0e10cSrcweir     i_pDummyVDev->AddGradientActions( i_rPolyPoly.GetBoundRect(), i_rGradient, aTmpMtf );
71*cdf0e10cSrcweir 
72*cdf0e10cSrcweir     m_rOuterFace.Push();
73*cdf0e10cSrcweir     m_rOuterFace.IntersectClipRegion( i_rPolyPoly.getB2DPolyPolygon() );
74*cdf0e10cSrcweir     playMetafile( aTmpMtf, NULL, i_rContext, i_pDummyVDev );
75*cdf0e10cSrcweir     m_rOuterFace.Pop();
76*cdf0e10cSrcweir }
77*cdf0e10cSrcweir 
78*cdf0e10cSrcweir // -----------------------------------------------------------------------------
79*cdf0e10cSrcweir 
80*cdf0e10cSrcweir void PDFWriterImpl::implWriteBitmapEx( const Point& i_rPoint, const Size& i_rSize, const BitmapEx& i_rBitmapEx,
81*cdf0e10cSrcweir                                        VirtualDevice* i_pDummyVDev, const vcl::PDFWriter::PlayMetafileContext& i_rContext )
82*cdf0e10cSrcweir {
83*cdf0e10cSrcweir 	if ( !i_rBitmapEx.IsEmpty() && i_rSize.Width() && i_rSize.Height() )
84*cdf0e10cSrcweir 	{
85*cdf0e10cSrcweir 		BitmapEx		aBitmapEx( i_rBitmapEx );
86*cdf0e10cSrcweir         Point			aPoint( i_rPoint );
87*cdf0e10cSrcweir         Size			aSize( i_rSize );
88*cdf0e10cSrcweir 
89*cdf0e10cSrcweir         // #i19065# Negative sizes have mirror semantics on
90*cdf0e10cSrcweir         // OutputDevice. BitmapEx and co. have no idea about that, so
91*cdf0e10cSrcweir         // perform that _before_ doing anything with aBitmapEx.
92*cdf0e10cSrcweir         sal_uLong nMirrorFlags(BMP_MIRROR_NONE);
93*cdf0e10cSrcweir         if( aSize.Width() < 0 )
94*cdf0e10cSrcweir         {
95*cdf0e10cSrcweir             aSize.Width() *= -1;
96*cdf0e10cSrcweir             aPoint.X() -= aSize.Width();
97*cdf0e10cSrcweir             nMirrorFlags |= BMP_MIRROR_HORZ;
98*cdf0e10cSrcweir         }
99*cdf0e10cSrcweir         if( aSize.Height() < 0 )
100*cdf0e10cSrcweir         {
101*cdf0e10cSrcweir             aSize.Height() *= -1;
102*cdf0e10cSrcweir             aPoint.Y() -= aSize.Height();
103*cdf0e10cSrcweir             nMirrorFlags |= BMP_MIRROR_VERT;
104*cdf0e10cSrcweir         }
105*cdf0e10cSrcweir 
106*cdf0e10cSrcweir         if( nMirrorFlags != BMP_MIRROR_NONE )
107*cdf0e10cSrcweir         {
108*cdf0e10cSrcweir             aBitmapEx.Mirror( nMirrorFlags );
109*cdf0e10cSrcweir         }
110*cdf0e10cSrcweir 		if( i_rContext.m_nMaxImageResolution > 50 )
111*cdf0e10cSrcweir 		{
112*cdf0e10cSrcweir 			// do downsampling if neccessary
113*cdf0e10cSrcweir 			const Size      aDstSizeTwip( i_pDummyVDev->PixelToLogic( i_pDummyVDev->LogicToPixel( aSize ), MAP_TWIP ) );
114*cdf0e10cSrcweir 			const Size      aBmpSize( aBitmapEx.GetSizePixel() );
115*cdf0e10cSrcweir 			const double    fBmpPixelX = aBmpSize.Width();
116*cdf0e10cSrcweir 			const double    fBmpPixelY = aBmpSize.Height();
117*cdf0e10cSrcweir 			const double    fMaxPixelX = aDstSizeTwip.Width() * i_rContext.m_nMaxImageResolution / 1440.0;
118*cdf0e10cSrcweir 			const double    fMaxPixelY = aDstSizeTwip.Height() * i_rContext.m_nMaxImageResolution / 1440.0;
119*cdf0e10cSrcweir 
120*cdf0e10cSrcweir 			// check, if the bitmap DPI exceeds the maximum DPI (allow 4 pixel rounding tolerance)
121*cdf0e10cSrcweir 			if( ( ( fBmpPixelX > ( fMaxPixelX + 4 ) ) ||
122*cdf0e10cSrcweir 				( fBmpPixelY > ( fMaxPixelY + 4 ) ) ) &&
123*cdf0e10cSrcweir 				( fBmpPixelY > 0.0 ) && ( fMaxPixelY > 0.0 ) )
124*cdf0e10cSrcweir 			{
125*cdf0e10cSrcweir 				// do scaling
126*cdf0e10cSrcweir 				Size            aNewBmpSize;
127*cdf0e10cSrcweir 				const double    fBmpWH = fBmpPixelX / fBmpPixelY;
128*cdf0e10cSrcweir 				const double    fMaxWH = fMaxPixelX / fMaxPixelY;
129*cdf0e10cSrcweir 
130*cdf0e10cSrcweir 				if( fBmpWH < fMaxWH )
131*cdf0e10cSrcweir 				{
132*cdf0e10cSrcweir 					aNewBmpSize.Width() = FRound( fMaxPixelY * fBmpWH );
133*cdf0e10cSrcweir 					aNewBmpSize.Height() = FRound( fMaxPixelY );
134*cdf0e10cSrcweir 				}
135*cdf0e10cSrcweir 				else if( fBmpWH > 0.0 )
136*cdf0e10cSrcweir 				{
137*cdf0e10cSrcweir 					aNewBmpSize.Width() = FRound( fMaxPixelX );
138*cdf0e10cSrcweir 					aNewBmpSize.Height() = FRound( fMaxPixelX / fBmpWH);
139*cdf0e10cSrcweir 				}
140*cdf0e10cSrcweir 				if( aNewBmpSize.Width() && aNewBmpSize.Height() )
141*cdf0e10cSrcweir 					aBitmapEx.Scale( aNewBmpSize );
142*cdf0e10cSrcweir 				else
143*cdf0e10cSrcweir 					aBitmapEx.SetEmpty();
144*cdf0e10cSrcweir 			}
145*cdf0e10cSrcweir 		}
146*cdf0e10cSrcweir 
147*cdf0e10cSrcweir 		const Size aSizePixel( aBitmapEx.GetSizePixel() );
148*cdf0e10cSrcweir 		if ( aSizePixel.Width() && aSizePixel.Height() )
149*cdf0e10cSrcweir 		{
150*cdf0e10cSrcweir             if( m_aContext.ColorMode == PDFWriter::DrawGreyscale )
151*cdf0e10cSrcweir             {
152*cdf0e10cSrcweir                 BmpConversion eConv = BMP_CONVERSION_8BIT_GREYS;
153*cdf0e10cSrcweir                 int nDepth = aBitmapEx.GetBitmap().GetBitCount();
154*cdf0e10cSrcweir                 if( nDepth <= 4 )
155*cdf0e10cSrcweir                     eConv = BMP_CONVERSION_4BIT_GREYS;
156*cdf0e10cSrcweir                 if( nDepth > 1 )
157*cdf0e10cSrcweir                     aBitmapEx.Convert( eConv );
158*cdf0e10cSrcweir             }
159*cdf0e10cSrcweir 			sal_Bool bUseJPGCompression = !i_rContext.m_bOnlyLosslessCompression;
160*cdf0e10cSrcweir 			if ( ( aSizePixel.Width() < 32 ) || ( aSizePixel.Height() < 32 ) )
161*cdf0e10cSrcweir 				bUseJPGCompression = sal_False;
162*cdf0e10cSrcweir 
163*cdf0e10cSrcweir 			SvMemoryStream	aStrm;
164*cdf0e10cSrcweir 			Bitmap			aMask;
165*cdf0e10cSrcweir 
166*cdf0e10cSrcweir 			bool bTrueColorJPG = true;
167*cdf0e10cSrcweir 			if ( bUseJPGCompression )
168*cdf0e10cSrcweir 			{
169*cdf0e10cSrcweir 				sal_uInt32 nZippedFileSize;		// sj: we will calculate the filesize of a zipped bitmap
170*cdf0e10cSrcweir 				{								// to determine if jpeg compression is usefull
171*cdf0e10cSrcweir 					SvMemoryStream aTemp;
172*cdf0e10cSrcweir 					aTemp.SetCompressMode( aTemp.GetCompressMode() | COMPRESSMODE_ZBITMAP );
173*cdf0e10cSrcweir 					aTemp.SetVersion( SOFFICE_FILEFORMAT_40 );	// sj: up from version 40 our bitmap stream operator
174*cdf0e10cSrcweir 					aTemp << aBitmapEx;							// is capable of zlib stream compression
175*cdf0e10cSrcweir 					aTemp.Seek( STREAM_SEEK_TO_END );
176*cdf0e10cSrcweir 					nZippedFileSize = aTemp.Tell();
177*cdf0e10cSrcweir 				}
178*cdf0e10cSrcweir 				if ( aBitmapEx.IsTransparent() )
179*cdf0e10cSrcweir 				{
180*cdf0e10cSrcweir 					if ( aBitmapEx.IsAlpha() )
181*cdf0e10cSrcweir 						aMask = aBitmapEx.GetAlpha().GetBitmap();
182*cdf0e10cSrcweir 					else
183*cdf0e10cSrcweir 						aMask = aBitmapEx.GetMask();
184*cdf0e10cSrcweir 				}
185*cdf0e10cSrcweir 				Graphic			aGraphic( aBitmapEx.GetBitmap() );
186*cdf0e10cSrcweir 				sal_Int32		nColorMode = 0;
187*cdf0e10cSrcweir 
188*cdf0e10cSrcweir 				Sequence< PropertyValue > aFilterData( 2 );
189*cdf0e10cSrcweir 				aFilterData[ 0 ].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "Quality" ) );
190*cdf0e10cSrcweir 				aFilterData[ 0 ].Value <<= sal_Int32(i_rContext.m_nJPEGQuality);
191*cdf0e10cSrcweir 				aFilterData[ 1 ].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "ColorMode" ) );
192*cdf0e10cSrcweir 				aFilterData[ 1 ].Value <<= nColorMode;
193*cdf0e10cSrcweir 
194*cdf0e10cSrcweir 				try
195*cdf0e10cSrcweir 				{
196*cdf0e10cSrcweir 					uno::Reference < io::XStream > xStream = new utl::OStreamWrapper( aStrm );
197*cdf0e10cSrcweir 					uno::Reference< io::XSeekable > xSeekable( xStream, UNO_QUERY_THROW );
198*cdf0e10cSrcweir 					uno::Reference< graphic::XGraphicProvider > xGraphicProvider( ImplGetSVData()->maAppData.mxMSF->createInstance(
199*cdf0e10cSrcweir 						OUString::createFromAscii( "com.sun.star.graphic.GraphicProvider" ) ), UNO_QUERY );
200*cdf0e10cSrcweir 					if ( xGraphicProvider.is() )
201*cdf0e10cSrcweir 					{
202*cdf0e10cSrcweir 						uno::Reference< graphic::XGraphic > xGraphic( aGraphic.GetXGraphic() );
203*cdf0e10cSrcweir 						uno::Reference < io::XOutputStream > xOut( xStream->getOutputStream() );
204*cdf0e10cSrcweir 						rtl::OUString aMimeType( ::rtl::OUString::createFromAscii( "image/jpeg" ) );
205*cdf0e10cSrcweir 						uno::Sequence< beans::PropertyValue > aOutMediaProperties( 3 );
206*cdf0e10cSrcweir 						aOutMediaProperties[0].Name = ::rtl::OUString::createFromAscii( "OutputStream" );
207*cdf0e10cSrcweir 						aOutMediaProperties[0].Value <<= xOut;
208*cdf0e10cSrcweir 						aOutMediaProperties[1].Name = ::rtl::OUString::createFromAscii( "MimeType" );
209*cdf0e10cSrcweir 						aOutMediaProperties[1].Value <<= aMimeType;
210*cdf0e10cSrcweir 						aOutMediaProperties[2].Name = ::rtl::OUString::createFromAscii( "FilterData" );
211*cdf0e10cSrcweir 						aOutMediaProperties[2].Value <<= aFilterData;
212*cdf0e10cSrcweir 						xGraphicProvider->storeGraphic( xGraphic, aOutMediaProperties );
213*cdf0e10cSrcweir 						xOut->flush();
214*cdf0e10cSrcweir 						if ( xSeekable->getLength() > nZippedFileSize )
215*cdf0e10cSrcweir 						{
216*cdf0e10cSrcweir 							bUseJPGCompression = sal_False;
217*cdf0e10cSrcweir 						}
218*cdf0e10cSrcweir 						else
219*cdf0e10cSrcweir 						{
220*cdf0e10cSrcweir                             aStrm.Seek( STREAM_SEEK_TO_END );
221*cdf0e10cSrcweir 
222*cdf0e10cSrcweir                             xSeekable->seek( 0 );
223*cdf0e10cSrcweir                             Sequence< PropertyValue > aArgs( 1 );
224*cdf0e10cSrcweir                             aArgs[ 0 ].Name = ::rtl::OUString::createFromAscii( "InputStream" );
225*cdf0e10cSrcweir                             aArgs[ 0 ].Value <<= xStream;
226*cdf0e10cSrcweir                             uno::Reference< XPropertySet > xPropSet( xGraphicProvider->queryGraphicDescriptor( aArgs ) );
227*cdf0e10cSrcweir                             if ( xPropSet.is() )
228*cdf0e10cSrcweir                             {
229*cdf0e10cSrcweir                                 sal_Int16 nBitsPerPixel = 24;
230*cdf0e10cSrcweir                                 if ( xPropSet->getPropertyValue( ::rtl::OUString::createFromAscii( "BitsPerPixel" ) ) >>= nBitsPerPixel )
231*cdf0e10cSrcweir                                 {
232*cdf0e10cSrcweir                                     bTrueColorJPG = nBitsPerPixel != 8;
233*cdf0e10cSrcweir                                 }
234*cdf0e10cSrcweir                             }
235*cdf0e10cSrcweir                         }
236*cdf0e10cSrcweir 					}
237*cdf0e10cSrcweir 					else
238*cdf0e10cSrcweir 					    bUseJPGCompression = sal_False;
239*cdf0e10cSrcweir 				}
240*cdf0e10cSrcweir 				catch( uno::Exception& )
241*cdf0e10cSrcweir 				{
242*cdf0e10cSrcweir 				    bUseJPGCompression = sal_False;
243*cdf0e10cSrcweir 				}
244*cdf0e10cSrcweir 			}
245*cdf0e10cSrcweir 			if ( bUseJPGCompression )
246*cdf0e10cSrcweir 				m_rOuterFace.DrawJPGBitmap( aStrm, bTrueColorJPG, aSizePixel, Rectangle( aPoint, aSize ), aMask );
247*cdf0e10cSrcweir 			else if ( aBitmapEx.IsTransparent() )
248*cdf0e10cSrcweir 				m_rOuterFace.DrawBitmapEx( aPoint, aSize, aBitmapEx );
249*cdf0e10cSrcweir 			else
250*cdf0e10cSrcweir 				m_rOuterFace.DrawBitmap( aPoint, aSize, aBitmapEx.GetBitmap() );
251*cdf0e10cSrcweir 		}
252*cdf0e10cSrcweir 	}
253*cdf0e10cSrcweir }
254*cdf0e10cSrcweir 
255*cdf0e10cSrcweir 
256*cdf0e10cSrcweir // -----------------------------------------------------------------------------
257*cdf0e10cSrcweir 
258*cdf0e10cSrcweir void PDFWriterImpl::playMetafile( const GDIMetaFile& i_rMtf, vcl::PDFExtOutDevData* i_pOutDevData, const vcl::PDFWriter::PlayMetafileContext& i_rContext, VirtualDevice* pDummyVDev )
259*cdf0e10cSrcweir {
260*cdf0e10cSrcweir     bool bAssertionFired( false );
261*cdf0e10cSrcweir 
262*cdf0e10cSrcweir     VirtualDevice* pPrivateDevice = NULL;
263*cdf0e10cSrcweir     if( ! pDummyVDev )
264*cdf0e10cSrcweir     {
265*cdf0e10cSrcweir         pPrivateDevice = pDummyVDev = new VirtualDevice();
266*cdf0e10cSrcweir         pDummyVDev->EnableOutput( sal_False );
267*cdf0e10cSrcweir         pDummyVDev->SetMapMode( i_rMtf.GetPrefMapMode() );
268*cdf0e10cSrcweir     }
269*cdf0e10cSrcweir     GDIMetaFile aMtf( i_rMtf );
270*cdf0e10cSrcweir 
271*cdf0e10cSrcweir 	for( sal_uInt32 i = 0, nCount = aMtf.GetActionCount(); i < nCount; )
272*cdf0e10cSrcweir 	{
273*cdf0e10cSrcweir 		if ( !i_pOutDevData || !i_pOutDevData->PlaySyncPageAct( m_rOuterFace, i ) )
274*cdf0e10cSrcweir 		{
275*cdf0e10cSrcweir 			const MetaAction*	pAction = aMtf.GetAction( i );
276*cdf0e10cSrcweir 			const sal_uInt16		nType = pAction->GetType();
277*cdf0e10cSrcweir 
278*cdf0e10cSrcweir 			switch( nType )
279*cdf0e10cSrcweir 			{
280*cdf0e10cSrcweir 				case( META_PIXEL_ACTION	):
281*cdf0e10cSrcweir 				{
282*cdf0e10cSrcweir 					const MetaPixelAction* pA = (const MetaPixelAction*) pAction;
283*cdf0e10cSrcweir 					m_rOuterFace.DrawPixel( pA->GetPoint(), pA->GetColor() );
284*cdf0e10cSrcweir 				}
285*cdf0e10cSrcweir 				break;
286*cdf0e10cSrcweir 
287*cdf0e10cSrcweir 				case( META_POINT_ACTION	):
288*cdf0e10cSrcweir 				{
289*cdf0e10cSrcweir 					const MetaPointAction* pA = (const MetaPointAction*) pAction;
290*cdf0e10cSrcweir 					m_rOuterFace.DrawPixel( pA->GetPoint() );
291*cdf0e10cSrcweir 				}
292*cdf0e10cSrcweir 				break;
293*cdf0e10cSrcweir 
294*cdf0e10cSrcweir 				case( META_LINE_ACTION ):
295*cdf0e10cSrcweir 				{
296*cdf0e10cSrcweir 					const MetaLineAction* pA = (const MetaLineAction*) pAction;
297*cdf0e10cSrcweir 					if ( pA->GetLineInfo().IsDefault() )
298*cdf0e10cSrcweir 						m_rOuterFace.DrawLine( pA->GetStartPoint(), pA->GetEndPoint() );
299*cdf0e10cSrcweir 					else
300*cdf0e10cSrcweir 						m_rOuterFace.DrawLine( pA->GetStartPoint(), pA->GetEndPoint(), pA->GetLineInfo() );
301*cdf0e10cSrcweir 				}
302*cdf0e10cSrcweir 				break;
303*cdf0e10cSrcweir 
304*cdf0e10cSrcweir 				case( META_RECT_ACTION ):
305*cdf0e10cSrcweir 				{
306*cdf0e10cSrcweir 					const MetaRectAction* pA = (const MetaRectAction*) pAction;
307*cdf0e10cSrcweir 					m_rOuterFace.DrawRect( pA->GetRect() );
308*cdf0e10cSrcweir 				}
309*cdf0e10cSrcweir 				break;
310*cdf0e10cSrcweir 
311*cdf0e10cSrcweir 				case( META_ROUNDRECT_ACTION	):
312*cdf0e10cSrcweir 				{
313*cdf0e10cSrcweir 					const MetaRoundRectAction* pA = (const MetaRoundRectAction*) pAction;
314*cdf0e10cSrcweir 					m_rOuterFace.DrawRect( pA->GetRect(), pA->GetHorzRound(), pA->GetVertRound() );
315*cdf0e10cSrcweir 				}
316*cdf0e10cSrcweir 				break;
317*cdf0e10cSrcweir 
318*cdf0e10cSrcweir 				case( META_ELLIPSE_ACTION ):
319*cdf0e10cSrcweir 				{
320*cdf0e10cSrcweir 					const MetaEllipseAction* pA = (const MetaEllipseAction*) pAction;
321*cdf0e10cSrcweir 					m_rOuterFace.DrawEllipse( pA->GetRect() );
322*cdf0e10cSrcweir 				}
323*cdf0e10cSrcweir 				break;
324*cdf0e10cSrcweir 
325*cdf0e10cSrcweir 				case( META_ARC_ACTION ):
326*cdf0e10cSrcweir 				{
327*cdf0e10cSrcweir 					const MetaArcAction* pA = (const MetaArcAction*) pAction;
328*cdf0e10cSrcweir 					m_rOuterFace.DrawArc( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint() );
329*cdf0e10cSrcweir 				}
330*cdf0e10cSrcweir 				break;
331*cdf0e10cSrcweir 
332*cdf0e10cSrcweir 				case( META_PIE_ACTION ):
333*cdf0e10cSrcweir 				{
334*cdf0e10cSrcweir 					const MetaArcAction* pA = (const MetaArcAction*) pAction;
335*cdf0e10cSrcweir 					m_rOuterFace.DrawPie( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint() );
336*cdf0e10cSrcweir 				}
337*cdf0e10cSrcweir 				break;
338*cdf0e10cSrcweir 
339*cdf0e10cSrcweir 				case( META_CHORD_ACTION	):
340*cdf0e10cSrcweir 				{
341*cdf0e10cSrcweir 					const MetaChordAction* pA = (const MetaChordAction*) pAction;
342*cdf0e10cSrcweir 					m_rOuterFace.DrawChord( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint() );
343*cdf0e10cSrcweir 				}
344*cdf0e10cSrcweir 				break;
345*cdf0e10cSrcweir 
346*cdf0e10cSrcweir 				case( META_POLYGON_ACTION ):
347*cdf0e10cSrcweir 				{
348*cdf0e10cSrcweir 					const MetaPolygonAction* pA = (const MetaPolygonAction*) pAction;
349*cdf0e10cSrcweir 					m_rOuterFace.DrawPolygon( pA->GetPolygon() );
350*cdf0e10cSrcweir 				}
351*cdf0e10cSrcweir 				break;
352*cdf0e10cSrcweir 
353*cdf0e10cSrcweir 				case( META_POLYLINE_ACTION ):
354*cdf0e10cSrcweir     			{
355*cdf0e10cSrcweir 					const MetaPolyLineAction* pA = (const MetaPolyLineAction*) pAction;
356*cdf0e10cSrcweir 					if ( pA->GetLineInfo().IsDefault() )
357*cdf0e10cSrcweir 						m_rOuterFace.DrawPolyLine( pA->GetPolygon() );
358*cdf0e10cSrcweir 					else
359*cdf0e10cSrcweir 						m_rOuterFace.DrawPolyLine( pA->GetPolygon(), pA->GetLineInfo() );
360*cdf0e10cSrcweir 				}
361*cdf0e10cSrcweir 				break;
362*cdf0e10cSrcweir 
363*cdf0e10cSrcweir 				case( META_POLYPOLYGON_ACTION ):
364*cdf0e10cSrcweir 				{
365*cdf0e10cSrcweir 					const MetaPolyPolygonAction* pA = (const MetaPolyPolygonAction*) pAction;
366*cdf0e10cSrcweir 					m_rOuterFace.DrawPolyPolygon( pA->GetPolyPolygon() );
367*cdf0e10cSrcweir 				}
368*cdf0e10cSrcweir 				break;
369*cdf0e10cSrcweir 
370*cdf0e10cSrcweir 				case( META_GRADIENT_ACTION ):
371*cdf0e10cSrcweir 				{
372*cdf0e10cSrcweir 					const MetaGradientAction* pA = (const MetaGradientAction*) pAction;
373*cdf0e10cSrcweir 					#ifdef USE_PDFGRADIENTS
374*cdf0e10cSrcweir 					m_rOuterFace.DrawGradient( pA->GetRect(), pA->GetGradient() );
375*cdf0e10cSrcweir 					#else
376*cdf0e10cSrcweir 					const PolyPolygon         aPolyPoly( pA->GetRect() );
377*cdf0e10cSrcweir 					implWriteGradient( aPolyPoly, pA->GetGradient(), pDummyVDev, i_rContext );
378*cdf0e10cSrcweir 					#endif
379*cdf0e10cSrcweir 				}
380*cdf0e10cSrcweir 				break;
381*cdf0e10cSrcweir 
382*cdf0e10cSrcweir 				case( META_GRADIENTEX_ACTION ):
383*cdf0e10cSrcweir 				{
384*cdf0e10cSrcweir 					const MetaGradientExAction*	pA = (const MetaGradientExAction*) pAction;
385*cdf0e10cSrcweir 					#ifdef USE_PDFGRADIENTS
386*cdf0e10cSrcweir 					m_rOuterFace.DrawGradient( pA->GetPolyPolygon(), pA->GetGradient() );
387*cdf0e10cSrcweir 					#else
388*cdf0e10cSrcweir 					implWriteGradient( pA->GetPolyPolygon(), pA->GetGradient(), pDummyVDev, i_rContext );
389*cdf0e10cSrcweir 					#endif
390*cdf0e10cSrcweir 				}
391*cdf0e10cSrcweir 				break;
392*cdf0e10cSrcweir 
393*cdf0e10cSrcweir 				case META_HATCH_ACTION:
394*cdf0e10cSrcweir 				{
395*cdf0e10cSrcweir 					const MetaHatchAction*	pA = (const MetaHatchAction*) pAction;
396*cdf0e10cSrcweir 					m_rOuterFace.DrawHatch( pA->GetPolyPolygon(), pA->GetHatch() );
397*cdf0e10cSrcweir 				}
398*cdf0e10cSrcweir 				break;
399*cdf0e10cSrcweir 
400*cdf0e10cSrcweir 				case( META_TRANSPARENT_ACTION ):
401*cdf0e10cSrcweir 				{
402*cdf0e10cSrcweir 					const MetaTransparentAction* pA = (const MetaTransparentAction*) pAction;
403*cdf0e10cSrcweir 					m_rOuterFace.DrawTransparent( pA->GetPolyPolygon(), pA->GetTransparence() );
404*cdf0e10cSrcweir 				}
405*cdf0e10cSrcweir 				break;
406*cdf0e10cSrcweir 
407*cdf0e10cSrcweir 				case( META_FLOATTRANSPARENT_ACTION ):
408*cdf0e10cSrcweir 				{
409*cdf0e10cSrcweir 					const MetaFloatTransparentAction* pA = (const MetaFloatTransparentAction*) pAction;
410*cdf0e10cSrcweir 
411*cdf0e10cSrcweir 					GDIMetaFile		aTmpMtf( pA->GetGDIMetaFile() );
412*cdf0e10cSrcweir 					const Point&	rPos = pA->GetPoint();
413*cdf0e10cSrcweir 					const Size&		rSize= pA->GetSize();
414*cdf0e10cSrcweir 					const Gradient&	rTransparenceGradient = pA->GetGradient();
415*cdf0e10cSrcweir 
416*cdf0e10cSrcweir                     // special case constant alpha value
417*cdf0e10cSrcweir                     if( rTransparenceGradient.GetStartColor() == rTransparenceGradient.GetEndColor() )
418*cdf0e10cSrcweir                     {
419*cdf0e10cSrcweir                         const Color aTransCol( rTransparenceGradient.GetStartColor() );
420*cdf0e10cSrcweir                         const sal_uInt16 nTransPercent = aTransCol.GetLuminance() * 100 / 255;
421*cdf0e10cSrcweir                         m_rOuterFace.BeginTransparencyGroup();
422*cdf0e10cSrcweir                         playMetafile( aTmpMtf, NULL, i_rContext, pDummyVDev );
423*cdf0e10cSrcweir                         m_rOuterFace.EndTransparencyGroup( Rectangle( rPos, rSize ), nTransPercent );
424*cdf0e10cSrcweir                     }
425*cdf0e10cSrcweir                     else
426*cdf0e10cSrcweir                     {
427*cdf0e10cSrcweir                         const Size	aDstSizeTwip( pDummyVDev->PixelToLogic( pDummyVDev->LogicToPixel( rSize ), MAP_TWIP ) );
428*cdf0e10cSrcweir                         sal_Int32	nMaxBmpDPI = i_rContext.m_bOnlyLosslessCompression ? 300 : 72;
429*cdf0e10cSrcweir                         if( i_rContext.m_nMaxImageResolution > 50 )
430*cdf0e10cSrcweir                         {
431*cdf0e10cSrcweir                             if ( nMaxBmpDPI > i_rContext.m_nMaxImageResolution )
432*cdf0e10cSrcweir                                 nMaxBmpDPI = i_rContext.m_nMaxImageResolution;
433*cdf0e10cSrcweir                         }
434*cdf0e10cSrcweir                         const sal_Int32	nPixelX = (sal_Int32)((double)aDstSizeTwip.Width() * (double)nMaxBmpDPI / 1440.0);
435*cdf0e10cSrcweir                         const sal_Int32 nPixelY = (sal_Int32)((double)aDstSizeTwip.Height() * (double)nMaxBmpDPI / 1440.0);
436*cdf0e10cSrcweir                         if ( nPixelX && nPixelY )
437*cdf0e10cSrcweir                         {
438*cdf0e10cSrcweir                             Size aDstSizePixel( nPixelX, nPixelY );
439*cdf0e10cSrcweir                             VirtualDevice* pVDev = new VirtualDevice;
440*cdf0e10cSrcweir                             if( pVDev->SetOutputSizePixel( aDstSizePixel ) )
441*cdf0e10cSrcweir                             {
442*cdf0e10cSrcweir                                 Bitmap			aPaint, aMask;
443*cdf0e10cSrcweir                                 AlphaMask		aAlpha;
444*cdf0e10cSrcweir                                 Point			aPoint;
445*cdf0e10cSrcweir 
446*cdf0e10cSrcweir                                 MapMode aMapMode( pDummyVDev->GetMapMode() );
447*cdf0e10cSrcweir                                 aMapMode.SetOrigin( aPoint );
448*cdf0e10cSrcweir                                 pVDev->SetMapMode( aMapMode );
449*cdf0e10cSrcweir                                 Size aDstSize( pVDev->PixelToLogic( aDstSizePixel ) );
450*cdf0e10cSrcweir 
451*cdf0e10cSrcweir                                 Point	aMtfOrigin( aTmpMtf.GetPrefMapMode().GetOrigin() );
452*cdf0e10cSrcweir                                 if ( aMtfOrigin.X() || aMtfOrigin.Y() )
453*cdf0e10cSrcweir                                     aTmpMtf.Move( -aMtfOrigin.X(), -aMtfOrigin.Y() );
454*cdf0e10cSrcweir                                 double	fScaleX = (double)aDstSize.Width() / (double)aTmpMtf.GetPrefSize().Width();
455*cdf0e10cSrcweir                                 double	fScaleY = (double)aDstSize.Height() / (double)aTmpMtf.GetPrefSize().Height();
456*cdf0e10cSrcweir                                 if( fScaleX != 1.0 || fScaleY != 1.0 )
457*cdf0e10cSrcweir                                     aTmpMtf.Scale( fScaleX, fScaleY );
458*cdf0e10cSrcweir                                 aTmpMtf.SetPrefMapMode( aMapMode );
459*cdf0e10cSrcweir 
460*cdf0e10cSrcweir                                 // create paint bitmap
461*cdf0e10cSrcweir                                 aTmpMtf.WindStart();
462*cdf0e10cSrcweir                                 aTmpMtf.Play( pVDev, aPoint, aDstSize );
463*cdf0e10cSrcweir                                 aTmpMtf.WindStart();
464*cdf0e10cSrcweir 
465*cdf0e10cSrcweir                                 pVDev->EnableMapMode( sal_False );
466*cdf0e10cSrcweir                                 aPaint = pVDev->GetBitmap( aPoint, aDstSizePixel );
467*cdf0e10cSrcweir                                 pVDev->EnableMapMode( sal_True );
468*cdf0e10cSrcweir 
469*cdf0e10cSrcweir                                 // create mask bitmap
470*cdf0e10cSrcweir                                 pVDev->SetLineColor( COL_BLACK );
471*cdf0e10cSrcweir                                 pVDev->SetFillColor( COL_BLACK );
472*cdf0e10cSrcweir                                 pVDev->DrawRect( Rectangle( aPoint, aDstSize ) );
473*cdf0e10cSrcweir                                 pVDev->SetDrawMode( DRAWMODE_WHITELINE | DRAWMODE_WHITEFILL | DRAWMODE_WHITETEXT |
474*cdf0e10cSrcweir                                                     DRAWMODE_WHITEBITMAP | DRAWMODE_WHITEGRADIENT );
475*cdf0e10cSrcweir                                 aTmpMtf.WindStart();
476*cdf0e10cSrcweir                                 aTmpMtf.Play( pVDev, aPoint, aDstSize );
477*cdf0e10cSrcweir                                 aTmpMtf.WindStart();
478*cdf0e10cSrcweir                                 pVDev->EnableMapMode( sal_False );
479*cdf0e10cSrcweir                                 aMask = pVDev->GetBitmap( aPoint, aDstSizePixel );
480*cdf0e10cSrcweir                                 pVDev->EnableMapMode( sal_True );
481*cdf0e10cSrcweir 
482*cdf0e10cSrcweir                                 // create alpha mask from gradient
483*cdf0e10cSrcweir                                 pVDev->SetDrawMode( DRAWMODE_GRAYGRADIENT );
484*cdf0e10cSrcweir                                 pVDev->DrawGradient( Rectangle( aPoint, aDstSize ), rTransparenceGradient );
485*cdf0e10cSrcweir                                 pVDev->SetDrawMode( DRAWMODE_DEFAULT );
486*cdf0e10cSrcweir                                 pVDev->EnableMapMode( sal_False );
487*cdf0e10cSrcweir                                 pVDev->DrawMask( aPoint, aDstSizePixel, aMask, Color( COL_WHITE ) );
488*cdf0e10cSrcweir                                 aAlpha = pVDev->GetBitmap( aPoint, aDstSizePixel );
489*cdf0e10cSrcweir                                 implWriteBitmapEx( rPos, rSize, BitmapEx( aPaint, aAlpha ), pDummyVDev, i_rContext );
490*cdf0e10cSrcweir                             }
491*cdf0e10cSrcweir                             delete pVDev;
492*cdf0e10cSrcweir                         }
493*cdf0e10cSrcweir                     }
494*cdf0e10cSrcweir 				}
495*cdf0e10cSrcweir 				break;
496*cdf0e10cSrcweir 
497*cdf0e10cSrcweir 				case( META_EPS_ACTION ):
498*cdf0e10cSrcweir 				{
499*cdf0e10cSrcweir 					const MetaEPSAction*	pA = (const MetaEPSAction*) pAction;
500*cdf0e10cSrcweir 					const GDIMetaFile		aSubstitute( pA->GetSubstitute() );
501*cdf0e10cSrcweir 
502*cdf0e10cSrcweir 					m_rOuterFace.Push();
503*cdf0e10cSrcweir 					pDummyVDev->Push();
504*cdf0e10cSrcweir 
505*cdf0e10cSrcweir 					MapMode	aMapMode( aSubstitute.GetPrefMapMode() );
506*cdf0e10cSrcweir 					Size aOutSize( pDummyVDev->LogicToLogic( pA->GetSize(), pDummyVDev->GetMapMode(), aMapMode ) );
507*cdf0e10cSrcweir 					aMapMode.SetScaleX( Fraction( aOutSize.Width(), aSubstitute.GetPrefSize().Width() ) );
508*cdf0e10cSrcweir 					aMapMode.SetScaleY( Fraction( aOutSize.Height(), aSubstitute.GetPrefSize().Height() ) );
509*cdf0e10cSrcweir 					aMapMode.SetOrigin( pDummyVDev->LogicToLogic( pA->GetPoint(), pDummyVDev->GetMapMode(), aMapMode ) );
510*cdf0e10cSrcweir 
511*cdf0e10cSrcweir 					m_rOuterFace.SetMapMode( aMapMode );
512*cdf0e10cSrcweir 					pDummyVDev->SetMapMode( aMapMode );
513*cdf0e10cSrcweir 					playMetafile( aSubstitute, NULL, i_rContext, pDummyVDev );
514*cdf0e10cSrcweir 					pDummyVDev->Pop();
515*cdf0e10cSrcweir 					m_rOuterFace.Pop();
516*cdf0e10cSrcweir 				}
517*cdf0e10cSrcweir 				break;
518*cdf0e10cSrcweir 
519*cdf0e10cSrcweir 				case( META_COMMENT_ACTION ):
520*cdf0e10cSrcweir                 if( ! i_rContext.m_bTransparenciesWereRemoved )
521*cdf0e10cSrcweir 				{
522*cdf0e10cSrcweir 					const MetaCommentAction*	pA = (const MetaCommentAction*) pAction;
523*cdf0e10cSrcweir 					String						aSkipComment;
524*cdf0e10cSrcweir 
525*cdf0e10cSrcweir 					if( pA->GetComment().CompareIgnoreCaseToAscii( "XGRAD_SEQ_BEGIN" ) == COMPARE_EQUAL )
526*cdf0e10cSrcweir 					{
527*cdf0e10cSrcweir 						const MetaGradientExAction*	pGradAction = NULL;
528*cdf0e10cSrcweir 						sal_Bool					bDone = sal_False;
529*cdf0e10cSrcweir 
530*cdf0e10cSrcweir 						while( !bDone && ( ++i < nCount ) )
531*cdf0e10cSrcweir 						{
532*cdf0e10cSrcweir 							pAction = aMtf.GetAction( i );
533*cdf0e10cSrcweir 
534*cdf0e10cSrcweir 							if( pAction->GetType() == META_GRADIENTEX_ACTION )
535*cdf0e10cSrcweir 								pGradAction = (const MetaGradientExAction*) pAction;
536*cdf0e10cSrcweir 							else if( ( pAction->GetType() == META_COMMENT_ACTION ) &&
537*cdf0e10cSrcweir 									( ( (const MetaCommentAction*) pAction )->GetComment().CompareIgnoreCaseToAscii( "XGRAD_SEQ_END" ) == COMPARE_EQUAL ) )
538*cdf0e10cSrcweir 							{
539*cdf0e10cSrcweir 								bDone = sal_True;
540*cdf0e10cSrcweir 							}
541*cdf0e10cSrcweir 						}
542*cdf0e10cSrcweir 
543*cdf0e10cSrcweir 						if( pGradAction )
544*cdf0e10cSrcweir 						{
545*cdf0e10cSrcweir 						    #if USE_PDFGRADIENTS
546*cdf0e10cSrcweir 							m_rOuterFace.DrawGradient( pGradAction->GetPolyPolygon(), pGradAction->GetGradient() );
547*cdf0e10cSrcweir 							#else
548*cdf0e10cSrcweir 							implWriteGradient( pGradAction->GetPolyPolygon(), pGradAction->GetGradient(), pDummyVDev, i_rContext );
549*cdf0e10cSrcweir 							#endif
550*cdf0e10cSrcweir 						}
551*cdf0e10cSrcweir 					}
552*cdf0e10cSrcweir 					else
553*cdf0e10cSrcweir 					{
554*cdf0e10cSrcweir 						const sal_uInt8* pData = pA->GetData();
555*cdf0e10cSrcweir 						if ( pData )
556*cdf0e10cSrcweir 						{
557*cdf0e10cSrcweir 							SvMemoryStream	aMemStm( (void*)pData, pA->GetDataSize(), STREAM_READ );
558*cdf0e10cSrcweir 							sal_Bool		bSkipSequence = sal_False;
559*cdf0e10cSrcweir 							ByteString		sSeqEnd;
560*cdf0e10cSrcweir 
561*cdf0e10cSrcweir 							if( pA->GetComment().Equals( "XPATHSTROKE_SEQ_BEGIN" ) )
562*cdf0e10cSrcweir 							{
563*cdf0e10cSrcweir 								sSeqEnd = ByteString( "XPATHSTROKE_SEQ_END" );
564*cdf0e10cSrcweir 								SvtGraphicStroke aStroke;
565*cdf0e10cSrcweir 								aMemStm >> aStroke;
566*cdf0e10cSrcweir 
567*cdf0e10cSrcweir 								Polygon aPath;
568*cdf0e10cSrcweir 								aStroke.getPath( aPath );
569*cdf0e10cSrcweir 
570*cdf0e10cSrcweir 								PolyPolygon aStartArrow;
571*cdf0e10cSrcweir 								PolyPolygon aEndArrow;
572*cdf0e10cSrcweir 								double fTransparency( aStroke.getTransparency() );
573*cdf0e10cSrcweir 								double fStrokeWidth( aStroke.getStrokeWidth() );
574*cdf0e10cSrcweir 								SvtGraphicStroke::DashArray aDashArray;
575*cdf0e10cSrcweir 
576*cdf0e10cSrcweir 								aStroke.getStartArrow( aStartArrow );
577*cdf0e10cSrcweir 								aStroke.getEndArrow( aEndArrow );
578*cdf0e10cSrcweir 								aStroke.getDashArray( aDashArray );
579*cdf0e10cSrcweir 
580*cdf0e10cSrcweir 								bSkipSequence = sal_True;
581*cdf0e10cSrcweir 								if ( aStartArrow.Count() || aEndArrow.Count() )
582*cdf0e10cSrcweir 									bSkipSequence = sal_False;
583*cdf0e10cSrcweir 								if ( aDashArray.size() && ( fStrokeWidth != 0.0 ) && ( fTransparency == 0.0 ) )
584*cdf0e10cSrcweir 									bSkipSequence = sal_False;
585*cdf0e10cSrcweir 								if ( bSkipSequence )
586*cdf0e10cSrcweir 								{
587*cdf0e10cSrcweir 									PDFWriter::ExtLineInfo aInfo;
588*cdf0e10cSrcweir                                     aInfo.m_fLineWidth      = fStrokeWidth;
589*cdf0e10cSrcweir                                     aInfo.m_fTransparency   = fTransparency;
590*cdf0e10cSrcweir                                     aInfo.m_fMiterLimit     = aStroke.getMiterLimit();
591*cdf0e10cSrcweir                                     switch( aStroke.getCapType() )
592*cdf0e10cSrcweir                                     {
593*cdf0e10cSrcweir                                         default:
594*cdf0e10cSrcweir                                         case SvtGraphicStroke::capButt:   aInfo.m_eCap = PDFWriter::capButt;break;
595*cdf0e10cSrcweir                                         case SvtGraphicStroke::capRound:  aInfo.m_eCap = PDFWriter::capRound;break;
596*cdf0e10cSrcweir                                         case SvtGraphicStroke::capSquare: aInfo.m_eCap = PDFWriter::capSquare;break;
597*cdf0e10cSrcweir                                     }
598*cdf0e10cSrcweir                                     switch( aStroke.getJoinType() )
599*cdf0e10cSrcweir                                     {
600*cdf0e10cSrcweir                                         default:
601*cdf0e10cSrcweir                                         case SvtGraphicStroke::joinMiter: aInfo.m_eJoin = PDFWriter::joinMiter;break;
602*cdf0e10cSrcweir                                         case SvtGraphicStroke::joinRound: aInfo.m_eJoin = PDFWriter::joinRound;break;
603*cdf0e10cSrcweir                                         case SvtGraphicStroke::joinBevel: aInfo.m_eJoin = PDFWriter::joinBevel;break;
604*cdf0e10cSrcweir                                         case SvtGraphicStroke::joinNone:
605*cdf0e10cSrcweir                                             aInfo.m_eJoin = PDFWriter::joinMiter;
606*cdf0e10cSrcweir                                             aInfo.m_fMiterLimit = 0.0;
607*cdf0e10cSrcweir                                             break;
608*cdf0e10cSrcweir                                     }
609*cdf0e10cSrcweir                                     aInfo.m_aDashArray = aDashArray;
610*cdf0e10cSrcweir 
611*cdf0e10cSrcweir                                     if(SvtGraphicStroke::joinNone == aStroke.getJoinType()
612*cdf0e10cSrcweir                                         && fStrokeWidth > 0.0)
613*cdf0e10cSrcweir                                     {
614*cdf0e10cSrcweir                                         // emulate no edge rounding by handling single edges
615*cdf0e10cSrcweir                                         const sal_uInt16 nPoints(aPath.GetSize());
616*cdf0e10cSrcweir                                         const bool bCurve(aPath.HasFlags());
617*cdf0e10cSrcweir 
618*cdf0e10cSrcweir                                         for(sal_uInt16 a(0); a + 1 < nPoints; a++)
619*cdf0e10cSrcweir                                         {
620*cdf0e10cSrcweir                                             if(bCurve
621*cdf0e10cSrcweir                                                 && POLY_NORMAL != aPath.GetFlags(a + 1)
622*cdf0e10cSrcweir                                                 && a + 2 < nPoints
623*cdf0e10cSrcweir                                                 && POLY_NORMAL != aPath.GetFlags(a + 2)
624*cdf0e10cSrcweir                                                 && a + 3 < nPoints)
625*cdf0e10cSrcweir                                             {
626*cdf0e10cSrcweir                 								const Polygon aSnippet(4,
627*cdf0e10cSrcweir                                                     aPath.GetConstPointAry() + a,
628*cdf0e10cSrcweir                                                     aPath.GetConstFlagAry() + a);
629*cdf0e10cSrcweir                                                 m_rOuterFace.DrawPolyLine( aSnippet, aInfo );
630*cdf0e10cSrcweir                                                 a += 2;
631*cdf0e10cSrcweir                                             }
632*cdf0e10cSrcweir                                             else
633*cdf0e10cSrcweir                                             {
634*cdf0e10cSrcweir                 								const Polygon aSnippet(2,
635*cdf0e10cSrcweir                                                     aPath.GetConstPointAry() + a);
636*cdf0e10cSrcweir                                                 m_rOuterFace.DrawPolyLine( aSnippet, aInfo );
637*cdf0e10cSrcweir                                             }
638*cdf0e10cSrcweir                                         }
639*cdf0e10cSrcweir                                     }
640*cdf0e10cSrcweir                                     else
641*cdf0e10cSrcweir                                     {
642*cdf0e10cSrcweir                                         m_rOuterFace.DrawPolyLine( aPath, aInfo );
643*cdf0e10cSrcweir                                     }
644*cdf0e10cSrcweir 								}
645*cdf0e10cSrcweir 							}
646*cdf0e10cSrcweir 							else if ( pA->GetComment().Equals( "XPATHFILL_SEQ_BEGIN" ) )
647*cdf0e10cSrcweir 							{
648*cdf0e10cSrcweir 								sSeqEnd = ByteString( "XPATHFILL_SEQ_END" );
649*cdf0e10cSrcweir 								SvtGraphicFill aFill;
650*cdf0e10cSrcweir 								aMemStm >> aFill;
651*cdf0e10cSrcweir 
652*cdf0e10cSrcweir 								if ( ( aFill.getFillType() == SvtGraphicFill::fillSolid ) && ( aFill.getFillRule() == SvtGraphicFill::fillEvenOdd ) )
653*cdf0e10cSrcweir 								{
654*cdf0e10cSrcweir 									double fTransparency = aFill.getTransparency();
655*cdf0e10cSrcweir 									if ( fTransparency == 0.0 )
656*cdf0e10cSrcweir 									{
657*cdf0e10cSrcweir 										PolyPolygon aPath;
658*cdf0e10cSrcweir 										aFill.getPath( aPath );
659*cdf0e10cSrcweir 
660*cdf0e10cSrcweir 										bSkipSequence = sal_True;
661*cdf0e10cSrcweir 										m_rOuterFace.DrawPolyPolygon( aPath );
662*cdf0e10cSrcweir 									}
663*cdf0e10cSrcweir 									else if ( fTransparency == 1.0 )
664*cdf0e10cSrcweir 										bSkipSequence = sal_True;
665*cdf0e10cSrcweir 								}
666*cdf0e10cSrcweir /* #i81548# removing optimization for fill textures, because most of the texture settings are not
667*cdf0e10cSrcweir    exported properly. In OpenOffice 3.1 the drawing layer will support graphic primitives, then it
668*cdf0e10cSrcweir    will not be a problem to optimize the filltexture export. But for wysiwyg is more important than
669*cdf0e10cSrcweir    filesize.
670*cdf0e10cSrcweir                                 else if( aFill.getFillType() == SvtGraphicFill::fillTexture && aFill.isTiling() )
671*cdf0e10cSrcweir                                 {
672*cdf0e10cSrcweir                                     sal_Int32 nPattern = mnCachePatternId;
673*cdf0e10cSrcweir                                     Graphic aPatternGraphic;
674*cdf0e10cSrcweir                                     aFill.getGraphic( aPatternGraphic );
675*cdf0e10cSrcweir                                     bool bUseCache = false;
676*cdf0e10cSrcweir                                     SvtGraphicFill::Transform aPatTransform;
677*cdf0e10cSrcweir                                     aFill.getTransform( aPatTransform );
678*cdf0e10cSrcweir 
679*cdf0e10cSrcweir                                     if(  mnCachePatternId >= 0 )
680*cdf0e10cSrcweir                                     {
681*cdf0e10cSrcweir                                         SvtGraphicFill::Transform aCacheTransform;
682*cdf0e10cSrcweir                                         maCacheFill.getTransform( aCacheTransform );
683*cdf0e10cSrcweir                                         if( aCacheTransform.matrix[0] == aPatTransform.matrix[0] &&
684*cdf0e10cSrcweir                                             aCacheTransform.matrix[1] == aPatTransform.matrix[1] &&
685*cdf0e10cSrcweir                                             aCacheTransform.matrix[2] == aPatTransform.matrix[2] &&
686*cdf0e10cSrcweir                                             aCacheTransform.matrix[3] == aPatTransform.matrix[3] &&
687*cdf0e10cSrcweir                                             aCacheTransform.matrix[4] == aPatTransform.matrix[4] &&
688*cdf0e10cSrcweir                                             aCacheTransform.matrix[5] == aPatTransform.matrix[5]
689*cdf0e10cSrcweir                                             )
690*cdf0e10cSrcweir                                         {
691*cdf0e10cSrcweir                                             Graphic aCacheGraphic;
692*cdf0e10cSrcweir                                             maCacheFill.getGraphic( aCacheGraphic );
693*cdf0e10cSrcweir                                             if( aCacheGraphic == aPatternGraphic )
694*cdf0e10cSrcweir                                                 bUseCache = true;
695*cdf0e10cSrcweir                                         }
696*cdf0e10cSrcweir                                     }
697*cdf0e10cSrcweir 
698*cdf0e10cSrcweir                                     if( ! bUseCache )
699*cdf0e10cSrcweir                                     {
700*cdf0e10cSrcweir 
701*cdf0e10cSrcweir                                         // paint graphic to metafile
702*cdf0e10cSrcweir                                         GDIMetaFile aPattern;
703*cdf0e10cSrcweir                                         pDummyVDev->SetConnectMetaFile( &aPattern );
704*cdf0e10cSrcweir                                         pDummyVDev->Push();
705*cdf0e10cSrcweir                                         pDummyVDev->SetMapMode( aPatternGraphic.GetPrefMapMode() );
706*cdf0e10cSrcweir 
707*cdf0e10cSrcweir                                         aPatternGraphic.Draw( &rDummyVDev, Point( 0, 0 ) );
708*cdf0e10cSrcweir                                         pDummyVDev->Pop();
709*cdf0e10cSrcweir                                         pDummyVDev->SetConnectMetaFile( NULL );
710*cdf0e10cSrcweir                                         aPattern.WindStart();
711*cdf0e10cSrcweir 
712*cdf0e10cSrcweir                                         MapMode	aPatternMapMode( aPatternGraphic.GetPrefMapMode() );
713*cdf0e10cSrcweir                                         // prepare pattern from metafile
714*cdf0e10cSrcweir                                         Size aPrefSize( aPatternGraphic.GetPrefSize() );
715*cdf0e10cSrcweir                                         // FIXME: this magic -1 shouldn't be necessary
716*cdf0e10cSrcweir                                         aPrefSize.Width() -= 1;
717*cdf0e10cSrcweir                                         aPrefSize.Height() -= 1;
718*cdf0e10cSrcweir                                         aPrefSize = m_rOuterFace.GetReferenceDevice()->
719*cdf0e10cSrcweir                                             LogicToLogic( aPrefSize,
720*cdf0e10cSrcweir                                                           &aPatternMapMode,
721*cdf0e10cSrcweir                                                           &m_rOuterFace.GetReferenceDevice()->GetMapMode() );
722*cdf0e10cSrcweir                                         // build bounding rectangle of pattern
723*cdf0e10cSrcweir                                         Rectangle aBound( Point( 0, 0 ), aPrefSize );
724*cdf0e10cSrcweir                                         m_rOuterFace.BeginPattern( aBound );
725*cdf0e10cSrcweir                                         m_rOuterFace.Push();
726*cdf0e10cSrcweir                                         pDummyVDev->Push();
727*cdf0e10cSrcweir                                         m_rOuterFace.SetMapMode( aPatternMapMode );
728*cdf0e10cSrcweir                                         pDummyVDev->SetMapMode( aPatternMapMode );
729*cdf0e10cSrcweir                                         ImplWriteActions( m_rOuterFace, NULL, aPattern, rDummyVDev );
730*cdf0e10cSrcweir                                         pDummyVDev->Pop();
731*cdf0e10cSrcweir                                         m_rOuterFace.Pop();
732*cdf0e10cSrcweir 
733*cdf0e10cSrcweir                                         nPattern = m_rOuterFace.EndPattern( aPatTransform );
734*cdf0e10cSrcweir 
735*cdf0e10cSrcweir                                         // try some caching and reuse pattern
736*cdf0e10cSrcweir                                         mnCachePatternId = nPattern;
737*cdf0e10cSrcweir                                         maCacheFill = aFill;
738*cdf0e10cSrcweir                                     }
739*cdf0e10cSrcweir 
740*cdf0e10cSrcweir                                     // draw polypolygon with pattern fill
741*cdf0e10cSrcweir                                     PolyPolygon aPath;
742*cdf0e10cSrcweir                                     aFill.getPath( aPath );
743*cdf0e10cSrcweir                                     m_rOuterFace.DrawPolyPolygon( aPath, nPattern, aFill.getFillRule() == SvtGraphicFill::fillEvenOdd );
744*cdf0e10cSrcweir 
745*cdf0e10cSrcweir                                     bSkipSequence = sal_True;
746*cdf0e10cSrcweir                                 }
747*cdf0e10cSrcweir */
748*cdf0e10cSrcweir 							}
749*cdf0e10cSrcweir 							if ( bSkipSequence )
750*cdf0e10cSrcweir 							{
751*cdf0e10cSrcweir 								while( ++i < nCount )
752*cdf0e10cSrcweir 								{
753*cdf0e10cSrcweir 									pAction = aMtf.GetAction( i );
754*cdf0e10cSrcweir 									if ( pAction->GetType() == META_COMMENT_ACTION )
755*cdf0e10cSrcweir 									{
756*cdf0e10cSrcweir 										ByteString sComment( ((MetaCommentAction*)pAction)->GetComment() );
757*cdf0e10cSrcweir 										if ( sComment.Equals( sSeqEnd ) )
758*cdf0e10cSrcweir 											break;
759*cdf0e10cSrcweir 									}
760*cdf0e10cSrcweir                                     // #i44496#
761*cdf0e10cSrcweir                                     // the replacement action for stroke is a filled rectangle
762*cdf0e10cSrcweir                                     // the set fillcolor of the replacement is part of the graphics
763*cdf0e10cSrcweir                                     // state and must not be skipped
764*cdf0e10cSrcweir                                     else if( pAction->GetType() == META_FILLCOLOR_ACTION )
765*cdf0e10cSrcweir                                     {
766*cdf0e10cSrcweir                                         const MetaFillColorAction* pMA = (const MetaFillColorAction*) pAction;
767*cdf0e10cSrcweir                                         if( pMA->IsSetting() )
768*cdf0e10cSrcweir                                             m_rOuterFace.SetFillColor( pMA->GetColor() );
769*cdf0e10cSrcweir                                         else
770*cdf0e10cSrcweir                                             m_rOuterFace.SetFillColor();
771*cdf0e10cSrcweir                                     }
772*cdf0e10cSrcweir 								}
773*cdf0e10cSrcweir 							}
774*cdf0e10cSrcweir 						}
775*cdf0e10cSrcweir 					}
776*cdf0e10cSrcweir 				}
777*cdf0e10cSrcweir 				break;
778*cdf0e10cSrcweir 
779*cdf0e10cSrcweir 				case( META_BMP_ACTION ):
780*cdf0e10cSrcweir 				{
781*cdf0e10cSrcweir 					const MetaBmpAction* pA = (const MetaBmpAction*) pAction;
782*cdf0e10cSrcweir 					BitmapEx aBitmapEx( pA->GetBitmap() );
783*cdf0e10cSrcweir 					Size aSize( OutputDevice::LogicToLogic( aBitmapEx.GetPrefSize(),
784*cdf0e10cSrcweir 							aBitmapEx.GetPrefMapMode(), pDummyVDev->GetMapMode() ) );
785*cdf0e10cSrcweir                     if( ! ( aSize.Width() && aSize.Height() ) )
786*cdf0e10cSrcweir                         aSize = pDummyVDev->PixelToLogic( aBitmapEx.GetSizePixel() );
787*cdf0e10cSrcweir 					implWriteBitmapEx( pA->GetPoint(), aSize, aBitmapEx, pDummyVDev, i_rContext );
788*cdf0e10cSrcweir 				}
789*cdf0e10cSrcweir 				break;
790*cdf0e10cSrcweir 
791*cdf0e10cSrcweir 				case( META_BMPSCALE_ACTION ):
792*cdf0e10cSrcweir 				{
793*cdf0e10cSrcweir 					const MetaBmpScaleAction* pA = (const MetaBmpScaleAction*) pAction;
794*cdf0e10cSrcweir 					implWriteBitmapEx( pA->GetPoint(), pA->GetSize(), BitmapEx( pA->GetBitmap() ), pDummyVDev, i_rContext );
795*cdf0e10cSrcweir 				}
796*cdf0e10cSrcweir 				break;
797*cdf0e10cSrcweir 
798*cdf0e10cSrcweir 				case( META_BMPSCALEPART_ACTION ):
799*cdf0e10cSrcweir 				{
800*cdf0e10cSrcweir 					const MetaBmpScalePartAction* pA = (const MetaBmpScalePartAction*) pAction;
801*cdf0e10cSrcweir 					BitmapEx aBitmapEx( pA->GetBitmap() );
802*cdf0e10cSrcweir 					aBitmapEx.Crop( Rectangle( pA->GetSrcPoint(), pA->GetSrcSize() ) );
803*cdf0e10cSrcweir 					implWriteBitmapEx( pA->GetDestPoint(), pA->GetDestSize(), aBitmapEx, pDummyVDev, i_rContext );
804*cdf0e10cSrcweir 				}
805*cdf0e10cSrcweir 				break;
806*cdf0e10cSrcweir 
807*cdf0e10cSrcweir 				case( META_BMPEX_ACTION	):
808*cdf0e10cSrcweir 				{
809*cdf0e10cSrcweir 					const MetaBmpExAction*	pA = (const MetaBmpExAction*) pAction;
810*cdf0e10cSrcweir 					BitmapEx aBitmapEx( pA->GetBitmapEx() );
811*cdf0e10cSrcweir 					Size aSize( OutputDevice::LogicToLogic( aBitmapEx.GetPrefSize(),
812*cdf0e10cSrcweir 							aBitmapEx.GetPrefMapMode(), pDummyVDev->GetMapMode() ) );
813*cdf0e10cSrcweir 					implWriteBitmapEx( pA->GetPoint(), aSize, aBitmapEx, pDummyVDev, i_rContext );
814*cdf0e10cSrcweir 				}
815*cdf0e10cSrcweir 				break;
816*cdf0e10cSrcweir 
817*cdf0e10cSrcweir 				case( META_BMPEXSCALE_ACTION ):
818*cdf0e10cSrcweir 				{
819*cdf0e10cSrcweir 					const MetaBmpExScaleAction* pA = (const MetaBmpExScaleAction*) pAction;
820*cdf0e10cSrcweir 					implWriteBitmapEx( pA->GetPoint(), pA->GetSize(), pA->GetBitmapEx(), pDummyVDev, i_rContext );
821*cdf0e10cSrcweir 				}
822*cdf0e10cSrcweir 				break;
823*cdf0e10cSrcweir 
824*cdf0e10cSrcweir 				case( META_BMPEXSCALEPART_ACTION ):
825*cdf0e10cSrcweir 				{
826*cdf0e10cSrcweir 					const MetaBmpExScalePartAction* pA = (const MetaBmpExScalePartAction*) pAction;
827*cdf0e10cSrcweir 					BitmapEx aBitmapEx( pA->GetBitmapEx() );
828*cdf0e10cSrcweir 					aBitmapEx.Crop( Rectangle( pA->GetSrcPoint(), pA->GetSrcSize() ) );
829*cdf0e10cSrcweir 					implWriteBitmapEx( pA->GetDestPoint(), pA->GetDestSize(), aBitmapEx, pDummyVDev, i_rContext );
830*cdf0e10cSrcweir 				}
831*cdf0e10cSrcweir 				break;
832*cdf0e10cSrcweir 
833*cdf0e10cSrcweir 				case( META_MASK_ACTION ):
834*cdf0e10cSrcweir 				case( META_MASKSCALE_ACTION	):
835*cdf0e10cSrcweir 				case( META_MASKSCALEPART_ACTION	):
836*cdf0e10cSrcweir 				{
837*cdf0e10cSrcweir 					DBG_ERROR( "MetaMask...Action not supported yet" );
838*cdf0e10cSrcweir 				}
839*cdf0e10cSrcweir 				break;
840*cdf0e10cSrcweir 
841*cdf0e10cSrcweir 				case( META_TEXT_ACTION ):
842*cdf0e10cSrcweir 				{
843*cdf0e10cSrcweir 					const MetaTextAction* pA = (const MetaTextAction*) pAction;
844*cdf0e10cSrcweir 					m_rOuterFace.DrawText( pA->GetPoint(), String( pA->GetText(), pA->GetIndex(), pA->GetLen() ) );
845*cdf0e10cSrcweir 				}
846*cdf0e10cSrcweir 				break;
847*cdf0e10cSrcweir 
848*cdf0e10cSrcweir 				case( META_TEXTRECT_ACTION ):
849*cdf0e10cSrcweir 				{
850*cdf0e10cSrcweir 					const MetaTextRectAction* pA = (const MetaTextRectAction*) pAction;
851*cdf0e10cSrcweir 					m_rOuterFace.DrawText( pA->GetRect(), String( pA->GetText() ), pA->GetStyle() );
852*cdf0e10cSrcweir 				}
853*cdf0e10cSrcweir 				break;
854*cdf0e10cSrcweir 
855*cdf0e10cSrcweir 				case( META_TEXTARRAY_ACTION	):
856*cdf0e10cSrcweir 				{
857*cdf0e10cSrcweir 					const MetaTextArrayAction* pA = (const MetaTextArrayAction*) pAction;
858*cdf0e10cSrcweir 					m_rOuterFace.DrawTextArray( pA->GetPoint(), pA->GetText(), pA->GetDXArray(), pA->GetIndex(), pA->GetLen() );
859*cdf0e10cSrcweir 				}
860*cdf0e10cSrcweir 				break;
861*cdf0e10cSrcweir 
862*cdf0e10cSrcweir 				case( META_STRETCHTEXT_ACTION ):
863*cdf0e10cSrcweir 				{
864*cdf0e10cSrcweir 					const MetaStretchTextAction* pA = (const MetaStretchTextAction*) pAction;
865*cdf0e10cSrcweir 					m_rOuterFace.DrawStretchText( pA->GetPoint(), pA->GetWidth(), pA->GetText(), pA->GetIndex(), pA->GetLen() );
866*cdf0e10cSrcweir 				}
867*cdf0e10cSrcweir 				break;
868*cdf0e10cSrcweir 
869*cdf0e10cSrcweir 
870*cdf0e10cSrcweir 				case( META_TEXTLINE_ACTION ):
871*cdf0e10cSrcweir 				{
872*cdf0e10cSrcweir 					const MetaTextLineAction* pA = (const MetaTextLineAction*) pAction;
873*cdf0e10cSrcweir 					m_rOuterFace.DrawTextLine( pA->GetStartPoint(), pA->GetWidth(), pA->GetStrikeout(), pA->GetUnderline(), pA->GetOverline() );
874*cdf0e10cSrcweir 
875*cdf0e10cSrcweir 				}
876*cdf0e10cSrcweir 				break;
877*cdf0e10cSrcweir 
878*cdf0e10cSrcweir 				case( META_CLIPREGION_ACTION ):
879*cdf0e10cSrcweir 				{
880*cdf0e10cSrcweir 					const MetaClipRegionAction* pA = (const MetaClipRegionAction*) pAction;
881*cdf0e10cSrcweir 
882*cdf0e10cSrcweir 					if( pA->IsClipping() )
883*cdf0e10cSrcweir 					{
884*cdf0e10cSrcweir 					    if( pA->GetRegion().IsEmpty() )
885*cdf0e10cSrcweir 					        m_rOuterFace.SetClipRegion( basegfx::B2DPolyPolygon() );
886*cdf0e10cSrcweir 					    else
887*cdf0e10cSrcweir 					    {
888*cdf0e10cSrcweir 					        Region aReg( pA->GetRegion() );
889*cdf0e10cSrcweir 					        m_rOuterFace.SetClipRegion( aReg.ConvertToB2DPolyPolygon() );
890*cdf0e10cSrcweir 					    }
891*cdf0e10cSrcweir 					}
892*cdf0e10cSrcweir 					else
893*cdf0e10cSrcweir 						m_rOuterFace.SetClipRegion();
894*cdf0e10cSrcweir 				}
895*cdf0e10cSrcweir 				break;
896*cdf0e10cSrcweir 
897*cdf0e10cSrcweir 				case( META_ISECTRECTCLIPREGION_ACTION ):
898*cdf0e10cSrcweir 				{
899*cdf0e10cSrcweir 					const MetaISectRectClipRegionAction* pA = (const MetaISectRectClipRegionAction*) pAction;
900*cdf0e10cSrcweir 					m_rOuterFace.IntersectClipRegion( pA->GetRect() );
901*cdf0e10cSrcweir 				}
902*cdf0e10cSrcweir 				break;
903*cdf0e10cSrcweir 
904*cdf0e10cSrcweir 				case( META_ISECTREGIONCLIPREGION_ACTION	):
905*cdf0e10cSrcweir 				{
906*cdf0e10cSrcweir 				    const MetaISectRegionClipRegionAction* pA = (const MetaISectRegionClipRegionAction*) pAction;
907*cdf0e10cSrcweir 				    Region aReg( pA->GetRegion() );
908*cdf0e10cSrcweir 				    m_rOuterFace.IntersectClipRegion( aReg.ConvertToB2DPolyPolygon() );
909*cdf0e10cSrcweir 				}
910*cdf0e10cSrcweir 				break;
911*cdf0e10cSrcweir 
912*cdf0e10cSrcweir 				case( META_MOVECLIPREGION_ACTION ):
913*cdf0e10cSrcweir 				{
914*cdf0e10cSrcweir 					const MetaMoveClipRegionAction* pA = (const MetaMoveClipRegionAction*) pAction;
915*cdf0e10cSrcweir 					m_rOuterFace.MoveClipRegion( pA->GetHorzMove(), pA->GetVertMove() );
916*cdf0e10cSrcweir 				}
917*cdf0e10cSrcweir 				break;
918*cdf0e10cSrcweir 
919*cdf0e10cSrcweir 				case( META_MAPMODE_ACTION ):
920*cdf0e10cSrcweir 				{
921*cdf0e10cSrcweir 					const_cast< MetaAction* >( pAction )->Execute( pDummyVDev );
922*cdf0e10cSrcweir 					m_rOuterFace.SetMapMode( pDummyVDev->GetMapMode() );
923*cdf0e10cSrcweir 				}
924*cdf0e10cSrcweir 				break;
925*cdf0e10cSrcweir 
926*cdf0e10cSrcweir 				case( META_LINECOLOR_ACTION	):
927*cdf0e10cSrcweir 				{
928*cdf0e10cSrcweir 					const MetaLineColorAction* pA = (const MetaLineColorAction*) pAction;
929*cdf0e10cSrcweir 
930*cdf0e10cSrcweir 					if( pA->IsSetting() )
931*cdf0e10cSrcweir 						m_rOuterFace.SetLineColor( pA->GetColor() );
932*cdf0e10cSrcweir 					else
933*cdf0e10cSrcweir 						m_rOuterFace.SetLineColor();
934*cdf0e10cSrcweir 				}
935*cdf0e10cSrcweir 				break;
936*cdf0e10cSrcweir 
937*cdf0e10cSrcweir 				case( META_FILLCOLOR_ACTION	):
938*cdf0e10cSrcweir 				{
939*cdf0e10cSrcweir 					const MetaFillColorAction* pA = (const MetaFillColorAction*) pAction;
940*cdf0e10cSrcweir 
941*cdf0e10cSrcweir 					if( pA->IsSetting() )
942*cdf0e10cSrcweir 						m_rOuterFace.SetFillColor( pA->GetColor() );
943*cdf0e10cSrcweir 					else
944*cdf0e10cSrcweir 						m_rOuterFace.SetFillColor();
945*cdf0e10cSrcweir 				}
946*cdf0e10cSrcweir 				break;
947*cdf0e10cSrcweir 
948*cdf0e10cSrcweir 				case( META_TEXTLINECOLOR_ACTION ):
949*cdf0e10cSrcweir 				{
950*cdf0e10cSrcweir 					const MetaTextLineColorAction* pA = (const MetaTextLineColorAction*) pAction;
951*cdf0e10cSrcweir 
952*cdf0e10cSrcweir 					if( pA->IsSetting() )
953*cdf0e10cSrcweir 						m_rOuterFace.SetTextLineColor( pA->GetColor() );
954*cdf0e10cSrcweir 					else
955*cdf0e10cSrcweir 						m_rOuterFace.SetTextLineColor();
956*cdf0e10cSrcweir 				}
957*cdf0e10cSrcweir 				break;
958*cdf0e10cSrcweir 
959*cdf0e10cSrcweir 				case( META_OVERLINECOLOR_ACTION ):
960*cdf0e10cSrcweir 				{
961*cdf0e10cSrcweir 					const MetaOverlineColorAction* pA = (const MetaOverlineColorAction*) pAction;
962*cdf0e10cSrcweir 
963*cdf0e10cSrcweir 					if( pA->IsSetting() )
964*cdf0e10cSrcweir 						m_rOuterFace.SetOverlineColor( pA->GetColor() );
965*cdf0e10cSrcweir 					else
966*cdf0e10cSrcweir 						m_rOuterFace.SetOverlineColor();
967*cdf0e10cSrcweir 				}
968*cdf0e10cSrcweir 				break;
969*cdf0e10cSrcweir 
970*cdf0e10cSrcweir 				case( META_TEXTFILLCOLOR_ACTION	):
971*cdf0e10cSrcweir 				{
972*cdf0e10cSrcweir 					const MetaTextFillColorAction* pA = (const MetaTextFillColorAction*) pAction;
973*cdf0e10cSrcweir 
974*cdf0e10cSrcweir 					if( pA->IsSetting() )
975*cdf0e10cSrcweir 						m_rOuterFace.SetTextFillColor( pA->GetColor() );
976*cdf0e10cSrcweir 					else
977*cdf0e10cSrcweir 						m_rOuterFace.SetTextFillColor();
978*cdf0e10cSrcweir 				}
979*cdf0e10cSrcweir 				break;
980*cdf0e10cSrcweir 
981*cdf0e10cSrcweir 				case( META_TEXTCOLOR_ACTION	):
982*cdf0e10cSrcweir 				{
983*cdf0e10cSrcweir 					const MetaTextColorAction* pA = (const MetaTextColorAction*) pAction;
984*cdf0e10cSrcweir 					m_rOuterFace.SetTextColor( pA->GetColor() );
985*cdf0e10cSrcweir 				}
986*cdf0e10cSrcweir 				break;
987*cdf0e10cSrcweir 
988*cdf0e10cSrcweir 				case( META_TEXTALIGN_ACTION	):
989*cdf0e10cSrcweir 				{
990*cdf0e10cSrcweir 					const MetaTextAlignAction* pA = (const MetaTextAlignAction*) pAction;
991*cdf0e10cSrcweir 					m_rOuterFace.SetTextAlign( pA->GetTextAlign() );
992*cdf0e10cSrcweir 				}
993*cdf0e10cSrcweir 				break;
994*cdf0e10cSrcweir 
995*cdf0e10cSrcweir 				case( META_FONT_ACTION ):
996*cdf0e10cSrcweir 				{
997*cdf0e10cSrcweir 					const MetaFontAction* pA = (const MetaFontAction*) pAction;
998*cdf0e10cSrcweir 					m_rOuterFace.SetFont( pA->GetFont() );
999*cdf0e10cSrcweir 				}
1000*cdf0e10cSrcweir 				break;
1001*cdf0e10cSrcweir 
1002*cdf0e10cSrcweir 				case( META_PUSH_ACTION ):
1003*cdf0e10cSrcweir 				{
1004*cdf0e10cSrcweir 					const MetaPushAction* pA = (const MetaPushAction*) pAction;
1005*cdf0e10cSrcweir 
1006*cdf0e10cSrcweir 					pDummyVDev->Push( pA->GetFlags() );
1007*cdf0e10cSrcweir 					m_rOuterFace.Push( pA->GetFlags() );
1008*cdf0e10cSrcweir 				}
1009*cdf0e10cSrcweir 				break;
1010*cdf0e10cSrcweir 
1011*cdf0e10cSrcweir 				case( META_POP_ACTION ):
1012*cdf0e10cSrcweir 				{
1013*cdf0e10cSrcweir 					pDummyVDev->Pop();
1014*cdf0e10cSrcweir 					m_rOuterFace.Pop();
1015*cdf0e10cSrcweir 				}
1016*cdf0e10cSrcweir 				break;
1017*cdf0e10cSrcweir 
1018*cdf0e10cSrcweir 				case( META_LAYOUTMODE_ACTION ):
1019*cdf0e10cSrcweir 				{
1020*cdf0e10cSrcweir 					const MetaLayoutModeAction* pA = (const MetaLayoutModeAction*) pAction;
1021*cdf0e10cSrcweir 					m_rOuterFace.SetLayoutMode( pA->GetLayoutMode() );
1022*cdf0e10cSrcweir 				}
1023*cdf0e10cSrcweir 				break;
1024*cdf0e10cSrcweir 
1025*cdf0e10cSrcweir 				case META_TEXTLANGUAGE_ACTION:
1026*cdf0e10cSrcweir 				{
1027*cdf0e10cSrcweir 					const  MetaTextLanguageAction* pA = (const MetaTextLanguageAction*) pAction;
1028*cdf0e10cSrcweir                     m_rOuterFace.SetDigitLanguage( pA->GetTextLanguage() );
1029*cdf0e10cSrcweir 				}
1030*cdf0e10cSrcweir 				break;
1031*cdf0e10cSrcweir 
1032*cdf0e10cSrcweir 				case( META_WALLPAPER_ACTION	):
1033*cdf0e10cSrcweir 				{
1034*cdf0e10cSrcweir 					const MetaWallpaperAction* pA = (const MetaWallpaperAction*) pAction;
1035*cdf0e10cSrcweir 					m_rOuterFace.DrawWallpaper( pA->GetRect(), pA->GetWallpaper() );
1036*cdf0e10cSrcweir 				}
1037*cdf0e10cSrcweir 				break;
1038*cdf0e10cSrcweir 
1039*cdf0e10cSrcweir 				case( META_RASTEROP_ACTION ):
1040*cdf0e10cSrcweir 				{
1041*cdf0e10cSrcweir 					// !!! >>> we don't want to support this actions
1042*cdf0e10cSrcweir 				}
1043*cdf0e10cSrcweir 				break;
1044*cdf0e10cSrcweir 
1045*cdf0e10cSrcweir 				case( META_REFPOINT_ACTION ):
1046*cdf0e10cSrcweir 				{
1047*cdf0e10cSrcweir 					// !!! >>> we don't want to support this actions
1048*cdf0e10cSrcweir 				}
1049*cdf0e10cSrcweir 				break;
1050*cdf0e10cSrcweir 
1051*cdf0e10cSrcweir 				case( META_RENDERGRAPHIC_ACTION ):
1052*cdf0e10cSrcweir 				{
1053*cdf0e10cSrcweir 					const MetaRenderGraphicAction* pA = static_cast< const MetaRenderGraphicAction* >( pAction );
1054*cdf0e10cSrcweir                     const ::vcl::RenderGraphicRasterizer aRasterizer( pA->GetRenderGraphic() );
1055*cdf0e10cSrcweir 
1056*cdf0e10cSrcweir 					implWriteBitmapEx( pA->GetPoint(), pA->GetSize(),
1057*cdf0e10cSrcweir                                        aRasterizer.Rasterize( pDummyVDev->LogicToPixel( pA->GetSize() ) ),
1058*cdf0e10cSrcweir                                        pDummyVDev, i_rContext );
1059*cdf0e10cSrcweir 				}
1060*cdf0e10cSrcweir 				break;
1061*cdf0e10cSrcweir 
1062*cdf0e10cSrcweir 				default:
1063*cdf0e10cSrcweir 					// #i24604# Made assertion fire only once per
1064*cdf0e10cSrcweir 					// metafile. The asserted actions here are all
1065*cdf0e10cSrcweir 					// deprecated
1066*cdf0e10cSrcweir 					if( !bAssertionFired )
1067*cdf0e10cSrcweir 					{
1068*cdf0e10cSrcweir 						bAssertionFired = true;
1069*cdf0e10cSrcweir 						DBG_ERROR( "PDFExport::ImplWriteActions: deprecated and unsupported MetaAction encountered" );
1070*cdf0e10cSrcweir 					}
1071*cdf0e10cSrcweir 				break;
1072*cdf0e10cSrcweir 			}
1073*cdf0e10cSrcweir 			i++;
1074*cdf0e10cSrcweir 		}
1075*cdf0e10cSrcweir 	}
1076*cdf0e10cSrcweir 
1077*cdf0e10cSrcweir     delete pPrivateDevice;
1078*cdf0e10cSrcweir }
1079*cdf0e10cSrcweir 
1080*cdf0e10cSrcweir // Encryption methods
1081*cdf0e10cSrcweir 
1082*cdf0e10cSrcweir /* a crutch to transport an rtlDigest safely though UNO API
1083*cdf0e10cSrcweir    this is needed for the PDF export dialog, which otherwise would have to pass
1084*cdf0e10cSrcweir    clear text passwords down till they can be used in PDFWriter. Unfortunately
1085*cdf0e10cSrcweir    the MD5 sum of the password (which is needed to create the PDF encryption key)
1086*cdf0e10cSrcweir    is not sufficient, since an rtl MD5 digest cannot be created in an arbitrary state
1087*cdf0e10cSrcweir    which would be needed in PDFWriterImpl::computeEncryptionKey.
1088*cdf0e10cSrcweir */
1089*cdf0e10cSrcweir class EncHashTransporter : public cppu::WeakImplHelper1 < com::sun::star::beans::XMaterialHolder >
1090*cdf0e10cSrcweir {
1091*cdf0e10cSrcweir     rtlDigest                   maUDigest;
1092*cdf0e10cSrcweir     sal_IntPtr                  maID;
1093*cdf0e10cSrcweir     std::vector< sal_uInt8 >    maOValue;
1094*cdf0e10cSrcweir 
1095*cdf0e10cSrcweir     static std::map< sal_IntPtr, EncHashTransporter* >      sTransporters;
1096*cdf0e10cSrcweir public:
1097*cdf0e10cSrcweir     EncHashTransporter()
1098*cdf0e10cSrcweir     : maUDigest( rtl_digest_createMD5() )
1099*cdf0e10cSrcweir     {
1100*cdf0e10cSrcweir         maID = reinterpret_cast< sal_IntPtr >(this);
1101*cdf0e10cSrcweir         while( sTransporters.find( maID ) != sTransporters.end() ) // paranoia mode
1102*cdf0e10cSrcweir             maID++;
1103*cdf0e10cSrcweir         sTransporters[ maID ] = this;
1104*cdf0e10cSrcweir     }
1105*cdf0e10cSrcweir 
1106*cdf0e10cSrcweir     virtual ~EncHashTransporter()
1107*cdf0e10cSrcweir     {
1108*cdf0e10cSrcweir         sTransporters.erase( maID );
1109*cdf0e10cSrcweir         if( maUDigest )
1110*cdf0e10cSrcweir             rtl_digest_destroyMD5( maUDigest );
1111*cdf0e10cSrcweir         OSL_TRACE( "EncHashTransporter freed\n" );
1112*cdf0e10cSrcweir     }
1113*cdf0e10cSrcweir 
1114*cdf0e10cSrcweir     rtlDigest getUDigest() const { return maUDigest; };
1115*cdf0e10cSrcweir     std::vector< sal_uInt8 >& getOValue() { return maOValue; }
1116*cdf0e10cSrcweir     void invalidate()
1117*cdf0e10cSrcweir     {
1118*cdf0e10cSrcweir         if( maUDigest )
1119*cdf0e10cSrcweir         {
1120*cdf0e10cSrcweir             rtl_digest_destroyMD5( maUDigest );
1121*cdf0e10cSrcweir             maUDigest = NULL;
1122*cdf0e10cSrcweir         }
1123*cdf0e10cSrcweir     }
1124*cdf0e10cSrcweir 
1125*cdf0e10cSrcweir     // XMaterialHolder
1126*cdf0e10cSrcweir     virtual uno::Any SAL_CALL getMaterial() throw()
1127*cdf0e10cSrcweir     {
1128*cdf0e10cSrcweir         return uno::makeAny( sal_Int64(maID) );
1129*cdf0e10cSrcweir     }
1130*cdf0e10cSrcweir 
1131*cdf0e10cSrcweir     static EncHashTransporter* getEncHashTransporter( const uno::Reference< beans::XMaterialHolder >& );
1132*cdf0e10cSrcweir 
1133*cdf0e10cSrcweir };
1134*cdf0e10cSrcweir 
1135*cdf0e10cSrcweir std::map< sal_IntPtr, EncHashTransporter* > EncHashTransporter::sTransporters;
1136*cdf0e10cSrcweir 
1137*cdf0e10cSrcweir EncHashTransporter* EncHashTransporter::getEncHashTransporter( const uno::Reference< beans::XMaterialHolder >& xRef )
1138*cdf0e10cSrcweir {
1139*cdf0e10cSrcweir     EncHashTransporter* pResult = NULL;
1140*cdf0e10cSrcweir     if( xRef.is() )
1141*cdf0e10cSrcweir     {
1142*cdf0e10cSrcweir         uno::Any aMat( xRef->getMaterial() );
1143*cdf0e10cSrcweir         sal_Int64 nMat = 0;
1144*cdf0e10cSrcweir         if( aMat >>= nMat )
1145*cdf0e10cSrcweir         {
1146*cdf0e10cSrcweir             std::map< sal_IntPtr, EncHashTransporter* >::iterator it = sTransporters.find( static_cast<sal_IntPtr>(nMat) );
1147*cdf0e10cSrcweir             if( it != sTransporters.end() )
1148*cdf0e10cSrcweir                 pResult = it->second;
1149*cdf0e10cSrcweir         }
1150*cdf0e10cSrcweir     }
1151*cdf0e10cSrcweir     return pResult;
1152*cdf0e10cSrcweir }
1153*cdf0e10cSrcweir 
1154*cdf0e10cSrcweir sal_Bool PDFWriterImpl::checkEncryptionBufferSize( register sal_Int32 newSize )
1155*cdf0e10cSrcweir {
1156*cdf0e10cSrcweir     if( m_nEncryptionBufferSize < newSize )
1157*cdf0e10cSrcweir     {
1158*cdf0e10cSrcweir         /* reallocate the buffer, the used function allocate as rtl_allocateMemory
1159*cdf0e10cSrcweir         if the pointer parameter is NULL */
1160*cdf0e10cSrcweir         m_pEncryptionBuffer = (sal_uInt8*)rtl_reallocateMemory( m_pEncryptionBuffer, newSize );
1161*cdf0e10cSrcweir         if( m_pEncryptionBuffer )
1162*cdf0e10cSrcweir             m_nEncryptionBufferSize = newSize;
1163*cdf0e10cSrcweir         else
1164*cdf0e10cSrcweir             m_nEncryptionBufferSize = 0;
1165*cdf0e10cSrcweir     }
1166*cdf0e10cSrcweir     return ( m_nEncryptionBufferSize != 0 );
1167*cdf0e10cSrcweir }
1168*cdf0e10cSrcweir 
1169*cdf0e10cSrcweir void PDFWriterImpl::checkAndEnableStreamEncryption( register sal_Int32 nObject )
1170*cdf0e10cSrcweir {
1171*cdf0e10cSrcweir     if( m_aContext.Encryption.Encrypt() )
1172*cdf0e10cSrcweir     {
1173*cdf0e10cSrcweir         m_bEncryptThisStream = true;
1174*cdf0e10cSrcweir         sal_Int32 i = m_nKeyLength;
1175*cdf0e10cSrcweir         m_aContext.Encryption.EncryptionKey[i++] = (sal_uInt8)nObject;
1176*cdf0e10cSrcweir         m_aContext.Encryption.EncryptionKey[i++] = (sal_uInt8)( nObject >> 8 );
1177*cdf0e10cSrcweir         m_aContext.Encryption.EncryptionKey[i++] = (sal_uInt8)( nObject >> 16 );
1178*cdf0e10cSrcweir         //the other location of m_nEncryptionKey are already set to 0, our fixed generation number
1179*cdf0e10cSrcweir         // do the MD5 hash
1180*cdf0e10cSrcweir         sal_uInt8 nMD5Sum[ RTL_DIGEST_LENGTH_MD5 ];
1181*cdf0e10cSrcweir         // the i+2 to take into account the generation number, always zero
1182*cdf0e10cSrcweir         rtl_digest_MD5( &m_aContext.Encryption.EncryptionKey[0], i+2, nMD5Sum, sizeof(nMD5Sum) );
1183*cdf0e10cSrcweir         // initialize the RC4 with the key
1184*cdf0e10cSrcweir         // key legth: see algoritm 3.1, step 4: (N+5) max 16
1185*cdf0e10cSrcweir         rtl_cipher_initARCFOUR( m_aCipher, rtl_Cipher_DirectionEncode, nMD5Sum, m_nRC4KeyLength, NULL, 0 );
1186*cdf0e10cSrcweir     }
1187*cdf0e10cSrcweir }
1188*cdf0e10cSrcweir 
1189*cdf0e10cSrcweir void PDFWriterImpl::enableStringEncryption( register sal_Int32 nObject )
1190*cdf0e10cSrcweir {
1191*cdf0e10cSrcweir     if( m_aContext.Encryption.Encrypt() )
1192*cdf0e10cSrcweir     {
1193*cdf0e10cSrcweir         sal_Int32 i = m_nKeyLength;
1194*cdf0e10cSrcweir         m_aContext.Encryption.EncryptionKey[i++] = (sal_uInt8)nObject;
1195*cdf0e10cSrcweir         m_aContext.Encryption.EncryptionKey[i++] = (sal_uInt8)( nObject >> 8 );
1196*cdf0e10cSrcweir         m_aContext.Encryption.EncryptionKey[i++] = (sal_uInt8)( nObject >> 16 );
1197*cdf0e10cSrcweir         //the other location of m_nEncryptionKey are already set to 0, our fixed generation number
1198*cdf0e10cSrcweir         // do the MD5 hash
1199*cdf0e10cSrcweir         sal_uInt8 nMD5Sum[ RTL_DIGEST_LENGTH_MD5 ];
1200*cdf0e10cSrcweir         // the i+2 to take into account the generation number, always zero
1201*cdf0e10cSrcweir         rtl_digest_MD5( &m_aContext.Encryption.EncryptionKey[0], i+2, nMD5Sum, sizeof(nMD5Sum) );
1202*cdf0e10cSrcweir         // initialize the RC4 with the key
1203*cdf0e10cSrcweir         // key legth: see algoritm 3.1, step 4: (N+5) max 16
1204*cdf0e10cSrcweir         rtl_cipher_initARCFOUR( m_aCipher, rtl_Cipher_DirectionEncode, nMD5Sum, m_nRC4KeyLength, NULL, 0 );
1205*cdf0e10cSrcweir     }
1206*cdf0e10cSrcweir }
1207*cdf0e10cSrcweir 
1208*cdf0e10cSrcweir /* init the encryption engine
1209*cdf0e10cSrcweir 1. init the document id, used both for building the document id and for building the encryption key(s)
1210*cdf0e10cSrcweir 2. build the encryption key following algorithms described in the PDF specification
1211*cdf0e10cSrcweir  */
1212*cdf0e10cSrcweir uno::Reference< beans::XMaterialHolder > PDFWriterImpl::initEncryption( const rtl::OUString& i_rOwnerPassword,
1213*cdf0e10cSrcweir                                                                         const rtl::OUString& i_rUserPassword,
1214*cdf0e10cSrcweir                                                                         bool b128Bit
1215*cdf0e10cSrcweir                                                                         )
1216*cdf0e10cSrcweir {
1217*cdf0e10cSrcweir     uno::Reference< beans::XMaterialHolder > xResult;
1218*cdf0e10cSrcweir     if( i_rOwnerPassword.getLength() || i_rUserPassword.getLength() )
1219*cdf0e10cSrcweir     {
1220*cdf0e10cSrcweir         EncHashTransporter* pTransporter = new EncHashTransporter;
1221*cdf0e10cSrcweir         xResult = pTransporter;
1222*cdf0e10cSrcweir 
1223*cdf0e10cSrcweir         // get padded passwords
1224*cdf0e10cSrcweir         sal_uInt8 aPadUPW[ENCRYPTED_PWD_SIZE], aPadOPW[ENCRYPTED_PWD_SIZE];
1225*cdf0e10cSrcweir         padPassword( i_rOwnerPassword.getLength() ? i_rOwnerPassword : i_rUserPassword, aPadOPW );
1226*cdf0e10cSrcweir         padPassword( i_rUserPassword, aPadUPW );
1227*cdf0e10cSrcweir         sal_Int32 nKeyLength = SECUR_40BIT_KEY;
1228*cdf0e10cSrcweir         if( b128Bit )
1229*cdf0e10cSrcweir             nKeyLength = SECUR_128BIT_KEY;
1230*cdf0e10cSrcweir 
1231*cdf0e10cSrcweir         if( computeODictionaryValue( aPadOPW, aPadUPW, pTransporter->getOValue(), nKeyLength ) )
1232*cdf0e10cSrcweir         {
1233*cdf0e10cSrcweir             rtlDigest aDig = pTransporter->getUDigest();
1234*cdf0e10cSrcweir             if( rtl_digest_updateMD5( aDig, aPadUPW, ENCRYPTED_PWD_SIZE ) != rtl_Digest_E_None )
1235*cdf0e10cSrcweir                 xResult.clear();
1236*cdf0e10cSrcweir         }
1237*cdf0e10cSrcweir         else
1238*cdf0e10cSrcweir             xResult.clear();
1239*cdf0e10cSrcweir 
1240*cdf0e10cSrcweir         // trash temporary padded cleartext PWDs
1241*cdf0e10cSrcweir         rtl_zeroMemory( aPadOPW, sizeof(aPadOPW) );
1242*cdf0e10cSrcweir         rtl_zeroMemory( aPadUPW, sizeof(aPadUPW) );
1243*cdf0e10cSrcweir 
1244*cdf0e10cSrcweir     }
1245*cdf0e10cSrcweir     return xResult;
1246*cdf0e10cSrcweir }
1247*cdf0e10cSrcweir 
1248*cdf0e10cSrcweir bool PDFWriterImpl::prepareEncryption( const uno::Reference< beans::XMaterialHolder >& xEnc )
1249*cdf0e10cSrcweir {
1250*cdf0e10cSrcweir     bool bSuccess = false;
1251*cdf0e10cSrcweir     EncHashTransporter* pTransporter = EncHashTransporter::getEncHashTransporter( xEnc );
1252*cdf0e10cSrcweir     if( pTransporter )
1253*cdf0e10cSrcweir     {
1254*cdf0e10cSrcweir         sal_Int32 nKeyLength = 0, nRC4KeyLength = 0;
1255*cdf0e10cSrcweir         sal_Int32 nAccessPermissions = computeAccessPermissions( m_aContext.Encryption, nKeyLength, nRC4KeyLength );
1256*cdf0e10cSrcweir         m_aContext.Encryption.OValue = pTransporter->getOValue();
1257*cdf0e10cSrcweir         bSuccess = computeUDictionaryValue( pTransporter, m_aContext.Encryption, nKeyLength, nAccessPermissions );
1258*cdf0e10cSrcweir     }
1259*cdf0e10cSrcweir     if( ! bSuccess )
1260*cdf0e10cSrcweir     {
1261*cdf0e10cSrcweir         m_aContext.Encryption.OValue.clear();
1262*cdf0e10cSrcweir         m_aContext.Encryption.UValue.clear();
1263*cdf0e10cSrcweir         m_aContext.Encryption.EncryptionKey.clear();
1264*cdf0e10cSrcweir     }
1265*cdf0e10cSrcweir     return bSuccess;
1266*cdf0e10cSrcweir }
1267*cdf0e10cSrcweir 
1268*cdf0e10cSrcweir sal_Int32 PDFWriterImpl::computeAccessPermissions( const vcl::PDFWriter::PDFEncryptionProperties& i_rProperties,
1269*cdf0e10cSrcweir 	                                               sal_Int32& o_rKeyLength, sal_Int32& o_rRC4KeyLength )
1270*cdf0e10cSrcweir {
1271*cdf0e10cSrcweir     /*
1272*cdf0e10cSrcweir     2) compute the access permissions, in numerical form
1273*cdf0e10cSrcweir 
1274*cdf0e10cSrcweir     the default value depends on the revision 2 (40 bit) or 3 (128 bit security):
1275*cdf0e10cSrcweir     - for 40 bit security the unused bit must be set to 1, since they are not used
1276*cdf0e10cSrcweir     - for 128 bit security the same bit must be preset to 0 and set later if needed
1277*cdf0e10cSrcweir     according to the table 3.15, pdf v 1.4 */
1278*cdf0e10cSrcweir     sal_Int32 nAccessPermissions = ( i_rProperties.Security128bit ) ? 0xfffff0c0 : 0xffffffc0 ;
1279*cdf0e10cSrcweir 
1280*cdf0e10cSrcweir     /* check permissions for 40 bit security case */
1281*cdf0e10cSrcweir     nAccessPermissions |= ( i_rProperties.CanPrintTheDocument ) ?  1 << 2 : 0;
1282*cdf0e10cSrcweir     nAccessPermissions |= ( i_rProperties.CanModifyTheContent ) ? 1 << 3 : 0;
1283*cdf0e10cSrcweir     nAccessPermissions |= ( i_rProperties.CanCopyOrExtract ) ?   1 << 4 : 0;
1284*cdf0e10cSrcweir     nAccessPermissions |= ( i_rProperties.CanAddOrModify ) ? 1 << 5 : 0;
1285*cdf0e10cSrcweir     o_rKeyLength = SECUR_40BIT_KEY;
1286*cdf0e10cSrcweir     o_rRC4KeyLength = SECUR_40BIT_KEY+5; // for this value see PDF spec v 1.4, algorithm 3.1 step 4, where n is 5
1287*cdf0e10cSrcweir 
1288*cdf0e10cSrcweir     if( i_rProperties.Security128bit )
1289*cdf0e10cSrcweir     {
1290*cdf0e10cSrcweir         o_rKeyLength = SECUR_128BIT_KEY;
1291*cdf0e10cSrcweir         o_rRC4KeyLength = 16; // for this value see PDF spec v 1.4, algorithm 3.1 step 4, where n is 16, thus maximum
1292*cdf0e10cSrcweir         // permitted value is 16
1293*cdf0e10cSrcweir         nAccessPermissions |= ( i_rProperties.CanFillInteractive ) ?         1 << 8 : 0;
1294*cdf0e10cSrcweir         nAccessPermissions |= ( i_rProperties.CanExtractForAccessibility ) ? 1 << 9 : 0;
1295*cdf0e10cSrcweir         nAccessPermissions |= ( i_rProperties.CanAssemble ) ?                1 << 10 : 0;
1296*cdf0e10cSrcweir         nAccessPermissions |= ( i_rProperties.CanPrintFull ) ?               1 << 11 : 0;
1297*cdf0e10cSrcweir     }
1298*cdf0e10cSrcweir     return nAccessPermissions;
1299*cdf0e10cSrcweir }
1300*cdf0e10cSrcweir 
1301*cdf0e10cSrcweir /*************************************************************
1302*cdf0e10cSrcweir begin i12626 methods
1303*cdf0e10cSrcweir 
1304*cdf0e10cSrcweir Implements Algorithm 3.2, step 1 only
1305*cdf0e10cSrcweir */
1306*cdf0e10cSrcweir void PDFWriterImpl::padPassword( const rtl::OUString& i_rPassword, sal_uInt8* o_pPaddedPW )
1307*cdf0e10cSrcweir {
1308*cdf0e10cSrcweir     // get ansi-1252 version of the password string CHECKIT ! i12626
1309*cdf0e10cSrcweir     rtl::OString aString( rtl::OUStringToOString( i_rPassword, RTL_TEXTENCODING_MS_1252 ) );
1310*cdf0e10cSrcweir 
1311*cdf0e10cSrcweir     //copy the string to the target
1312*cdf0e10cSrcweir     sal_Int32 nToCopy = ( aString.getLength() < ENCRYPTED_PWD_SIZE ) ? aString.getLength() : ENCRYPTED_PWD_SIZE;
1313*cdf0e10cSrcweir     sal_Int32 nCurrentChar;
1314*cdf0e10cSrcweir 
1315*cdf0e10cSrcweir     for( nCurrentChar = 0; nCurrentChar < nToCopy; nCurrentChar++ )
1316*cdf0e10cSrcweir         o_pPaddedPW[nCurrentChar] = (sal_uInt8)( aString.getStr()[nCurrentChar] );
1317*cdf0e10cSrcweir 
1318*cdf0e10cSrcweir     //pad it with standard byte string
1319*cdf0e10cSrcweir     sal_Int32 i,y;
1320*cdf0e10cSrcweir     for( i = nCurrentChar, y = 0 ; i < ENCRYPTED_PWD_SIZE; i++, y++ )
1321*cdf0e10cSrcweir         o_pPaddedPW[i] = s_nPadString[y];
1322*cdf0e10cSrcweir 
1323*cdf0e10cSrcweir     // trash memory of temporary clear text password
1324*cdf0e10cSrcweir     rtl_zeroMemory( (sal_Char*)aString.getStr(), aString.getLength() );
1325*cdf0e10cSrcweir }
1326*cdf0e10cSrcweir 
1327*cdf0e10cSrcweir /**********************************
1328*cdf0e10cSrcweir Algorithm 3.2  Compute the encryption key used
1329*cdf0e10cSrcweir 
1330*cdf0e10cSrcweir step 1 should already be done before calling, the paThePaddedPassword parameter should contain
1331*cdf0e10cSrcweir the padded password and must be 32 byte long, the encryption key is returned into the paEncryptionKey parameter,
1332*cdf0e10cSrcweir it will be 16 byte long for 128 bit security; for 40 bit security only the first 5 bytes are used
1333*cdf0e10cSrcweir 
1334*cdf0e10cSrcweir TODO: in pdf ver 1.5 and 1.6 the step 6 is different, should be implemented. See spec.
1335*cdf0e10cSrcweir 
1336*cdf0e10cSrcweir */
1337*cdf0e10cSrcweir bool PDFWriterImpl::computeEncryptionKey( EncHashTransporter* i_pTransporter, vcl::PDFWriter::PDFEncryptionProperties& io_rProperties, sal_Int32 i_nAccessPermissions )
1338*cdf0e10cSrcweir {
1339*cdf0e10cSrcweir     bool bSuccess = true;
1340*cdf0e10cSrcweir     sal_uInt8 nMD5Sum[ RTL_DIGEST_LENGTH_MD5 ];
1341*cdf0e10cSrcweir 
1342*cdf0e10cSrcweir     // transporter contains an MD5 digest with the padded user password already
1343*cdf0e10cSrcweir     rtlDigest aDigest = i_pTransporter->getUDigest();
1344*cdf0e10cSrcweir     rtlDigestError nError = rtl_Digest_E_None;
1345*cdf0e10cSrcweir     if( aDigest )
1346*cdf0e10cSrcweir     {
1347*cdf0e10cSrcweir         //step 3
1348*cdf0e10cSrcweir         if( ! io_rProperties.OValue.empty() )
1349*cdf0e10cSrcweir             nError = rtl_digest_updateMD5( aDigest, &io_rProperties.OValue[0] , sal_Int32(io_rProperties.OValue.size()) );
1350*cdf0e10cSrcweir         else
1351*cdf0e10cSrcweir             bSuccess = false;
1352*cdf0e10cSrcweir         //Step 4
1353*cdf0e10cSrcweir         sal_uInt8 nPerm[4];
1354*cdf0e10cSrcweir 
1355*cdf0e10cSrcweir         nPerm[0] = (sal_uInt8)i_nAccessPermissions;
1356*cdf0e10cSrcweir         nPerm[1] = (sal_uInt8)( i_nAccessPermissions >> 8 );
1357*cdf0e10cSrcweir         nPerm[2] = (sal_uInt8)( i_nAccessPermissions >> 16 );
1358*cdf0e10cSrcweir         nPerm[3] = (sal_uInt8)( i_nAccessPermissions >> 24 );
1359*cdf0e10cSrcweir 
1360*cdf0e10cSrcweir         if( nError == rtl_Digest_E_None )
1361*cdf0e10cSrcweir             nError = rtl_digest_updateMD5( aDigest, nPerm , sizeof( nPerm ) );
1362*cdf0e10cSrcweir 
1363*cdf0e10cSrcweir         //step 5, get the document ID, binary form
1364*cdf0e10cSrcweir         if( nError == rtl_Digest_E_None )
1365*cdf0e10cSrcweir             nError = rtl_digest_updateMD5( aDigest, &io_rProperties.DocumentIdentifier[0], sal_Int32(io_rProperties.DocumentIdentifier.size()) );
1366*cdf0e10cSrcweir         //get the digest
1367*cdf0e10cSrcweir         if( nError == rtl_Digest_E_None )
1368*cdf0e10cSrcweir         {
1369*cdf0e10cSrcweir             rtl_digest_getMD5( aDigest, nMD5Sum, sizeof( nMD5Sum ) );
1370*cdf0e10cSrcweir 
1371*cdf0e10cSrcweir             //step 6, only if 128 bit
1372*cdf0e10cSrcweir             if( io_rProperties.Security128bit )
1373*cdf0e10cSrcweir             {
1374*cdf0e10cSrcweir                 for( sal_Int32 i = 0; i < 50; i++ )
1375*cdf0e10cSrcweir                 {
1376*cdf0e10cSrcweir                     nError = rtl_digest_updateMD5( aDigest, &nMD5Sum, sizeof( nMD5Sum ) );
1377*cdf0e10cSrcweir                     if( nError != rtl_Digest_E_None )
1378*cdf0e10cSrcweir                     {
1379*cdf0e10cSrcweir                         bSuccess =  false;
1380*cdf0e10cSrcweir                         break;
1381*cdf0e10cSrcweir                     }
1382*cdf0e10cSrcweir                     rtl_digest_getMD5( aDigest, nMD5Sum, sizeof( nMD5Sum ) );
1383*cdf0e10cSrcweir                 }
1384*cdf0e10cSrcweir             }
1385*cdf0e10cSrcweir         }
1386*cdf0e10cSrcweir     }
1387*cdf0e10cSrcweir     else
1388*cdf0e10cSrcweir         bSuccess = false;
1389*cdf0e10cSrcweir 
1390*cdf0e10cSrcweir     i_pTransporter->invalidate();
1391*cdf0e10cSrcweir 
1392*cdf0e10cSrcweir     //Step 7
1393*cdf0e10cSrcweir     if( bSuccess )
1394*cdf0e10cSrcweir     {
1395*cdf0e10cSrcweir         io_rProperties.EncryptionKey.resize( MAXIMUM_RC4_KEY_LENGTH );
1396*cdf0e10cSrcweir         for( sal_Int32 i = 0; i < MD5_DIGEST_SIZE; i++ )
1397*cdf0e10cSrcweir             io_rProperties.EncryptionKey[i] = nMD5Sum[i];
1398*cdf0e10cSrcweir     }
1399*cdf0e10cSrcweir     else
1400*cdf0e10cSrcweir         io_rProperties.EncryptionKey.clear();
1401*cdf0e10cSrcweir 
1402*cdf0e10cSrcweir     return bSuccess;
1403*cdf0e10cSrcweir }
1404*cdf0e10cSrcweir 
1405*cdf0e10cSrcweir /**********************************
1406*cdf0e10cSrcweir Algorithm 3.3  Compute the encryption dictionary /O value, save into the class data member
1407*cdf0e10cSrcweir the step numbers down here correspond to the ones in PDF v.1.4 specfication
1408*cdf0e10cSrcweir */
1409*cdf0e10cSrcweir bool PDFWriterImpl::computeODictionaryValue( const sal_uInt8* i_pPaddedOwnerPassword,
1410*cdf0e10cSrcweir                                              const sal_uInt8* i_pPaddedUserPassword,
1411*cdf0e10cSrcweir                                              std::vector< sal_uInt8 >& io_rOValue,
1412*cdf0e10cSrcweir                                              sal_Int32 i_nKeyLength
1413*cdf0e10cSrcweir                                              )
1414*cdf0e10cSrcweir {
1415*cdf0e10cSrcweir     bool bSuccess = true;
1416*cdf0e10cSrcweir 
1417*cdf0e10cSrcweir     io_rOValue.resize( ENCRYPTED_PWD_SIZE );
1418*cdf0e10cSrcweir 
1419*cdf0e10cSrcweir     rtlDigest aDigest = rtl_digest_createMD5();
1420*cdf0e10cSrcweir     rtlCipher aCipher = rtl_cipher_createARCFOUR( rtl_Cipher_ModeStream );
1421*cdf0e10cSrcweir     if( aDigest && aCipher)
1422*cdf0e10cSrcweir     {
1423*cdf0e10cSrcweir         //step 1 already done, data is in i_pPaddedOwnerPassword
1424*cdf0e10cSrcweir         //step 2
1425*cdf0e10cSrcweir 
1426*cdf0e10cSrcweir         rtlDigestError nError = rtl_digest_updateMD5( aDigest, i_pPaddedOwnerPassword, ENCRYPTED_PWD_SIZE );
1427*cdf0e10cSrcweir         if( nError == rtl_Digest_E_None )
1428*cdf0e10cSrcweir         {
1429*cdf0e10cSrcweir             sal_uInt8 nMD5Sum[ RTL_DIGEST_LENGTH_MD5 ];
1430*cdf0e10cSrcweir 
1431*cdf0e10cSrcweir             rtl_digest_getMD5( aDigest, nMD5Sum, sizeof(nMD5Sum) );
1432*cdf0e10cSrcweir //step 3, only if 128 bit
1433*cdf0e10cSrcweir             if( i_nKeyLength == SECUR_128BIT_KEY )
1434*cdf0e10cSrcweir             {
1435*cdf0e10cSrcweir                 sal_Int32 i;
1436*cdf0e10cSrcweir                 for( i = 0; i < 50; i++ )
1437*cdf0e10cSrcweir                 {
1438*cdf0e10cSrcweir                     nError = rtl_digest_updateMD5( aDigest, nMD5Sum, sizeof( nMD5Sum ) );
1439*cdf0e10cSrcweir                     if( nError != rtl_Digest_E_None )
1440*cdf0e10cSrcweir                     {
1441*cdf0e10cSrcweir                         bSuccess = false;
1442*cdf0e10cSrcweir                         break;
1443*cdf0e10cSrcweir                     }
1444*cdf0e10cSrcweir                     rtl_digest_getMD5( aDigest, nMD5Sum, sizeof( nMD5Sum ) );
1445*cdf0e10cSrcweir                 }
1446*cdf0e10cSrcweir             }
1447*cdf0e10cSrcweir             //Step 4, the key is in nMD5Sum
1448*cdf0e10cSrcweir             //step 5 already done, data is in i_pPaddedUserPassword
1449*cdf0e10cSrcweir             //step 6
1450*cdf0e10cSrcweir             rtl_cipher_initARCFOUR( aCipher, rtl_Cipher_DirectionEncode,
1451*cdf0e10cSrcweir                                      nMD5Sum, i_nKeyLength , NULL, 0 );
1452*cdf0e10cSrcweir             // encrypt the user password using the key set above
1453*cdf0e10cSrcweir             rtl_cipher_encodeARCFOUR( aCipher, i_pPaddedUserPassword, ENCRYPTED_PWD_SIZE, // the data to be encrypted
1454*cdf0e10cSrcweir                                       &io_rOValue[0], sal_Int32(io_rOValue.size()) ); //encrypted data
1455*cdf0e10cSrcweir             //Step 7, only if 128 bit
1456*cdf0e10cSrcweir             if( i_nKeyLength == SECUR_128BIT_KEY )
1457*cdf0e10cSrcweir             {
1458*cdf0e10cSrcweir                 sal_uInt32 i, y;
1459*cdf0e10cSrcweir                 sal_uInt8 nLocalKey[ SECUR_128BIT_KEY ]; // 16 = 128 bit key
1460*cdf0e10cSrcweir 
1461*cdf0e10cSrcweir                 for( i = 1; i <= 19; i++ ) // do it 19 times, start with 1
1462*cdf0e10cSrcweir                 {
1463*cdf0e10cSrcweir                     for( y = 0; y < sizeof( nLocalKey ); y++ )
1464*cdf0e10cSrcweir                         nLocalKey[y] = (sal_uInt8)( nMD5Sum[y] ^ i );
1465*cdf0e10cSrcweir 
1466*cdf0e10cSrcweir                     rtl_cipher_initARCFOUR( aCipher, rtl_Cipher_DirectionEncode,
1467*cdf0e10cSrcweir                                             nLocalKey, SECUR_128BIT_KEY, NULL, 0 ); //destination data area, on init can be NULL
1468*cdf0e10cSrcweir                     rtl_cipher_encodeARCFOUR( aCipher, &io_rOValue[0], sal_Int32(io_rOValue.size()), // the data to be encrypted
1469*cdf0e10cSrcweir                                               &io_rOValue[0], sal_Int32(io_rOValue.size()) ); // encrypted data, can be the same as the input, encrypt "in place"
1470*cdf0e10cSrcweir                     //step 8, store in class data member
1471*cdf0e10cSrcweir                 }
1472*cdf0e10cSrcweir             }
1473*cdf0e10cSrcweir         }
1474*cdf0e10cSrcweir         else
1475*cdf0e10cSrcweir             bSuccess = false;
1476*cdf0e10cSrcweir     }
1477*cdf0e10cSrcweir     else
1478*cdf0e10cSrcweir         bSuccess = false;
1479*cdf0e10cSrcweir 
1480*cdf0e10cSrcweir     if( aDigest )
1481*cdf0e10cSrcweir         rtl_digest_destroyMD5( aDigest );
1482*cdf0e10cSrcweir     if( aCipher )
1483*cdf0e10cSrcweir         rtl_cipher_destroyARCFOUR( aCipher );
1484*cdf0e10cSrcweir 
1485*cdf0e10cSrcweir     if( ! bSuccess )
1486*cdf0e10cSrcweir         io_rOValue.clear();
1487*cdf0e10cSrcweir     return bSuccess;
1488*cdf0e10cSrcweir }
1489*cdf0e10cSrcweir 
1490*cdf0e10cSrcweir /**********************************
1491*cdf0e10cSrcweir Algorithms 3.4 and 3.5  Compute the encryption dictionary /U value, save into the class data member, revision 2 (40 bit) or 3 (128 bit)
1492*cdf0e10cSrcweir */
1493*cdf0e10cSrcweir bool PDFWriterImpl::computeUDictionaryValue( EncHashTransporter* i_pTransporter,
1494*cdf0e10cSrcweir                                              vcl::PDFWriter::PDFEncryptionProperties& io_rProperties,
1495*cdf0e10cSrcweir                                              sal_Int32 i_nKeyLength,
1496*cdf0e10cSrcweir                                              sal_Int32 i_nAccessPermissions
1497*cdf0e10cSrcweir                                              )
1498*cdf0e10cSrcweir {
1499*cdf0e10cSrcweir     bool bSuccess = true;
1500*cdf0e10cSrcweir 
1501*cdf0e10cSrcweir     io_rProperties.UValue.resize( ENCRYPTED_PWD_SIZE );
1502*cdf0e10cSrcweir 
1503*cdf0e10cSrcweir     rtlDigest aDigest = rtl_digest_createMD5();
1504*cdf0e10cSrcweir     rtlCipher aCipher = rtl_cipher_createARCFOUR( rtl_Cipher_ModeStream );
1505*cdf0e10cSrcweir     if( aDigest && aCipher )
1506*cdf0e10cSrcweir     {
1507*cdf0e10cSrcweir         //step 1, common to both 3.4 and 3.5
1508*cdf0e10cSrcweir         if( computeEncryptionKey( i_pTransporter, io_rProperties, i_nAccessPermissions ) )
1509*cdf0e10cSrcweir         {
1510*cdf0e10cSrcweir             // prepare encryption key for object
1511*cdf0e10cSrcweir             for( sal_Int32 i = i_nKeyLength, y = 0; y < 5 ; y++ )
1512*cdf0e10cSrcweir                 io_rProperties.EncryptionKey[i++] = 0;
1513*cdf0e10cSrcweir 
1514*cdf0e10cSrcweir             if( io_rProperties.Security128bit == false )
1515*cdf0e10cSrcweir             {
1516*cdf0e10cSrcweir                 //3.4
1517*cdf0e10cSrcweir                 //step 2 and 3
1518*cdf0e10cSrcweir                 rtl_cipher_initARCFOUR( aCipher, rtl_Cipher_DirectionEncode,
1519*cdf0e10cSrcweir                                         &io_rProperties.EncryptionKey[0], 5 , // key and key length
1520*cdf0e10cSrcweir                                         NULL, 0 ); //destination data area
1521*cdf0e10cSrcweir                 // encrypt the user password using the key set above, save for later use
1522*cdf0e10cSrcweir                 rtl_cipher_encodeARCFOUR( aCipher, s_nPadString, sizeof( s_nPadString ), // the data to be encrypted
1523*cdf0e10cSrcweir                                           &io_rProperties.UValue[0], sal_Int32(io_rProperties.UValue.size()) ); //encrypted data, stored in class data member
1524*cdf0e10cSrcweir             }
1525*cdf0e10cSrcweir             else
1526*cdf0e10cSrcweir             {
1527*cdf0e10cSrcweir                 //or 3.5, for 128 bit security
1528*cdf0e10cSrcweir                 //step6, initilize the last 16 bytes of the encrypted user password to 0
1529*cdf0e10cSrcweir                 for(sal_uInt32 i = MD5_DIGEST_SIZE; i < sal_uInt32(io_rProperties.UValue.size()); i++)
1530*cdf0e10cSrcweir                     io_rProperties.UValue[i] = 0;
1531*cdf0e10cSrcweir                 //step 2
1532*cdf0e10cSrcweir                 rtlDigestError nError = rtl_digest_updateMD5( aDigest, s_nPadString, sizeof( s_nPadString ) );
1533*cdf0e10cSrcweir                 //step 3
1534*cdf0e10cSrcweir                 if( nError == rtl_Digest_E_None )
1535*cdf0e10cSrcweir                     nError = rtl_digest_updateMD5( aDigest, &io_rProperties.DocumentIdentifier[0], sal_Int32(io_rProperties.DocumentIdentifier.size()) );
1536*cdf0e10cSrcweir                 else
1537*cdf0e10cSrcweir                     bSuccess = false;
1538*cdf0e10cSrcweir 
1539*cdf0e10cSrcweir                 sal_uInt8 nMD5Sum[ RTL_DIGEST_LENGTH_MD5 ];
1540*cdf0e10cSrcweir                 rtl_digest_getMD5( aDigest, nMD5Sum, sizeof(nMD5Sum) );
1541*cdf0e10cSrcweir                 //Step 4
1542*cdf0e10cSrcweir                 rtl_cipher_initARCFOUR( aCipher, rtl_Cipher_DirectionEncode,
1543*cdf0e10cSrcweir                                         &io_rProperties.EncryptionKey[0], SECUR_128BIT_KEY, NULL, 0 ); //destination data area
1544*cdf0e10cSrcweir                 rtl_cipher_encodeARCFOUR( aCipher, nMD5Sum, sizeof( nMD5Sum ), // the data to be encrypted
1545*cdf0e10cSrcweir                                           &io_rProperties.UValue[0], sizeof( nMD5Sum ) ); //encrypted data, stored in class data member
1546*cdf0e10cSrcweir                 //step 5
1547*cdf0e10cSrcweir                 sal_uInt32 i, y;
1548*cdf0e10cSrcweir                 sal_uInt8 nLocalKey[SECUR_128BIT_KEY];
1549*cdf0e10cSrcweir 
1550*cdf0e10cSrcweir                 for( i = 1; i <= 19; i++ ) // do it 19 times, start with 1
1551*cdf0e10cSrcweir                 {
1552*cdf0e10cSrcweir                     for( y = 0; y < sizeof( nLocalKey ) ; y++ )
1553*cdf0e10cSrcweir                         nLocalKey[y] = (sal_uInt8)( io_rProperties.EncryptionKey[y] ^ i );
1554*cdf0e10cSrcweir 
1555*cdf0e10cSrcweir                     rtl_cipher_initARCFOUR( aCipher, rtl_Cipher_DirectionEncode,
1556*cdf0e10cSrcweir                                             nLocalKey, SECUR_128BIT_KEY, // key and key length
1557*cdf0e10cSrcweir                                             NULL, 0 ); //destination data area, on init can be NULL
1558*cdf0e10cSrcweir                     rtl_cipher_encodeARCFOUR( aCipher, &io_rProperties.UValue[0], SECUR_128BIT_KEY, // the data to be encrypted
1559*cdf0e10cSrcweir                                               &io_rProperties.UValue[0], SECUR_128BIT_KEY ); // encrypted data, can be the same as the input, encrypt "in place"
1560*cdf0e10cSrcweir                 }
1561*cdf0e10cSrcweir             }
1562*cdf0e10cSrcweir         }
1563*cdf0e10cSrcweir         else
1564*cdf0e10cSrcweir             bSuccess = false;
1565*cdf0e10cSrcweir     }
1566*cdf0e10cSrcweir     else
1567*cdf0e10cSrcweir         bSuccess = false;
1568*cdf0e10cSrcweir 
1569*cdf0e10cSrcweir     if( aDigest )
1570*cdf0e10cSrcweir         rtl_digest_destroyMD5( aDigest );
1571*cdf0e10cSrcweir     if( aCipher )
1572*cdf0e10cSrcweir         rtl_cipher_destroyARCFOUR( aCipher );
1573*cdf0e10cSrcweir 
1574*cdf0e10cSrcweir     if( ! bSuccess )
1575*cdf0e10cSrcweir         io_rProperties.UValue.clear();
1576*cdf0e10cSrcweir     return bSuccess;
1577*cdf0e10cSrcweir }
1578*cdf0e10cSrcweir 
1579*cdf0e10cSrcweir /* end i12626 methods */
1580*cdf0e10cSrcweir 
1581*cdf0e10cSrcweir static const long unsetRun[256] =
1582*cdf0e10cSrcweir {
1583*cdf0e10cSrcweir     8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,	/* 0x00 - 0x0f */
1584*cdf0e10cSrcweir     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,	/* 0x10 - 0x1f */
1585*cdf0e10cSrcweir     2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,	/* 0x20 - 0x2f */
1586*cdf0e10cSrcweir     2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,	/* 0x30 - 0x3f */
1587*cdf0e10cSrcweir     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,	/* 0x40 - 0x4f */
1588*cdf0e10cSrcweir     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,	/* 0x50 - 0x5f */
1589*cdf0e10cSrcweir     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,	/* 0x60 - 0x6f */
1590*cdf0e10cSrcweir     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,	/* 0x70 - 0x7f */
1591*cdf0e10cSrcweir     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0x80 - 0x8f */
1592*cdf0e10cSrcweir     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0x90 - 0x9f */
1593*cdf0e10cSrcweir     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0xa0 - 0xaf */
1594*cdf0e10cSrcweir     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0xb0 - 0xbf */
1595*cdf0e10cSrcweir     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0xc0 - 0xcf */
1596*cdf0e10cSrcweir     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0xd0 - 0xdf */
1597*cdf0e10cSrcweir     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0xe0 - 0xef */
1598*cdf0e10cSrcweir     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0xf0 - 0xff */
1599*cdf0e10cSrcweir };
1600*cdf0e10cSrcweir 
1601*cdf0e10cSrcweir static const long setRun[256] =
1602*cdf0e10cSrcweir {
1603*cdf0e10cSrcweir     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0x00 - 0x0f */
1604*cdf0e10cSrcweir     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0x10 - 0x1f */
1605*cdf0e10cSrcweir     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0x20 - 0x2f */
1606*cdf0e10cSrcweir     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0x30 - 0x3f */
1607*cdf0e10cSrcweir     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0x40 - 0x4f */
1608*cdf0e10cSrcweir     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0x50 - 0x5f */
1609*cdf0e10cSrcweir     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0x60 - 0x6f */
1610*cdf0e10cSrcweir     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0x70 - 0x7f */
1611*cdf0e10cSrcweir     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,	/* 0x80 - 0x8f */
1612*cdf0e10cSrcweir     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,	/* 0x90 - 0x9f */
1613*cdf0e10cSrcweir     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,	/* 0xa0 - 0xaf */
1614*cdf0e10cSrcweir     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,	/* 0xb0 - 0xbf */
1615*cdf0e10cSrcweir     2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,	/* 0xc0 - 0xcf */
1616*cdf0e10cSrcweir     2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,	/* 0xd0 - 0xdf */
1617*cdf0e10cSrcweir     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,	/* 0xe0 - 0xef */
1618*cdf0e10cSrcweir     4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 8,	/* 0xf0 - 0xff */
1619*cdf0e10cSrcweir };
1620*cdf0e10cSrcweir 
1621*cdf0e10cSrcweir inline bool isSet( const Scanline i_pLine, long i_nIndex )
1622*cdf0e10cSrcweir {
1623*cdf0e10cSrcweir     return (i_pLine[ i_nIndex/8 ] & (0x80 >> (i_nIndex&7))) != 0;
1624*cdf0e10cSrcweir }
1625*cdf0e10cSrcweir 
1626*cdf0e10cSrcweir long findBitRun( const Scanline i_pLine, long i_nStartIndex, long i_nW, bool i_bSet )
1627*cdf0e10cSrcweir {
1628*cdf0e10cSrcweir     if( i_nStartIndex < 0 )
1629*cdf0e10cSrcweir         return i_nW;
1630*cdf0e10cSrcweir 
1631*cdf0e10cSrcweir     long nIndex = i_nStartIndex;
1632*cdf0e10cSrcweir     if( nIndex < i_nW )
1633*cdf0e10cSrcweir     {
1634*cdf0e10cSrcweir         const sal_uInt8 * pByte = static_cast<sal_uInt8*>(i_pLine) + (nIndex/8);
1635*cdf0e10cSrcweir         sal_uInt8 nByte = *pByte;
1636*cdf0e10cSrcweir 
1637*cdf0e10cSrcweir         // run up to byte boundary
1638*cdf0e10cSrcweir         long nBitInByte = (nIndex & 7);
1639*cdf0e10cSrcweir         if( nBitInByte )
1640*cdf0e10cSrcweir         {
1641*cdf0e10cSrcweir             sal_uInt8 nMask = 0x80 >> nBitInByte;
1642*cdf0e10cSrcweir             while( nBitInByte != 8 )
1643*cdf0e10cSrcweir             {
1644*cdf0e10cSrcweir                 if( (nByte & nMask) != (i_bSet ? nMask : 0) )
1645*cdf0e10cSrcweir                     return nIndex < i_nW ? nIndex : i_nW;
1646*cdf0e10cSrcweir                 nMask = nMask >> 1;
1647*cdf0e10cSrcweir                 nBitInByte++;
1648*cdf0e10cSrcweir                 nIndex++;
1649*cdf0e10cSrcweir             }
1650*cdf0e10cSrcweir             if( nIndex < i_nW )
1651*cdf0e10cSrcweir             {
1652*cdf0e10cSrcweir                 pByte++;
1653*cdf0e10cSrcweir                 nByte = *pByte;
1654*cdf0e10cSrcweir             }
1655*cdf0e10cSrcweir         }
1656*cdf0e10cSrcweir 
1657*cdf0e10cSrcweir         sal_uInt8 nRunByte;
1658*cdf0e10cSrcweir         const long* pRunTable;
1659*cdf0e10cSrcweir         if( i_bSet )
1660*cdf0e10cSrcweir         {
1661*cdf0e10cSrcweir             nRunByte = 0xff;
1662*cdf0e10cSrcweir             pRunTable = setRun;
1663*cdf0e10cSrcweir         }
1664*cdf0e10cSrcweir         else
1665*cdf0e10cSrcweir         {
1666*cdf0e10cSrcweir             nRunByte = 0;
1667*cdf0e10cSrcweir             pRunTable = unsetRun;
1668*cdf0e10cSrcweir         }
1669*cdf0e10cSrcweir 
1670*cdf0e10cSrcweir         while( nByte == nRunByte && nIndex < i_nW )
1671*cdf0e10cSrcweir         {
1672*cdf0e10cSrcweir             nIndex += 8;
1673*cdf0e10cSrcweir             pByte++;
1674*cdf0e10cSrcweir             nByte = *pByte;
1675*cdf0e10cSrcweir         }
1676*cdf0e10cSrcweir         if( nIndex < i_nW )
1677*cdf0e10cSrcweir         {
1678*cdf0e10cSrcweir             nIndex += pRunTable[nByte];
1679*cdf0e10cSrcweir         }
1680*cdf0e10cSrcweir     }
1681*cdf0e10cSrcweir     return nIndex < i_nW ? nIndex : i_nW;
1682*cdf0e10cSrcweir }
1683*cdf0e10cSrcweir 
1684*cdf0e10cSrcweir struct BitStreamState
1685*cdf0e10cSrcweir {
1686*cdf0e10cSrcweir     sal_uInt8       mnBuffer;
1687*cdf0e10cSrcweir     sal_uInt32      mnNextBitPos;
1688*cdf0e10cSrcweir 
1689*cdf0e10cSrcweir     BitStreamState()
1690*cdf0e10cSrcweir     : mnBuffer( 0 )
1691*cdf0e10cSrcweir     , mnNextBitPos( 8 )
1692*cdf0e10cSrcweir     {
1693*cdf0e10cSrcweir     }
1694*cdf0e10cSrcweir 
1695*cdf0e10cSrcweir     const sal_uInt8* getByte() const { return &mnBuffer; }
1696*cdf0e10cSrcweir     void flush() { mnNextBitPos = 8; mnBuffer = 0; }
1697*cdf0e10cSrcweir };
1698*cdf0e10cSrcweir 
1699*cdf0e10cSrcweir void PDFWriterImpl::putG4Bits( sal_uInt32 i_nLength, sal_uInt32 i_nCode, BitStreamState& io_rState )
1700*cdf0e10cSrcweir {
1701*cdf0e10cSrcweir     while( i_nLength > io_rState.mnNextBitPos )
1702*cdf0e10cSrcweir     {
1703*cdf0e10cSrcweir         io_rState.mnBuffer |= static_cast<sal_uInt8>( i_nCode >> (i_nLength - io_rState.mnNextBitPos) );
1704*cdf0e10cSrcweir         i_nLength -= io_rState.mnNextBitPos;
1705*cdf0e10cSrcweir         writeBuffer( io_rState.getByte(), 1 );
1706*cdf0e10cSrcweir         io_rState.flush();
1707*cdf0e10cSrcweir     }
1708*cdf0e10cSrcweir     OSL_ASSERT( i_nLength < 9 );
1709*cdf0e10cSrcweir     static const unsigned int msbmask[9] = { 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };
1710*cdf0e10cSrcweir     io_rState.mnBuffer |= static_cast<sal_uInt8>( (i_nCode & msbmask[i_nLength]) << (io_rState.mnNextBitPos - i_nLength) );
1711*cdf0e10cSrcweir     io_rState.mnNextBitPos -= i_nLength;
1712*cdf0e10cSrcweir     if( io_rState.mnNextBitPos == 0 )
1713*cdf0e10cSrcweir     {
1714*cdf0e10cSrcweir         writeBuffer( io_rState.getByte(), 1 );
1715*cdf0e10cSrcweir         io_rState.flush();
1716*cdf0e10cSrcweir     }
1717*cdf0e10cSrcweir }
1718*cdf0e10cSrcweir 
1719*cdf0e10cSrcweir struct PixelCode
1720*cdf0e10cSrcweir {
1721*cdf0e10cSrcweir     sal_uInt32      mnEncodedPixels;
1722*cdf0e10cSrcweir     sal_uInt32      mnCodeBits;
1723*cdf0e10cSrcweir     sal_uInt32      mnCode;
1724*cdf0e10cSrcweir };
1725*cdf0e10cSrcweir 
1726*cdf0e10cSrcweir static const PixelCode WhitePixelCodes[] =
1727*cdf0e10cSrcweir {
1728*cdf0e10cSrcweir     { 0, 8, 0x35 },     // 0011 0101
1729*cdf0e10cSrcweir     { 1, 6, 0x7 },      // 0001 11
1730*cdf0e10cSrcweir     { 2, 4, 0x7 },      // 0111
1731*cdf0e10cSrcweir     { 3, 4, 0x8 },      // 1000
1732*cdf0e10cSrcweir     { 4, 4, 0xB },      // 1011
1733*cdf0e10cSrcweir     { 5, 4, 0xC },      // 1100
1734*cdf0e10cSrcweir     { 6, 4, 0xE },      // 1110
1735*cdf0e10cSrcweir     { 7, 4, 0xF },      // 1111
1736*cdf0e10cSrcweir     { 8, 5, 0x13 },     // 1001 1
1737*cdf0e10cSrcweir     { 9, 5, 0x14 },     // 1010 0
1738*cdf0e10cSrcweir     { 10, 5, 0x7 },     // 0011 1
1739*cdf0e10cSrcweir     { 11, 5, 0x8 },     // 0100 0
1740*cdf0e10cSrcweir     { 12, 6, 0x8 },     // 0010 00
1741*cdf0e10cSrcweir     { 13, 6, 0x3 },     // 0000 11
1742*cdf0e10cSrcweir     { 14, 6, 0x34 },    // 1101 00
1743*cdf0e10cSrcweir     { 15, 6, 0x35 },    // 1101 01
1744*cdf0e10cSrcweir     { 16, 6, 0x2A },    // 1010 10
1745*cdf0e10cSrcweir     { 17, 6, 0x2B },    // 1010 11
1746*cdf0e10cSrcweir     { 18, 7, 0x27 },    // 0100 111
1747*cdf0e10cSrcweir     { 19, 7, 0xC },     // 0001 100
1748*cdf0e10cSrcweir     { 20, 7, 0x8 },     // 0001 000
1749*cdf0e10cSrcweir     { 21, 7, 0x17 },    // 0010 111
1750*cdf0e10cSrcweir     { 22, 7, 0x3 },     // 0000 011
1751*cdf0e10cSrcweir     { 23, 7, 0x4 },     // 0000 100
1752*cdf0e10cSrcweir     { 24, 7, 0x28 },    // 0101 000
1753*cdf0e10cSrcweir     { 25, 7, 0x2B },    // 0101 011
1754*cdf0e10cSrcweir     { 26, 7, 0x13 },    // 0010 011
1755*cdf0e10cSrcweir     { 27, 7, 0x24 },    // 0100 100
1756*cdf0e10cSrcweir     { 28, 7, 0x18 },    // 0011 000
1757*cdf0e10cSrcweir     { 29, 8, 0x2 },     // 0000 0010
1758*cdf0e10cSrcweir     { 30, 8, 0x3 },     // 0000 0011
1759*cdf0e10cSrcweir     { 31, 8, 0x1A },    // 0001 1010
1760*cdf0e10cSrcweir     { 32, 8, 0x1B },    // 0001 1011
1761*cdf0e10cSrcweir     { 33, 8, 0x12 },    // 0001 0010
1762*cdf0e10cSrcweir     { 34, 8, 0x13 },    // 0001 0011
1763*cdf0e10cSrcweir     { 35, 8, 0x14 },    // 0001 0100
1764*cdf0e10cSrcweir     { 36, 8, 0x15 },    // 0001 0101
1765*cdf0e10cSrcweir     { 37, 8, 0x16 },    // 0001 0110
1766*cdf0e10cSrcweir     { 38, 8, 0x17 },    // 0001 0111
1767*cdf0e10cSrcweir     { 39, 8, 0x28 },    // 0010 1000
1768*cdf0e10cSrcweir     { 40, 8, 0x29 },    // 0010 1001
1769*cdf0e10cSrcweir     { 41, 8, 0x2A },    // 0010 1010
1770*cdf0e10cSrcweir     { 42, 8, 0x2B },    // 0010 1011
1771*cdf0e10cSrcweir     { 43, 8, 0x2C },    // 0010 1100
1772*cdf0e10cSrcweir     { 44, 8, 0x2D },    // 0010 1101
1773*cdf0e10cSrcweir     { 45, 8, 0x4 },     // 0000 0100
1774*cdf0e10cSrcweir     { 46, 8, 0x5 },     // 0000 0101
1775*cdf0e10cSrcweir     { 47, 8, 0xA },     // 0000 1010
1776*cdf0e10cSrcweir     { 48, 8, 0xB },     // 0000 1011
1777*cdf0e10cSrcweir     { 49, 8, 0x52 },    // 0101 0010
1778*cdf0e10cSrcweir     { 50, 8, 0x53 },    // 0101 0011
1779*cdf0e10cSrcweir     { 51, 8, 0x54 },    // 0101 0100
1780*cdf0e10cSrcweir     { 52, 8, 0x55 },    // 0101 0101
1781*cdf0e10cSrcweir     { 53, 8, 0x24 },    // 0010 0100
1782*cdf0e10cSrcweir     { 54, 8, 0x25 },    // 0010 0101
1783*cdf0e10cSrcweir     { 55, 8, 0x58 },    // 0101 1000
1784*cdf0e10cSrcweir     { 56, 8, 0x59 },    // 0101 1001
1785*cdf0e10cSrcweir     { 57, 8, 0x5A },    // 0101 1010
1786*cdf0e10cSrcweir     { 58, 8, 0x5B },    // 0101 1011
1787*cdf0e10cSrcweir     { 59, 8, 0x4A },    // 0100 1010
1788*cdf0e10cSrcweir     { 60, 8, 0x4B },    // 0100 1011
1789*cdf0e10cSrcweir     { 61, 8, 0x32 },    // 0011 0010
1790*cdf0e10cSrcweir     { 62, 8, 0x33 },    // 0011 0011
1791*cdf0e10cSrcweir     { 63, 8, 0x34 },    // 0011 0100
1792*cdf0e10cSrcweir     { 64, 5, 0x1B },    // 1101 1
1793*cdf0e10cSrcweir     { 128, 5, 0x12 },   // 1001 0
1794*cdf0e10cSrcweir     { 192, 6, 0x17 },   // 0101 11
1795*cdf0e10cSrcweir     { 256, 7, 0x37 },   // 0110 111
1796*cdf0e10cSrcweir     { 320, 8, 0x36 },   // 0011 0110
1797*cdf0e10cSrcweir     { 384, 8, 0x37 },   // 0011 0111
1798*cdf0e10cSrcweir     { 448, 8, 0x64 },   // 0110 0100
1799*cdf0e10cSrcweir     { 512, 8, 0x65 },   // 0110 0101
1800*cdf0e10cSrcweir     { 576, 8, 0x68 },   // 0110 1000
1801*cdf0e10cSrcweir     { 640, 8, 0x67 },   // 0110 0111
1802*cdf0e10cSrcweir     { 704, 9, 0xCC },   // 0110 0110 0
1803*cdf0e10cSrcweir     { 768, 9, 0xCD },   // 0110 0110 1
1804*cdf0e10cSrcweir     { 832, 9, 0xD2 },   // 0110 1001 0
1805*cdf0e10cSrcweir     { 896, 9, 0xD3 },   // 0110 1001 1
1806*cdf0e10cSrcweir     { 960, 9, 0xD4 },   // 0110 1010 0
1807*cdf0e10cSrcweir     { 1024, 9, 0xD5 },  // 0110 1010 1
1808*cdf0e10cSrcweir     { 1088, 9, 0xD6 },  // 0110 1011 0
1809*cdf0e10cSrcweir     { 1152, 9, 0xD7 },  // 0110 1011 1
1810*cdf0e10cSrcweir     { 1216, 9, 0xD8 },  // 0110 1100 0
1811*cdf0e10cSrcweir     { 1280, 9, 0xD9 },  // 0110 1100 1
1812*cdf0e10cSrcweir     { 1344, 9, 0xDA },  // 0110 1101 0
1813*cdf0e10cSrcweir     { 1408, 9, 0xDB },  // 0110 1101 1
1814*cdf0e10cSrcweir     { 1472, 9, 0x98 },  // 0100 1100 0
1815*cdf0e10cSrcweir     { 1536, 9, 0x99 },  // 0100 1100 1
1816*cdf0e10cSrcweir     { 1600, 9, 0x9A },  // 0100 1101 0
1817*cdf0e10cSrcweir     { 1664, 6, 0x18 },  // 0110 00
1818*cdf0e10cSrcweir     { 1728, 9, 0x9B },  // 0100 1101 1
1819*cdf0e10cSrcweir     { 1792, 11, 0x8 },  // 0000 0001 000
1820*cdf0e10cSrcweir     { 1856, 11, 0xC },  // 0000 0001 100
1821*cdf0e10cSrcweir     { 1920, 11, 0xD },  // 0000 0001 101
1822*cdf0e10cSrcweir     { 1984, 12, 0x12 }, // 0000 0001 0010
1823*cdf0e10cSrcweir     { 2048, 12, 0x13 }, // 0000 0001 0011
1824*cdf0e10cSrcweir     { 2112, 12, 0x14 }, // 0000 0001 0100
1825*cdf0e10cSrcweir     { 2176, 12, 0x15 }, // 0000 0001 0101
1826*cdf0e10cSrcweir     { 2240, 12, 0x16 }, // 0000 0001 0110
1827*cdf0e10cSrcweir     { 2304, 12, 0x17 }, // 0000 0001 0111
1828*cdf0e10cSrcweir     { 2368, 12, 0x1C }, // 0000 0001 1100
1829*cdf0e10cSrcweir     { 2432, 12, 0x1D }, // 0000 0001 1101
1830*cdf0e10cSrcweir     { 2496, 12, 0x1E }, // 0000 0001 1110
1831*cdf0e10cSrcweir     { 2560, 12, 0x1F }  // 0000 0001 1111
1832*cdf0e10cSrcweir };
1833*cdf0e10cSrcweir 
1834*cdf0e10cSrcweir static const PixelCode BlackPixelCodes[] =
1835*cdf0e10cSrcweir {
1836*cdf0e10cSrcweir     { 0, 10, 0x37 },    // 0000 1101 11
1837*cdf0e10cSrcweir     { 1, 3, 0x2 },      // 010
1838*cdf0e10cSrcweir     { 2, 2, 0x3 },      // 11
1839*cdf0e10cSrcweir     { 3, 2, 0x2 },      // 10
1840*cdf0e10cSrcweir     { 4, 3, 0x3 },      // 011
1841*cdf0e10cSrcweir     { 5, 4, 0x3 },      // 0011
1842*cdf0e10cSrcweir     { 6, 4, 0x2 },      // 0010
1843*cdf0e10cSrcweir     { 7, 5, 0x3 },      // 0001 1
1844*cdf0e10cSrcweir     { 8, 6, 0x5 },      // 0001 01
1845*cdf0e10cSrcweir     { 9, 6, 0x4 },      // 0001 00
1846*cdf0e10cSrcweir     { 10, 7, 0x4 },     // 0000 100
1847*cdf0e10cSrcweir     { 11, 7, 0x5 },     // 0000 101
1848*cdf0e10cSrcweir     { 12, 7, 0x7 },     // 0000 111
1849*cdf0e10cSrcweir     { 13, 8, 0x4 },     // 0000 0100
1850*cdf0e10cSrcweir     { 14, 8, 0x7 },     // 0000 0111
1851*cdf0e10cSrcweir     { 15, 9, 0x18 },    // 0000 1100 0
1852*cdf0e10cSrcweir     { 16, 10, 0x17 },   // 0000 0101 11
1853*cdf0e10cSrcweir     { 17, 10, 0x18 },   // 0000 0110 00
1854*cdf0e10cSrcweir     { 18, 10, 0x8 },    // 0000 0010 00
1855*cdf0e10cSrcweir     { 19, 11, 0x67 },   // 0000 1100 111
1856*cdf0e10cSrcweir     { 20, 11, 0x68 },   // 0000 1101 000
1857*cdf0e10cSrcweir     { 21, 11, 0x6C },   // 0000 1101 100
1858*cdf0e10cSrcweir     { 22, 11, 0x37 },   // 0000 0110 111
1859*cdf0e10cSrcweir     { 23, 11, 0x28 },   // 0000 0101 000
1860*cdf0e10cSrcweir     { 24, 11, 0x17 },   // 0000 0010 111
1861*cdf0e10cSrcweir     { 25, 11, 0x18 },   // 0000 0011 000
1862*cdf0e10cSrcweir     { 26, 12, 0xCA },   // 0000 1100 1010
1863*cdf0e10cSrcweir     { 27, 12, 0xCB },   // 0000 1100 1011
1864*cdf0e10cSrcweir     { 28, 12, 0xCC },   // 0000 1100 1100
1865*cdf0e10cSrcweir     { 29, 12, 0xCD },   // 0000 1100 1101
1866*cdf0e10cSrcweir     { 30, 12, 0x68 },   // 0000 0110 1000
1867*cdf0e10cSrcweir     { 31, 12, 0x69 },   // 0000 0110 1001
1868*cdf0e10cSrcweir     { 32, 12, 0x6A },   // 0000 0110 1010
1869*cdf0e10cSrcweir     { 33, 12, 0x6B },   // 0000 0110 1011
1870*cdf0e10cSrcweir     { 34, 12, 0xD2 },   // 0000 1101 0010
1871*cdf0e10cSrcweir     { 35, 12, 0xD3 },   // 0000 1101 0011
1872*cdf0e10cSrcweir     { 36, 12, 0xD4 },   // 0000 1101 0100
1873*cdf0e10cSrcweir     { 37, 12, 0xD5 },   // 0000 1101 0101
1874*cdf0e10cSrcweir     { 38, 12, 0xD6 },   // 0000 1101 0110
1875*cdf0e10cSrcweir     { 39, 12, 0xD7 },   // 0000 1101 0111
1876*cdf0e10cSrcweir     { 40, 12, 0x6C },   // 0000 0110 1100
1877*cdf0e10cSrcweir     { 41, 12, 0x6D },   // 0000 0110 1101
1878*cdf0e10cSrcweir     { 42, 12, 0xDA },   // 0000 1101 1010
1879*cdf0e10cSrcweir     { 43, 12, 0xDB },   // 0000 1101 1011
1880*cdf0e10cSrcweir     { 44, 12, 0x54 },   // 0000 0101 0100
1881*cdf0e10cSrcweir     { 45, 12, 0x55 },   // 0000 0101 0101
1882*cdf0e10cSrcweir     { 46, 12, 0x56 },   // 0000 0101 0110
1883*cdf0e10cSrcweir     { 47, 12, 0x57 },   // 0000 0101 0111
1884*cdf0e10cSrcweir     { 48, 12, 0x64 },   // 0000 0110 0100
1885*cdf0e10cSrcweir     { 49, 12, 0x65 },   // 0000 0110 0101
1886*cdf0e10cSrcweir     { 50, 12, 0x52 },   // 0000 0101 0010
1887*cdf0e10cSrcweir     { 51, 12, 0x53 },   // 0000 0101 0011
1888*cdf0e10cSrcweir     { 52, 12, 0x24 },   // 0000 0010 0100
1889*cdf0e10cSrcweir     { 53, 12, 0x37 },   // 0000 0011 0111
1890*cdf0e10cSrcweir     { 54, 12, 0x38 },   // 0000 0011 1000
1891*cdf0e10cSrcweir     { 55, 12, 0x27 },   // 0000 0010 0111
1892*cdf0e10cSrcweir     { 56, 12, 0x28 },   // 0000 0010 1000
1893*cdf0e10cSrcweir     { 57, 12, 0x58 },   // 0000 0101 1000
1894*cdf0e10cSrcweir     { 58, 12, 0x59 },   // 0000 0101 1001
1895*cdf0e10cSrcweir     { 59, 12, 0x2B },   // 0000 0010 1011
1896*cdf0e10cSrcweir     { 60, 12, 0x2C },   // 0000 0010 1100
1897*cdf0e10cSrcweir     { 61, 12, 0x5A },   // 0000 0101 1010
1898*cdf0e10cSrcweir     { 62, 12, 0x66 },   // 0000 0110 0110
1899*cdf0e10cSrcweir     { 63, 12, 0x67 },   // 0000 0110 0111
1900*cdf0e10cSrcweir     { 64, 10, 0xF },    // 0000 0011 11
1901*cdf0e10cSrcweir     { 128, 12, 0xC8 },  // 0000 1100 1000
1902*cdf0e10cSrcweir     { 192, 12, 0xC9 },  // 0000 1100 1001
1903*cdf0e10cSrcweir     { 256, 12, 0x5B },  // 0000 0101 1011
1904*cdf0e10cSrcweir     { 320, 12, 0x33 },  // 0000 0011 0011
1905*cdf0e10cSrcweir     { 384, 12, 0x34 },  // 0000 0011 0100
1906*cdf0e10cSrcweir     { 448, 12, 0x35 },  // 0000 0011 0101
1907*cdf0e10cSrcweir     { 512, 13, 0x6C },  // 0000 0011 0110 0
1908*cdf0e10cSrcweir     { 576, 13, 0x6D },  // 0000 0011 0110 1
1909*cdf0e10cSrcweir     { 640, 13, 0x4A },  // 0000 0010 0101 0
1910*cdf0e10cSrcweir     { 704, 13, 0x4B },  // 0000 0010 0101 1
1911*cdf0e10cSrcweir     { 768, 13, 0x4C },  // 0000 0010 0110 0
1912*cdf0e10cSrcweir     { 832, 13, 0x4D },  // 0000 0010 0110 1
1913*cdf0e10cSrcweir     { 896, 13, 0x72 },  // 0000 0011 1001 0
1914*cdf0e10cSrcweir     { 960, 13, 0x73 },  // 0000 0011 1001 1
1915*cdf0e10cSrcweir     { 1024, 13, 0x74 }, // 0000 0011 1010 0
1916*cdf0e10cSrcweir     { 1088, 13, 0x75 }, // 0000 0011 1010 1
1917*cdf0e10cSrcweir     { 1152, 13, 0x76 }, // 0000 0011 1011 0
1918*cdf0e10cSrcweir     { 1216, 13, 0x77 }, // 0000 0011 1011 1
1919*cdf0e10cSrcweir     { 1280, 13, 0x52 }, // 0000 0010 1001 0
1920*cdf0e10cSrcweir     { 1344, 13, 0x53 }, // 0000 0010 1001 1
1921*cdf0e10cSrcweir     { 1408, 13, 0x54 }, // 0000 0010 1010 0
1922*cdf0e10cSrcweir     { 1472, 13, 0x55 }, // 0000 0010 1010 1
1923*cdf0e10cSrcweir     { 1536, 13, 0x5A }, // 0000 0010 1101 0
1924*cdf0e10cSrcweir     { 1600, 13, 0x5B }, // 0000 0010 1101 1
1925*cdf0e10cSrcweir     { 1664, 13, 0x64 }, // 0000 0011 0010 0
1926*cdf0e10cSrcweir     { 1728, 13, 0x65 }, // 0000 0011 0010 1
1927*cdf0e10cSrcweir     { 1792, 11, 0x8 },  // 0000 0001 000
1928*cdf0e10cSrcweir     { 1856, 11, 0xC },  // 0000 0001 100
1929*cdf0e10cSrcweir     { 1920, 11, 0xD },  // 0000 0001 101
1930*cdf0e10cSrcweir     { 1984, 12, 0x12 }, // 0000 0001 0010
1931*cdf0e10cSrcweir     { 2048, 12, 0x13 }, // 0000 0001 0011
1932*cdf0e10cSrcweir     { 2112, 12, 0x14 }, // 0000 0001 0100
1933*cdf0e10cSrcweir     { 2176, 12, 0x15 }, // 0000 0001 0101
1934*cdf0e10cSrcweir     { 2240, 12, 0x16 }, // 0000 0001 0110
1935*cdf0e10cSrcweir     { 2304, 12, 0x17 }, // 0000 0001 0111
1936*cdf0e10cSrcweir     { 2368, 12, 0x1C }, // 0000 0001 1100
1937*cdf0e10cSrcweir     { 2432, 12, 0x1D }, // 0000 0001 1101
1938*cdf0e10cSrcweir     { 2496, 12, 0x1E }, // 0000 0001 1110
1939*cdf0e10cSrcweir     { 2560, 12, 0x1F }  // 0000 0001 1111
1940*cdf0e10cSrcweir };
1941*cdf0e10cSrcweir 
1942*cdf0e10cSrcweir 
1943*cdf0e10cSrcweir void PDFWriterImpl::putG4Span( long i_nSpan, bool i_bWhitePixel, BitStreamState& io_rState )
1944*cdf0e10cSrcweir {
1945*cdf0e10cSrcweir     const PixelCode* pTable = i_bWhitePixel ? WhitePixelCodes : BlackPixelCodes;
1946*cdf0e10cSrcweir     // maximum encoded span is 2560 consecutive pixels
1947*cdf0e10cSrcweir     while( i_nSpan > 2623 )
1948*cdf0e10cSrcweir     {
1949*cdf0e10cSrcweir         // write 2560 bits, that is entry (63 + (2560 >> 6)) == 103 in the appropriate table
1950*cdf0e10cSrcweir         putG4Bits( pTable[103].mnCodeBits, pTable[103].mnCode, io_rState );
1951*cdf0e10cSrcweir         i_nSpan -= pTable[103].mnEncodedPixels;
1952*cdf0e10cSrcweir     }
1953*cdf0e10cSrcweir     // write multiples of 64 pixels up to 2560
1954*cdf0e10cSrcweir     if( i_nSpan > 63 )
1955*cdf0e10cSrcweir     {
1956*cdf0e10cSrcweir         sal_uInt32 nTabIndex = 63 + (i_nSpan >> 6);
1957*cdf0e10cSrcweir         OSL_ASSERT( pTable[nTabIndex].mnEncodedPixels == static_cast<sal_uInt32>(64*(i_nSpan >> 6)) );
1958*cdf0e10cSrcweir         putG4Bits( pTable[nTabIndex].mnCodeBits, pTable[nTabIndex].mnCode, io_rState );
1959*cdf0e10cSrcweir         i_nSpan -= pTable[nTabIndex].mnEncodedPixels;
1960*cdf0e10cSrcweir     }
1961*cdf0e10cSrcweir     putG4Bits( pTable[i_nSpan].mnCodeBits, pTable[i_nSpan].mnCode, io_rState );
1962*cdf0e10cSrcweir }
1963*cdf0e10cSrcweir 
1964*cdf0e10cSrcweir void PDFWriterImpl::writeG4Stream( BitmapReadAccess* i_pBitmap )
1965*cdf0e10cSrcweir {
1966*cdf0e10cSrcweir     long nW = i_pBitmap->Width();
1967*cdf0e10cSrcweir     long nH = i_pBitmap->Height();
1968*cdf0e10cSrcweir     if( nW <= 0 || nH <= 0 )
1969*cdf0e10cSrcweir         return;
1970*cdf0e10cSrcweir     if( i_pBitmap->GetBitCount() != 1 )
1971*cdf0e10cSrcweir         return;
1972*cdf0e10cSrcweir 
1973*cdf0e10cSrcweir     BitStreamState aBitState;
1974*cdf0e10cSrcweir 
1975*cdf0e10cSrcweir     // the first reference line is virtual and completely empty
1976*cdf0e10cSrcweir     const Scanline pFirstRefLine = (Scanline)rtl_allocateZeroMemory( nW/8 + 1 );
1977*cdf0e10cSrcweir     Scanline pRefLine = pFirstRefLine;
1978*cdf0e10cSrcweir     for( long nY = 0; nY < nH; nY++ )
1979*cdf0e10cSrcweir     {
1980*cdf0e10cSrcweir         const Scanline pCurLine = i_pBitmap->GetScanline( nY );
1981*cdf0e10cSrcweir         long nLineIndex = 0;
1982*cdf0e10cSrcweir         bool bRunSet = (*pCurLine & 0x80) ? true : false;
1983*cdf0e10cSrcweir         bool bRefSet = (*pRefLine & 0x80) ? true : false;
1984*cdf0e10cSrcweir         long nRunIndex1 = bRunSet ? 0 : findBitRun( pCurLine, 0, nW, bRunSet );
1985*cdf0e10cSrcweir         long nRefIndex1 = bRefSet ? 0 : findBitRun( pRefLine, 0, nW, bRefSet );
1986*cdf0e10cSrcweir         for( ; nLineIndex < nW; )
1987*cdf0e10cSrcweir         {
1988*cdf0e10cSrcweir             long nRefIndex2 = findBitRun( pRefLine, nRefIndex1, nW, isSet( pRefLine, nRefIndex1 ) );
1989*cdf0e10cSrcweir             if( nRefIndex2 >= nRunIndex1 )
1990*cdf0e10cSrcweir             {
1991*cdf0e10cSrcweir                 long nDiff = nRefIndex1 - nRunIndex1;
1992*cdf0e10cSrcweir                 if( -3 <= nDiff && nDiff <= 3 )
1993*cdf0e10cSrcweir                 {   // vertical coding
1994*cdf0e10cSrcweir                     static const struct
1995*cdf0e10cSrcweir                     {
1996*cdf0e10cSrcweir                         sal_uInt32 mnCodeBits;
1997*cdf0e10cSrcweir                         sal_uInt32 mnCode;
1998*cdf0e10cSrcweir                     } VerticalCodes[7] = {
1999*cdf0e10cSrcweir                         { 7, 0x03 },    // 0000 011
2000*cdf0e10cSrcweir                         { 6, 0x03 },    // 0000 11
2001*cdf0e10cSrcweir                         { 3, 0x03 },    // 011
2002*cdf0e10cSrcweir                         { 1, 0x1 },     // 1
2003*cdf0e10cSrcweir                         { 3, 0x2 },     // 010
2004*cdf0e10cSrcweir                         { 6, 0x02 },    // 0000 10
2005*cdf0e10cSrcweir                         { 7, 0x02 }     // 0000 010
2006*cdf0e10cSrcweir                     };
2007*cdf0e10cSrcweir                     // convert to index
2008*cdf0e10cSrcweir                     nDiff += 3;
2009*cdf0e10cSrcweir 
2010*cdf0e10cSrcweir                     // emit diff code
2011*cdf0e10cSrcweir                     putG4Bits( VerticalCodes[nDiff].mnCodeBits, VerticalCodes[nDiff].mnCode, aBitState );
2012*cdf0e10cSrcweir                     nLineIndex = nRunIndex1;
2013*cdf0e10cSrcweir                 }
2014*cdf0e10cSrcweir                 else
2015*cdf0e10cSrcweir                 {   // difference too large, horizontal coding
2016*cdf0e10cSrcweir                     // emit horz code 001
2017*cdf0e10cSrcweir                     putG4Bits( 3, 0x1, aBitState );
2018*cdf0e10cSrcweir                     long nRunIndex2 = findBitRun( pCurLine, nRunIndex1, nW, isSet( pCurLine, nRunIndex1 ) );
2019*cdf0e10cSrcweir                     bool bWhiteFirst = ( nLineIndex + nRunIndex1 == 0 || ! isSet( pCurLine, nLineIndex ) );
2020*cdf0e10cSrcweir                     putG4Span( nRunIndex1 - nLineIndex, bWhiteFirst, aBitState );
2021*cdf0e10cSrcweir                     putG4Span( nRunIndex2 - nRunIndex1, ! bWhiteFirst, aBitState );
2022*cdf0e10cSrcweir                     nLineIndex = nRunIndex2;
2023*cdf0e10cSrcweir                 }
2024*cdf0e10cSrcweir             }
2025*cdf0e10cSrcweir             else
2026*cdf0e10cSrcweir             {   // emit pass code 0001
2027*cdf0e10cSrcweir                 putG4Bits( 4, 0x1, aBitState );
2028*cdf0e10cSrcweir                 nLineIndex = nRefIndex2;
2029*cdf0e10cSrcweir             }
2030*cdf0e10cSrcweir             if( nLineIndex < nW )
2031*cdf0e10cSrcweir             {
2032*cdf0e10cSrcweir                 bool bSet = isSet( pCurLine, nLineIndex );
2033*cdf0e10cSrcweir                 nRunIndex1 = findBitRun( pCurLine, nLineIndex, nW, bSet );
2034*cdf0e10cSrcweir                 nRefIndex1 = findBitRun( pRefLine, nLineIndex, nW, ! bSet );
2035*cdf0e10cSrcweir                 nRefIndex1 = findBitRun( pRefLine, nRefIndex1, nW, bSet );
2036*cdf0e10cSrcweir             }
2037*cdf0e10cSrcweir         }
2038*cdf0e10cSrcweir 
2039*cdf0e10cSrcweir         // the current line is the reference for the next line
2040*cdf0e10cSrcweir         pRefLine = pCurLine;
2041*cdf0e10cSrcweir     }
2042*cdf0e10cSrcweir     // terminate strip with EOFB
2043*cdf0e10cSrcweir     putG4Bits( 12, 1, aBitState );
2044*cdf0e10cSrcweir     putG4Bits( 12, 1, aBitState );
2045*cdf0e10cSrcweir     if( aBitState.mnNextBitPos != 8 )
2046*cdf0e10cSrcweir     {
2047*cdf0e10cSrcweir         writeBuffer( aBitState.getByte(), 1 );
2048*cdf0e10cSrcweir         aBitState.flush();
2049*cdf0e10cSrcweir     }
2050*cdf0e10cSrcweir 
2051*cdf0e10cSrcweir     rtl_freeMemory( pFirstRefLine );
2052*cdf0e10cSrcweir }
2053