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