xref: /AOO41X/main/vcl/source/gdi/pdfwriter_impl.cxx (revision 3c19fd8c4ba6cc9cacb84fb49b8ca6bab32bc844)
19f62ea84SAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
39f62ea84SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
49f62ea84SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
59f62ea84SAndrew Rist  * distributed with this work for additional information
69f62ea84SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
79f62ea84SAndrew Rist  * to you under the Apache License, Version 2.0 (the
89f62ea84SAndrew Rist  * "License"); you may not use this file except in compliance
99f62ea84SAndrew Rist  * with the License.  You may obtain a copy of the License at
10cdf0e10cSrcweir  *
119f62ea84SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12cdf0e10cSrcweir  *
139f62ea84SAndrew Rist  * Unless required by applicable law or agreed to in writing,
149f62ea84SAndrew Rist  * software distributed under the License is distributed on an
159f62ea84SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
169f62ea84SAndrew Rist  * KIND, either express or implied.  See the License for the
179f62ea84SAndrew Rist  * specific language governing permissions and limitations
189f62ea84SAndrew Rist  * under the License.
19cdf0e10cSrcweir  *
209f62ea84SAndrew Rist  *************************************************************/
219f62ea84SAndrew Rist 
229f62ea84SAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_vcl.hxx"
26cdf0e10cSrcweir 
27cdf0e10cSrcweir #define _USE_MATH_DEFINES
28cdf0e10cSrcweir #include <math.h>
29cdf0e10cSrcweir #include <algorithm>
30cdf0e10cSrcweir 
31cdf0e10cSrcweir #include <tools/urlobj.hxx>
32cdf0e10cSrcweir 
33cdf0e10cSrcweir #include <pdfwriter_impl.hxx>
34cdf0e10cSrcweir 
35cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygon.hxx>
36cdf0e10cSrcweir #include <basegfx/polygon/b2dpolypolygon.hxx>
37cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygontools.hxx>
38cdf0e10cSrcweir #include <basegfx/polygon/b2dpolypolygontools.hxx>
39cdf0e10cSrcweir #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
40cdf0e10cSrcweir #include <basegfx/matrix/b2dhommatrix.hxx>
41cdf0e10cSrcweir 
42cdf0e10cSrcweir #include <osl/thread.h>
43cdf0e10cSrcweir #include <osl/file.h>
44cdf0e10cSrcweir 
45cdf0e10cSrcweir #include <rtl/crc.h>
46cdf0e10cSrcweir #include <rtl/digest.h>
47cdf0e10cSrcweir #include <rtl/ustrbuf.hxx>
48cdf0e10cSrcweir 
49cdf0e10cSrcweir #include <tools/debug.hxx>
50cdf0e10cSrcweir #include <tools/zcodec.hxx>
51cdf0e10cSrcweir #include <tools/stream.hxx>
52cdf0e10cSrcweir 
53cdf0e10cSrcweir #include <i18npool/mslangid.hxx>
54cdf0e10cSrcweir 
55cdf0e10cSrcweir #include <vcl/virdev.hxx>
56cdf0e10cSrcweir #include <vcl/bmpacc.hxx>
57cdf0e10cSrcweir #include <vcl/bitmapex.hxx>
58cdf0e10cSrcweir #include <vcl/image.hxx>
59cdf0e10cSrcweir #include <vcl/metric.hxx>
60cdf0e10cSrcweir #include <vcl/svapp.hxx>
61cdf0e10cSrcweir #include <vcl/lineinfo.hxx>
62cdf0e10cSrcweir #include "vcl/cvtgrf.hxx"
63cdf0e10cSrcweir #include "vcl/strhelper.hxx"
64cdf0e10cSrcweir 
65cdf0e10cSrcweir #include <fontsubset.hxx>
66cdf0e10cSrcweir #include <outdev.h>
67cdf0e10cSrcweir #include <sallayout.hxx>
68cdf0e10cSrcweir #include <textlayout.hxx>
69cdf0e10cSrcweir #include <salgdi.hxx>
70cdf0e10cSrcweir 
71cdf0e10cSrcweir #include <icc/sRGB-IEC61966-2.1.hxx>
72cdf0e10cSrcweir 
73cdf0e10cSrcweir #include <comphelper/processfactory.hxx>
74cdf0e10cSrcweir 
75cdf0e10cSrcweir #include <com/sun/star/lang/XMultiServiceFactory.hpp>
76cdf0e10cSrcweir #include <com/sun/star/util/URL.hpp>
77cdf0e10cSrcweir 
78cdf0e10cSrcweir #include "cppuhelper/implbase1.hxx"
79cdf0e10cSrcweir 
80cdf0e10cSrcweir using namespace vcl;
81cdf0e10cSrcweir using namespace rtl;
82cdf0e10cSrcweir 
83cdf0e10cSrcweir #if (OSL_DEBUG_LEVEL < 2)
84cdf0e10cSrcweir #define COMPRESS_PAGES
85cdf0e10cSrcweir #else
86cdf0e10cSrcweir #define DEBUG_DISABLE_PDFCOMPRESSION // also do not compress streams
87cdf0e10cSrcweir #endif
88cdf0e10cSrcweir 
89cdf0e10cSrcweir #ifdef DO_TEST_PDF
90cdf0e10cSrcweir class PDFTestOutputStream : public PDFOutputStream
91cdf0e10cSrcweir {
92cdf0e10cSrcweir     public:
93cdf0e10cSrcweir     virtual ~PDFTestOutputStream();
94cdf0e10cSrcweir     virtual void write( const com::sun::star::uno::Reference< com::sun::star::io::XOutputStream >& xStream );
95cdf0e10cSrcweir };
96cdf0e10cSrcweir 
97cdf0e10cSrcweir PDFTestOutputStream::~PDFTestOutputStream()
98cdf0e10cSrcweir {
99cdf0e10cSrcweir }
100cdf0e10cSrcweir 
101cdf0e10cSrcweir void PDFTestOutputStream::write( const com::sun::star::uno::Reference< com::sun::star::io::XOutputStream >& xStream )
102cdf0e10cSrcweir {
103cdf0e10cSrcweir     OString aStr( "lalala\ntest\ntest\ntest" );
104cdf0e10cSrcweir     com::sun::star::uno::Sequence< sal_Int8 > aData( aStr.getLength() );
105cdf0e10cSrcweir     rtl_copyMemory( aData.getArray(), aStr.getStr(), aStr.getLength() );
106cdf0e10cSrcweir     xStream->writeBytes( aData );
107cdf0e10cSrcweir }
108cdf0e10cSrcweir 
109cdf0e10cSrcweir // this test code cannot be used to test PDF/A-1 because it forces
110cdf0e10cSrcweir // control item (widgets) to bypass the structure controlling
111cdf0e10cSrcweir // the embedding of such elements in actual run
112cdf0e10cSrcweir void doTestCode()
113cdf0e10cSrcweir {
114cdf0e10cSrcweir     static const char* pHome = getenv( "HOME"  );
115cdf0e10cSrcweir     rtl::OUString aTestFile( RTL_CONSTASCII_USTRINGPARAM( "file://" ) );
116cdf0e10cSrcweir     aTestFile += rtl::OUString( pHome, strlen( pHome ), RTL_TEXTENCODING_MS_1252 );
117cdf0e10cSrcweir     aTestFile += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/pdf_export_test.pdf" ) );
118cdf0e10cSrcweir 
119cdf0e10cSrcweir     PDFWriter::PDFWriterContext aContext;
120cdf0e10cSrcweir     aContext.URL			= aTestFile;
121cdf0e10cSrcweir     aContext.Version		= PDFWriter::PDF_1_4;
122cdf0e10cSrcweir     aContext.Tagged			= true;
123cdf0e10cSrcweir     aContext.InitialPage    = 2;
124cdf0e10cSrcweir     aContext.DocumentInfo.Title = OUString( RTL_CONSTASCII_USTRINGPARAM( "PDF export test document" ) );
125cdf0e10cSrcweir     aContext.DocumentInfo.Producer = OUString( RTL_CONSTASCII_USTRINGPARAM( "VCL" ) );
126cdf0e10cSrcweir 
127cdf0e10cSrcweir     PDFWriter aWriter( aContext );
128cdf0e10cSrcweir     aWriter.NewPage( 595, 842 );
129cdf0e10cSrcweir     aWriter.BeginStructureElement( PDFWriter::Document );
130cdf0e10cSrcweir     // set duration of 3 sec for first page
131cdf0e10cSrcweir     aWriter.SetAutoAdvanceTime( 3 );
132cdf0e10cSrcweir     aWriter.SetMapMode( MapMode( MAP_100TH_MM ) );
133cdf0e10cSrcweir 
134cdf0e10cSrcweir     aWriter.SetFillColor( Color( COL_LIGHTRED ) );
135cdf0e10cSrcweir     aWriter.SetLineColor( Color( COL_LIGHTGREEN ) );
136cdf0e10cSrcweir     aWriter.DrawRect( Rectangle( Point( 2000, 200 ), Size( 8000, 3000 ) ), 5000, 2000 );
137cdf0e10cSrcweir 
138cdf0e10cSrcweir     aWriter.SetFont( Font( String( RTL_CONSTASCII_USTRINGPARAM( "Times" ) ), Size( 0, 500 ) ) );
139cdf0e10cSrcweir     aWriter.SetTextColor( Color( COL_BLACK ) );
140cdf0e10cSrcweir     aWriter.SetLineColor( Color( COL_BLACK ) );
141cdf0e10cSrcweir     aWriter.SetFillColor( Color( COL_LIGHTBLUE ) );
142cdf0e10cSrcweir 
143cdf0e10cSrcweir     Rectangle aRect( Point( 5000, 5000 ), Size( 6000, 3000 ) );
144cdf0e10cSrcweir     aWriter.DrawRect( aRect );
145cdf0e10cSrcweir     aWriter.DrawText( aRect, String( RTL_CONSTASCII_USTRINGPARAM( "Link annot 1" ) ) );
146cdf0e10cSrcweir     sal_Int32 nFirstLink = aWriter.CreateLink( aRect );
147cdf0e10cSrcweir     PDFNote aNote;
148cdf0e10cSrcweir     aNote.Title = String( RTL_CONSTASCII_USTRINGPARAM( "A small test note" ) );
149cdf0e10cSrcweir     aNote.Contents = String( RTL_CONSTASCII_USTRINGPARAM( "There is no business like show business like no business i know. Everything about it is appealing." ) );
150cdf0e10cSrcweir     aWriter.CreateNote( Rectangle( Point( aRect.Right(), aRect.Top() ), Size( 6000, 3000 ) ), aNote );
151cdf0e10cSrcweir 
152cdf0e10cSrcweir     Rectangle aTargetRect( Point( 3000, 23000 ), Size( 12000, 6000 ) );
153cdf0e10cSrcweir     aWriter.SetFillColor( Color( COL_LIGHTGREEN ) );
154cdf0e10cSrcweir     aWriter.DrawRect( aTargetRect );
155cdf0e10cSrcweir     aWriter.DrawText( aTargetRect, String( RTL_CONSTASCII_USTRINGPARAM( "Dest second link" ) ) );
156cdf0e10cSrcweir     sal_Int32 nSecondDest = aWriter.CreateDest( aTargetRect );
157cdf0e10cSrcweir 
158cdf0e10cSrcweir     aWriter.BeginStructureElement( PDFWriter::Section );
159cdf0e10cSrcweir     aWriter.BeginStructureElement( PDFWriter::Heading );
160cdf0e10cSrcweir     aWriter.DrawText( Point(4500, 9000), String( RTL_CONSTASCII_USTRINGPARAM( "A small structure test" ) ) );
161cdf0e10cSrcweir     aWriter.EndStructureElement();
162cdf0e10cSrcweir     aWriter.BeginStructureElement( PDFWriter::Paragraph );
163cdf0e10cSrcweir     aWriter.SetStructureAttribute( PDFWriter::WritingMode, PDFWriter::LrTb );
164cdf0e10cSrcweir     aWriter.SetStructureAttribute( PDFWriter::TextDecorationType, PDFWriter::Underline );
165cdf0e10cSrcweir     aWriter.DrawText( Rectangle( Point( 4500, 10000 ), Size( 12000, 6000 ) ),
166cdf0e10cSrcweir                       String( RTL_CONSTASCII_USTRINGPARAM( "It was the best of PDF, it was the worst of PDF ... or so. This is a pretty nonsensical text to denote a paragraph. I suggest you stop reading it. Because if you read on you might get bored. So continue on your on risk. Hey, you're still here ? Why do you continue to read this as it is of no use at all ? OK, it's your time, but still... . Woah, i even get bored writing this, so let's end this here and now." ) ),
167cdf0e10cSrcweir                       TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK
168cdf0e10cSrcweir                       );
169cdf0e10cSrcweir     aWriter.SetActualText( String( RTL_CONSTASCII_USTRINGPARAM( "It was the best of PDF, it was the worst of PDF ... or so. This is a pretty nonsensical text to denote a paragraph. I suggest you stop reading it. Because if you read on you might get bored. So continue on your on risk. Hey, you're still here ? Why do you continue to read this as it is of no use at all ? OK, it's your time, but still... . Woah, i even get bored writing this, so let's end this here and now." ) ) );
170cdf0e10cSrcweir     aWriter.SetAlternateText( String( RTL_CONSTASCII_USTRINGPARAM( "This paragraph contains some lengthy nonsense to test structural element emission of PDFWriter." ) ) );
171cdf0e10cSrcweir     aWriter.EndStructureElement();
172cdf0e10cSrcweir     sal_Int32 nLongPara = aWriter.BeginStructureElement( PDFWriter::Paragraph );
173cdf0e10cSrcweir     aWriter.SetStructureAttribute( PDFWriter::WritingMode, PDFWriter::LrTb );
174cdf0e10cSrcweir     aWriter.DrawText( Rectangle( Point( 4500, 19000 ), Size( 12000, 1000 ) ),
175cdf0e10cSrcweir                       String( RTL_CONSTASCII_USTRINGPARAM( "This paragraph is nothing special either but ends on the next page structurewise" ) ),
176cdf0e10cSrcweir                       TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK
177cdf0e10cSrcweir                       );
178cdf0e10cSrcweir 
179cdf0e10cSrcweir     aWriter.NewPage( 595, 842 );
180cdf0e10cSrcweir     // test AddStream interface
181cdf0e10cSrcweir     aWriter.AddStream( String( RTL_CONSTASCII_USTRINGPARAM( "text/plain" ) ), new PDFTestOutputStream(), true );
182cdf0e10cSrcweir     // set transitional mode
183cdf0e10cSrcweir     aWriter.SetPageTransition( PDFWriter::WipeRightToLeft, 1500 );
184cdf0e10cSrcweir     aWriter.SetMapMode( MapMode( MAP_100TH_MM ) );
185cdf0e10cSrcweir     aWriter.SetTextColor( Color( COL_BLACK ) );
186cdf0e10cSrcweir     aWriter.SetFont( Font( String( RTL_CONSTASCII_USTRINGPARAM( "Times" ) ), Size( 0, 500 ) ) );
187cdf0e10cSrcweir     aWriter.DrawText( Rectangle( Point( 4500, 1500 ), Size( 12000, 3000 ) ),
188cdf0e10cSrcweir                       String( RTL_CONSTASCII_USTRINGPARAM( "Here's where all things come to an end ... well at least the paragaph from the last page." ) ),
189cdf0e10cSrcweir                       TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK
190cdf0e10cSrcweir                       );
191cdf0e10cSrcweir     aWriter.EndStructureElement();
192cdf0e10cSrcweir 
193cdf0e10cSrcweir     aWriter.SetFillColor( Color( COL_LIGHTBLUE ) );
194cdf0e10cSrcweir     // disable structure
195cdf0e10cSrcweir     aWriter.BeginStructureElement( PDFWriter::NonStructElement );
196cdf0e10cSrcweir     aWriter.DrawRect( aRect );
197cdf0e10cSrcweir     aWriter.BeginStructureElement( PDFWriter::Paragraph );
198cdf0e10cSrcweir     aWriter.DrawText( aRect, String( RTL_CONSTASCII_USTRINGPARAM( "Link annot 2" ) ) );
199cdf0e10cSrcweir     sal_Int32 nSecondLink = aWriter.CreateLink( aRect );
200cdf0e10cSrcweir 
201cdf0e10cSrcweir     aWriter.SetFillColor( Color( COL_LIGHTGREEN ) );
202cdf0e10cSrcweir     aWriter.BeginStructureElement( PDFWriter::ListItem );
203cdf0e10cSrcweir     aWriter.DrawRect( aTargetRect );
204cdf0e10cSrcweir     aWriter.DrawText( aTargetRect, String( RTL_CONSTASCII_USTRINGPARAM( "Dest first link" ) ) );
205cdf0e10cSrcweir     sal_Int32 nFirstDest = aWriter.CreateDest( aTargetRect );
206cdf0e10cSrcweir     // enable structure
207cdf0e10cSrcweir     aWriter.EndStructureElement();
208cdf0e10cSrcweir     // add something to the long paragraph as an afterthought
209cdf0e10cSrcweir     sal_Int32 nSaveStruct = aWriter.GetCurrentStructureElement();
210cdf0e10cSrcweir     aWriter.SetCurrentStructureElement( nLongPara );
211cdf0e10cSrcweir     aWriter.DrawText( Rectangle( Point( 4500,4500 ),  Size( 12000, 1000 ) ),
212cdf0e10cSrcweir                       String( RTL_CONSTASCII_USTRINGPARAM( "Add something to the longish paragraph above." ) ),
213cdf0e10cSrcweir                       TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK );
214cdf0e10cSrcweir     aWriter.SetCurrentStructureElement( nSaveStruct );
215cdf0e10cSrcweir     aWriter.EndStructureElement();
216cdf0e10cSrcweir     aWriter.EndStructureElement();
217cdf0e10cSrcweir     aWriter.BeginStructureElement( PDFWriter::Figure );
218cdf0e10cSrcweir     aWriter.BeginStructureElement( PDFWriter::Caption );
219cdf0e10cSrcweir     aWriter.DrawText( Point( 4500, 9000 ), String( RTL_CONSTASCII_USTRINGPARAM( "Some drawing stuff inside the structure" ) ) );
220cdf0e10cSrcweir     aWriter.EndStructureElement();
221cdf0e10cSrcweir 
222cdf0e10cSrcweir     // test clipping
223cdf0e10cSrcweir     basegfx::B2DPolyPolygon aClip;
224cdf0e10cSrcweir     basegfx::B2DPolygon aClipPoly;
225cdf0e10cSrcweir     aClipPoly.append( basegfx::B2DPoint( 8250, 9600 ) );
226cdf0e10cSrcweir     aClipPoly.append( basegfx::B2DPoint( 16500, 11100 ) );
227cdf0e10cSrcweir     aClipPoly.append( basegfx::B2DPoint( 8250, 12600 ) );
228cdf0e10cSrcweir     aClipPoly.append( basegfx::B2DPoint( 4500, 11100 ) );
229cdf0e10cSrcweir     aClipPoly.setClosed( true );
230cdf0e10cSrcweir     //aClipPoly.flip();
231cdf0e10cSrcweir     aClip.append( aClipPoly );
232cdf0e10cSrcweir 
233cdf0e10cSrcweir     aWriter.Push( PUSH_CLIPREGION | PUSH_FILLCOLOR );
234cdf0e10cSrcweir     aWriter.SetClipRegion( aClip );
235cdf0e10cSrcweir     aWriter.DrawEllipse( Rectangle( Point( 4500, 9600 ), Size( 12000, 3000 ) ) );
236cdf0e10cSrcweir     aWriter.MoveClipRegion( 1000, 500 );
237cdf0e10cSrcweir     aWriter.SetFillColor( Color( COL_RED ) );
238cdf0e10cSrcweir     aWriter.DrawEllipse( Rectangle( Point( 4500, 9600 ), Size( 12000, 3000 ) ) );
239cdf0e10cSrcweir     aWriter.Pop();
240cdf0e10cSrcweir     // test transparency
241cdf0e10cSrcweir     // draw background
242cdf0e10cSrcweir     Rectangle aTranspRect( Point( 7500, 13500 ), Size( 9000, 6000 ) );
243cdf0e10cSrcweir     aWriter.SetFillColor( Color( COL_LIGHTRED ) );
244cdf0e10cSrcweir     aWriter.DrawRect( aTranspRect );
245cdf0e10cSrcweir     aWriter.BeginTransparencyGroup();
246cdf0e10cSrcweir 
247cdf0e10cSrcweir     aWriter.SetFillColor( Color( COL_LIGHTGREEN ) );
248cdf0e10cSrcweir     aWriter.DrawEllipse( aTranspRect );
249cdf0e10cSrcweir     aWriter.SetTextColor( Color( COL_LIGHTBLUE ) );
250cdf0e10cSrcweir     aWriter.DrawText( aTranspRect,
251cdf0e10cSrcweir                       String( RTL_CONSTASCII_USTRINGPARAM( "Some transparent text" ) ),
252cdf0e10cSrcweir                       TEXT_DRAW_CENTER | TEXT_DRAW_VCENTER | TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK );
253cdf0e10cSrcweir 
254cdf0e10cSrcweir     aWriter.EndTransparencyGroup( aTranspRect, 50 );
255cdf0e10cSrcweir 
256cdf0e10cSrcweir     // prepare an alpha mask
257cdf0e10cSrcweir     Bitmap aTransMask( Size( 256, 256 ), 8, &Bitmap::GetGreyPalette( 256 ) );
258cdf0e10cSrcweir     BitmapWriteAccess* pAcc = aTransMask.AcquireWriteAccess();
259cdf0e10cSrcweir     for( int nX = 0; nX < 256; nX++ )
260cdf0e10cSrcweir         for( int nY = 0; nY < 256; nY++ )
261cdf0e10cSrcweir             pAcc->SetPixel( nX, nY, BitmapColor( (sal_uInt8)((nX+nY)/2) ) );
262cdf0e10cSrcweir     aTransMask.ReleaseAccess( pAcc );
263cdf0e10cSrcweir     aTransMask.SetPrefMapMode( MAP_MM );
264cdf0e10cSrcweir     aTransMask.SetPrefSize( Size( 10, 10 ) );
265cdf0e10cSrcweir 
266cdf0e10cSrcweir     aWriter.DrawBitmap( Point( 600, 13500 ), Size( 3000, 3000 ), aTransMask );
267cdf0e10cSrcweir 
268cdf0e10cSrcweir     aTranspRect = Rectangle( Point( 4200, 13500 ), Size( 3000, 3000 ) );
269cdf0e10cSrcweir     aWriter.SetFillColor( Color( COL_LIGHTRED ) );
270cdf0e10cSrcweir     aWriter.DrawRect( aTranspRect );
271cdf0e10cSrcweir     aWriter.SetFillColor( Color( COL_LIGHTGREEN ) );
272cdf0e10cSrcweir     aWriter.DrawEllipse( aTranspRect );
273cdf0e10cSrcweir     aWriter.SetTextColor( Color( COL_LIGHTBLUE ) );
274cdf0e10cSrcweir     aWriter.DrawText( aTranspRect,
275cdf0e10cSrcweir                       String( RTL_CONSTASCII_USTRINGPARAM( "Some transparent text" ) ),
276cdf0e10cSrcweir                       TEXT_DRAW_CENTER | TEXT_DRAW_VCENTER | TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK );
277cdf0e10cSrcweir     aTranspRect = Rectangle( Point( 1500, 16500 ), Size( 4800, 3000 ) );
278cdf0e10cSrcweir     aWriter.SetFillColor( Color( COL_LIGHTRED ) );
279cdf0e10cSrcweir     aWriter.DrawRect( aTranspRect );
280cdf0e10cSrcweir     aWriter.BeginTransparencyGroup();
281cdf0e10cSrcweir     aWriter.SetFillColor( Color( COL_LIGHTGREEN ) );
282cdf0e10cSrcweir     aWriter.DrawEllipse( aTranspRect );
283cdf0e10cSrcweir     aWriter.SetTextColor( Color( COL_LIGHTBLUE ) );
284cdf0e10cSrcweir     aWriter.DrawText( aTranspRect,
285cdf0e10cSrcweir                       String( RTL_CONSTASCII_USTRINGPARAM( "Some transparent text" ) ),
286cdf0e10cSrcweir                       TEXT_DRAW_CENTER | TEXT_DRAW_VCENTER | TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK );
287cdf0e10cSrcweir     aWriter.EndTransparencyGroup( aTranspRect, aTransMask );
288cdf0e10cSrcweir 
289cdf0e10cSrcweir     Bitmap aImageBmp( Size( 256, 256 ), 24 );
290cdf0e10cSrcweir     pAcc = aImageBmp.AcquireWriteAccess();
291cdf0e10cSrcweir     pAcc->SetFillColor( Color( 0xff, 0, 0xff ) );
292cdf0e10cSrcweir     pAcc->FillRect( Rectangle( Point( 0, 0 ), Size( 256, 256 ) ) );
293cdf0e10cSrcweir     aImageBmp.ReleaseAccess( pAcc );
294cdf0e10cSrcweir     BitmapEx aBmpEx( aImageBmp, AlphaMask( aTransMask ) );
295cdf0e10cSrcweir     aWriter.DrawBitmapEx( Point( 1500, 19500 ), Size( 4800, 3000 ), aBmpEx );
296cdf0e10cSrcweir 
297cdf0e10cSrcweir 
298cdf0e10cSrcweir     aWriter.EndStructureElement();
299cdf0e10cSrcweir     aWriter.EndStructureElement();
300cdf0e10cSrcweir 
301cdf0e10cSrcweir     LineInfo aLI( LINE_DASH, 3 );
302cdf0e10cSrcweir     aLI.SetDashCount( 2 );
303cdf0e10cSrcweir     aLI.SetDashLen( 50 );
304cdf0e10cSrcweir     aLI.SetDotCount( 2 );
305cdf0e10cSrcweir     aLI.SetDotLen( 25 );
306cdf0e10cSrcweir     aLI.SetDistance( 15 );
307cdf0e10cSrcweir     Point aLIPoints[] = { Point( 4000, 10000 ),
308cdf0e10cSrcweir                           Point( 8000, 12000 ),
309cdf0e10cSrcweir                           Point( 3000, 19000 ) };
310cdf0e10cSrcweir     Polygon aLIPoly( 3, aLIPoints );
311cdf0e10cSrcweir     aWriter.SetLineColor( Color( COL_BLUE ) );
312cdf0e10cSrcweir     aWriter.SetFillColor();
313cdf0e10cSrcweir     aWriter.DrawPolyLine( aLIPoly, aLI );
314cdf0e10cSrcweir 
315cdf0e10cSrcweir     aLI.SetDashCount( 4 );
316cdf0e10cSrcweir     aLIPoly.Move( 1000, 1000 );
317cdf0e10cSrcweir     aWriter.DrawPolyLine( aLIPoly, aLI );
318cdf0e10cSrcweir 
319cdf0e10cSrcweir     aWriter.NewPage( 595, 842 );
320cdf0e10cSrcweir     aWriter.SetMapMode( MapMode( MAP_100TH_MM ) );
321cdf0e10cSrcweir     Wallpaper aWall( aTransMask );
322cdf0e10cSrcweir     aWall.SetStyle( WALLPAPER_TILE );
323cdf0e10cSrcweir     aWriter.DrawWallpaper( Rectangle( Point( 4400, 4200 ), Size( 10200, 6300 ) ), aWall );
324cdf0e10cSrcweir 
325cdf0e10cSrcweir     aWriter.Push( PUSH_ALL );
326cdf0e10cSrcweir     aWriter.BeginPattern(Rectangle(Point(0,0),Size(2000,1000)));
327cdf0e10cSrcweir     aWriter.SetFillColor( Color( COL_RED ) );
328cdf0e10cSrcweir     aWriter.SetLineColor( Color( COL_LIGHTBLUE ) );
329cdf0e10cSrcweir     Point aFillPoints[] = { Point( 1000, 0 ),
330cdf0e10cSrcweir                             Point( 0, 1000 ),
331cdf0e10cSrcweir                             Point( 2000, 1000 ) };
332cdf0e10cSrcweir     aWriter.DrawPolygon( Polygon( 3, aFillPoints ) );
333cdf0e10cSrcweir     aWriter.DrawBitmap( Point( 200, 200 ), Size( 1600, 600 ), aTransMask );
334cdf0e10cSrcweir     aWriter.DrawText( Rectangle( Point( 200, 200 ), Size( 1600, 600 ) ), String( RTL_CONSTASCII_USTRINGPARAM( "Pattern" ) ) );
335cdf0e10cSrcweir     sal_Int32 nPattern = aWriter.EndPattern( SvtGraphicFill::Transform() );
336cdf0e10cSrcweir     aWriter.Pop();
337cdf0e10cSrcweir     Rectangle aPolyRect( Point( 3800, 11200 ), Size( 10200, 6300 ) );
338cdf0e10cSrcweir     aWriter.DrawPolyPolygon( PolyPolygon( Polygon( aPolyRect ) ), nPattern, true );
339cdf0e10cSrcweir     aWriter.SetFillColor();
340cdf0e10cSrcweir     aWriter.SetLineColor( Color( COL_LIGHTBLUE ) );
341cdf0e10cSrcweir     aWriter.DrawRect( aPolyRect );
342cdf0e10cSrcweir 
343cdf0e10cSrcweir     aWriter.NewPage( 595, 842 );
344cdf0e10cSrcweir     aWriter.SetMapMode( MapMode( MAP_100TH_MM ) );
345cdf0e10cSrcweir     aWriter.SetFont( Font( String( RTL_CONSTASCII_USTRINGPARAM( "Times" ) ), Size( 0, 500 ) ) );
346cdf0e10cSrcweir     aWriter.SetTextColor( Color( COL_BLACK ) );
347cdf0e10cSrcweir     aRect = Rectangle( Point( 4500, 6000 ), Size( 6000, 1500 ) );
348cdf0e10cSrcweir     aWriter.DrawRect( aRect );
349cdf0e10cSrcweir     aWriter.DrawText( aRect, String( RTL_CONSTASCII_USTRINGPARAM( "www.heise.de" ) ) );
350cdf0e10cSrcweir     sal_Int32 nURILink = aWriter.CreateLink( aRect );
351cdf0e10cSrcweir     aWriter.SetLinkURL( nURILink, OUString( RTL_CONSTASCII_USTRINGPARAM( "http://www.heise.de" ) ) );
352cdf0e10cSrcweir 
353cdf0e10cSrcweir     aWriter.SetLinkDest( nFirstLink, nFirstDest );
354cdf0e10cSrcweir     aWriter.SetLinkDest( nSecondLink, nSecondDest );
355cdf0e10cSrcweir 
356cdf0e10cSrcweir     // include a button
357cdf0e10cSrcweir     PDFWriter::PushButtonWidget aBtn;
358cdf0e10cSrcweir     aBtn.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "testButton" ) );
359cdf0e10cSrcweir     aBtn.Description = OUString( RTL_CONSTASCII_USTRINGPARAM( "A test button" ) );
360cdf0e10cSrcweir     aBtn.Text = OUString( RTL_CONSTASCII_USTRINGPARAM( "hit me" ) );
361cdf0e10cSrcweir     aBtn.Location = Rectangle( Point( 4500, 9000 ), Size( 4500, 3000 ) );
362cdf0e10cSrcweir     aBtn.Border = aBtn.Background = true;
363cdf0e10cSrcweir     aWriter.CreateControl( aBtn );
364cdf0e10cSrcweir 
365cdf0e10cSrcweir     // include a uri button
366cdf0e10cSrcweir     PDFWriter::PushButtonWidget aUriBtn;
367cdf0e10cSrcweir     aUriBtn.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "wwwButton" ) );
368cdf0e10cSrcweir     aUriBtn.Description = OUString( RTL_CONSTASCII_USTRINGPARAM( "A URI button" ) );
369cdf0e10cSrcweir     aUriBtn.Text = OUString( RTL_CONSTASCII_USTRINGPARAM( "to www" ) );
370cdf0e10cSrcweir     aUriBtn.Location = Rectangle( Point( 9500, 9000 ), Size( 4500, 3000 ) );
371cdf0e10cSrcweir     aUriBtn.Border = aUriBtn.Background = true;
372cdf0e10cSrcweir     aUriBtn.URL = OUString( RTL_CONSTASCII_USTRINGPARAM( "http://www.heise.de" ) );
373cdf0e10cSrcweir     aWriter.CreateControl( aUriBtn );
374cdf0e10cSrcweir 
375cdf0e10cSrcweir     // include a dest button
376cdf0e10cSrcweir     PDFWriter::PushButtonWidget aDstBtn;
377cdf0e10cSrcweir     aDstBtn.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "destButton" ) );
378cdf0e10cSrcweir     aDstBtn.Description = OUString( RTL_CONSTASCII_USTRINGPARAM( "A Dest button" ) );
379cdf0e10cSrcweir     aDstBtn.Text = OUString( RTL_CONSTASCII_USTRINGPARAM( "to paragraph" ) );
380cdf0e10cSrcweir     aDstBtn.Location = Rectangle( Point( 14500, 9000 ), Size( 4500, 3000 ) );
381cdf0e10cSrcweir     aDstBtn.Border = aDstBtn.Background = true;
382cdf0e10cSrcweir     aDstBtn.Dest = nFirstDest;
383cdf0e10cSrcweir     aWriter.CreateControl( aDstBtn );
384cdf0e10cSrcweir 
385cdf0e10cSrcweir     PDFWriter::CheckBoxWidget aCBox;
386cdf0e10cSrcweir     aCBox.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "textCheckBox" ) );
387cdf0e10cSrcweir     aCBox.Description = OUString( RTL_CONSTASCII_USTRINGPARAM( "A test check box" ) );
388cdf0e10cSrcweir     aCBox.Text = OUString( RTL_CONSTASCII_USTRINGPARAM( "check me" ) );
389cdf0e10cSrcweir     aCBox.Location = Rectangle( Point( 4500, 13500 ), Size( 3000, 750 ) );
390cdf0e10cSrcweir     aCBox.Checked = true;
391cdf0e10cSrcweir     aCBox.Border = aCBox.Background = false;
392cdf0e10cSrcweir     aWriter.CreateControl( aCBox );
393cdf0e10cSrcweir 
394cdf0e10cSrcweir     PDFWriter::CheckBoxWidget aCBox2;
395cdf0e10cSrcweir     aCBox2.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "textCheckBox2" ) );
396cdf0e10cSrcweir     aCBox2.Description = OUString( RTL_CONSTASCII_USTRINGPARAM( "Another test check box" ) );
397cdf0e10cSrcweir     aCBox2.Text = OUString( RTL_CONSTASCII_USTRINGPARAM( "check me right" ) );
398cdf0e10cSrcweir     aCBox2.Location = Rectangle( Point( 4500, 14250 ), Size( 3000, 750 ) );
399cdf0e10cSrcweir     aCBox2.Checked = true;
400cdf0e10cSrcweir     aCBox2.Border = aCBox2.Background = false;
401cdf0e10cSrcweir     aCBox2.ButtonIsLeft = false;
402cdf0e10cSrcweir     aWriter.CreateControl( aCBox2 );
403cdf0e10cSrcweir 
404cdf0e10cSrcweir     PDFWriter::RadioButtonWidget aRB1;
405cdf0e10cSrcweir     aRB1.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "rb1_1" ) );
406cdf0e10cSrcweir     aRB1.Description = OUString( RTL_CONSTASCII_USTRINGPARAM( "radio 1 button 1" ) );
407cdf0e10cSrcweir     aRB1.Text = OUString( RTL_CONSTASCII_USTRINGPARAM( "Despair" ) );
408cdf0e10cSrcweir     aRB1.Location = Rectangle( Point( 4500, 15000 ), Size( 6000, 1000 ) );
409cdf0e10cSrcweir     aRB1.Selected = true;
410cdf0e10cSrcweir     aRB1.RadioGroup = 1;
411cdf0e10cSrcweir     aRB1.Border = aRB1.Background = true;
412cdf0e10cSrcweir     aRB1.ButtonIsLeft = false;
413cdf0e10cSrcweir     aRB1.BorderColor = Color( COL_LIGHTGREEN );
414cdf0e10cSrcweir     aRB1.BackgroundColor = Color( COL_LIGHTBLUE );
415cdf0e10cSrcweir     aRB1.TextColor = Color( COL_LIGHTRED );
416cdf0e10cSrcweir     aRB1.TextFont = Font( String( RTL_CONSTASCII_USTRINGPARAM( "Courier" ) ), Size( 0, 800 ) );
417cdf0e10cSrcweir     aWriter.CreateControl( aRB1 );
418cdf0e10cSrcweir 
419cdf0e10cSrcweir     PDFWriter::RadioButtonWidget aRB2;
420cdf0e10cSrcweir     aRB2.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "rb2_1" ) );
421cdf0e10cSrcweir     aRB2.Description = OUString( RTL_CONSTASCII_USTRINGPARAM( "radio 2 button 1" ) );
422cdf0e10cSrcweir     aRB2.Text = OUString( RTL_CONSTASCII_USTRINGPARAM( "Joy" ) );
423cdf0e10cSrcweir     aRB2.Location = Rectangle( Point( 10500, 15000 ), Size( 3000, 1000 ) );
424cdf0e10cSrcweir     aRB2.Selected = true;
425cdf0e10cSrcweir     aRB2.RadioGroup = 2;
426cdf0e10cSrcweir     aWriter.CreateControl( aRB2 );
427cdf0e10cSrcweir 
428cdf0e10cSrcweir     PDFWriter::RadioButtonWidget aRB3;
429cdf0e10cSrcweir     aRB3.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "rb1_2" ) );
430cdf0e10cSrcweir     aRB3.Description = OUString( RTL_CONSTASCII_USTRINGPARAM( "radio 1 button 2" ) );
431cdf0e10cSrcweir     aRB3.Text = OUString( RTL_CONSTASCII_USTRINGPARAM( "Desperation" ) );
432cdf0e10cSrcweir     aRB3.Location = Rectangle( Point( 4500, 16000 ), Size( 3000, 1000 ) );
433cdf0e10cSrcweir     aRB3.Selected = true;
434cdf0e10cSrcweir     aRB3.RadioGroup = 1;
435cdf0e10cSrcweir     aWriter.CreateControl( aRB3 );
436cdf0e10cSrcweir 
437cdf0e10cSrcweir     PDFWriter::EditWidget aEditBox;
438cdf0e10cSrcweir     aEditBox.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "testEdit" ) );
439cdf0e10cSrcweir     aEditBox.Description = OUString( RTL_CONSTASCII_USTRINGPARAM( "A test edit field" ) );
440cdf0e10cSrcweir     aEditBox.Text = OUString( RTL_CONSTASCII_USTRINGPARAM( "A little test text" ) );
441cdf0e10cSrcweir     aEditBox.TextStyle = TEXT_DRAW_LEFT | TEXT_DRAW_VCENTER;
442cdf0e10cSrcweir     aEditBox.Location = Rectangle( Point( 10000, 18000 ), Size( 5000, 1500 ) );
443cdf0e10cSrcweir     aEditBox.MaxLen = 100;
444cdf0e10cSrcweir     aEditBox.Border = aEditBox.Background = true;
445cdf0e10cSrcweir     aEditBox.BorderColor = Color( COL_BLACK );
446cdf0e10cSrcweir     aWriter.CreateControl( aEditBox );
447cdf0e10cSrcweir 
448cdf0e10cSrcweir     // normal list box
449cdf0e10cSrcweir     PDFWriter::ListBoxWidget aLstBox;
450cdf0e10cSrcweir     aLstBox.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "testListBox" ) );
451cdf0e10cSrcweir     aLstBox.Text = OUString( RTL_CONSTASCII_USTRINGPARAM( "One" ) );
452cdf0e10cSrcweir     aLstBox.Description = OUString( RTL_CONSTASCII_USTRINGPARAM( "select me" ) );
453cdf0e10cSrcweir     aLstBox.Location = Rectangle( Point( 4500, 18000 ), Size( 3000, 1500 ) );
454cdf0e10cSrcweir     aLstBox.Sort = true;
455cdf0e10cSrcweir     aLstBox.MultiSelect = true;
456cdf0e10cSrcweir     aLstBox.Border = aLstBox.Background = true;
457cdf0e10cSrcweir     aLstBox.BorderColor = Color( COL_BLACK );
458cdf0e10cSrcweir     aLstBox.Entries.push_back( OUString( RTL_CONSTASCII_USTRINGPARAM( "One" ) ) );
459cdf0e10cSrcweir     aLstBox.Entries.push_back( OUString( RTL_CONSTASCII_USTRINGPARAM( "Two" ) ) );
460cdf0e10cSrcweir     aLstBox.Entries.push_back( OUString( RTL_CONSTASCII_USTRINGPARAM( "Three" ) ) );
461cdf0e10cSrcweir     aLstBox.Entries.push_back( OUString( RTL_CONSTASCII_USTRINGPARAM( "Four" ) ) );
462cdf0e10cSrcweir     aLstBox.SelectedEntries.push_back( 1 );
463cdf0e10cSrcweir     aLstBox.SelectedEntries.push_back( 2 );
464cdf0e10cSrcweir     aWriter.CreateControl( aLstBox );
465cdf0e10cSrcweir 
466cdf0e10cSrcweir     // dropdown list box
467cdf0e10cSrcweir     aLstBox.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "testDropDownListBox" ) );
468cdf0e10cSrcweir     aLstBox.DropDown = true;
469cdf0e10cSrcweir     aLstBox.Location = Rectangle( Point( 4500, 19500 ), Size( 3000, 500 ) );
470cdf0e10cSrcweir     aWriter.CreateControl( aLstBox );
471cdf0e10cSrcweir 
472cdf0e10cSrcweir     // combo box
473cdf0e10cSrcweir     PDFWriter::ComboBoxWidget aComboBox;
474cdf0e10cSrcweir     aComboBox.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "testComboBox" ) );
475cdf0e10cSrcweir     aComboBox.Text = OUString( RTL_CONSTASCII_USTRINGPARAM( "test a combobox" ) );
476cdf0e10cSrcweir     aComboBox.Entries.push_back( OUString( RTL_CONSTASCII_USTRINGPARAM( "Larry" ) ) );
477cdf0e10cSrcweir     aComboBox.Entries.push_back( OUString( RTL_CONSTASCII_USTRINGPARAM( "Curly" ) ) );
478cdf0e10cSrcweir     aComboBox.Entries.push_back( OUString( RTL_CONSTASCII_USTRINGPARAM( "Moe" ) ) );
479cdf0e10cSrcweir     aComboBox.Location = Rectangle( Point( 4500, 20000 ), Size( 3000, 500 ) );
480cdf0e10cSrcweir     aWriter.CreateControl( aComboBox );
481cdf0e10cSrcweir 
482cdf0e10cSrcweir     // test outlines
483cdf0e10cSrcweir     sal_Int32 nPage1OL = aWriter.CreateOutlineItem();
484cdf0e10cSrcweir     aWriter.SetOutlineItemText( nPage1OL, OUString( RTL_CONSTASCII_USTRINGPARAM( "Page 1" ) ) );
485cdf0e10cSrcweir     aWriter.SetOutlineItemDest( nPage1OL, nSecondDest );
486cdf0e10cSrcweir     aWriter.CreateOutlineItem( nPage1OL, OUString( RTL_CONSTASCII_USTRINGPARAM( "Dest 2" ) ), nSecondDest );
487cdf0e10cSrcweir     aWriter.CreateOutlineItem( nPage1OL, OUString( RTL_CONSTASCII_USTRINGPARAM( "Dest 2 revisited" ) ), nSecondDest );
488cdf0e10cSrcweir     aWriter.CreateOutlineItem( nPage1OL, OUString( RTL_CONSTASCII_USTRINGPARAM( "Dest 2 again" ) ), nSecondDest );
489cdf0e10cSrcweir     sal_Int32 nPage2OL = aWriter.CreateOutlineItem();
490cdf0e10cSrcweir     aWriter.SetOutlineItemText( nPage2OL, OUString( RTL_CONSTASCII_USTRINGPARAM( "Page 2" ) ) );
491cdf0e10cSrcweir     aWriter.CreateOutlineItem( nPage2OL, OUString( RTL_CONSTASCII_USTRINGPARAM( "Dest 1" ) ), nFirstDest );
492cdf0e10cSrcweir 
493cdf0e10cSrcweir     aWriter.EndStructureElement(); // close document
494cdf0e10cSrcweir     aWriter.Emit();
495cdf0e10cSrcweir }
496cdf0e10cSrcweir #endif
497cdf0e10cSrcweir 
498cdf0e10cSrcweir static const sal_Int32 nLog10Divisor = 1;
499cdf0e10cSrcweir static const double fDivisor = 10.0;
500cdf0e10cSrcweir 
501cdf0e10cSrcweir static inline double pixelToPoint( sal_Int32 px ) { return double(px)/fDivisor; }
502cdf0e10cSrcweir static inline double pixelToPoint( double px ) { return px/fDivisor; }
503cdf0e10cSrcweir static inline sal_Int32 pointToPixel( double pt ) { return sal_Int32(pt*fDivisor); }
504cdf0e10cSrcweir 
505cdf0e10cSrcweir const sal_uInt8 PDFWriterImpl::s_nPadString[32] =
506cdf0e10cSrcweir {
507cdf0e10cSrcweir     0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08,
508cdf0e10cSrcweir     0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80, 0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A
509cdf0e10cSrcweir };
510cdf0e10cSrcweir 
511cdf0e10cSrcweir static void appendHex( sal_Int8 nInt, OStringBuffer& rBuffer )
512cdf0e10cSrcweir {
513cdf0e10cSrcweir     static const sal_Char pHexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7',
514cdf0e10cSrcweir                                            '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
515cdf0e10cSrcweir     rBuffer.append( pHexDigits[ (nInt >> 4) & 15 ] );
516cdf0e10cSrcweir     rBuffer.append( pHexDigits[ nInt & 15 ] );
517cdf0e10cSrcweir }
518cdf0e10cSrcweir 
519cdf0e10cSrcweir static void appendName( const OUString& rStr, OStringBuffer& rBuffer )
520cdf0e10cSrcweir {
521cdf0e10cSrcweir // FIXME i59651 add a check for max length of 127 chars? Per PDF spec 1.4, appendix C.1
522cdf0e10cSrcweir // I guess than when reading the #xx sequence it will count for a single character.
523cdf0e10cSrcweir     OString aStr( OUStringToOString( rStr, RTL_TEXTENCODING_UTF8 ) );
524cdf0e10cSrcweir     const sal_Char* pStr = aStr.getStr();
525cdf0e10cSrcweir     int nLen = aStr.getLength();
526cdf0e10cSrcweir     for( int i = 0; i < nLen; i++ )
527cdf0e10cSrcweir     {
528cdf0e10cSrcweir         /*  #i16920# PDF recommendation: output UTF8, any byte
529cdf0e10cSrcweir          *  outside the interval [33(=ASCII'!');126(=ASCII'~')]
530cdf0e10cSrcweir          *  should be escaped hexadecimal
531cdf0e10cSrcweir          *  for the sake of ghostscript which also reads PDF
532cdf0e10cSrcweir          *  but has a narrower acceptance rate we only pass
533cdf0e10cSrcweir          *  alphanumerics and '-' literally.
534cdf0e10cSrcweir          */
535cdf0e10cSrcweir         if( (pStr[i] >= 'A' && pStr[i] <= 'Z' ) ||
536cdf0e10cSrcweir             (pStr[i] >= 'a' && pStr[i] <= 'z' ) ||
537cdf0e10cSrcweir             (pStr[i] >= '0' && pStr[i] <= '9' ) ||
538cdf0e10cSrcweir             pStr[i] == '-' )
539cdf0e10cSrcweir         {
540cdf0e10cSrcweir             rBuffer.append( pStr[i] );
541cdf0e10cSrcweir         }
542cdf0e10cSrcweir         else
543cdf0e10cSrcweir         {
544cdf0e10cSrcweir             rBuffer.append( '#' );
545cdf0e10cSrcweir             appendHex( (sal_Int8)pStr[i], rBuffer );
546cdf0e10cSrcweir         }
547cdf0e10cSrcweir     }
548cdf0e10cSrcweir }
549cdf0e10cSrcweir 
550cdf0e10cSrcweir static void appendName( const sal_Char* pStr, OStringBuffer& rBuffer )
551cdf0e10cSrcweir {
552cdf0e10cSrcweir //FIXME i59651 see above
553cdf0e10cSrcweir     while( pStr && *pStr )
554cdf0e10cSrcweir     {
555cdf0e10cSrcweir         if( (*pStr >= 'A' && *pStr <= 'Z' ) ||
556cdf0e10cSrcweir             (*pStr >= 'a' && *pStr <= 'z' ) ||
557cdf0e10cSrcweir             (*pStr >= '0' && *pStr <= '9' ) ||
558cdf0e10cSrcweir             *pStr == '-' )
559cdf0e10cSrcweir         {
560cdf0e10cSrcweir             rBuffer.append( *pStr );
561cdf0e10cSrcweir         }
562cdf0e10cSrcweir         else
563cdf0e10cSrcweir         {
564cdf0e10cSrcweir             rBuffer.append( '#' );
565cdf0e10cSrcweir             appendHex( (sal_Int8)*pStr, rBuffer );
566cdf0e10cSrcweir         }
567cdf0e10cSrcweir         pStr++;
568cdf0e10cSrcweir     }
569cdf0e10cSrcweir }
570cdf0e10cSrcweir 
571cdf0e10cSrcweir //used only to emit encoded passwords
572cdf0e10cSrcweir static void appendLiteralString( const sal_Char* pStr, sal_Int32 nLength, OStringBuffer& rBuffer )
573cdf0e10cSrcweir {
574cdf0e10cSrcweir 	while( nLength )
575cdf0e10cSrcweir 	{
576cdf0e10cSrcweir 		switch( *pStr )
577cdf0e10cSrcweir 		{
578cdf0e10cSrcweir 		case '\n' :
579cdf0e10cSrcweir 			rBuffer.append( "\\n" );
580cdf0e10cSrcweir 			break;
581cdf0e10cSrcweir 		case '\r' :
582cdf0e10cSrcweir 			rBuffer.append( "\\r" );
583cdf0e10cSrcweir 			break;
584cdf0e10cSrcweir 		case '\t' :
585cdf0e10cSrcweir 			rBuffer.append( "\\t" );
586cdf0e10cSrcweir 			break;
587cdf0e10cSrcweir 		case '\b' :
588cdf0e10cSrcweir 			rBuffer.append( "\\b" );
589cdf0e10cSrcweir 			break;
590cdf0e10cSrcweir 		case '\f' :
591cdf0e10cSrcweir 			rBuffer.append( "\\f" );
592cdf0e10cSrcweir 			break;
593cdf0e10cSrcweir 		case '(' :
594cdf0e10cSrcweir 		case ')' :
595cdf0e10cSrcweir 		case '\\' :
596cdf0e10cSrcweir 			rBuffer.append( "\\" );
597cdf0e10cSrcweir 			rBuffer.append( (sal_Char) *pStr );
598cdf0e10cSrcweir 			break;
599cdf0e10cSrcweir 		default:
600cdf0e10cSrcweir 			rBuffer.append( (sal_Char) *pStr );
601cdf0e10cSrcweir 			break;
602cdf0e10cSrcweir 		}
603cdf0e10cSrcweir 		pStr++;
604cdf0e10cSrcweir 		nLength--;
605cdf0e10cSrcweir 	}
606cdf0e10cSrcweir }
607cdf0e10cSrcweir 
608cdf0e10cSrcweir /**--->i56629
609cdf0e10cSrcweir  * Convert a string before using it.
610cdf0e10cSrcweir  *
611cdf0e10cSrcweir  * This string conversion function is needed because the destination name
612cdf0e10cSrcweir  * in a PDF file seen through an Internet browser should be
613cdf0e10cSrcweir  * specially crafted, in order to be used directly by the browser.
614cdf0e10cSrcweir  * In this way the fragment part of a hyperlink to a PDF file (e.g. something
615cdf0e10cSrcweir  * as 'test1/test2/a-file.pdf#thefragment) will be (hopefully) interpreted by the
616cdf0e10cSrcweir  * PDF reader (currently only Adobe Reader plug-in seems to be working that way) called
617cdf0e10cSrcweir  * from inside the Internet browser as: 'open the file test1/test2/a-file.pdf
618cdf0e10cSrcweir  * and go to named destination thefragment using default zoom'.
619cdf0e10cSrcweir  * The conversion is needed because in case of a fragment in the form: Slide%201
620cdf0e10cSrcweir  * (meaning Slide 1) as it is converted obeying the Inet rules, it will become Slide25201
621cdf0e10cSrcweir  * using this conversion, in both the generated named destinations, fragment and GoToR
622cdf0e10cSrcweir  * destination.
623cdf0e10cSrcweir  *
624cdf0e10cSrcweir  * The names for destinations are name objects and so they don't need to be encrypted
625cdf0e10cSrcweir  * even though they expose the content of PDF file (e.g. guessing the PDF content from the
626cdf0e10cSrcweir  * destination name).
627cdf0e10cSrcweir  *
628cdf0e10cSrcweir  * Fhurter limitation: it is advisable to use standard ASCII characters for
629cdf0e10cSrcweir  * OOo bookmarks.
630cdf0e10cSrcweir */
631cdf0e10cSrcweir static void appendDestinationName( const rtl::OUString& rString, OStringBuffer& rBuffer )
632cdf0e10cSrcweir {
633cdf0e10cSrcweir     const sal_Unicode* pStr = rString.getStr();
634cdf0e10cSrcweir     sal_Int32 nLen = rString.getLength();
635cdf0e10cSrcweir     for( int i = 0; i < nLen; i++ )
636cdf0e10cSrcweir     {
637cdf0e10cSrcweir         sal_Unicode aChar = pStr[i];
638cdf0e10cSrcweir         if( (aChar >= '0' && aChar <= '9' ) ||
639cdf0e10cSrcweir             (aChar >= 'a' && aChar <= 'z' ) ||
640cdf0e10cSrcweir             (aChar >= 'A' && aChar <= 'Z' ) ||
641cdf0e10cSrcweir             aChar == '-' )
642cdf0e10cSrcweir         {
643cdf0e10cSrcweir             rBuffer.append((sal_Char)aChar);
644cdf0e10cSrcweir         }
645cdf0e10cSrcweir         else
646cdf0e10cSrcweir         {
647cdf0e10cSrcweir             sal_Int8 aValueHigh = sal_Int8(aChar >> 8);
648cdf0e10cSrcweir             if(aValueHigh > 0)
649cdf0e10cSrcweir                 appendHex( aValueHigh, rBuffer );
650cdf0e10cSrcweir             appendHex( (sal_Int8)(aChar & 255 ), rBuffer );
651cdf0e10cSrcweir         }
652cdf0e10cSrcweir     }
653cdf0e10cSrcweir }
654cdf0e10cSrcweir //<--- i56629
655cdf0e10cSrcweir 
656cdf0e10cSrcweir static void appendUnicodeTextString( const rtl::OUString& rString, OStringBuffer& rBuffer )
657cdf0e10cSrcweir {
658cdf0e10cSrcweir 	rBuffer.append( "FEFF" );
659cdf0e10cSrcweir 	const sal_Unicode* pStr = rString.getStr();
660cdf0e10cSrcweir 	sal_Int32 nLen = rString.getLength();
661cdf0e10cSrcweir 	for( int i = 0; i < nLen; i++ )
662cdf0e10cSrcweir 	{
663cdf0e10cSrcweir 		sal_Unicode aChar = pStr[i];
664cdf0e10cSrcweir 		appendHex( (sal_Int8)(aChar >> 8), rBuffer );
665cdf0e10cSrcweir 		appendHex( (sal_Int8)(aChar & 255 ), rBuffer );
666cdf0e10cSrcweir 	}
667cdf0e10cSrcweir }
668cdf0e10cSrcweir 
669cdf0e10cSrcweir void PDFWriterImpl::createWidgetFieldName( sal_Int32 i_nWidgetIndex, const PDFWriter::AnyWidget& i_rControl )
670cdf0e10cSrcweir {
671cdf0e10cSrcweir     /* #i80258# previously we use appendName here
672cdf0e10cSrcweir        however we need a slightly different coding scheme than the normal
673cdf0e10cSrcweir        name encoding for field names
674cdf0e10cSrcweir     */
675cdf0e10cSrcweir     const OUString& rName = (m_aContext.Version > PDFWriter::PDF_1_2) ? i_rControl.Name : i_rControl.Text;
676cdf0e10cSrcweir     OString aStr( OUStringToOString( rName, RTL_TEXTENCODING_UTF8 ) );
677cdf0e10cSrcweir     const sal_Char* pStr = aStr.getStr();
678cdf0e10cSrcweir     int nLen = aStr.getLength();
679cdf0e10cSrcweir 
680cdf0e10cSrcweir     OStringBuffer aBuffer( rName.getLength()+64 );
681cdf0e10cSrcweir     for( int i = 0; i < nLen; i++ )
682cdf0e10cSrcweir     {
683cdf0e10cSrcweir         /*  #i16920# PDF recommendation: output UTF8, any byte
684cdf0e10cSrcweir          *  outside the interval [32(=ASCII' ');126(=ASCII'~')]
685cdf0e10cSrcweir          *  should be escaped hexadecimal
686cdf0e10cSrcweir          */
687cdf0e10cSrcweir         if( (pStr[i] >= 32 && pStr[i] <= 126 ) )
688cdf0e10cSrcweir             aBuffer.append( pStr[i] );
689cdf0e10cSrcweir         else
690cdf0e10cSrcweir         {
691cdf0e10cSrcweir             aBuffer.append( '#' );
692cdf0e10cSrcweir             appendHex( (sal_Int8)pStr[i], aBuffer );
693cdf0e10cSrcweir         }
694cdf0e10cSrcweir     }
695cdf0e10cSrcweir 
696cdf0e10cSrcweir     OString aFullName( aBuffer.makeStringAndClear() );
697cdf0e10cSrcweir 
698cdf0e10cSrcweir     /* #i82785# create hierarchical fields down to the for each dot in i_rName */
699cdf0e10cSrcweir     sal_Int32 nTokenIndex = 0, nLastTokenIndex = 0;
700cdf0e10cSrcweir     OString aPartialName;
701cdf0e10cSrcweir     OString aDomain;
702cdf0e10cSrcweir     do
703cdf0e10cSrcweir     {
704cdf0e10cSrcweir         nLastTokenIndex = nTokenIndex;
705cdf0e10cSrcweir         aPartialName = aFullName.getToken( 0, '.', nTokenIndex );
706cdf0e10cSrcweir         if( nTokenIndex != -1 )
707cdf0e10cSrcweir         {
708cdf0e10cSrcweir             // find or create a hierarchical field
709cdf0e10cSrcweir             // first find the fully qualified name up to this field
710cdf0e10cSrcweir             aDomain = aFullName.copy( 0, nTokenIndex-1 );
711cdf0e10cSrcweir             std::hash_map< rtl::OString, sal_Int32, rtl::OStringHash >::const_iterator it = m_aFieldNameMap.find( aDomain );
712cdf0e10cSrcweir             if( it == m_aFieldNameMap.end() )
713cdf0e10cSrcweir             {
714cdf0e10cSrcweir                  // create new hierarchy field
715cdf0e10cSrcweir                 sal_Int32 nNewWidget = m_aWidgets.size();
716cdf0e10cSrcweir                 m_aWidgets.push_back( PDFWidget() );
717cdf0e10cSrcweir                 m_aWidgets[nNewWidget].m_nObject = createObject();
718cdf0e10cSrcweir                 m_aWidgets[nNewWidget].m_eType = PDFWriter::Hierarchy;
719cdf0e10cSrcweir                 m_aWidgets[nNewWidget].m_aName = aPartialName;
720cdf0e10cSrcweir                 m_aWidgets[i_nWidgetIndex].m_nParent = m_aWidgets[nNewWidget].m_nObject;
721cdf0e10cSrcweir                 m_aFieldNameMap[aDomain] = nNewWidget;
722cdf0e10cSrcweir                 m_aWidgets[i_nWidgetIndex].m_nParent = m_aWidgets[nNewWidget].m_nObject;
723cdf0e10cSrcweir                 if( nLastTokenIndex > 0 )
724cdf0e10cSrcweir                 {
725cdf0e10cSrcweir                     // this field is not a root field and
726cdf0e10cSrcweir                     // needs to be inserted to its parent
727cdf0e10cSrcweir                     OString aParentDomain( aDomain.copy( 0, nLastTokenIndex-1 ) );
728cdf0e10cSrcweir                     it = m_aFieldNameMap.find( aParentDomain );
729cdf0e10cSrcweir                     OSL_ENSURE( it != m_aFieldNameMap.end(), "field name not found" );
730cdf0e10cSrcweir                     if( it != m_aFieldNameMap.end()  )
731cdf0e10cSrcweir                     {
732cdf0e10cSrcweir                         OSL_ENSURE( it->second < sal_Int32(m_aWidgets.size()), "invalid field number entry" );
733cdf0e10cSrcweir                         if( it->second < sal_Int32(m_aWidgets.size()) )
734cdf0e10cSrcweir                         {
735cdf0e10cSrcweir                             PDFWidget& rParentField( m_aWidgets[it->second] );
736cdf0e10cSrcweir                             rParentField.m_aKids.push_back( m_aWidgets[nNewWidget].m_nObject );
737cdf0e10cSrcweir                             rParentField.m_aKidsIndex.push_back( nNewWidget );
738cdf0e10cSrcweir                             m_aWidgets[nNewWidget].m_nParent = rParentField.m_nObject;
739cdf0e10cSrcweir                         }
740cdf0e10cSrcweir                     }
741cdf0e10cSrcweir                 }
742cdf0e10cSrcweir             }
743cdf0e10cSrcweir             else if( m_aWidgets[it->second].m_eType != PDFWriter::Hierarchy )
744cdf0e10cSrcweir             {
745cdf0e10cSrcweir                 // this is invalid, someone tries to have a terminal field as parent
746cdf0e10cSrcweir                 // example: a button with the name foo.bar exists and
747cdf0e10cSrcweir                 // another button is named foo.bar.no
748cdf0e10cSrcweir                 // workaround: put the second terminal field as much up in the hierarchy as
749cdf0e10cSrcweir                 // necessary to have a non-terminal field as parent (or none at all)
750cdf0e10cSrcweir                 // since it->second already is terminal, we just need to use its parent
751cdf0e10cSrcweir                 aDomain = OString();
752cdf0e10cSrcweir                 aPartialName = aFullName.copy( aFullName.lastIndexOf( '.' )+1 );
753cdf0e10cSrcweir                 if( nLastTokenIndex > 0 )
754cdf0e10cSrcweir                 {
755cdf0e10cSrcweir                     aDomain = aFullName.copy( 0, nLastTokenIndex-1 );
756cdf0e10cSrcweir                     OStringBuffer aBuf( aDomain.getLength() + 1 + aPartialName.getLength() );
757cdf0e10cSrcweir                     aBuf.append( aDomain );
758cdf0e10cSrcweir                     aBuf.append( '.' );
759cdf0e10cSrcweir                     aBuf.append( aPartialName );
760cdf0e10cSrcweir                     aFullName = aBuf.makeStringAndClear();
761cdf0e10cSrcweir                 }
762cdf0e10cSrcweir                 else
763cdf0e10cSrcweir                     aFullName = aPartialName;
764cdf0e10cSrcweir                 break;
765cdf0e10cSrcweir             }
766cdf0e10cSrcweir         }
767cdf0e10cSrcweir     } while( nTokenIndex != -1 );
768cdf0e10cSrcweir 
769cdf0e10cSrcweir     // insert widget into its hierarchy field
770cdf0e10cSrcweir     if( aDomain.getLength() )
771cdf0e10cSrcweir     {
772cdf0e10cSrcweir         std::hash_map< rtl::OString, sal_Int32, rtl::OStringHash >::const_iterator it = m_aFieldNameMap.find( aDomain );
773cdf0e10cSrcweir         if( it != m_aFieldNameMap.end() )
774cdf0e10cSrcweir         {
775cdf0e10cSrcweir             OSL_ENSURE( it->second >= 0 && it->second < sal_Int32( m_aWidgets.size() ), "invalid field index" );
776cdf0e10cSrcweir             if( it->second >= 0 && it->second < sal_Int32(m_aWidgets.size()) )
777cdf0e10cSrcweir             {
778cdf0e10cSrcweir                 m_aWidgets[i_nWidgetIndex].m_nParent = m_aWidgets[it->second].m_nObject;
779cdf0e10cSrcweir                 m_aWidgets[it->second].m_aKids.push_back( m_aWidgets[i_nWidgetIndex].m_nObject);
780cdf0e10cSrcweir                 m_aWidgets[it->second].m_aKidsIndex.push_back( i_nWidgetIndex );
781cdf0e10cSrcweir             }
782cdf0e10cSrcweir         }
783cdf0e10cSrcweir     }
784cdf0e10cSrcweir 
785cdf0e10cSrcweir     if( aPartialName.getLength() == 0 )
786cdf0e10cSrcweir     {
787cdf0e10cSrcweir         // how funny, an empty field name
788cdf0e10cSrcweir         if( i_rControl.getType() == PDFWriter::RadioButton )
789cdf0e10cSrcweir         {
790cdf0e10cSrcweir             aPartialName  = "RadioGroup";
791cdf0e10cSrcweir             aPartialName += OString::valueOf( static_cast<const PDFWriter::RadioButtonWidget&>(i_rControl).RadioGroup );
792cdf0e10cSrcweir         }
793cdf0e10cSrcweir         else
794cdf0e10cSrcweir             aPartialName = OString( "Widget" );
795cdf0e10cSrcweir     }
796cdf0e10cSrcweir 
797cdf0e10cSrcweir     if( ! m_aContext.AllowDuplicateFieldNames )
798cdf0e10cSrcweir     {
799cdf0e10cSrcweir         std::hash_map<OString, sal_Int32, OStringHash>::iterator it = m_aFieldNameMap.find( aFullName );
800cdf0e10cSrcweir 
801cdf0e10cSrcweir         if( it != m_aFieldNameMap.end() ) // not unique
802cdf0e10cSrcweir         {
803cdf0e10cSrcweir             std::hash_map< OString, sal_Int32, OStringHash >::const_iterator check_it;
804cdf0e10cSrcweir             OString aTry;
805cdf0e10cSrcweir             sal_Int32 nTry = 2;
806cdf0e10cSrcweir             do
807cdf0e10cSrcweir             {
808cdf0e10cSrcweir                 OStringBuffer aUnique( aFullName.getLength() + 16 );
809cdf0e10cSrcweir                 aUnique.append( aFullName );
810cdf0e10cSrcweir                 aUnique.append( '_' );
811cdf0e10cSrcweir                 aUnique.append( nTry++ );
812cdf0e10cSrcweir                 aTry = aUnique.makeStringAndClear();
813cdf0e10cSrcweir                 check_it = m_aFieldNameMap.find( aTry );
814cdf0e10cSrcweir             } while( check_it != m_aFieldNameMap.end() );
815cdf0e10cSrcweir             aFullName = aTry;
816cdf0e10cSrcweir             m_aFieldNameMap[ aFullName ] = i_nWidgetIndex;
817cdf0e10cSrcweir             aPartialName = aFullName.copy( aFullName.lastIndexOf( '.' )+1 );
818cdf0e10cSrcweir         }
819cdf0e10cSrcweir         else
820cdf0e10cSrcweir             m_aFieldNameMap[ aFullName ] = i_nWidgetIndex;
821cdf0e10cSrcweir     }
822cdf0e10cSrcweir 
823cdf0e10cSrcweir     // finally
824cdf0e10cSrcweir     m_aWidgets[i_nWidgetIndex].m_aName = aPartialName;
825cdf0e10cSrcweir }
826cdf0e10cSrcweir 
827cdf0e10cSrcweir static void appendFixedInt( sal_Int32 nValue, OStringBuffer& rBuffer, sal_Int32 nPrecision = nLog10Divisor )
828cdf0e10cSrcweir {
829cdf0e10cSrcweir     if( nValue < 0 )
830cdf0e10cSrcweir     {
831cdf0e10cSrcweir         rBuffer.append( '-' );
832cdf0e10cSrcweir         nValue = -nValue;
833cdf0e10cSrcweir     }
834cdf0e10cSrcweir     sal_Int32 nFactor = 1, nDiv = nPrecision;
835cdf0e10cSrcweir     while( nDiv-- )
836cdf0e10cSrcweir         nFactor *= 10;
837cdf0e10cSrcweir 
838cdf0e10cSrcweir     sal_Int32 nInt		= nValue / nFactor;
839cdf0e10cSrcweir     rBuffer.append( nInt );
840cdf0e10cSrcweir     if( nFactor > 1 )
841cdf0e10cSrcweir     {
842cdf0e10cSrcweir         sal_Int32 nDecimal	= nValue % nFactor;
843cdf0e10cSrcweir         if( nDecimal )
844cdf0e10cSrcweir         {
845cdf0e10cSrcweir             rBuffer.append( '.' );
846cdf0e10cSrcweir             // omit trailing zeros
847cdf0e10cSrcweir             while( (nDecimal % 10) == 0 )
848cdf0e10cSrcweir                 nDecimal /= 10;
849cdf0e10cSrcweir             rBuffer.append( nDecimal );
850cdf0e10cSrcweir         }
851cdf0e10cSrcweir     }
852cdf0e10cSrcweir }
853cdf0e10cSrcweir 
854cdf0e10cSrcweir 
855cdf0e10cSrcweir // appends a double. PDF does not accept exponential format, only fixed point
856cdf0e10cSrcweir static void appendDouble( double fValue, OStringBuffer& rBuffer, sal_Int32 nPrecision = 5 )
857cdf0e10cSrcweir {
858cdf0e10cSrcweir     bool bNeg = false;
859cdf0e10cSrcweir     if( fValue < 0.0 )
860cdf0e10cSrcweir     {
861cdf0e10cSrcweir         bNeg = true;
862cdf0e10cSrcweir         fValue=-fValue;
863cdf0e10cSrcweir     }
864cdf0e10cSrcweir 
865cdf0e10cSrcweir     sal_Int64 nInt = (sal_Int64)fValue;
866cdf0e10cSrcweir     fValue -= (double)nInt;
867cdf0e10cSrcweir     // optimizing hardware may lead to a value of 1.0 after the subtraction
868cdf0e10cSrcweir     if( fValue == 1.0 || log10( 1.0-fValue ) <= -nPrecision )
869cdf0e10cSrcweir     {
870cdf0e10cSrcweir         nInt++;
871cdf0e10cSrcweir         fValue = 0.0;
872cdf0e10cSrcweir     }
873cdf0e10cSrcweir     sal_Int64 nFrac = 0;
874cdf0e10cSrcweir     if( fValue )
875cdf0e10cSrcweir     {
876cdf0e10cSrcweir         fValue *= pow( 10.0, (double)nPrecision );
877cdf0e10cSrcweir         nFrac = (sal_Int64)fValue;
878cdf0e10cSrcweir     }
879cdf0e10cSrcweir     if( bNeg && ( nInt || nFrac ) )
880cdf0e10cSrcweir         rBuffer.append( '-' );
881cdf0e10cSrcweir     rBuffer.append( nInt );
882cdf0e10cSrcweir     if( nFrac )
883cdf0e10cSrcweir     {
884cdf0e10cSrcweir 		int i;
885cdf0e10cSrcweir         rBuffer.append( '.' );
886cdf0e10cSrcweir 		sal_Int64 nBound = (sal_Int64)(pow( 10.0, nPrecision - 1.0 )+0.5);
887cdf0e10cSrcweir 		for ( i = 0; ( i < nPrecision ) && nFrac; i++ )
888cdf0e10cSrcweir 		{
889cdf0e10cSrcweir 			sal_Int64 nNumb = nFrac / nBound;
890cdf0e10cSrcweir 			nFrac -= nNumb * nBound;
891cdf0e10cSrcweir 			rBuffer.append( nNumb );
892cdf0e10cSrcweir 			nBound /= 10;
893cdf0e10cSrcweir 		}
894cdf0e10cSrcweir     }
895cdf0e10cSrcweir }
896cdf0e10cSrcweir 
897cdf0e10cSrcweir 
898cdf0e10cSrcweir static void appendColor( const Color& rColor, OStringBuffer& rBuffer, bool bConvertToGrey = false )
899cdf0e10cSrcweir {
900cdf0e10cSrcweir 
901cdf0e10cSrcweir     if( rColor != Color( COL_TRANSPARENT ) )
902cdf0e10cSrcweir     {
903cdf0e10cSrcweir         if( bConvertToGrey )
904cdf0e10cSrcweir         {
905cdf0e10cSrcweir             sal_uInt8 cByte = rColor.GetLuminance();
906cdf0e10cSrcweir             appendDouble( (double)cByte / 255.0, rBuffer );
907cdf0e10cSrcweir         }
908cdf0e10cSrcweir         else
909cdf0e10cSrcweir         {
910cdf0e10cSrcweir             appendDouble( (double)rColor.GetRed() / 255.0, rBuffer );
911cdf0e10cSrcweir             rBuffer.append( ' ' );
912cdf0e10cSrcweir             appendDouble( (double)rColor.GetGreen() / 255.0, rBuffer );
913cdf0e10cSrcweir             rBuffer.append( ' ' );
914cdf0e10cSrcweir             appendDouble( (double)rColor.GetBlue() / 255.0, rBuffer );
915cdf0e10cSrcweir         }
916cdf0e10cSrcweir     }
917cdf0e10cSrcweir }
918cdf0e10cSrcweir 
919cdf0e10cSrcweir void PDFWriterImpl::appendStrokingColor( const Color& rColor, OStringBuffer& rBuffer )
920cdf0e10cSrcweir {
921cdf0e10cSrcweir     if( rColor != Color( COL_TRANSPARENT ) )
922cdf0e10cSrcweir     {
923cdf0e10cSrcweir         bool bGrey = m_aContext.ColorMode == PDFWriter::DrawGreyscale;
924cdf0e10cSrcweir         appendColor( rColor, rBuffer, bGrey );
925cdf0e10cSrcweir         rBuffer.append( bGrey ? " G" : " RG" );
926cdf0e10cSrcweir     }
927cdf0e10cSrcweir }
928cdf0e10cSrcweir 
929cdf0e10cSrcweir void PDFWriterImpl::appendNonStrokingColor( const Color& rColor, OStringBuffer& rBuffer )
930cdf0e10cSrcweir {
931cdf0e10cSrcweir     if( rColor != Color( COL_TRANSPARENT ) )
932cdf0e10cSrcweir     {
933cdf0e10cSrcweir         bool bGrey = m_aContext.ColorMode == PDFWriter::DrawGreyscale;
934cdf0e10cSrcweir         appendColor( rColor, rBuffer, bGrey );
935cdf0e10cSrcweir         rBuffer.append( bGrey ? " g" : " rg" );
936cdf0e10cSrcweir     }
937cdf0e10cSrcweir }
938cdf0e10cSrcweir 
939cdf0e10cSrcweir // matrix helper class
940cdf0e10cSrcweir // TODO: use basegfx matrix class instead or derive from it
941cdf0e10cSrcweir namespace vcl // TODO: use anonymous namespace to keep this class local
942cdf0e10cSrcweir {
943cdf0e10cSrcweir /*	for sparse matrices of the form (2D linear transformations)
944cdf0e10cSrcweir  *  f[0] f[1] 0
945cdf0e10cSrcweir  *  f[2] f[3] 0
946cdf0e10cSrcweir  *  f[4] f[5] 1
947cdf0e10cSrcweir  */
948cdf0e10cSrcweir class Matrix3
949cdf0e10cSrcweir {
950cdf0e10cSrcweir     double f[6];
951cdf0e10cSrcweir 
952cdf0e10cSrcweir     void set( double *pn ) { for( int i = 0 ; i < 6; i++ ) f[i] = pn[i]; }
953cdf0e10cSrcweir public:
954cdf0e10cSrcweir     Matrix3();
955cdf0e10cSrcweir     ~Matrix3() {}
956cdf0e10cSrcweir 
957cdf0e10cSrcweir     void skew( double alpha, double beta );
958cdf0e10cSrcweir     void scale( double sx, double sy );
959cdf0e10cSrcweir     void rotate( double angle );
960cdf0e10cSrcweir     void translate( double tx, double ty );
961cdf0e10cSrcweir     bool invert();
962cdf0e10cSrcweir 
963cdf0e10cSrcweir     void append( PDFWriterImpl::PDFPage& rPage, OStringBuffer& rBuffer, Point* pBack = NULL );
964cdf0e10cSrcweir 
965cdf0e10cSrcweir     Point transform( const Point& rPoint ) const;
966cdf0e10cSrcweir };
967cdf0e10cSrcweir }
968cdf0e10cSrcweir 
969cdf0e10cSrcweir Matrix3::Matrix3()
970cdf0e10cSrcweir {
971cdf0e10cSrcweir     // initialize to unity
972cdf0e10cSrcweir     f[0] = 1.0;
973cdf0e10cSrcweir     f[1] = 0.0;
974cdf0e10cSrcweir     f[2] = 0.0;
975cdf0e10cSrcweir     f[3] = 1.0;
976cdf0e10cSrcweir     f[4] = 0.0;
977cdf0e10cSrcweir     f[5] = 0.0;
978cdf0e10cSrcweir }
979cdf0e10cSrcweir 
980cdf0e10cSrcweir Point Matrix3::transform( const Point& rOrig ) const
981cdf0e10cSrcweir {
982cdf0e10cSrcweir     double x = (double)rOrig.X(), y = (double)rOrig.Y();
983cdf0e10cSrcweir     return Point( (int)(x*f[0] + y*f[2] + f[4]), (int)(x*f[1] + y*f[3] + f[5]) );
984cdf0e10cSrcweir }
985cdf0e10cSrcweir 
986cdf0e10cSrcweir void Matrix3::skew( double alpha, double beta )
987cdf0e10cSrcweir {
988cdf0e10cSrcweir     double fn[6];
989cdf0e10cSrcweir     double tb = tan( beta );
990cdf0e10cSrcweir     fn[0] = f[0] + f[2]*tb;
991cdf0e10cSrcweir     fn[1] = f[1];
992cdf0e10cSrcweir     fn[2] = f[2] + f[3]*tb;
993cdf0e10cSrcweir     fn[3] = f[3];
994cdf0e10cSrcweir     fn[4] = f[4] + f[5]*tb;
995cdf0e10cSrcweir     fn[5] = f[5];
996cdf0e10cSrcweir     if( alpha != 0.0 )
997cdf0e10cSrcweir     {
998cdf0e10cSrcweir         double ta = tan( alpha );
999cdf0e10cSrcweir         fn[1] += f[0]*ta;
1000cdf0e10cSrcweir         fn[3] += f[2]*ta;
1001cdf0e10cSrcweir         fn[5] += f[4]*ta;
1002cdf0e10cSrcweir     }
1003cdf0e10cSrcweir     set( fn );
1004cdf0e10cSrcweir }
1005cdf0e10cSrcweir 
1006cdf0e10cSrcweir void Matrix3::scale( double sx, double sy )
1007cdf0e10cSrcweir {
1008cdf0e10cSrcweir     double fn[6];
1009cdf0e10cSrcweir     fn[0] = sx*f[0];
1010cdf0e10cSrcweir     fn[1] = sy*f[1];
1011cdf0e10cSrcweir     fn[2] = sx*f[2];
1012cdf0e10cSrcweir     fn[3] = sy*f[3];
1013cdf0e10cSrcweir     fn[4] = sx*f[4];
1014cdf0e10cSrcweir     fn[5] = sy*f[5];
1015cdf0e10cSrcweir     set( fn );
1016cdf0e10cSrcweir }
1017cdf0e10cSrcweir 
1018cdf0e10cSrcweir void Matrix3::rotate( double angle )
1019cdf0e10cSrcweir {
1020cdf0e10cSrcweir     double fn[6];
1021cdf0e10cSrcweir     double fSin = sin(angle);
1022cdf0e10cSrcweir     double fCos = cos(angle);
1023cdf0e10cSrcweir     fn[0] = f[0]*fCos - f[1]*fSin;
1024cdf0e10cSrcweir     fn[1] = f[0]*fSin + f[1]*fCos;
1025cdf0e10cSrcweir     fn[2] = f[2]*fCos - f[3]*fSin;
1026cdf0e10cSrcweir     fn[3] = f[2]*fSin + f[3]*fCos;
1027cdf0e10cSrcweir     fn[4] = f[4]*fCos - f[5]*fSin;
1028cdf0e10cSrcweir     fn[5] = f[4]*fSin + f[5]*fCos;
1029cdf0e10cSrcweir     set( fn );
1030cdf0e10cSrcweir }
1031cdf0e10cSrcweir 
1032cdf0e10cSrcweir void Matrix3::translate( double tx, double ty )
1033cdf0e10cSrcweir {
1034cdf0e10cSrcweir     f[4] += tx;
1035cdf0e10cSrcweir     f[5] += ty;
1036cdf0e10cSrcweir }
1037cdf0e10cSrcweir 
1038cdf0e10cSrcweir bool Matrix3::invert()
1039cdf0e10cSrcweir {
1040cdf0e10cSrcweir 	// short circuit trivial cases
1041cdf0e10cSrcweir 	if( f[1]==f[2] && f[1]==0.0 && f[0]==f[3] && f[0]==1.0 )
1042cdf0e10cSrcweir 	{
1043cdf0e10cSrcweir 		f[4] = -f[4];
1044cdf0e10cSrcweir 		f[5] = -f[5];
1045cdf0e10cSrcweir 		return true;
1046cdf0e10cSrcweir 	}
1047cdf0e10cSrcweir 
1048cdf0e10cSrcweir 	// check determinant
1049cdf0e10cSrcweir 	const double fDet = f[0]*f[3]-f[1]*f[2];
1050cdf0e10cSrcweir 	if( fDet == 0.0 )
1051cdf0e10cSrcweir 		return false;
1052cdf0e10cSrcweir 
1053cdf0e10cSrcweir 	// invert the matrix
1054cdf0e10cSrcweir 	double fn[6];
1055cdf0e10cSrcweir 	fn[0] = +f[3] / fDet;
1056cdf0e10cSrcweir 	fn[1] = -f[1] / fDet;
1057cdf0e10cSrcweir 	fn[2] = -f[2] / fDet;
1058cdf0e10cSrcweir 	fn[3] = +f[0] / fDet;
1059cdf0e10cSrcweir 
1060cdf0e10cSrcweir 	// apply inversion to translation
1061cdf0e10cSrcweir 	fn[4] = -(f[4]*fn[0] + f[5]*fn[2]);
1062cdf0e10cSrcweir 	fn[5] = -(f[4]*fn[1] + f[5]*fn[3]);
1063cdf0e10cSrcweir 
1064cdf0e10cSrcweir 	set( fn );
1065cdf0e10cSrcweir 	return true;
1066cdf0e10cSrcweir }
1067cdf0e10cSrcweir 
1068cdf0e10cSrcweir void Matrix3::append( PDFWriterImpl::PDFPage& rPage, OStringBuffer& rBuffer, Point* pBack )
1069cdf0e10cSrcweir {
1070cdf0e10cSrcweir     appendDouble( f[0], rBuffer );
1071cdf0e10cSrcweir     rBuffer.append( ' ' );
1072cdf0e10cSrcweir     appendDouble( f[1], rBuffer );
1073cdf0e10cSrcweir     rBuffer.append( ' ' );
1074cdf0e10cSrcweir     appendDouble( f[2], rBuffer );
1075cdf0e10cSrcweir     rBuffer.append( ' ' );
1076cdf0e10cSrcweir     appendDouble( f[3], rBuffer );
1077cdf0e10cSrcweir     rBuffer.append( ' ' );
1078cdf0e10cSrcweir     rPage.appendPoint( Point( (long)f[4], (long)f[5] ), rBuffer, false, pBack );
1079cdf0e10cSrcweir }
1080cdf0e10cSrcweir 
1081cdf0e10cSrcweir static void appendResourceMap( OStringBuffer& rBuf, const char* pPrefix, const PDFWriterImpl::ResourceMap& rList )
1082cdf0e10cSrcweir {
1083cdf0e10cSrcweir     if( rList.empty() )
1084cdf0e10cSrcweir         return;
1085cdf0e10cSrcweir     rBuf.append( '/' );
1086cdf0e10cSrcweir     rBuf.append( pPrefix );
1087cdf0e10cSrcweir     rBuf.append( "<<" );
1088cdf0e10cSrcweir     int ni = 0;
1089cdf0e10cSrcweir     for( PDFWriterImpl::ResourceMap::const_iterator it = rList.begin(); it != rList.end(); ++it )
1090cdf0e10cSrcweir     {
1091cdf0e10cSrcweir         if( it->first.getLength() && it->second > 0 )
1092cdf0e10cSrcweir         {
1093cdf0e10cSrcweir             rBuf.append( '/' );
1094cdf0e10cSrcweir             rBuf.append( it->first );
1095cdf0e10cSrcweir             rBuf.append( ' ' );
1096cdf0e10cSrcweir             rBuf.append( it->second );
1097cdf0e10cSrcweir             rBuf.append( " 0 R" );
1098cdf0e10cSrcweir             if( ((++ni) & 7) == 0 )
1099cdf0e10cSrcweir                 rBuf.append( '\n' );
1100cdf0e10cSrcweir         }
1101cdf0e10cSrcweir     }
1102cdf0e10cSrcweir     rBuf.append( ">>\n" );
1103cdf0e10cSrcweir }
1104cdf0e10cSrcweir 
1105cdf0e10cSrcweir void PDFWriterImpl::ResourceDict::append( OStringBuffer& rBuf, sal_Int32 nFontDictObject )
1106cdf0e10cSrcweir {
1107cdf0e10cSrcweir     rBuf.append( "<</Font " );
1108cdf0e10cSrcweir     rBuf.append( nFontDictObject );
1109cdf0e10cSrcweir     rBuf.append( " 0 R\n" );
1110cdf0e10cSrcweir     appendResourceMap( rBuf, "XObject", m_aXObjects );
1111cdf0e10cSrcweir     appendResourceMap( rBuf, "ExtGState", m_aExtGStates );
1112cdf0e10cSrcweir     appendResourceMap( rBuf, "Shading", m_aShadings );
1113cdf0e10cSrcweir     appendResourceMap( rBuf, "Pattern", m_aPatterns );
1114cdf0e10cSrcweir     rBuf.append( "/ProcSet[/PDF/Text" );
1115cdf0e10cSrcweir     if( !m_aXObjects.empty() )
1116cdf0e10cSrcweir         rBuf.append( "/ImageC/ImageI/ImageB" );
1117cdf0e10cSrcweir     rBuf.append( "]\n>>\n" );
1118cdf0e10cSrcweir };
1119cdf0e10cSrcweir 
1120cdf0e10cSrcweir PDFWriterImpl::PDFPage::PDFPage( PDFWriterImpl* pWriter, sal_Int32 nPageWidth, sal_Int32 nPageHeight, PDFWriter::Orientation eOrientation )
1121cdf0e10cSrcweir         :
1122cdf0e10cSrcweir         m_pWriter( pWriter ),
1123cdf0e10cSrcweir         m_nPageWidth( nPageWidth ),
1124cdf0e10cSrcweir         m_nPageHeight( nPageHeight ),
1125cdf0e10cSrcweir         m_eOrientation( eOrientation ),
1126cdf0e10cSrcweir         m_nPageObject( 0 ),  // invalid object number
1127cdf0e10cSrcweir         m_nPageIndex( -1 ), // invalid index
1128cdf0e10cSrcweir         m_nStreamLengthObject( 0 ),
1129cdf0e10cSrcweir         m_nBeginStreamPos( 0 ),
1130cdf0e10cSrcweir         m_eTransition( PDFWriter::Regular ),
1131cdf0e10cSrcweir         m_nTransTime( 0 ),
1132cdf0e10cSrcweir         m_nDuration( 0 ),
1133cdf0e10cSrcweir         m_bHasWidgets( false )
1134cdf0e10cSrcweir {
1135cdf0e10cSrcweir     // object ref must be only ever updated in emit()
1136cdf0e10cSrcweir     m_nPageObject = m_pWriter->createObject();
1137cdf0e10cSrcweir }
1138cdf0e10cSrcweir 
1139cdf0e10cSrcweir PDFWriterImpl::PDFPage::~PDFPage()
1140cdf0e10cSrcweir {
1141cdf0e10cSrcweir }
1142cdf0e10cSrcweir 
1143cdf0e10cSrcweir void PDFWriterImpl::PDFPage::beginStream()
1144cdf0e10cSrcweir {
1145cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
1146cdf0e10cSrcweir     {
1147cdf0e10cSrcweir         OStringBuffer aLine( "PDFWriterImpl::PDFPage::beginStream, +" );
1148cdf0e10cSrcweir          m_pWriter->emitComment( aLine.getStr() );
1149cdf0e10cSrcweir     }
1150cdf0e10cSrcweir #endif
1151cdf0e10cSrcweir     m_aStreamObjects.push_back(m_pWriter->createObject());
1152cdf0e10cSrcweir     if( ! m_pWriter->updateObject( m_aStreamObjects.back() ) )
1153cdf0e10cSrcweir         return;
1154cdf0e10cSrcweir 
1155cdf0e10cSrcweir     m_nStreamLengthObject = m_pWriter->createObject();
1156cdf0e10cSrcweir     // write content stream header
1157cdf0e10cSrcweir     OStringBuffer aLine;
1158cdf0e10cSrcweir     aLine.append( m_aStreamObjects.back() );
1159cdf0e10cSrcweir     aLine.append( " 0 obj\n<</Length " );
1160cdf0e10cSrcweir     aLine.append( m_nStreamLengthObject );
1161cdf0e10cSrcweir     aLine.append( " 0 R" );
1162cdf0e10cSrcweir #if defined ( COMPRESS_PAGES ) && !defined ( DEBUG_DISABLE_PDFCOMPRESSION )
1163cdf0e10cSrcweir     aLine.append( "/Filter/FlateDecode" );
1164cdf0e10cSrcweir #endif
1165cdf0e10cSrcweir     aLine.append( ">>\nstream\n" );
1166cdf0e10cSrcweir     if( ! m_pWriter->writeBuffer( aLine.getStr(), aLine.getLength() ) )
1167cdf0e10cSrcweir         return;
1168cdf0e10cSrcweir     if( osl_File_E_None != osl_getFilePos( m_pWriter->m_aFile, &m_nBeginStreamPos ) )
1169cdf0e10cSrcweir     {
1170cdf0e10cSrcweir         osl_closeFile( m_pWriter->m_aFile );
1171cdf0e10cSrcweir         m_pWriter->m_bOpen = false;
1172cdf0e10cSrcweir     }
1173cdf0e10cSrcweir #if defined ( COMPRESS_PAGES ) && !defined ( DEBUG_DISABLE_PDFCOMPRESSION )
1174cdf0e10cSrcweir     m_pWriter->beginCompression();
1175cdf0e10cSrcweir #endif
1176cdf0e10cSrcweir     m_pWriter->checkAndEnableStreamEncryption( m_aStreamObjects.back() );
1177cdf0e10cSrcweir }
1178cdf0e10cSrcweir 
1179cdf0e10cSrcweir void PDFWriterImpl::PDFPage::endStream()
1180cdf0e10cSrcweir {
1181cdf0e10cSrcweir #if defined ( COMPRESS_PAGES ) && !defined ( DEBUG_DISABLE_PDFCOMPRESSION )
1182cdf0e10cSrcweir     m_pWriter->endCompression();
1183cdf0e10cSrcweir #endif
1184cdf0e10cSrcweir     sal_uInt64 nEndStreamPos;
1185cdf0e10cSrcweir     if( osl_File_E_None != osl_getFilePos( m_pWriter->m_aFile, &nEndStreamPos ) )
1186cdf0e10cSrcweir     {
1187cdf0e10cSrcweir         osl_closeFile( m_pWriter->m_aFile );
1188cdf0e10cSrcweir         m_pWriter->m_bOpen = false;
1189cdf0e10cSrcweir         return;
1190cdf0e10cSrcweir     }
1191cdf0e10cSrcweir     m_pWriter->disableStreamEncryption();
1192cdf0e10cSrcweir     if( ! m_pWriter->writeBuffer( "\nendstream\nendobj\n\n", 19 ) )
1193cdf0e10cSrcweir         return;
1194cdf0e10cSrcweir     // emit stream length object
1195cdf0e10cSrcweir     if( ! m_pWriter->updateObject( m_nStreamLengthObject ) )
1196cdf0e10cSrcweir         return;
1197cdf0e10cSrcweir     OStringBuffer aLine;
1198cdf0e10cSrcweir     aLine.append( m_nStreamLengthObject );
1199cdf0e10cSrcweir     aLine.append( " 0 obj\n" );
1200cdf0e10cSrcweir     aLine.append( (sal_Int64)(nEndStreamPos-m_nBeginStreamPos) );
1201cdf0e10cSrcweir     aLine.append( "\nendobj\n\n" );
1202cdf0e10cSrcweir     m_pWriter->writeBuffer( aLine.getStr(), aLine.getLength() );
1203cdf0e10cSrcweir }
1204cdf0e10cSrcweir 
1205cdf0e10cSrcweir bool PDFWriterImpl::PDFPage::emit(sal_Int32 nParentObject )
1206cdf0e10cSrcweir {
1207cdf0e10cSrcweir     // emit page object
1208cdf0e10cSrcweir     if( ! m_pWriter->updateObject( m_nPageObject ) )
1209cdf0e10cSrcweir         return false;
1210cdf0e10cSrcweir     OStringBuffer aLine;
1211cdf0e10cSrcweir 
1212cdf0e10cSrcweir     aLine.append( m_nPageObject );
1213cdf0e10cSrcweir     aLine.append( " 0 obj\n"
1214cdf0e10cSrcweir                   "<</Type/Page/Parent " );
1215cdf0e10cSrcweir     aLine.append( nParentObject );
1216cdf0e10cSrcweir     aLine.append( " 0 R" );
1217cdf0e10cSrcweir     aLine.append( "/Resources " );
1218cdf0e10cSrcweir     aLine.append( m_pWriter->getResourceDictObj() );
1219cdf0e10cSrcweir     aLine.append( " 0 R" );
1220cdf0e10cSrcweir     if( m_nPageWidth && m_nPageHeight )
1221cdf0e10cSrcweir     {
1222cdf0e10cSrcweir         aLine.append( "/MediaBox[0 0 " );
1223cdf0e10cSrcweir         aLine.append( m_nPageWidth );
1224cdf0e10cSrcweir         aLine.append( ' ' );
1225cdf0e10cSrcweir         aLine.append( m_nPageHeight );
1226cdf0e10cSrcweir         aLine.append( "]" );
1227cdf0e10cSrcweir     }
1228cdf0e10cSrcweir     switch( m_eOrientation )
1229cdf0e10cSrcweir     {
1230cdf0e10cSrcweir         case PDFWriter::Landscape: aLine.append( "/Rotate 90\n" );break;
1231cdf0e10cSrcweir         case PDFWriter::Seascape:  aLine.append( "/Rotate -90\n" );break;
1232cdf0e10cSrcweir         case PDFWriter::Portrait:  aLine.append( "/Rotate 0\n" );break;
1233cdf0e10cSrcweir 
1234cdf0e10cSrcweir         case PDFWriter::Inherit:
1235cdf0e10cSrcweir         default:
1236cdf0e10cSrcweir             break;
1237cdf0e10cSrcweir     }
1238cdf0e10cSrcweir     int nAnnots = m_aAnnotations.size();
1239cdf0e10cSrcweir     if( nAnnots > 0 )
1240cdf0e10cSrcweir     {
1241cdf0e10cSrcweir         aLine.append( "/Annots[\n" );
1242cdf0e10cSrcweir         for( int i = 0; i < nAnnots; i++ )
1243cdf0e10cSrcweir         {
1244cdf0e10cSrcweir             aLine.append( m_aAnnotations[i] );
1245cdf0e10cSrcweir             aLine.append( " 0 R" );
1246cdf0e10cSrcweir             aLine.append( ((i+1)%15) ? " " : "\n" );
1247cdf0e10cSrcweir         }
1248cdf0e10cSrcweir         aLine.append( "]\n" );
1249cdf0e10cSrcweir     }
1250cdf0e10cSrcweir     #if 0
1251cdf0e10cSrcweir     // FIXME: implement tab order as Structure Tree
1252cdf0e10cSrcweir     if( m_bHasWidgets && m_pWriter->getVersion() >= PDFWriter::PDF_1_5 )
1253cdf0e10cSrcweir         aLine.append( "   /Tabs /S\n" );
1254cdf0e10cSrcweir     #endif
1255cdf0e10cSrcweir     if( m_aMCIDParents.size() > 0 )
1256cdf0e10cSrcweir     {
1257cdf0e10cSrcweir         OStringBuffer aStructParents( 1024 );
1258cdf0e10cSrcweir         aStructParents.append( "[ " );
1259cdf0e10cSrcweir         int nParents = m_aMCIDParents.size();
1260cdf0e10cSrcweir         for( int i = 0; i < nParents; i++ )
1261cdf0e10cSrcweir         {
1262cdf0e10cSrcweir             aStructParents.append( m_aMCIDParents[i] );
1263cdf0e10cSrcweir             aStructParents.append( " 0 R" );
1264cdf0e10cSrcweir             aStructParents.append( ((i%10) == 9) ? "\n" : " " );
1265cdf0e10cSrcweir         }
1266cdf0e10cSrcweir         aStructParents.append( "]" );
1267cdf0e10cSrcweir         m_pWriter->m_aStructParentTree.push_back( aStructParents.makeStringAndClear() );
1268cdf0e10cSrcweir 
1269cdf0e10cSrcweir         aLine.append( "/StructParents " );
1270cdf0e10cSrcweir         aLine.append( sal_Int32(m_pWriter->m_aStructParentTree.size()-1) );
1271cdf0e10cSrcweir         aLine.append( "\n" );
1272cdf0e10cSrcweir     }
1273cdf0e10cSrcweir     if( m_nDuration > 0 )
1274cdf0e10cSrcweir     {
1275cdf0e10cSrcweir         aLine.append( "/Dur " );
1276cdf0e10cSrcweir         aLine.append( (sal_Int32)m_nDuration );
1277cdf0e10cSrcweir         aLine.append( "\n" );
1278cdf0e10cSrcweir     }
1279cdf0e10cSrcweir     if( m_eTransition != PDFWriter::Regular && m_nTransTime > 0 )
1280cdf0e10cSrcweir     {
1281cdf0e10cSrcweir         // transition duration
1282cdf0e10cSrcweir         aLine.append( "/Trans<</D " );
1283cdf0e10cSrcweir         appendDouble( (double)m_nTransTime/1000.0, aLine, 3 );
1284cdf0e10cSrcweir         aLine.append( "\n" );
1285cdf0e10cSrcweir         const char *pStyle = NULL, *pDm = NULL, *pM = NULL, *pDi = NULL;
1286cdf0e10cSrcweir         switch( m_eTransition )
1287cdf0e10cSrcweir         {
1288cdf0e10cSrcweir             case PDFWriter::SplitHorizontalInward:
1289cdf0e10cSrcweir                 pStyle = "Split"; pDm = "H"; pM = "I"; break;
1290cdf0e10cSrcweir             case PDFWriter::SplitHorizontalOutward:
1291cdf0e10cSrcweir                 pStyle = "Split"; pDm = "H"; pM = "O"; break;
1292cdf0e10cSrcweir             case PDFWriter::SplitVerticalInward:
1293cdf0e10cSrcweir                 pStyle = "Split"; pDm = "V"; pM = "I"; break;
1294cdf0e10cSrcweir             case PDFWriter::SplitVerticalOutward:
1295cdf0e10cSrcweir                 pStyle = "Split"; pDm = "V"; pM = "O"; break;
1296cdf0e10cSrcweir             case PDFWriter::BlindsHorizontal:
1297cdf0e10cSrcweir                 pStyle = "Blinds"; pDm = "H"; break;
1298cdf0e10cSrcweir             case PDFWriter::BlindsVertical:
1299cdf0e10cSrcweir                 pStyle = "Blinds"; pDm = "V"; break;
1300cdf0e10cSrcweir             case PDFWriter::BoxInward:
1301cdf0e10cSrcweir                 pStyle = "Box"; pM = "I"; break;
1302cdf0e10cSrcweir             case PDFWriter::BoxOutward:
1303cdf0e10cSrcweir                 pStyle = "Box"; pM = "O"; break;
1304cdf0e10cSrcweir             case PDFWriter::WipeLeftToRight:
1305cdf0e10cSrcweir                 pStyle = "Wipe"; pDi = "0"; break;
1306cdf0e10cSrcweir             case PDFWriter::WipeBottomToTop:
1307cdf0e10cSrcweir                 pStyle = "Wipe"; pDi = "90"; break;
1308cdf0e10cSrcweir             case PDFWriter::WipeRightToLeft:
1309cdf0e10cSrcweir                 pStyle = "Wipe"; pDi = "180"; break;
1310cdf0e10cSrcweir             case PDFWriter::WipeTopToBottom:
1311cdf0e10cSrcweir                 pStyle = "Wipe"; pDi = "270"; break;
1312cdf0e10cSrcweir             case PDFWriter::Dissolve:
1313cdf0e10cSrcweir                 pStyle = "Dissolve"; break;
1314cdf0e10cSrcweir             case PDFWriter::GlitterLeftToRight:
1315cdf0e10cSrcweir                 pStyle = "Glitter"; pDi = "0"; break;
1316cdf0e10cSrcweir             case PDFWriter::GlitterTopToBottom:
1317cdf0e10cSrcweir                 pStyle = "Glitter"; pDi = "270"; break;
1318cdf0e10cSrcweir             case PDFWriter::GlitterTopLeftToBottomRight:
1319cdf0e10cSrcweir                 pStyle = "Glitter"; pDi = "315"; break;
1320cdf0e10cSrcweir             case PDFWriter::Regular:
1321cdf0e10cSrcweir                 break;
1322cdf0e10cSrcweir         }
1323cdf0e10cSrcweir         // transition style
1324cdf0e10cSrcweir         if( pStyle )
1325cdf0e10cSrcweir         {
1326cdf0e10cSrcweir             aLine.append( "/S/" );
1327cdf0e10cSrcweir             aLine.append( pStyle );
1328cdf0e10cSrcweir             aLine.append( "\n" );
1329cdf0e10cSrcweir         }
1330cdf0e10cSrcweir         if( pDm )
1331cdf0e10cSrcweir         {
1332cdf0e10cSrcweir             aLine.append( "/Dm/" );
1333cdf0e10cSrcweir             aLine.append( pDm );
1334cdf0e10cSrcweir             aLine.append( "\n" );
1335cdf0e10cSrcweir         }
1336cdf0e10cSrcweir         if( pM )
1337cdf0e10cSrcweir         {
1338cdf0e10cSrcweir             aLine.append( "/M/" );
1339cdf0e10cSrcweir             aLine.append( pM );
1340cdf0e10cSrcweir             aLine.append( "\n" );
1341cdf0e10cSrcweir         }
1342cdf0e10cSrcweir         if( pDi  )
1343cdf0e10cSrcweir         {
1344cdf0e10cSrcweir             aLine.append( "/Di " );
1345cdf0e10cSrcweir             aLine.append( pDi );
1346cdf0e10cSrcweir             aLine.append( "\n" );
1347cdf0e10cSrcweir         }
1348cdf0e10cSrcweir         aLine.append( ">>\n" );
1349cdf0e10cSrcweir     }
1350cdf0e10cSrcweir     if( m_pWriter->getVersion() > PDFWriter::PDF_1_3 && ! m_pWriter->m_bIsPDF_A1 )
1351cdf0e10cSrcweir     {
1352cdf0e10cSrcweir         aLine.append( "/Group<</S/Transparency/CS/DeviceRGB/I true>>" );
1353cdf0e10cSrcweir     }
1354cdf0e10cSrcweir     aLine.append( "/Contents" );
1355cdf0e10cSrcweir     unsigned int nStreamObjects = m_aStreamObjects.size();
1356cdf0e10cSrcweir     if( nStreamObjects > 1 )
1357cdf0e10cSrcweir         aLine.append( '[' );
1358cdf0e10cSrcweir     for( unsigned int i = 0; i < m_aStreamObjects.size(); i++ )
1359cdf0e10cSrcweir     {
1360cdf0e10cSrcweir         aLine.append( ' ' );
1361cdf0e10cSrcweir         aLine.append( m_aStreamObjects[i] );
1362cdf0e10cSrcweir         aLine.append( " 0 R" );
1363cdf0e10cSrcweir     }
1364cdf0e10cSrcweir     if( nStreamObjects > 1 )
1365cdf0e10cSrcweir         aLine.append( ']' );
1366cdf0e10cSrcweir     aLine.append( ">>\nendobj\n\n" );
1367cdf0e10cSrcweir     return m_pWriter->writeBuffer( aLine.getStr(), aLine.getLength() );
1368cdf0e10cSrcweir }
1369cdf0e10cSrcweir 
1370cdf0e10cSrcweir namespace vcl
1371cdf0e10cSrcweir {
1372cdf0e10cSrcweir template < class GEOMETRY >
1373cdf0e10cSrcweir GEOMETRY lcl_convert( const MapMode& _rSource, const MapMode& _rDest, OutputDevice* _pPixelConversion, const GEOMETRY& _rObject )
1374cdf0e10cSrcweir {
1375cdf0e10cSrcweir     GEOMETRY aPoint;
1376cdf0e10cSrcweir     if ( MAP_PIXEL == _rSource.GetMapUnit() )
1377cdf0e10cSrcweir     {
1378cdf0e10cSrcweir         aPoint = _pPixelConversion->PixelToLogic( _rObject, _rDest );
1379cdf0e10cSrcweir     }
1380cdf0e10cSrcweir     else
1381cdf0e10cSrcweir     {
1382cdf0e10cSrcweir         aPoint = OutputDevice::LogicToLogic( _rObject, _rSource, _rDest );
1383cdf0e10cSrcweir     }
1384cdf0e10cSrcweir     return aPoint;
1385cdf0e10cSrcweir }
1386cdf0e10cSrcweir }
1387cdf0e10cSrcweir 
1388cdf0e10cSrcweir void PDFWriterImpl::PDFPage::appendPoint( const Point& rPoint, OStringBuffer& rBuffer, bool bNeg, Point* pOutPoint ) const
1389cdf0e10cSrcweir {
1390cdf0e10cSrcweir     if( pOutPoint )
1391cdf0e10cSrcweir     {
1392cdf0e10cSrcweir         Point aPoint( lcl_convert( m_pWriter->m_aGraphicsStack.front().m_aMapMode,
1393cdf0e10cSrcweir                                    m_pWriter->m_aMapMode,
1394cdf0e10cSrcweir                                    m_pWriter->getReferenceDevice(),
1395cdf0e10cSrcweir                                    rPoint ) );
1396cdf0e10cSrcweir         *pOutPoint = aPoint;
1397cdf0e10cSrcweir     }
1398cdf0e10cSrcweir 
1399cdf0e10cSrcweir     Point aPoint( lcl_convert( m_pWriter->m_aGraphicsStack.front().m_aMapMode,
1400cdf0e10cSrcweir                                m_pWriter->m_aMapMode,
1401cdf0e10cSrcweir                                m_pWriter->getReferenceDevice(),
1402cdf0e10cSrcweir                                rPoint ) );
1403cdf0e10cSrcweir 
1404cdf0e10cSrcweir     sal_Int32 nValue	= aPoint.X();
1405cdf0e10cSrcweir     if( bNeg )
1406cdf0e10cSrcweir         nValue = -nValue;
1407cdf0e10cSrcweir 
1408cdf0e10cSrcweir     appendFixedInt( nValue, rBuffer );
1409cdf0e10cSrcweir 
1410cdf0e10cSrcweir     rBuffer.append( ' ' );
1411cdf0e10cSrcweir 
1412cdf0e10cSrcweir     nValue		= pointToPixel(getHeight()) - aPoint.Y();
1413cdf0e10cSrcweir     if( bNeg )
1414cdf0e10cSrcweir         nValue = -nValue;
1415cdf0e10cSrcweir 
1416cdf0e10cSrcweir     appendFixedInt( nValue, rBuffer );
1417cdf0e10cSrcweir }
1418cdf0e10cSrcweir 
1419cdf0e10cSrcweir void PDFWriterImpl::PDFPage::appendPixelPoint( const basegfx::B2DPoint& rPoint, OStringBuffer& rBuffer ) const
1420cdf0e10cSrcweir {
1421cdf0e10cSrcweir     double fValue	= pixelToPoint(rPoint.getX());
1422cdf0e10cSrcweir 
1423cdf0e10cSrcweir     appendDouble( fValue, rBuffer, nLog10Divisor );
1424cdf0e10cSrcweir 
1425cdf0e10cSrcweir     rBuffer.append( ' ' );
1426cdf0e10cSrcweir 
1427cdf0e10cSrcweir     fValue		= double(getHeight()) - pixelToPoint(rPoint.getY());
1428cdf0e10cSrcweir 
1429cdf0e10cSrcweir     appendDouble( fValue, rBuffer, nLog10Divisor );
1430cdf0e10cSrcweir }
1431cdf0e10cSrcweir 
1432cdf0e10cSrcweir void PDFWriterImpl::PDFPage::appendRect( const Rectangle& rRect, OStringBuffer& rBuffer ) const
1433cdf0e10cSrcweir {
1434cdf0e10cSrcweir     appendPoint( rRect.BottomLeft() + Point( 0, 1 ), rBuffer );
1435cdf0e10cSrcweir     rBuffer.append( ' ' );
1436cdf0e10cSrcweir     appendMappedLength( (sal_Int32)rRect.GetWidth(), rBuffer, false );
1437cdf0e10cSrcweir     rBuffer.append( ' ' );
1438cdf0e10cSrcweir     appendMappedLength( (sal_Int32)rRect.GetHeight(), rBuffer, true );
1439cdf0e10cSrcweir     rBuffer.append( " re" );
1440cdf0e10cSrcweir }
1441cdf0e10cSrcweir 
1442cdf0e10cSrcweir void PDFWriterImpl::PDFPage::convertRect( Rectangle& rRect ) const
1443cdf0e10cSrcweir {
1444cdf0e10cSrcweir     Point aLL = lcl_convert( m_pWriter->m_aGraphicsStack.front().m_aMapMode,
1445cdf0e10cSrcweir                              m_pWriter->m_aMapMode,
1446cdf0e10cSrcweir                              m_pWriter->getReferenceDevice(),
1447cdf0e10cSrcweir                              rRect.BottomLeft() + Point( 0, 1 )
1448cdf0e10cSrcweir                              );
1449cdf0e10cSrcweir     Size aSize = lcl_convert( m_pWriter->m_aGraphicsStack.front().m_aMapMode,
1450cdf0e10cSrcweir                               m_pWriter->m_aMapMode,
1451cdf0e10cSrcweir                               m_pWriter->getReferenceDevice(),
1452cdf0e10cSrcweir                               rRect.GetSize() );
1453cdf0e10cSrcweir     rRect.Left()	= aLL.X();
1454cdf0e10cSrcweir     rRect.Right()	= aLL.X() + aSize.Width();
1455cdf0e10cSrcweir     rRect.Top()		= pointToPixel(getHeight()) - aLL.Y();
1456cdf0e10cSrcweir     rRect.Bottom()	= rRect.Top() + aSize.Height();
1457cdf0e10cSrcweir }
1458cdf0e10cSrcweir 
1459cdf0e10cSrcweir void PDFWriterImpl::PDFPage::appendPolygon( const Polygon& rPoly, OStringBuffer& rBuffer, bool bClose ) const
1460cdf0e10cSrcweir {
1461cdf0e10cSrcweir     sal_uInt16 nPoints = rPoly.GetSize();
1462cdf0e10cSrcweir     /*
1463cdf0e10cSrcweir      *  #108582# applications do weird things
1464cdf0e10cSrcweir      */
1465cdf0e10cSrcweir     sal_uInt32 nBufLen = rBuffer.getLength();
1466cdf0e10cSrcweir     if( nPoints > 0 )
1467cdf0e10cSrcweir     {
1468cdf0e10cSrcweir         const sal_uInt8* pFlagArray = rPoly.GetConstFlagAry();
1469cdf0e10cSrcweir         appendPoint( rPoly[0], rBuffer );
1470cdf0e10cSrcweir         rBuffer.append( " m\n" );
1471cdf0e10cSrcweir         for( sal_uInt16 i = 1; i < nPoints; i++ )
1472cdf0e10cSrcweir         {
1473cdf0e10cSrcweir             if( pFlagArray && pFlagArray[i] == POLY_CONTROL && nPoints-i > 2 )
1474cdf0e10cSrcweir             {
1475cdf0e10cSrcweir                 // bezier
1476cdf0e10cSrcweir                 DBG_ASSERT( pFlagArray[i+1] == POLY_CONTROL && pFlagArray[i+2] != POLY_CONTROL, "unexpected sequence of control points" );
1477cdf0e10cSrcweir                 appendPoint( rPoly[i], rBuffer );
1478cdf0e10cSrcweir                 rBuffer.append( " " );
1479cdf0e10cSrcweir                 appendPoint( rPoly[i+1], rBuffer );
1480cdf0e10cSrcweir                 rBuffer.append( " " );
1481cdf0e10cSrcweir                 appendPoint( rPoly[i+2], rBuffer );
1482cdf0e10cSrcweir                 rBuffer.append( " c" );
1483cdf0e10cSrcweir                 i += 2; // add additionally consumed points
1484cdf0e10cSrcweir             }
1485cdf0e10cSrcweir             else
1486cdf0e10cSrcweir             {
1487cdf0e10cSrcweir                 // line
1488cdf0e10cSrcweir                 appendPoint( rPoly[i], rBuffer );
1489cdf0e10cSrcweir                 rBuffer.append( " l" );
1490cdf0e10cSrcweir             }
1491cdf0e10cSrcweir             if( (rBuffer.getLength() - nBufLen) > 65 )
1492cdf0e10cSrcweir             {
1493cdf0e10cSrcweir                 rBuffer.append( "\n" );
1494cdf0e10cSrcweir                 nBufLen = rBuffer.getLength();
1495cdf0e10cSrcweir             }
1496cdf0e10cSrcweir             else
1497cdf0e10cSrcweir                 rBuffer.append( " " );
1498cdf0e10cSrcweir         }
1499cdf0e10cSrcweir         if( bClose )
1500cdf0e10cSrcweir             rBuffer.append( "h\n" );
1501cdf0e10cSrcweir     }
1502cdf0e10cSrcweir }
1503cdf0e10cSrcweir 
1504cdf0e10cSrcweir void PDFWriterImpl::PDFPage::appendPolygon( const basegfx::B2DPolygon& rPoly, OStringBuffer& rBuffer, bool bClose ) const
1505cdf0e10cSrcweir {
1506cdf0e10cSrcweir     basegfx::B2DPolygon aPoly( lcl_convert( m_pWriter->m_aGraphicsStack.front().m_aMapMode,
1507cdf0e10cSrcweir                                             m_pWriter->m_aMapMode,
1508cdf0e10cSrcweir                                             m_pWriter->getReferenceDevice(),
1509cdf0e10cSrcweir                                             rPoly ) );
1510cdf0e10cSrcweir 
1511cdf0e10cSrcweir     if( basegfx::tools::isRectangle( aPoly ) )
1512cdf0e10cSrcweir     {
1513cdf0e10cSrcweir         basegfx::B2DRange aRange( aPoly.getB2DRange() );
1514cdf0e10cSrcweir         basegfx::B2DPoint aBL( aRange.getMinX(), aRange.getMaxY() );
1515cdf0e10cSrcweir         appendPixelPoint( aBL, rBuffer );
1516cdf0e10cSrcweir         rBuffer.append( ' ' );
1517cdf0e10cSrcweir         appendMappedLength( aRange.getWidth(), rBuffer, false, NULL, nLog10Divisor );
1518cdf0e10cSrcweir         rBuffer.append( ' ' );
1519cdf0e10cSrcweir         appendMappedLength( aRange.getHeight(), rBuffer, true, NULL, nLog10Divisor );
1520cdf0e10cSrcweir         rBuffer.append( " re\n" );
1521cdf0e10cSrcweir         return;
1522cdf0e10cSrcweir     }
1523cdf0e10cSrcweir     sal_uInt32 nPoints = aPoly.count();
1524cdf0e10cSrcweir     if( nPoints > 0 )
1525cdf0e10cSrcweir     {
1526cdf0e10cSrcweir         sal_uInt32 nBufLen = rBuffer.getLength();
1527cdf0e10cSrcweir         basegfx::B2DPoint aLastPoint( aPoly.getB2DPoint( 0 ) );
1528cdf0e10cSrcweir         appendPixelPoint( aLastPoint, rBuffer );
1529cdf0e10cSrcweir         rBuffer.append( " m\n" );
1530cdf0e10cSrcweir         for( sal_uInt32 i = 1; i <= nPoints; i++ )
1531cdf0e10cSrcweir         {
1532cdf0e10cSrcweir             if( i != nPoints || aPoly.isClosed() )
1533cdf0e10cSrcweir             {
1534cdf0e10cSrcweir                 sal_uInt32 nCurPoint  = i % nPoints;
1535cdf0e10cSrcweir                 sal_uInt32 nLastPoint = i-1;
1536cdf0e10cSrcweir                 basegfx::B2DPoint aPoint( aPoly.getB2DPoint( nCurPoint ) );
1537cdf0e10cSrcweir                 if( aPoly.isNextControlPointUsed( nLastPoint ) &&
1538cdf0e10cSrcweir                     aPoly.isPrevControlPointUsed( nCurPoint ) )
1539cdf0e10cSrcweir                 {
1540cdf0e10cSrcweir                     appendPixelPoint( aPoly.getNextControlPoint( nLastPoint ), rBuffer );
1541cdf0e10cSrcweir                     rBuffer.append( ' ' );
1542cdf0e10cSrcweir                     appendPixelPoint( aPoly.getPrevControlPoint( nCurPoint ), rBuffer );
1543cdf0e10cSrcweir                     rBuffer.append( ' ' );
1544cdf0e10cSrcweir                     appendPixelPoint( aPoint, rBuffer );
1545cdf0e10cSrcweir                     rBuffer.append( " c" );
1546cdf0e10cSrcweir                 }
1547cdf0e10cSrcweir                 else if( aPoly.isNextControlPointUsed( nLastPoint ) )
1548cdf0e10cSrcweir                 {
1549cdf0e10cSrcweir                     appendPixelPoint( aPoly.getNextControlPoint( nLastPoint ), rBuffer );
1550cdf0e10cSrcweir                     rBuffer.append( ' ' );
1551cdf0e10cSrcweir                     appendPixelPoint( aPoint, rBuffer );
1552cdf0e10cSrcweir                     rBuffer.append( " y" );
1553cdf0e10cSrcweir                 }
1554cdf0e10cSrcweir                 else if( aPoly.isPrevControlPointUsed( nCurPoint ) )
1555cdf0e10cSrcweir                 {
1556cdf0e10cSrcweir                     appendPixelPoint( aPoly.getPrevControlPoint( nCurPoint ), rBuffer );
1557cdf0e10cSrcweir                     rBuffer.append( ' ' );
1558cdf0e10cSrcweir                     appendPixelPoint( aPoint, rBuffer );
1559cdf0e10cSrcweir                     rBuffer.append( " v" );
1560cdf0e10cSrcweir                 }
1561cdf0e10cSrcweir                 else
1562cdf0e10cSrcweir                 {
1563cdf0e10cSrcweir                     appendPixelPoint( aPoint, rBuffer );
1564cdf0e10cSrcweir                     rBuffer.append( " l" );
1565cdf0e10cSrcweir                 }
1566cdf0e10cSrcweir                 if( (rBuffer.getLength() - nBufLen) > 65 )
1567cdf0e10cSrcweir                 {
1568cdf0e10cSrcweir                     rBuffer.append( "\n" );
1569cdf0e10cSrcweir                     nBufLen = rBuffer.getLength();
1570cdf0e10cSrcweir                 }
1571cdf0e10cSrcweir                 else
1572cdf0e10cSrcweir                     rBuffer.append( " " );
1573cdf0e10cSrcweir             }
1574cdf0e10cSrcweir         }
1575cdf0e10cSrcweir         if( bClose )
1576cdf0e10cSrcweir             rBuffer.append( "h\n" );
1577cdf0e10cSrcweir     }
1578cdf0e10cSrcweir }
1579cdf0e10cSrcweir 
1580cdf0e10cSrcweir void PDFWriterImpl::PDFPage::appendPolyPolygon( const PolyPolygon& rPolyPoly, OStringBuffer& rBuffer, bool bClose ) const
1581cdf0e10cSrcweir {
1582cdf0e10cSrcweir     sal_uInt16 nPolygons = rPolyPoly.Count();
1583cdf0e10cSrcweir     for( sal_uInt16 n = 0; n < nPolygons; n++ )
1584cdf0e10cSrcweir         appendPolygon( rPolyPoly[n], rBuffer, bClose );
1585cdf0e10cSrcweir }
1586cdf0e10cSrcweir 
1587cdf0e10cSrcweir void PDFWriterImpl::PDFPage::appendPolyPolygon( const basegfx::B2DPolyPolygon& rPolyPoly, OStringBuffer& rBuffer, bool bClose ) const
1588cdf0e10cSrcweir {
1589cdf0e10cSrcweir     sal_uInt32 nPolygons = rPolyPoly.count();
1590cdf0e10cSrcweir     for( sal_uInt32 n = 0; n < nPolygons; n++ )
1591cdf0e10cSrcweir         appendPolygon( rPolyPoly.getB2DPolygon( n ), rBuffer, bClose );
1592cdf0e10cSrcweir }
1593cdf0e10cSrcweir 
1594cdf0e10cSrcweir void PDFWriterImpl::PDFPage::appendMappedLength( sal_Int32 nLength, OStringBuffer& rBuffer, bool bVertical, sal_Int32* pOutLength ) const
1595cdf0e10cSrcweir {
1596cdf0e10cSrcweir     sal_Int32 nValue = nLength;
1597cdf0e10cSrcweir     if ( nLength < 0 )
1598cdf0e10cSrcweir     {
1599cdf0e10cSrcweir         rBuffer.append( '-' );
1600cdf0e10cSrcweir         nValue = -nLength;
1601cdf0e10cSrcweir     }
1602cdf0e10cSrcweir     Size aSize( lcl_convert( m_pWriter->m_aGraphicsStack.front().m_aMapMode,
1603cdf0e10cSrcweir                              m_pWriter->m_aMapMode,
1604cdf0e10cSrcweir                              m_pWriter->getReferenceDevice(),
1605cdf0e10cSrcweir                              Size( nValue, nValue ) ) );
1606cdf0e10cSrcweir     nValue = bVertical ? aSize.Height() : aSize.Width();
1607cdf0e10cSrcweir     if( pOutLength )
1608cdf0e10cSrcweir         *pOutLength = ((nLength < 0 ) ? -nValue : nValue);
1609cdf0e10cSrcweir 
1610cdf0e10cSrcweir     appendFixedInt( nValue, rBuffer, 1 );
1611cdf0e10cSrcweir }
1612cdf0e10cSrcweir 
1613cdf0e10cSrcweir void PDFWriterImpl::PDFPage::appendMappedLength( double fLength, OStringBuffer& rBuffer, bool bVertical, sal_Int32* pOutLength, sal_Int32 nPrecision ) const
1614cdf0e10cSrcweir {
1615cdf0e10cSrcweir     Size aSize( lcl_convert( m_pWriter->m_aGraphicsStack.front().m_aMapMode,
1616cdf0e10cSrcweir                              m_pWriter->m_aMapMode,
1617cdf0e10cSrcweir                              m_pWriter->getReferenceDevice(),
1618cdf0e10cSrcweir                              Size( 1000, 1000 )	) );
1619cdf0e10cSrcweir     if( pOutLength )
1620cdf0e10cSrcweir         *pOutLength = (sal_Int32)(fLength*(double)(bVertical ? aSize.Height() : aSize.Width())/1000.0);
1621cdf0e10cSrcweir     fLength *= pixelToPoint((double)(bVertical ? aSize.Height() : aSize.Width()) / 1000.0);
1622cdf0e10cSrcweir     appendDouble( fLength, rBuffer, nPrecision );
1623cdf0e10cSrcweir }
1624cdf0e10cSrcweir 
1625cdf0e10cSrcweir bool PDFWriterImpl::PDFPage::appendLineInfo( const LineInfo& rInfo, OStringBuffer& rBuffer ) const
1626cdf0e10cSrcweir {
16275aaf853bSArmin Le Grand     if(LINE_DASH == rInfo.GetStyle() && rInfo.GetDashLen() != rInfo.GetDotLen())
16285aaf853bSArmin Le Grand     {
16295aaf853bSArmin Le Grand         // dashed and non-degraded case, check for implementation limits of dash array
16305aaf853bSArmin Le Grand         // in PDF reader apps (e.g. acroread)
16315aaf853bSArmin Le Grand         if(2 * (rInfo.GetDashCount() + rInfo.GetDotCount()) > 10)
16325aaf853bSArmin Le Grand         {
16335aaf853bSArmin Le Grand             return false;
16345aaf853bSArmin Le Grand         }
16355aaf853bSArmin Le Grand     }
16365aaf853bSArmin Le Grand 
16375aaf853bSArmin Le Grand     if(basegfx::B2DLINEJOIN_NONE != rInfo.GetLineJoin())
16385aaf853bSArmin Le Grand     {
16395aaf853bSArmin Le Grand         // LineJoin used, ExtLineInfo required
16405aaf853bSArmin Le Grand         return false;
16415aaf853bSArmin Le Grand     }
16425aaf853bSArmin Le Grand 
16435aaf853bSArmin Le Grand     if(com::sun::star::drawing::LineCap_BUTT != rInfo.GetLineCap())
16445aaf853bSArmin Le Grand     {
16455aaf853bSArmin Le Grand         // LineCap used, ExtLineInfo required
16465aaf853bSArmin Le Grand         return false;
16475aaf853bSArmin Le Grand     }
16485aaf853bSArmin Le Grand 
1649cdf0e10cSrcweir     if( rInfo.GetStyle() == LINE_DASH )
1650cdf0e10cSrcweir     {
1651cdf0e10cSrcweir         rBuffer.append( "[ " );
1652cdf0e10cSrcweir         if( rInfo.GetDashLen() == rInfo.GetDotLen() ) // degraded case
1653cdf0e10cSrcweir         {
1654cdf0e10cSrcweir             appendMappedLength( (sal_Int32)rInfo.GetDashLen(), rBuffer );
1655cdf0e10cSrcweir             rBuffer.append( ' ' );
1656cdf0e10cSrcweir             appendMappedLength( (sal_Int32)rInfo.GetDistance(), rBuffer );
1657cdf0e10cSrcweir             rBuffer.append( ' ' );
1658cdf0e10cSrcweir         }
1659cdf0e10cSrcweir         else
1660cdf0e10cSrcweir         {
1661cdf0e10cSrcweir             for( int n = 0; n < rInfo.GetDashCount(); n++ )
1662cdf0e10cSrcweir             {
1663cdf0e10cSrcweir                 appendMappedLength( (sal_Int32)rInfo.GetDashLen(), rBuffer );
1664cdf0e10cSrcweir                 rBuffer.append( ' ' );
1665cdf0e10cSrcweir                 appendMappedLength( (sal_Int32)rInfo.GetDistance(), rBuffer );
1666cdf0e10cSrcweir                 rBuffer.append( ' ' );
1667cdf0e10cSrcweir             }
1668cdf0e10cSrcweir             for( int m = 0; m < rInfo.GetDotCount(); m++ )
1669cdf0e10cSrcweir             {
1670cdf0e10cSrcweir                 appendMappedLength( (sal_Int32)rInfo.GetDotLen(), rBuffer );
1671cdf0e10cSrcweir                 rBuffer.append( ' ' );
1672cdf0e10cSrcweir                 appendMappedLength( (sal_Int32)rInfo.GetDistance(), rBuffer );
1673cdf0e10cSrcweir                 rBuffer.append( ' ' );
1674cdf0e10cSrcweir             }
1675cdf0e10cSrcweir         }
1676cdf0e10cSrcweir         rBuffer.append( "] 0 d\n" );
1677cdf0e10cSrcweir     }
16785aaf853bSArmin Le Grand 
1679cdf0e10cSrcweir     if( rInfo.GetWidth() > 1 )
1680cdf0e10cSrcweir     {
1681cdf0e10cSrcweir         appendMappedLength( (sal_Int32)rInfo.GetWidth(), rBuffer );
1682cdf0e10cSrcweir         rBuffer.append( " w\n" );
1683cdf0e10cSrcweir     }
1684cdf0e10cSrcweir     else if( rInfo.GetWidth() == 0 )
1685cdf0e10cSrcweir     {
1686cdf0e10cSrcweir         // "pixel" line
1687cdf0e10cSrcweir         appendDouble( 72.0/double(m_pWriter->getReferenceDevice()->ImplGetDPIX()), rBuffer );
1688cdf0e10cSrcweir         rBuffer.append( " w\n" );
1689cdf0e10cSrcweir     }
16905aaf853bSArmin Le Grand 
16915aaf853bSArmin Le Grand     return true;
1692cdf0e10cSrcweir }
1693cdf0e10cSrcweir 
1694cdf0e10cSrcweir void PDFWriterImpl::PDFPage::appendWaveLine( sal_Int32 nWidth, sal_Int32 nY, sal_Int32 nDelta, OStringBuffer& rBuffer ) const
1695cdf0e10cSrcweir {
1696cdf0e10cSrcweir     if( nWidth <= 0 )
1697cdf0e10cSrcweir         return;
1698cdf0e10cSrcweir     if( nDelta < 1 )
1699cdf0e10cSrcweir         nDelta = 1;
1700cdf0e10cSrcweir 
1701cdf0e10cSrcweir     rBuffer.append( "0 " );
1702cdf0e10cSrcweir     appendMappedLength( nY, rBuffer, true );
1703cdf0e10cSrcweir     rBuffer.append( " m\n" );
1704cdf0e10cSrcweir     for( sal_Int32 n = 0; n < nWidth; )
1705cdf0e10cSrcweir     {
1706cdf0e10cSrcweir         n += nDelta;
1707cdf0e10cSrcweir         appendMappedLength( n, rBuffer, false );
1708cdf0e10cSrcweir         rBuffer.append( ' ' );
1709cdf0e10cSrcweir         appendMappedLength( nDelta+nY, rBuffer, true );
1710cdf0e10cSrcweir         rBuffer.append( ' ' );
1711cdf0e10cSrcweir         n += nDelta;
1712cdf0e10cSrcweir         appendMappedLength( n, rBuffer, false );
1713cdf0e10cSrcweir         rBuffer.append( ' ' );
1714cdf0e10cSrcweir         appendMappedLength( nY, rBuffer, true );
1715cdf0e10cSrcweir         rBuffer.append( " v " );
1716cdf0e10cSrcweir         if( n < nWidth )
1717cdf0e10cSrcweir         {
1718cdf0e10cSrcweir             n += nDelta;
1719cdf0e10cSrcweir             appendMappedLength( n, rBuffer, false );
1720cdf0e10cSrcweir             rBuffer.append( ' ' );
1721cdf0e10cSrcweir             appendMappedLength( nY-nDelta, rBuffer, true );
1722cdf0e10cSrcweir             rBuffer.append( ' ' );
1723cdf0e10cSrcweir             n += nDelta;
1724cdf0e10cSrcweir             appendMappedLength( n, rBuffer, false );
1725cdf0e10cSrcweir             rBuffer.append( ' ' );
1726cdf0e10cSrcweir             appendMappedLength( nY, rBuffer, true );
1727cdf0e10cSrcweir             rBuffer.append( " v\n" );
1728cdf0e10cSrcweir         }
1729cdf0e10cSrcweir     }
1730cdf0e10cSrcweir     rBuffer.append( "S\n" );
1731cdf0e10cSrcweir }
1732cdf0e10cSrcweir 
1733cdf0e10cSrcweir /*
1734cdf0e10cSrcweir  *  class PDFWriterImpl
1735cdf0e10cSrcweir  */
1736cdf0e10cSrcweir 
1737cdf0e10cSrcweir  PDFWriterImpl::PDFWriterImpl( const PDFWriter::PDFWriterContext& rContext,
1738cdf0e10cSrcweir                                const com::sun::star::uno::Reference< com::sun::star::beans::XMaterialHolder >& xEnc,
1739cdf0e10cSrcweir                                PDFWriter& i_rOuterFace)
1740cdf0e10cSrcweir         :
1741cdf0e10cSrcweir         m_pReferenceDevice( NULL ),
1742cdf0e10cSrcweir         m_aMapMode( MAP_POINT, Point(), Fraction( 1L, pointToPixel(1) ), Fraction( 1L, pointToPixel(1) ) ),
1743cdf0e10cSrcweir         m_nCurrentStructElement( 0 ),
1744cdf0e10cSrcweir         m_bEmitStructure( true ),
1745cdf0e10cSrcweir         m_bNewMCID( false ),
1746cdf0e10cSrcweir         m_nCurrentControl( -1 ),
1747cdf0e10cSrcweir         m_bEmbedStandardFonts( false ),
1748cdf0e10cSrcweir         m_nNextFID( 1 ),
1749cdf0e10cSrcweir         m_nInheritedPageWidth( 595 ),  // default A4
1750cdf0e10cSrcweir         m_nInheritedPageHeight( 842 ), // default A4
1751cdf0e10cSrcweir         m_eInheritedOrientation( PDFWriter::Portrait ),
1752cdf0e10cSrcweir         m_nCurrentPage( -1 ),
1753cdf0e10cSrcweir         m_nResourceDict( -1 ),
1754cdf0e10cSrcweir         m_nFontDictObject( -1 ),
1755cdf0e10cSrcweir         m_pCodec( NULL ),
1756cdf0e10cSrcweir         m_aDocDigest( rtl_digest_createMD5() ),
1757cdf0e10cSrcweir 		m_aCipher( (rtlCipher)NULL ),
1758cdf0e10cSrcweir 		m_aDigest( NULL ),
1759cdf0e10cSrcweir 		m_bEncryptThisStream( false ),
1760cdf0e10cSrcweir 		m_pEncryptionBuffer( NULL ),
1761cdf0e10cSrcweir 		m_nEncryptionBufferSize( 0 ),
1762cdf0e10cSrcweir         m_bIsPDF_A1( false ),
1763cdf0e10cSrcweir         m_rOuterFace( i_rOuterFace )
1764cdf0e10cSrcweir {
1765cdf0e10cSrcweir #ifdef DO_TEST_PDF
1766cdf0e10cSrcweir     static bool bOnce = true;
1767cdf0e10cSrcweir     if( bOnce )
1768cdf0e10cSrcweir     {
1769cdf0e10cSrcweir         bOnce = false;
1770cdf0e10cSrcweir         doTestCode();
1771cdf0e10cSrcweir     }
1772cdf0e10cSrcweir #endif
1773cdf0e10cSrcweir     m_aContext = rContext;
1774cdf0e10cSrcweir     m_aStructure.push_back( PDFStructureElement() );
1775cdf0e10cSrcweir     m_aStructure[0].m_nOwnElement		= 0;
1776cdf0e10cSrcweir     m_aStructure[0].m_nParentElement	= 0;
1777cdf0e10cSrcweir 
1778cdf0e10cSrcweir     Font aFont;
1779cdf0e10cSrcweir     aFont.SetName( String( RTL_CONSTASCII_USTRINGPARAM( "Times" ) ) );
1780cdf0e10cSrcweir     aFont.SetSize( Size( 0, 12 ) );
1781cdf0e10cSrcweir 
1782cdf0e10cSrcweir     GraphicsState aState;
1783cdf0e10cSrcweir     aState.m_aMapMode		= m_aMapMode;
1784cdf0e10cSrcweir     aState.m_aFont			= aFont;
1785cdf0e10cSrcweir     m_aGraphicsStack.push_front( aState );
1786cdf0e10cSrcweir 
1787cdf0e10cSrcweir     oslFileError  aError = osl_openFile( m_aContext.URL.pData, &m_aFile, osl_File_OpenFlag_Write | osl_File_OpenFlag_Create );
1788cdf0e10cSrcweir     if( aError != osl_File_E_None )
1789cdf0e10cSrcweir     {
1790cdf0e10cSrcweir         if( aError == osl_File_E_EXIST )
1791cdf0e10cSrcweir         {
1792cdf0e10cSrcweir             aError = osl_openFile( m_aContext.URL.pData, &m_aFile, osl_File_OpenFlag_Write );
1793cdf0e10cSrcweir             if( aError == osl_File_E_None )
1794cdf0e10cSrcweir                 aError = osl_setFileSize( m_aFile, 0 );
1795cdf0e10cSrcweir         }
1796cdf0e10cSrcweir     }
1797cdf0e10cSrcweir     if( aError != osl_File_E_None )
1798cdf0e10cSrcweir         return;
1799cdf0e10cSrcweir 
1800cdf0e10cSrcweir     m_bOpen = true;
1801cdf0e10cSrcweir 
1802cdf0e10cSrcweir     // setup DocInfo
1803cdf0e10cSrcweir     setupDocInfo();
1804cdf0e10cSrcweir 
1805cdf0e10cSrcweir     /* prepare the cypher engine, can be done in CTOR, free in DTOR */
1806cdf0e10cSrcweir 	m_aCipher = rtl_cipher_createARCFOUR( rtl_Cipher_ModeStream );
1807cdf0e10cSrcweir 	m_aDigest = rtl_digest_createMD5();
1808cdf0e10cSrcweir 
1809cdf0e10cSrcweir 	/* the size of the Codec default maximum */
1810cdf0e10cSrcweir 	checkEncryptionBufferSize( 0x4000 );
1811cdf0e10cSrcweir 
1812cdf0e10cSrcweir 	if( xEnc.is() )
1813cdf0e10cSrcweir 	    prepareEncryption( xEnc );
1814cdf0e10cSrcweir 
1815cdf0e10cSrcweir 	if( m_aContext.Encryption.Encrypt() )
1816cdf0e10cSrcweir 	{
1817cdf0e10cSrcweir 	    // sanity check
1818cdf0e10cSrcweir 	    if( m_aContext.Encryption.OValue.size() != ENCRYPTED_PWD_SIZE ||
1819cdf0e10cSrcweir 	        m_aContext.Encryption.UValue.size() != ENCRYPTED_PWD_SIZE ||
1820cdf0e10cSrcweir 	        m_aContext.Encryption.EncryptionKey.size() != MAXIMUM_RC4_KEY_LENGTH
1821cdf0e10cSrcweir 	       )
1822cdf0e10cSrcweir 	    {
1823cdf0e10cSrcweir 	        // the field lengths are invalid ? This was not setup by initEncryption.
1824cdf0e10cSrcweir 	        // do not encrypt after all
1825cdf0e10cSrcweir 	        m_aContext.Encryption.OValue.clear();
1826cdf0e10cSrcweir 	        m_aContext.Encryption.UValue.clear();
1827cdf0e10cSrcweir 	        OSL_ENSURE( 0, "encryption data failed sanity check, encryption disabled" );
1828cdf0e10cSrcweir 	    }
1829cdf0e10cSrcweir 	    else // setup key lengths
1830cdf0e10cSrcweir 	        m_nAccessPermissions = computeAccessPermissions( m_aContext.Encryption, m_nKeyLength, m_nRC4KeyLength );
1831cdf0e10cSrcweir 	}
1832cdf0e10cSrcweir 
1833cdf0e10cSrcweir     // write header
1834cdf0e10cSrcweir     OStringBuffer aBuffer( 20 );
1835cdf0e10cSrcweir     aBuffer.append( "%PDF-" );
1836cdf0e10cSrcweir     switch( m_aContext.Version )
1837cdf0e10cSrcweir     {
1838cdf0e10cSrcweir         case PDFWriter::PDF_1_2: aBuffer.append( "1.2" );break;
1839cdf0e10cSrcweir         case PDFWriter::PDF_1_3: aBuffer.append( "1.3" );break;
1840cdf0e10cSrcweir         case PDFWriter::PDF_A_1:
1841cdf0e10cSrcweir         default:
1842cdf0e10cSrcweir         case PDFWriter::PDF_1_4: aBuffer.append( "1.4" );break;
1843cdf0e10cSrcweir         case PDFWriter::PDF_1_5: aBuffer.append( "1.5" );break;
1844cdf0e10cSrcweir     }
1845cdf0e10cSrcweir     // append something binary as comment (suggested in PDF Reference)
1846cdf0e10cSrcweir     aBuffer.append( "\n%äüöß\n" );
1847cdf0e10cSrcweir     if( !writeBuffer( aBuffer.getStr(), aBuffer.getLength() ) )
1848cdf0e10cSrcweir     {
1849cdf0e10cSrcweir         osl_closeFile( m_aFile );
1850cdf0e10cSrcweir         m_bOpen = false;
1851cdf0e10cSrcweir         return;
1852cdf0e10cSrcweir     }
1853cdf0e10cSrcweir 
1854cdf0e10cSrcweir     // insert outline root
1855cdf0e10cSrcweir     m_aOutline.push_back( PDFOutlineEntry() );
1856cdf0e10cSrcweir 
1857cdf0e10cSrcweir     m_bIsPDF_A1 = (m_aContext.Version == PDFWriter::PDF_A_1);
1858cdf0e10cSrcweir     if( m_bIsPDF_A1 )
1859cdf0e10cSrcweir         m_aContext.Version = PDFWriter::PDF_1_4; //meaning we need PDF 1.4, PDF/A flavour
1860cdf0e10cSrcweir 
1861cdf0e10cSrcweir     m_bEmbedStandardFonts = m_aContext.EmbedStandardFonts;
1862cdf0e10cSrcweir }
1863cdf0e10cSrcweir 
1864cdf0e10cSrcweir PDFWriterImpl::~PDFWriterImpl()
1865cdf0e10cSrcweir {
1866cdf0e10cSrcweir     if( m_aDocDigest )
1867cdf0e10cSrcweir         rtl_digest_destroyMD5( m_aDocDigest );
1868cdf0e10cSrcweir     delete static_cast<VirtualDevice*>(m_pReferenceDevice);
1869cdf0e10cSrcweir 
1870cdf0e10cSrcweir 	if( m_aCipher )
1871cdf0e10cSrcweir 		rtl_cipher_destroyARCFOUR( m_aCipher );
1872cdf0e10cSrcweir 	if( m_aDigest )
1873cdf0e10cSrcweir 		rtl_digest_destroyMD5( m_aDigest );
1874cdf0e10cSrcweir 
1875cdf0e10cSrcweir     rtl_freeMemory( m_pEncryptionBuffer );
1876cdf0e10cSrcweir }
1877cdf0e10cSrcweir 
1878cdf0e10cSrcweir void PDFWriterImpl::setupDocInfo()
1879cdf0e10cSrcweir {
1880cdf0e10cSrcweir     std::vector< sal_uInt8 > aId;
1881cdf0e10cSrcweir     computeDocumentIdentifier( aId, m_aContext.DocumentInfo, m_aCreationDateString, m_aCreationMetaDateString );
1882cdf0e10cSrcweir     if( m_aContext.Encryption.DocumentIdentifier.empty() )
1883cdf0e10cSrcweir         m_aContext.Encryption.DocumentIdentifier = aId;
1884cdf0e10cSrcweir }
1885cdf0e10cSrcweir 
1886cdf0e10cSrcweir void PDFWriterImpl::computeDocumentIdentifier( std::vector< sal_uInt8 >& o_rIdentifier,
1887cdf0e10cSrcweir                                                const vcl::PDFWriter::PDFDocInfo& i_rDocInfo,
1888cdf0e10cSrcweir                                                rtl::OString& o_rCString1,
1889cdf0e10cSrcweir                                                rtl::OString& o_rCString2
1890cdf0e10cSrcweir                                                )
1891cdf0e10cSrcweir {
1892cdf0e10cSrcweir     o_rIdentifier.clear();
1893cdf0e10cSrcweir 
1894cdf0e10cSrcweir     //build the document id
1895cdf0e10cSrcweir 	rtl::OString aInfoValuesOut;
1896cdf0e10cSrcweir 	OStringBuffer aID( 1024 );
1897cdf0e10cSrcweir 	if( i_rDocInfo.Title.Len() )
1898cdf0e10cSrcweir 		appendUnicodeTextString( i_rDocInfo.Title, aID );
1899cdf0e10cSrcweir 	if( i_rDocInfo.Author.Len() )
1900cdf0e10cSrcweir 		appendUnicodeTextString( i_rDocInfo.Author, aID );
1901cdf0e10cSrcweir 	if( i_rDocInfo.Subject.Len() )
1902cdf0e10cSrcweir 		appendUnicodeTextString( i_rDocInfo.Subject, aID );
1903cdf0e10cSrcweir 	if( i_rDocInfo.Keywords.Len() )
1904cdf0e10cSrcweir 		appendUnicodeTextString( i_rDocInfo.Keywords, aID );
1905cdf0e10cSrcweir 	if( i_rDocInfo.Creator.Len() )
1906cdf0e10cSrcweir 		appendUnicodeTextString( i_rDocInfo.Creator, aID );
1907cdf0e10cSrcweir 	if( i_rDocInfo.Producer.Len() )
1908cdf0e10cSrcweir 		appendUnicodeTextString( i_rDocInfo.Producer, aID );
1909cdf0e10cSrcweir 
1910cdf0e10cSrcweir 	TimeValue aTVal, aGMT;
1911cdf0e10cSrcweir 	oslDateTime aDT;
1912cdf0e10cSrcweir 	osl_getSystemTime( &aGMT );
1913cdf0e10cSrcweir 	osl_getLocalTimeFromSystemTime( &aGMT, &aTVal );
1914cdf0e10cSrcweir 	osl_getDateTimeFromTimeValue( &aTVal, &aDT );
1915cdf0e10cSrcweir 	rtl::OStringBuffer aCreationDateString(64), aCreationMetaDateString(64);
1916cdf0e10cSrcweir 	aCreationDateString.append( "D:" );
1917cdf0e10cSrcweir 	aCreationDateString.append( (sal_Char)('0' + ((aDT.Year/1000)%10)) );
1918cdf0e10cSrcweir 	aCreationDateString.append( (sal_Char)('0' + ((aDT.Year/100)%10)) );
1919cdf0e10cSrcweir 	aCreationDateString.append( (sal_Char)('0' + ((aDT.Year/10)%10)) );
1920cdf0e10cSrcweir 	aCreationDateString.append( (sal_Char)('0' + ((aDT.Year)%10)) );
1921cdf0e10cSrcweir 	aCreationDateString.append( (sal_Char)('0' + ((aDT.Month/10)%10)) );
1922cdf0e10cSrcweir 	aCreationDateString.append( (sal_Char)('0' + ((aDT.Month)%10)) );
1923cdf0e10cSrcweir 	aCreationDateString.append( (sal_Char)('0' + ((aDT.Day/10)%10)) );
1924cdf0e10cSrcweir 	aCreationDateString.append( (sal_Char)('0' + ((aDT.Day)%10)) );
1925cdf0e10cSrcweir 	aCreationDateString.append( (sal_Char)('0' + ((aDT.Hours/10)%10)) );
1926cdf0e10cSrcweir 	aCreationDateString.append( (sal_Char)('0' + ((aDT.Hours)%10)) );
1927cdf0e10cSrcweir 	aCreationDateString.append( (sal_Char)('0' + ((aDT.Minutes/10)%10)) );
1928cdf0e10cSrcweir 	aCreationDateString.append( (sal_Char)('0' + ((aDT.Minutes)%10)) );
1929cdf0e10cSrcweir 	aCreationDateString.append( (sal_Char)('0' + ((aDT.Seconds/10)%10)) );
1930cdf0e10cSrcweir 	aCreationDateString.append( (sal_Char)('0' + ((aDT.Seconds)%10)) );
1931cdf0e10cSrcweir 
1932cdf0e10cSrcweir 	//--> i59651, we fill the Metadata date string as well, if PDF/A is requested
1933cdf0e10cSrcweir     // according to ISO 19005-1:2005 6.7.3 the date is corrected for
1934cdf0e10cSrcweir     // local time zone offset UTC only, whereas Acrobat 8 seems
1935cdf0e10cSrcweir     // to use the localtime notation only
1936cdf0e10cSrcweir     // according to a raccomandation in XMP Specification (Jan 2004, page 75)
1937cdf0e10cSrcweir     // the Acrobat way seems the right approach
1938cdf0e10cSrcweir     aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Year/1000)%10)) );
1939cdf0e10cSrcweir     aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Year/100)%10)) );
1940cdf0e10cSrcweir     aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Year/10)%10)) );
1941cdf0e10cSrcweir     aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Year)%10)) );
1942cdf0e10cSrcweir     aCreationMetaDateString.append( "-" );
1943cdf0e10cSrcweir     aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Month/10)%10)) );
1944cdf0e10cSrcweir     aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Month)%10)) );
1945cdf0e10cSrcweir     aCreationMetaDateString.append( "-" );
1946cdf0e10cSrcweir     aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Day/10)%10)) );
1947cdf0e10cSrcweir     aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Day)%10)) );
1948cdf0e10cSrcweir     aCreationMetaDateString.append( "T" );
1949cdf0e10cSrcweir     aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Hours/10)%10)) );
1950cdf0e10cSrcweir     aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Hours)%10)) );
1951cdf0e10cSrcweir     aCreationMetaDateString.append( ":" );
1952cdf0e10cSrcweir     aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Minutes/10)%10)) );
1953cdf0e10cSrcweir     aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Minutes)%10)) );
1954cdf0e10cSrcweir     aCreationMetaDateString.append( ":" );
1955cdf0e10cSrcweir     aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Seconds/10)%10)) );
1956cdf0e10cSrcweir     aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Seconds)%10)) );
1957cdf0e10cSrcweir 
1958cdf0e10cSrcweir 	sal_uInt32 nDelta = 0;
1959cdf0e10cSrcweir 	if( aGMT.Seconds > aTVal.Seconds )
1960cdf0e10cSrcweir 	{
1961cdf0e10cSrcweir 		aCreationDateString.append( "-" );
1962cdf0e10cSrcweir 		nDelta = aGMT.Seconds-aTVal.Seconds;
1963cdf0e10cSrcweir 		aCreationMetaDateString.append( "-" );
1964cdf0e10cSrcweir 	}
1965cdf0e10cSrcweir 	else if( aGMT.Seconds < aTVal.Seconds )
1966cdf0e10cSrcweir 	{
1967cdf0e10cSrcweir 		aCreationDateString.append( "+" );
1968cdf0e10cSrcweir 		nDelta = aTVal.Seconds-aGMT.Seconds;
1969cdf0e10cSrcweir 		aCreationMetaDateString.append( "+" );
1970cdf0e10cSrcweir 	}
1971cdf0e10cSrcweir 	else
1972cdf0e10cSrcweir     {
1973cdf0e10cSrcweir 		aCreationDateString.append( "Z" );
1974cdf0e10cSrcweir 		aCreationMetaDateString.append( "Z" );
1975cdf0e10cSrcweir 
1976cdf0e10cSrcweir     }
1977cdf0e10cSrcweir 	if( nDelta )
1978cdf0e10cSrcweir 	{
1979cdf0e10cSrcweir 		aCreationDateString.append( (sal_Char)('0' + ((nDelta/36000)%10)) );
1980cdf0e10cSrcweir 		aCreationDateString.append( (sal_Char)('0' + ((nDelta/3600)%10)) );
1981cdf0e10cSrcweir 		aCreationDateString.append( "'" );
1982cdf0e10cSrcweir 		aCreationDateString.append( (sal_Char)('0' + ((nDelta/600)%6)) );
1983cdf0e10cSrcweir 		aCreationDateString.append( (sal_Char)('0' + ((nDelta/60)%10)) );
1984cdf0e10cSrcweir 
1985cdf0e10cSrcweir 		aCreationMetaDateString.append( (sal_Char)('0' + ((nDelta/36000)%10)) );
1986cdf0e10cSrcweir 		aCreationMetaDateString.append( (sal_Char)('0' + ((nDelta/3600)%10)) );
1987cdf0e10cSrcweir 		aCreationMetaDateString.append( ":" );
1988cdf0e10cSrcweir 		aCreationMetaDateString.append( (sal_Char)('0' + ((nDelta/600)%6)) );
1989cdf0e10cSrcweir 		aCreationMetaDateString.append( (sal_Char)('0' + ((nDelta/60)%10)) );
1990cdf0e10cSrcweir 	}
1991cdf0e10cSrcweir 	aCreationDateString.append( "'" );
1992cdf0e10cSrcweir 	aID.append( aCreationDateString.getStr(), aCreationDateString.getLength() );
1993cdf0e10cSrcweir 
1994cdf0e10cSrcweir 	aInfoValuesOut = aID.makeStringAndClear();
1995cdf0e10cSrcweir 	o_rCString1 = aCreationDateString.makeStringAndClear();
1996cdf0e10cSrcweir 	o_rCString2 = aCreationMetaDateString.makeStringAndClear();
1997cdf0e10cSrcweir 
1998cdf0e10cSrcweir 	rtlDigest aDigest = rtl_digest_createMD5();
1999cdf0e10cSrcweir 	OSL_ENSURE( aDigest != NULL, "PDFWriterImpl::computeDocumentIdentifier: cannot obtain a digest object !" );
2000cdf0e10cSrcweir 	if( aDigest )
2001cdf0e10cSrcweir 	{
2002cdf0e10cSrcweir 		rtlDigestError nError = rtl_digest_updateMD5( aDigest, &aGMT, sizeof( aGMT ) );
2003cdf0e10cSrcweir 		if( nError == rtl_Digest_E_None )
2004cdf0e10cSrcweir 			nError = rtl_digest_updateMD5( aDigest, aInfoValuesOut.getStr(), aInfoValuesOut.getLength() );
2005cdf0e10cSrcweir 		if( nError == rtl_Digest_E_None )
2006cdf0e10cSrcweir 		{
2007cdf0e10cSrcweir 		    o_rIdentifier = std::vector< sal_uInt8 >( 16, 0 );
2008cdf0e10cSrcweir 		    //the binary form of the doc id is needed for encryption stuff
2009cdf0e10cSrcweir 			rtl_digest_getMD5( aDigest, &o_rIdentifier[0], 16 );
2010cdf0e10cSrcweir 		}
2011cdf0e10cSrcweir 	}
2012cdf0e10cSrcweir }
2013cdf0e10cSrcweir 
2014cdf0e10cSrcweir /* i12626 methods */
2015cdf0e10cSrcweir /*
2016cdf0e10cSrcweir check if the Unicode string must be encrypted or not, perform the requested task,
2017cdf0e10cSrcweir append the string as unicode hex, encrypted if needed
2018cdf0e10cSrcweir  */
2019cdf0e10cSrcweir inline void PDFWriterImpl::appendUnicodeTextStringEncrypt( const rtl::OUString& rInString, const sal_Int32 nInObjectNumber, OStringBuffer& rOutBuffer )
2020cdf0e10cSrcweir {
2021cdf0e10cSrcweir 	rOutBuffer.append( "<" );
2022cdf0e10cSrcweir 	if( m_aContext.Encryption.Encrypt() )
2023cdf0e10cSrcweir 	{
2024cdf0e10cSrcweir 		const sal_Unicode* pStr = rInString.getStr();
2025cdf0e10cSrcweir 		sal_Int32 nLen = rInString.getLength();
2026cdf0e10cSrcweir //prepare a unicode string, encrypt it
2027cdf0e10cSrcweir 		if( checkEncryptionBufferSize( nLen*2 ) )
2028cdf0e10cSrcweir 		{
2029cdf0e10cSrcweir 			enableStringEncryption( nInObjectNumber );
2030cdf0e10cSrcweir 			register sal_uInt8 *pCopy = m_pEncryptionBuffer;
2031cdf0e10cSrcweir 			sal_Int32 nChars = 2;
2032cdf0e10cSrcweir 			*pCopy++ = 0xFE;
2033cdf0e10cSrcweir 			*pCopy++ = 0xFF;
2034cdf0e10cSrcweir // we need to prepare a byte stream from the unicode string buffer
2035cdf0e10cSrcweir 			for( register int i = 0; i < nLen; i++ )
2036cdf0e10cSrcweir 			{
2037cdf0e10cSrcweir 				register sal_Unicode aUnChar = pStr[i];
2038cdf0e10cSrcweir 				*pCopy++ = (sal_uInt8)( aUnChar >> 8 );
2039cdf0e10cSrcweir 				*pCopy++ = (sal_uInt8)( aUnChar & 255 );
2040cdf0e10cSrcweir 				nChars += 2;
2041cdf0e10cSrcweir 			}
2042cdf0e10cSrcweir //encrypt in place
2043cdf0e10cSrcweir 			rtl_cipher_encodeARCFOUR( m_aCipher, m_pEncryptionBuffer, nChars, m_pEncryptionBuffer, nChars );
2044cdf0e10cSrcweir //now append, hexadecimal (appendHex), the encrypted result
2045cdf0e10cSrcweir 			for(register int i = 0; i < nChars; i++)
2046cdf0e10cSrcweir 				appendHex( m_pEncryptionBuffer[i], rOutBuffer );
2047cdf0e10cSrcweir 		}
2048cdf0e10cSrcweir 	}
2049cdf0e10cSrcweir 	else
2050cdf0e10cSrcweir 		appendUnicodeTextString( rInString, rOutBuffer );
2051cdf0e10cSrcweir 	rOutBuffer.append( ">" );
2052cdf0e10cSrcweir }
2053cdf0e10cSrcweir 
2054cdf0e10cSrcweir inline void PDFWriterImpl::appendLiteralStringEncrypt( rtl::OStringBuffer& rInString, const sal_Int32 nInObjectNumber, rtl::OStringBuffer& rOutBuffer )
2055cdf0e10cSrcweir {
2056cdf0e10cSrcweir 	rOutBuffer.append( "(" );
2057cdf0e10cSrcweir 	sal_Int32 nChars = rInString.getLength();
2058cdf0e10cSrcweir //check for encryption, if ok, encrypt the string, then convert with appndLiteralString
2059cdf0e10cSrcweir 	if( m_aContext.Encryption.Encrypt() && checkEncryptionBufferSize( nChars ) )
2060cdf0e10cSrcweir 	{
2061cdf0e10cSrcweir //encrypt the string in a buffer, then append it
2062cdf0e10cSrcweir 		enableStringEncryption( nInObjectNumber );
2063cdf0e10cSrcweir 		rtl_cipher_encodeARCFOUR( m_aCipher, rInString.getStr(), nChars, m_pEncryptionBuffer, nChars );
2064cdf0e10cSrcweir 		appendLiteralString( (const sal_Char*)m_pEncryptionBuffer, nChars, rOutBuffer );
2065cdf0e10cSrcweir 	}
2066cdf0e10cSrcweir 	else
2067cdf0e10cSrcweir         appendLiteralString( rInString.getStr(), nChars , rOutBuffer );
2068cdf0e10cSrcweir 	rOutBuffer.append( ")" );
2069cdf0e10cSrcweir }
2070cdf0e10cSrcweir 
2071cdf0e10cSrcweir inline void PDFWriterImpl::appendLiteralStringEncrypt( const rtl::OString& rInString, const sal_Int32 nInObjectNumber, rtl::OStringBuffer& rOutBuffer )
2072cdf0e10cSrcweir {
2073cdf0e10cSrcweir 	rtl::OStringBuffer aBufferString( rInString );
2074cdf0e10cSrcweir 	appendLiteralStringEncrypt( aBufferString, nInObjectNumber, rOutBuffer);
2075cdf0e10cSrcweir }
2076cdf0e10cSrcweir 
2077cdf0e10cSrcweir void PDFWriterImpl::appendLiteralStringEncrypt( const rtl::OUString& rInString, const sal_Int32 nInObjectNumber, rtl::OStringBuffer& rOutBuffer, rtl_TextEncoding nEnc )
2078cdf0e10cSrcweir {
2079cdf0e10cSrcweir 	rtl::OString aBufferString( rtl::OUStringToOString( rInString, nEnc ) );
2080cdf0e10cSrcweir 	sal_Int32 nLen = aBufferString.getLength();
2081cdf0e10cSrcweir 	rtl::OStringBuffer aBuf( nLen );
2082cdf0e10cSrcweir 	const sal_Char* pT = aBufferString.getStr();
2083cdf0e10cSrcweir 
2084cdf0e10cSrcweir 	for( sal_Int32 i = 0; i < nLen; i++, pT++ )
2085cdf0e10cSrcweir 	{
2086cdf0e10cSrcweir 	    if( (*pT & 0x80) == 0 )
2087cdf0e10cSrcweir 	        aBuf.append( *pT );
2088cdf0e10cSrcweir 	    else
2089cdf0e10cSrcweir 	    {
2090cdf0e10cSrcweir 	        aBuf.append( '<' );
2091cdf0e10cSrcweir 	        appendHex( *pT, aBuf );
2092cdf0e10cSrcweir 	        aBuf.append( '>' );
2093cdf0e10cSrcweir 	    }
2094cdf0e10cSrcweir 	}
2095cdf0e10cSrcweir 	aBufferString = aBuf.makeStringAndClear();
2096cdf0e10cSrcweir 	appendLiteralStringEncrypt( aBufferString, nInObjectNumber, rOutBuffer);
2097cdf0e10cSrcweir }
2098cdf0e10cSrcweir 
2099cdf0e10cSrcweir /* end i12626 methods */
2100cdf0e10cSrcweir 
2101cdf0e10cSrcweir void PDFWriterImpl::emitComment( const char* pComment )
2102cdf0e10cSrcweir {
2103cdf0e10cSrcweir     OStringBuffer aLine( 64 );
2104cdf0e10cSrcweir     aLine.append( "% " );
2105cdf0e10cSrcweir     aLine.append( (const sal_Char*)pComment );
2106cdf0e10cSrcweir     aLine.append( "\n" );
2107cdf0e10cSrcweir     writeBuffer( aLine.getStr(), aLine.getLength() );
2108cdf0e10cSrcweir }
2109cdf0e10cSrcweir 
2110cdf0e10cSrcweir bool PDFWriterImpl::compressStream( SvMemoryStream* pStream )
2111cdf0e10cSrcweir {
2112cdf0e10cSrcweir #ifndef DEBUG_DISABLE_PDFCOMPRESSION
2113cdf0e10cSrcweir     pStream->Seek( STREAM_SEEK_TO_END );
2114cdf0e10cSrcweir     sal_uLong nEndPos = pStream->Tell();
2115cdf0e10cSrcweir     pStream->Seek( STREAM_SEEK_TO_BEGIN );
2116cdf0e10cSrcweir     ZCodec* pCodec = new ZCodec( 0x4000, 0x4000 );
2117cdf0e10cSrcweir     SvMemoryStream aStream;
2118cdf0e10cSrcweir     pCodec->BeginCompression();
2119cdf0e10cSrcweir     pCodec->Write( aStream, (const sal_uInt8*)pStream->GetData(), nEndPos );
2120cdf0e10cSrcweir     pCodec->EndCompression();
2121cdf0e10cSrcweir     delete pCodec;
2122cdf0e10cSrcweir     nEndPos = aStream.Tell();
2123cdf0e10cSrcweir     pStream->Seek( STREAM_SEEK_TO_BEGIN );
2124cdf0e10cSrcweir     aStream.Seek( STREAM_SEEK_TO_BEGIN );
2125cdf0e10cSrcweir     pStream->SetStreamSize( nEndPos );
2126cdf0e10cSrcweir     pStream->Write( aStream.GetData(), nEndPos );
2127cdf0e10cSrcweir     return true;
2128cdf0e10cSrcweir #else
2129cdf0e10cSrcweir     (void)pStream;
2130cdf0e10cSrcweir     return false;
2131cdf0e10cSrcweir #endif
2132cdf0e10cSrcweir }
2133cdf0e10cSrcweir 
2134cdf0e10cSrcweir void PDFWriterImpl::beginCompression()
2135cdf0e10cSrcweir {
2136cdf0e10cSrcweir #ifndef DEBUG_DISABLE_PDFCOMPRESSION
2137cdf0e10cSrcweir     m_pCodec = new ZCodec( 0x4000, 0x4000 );
2138cdf0e10cSrcweir     m_pMemStream = new SvMemoryStream();
2139cdf0e10cSrcweir     m_pCodec->BeginCompression();
2140cdf0e10cSrcweir #endif
2141cdf0e10cSrcweir }
2142cdf0e10cSrcweir 
2143cdf0e10cSrcweir void PDFWriterImpl::endCompression()
2144cdf0e10cSrcweir {
2145cdf0e10cSrcweir #ifndef DEBUG_DISABLE_PDFCOMPRESSION
2146cdf0e10cSrcweir     if( m_pCodec )
2147cdf0e10cSrcweir     {
2148cdf0e10cSrcweir         m_pCodec->EndCompression();
2149cdf0e10cSrcweir         delete m_pCodec;
2150cdf0e10cSrcweir         m_pCodec = NULL;
2151cdf0e10cSrcweir         sal_uInt64 nLen = m_pMemStream->Tell();
2152cdf0e10cSrcweir         m_pMemStream->Seek( 0 );
2153cdf0e10cSrcweir         writeBuffer( m_pMemStream->GetData(), nLen );
2154cdf0e10cSrcweir         delete m_pMemStream;
2155cdf0e10cSrcweir         m_pMemStream = NULL;
2156cdf0e10cSrcweir     }
2157cdf0e10cSrcweir #endif
2158cdf0e10cSrcweir }
2159cdf0e10cSrcweir 
2160cdf0e10cSrcweir bool PDFWriterImpl::writeBuffer( const void* pBuffer, sal_uInt64 nBytes )
2161cdf0e10cSrcweir {
2162cdf0e10cSrcweir     if( ! m_bOpen ) // we are already down the drain
2163cdf0e10cSrcweir         return false;
2164cdf0e10cSrcweir 
2165cdf0e10cSrcweir     if( ! nBytes ) // huh ?
2166cdf0e10cSrcweir         return true;
2167cdf0e10cSrcweir 
2168cdf0e10cSrcweir     if( m_aOutputStreams.begin() != m_aOutputStreams.end() )
2169cdf0e10cSrcweir     {
2170cdf0e10cSrcweir         m_aOutputStreams.front().m_pStream->Seek( STREAM_SEEK_TO_END );
2171cdf0e10cSrcweir         m_aOutputStreams.front().m_pStream->Write( pBuffer, sal::static_int_cast<sal_Size>(nBytes) );
2172cdf0e10cSrcweir         return true;
2173cdf0e10cSrcweir     }
2174cdf0e10cSrcweir 
2175cdf0e10cSrcweir     sal_uInt64 nWritten;
2176cdf0e10cSrcweir     if( m_pCodec )
2177cdf0e10cSrcweir     {
2178cdf0e10cSrcweir         m_pCodec->Write( *m_pMemStream, static_cast<const sal_uInt8*>(pBuffer), (sal_uLong)nBytes );
2179cdf0e10cSrcweir         nWritten = nBytes;
2180cdf0e10cSrcweir     }
2181cdf0e10cSrcweir     else
2182cdf0e10cSrcweir     {
2183cdf0e10cSrcweir 		sal_Bool  buffOK = sal_True;
2184cdf0e10cSrcweir 		if( m_bEncryptThisStream )
2185cdf0e10cSrcweir 		{
2186cdf0e10cSrcweir /* implement the encryption part of the PDF spec encryption algorithm 3.1 */
2187cdf0e10cSrcweir 			if( ( buffOK = checkEncryptionBufferSize( static_cast<sal_Int32>(nBytes) ) ) != sal_False )
2188cdf0e10cSrcweir 				rtl_cipher_encodeARCFOUR( m_aCipher,
2189cdf0e10cSrcweir                                           (sal_uInt8*)pBuffer, static_cast<sal_Size>(nBytes),
2190cdf0e10cSrcweir                                           m_pEncryptionBuffer, static_cast<sal_Size>(nBytes) );
2191cdf0e10cSrcweir 		}
2192cdf0e10cSrcweir 
2193cdf0e10cSrcweir         const void* pWriteBuffer = ( m_bEncryptThisStream && buffOK ) ? m_pEncryptionBuffer  : pBuffer;
2194cdf0e10cSrcweir         if( m_aDocDigest )
2195cdf0e10cSrcweir             rtl_digest_updateMD5( m_aDocDigest, pWriteBuffer, static_cast<sal_uInt32>(nBytes) );
2196cdf0e10cSrcweir 
2197cdf0e10cSrcweir         if( osl_writeFile( m_aFile,
2198cdf0e10cSrcweir                            pWriteBuffer,
2199cdf0e10cSrcweir                            nBytes, &nWritten ) != osl_File_E_None )
2200cdf0e10cSrcweir             nWritten = 0;
2201cdf0e10cSrcweir 
2202cdf0e10cSrcweir         if( nWritten != nBytes )
2203cdf0e10cSrcweir         {
2204cdf0e10cSrcweir             osl_closeFile( m_aFile );
2205cdf0e10cSrcweir             m_bOpen = false;
2206cdf0e10cSrcweir         }
2207cdf0e10cSrcweir     }
2208cdf0e10cSrcweir 
2209cdf0e10cSrcweir     return nWritten == nBytes;
2210cdf0e10cSrcweir }
2211cdf0e10cSrcweir 
2212cdf0e10cSrcweir OutputDevice* PDFWriterImpl::getReferenceDevice()
2213cdf0e10cSrcweir {
2214cdf0e10cSrcweir     if( ! m_pReferenceDevice )
2215cdf0e10cSrcweir     {
2216cdf0e10cSrcweir         VirtualDevice*  pVDev = new VirtualDevice( 0 );
2217cdf0e10cSrcweir 
2218cdf0e10cSrcweir         m_pReferenceDevice = pVDev;
2219cdf0e10cSrcweir 
2220cdf0e10cSrcweir         if( m_aContext.DPIx == 0 || m_aContext.DPIy == 0 )
2221cdf0e10cSrcweir             pVDev->SetReferenceDevice( VirtualDevice::REFDEV_MODE_PDF1 );
2222cdf0e10cSrcweir         else
2223cdf0e10cSrcweir             pVDev->SetReferenceDevice( m_aContext.DPIx, m_aContext.DPIy );
2224cdf0e10cSrcweir 
2225cdf0e10cSrcweir         pVDev->SetOutputSizePixel( Size( 640, 480 ) );
2226cdf0e10cSrcweir         pVDev->SetMapMode( MAP_MM );
2227cdf0e10cSrcweir 
2228cdf0e10cSrcweir         m_pReferenceDevice->mpPDFWriter = this;
2229cdf0e10cSrcweir         m_pReferenceDevice->ImplUpdateFontData( sal_True );
2230cdf0e10cSrcweir     }
2231cdf0e10cSrcweir     return m_pReferenceDevice;
2232cdf0e10cSrcweir }
2233cdf0e10cSrcweir 
2234cdf0e10cSrcweir class ImplPdfBuiltinFontData : public ImplFontData
2235cdf0e10cSrcweir {
2236cdf0e10cSrcweir private:
2237cdf0e10cSrcweir     const PDFWriterImpl::BuiltinFont& mrBuiltin;
2238cdf0e10cSrcweir 
2239cdf0e10cSrcweir public:
2240cdf0e10cSrcweir     enum {PDF_FONT_MAGIC = 0xBDFF0A1C };
2241cdf0e10cSrcweir                                         ImplPdfBuiltinFontData( const PDFWriterImpl::BuiltinFont& );
2242cdf0e10cSrcweir     const PDFWriterImpl::BuiltinFont*   GetBuiltinFont() const  { return &mrBuiltin; }
2243cdf0e10cSrcweir 
2244cdf0e10cSrcweir     virtual ImplFontData*               Clone() const { return new ImplPdfBuiltinFontData(*this); }
2245cdf0e10cSrcweir     virtual ImplFontEntry*              CreateFontInstance( ImplFontSelectData& ) const;
2246cdf0e10cSrcweir     virtual sal_IntPtr                  GetFontId() const { return reinterpret_cast<sal_IntPtr>(&mrBuiltin); }
2247cdf0e10cSrcweir };
2248cdf0e10cSrcweir 
2249cdf0e10cSrcweir inline const ImplPdfBuiltinFontData* GetPdfFontData( const ImplFontData* pFontData )
2250cdf0e10cSrcweir {
2251cdf0e10cSrcweir     const ImplPdfBuiltinFontData* pFD = NULL;
2252cdf0e10cSrcweir     if( pFontData && pFontData->CheckMagic( ImplPdfBuiltinFontData::PDF_FONT_MAGIC ) )
2253cdf0e10cSrcweir         pFD = static_cast<const ImplPdfBuiltinFontData*>( pFontData );
2254cdf0e10cSrcweir     return pFD;
2255cdf0e10cSrcweir }
2256cdf0e10cSrcweir 
2257cdf0e10cSrcweir static ImplDevFontAttributes GetDevFontAttributes( const PDFWriterImpl::BuiltinFont& rBuiltin )
2258cdf0e10cSrcweir {
2259cdf0e10cSrcweir     ImplDevFontAttributes aDFA;
2260cdf0e10cSrcweir     aDFA.maName         = String::CreateFromAscii( rBuiltin.m_pName );
2261cdf0e10cSrcweir     aDFA.maStyleName    = String::CreateFromAscii( rBuiltin.m_pStyleName );
2262cdf0e10cSrcweir     aDFA.meFamily       = rBuiltin.m_eFamily;
2263cdf0e10cSrcweir     aDFA.mbSymbolFlag   = (rBuiltin.m_eCharSet != RTL_TEXTENCODING_MS_1252 );
2264cdf0e10cSrcweir     aDFA.mePitch        = rBuiltin.m_ePitch;
2265cdf0e10cSrcweir     aDFA.meWeight       = rBuiltin.m_eWeight;
2266cdf0e10cSrcweir     aDFA.meItalic       = rBuiltin.m_eItalic;
2267cdf0e10cSrcweir     aDFA.meWidthType    = rBuiltin.m_eWidthType;
2268cdf0e10cSrcweir 
2269cdf0e10cSrcweir     aDFA.mbOrientation  = true;
2270cdf0e10cSrcweir     aDFA.mbDevice       = true;
2271cdf0e10cSrcweir     aDFA.mnQuality      = 50000;
2272cdf0e10cSrcweir     aDFA.mbSubsettable  = false;
2273cdf0e10cSrcweir     aDFA.mbEmbeddable   = false;
2274cdf0e10cSrcweir     return aDFA;
2275cdf0e10cSrcweir }
2276cdf0e10cSrcweir 
2277cdf0e10cSrcweir ImplPdfBuiltinFontData::ImplPdfBuiltinFontData( const PDFWriterImpl::BuiltinFont& rBuiltin )
2278cdf0e10cSrcweir :   ImplFontData( GetDevFontAttributes(rBuiltin), PDF_FONT_MAGIC ),
2279cdf0e10cSrcweir     mrBuiltin( rBuiltin )
2280cdf0e10cSrcweir {}
2281cdf0e10cSrcweir 
2282cdf0e10cSrcweir ImplFontEntry* ImplPdfBuiltinFontData::CreateFontInstance( ImplFontSelectData& rFSD ) const
2283cdf0e10cSrcweir {
2284cdf0e10cSrcweir     ImplFontEntry* pEntry = new ImplFontEntry( rFSD );
2285cdf0e10cSrcweir     return pEntry;
2286cdf0e10cSrcweir }
2287cdf0e10cSrcweir 
2288cdf0e10cSrcweir ImplDevFontList* PDFWriterImpl::filterDevFontList( ImplDevFontList* pFontList )
2289cdf0e10cSrcweir {
2290cdf0e10cSrcweir     DBG_ASSERT( m_aSubsets.size() == 0, "Fonts changing during PDF generation, document will be invalid" );
2291cdf0e10cSrcweir     ImplDevFontList* pFiltered = pFontList->Clone( true, true );
2292cdf0e10cSrcweir 
2293cdf0e10cSrcweir     // append the PDF builtin fonts
2294cdf0e10cSrcweir     if( !m_bIsPDF_A1 && !m_bEmbedStandardFonts)
2295cdf0e10cSrcweir         for( unsigned int i = 0; i < sizeof(m_aBuiltinFonts)/sizeof(m_aBuiltinFonts[0]); i++ )
2296cdf0e10cSrcweir         {
2297cdf0e10cSrcweir             ImplFontData* pNewData = new ImplPdfBuiltinFontData( m_aBuiltinFonts[i] );
2298cdf0e10cSrcweir             pFiltered->Add( pNewData );
2299cdf0e10cSrcweir         }
2300cdf0e10cSrcweir     return pFiltered;
2301cdf0e10cSrcweir }
2302cdf0e10cSrcweir 
2303cdf0e10cSrcweir bool PDFWriterImpl::isBuiltinFont( const ImplFontData* pFont ) const
2304cdf0e10cSrcweir {
2305cdf0e10cSrcweir     const ImplPdfBuiltinFontData* pFD = GetPdfFontData( pFont );
2306cdf0e10cSrcweir     return (pFD != NULL);
2307cdf0e10cSrcweir }
2308cdf0e10cSrcweir 
2309cdf0e10cSrcweir void PDFWriterImpl::getFontMetric( ImplFontSelectData* pSelect, ImplFontMetricData* pMetric ) const
2310cdf0e10cSrcweir {
2311cdf0e10cSrcweir     const ImplPdfBuiltinFontData* pFD = GetPdfFontData( pSelect->mpFontData );
2312cdf0e10cSrcweir     if( !pFD )
2313cdf0e10cSrcweir         return;
2314cdf0e10cSrcweir     const BuiltinFont* pBuiltinFont = pFD->GetBuiltinFont();
2315cdf0e10cSrcweir 
2316cdf0e10cSrcweir     pMetric->mnOrientation	= sal::static_int_cast<short>(pSelect->mnOrientation);
2317cdf0e10cSrcweir     pMetric->meFamily		= pBuiltinFont->m_eFamily;
2318cdf0e10cSrcweir     pMetric->mePitch		= pBuiltinFont->m_ePitch;
2319cdf0e10cSrcweir     pMetric->meWeight		= pBuiltinFont->m_eWeight;
2320cdf0e10cSrcweir     pMetric->meItalic		= pBuiltinFont->m_eItalic;
2321cdf0e10cSrcweir     pMetric->mbSymbolFlag	= pFD->IsSymbolFont();
2322cdf0e10cSrcweir     pMetric->mnWidth		= pSelect->mnHeight;
2323cdf0e10cSrcweir     pMetric->mnAscent		= ( pSelect->mnHeight * +pBuiltinFont->m_nAscent + 500 ) / 1000;
2324cdf0e10cSrcweir     pMetric->mnDescent		= ( pSelect->mnHeight * -pBuiltinFont->m_nDescent + 500 ) / 1000;
2325cdf0e10cSrcweir     pMetric->mnIntLeading	= 0;
2326cdf0e10cSrcweir     pMetric->mnExtLeading	= 0;
2327cdf0e10cSrcweir     pMetric->mnSlant		= 0;
2328cdf0e10cSrcweir     pMetric->mbScalableFont	= true;
2329cdf0e10cSrcweir     pMetric->mbDevice		= true;
2330cdf0e10cSrcweir }
2331cdf0e10cSrcweir 
2332cdf0e10cSrcweir // -----------------------------------------------------------------------
2333cdf0e10cSrcweir 
2334cdf0e10cSrcweir namespace vcl {
2335cdf0e10cSrcweir 
2336cdf0e10cSrcweir class PDFSalLayout : public GenericSalLayout
2337cdf0e10cSrcweir {
2338cdf0e10cSrcweir     PDFWriterImpl&  mrPDFWriterImpl;
2339cdf0e10cSrcweir     const PDFWriterImpl::BuiltinFont& mrBuiltinFont;
2340cdf0e10cSrcweir     bool            mbIsSymbolFont;
2341cdf0e10cSrcweir     long            mnPixelPerEM;
2342cdf0e10cSrcweir     String          maOrigText;
2343cdf0e10cSrcweir 
2344cdf0e10cSrcweir public:
2345cdf0e10cSrcweir                     PDFSalLayout( PDFWriterImpl&,
2346cdf0e10cSrcweir                                   const PDFWriterImpl::BuiltinFont&,
2347cdf0e10cSrcweir                                   long nPixelPerEM, int nOrientation );
2348cdf0e10cSrcweir 
2349cdf0e10cSrcweir     void            SetText( const String& rText )  { maOrigText = rText; }
2350cdf0e10cSrcweir     virtual bool    LayoutText( ImplLayoutArgs& );
2351cdf0e10cSrcweir     virtual void    InitFont() const;
2352cdf0e10cSrcweir     virtual void    DrawText( SalGraphics& ) const;
2353cdf0e10cSrcweir };
2354cdf0e10cSrcweir 
2355cdf0e10cSrcweir }
2356cdf0e10cSrcweir 
2357cdf0e10cSrcweir // -----------------------------------------------------------------------
2358cdf0e10cSrcweir 
2359cdf0e10cSrcweir PDFSalLayout::PDFSalLayout( PDFWriterImpl& rPDFWriterImpl,
2360cdf0e10cSrcweir     const PDFWriterImpl::BuiltinFont& rBuiltinFont,
2361cdf0e10cSrcweir     long nPixelPerEM, int nOrientation )
2362cdf0e10cSrcweir :   mrPDFWriterImpl( rPDFWriterImpl ),
2363cdf0e10cSrcweir     mrBuiltinFont( rBuiltinFont ),
2364cdf0e10cSrcweir     mnPixelPerEM( nPixelPerEM )
2365cdf0e10cSrcweir {
2366cdf0e10cSrcweir     mbIsSymbolFont = (rBuiltinFont.m_eCharSet != RTL_TEXTENCODING_MS_1252);
2367cdf0e10cSrcweir     SetOrientation( nOrientation );
2368cdf0e10cSrcweir }
2369cdf0e10cSrcweir 
2370cdf0e10cSrcweir // -----------------------------------------------------------------------
2371cdf0e10cSrcweir 
2372cdf0e10cSrcweir bool PDFSalLayout::LayoutText( ImplLayoutArgs& rArgs )
2373cdf0e10cSrcweir {
2374cdf0e10cSrcweir     const String aText( rArgs.mpStr+rArgs.mnMinCharPos, sal::static_int_cast<xub_StrLen>(rArgs.mnEndCharPos-rArgs.mnMinCharPos) );
2375cdf0e10cSrcweir     SetText( aText );
2376cdf0e10cSrcweir     SetUnitsPerPixel( 1000 );
2377cdf0e10cSrcweir 
2378cdf0e10cSrcweir     rtl_UnicodeToTextConverter aConv = rtl_createTextToUnicodeConverter( mrBuiltinFont.m_eCharSet );
2379cdf0e10cSrcweir 
2380cdf0e10cSrcweir     Point aNewPos( 0, 0 );
2381cdf0e10cSrcweir     bool bRightToLeft;
2382cdf0e10cSrcweir     for( int nCharPos = -1; rArgs.GetNextPos( &nCharPos, &bRightToLeft ); )
2383cdf0e10cSrcweir     {
2384cdf0e10cSrcweir         // TODO: handle unicode surrogates
2385cdf0e10cSrcweir         // on the other hand the PDF builtin fonts don't support them anyway
2386cdf0e10cSrcweir         sal_Unicode cChar = rArgs.mpStr[ nCharPos ];
2387cdf0e10cSrcweir         if( bRightToLeft )
2388cdf0e10cSrcweir             cChar = static_cast<sal_Unicode>(GetMirroredChar( cChar ));
2389cdf0e10cSrcweir 
2390cdf0e10cSrcweir         if( 1 ) // TODO: shortcut for ASCII?
2391cdf0e10cSrcweir         {
2392cdf0e10cSrcweir             sal_Char aBuf[4];
2393cdf0e10cSrcweir             sal_uInt32 nInfo;
2394cdf0e10cSrcweir             sal_Size nSrcCvtChars;
2395cdf0e10cSrcweir 
2396cdf0e10cSrcweir             sal_Size nConv = rtl_convertUnicodeToText( aConv,
2397cdf0e10cSrcweir                                                        NULL,
2398cdf0e10cSrcweir                                                        &cChar, 1,
2399cdf0e10cSrcweir                                                        aBuf, sizeof(aBuf)/sizeof(*aBuf),
2400cdf0e10cSrcweir                                                        RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR,
2401cdf0e10cSrcweir                                                        &nInfo, &nSrcCvtChars );
2402cdf0e10cSrcweir             // check whether conversion was possible
2403cdf0e10cSrcweir             // else fallback font is needed as the standard fonts
2404cdf0e10cSrcweir             // are handled via WinAnsi encoding
2405cdf0e10cSrcweir             if( nConv > 0 )
2406cdf0e10cSrcweir                 cChar = ((sal_Unicode)aBuf[0]) & 0x00ff;
2407cdf0e10cSrcweir         }
2408cdf0e10cSrcweir         if( cChar & 0xff00 )
2409cdf0e10cSrcweir         {
2410cdf0e10cSrcweir             cChar = 0;   // NotDef glyph
2411cdf0e10cSrcweir             rArgs.NeedFallback( nCharPos, bRightToLeft );
2412cdf0e10cSrcweir         }
2413cdf0e10cSrcweir 
2414cdf0e10cSrcweir         long nGlyphWidth = (long)mrBuiltinFont.m_aWidths[cChar] * mnPixelPerEM;
2415cdf0e10cSrcweir         long nGlyphFlags = 0; // builtin fonts don't have diacritic glyphs
2416cdf0e10cSrcweir         if( bRightToLeft )
2417cdf0e10cSrcweir             nGlyphFlags |= GlyphItem::IS_RTL_GLYPH;
2418cdf0e10cSrcweir         // TODO: get kerning from builtin fonts
2419cdf0e10cSrcweir         GlyphItem aGI( nCharPos, cChar, aNewPos, nGlyphFlags, nGlyphWidth );
2420cdf0e10cSrcweir         AppendGlyph( aGI );
2421cdf0e10cSrcweir 
2422cdf0e10cSrcweir         aNewPos.X() += nGlyphWidth;
2423cdf0e10cSrcweir     }
2424cdf0e10cSrcweir 
2425cdf0e10cSrcweir     rtl_destroyUnicodeToTextConverter( aConv );
2426cdf0e10cSrcweir 
2427cdf0e10cSrcweir     return true;
2428cdf0e10cSrcweir }
2429cdf0e10cSrcweir 
2430cdf0e10cSrcweir // -----------------------------------------------------------------------
2431cdf0e10cSrcweir 
2432cdf0e10cSrcweir void PDFSalLayout::InitFont() const
2433cdf0e10cSrcweir {
2434cdf0e10cSrcweir     // TODO: recreate font with all its attributes
2435cdf0e10cSrcweir }
2436cdf0e10cSrcweir 
2437cdf0e10cSrcweir // -----------------------------------------------------------------------
2438cdf0e10cSrcweir 
2439cdf0e10cSrcweir void PDFSalLayout::DrawText( SalGraphics& ) const
2440cdf0e10cSrcweir {
2441cdf0e10cSrcweir     mrPDFWriterImpl.drawLayout( *const_cast<PDFSalLayout*>(this), maOrigText, true );
2442cdf0e10cSrcweir }
2443cdf0e10cSrcweir 
2444cdf0e10cSrcweir // -----------------------------------------------------------------------
2445cdf0e10cSrcweir 
2446cdf0e10cSrcweir SalLayout* PDFWriterImpl::GetTextLayout( ImplLayoutArgs& rArgs, ImplFontSelectData* pSelect )
2447cdf0e10cSrcweir {
2448cdf0e10cSrcweir     DBG_ASSERT( (pSelect->mpFontData != NULL),
2449cdf0e10cSrcweir         "PDFWriterImpl::GetTextLayout mpFontData is NULL" );
2450cdf0e10cSrcweir 
2451cdf0e10cSrcweir     const ImplPdfBuiltinFontData* pFD = GetPdfFontData( pSelect->mpFontData );
2452cdf0e10cSrcweir     if( !pFD )
2453cdf0e10cSrcweir         return NULL;
2454cdf0e10cSrcweir     const BuiltinFont* pBuiltinFont = pFD->GetBuiltinFont();
2455cdf0e10cSrcweir 
2456cdf0e10cSrcweir     long nPixelPerEM = pSelect->mnWidth ? pSelect->mnWidth : pSelect->mnHeight;
2457cdf0e10cSrcweir     int nOrientation = pSelect->mnOrientation;
2458cdf0e10cSrcweir     PDFSalLayout* pLayout = new PDFSalLayout( *this, *pBuiltinFont, nPixelPerEM, nOrientation );
2459cdf0e10cSrcweir     pLayout->SetText( rArgs.mpStr );
2460cdf0e10cSrcweir     return pLayout;
2461cdf0e10cSrcweir }
2462cdf0e10cSrcweir 
2463cdf0e10cSrcweir sal_Int32 PDFWriterImpl::newPage( sal_Int32 nPageWidth, sal_Int32 nPageHeight, PDFWriter::Orientation eOrientation )
2464cdf0e10cSrcweir {
2465cdf0e10cSrcweir     endPage();
2466cdf0e10cSrcweir     m_nCurrentPage = m_aPages.size();
2467cdf0e10cSrcweir     m_aPages.push_back( PDFPage(this, nPageWidth, nPageHeight, eOrientation ) );
2468cdf0e10cSrcweir     m_aPages.back().m_nPageIndex = m_nCurrentPage;
2469cdf0e10cSrcweir     m_aPages.back().beginStream();
2470cdf0e10cSrcweir 
2471cdf0e10cSrcweir     // setup global graphics state
2472cdf0e10cSrcweir     // linewidth is "1 pixel" by default
2473cdf0e10cSrcweir     OStringBuffer aBuf( 16 );
2474cdf0e10cSrcweir     appendDouble( 72.0/double(getReferenceDevice()->ImplGetDPIX()), aBuf );
2475cdf0e10cSrcweir     aBuf.append( " w\n" );
2476cdf0e10cSrcweir     writeBuffer( aBuf.getStr(), aBuf.getLength() );
2477cdf0e10cSrcweir 
2478cdf0e10cSrcweir     return m_nCurrentPage;
2479cdf0e10cSrcweir }
2480cdf0e10cSrcweir 
2481cdf0e10cSrcweir void PDFWriterImpl::endPage()
2482cdf0e10cSrcweir {
2483cdf0e10cSrcweir     if( m_aPages.begin() != m_aPages.end() )
2484cdf0e10cSrcweir     {
2485cdf0e10cSrcweir         // close eventual MC sequence
2486cdf0e10cSrcweir         endStructureElementMCSeq();
2487cdf0e10cSrcweir 
2488cdf0e10cSrcweir         // sanity check
2489cdf0e10cSrcweir         if( m_aOutputStreams.begin() != m_aOutputStreams.end() )
2490cdf0e10cSrcweir         {
2491cdf0e10cSrcweir             DBG_ERROR( "redirection across pages !!!" );
2492cdf0e10cSrcweir             m_aOutputStreams.clear(); // leak !
2493cdf0e10cSrcweir             m_aMapMode.SetOrigin( Point() );
2494cdf0e10cSrcweir         }
2495cdf0e10cSrcweir 
2496cdf0e10cSrcweir         m_aGraphicsStack.clear();
2497cdf0e10cSrcweir         m_aGraphicsStack.push_back( GraphicsState() );
2498cdf0e10cSrcweir 
2499cdf0e10cSrcweir         // this should pop the PDF graphics stack if necessary
2500cdf0e10cSrcweir         updateGraphicsState();
2501cdf0e10cSrcweir 
2502cdf0e10cSrcweir         m_aPages.back().endStream();
2503cdf0e10cSrcweir 
2504cdf0e10cSrcweir         // reset the default font
2505cdf0e10cSrcweir         Font aFont;
2506cdf0e10cSrcweir         aFont.SetName( String( RTL_CONSTASCII_USTRINGPARAM( "Times" ) ) );
2507cdf0e10cSrcweir         aFont.SetSize( Size( 0, 12 ) );
2508cdf0e10cSrcweir 
2509cdf0e10cSrcweir         m_aCurrentPDFState = m_aGraphicsStack.front();
2510cdf0e10cSrcweir         m_aGraphicsStack.front().m_aFont =  aFont;
2511cdf0e10cSrcweir 
2512cdf0e10cSrcweir         for( std::list<BitmapEmit>::iterator it = m_aBitmaps.begin();
2513cdf0e10cSrcweir              it != m_aBitmaps.end(); ++it )
2514cdf0e10cSrcweir         {
2515cdf0e10cSrcweir             if( ! it->m_aBitmap.IsEmpty() )
2516cdf0e10cSrcweir             {
2517cdf0e10cSrcweir                 writeBitmapObject( *it );
2518cdf0e10cSrcweir                 it->m_aBitmap = BitmapEx();
2519cdf0e10cSrcweir             }
2520cdf0e10cSrcweir         }
2521cdf0e10cSrcweir         for( std::list<JPGEmit>::iterator jpeg = m_aJPGs.begin(); jpeg != m_aJPGs.end(); ++jpeg )
2522cdf0e10cSrcweir         {
2523cdf0e10cSrcweir             if( jpeg->m_pStream )
2524cdf0e10cSrcweir             {
2525cdf0e10cSrcweir                 writeJPG( *jpeg );
2526cdf0e10cSrcweir                 delete jpeg->m_pStream;
2527cdf0e10cSrcweir                 jpeg->m_pStream = NULL;
2528cdf0e10cSrcweir                 jpeg->m_aMask = Bitmap();
2529cdf0e10cSrcweir             }
2530cdf0e10cSrcweir         }
2531cdf0e10cSrcweir         for( std::list<TransparencyEmit>::iterator t = m_aTransparentObjects.begin();
2532cdf0e10cSrcweir              t != m_aTransparentObjects.end(); ++t )
2533cdf0e10cSrcweir         {
2534cdf0e10cSrcweir             if( t->m_pContentStream )
2535cdf0e10cSrcweir             {
2536cdf0e10cSrcweir                 writeTransparentObject( *t );
2537cdf0e10cSrcweir                 delete t->m_pContentStream;
2538cdf0e10cSrcweir                 t->m_pContentStream = NULL;
2539cdf0e10cSrcweir             }
2540cdf0e10cSrcweir         }
2541cdf0e10cSrcweir     }
2542cdf0e10cSrcweir }
2543cdf0e10cSrcweir 
2544cdf0e10cSrcweir sal_Int32 PDFWriterImpl::createObject()
2545cdf0e10cSrcweir {
2546cdf0e10cSrcweir     m_aObjects.push_back( ~0U );
2547cdf0e10cSrcweir     return m_aObjects.size();
2548cdf0e10cSrcweir }
2549cdf0e10cSrcweir 
2550cdf0e10cSrcweir bool PDFWriterImpl::updateObject( sal_Int32 n )
2551cdf0e10cSrcweir {
2552cdf0e10cSrcweir     if( ! m_bOpen )
2553cdf0e10cSrcweir         return false;
2554cdf0e10cSrcweir 
2555cdf0e10cSrcweir     sal_uInt64 nOffset = ~0U;
2556cdf0e10cSrcweir     oslFileError aError = osl_getFilePos( m_aFile, &nOffset );
2557cdf0e10cSrcweir     DBG_ASSERT( aError == osl_File_E_None, "could not register object" );
2558cdf0e10cSrcweir     if( aError != osl_File_E_None )
2559cdf0e10cSrcweir     {
2560cdf0e10cSrcweir         osl_closeFile( m_aFile );
2561cdf0e10cSrcweir         m_bOpen = false;
2562cdf0e10cSrcweir     }
2563cdf0e10cSrcweir     m_aObjects[ n-1 ] = nOffset;
2564cdf0e10cSrcweir     return aError == osl_File_E_None;
2565cdf0e10cSrcweir }
2566cdf0e10cSrcweir 
2567cdf0e10cSrcweir #define CHECK_RETURN( x ) if( !(x) ) return 0
2568cdf0e10cSrcweir 
2569cdf0e10cSrcweir sal_Int32 PDFWriterImpl::emitStructParentTree( sal_Int32 nObject )
2570cdf0e10cSrcweir {
2571cdf0e10cSrcweir     if( nObject > 0 )
2572cdf0e10cSrcweir     {
2573cdf0e10cSrcweir         OStringBuffer aLine( 1024 );
2574cdf0e10cSrcweir 
2575cdf0e10cSrcweir         aLine.append( nObject );
2576cdf0e10cSrcweir         aLine.append( " 0 obj\n"
2577cdf0e10cSrcweir                       "<</Nums[\n" );
2578cdf0e10cSrcweir         sal_Int32 nTreeItems = m_aStructParentTree.size();
2579cdf0e10cSrcweir         for( sal_Int32 n = 0; n < nTreeItems; n++ )
2580cdf0e10cSrcweir         {
2581cdf0e10cSrcweir             aLine.append( n );
2582cdf0e10cSrcweir             aLine.append( ' ' );
2583cdf0e10cSrcweir             aLine.append( m_aStructParentTree[n] );
2584cdf0e10cSrcweir             aLine.append( "\n" );
2585cdf0e10cSrcweir         }
2586cdf0e10cSrcweir         aLine.append( "]>>\nendobj\n\n" );
2587cdf0e10cSrcweir         CHECK_RETURN( updateObject( nObject ) );
2588cdf0e10cSrcweir         CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
2589cdf0e10cSrcweir     }
2590cdf0e10cSrcweir     return nObject;
2591cdf0e10cSrcweir }
2592cdf0e10cSrcweir 
2593cdf0e10cSrcweir const sal_Char* PDFWriterImpl::getAttributeTag( PDFWriter::StructAttribute eAttr )
2594cdf0e10cSrcweir {
2595cdf0e10cSrcweir     static std::map< PDFWriter::StructAttribute, const char* > aAttributeStrings;
2596cdf0e10cSrcweir     // fill maps once
2597cdf0e10cSrcweir     if( aAttributeStrings.empty() )
2598cdf0e10cSrcweir     {
2599cdf0e10cSrcweir         aAttributeStrings[ PDFWriter::Placement ]			= "Placement";
2600cdf0e10cSrcweir         aAttributeStrings[ PDFWriter::WritingMode ]			= "WritingMode";
2601cdf0e10cSrcweir         aAttributeStrings[ PDFWriter::SpaceBefore ]			= "SpaceBefore";
2602cdf0e10cSrcweir         aAttributeStrings[ PDFWriter::SpaceAfter ]			= "SpaceAfter";
2603cdf0e10cSrcweir         aAttributeStrings[ PDFWriter::StartIndent ]			= "StartIndent";
2604cdf0e10cSrcweir         aAttributeStrings[ PDFWriter::EndIndent ]			= "EndIndent";
2605cdf0e10cSrcweir         aAttributeStrings[ PDFWriter::TextIndent ]			= "TextIndent";
2606cdf0e10cSrcweir         aAttributeStrings[ PDFWriter::TextAlign ]			= "TextAlign";
2607cdf0e10cSrcweir         aAttributeStrings[ PDFWriter::Width ]				= "Width";
2608cdf0e10cSrcweir         aAttributeStrings[ PDFWriter::Height ]				= "Height";
2609cdf0e10cSrcweir         aAttributeStrings[ PDFWriter::BlockAlign ]			= "BlockAlign";
2610cdf0e10cSrcweir         aAttributeStrings[ PDFWriter::InlineAlign ]			= "InlineAlign";
2611cdf0e10cSrcweir         aAttributeStrings[ PDFWriter::LineHeight ]			= "LineHeight";
2612cdf0e10cSrcweir         aAttributeStrings[ PDFWriter::BaselineShift ]		= "BaselineShift";
2613cdf0e10cSrcweir         aAttributeStrings[ PDFWriter::TextDecorationType ]	= "TextDecorationType";
2614cdf0e10cSrcweir         aAttributeStrings[ PDFWriter::ListNumbering ]		= "ListNumbering";
2615cdf0e10cSrcweir         aAttributeStrings[ PDFWriter::RowSpan ]				= "RowSpan";
2616cdf0e10cSrcweir         aAttributeStrings[ PDFWriter::ColSpan ]				= "ColSpan";
2617cdf0e10cSrcweir         aAttributeStrings[ PDFWriter::LinkAnnotation ]      = "LinkAnnotation";
2618cdf0e10cSrcweir     }
2619cdf0e10cSrcweir 
2620cdf0e10cSrcweir     std::map< PDFWriter::StructAttribute, const char* >::const_iterator it =
2621cdf0e10cSrcweir         aAttributeStrings.find( eAttr );
2622cdf0e10cSrcweir 
2623cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
2624cdf0e10cSrcweir     if( it == aAttributeStrings.end() )
2625cdf0e10cSrcweir         fprintf( stderr, "invalid PDFWriter::StructAttribute %d\n", eAttr );
2626cdf0e10cSrcweir #endif
2627cdf0e10cSrcweir 
2628cdf0e10cSrcweir     return it != aAttributeStrings.end() ? it->second : "";
2629cdf0e10cSrcweir }
2630cdf0e10cSrcweir 
2631cdf0e10cSrcweir const sal_Char* PDFWriterImpl::getAttributeValueTag( PDFWriter::StructAttributeValue eVal )
2632cdf0e10cSrcweir {
2633cdf0e10cSrcweir     static std::map< PDFWriter::StructAttributeValue, const char* > aValueStrings;
2634cdf0e10cSrcweir 
2635cdf0e10cSrcweir     if( aValueStrings.empty() )
2636cdf0e10cSrcweir     {
2637cdf0e10cSrcweir         aValueStrings[ PDFWriter::NONE ]					= "None";
2638cdf0e10cSrcweir         aValueStrings[ PDFWriter::Block ]					= "Block";
2639cdf0e10cSrcweir         aValueStrings[ PDFWriter::Inline ]					= "Inline";
2640cdf0e10cSrcweir         aValueStrings[ PDFWriter::Before ]					= "Before";
2641cdf0e10cSrcweir         aValueStrings[ PDFWriter::After ]					= "After";
2642cdf0e10cSrcweir         aValueStrings[ PDFWriter::Start ]					= "Start";
2643cdf0e10cSrcweir         aValueStrings[ PDFWriter::End ]						= "End";
2644cdf0e10cSrcweir         aValueStrings[ PDFWriter::LrTb ]					= "LrTb";
2645cdf0e10cSrcweir         aValueStrings[ PDFWriter::RlTb ]					= "RlTb";
2646cdf0e10cSrcweir         aValueStrings[ PDFWriter::TbRl ]					= "TbRl";
2647cdf0e10cSrcweir         aValueStrings[ PDFWriter::Center ]					= "Center";
2648cdf0e10cSrcweir         aValueStrings[ PDFWriter::Justify ]					= "Justify";
2649cdf0e10cSrcweir         aValueStrings[ PDFWriter::Auto ]					= "Auto";
2650cdf0e10cSrcweir         aValueStrings[ PDFWriter::Middle ]					= "Middle";
2651cdf0e10cSrcweir         aValueStrings[ PDFWriter::Normal ]					= "Normal";
2652cdf0e10cSrcweir         aValueStrings[ PDFWriter::Underline ]				= "Underline";
2653cdf0e10cSrcweir 		aValueStrings[ PDFWriter::Overline ]				= "Overline";
2654cdf0e10cSrcweir         aValueStrings[ PDFWriter::LineThrough ]				= "LineThrough";
2655cdf0e10cSrcweir         aValueStrings[ PDFWriter::Disc ]					= "Disc";
2656cdf0e10cSrcweir         aValueStrings[ PDFWriter::Circle ]					= "Circle";
2657cdf0e10cSrcweir         aValueStrings[ PDFWriter::Square ]					= "Square";
2658cdf0e10cSrcweir         aValueStrings[ PDFWriter::Decimal ]					= "Decimal";
2659cdf0e10cSrcweir         aValueStrings[ PDFWriter::UpperRoman ]				= "UpperRoman";
2660cdf0e10cSrcweir         aValueStrings[ PDFWriter::LowerRoman ]				= "LowerRoman";
2661cdf0e10cSrcweir         aValueStrings[ PDFWriter::UpperAlpha ]				= "UpperAlpha";
2662cdf0e10cSrcweir         aValueStrings[ PDFWriter::LowerAlpha ]				= "LowerAlpha";
2663cdf0e10cSrcweir     }
2664cdf0e10cSrcweir 
2665cdf0e10cSrcweir     std::map< PDFWriter::StructAttributeValue, const char* >::const_iterator it =
2666cdf0e10cSrcweir         aValueStrings.find( eVal );
2667cdf0e10cSrcweir 
2668cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
2669cdf0e10cSrcweir     if( it == aValueStrings.end() )
2670cdf0e10cSrcweir         fprintf( stderr, "invalid PDFWriter::StructAttributeValue %d\n", eVal );
2671cdf0e10cSrcweir #endif
2672cdf0e10cSrcweir 
2673cdf0e10cSrcweir     return it != aValueStrings.end() ? it->second : "";
2674cdf0e10cSrcweir }
2675cdf0e10cSrcweir 
2676cdf0e10cSrcweir static void appendStructureAttributeLine( PDFWriter::StructAttribute i_eAttr, const PDFWriterImpl::PDFStructureAttribute& i_rVal, OStringBuffer& o_rLine, bool i_bIsFixedInt )
2677cdf0e10cSrcweir {
2678cdf0e10cSrcweir     o_rLine.append( "/" );
2679cdf0e10cSrcweir     o_rLine.append( PDFWriterImpl::getAttributeTag( i_eAttr ) );
2680cdf0e10cSrcweir 
2681cdf0e10cSrcweir     if( i_rVal.eValue != PDFWriter::Invalid )
2682cdf0e10cSrcweir     {
2683cdf0e10cSrcweir         o_rLine.append( "/" );
2684cdf0e10cSrcweir         o_rLine.append( PDFWriterImpl::getAttributeValueTag( i_rVal.eValue ) );
2685cdf0e10cSrcweir     }
2686cdf0e10cSrcweir     else
2687cdf0e10cSrcweir     {
2688cdf0e10cSrcweir         // numerical value
2689cdf0e10cSrcweir         o_rLine.append( " " );
2690cdf0e10cSrcweir         if( i_bIsFixedInt )
2691cdf0e10cSrcweir             appendFixedInt( i_rVal.nValue, o_rLine );
2692cdf0e10cSrcweir         else
2693cdf0e10cSrcweir             o_rLine.append( i_rVal.nValue );
2694cdf0e10cSrcweir     }
2695cdf0e10cSrcweir     o_rLine.append( "\n" );
2696cdf0e10cSrcweir }
2697cdf0e10cSrcweir 
2698cdf0e10cSrcweir OString PDFWriterImpl::emitStructureAttributes( PDFStructureElement& i_rEle )
2699cdf0e10cSrcweir {
2700cdf0e10cSrcweir     // create layout, list and table attribute sets
2701cdf0e10cSrcweir     OStringBuffer aLayout(256), aList(64), aTable(64);
2702cdf0e10cSrcweir     for( PDFStructAttributes::const_iterator it = i_rEle.m_aAttributes.begin();
2703cdf0e10cSrcweir          it != i_rEle.m_aAttributes.end(); ++it )
2704cdf0e10cSrcweir     {
2705cdf0e10cSrcweir         if( it->first == PDFWriter::ListNumbering )
2706cdf0e10cSrcweir             appendStructureAttributeLine( it->first, it->second, aList, true );
2707cdf0e10cSrcweir         else if( it->first == PDFWriter::RowSpan ||
2708cdf0e10cSrcweir                  it->first == PDFWriter::ColSpan )
2709cdf0e10cSrcweir             appendStructureAttributeLine( it->first, it->second, aTable, false );
2710cdf0e10cSrcweir         else if( it->first == PDFWriter::LinkAnnotation )
2711cdf0e10cSrcweir         {
2712cdf0e10cSrcweir             sal_Int32 nLink = it->second.nValue;
2713cdf0e10cSrcweir             std::map< sal_Int32, sal_Int32 >::const_iterator link_it =
2714cdf0e10cSrcweir                 m_aLinkPropertyMap.find( nLink );
2715cdf0e10cSrcweir             if( link_it != m_aLinkPropertyMap.end() )
2716cdf0e10cSrcweir                 nLink = link_it->second;
2717cdf0e10cSrcweir             if( nLink >= 0 && nLink < (sal_Int32)m_aLinks.size() )
2718cdf0e10cSrcweir             {
2719cdf0e10cSrcweir                 // update struct parent of link
2720cdf0e10cSrcweir                 OStringBuffer aStructParentEntry( 32 );
2721cdf0e10cSrcweir                 aStructParentEntry.append( i_rEle.m_nObject );
2722cdf0e10cSrcweir                 aStructParentEntry.append( " 0 R" );
2723cdf0e10cSrcweir                 m_aStructParentTree.push_back( aStructParentEntry.makeStringAndClear() );
2724cdf0e10cSrcweir                 m_aLinks[ nLink ].m_nStructParent = m_aStructParentTree.size()-1;
2725cdf0e10cSrcweir 
2726cdf0e10cSrcweir                 sal_Int32 nRefObject = createObject();
2727cdf0e10cSrcweir                 OStringBuffer aRef( 256 );
2728cdf0e10cSrcweir                 aRef.append( nRefObject );
2729cdf0e10cSrcweir                 aRef.append( " 0 obj\n"
2730cdf0e10cSrcweir                              "<</Type/OBJR/Obj " );
2731cdf0e10cSrcweir                 aRef.append( m_aLinks[ nLink ].m_nObject );
2732cdf0e10cSrcweir                 aRef.append( " 0 R>>\n"
2733cdf0e10cSrcweir                              "endobj\n\n"
2734cdf0e10cSrcweir                              );
2735cdf0e10cSrcweir                 updateObject( nRefObject );
2736cdf0e10cSrcweir                 writeBuffer( aRef.getStr(), aRef.getLength() );
2737cdf0e10cSrcweir 
2738cdf0e10cSrcweir                 i_rEle.m_aKids.push_back( PDFStructureElementKid( nRefObject ) );
2739cdf0e10cSrcweir             }
2740cdf0e10cSrcweir             else
2741cdf0e10cSrcweir             {
2742cdf0e10cSrcweir                 DBG_ERROR( "unresolved link id for Link structure" );
2743cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
2744cdf0e10cSrcweir                 fprintf( stderr, "unresolved link id %" SAL_PRIdINT32 " for Link structure\n", nLink );
2745cdf0e10cSrcweir                 {
2746cdf0e10cSrcweir                     OStringBuffer aLine( "unresolved link id " );
2747cdf0e10cSrcweir                     aLine.append( nLink );
2748cdf0e10cSrcweir                     aLine.append( " for Link structure" );
2749cdf0e10cSrcweir                     emitComment( aLine.getStr() );
2750cdf0e10cSrcweir                 }
2751cdf0e10cSrcweir #endif
2752cdf0e10cSrcweir             }
2753cdf0e10cSrcweir         }
2754cdf0e10cSrcweir         else
2755cdf0e10cSrcweir             appendStructureAttributeLine( it->first, it->second, aLayout, true );
2756cdf0e10cSrcweir     }
2757cdf0e10cSrcweir     if( ! i_rEle.m_aBBox.IsEmpty() )
2758cdf0e10cSrcweir     {
2759cdf0e10cSrcweir         aLayout.append( "/BBox[" );
2760cdf0e10cSrcweir         appendFixedInt( i_rEle.m_aBBox.Left(), aLayout );
2761cdf0e10cSrcweir         aLayout.append( " " );
2762cdf0e10cSrcweir         appendFixedInt( i_rEle.m_aBBox.Top(), aLayout );
2763cdf0e10cSrcweir         aLayout.append( " " );
2764cdf0e10cSrcweir         appendFixedInt( i_rEle.m_aBBox.Right(), aLayout );
2765cdf0e10cSrcweir         aLayout.append( " " );
2766cdf0e10cSrcweir         appendFixedInt( i_rEle.m_aBBox.Bottom(), aLayout );
2767cdf0e10cSrcweir         aLayout.append( "]\n" );
2768cdf0e10cSrcweir     }
2769cdf0e10cSrcweir 
2770cdf0e10cSrcweir     std::vector< sal_Int32 > aAttribObjects;
2771cdf0e10cSrcweir     if( aLayout.getLength() )
2772cdf0e10cSrcweir     {
2773cdf0e10cSrcweir         aAttribObjects.push_back( createObject() );
2774cdf0e10cSrcweir         updateObject( aAttribObjects.back() );
2775cdf0e10cSrcweir         OStringBuffer aObj( 64 );
2776cdf0e10cSrcweir         aObj.append( aAttribObjects.back() );
2777cdf0e10cSrcweir         aObj.append( " 0 obj\n"
2778cdf0e10cSrcweir                      "<</O/Layout\n" );
2779cdf0e10cSrcweir         aLayout.append( ">>\nendobj\n\n" );
2780cdf0e10cSrcweir         writeBuffer( aObj.getStr(), aObj.getLength() );
2781cdf0e10cSrcweir         writeBuffer( aLayout.getStr(), aLayout.getLength() );
2782cdf0e10cSrcweir     }
2783cdf0e10cSrcweir     if( aList.getLength() )
2784cdf0e10cSrcweir     {
2785cdf0e10cSrcweir         aAttribObjects.push_back( createObject() );
2786cdf0e10cSrcweir         updateObject( aAttribObjects.back() );
2787cdf0e10cSrcweir         OStringBuffer aObj( 64 );
2788cdf0e10cSrcweir         aObj.append( aAttribObjects.back() );
2789cdf0e10cSrcweir         aObj.append( " 0 obj\n"
2790cdf0e10cSrcweir                      "<</O/List\n" );
2791cdf0e10cSrcweir         aList.append( ">>\nendobj\n\n" );
2792cdf0e10cSrcweir         writeBuffer( aObj.getStr(), aObj.getLength() );
2793cdf0e10cSrcweir         writeBuffer( aList.getStr(), aList.getLength() );
2794cdf0e10cSrcweir     }
2795cdf0e10cSrcweir     if( aTable.getLength() )
2796cdf0e10cSrcweir     {
2797cdf0e10cSrcweir         aAttribObjects.push_back( createObject() );
2798cdf0e10cSrcweir         updateObject( aAttribObjects.back() );
2799cdf0e10cSrcweir         OStringBuffer aObj( 64 );
2800cdf0e10cSrcweir         aObj.append( aAttribObjects.back() );
2801cdf0e10cSrcweir         aObj.append( " 0 obj\n"
2802cdf0e10cSrcweir                      "<</O/Table\n" );
2803cdf0e10cSrcweir         aTable.append( ">>\nendobj\n\n" );
2804cdf0e10cSrcweir         writeBuffer( aObj.getStr(), aObj.getLength() );
2805cdf0e10cSrcweir         writeBuffer( aTable.getStr(), aTable.getLength() );
2806cdf0e10cSrcweir     }
2807cdf0e10cSrcweir 
2808cdf0e10cSrcweir     OStringBuffer aRet( 64 );
2809cdf0e10cSrcweir     if( aAttribObjects.size() > 1 )
2810cdf0e10cSrcweir         aRet.append( " [" );
2811cdf0e10cSrcweir     for( std::vector< sal_Int32 >::const_iterator at_it = aAttribObjects.begin();
2812cdf0e10cSrcweir          at_it != aAttribObjects.end(); ++at_it )
2813cdf0e10cSrcweir     {
2814cdf0e10cSrcweir         aRet.append( " " );
2815cdf0e10cSrcweir         aRet.append( *at_it );
2816cdf0e10cSrcweir         aRet.append( " 0 R" );
2817cdf0e10cSrcweir     }
2818cdf0e10cSrcweir     if( aAttribObjects.size() > 1 )
2819cdf0e10cSrcweir         aRet.append( " ]" );
2820cdf0e10cSrcweir     return aRet.makeStringAndClear();
2821cdf0e10cSrcweir }
2822cdf0e10cSrcweir 
2823cdf0e10cSrcweir sal_Int32 PDFWriterImpl::emitStructure( PDFStructureElement& rEle )
2824cdf0e10cSrcweir {
2825cdf0e10cSrcweir     if(
2826cdf0e10cSrcweir        // do not emit NonStruct and its children
2827cdf0e10cSrcweir        rEle.m_eType == PDFWriter::NonStructElement &&
2828cdf0e10cSrcweir        rEle.m_nOwnElement != rEle.m_nParentElement // but of course emit the struct tree root
2829cdf0e10cSrcweir        )
2830cdf0e10cSrcweir         return 0;
2831cdf0e10cSrcweir 
2832cdf0e10cSrcweir     for( std::list< sal_Int32 >::const_iterator it = rEle.m_aChildren.begin(); it != rEle.m_aChildren.end(); ++it )
2833cdf0e10cSrcweir     {
2834cdf0e10cSrcweir         if( *it > 0 && *it < sal_Int32(m_aStructure.size()) )
2835cdf0e10cSrcweir         {
2836cdf0e10cSrcweir             PDFStructureElement& rChild = m_aStructure[ *it ];
2837cdf0e10cSrcweir             if( rChild.m_eType != PDFWriter::NonStructElement )
2838cdf0e10cSrcweir             {
2839cdf0e10cSrcweir                 if( rChild.m_nParentElement == rEle.m_nOwnElement )
2840cdf0e10cSrcweir                     emitStructure( rChild );
2841cdf0e10cSrcweir                 else
2842cdf0e10cSrcweir                 {
2843cdf0e10cSrcweir                     DBG_ERROR( "PDFWriterImpl::emitStructure: invalid child structure element" );
2844cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
2845cdf0e10cSrcweir                     fprintf( stderr, "PDFWriterImpl::emitStructure: invalid child structure elemnt with id %" SAL_PRIdINT32 "\n", *it );
2846cdf0e10cSrcweir #endif
2847cdf0e10cSrcweir                 }
2848cdf0e10cSrcweir             }
2849cdf0e10cSrcweir         }
2850cdf0e10cSrcweir         else
2851cdf0e10cSrcweir         {
2852cdf0e10cSrcweir             DBG_ERROR( "PDFWriterImpl::emitStructure: invalid child structure id" );
2853cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
2854cdf0e10cSrcweir             fprintf( stderr, "PDFWriterImpl::emitStructure: invalid child structure id %" SAL_PRIdINT32 "\n", *it );
2855cdf0e10cSrcweir #endif
2856cdf0e10cSrcweir         }
2857cdf0e10cSrcweir     }
2858cdf0e10cSrcweir 
2859cdf0e10cSrcweir     OStringBuffer aLine( 512 );
2860cdf0e10cSrcweir     aLine.append( rEle.m_nObject );
2861cdf0e10cSrcweir     aLine.append( " 0 obj\n"
2862cdf0e10cSrcweir                   "<</Type" );
2863cdf0e10cSrcweir     sal_Int32 nParentTree = -1;
2864cdf0e10cSrcweir     if( rEle.m_nOwnElement == rEle.m_nParentElement )
2865cdf0e10cSrcweir     {
2866cdf0e10cSrcweir         nParentTree = createObject();
2867cdf0e10cSrcweir         CHECK_RETURN( nParentTree );
2868cdf0e10cSrcweir         aLine.append( "/StructTreeRoot\n" );
2869cdf0e10cSrcweir         aLine.append( "/ParentTree " );
2870cdf0e10cSrcweir         aLine.append( nParentTree );
2871cdf0e10cSrcweir         aLine.append( " 0 R\n" );
2872cdf0e10cSrcweir         if( ! m_aRoleMap.empty() )
2873cdf0e10cSrcweir         {
2874cdf0e10cSrcweir             aLine.append( "/RoleMap<<" );
2875cdf0e10cSrcweir             for( std::hash_map<OString,OString,OStringHash>::const_iterator
2876cdf0e10cSrcweir                  it = m_aRoleMap.begin(); it != m_aRoleMap.end(); ++it )
2877cdf0e10cSrcweir             {
2878cdf0e10cSrcweir                 aLine.append( '/' );
2879cdf0e10cSrcweir                 aLine.append(it->first);
2880cdf0e10cSrcweir                 aLine.append( '/' );
2881cdf0e10cSrcweir                 aLine.append( it->second );
2882cdf0e10cSrcweir                 aLine.append( '\n' );
2883cdf0e10cSrcweir             }
2884cdf0e10cSrcweir             aLine.append( ">>\n" );
2885cdf0e10cSrcweir         }
2886cdf0e10cSrcweir     }
2887cdf0e10cSrcweir     else
2888cdf0e10cSrcweir     {
2889cdf0e10cSrcweir         aLine.append( "/StructElem\n"
2890cdf0e10cSrcweir                       "/S/" );
2891cdf0e10cSrcweir         if( rEle.m_aAlias.getLength() > 0 )
2892cdf0e10cSrcweir             aLine.append( rEle.m_aAlias );
2893cdf0e10cSrcweir         else
2894cdf0e10cSrcweir             aLine.append( getStructureTag( rEle.m_eType ) );
2895cdf0e10cSrcweir         aLine.append( "\n"
2896cdf0e10cSrcweir                       "/P " );
2897cdf0e10cSrcweir         aLine.append( m_aStructure[ rEle.m_nParentElement ].m_nObject );
2898cdf0e10cSrcweir         aLine.append( " 0 R\n"
2899cdf0e10cSrcweir                       "/Pg " );
2900cdf0e10cSrcweir         aLine.append( rEle.m_nFirstPageObject );
2901cdf0e10cSrcweir         aLine.append( " 0 R\n" );
2902cdf0e10cSrcweir         if( rEle.m_aActualText.getLength() )
2903cdf0e10cSrcweir         {
2904cdf0e10cSrcweir             aLine.append( "/ActualText" );
2905cdf0e10cSrcweir             appendUnicodeTextStringEncrypt( rEle.m_aActualText, rEle.m_nObject, aLine );
2906cdf0e10cSrcweir             aLine.append( "\n" );
2907cdf0e10cSrcweir         }
2908cdf0e10cSrcweir         if( rEle.m_aAltText.getLength() )
2909cdf0e10cSrcweir         {
2910cdf0e10cSrcweir             aLine.append( "/Alt" );
2911cdf0e10cSrcweir             appendUnicodeTextStringEncrypt( rEle.m_aAltText, rEle.m_nObject, aLine );
2912cdf0e10cSrcweir             aLine.append( "\n" );
2913cdf0e10cSrcweir         }
2914cdf0e10cSrcweir     }
2915cdf0e10cSrcweir     if( ! rEle.m_aBBox.IsEmpty() || rEle.m_aAttributes.size() )
2916cdf0e10cSrcweir     {
2917cdf0e10cSrcweir         OString aAttribs =  emitStructureAttributes( rEle );
2918cdf0e10cSrcweir         if( aAttribs.getLength() )
2919cdf0e10cSrcweir         {
2920cdf0e10cSrcweir             aLine.append( "/A" );
2921cdf0e10cSrcweir             aLine.append( aAttribs );
2922cdf0e10cSrcweir             aLine.append( "\n" );
2923cdf0e10cSrcweir         }
2924cdf0e10cSrcweir     }
2925cdf0e10cSrcweir     if( rEle.m_aLocale.Language.getLength() > 0 )
2926cdf0e10cSrcweir     {
2927cdf0e10cSrcweir         OUStringBuffer aLocBuf( 16 );
2928cdf0e10cSrcweir         aLocBuf.append( rEle.m_aLocale.Language.toAsciiLowerCase() );
2929cdf0e10cSrcweir         if( rEle.m_aLocale.Country.getLength() > 0 )
2930cdf0e10cSrcweir         {
2931cdf0e10cSrcweir             aLocBuf.append( sal_Unicode('-') );
2932cdf0e10cSrcweir             aLocBuf.append( rEle.m_aLocale.Country );
2933cdf0e10cSrcweir         }
2934cdf0e10cSrcweir         aLine.append( "/Lang" );
2935cdf0e10cSrcweir         appendLiteralStringEncrypt( aLocBuf.makeStringAndClear(), rEle.m_nObject, aLine );
2936cdf0e10cSrcweir         aLine.append( "\n" );
2937cdf0e10cSrcweir     }
2938cdf0e10cSrcweir     if( ! rEle.m_aKids.empty() )
2939cdf0e10cSrcweir     {
2940cdf0e10cSrcweir         unsigned int i = 0;
2941cdf0e10cSrcweir         aLine.append( "/K[" );
2942cdf0e10cSrcweir         for( std::list< PDFStructureElementKid >::const_iterator it =
2943cdf0e10cSrcweir                  rEle.m_aKids.begin(); it != rEle.m_aKids.end(); ++it, i++ )
2944cdf0e10cSrcweir         {
2945cdf0e10cSrcweir             if( it->nMCID == -1 )
2946cdf0e10cSrcweir             {
2947cdf0e10cSrcweir                 aLine.append( it->nObject );
2948cdf0e10cSrcweir                 aLine.append( " 0 R" );
2949cdf0e10cSrcweir                 aLine.append( ( (i & 15) == 15 ) ? "\n" : " " );
2950cdf0e10cSrcweir             }
2951cdf0e10cSrcweir             else
2952cdf0e10cSrcweir             {
2953cdf0e10cSrcweir                 if( it->nObject == rEle.m_nFirstPageObject )
2954cdf0e10cSrcweir                 {
2955cdf0e10cSrcweir                     aLine.append( it->nMCID );
2956cdf0e10cSrcweir                     aLine.append( " " );
2957cdf0e10cSrcweir                 }
2958cdf0e10cSrcweir                 else
2959cdf0e10cSrcweir                 {
2960cdf0e10cSrcweir                     aLine.append( "<</Type/MCR/Pg " );
2961cdf0e10cSrcweir                     aLine.append( it->nObject );
2962cdf0e10cSrcweir                     aLine.append( " 0 R /MCID " );
2963cdf0e10cSrcweir                     aLine.append( it->nMCID );
2964cdf0e10cSrcweir                     aLine.append( ">>\n" );
2965cdf0e10cSrcweir                 }
2966cdf0e10cSrcweir             }
2967cdf0e10cSrcweir         }
2968cdf0e10cSrcweir         aLine.append( "]\n" );
2969cdf0e10cSrcweir     }
2970cdf0e10cSrcweir     aLine.append( ">>\nendobj\n\n" );
2971cdf0e10cSrcweir 
2972cdf0e10cSrcweir     CHECK_RETURN( updateObject( rEle.m_nObject ) );
2973cdf0e10cSrcweir     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
2974cdf0e10cSrcweir 
2975cdf0e10cSrcweir     CHECK_RETURN( emitStructParentTree( nParentTree ) );
2976cdf0e10cSrcweir 
2977cdf0e10cSrcweir     return rEle.m_nObject;
2978cdf0e10cSrcweir }
2979cdf0e10cSrcweir 
2980cdf0e10cSrcweir bool PDFWriterImpl::emitGradients()
2981cdf0e10cSrcweir {
2982cdf0e10cSrcweir     for( std::list<GradientEmit>::iterator it = m_aGradients.begin();
2983cdf0e10cSrcweir          it != m_aGradients.end(); ++it )
2984cdf0e10cSrcweir     {
2985cdf0e10cSrcweir         CHECK_RETURN( writeGradientFunction( *it ) );
2986cdf0e10cSrcweir     }
2987cdf0e10cSrcweir     return true;
2988cdf0e10cSrcweir }
2989cdf0e10cSrcweir 
2990cdf0e10cSrcweir bool PDFWriterImpl::emitTilings()
2991cdf0e10cSrcweir {
2992cdf0e10cSrcweir     OStringBuffer aTilingObj( 1024 );
2993cdf0e10cSrcweir 
2994cdf0e10cSrcweir     for( std::vector<TilingEmit>::iterator it = m_aTilings.begin(); it != m_aTilings.end(); ++it )
2995cdf0e10cSrcweir     {
2996cdf0e10cSrcweir         DBG_ASSERT( it->m_pTilingStream, "tiling without stream" );
2997cdf0e10cSrcweir         if( ! it->m_pTilingStream )
2998cdf0e10cSrcweir             continue;
2999cdf0e10cSrcweir 
3000cdf0e10cSrcweir         aTilingObj.setLength( 0 );
3001cdf0e10cSrcweir 
3002cdf0e10cSrcweir         #if OSL_DEBUG_LEVEL > 1
3003cdf0e10cSrcweir         emitComment( "PDFWriterImpl::emitTilings" );
3004cdf0e10cSrcweir         #endif
3005cdf0e10cSrcweir 
3006cdf0e10cSrcweir         sal_Int32 nX = (sal_Int32)it->m_aRectangle.Left();
3007cdf0e10cSrcweir         sal_Int32 nY = (sal_Int32)it->m_aRectangle.Top();
3008cdf0e10cSrcweir         sal_Int32 nW = (sal_Int32)it->m_aRectangle.GetWidth();
3009cdf0e10cSrcweir         sal_Int32 nH = (sal_Int32)it->m_aRectangle.GetHeight();
3010cdf0e10cSrcweir         if( it->m_aCellSize.Width() == 0 )
3011cdf0e10cSrcweir             it->m_aCellSize.Width() = nW;
3012cdf0e10cSrcweir         if( it->m_aCellSize.Height() == 0 )
3013cdf0e10cSrcweir             it->m_aCellSize.Height() = nH;
3014cdf0e10cSrcweir 
3015cdf0e10cSrcweir         bool bDeflate = compressStream( it->m_pTilingStream );
3016cdf0e10cSrcweir         it->m_pTilingStream->Seek( STREAM_SEEK_TO_END );
3017cdf0e10cSrcweir         sal_Size nTilingStreamSize = it->m_pTilingStream->Tell();
3018cdf0e10cSrcweir         it->m_pTilingStream->Seek( STREAM_SEEK_TO_BEGIN );
3019cdf0e10cSrcweir 
3020cdf0e10cSrcweir         // write pattern object
3021cdf0e10cSrcweir         aTilingObj.append( it->m_nObject );
3022cdf0e10cSrcweir         aTilingObj.append( " 0 obj\n" );
3023cdf0e10cSrcweir         aTilingObj.append( "<</Type/Pattern/PatternType 1\n"
3024cdf0e10cSrcweir                            "/PaintType 1\n"
3025cdf0e10cSrcweir                            "/TilingType 2\n"
3026cdf0e10cSrcweir                            "/BBox[" );
3027cdf0e10cSrcweir         appendFixedInt( nX, aTilingObj );
3028cdf0e10cSrcweir         aTilingObj.append( ' ' );
3029cdf0e10cSrcweir         appendFixedInt( nY, aTilingObj );
3030cdf0e10cSrcweir         aTilingObj.append( ' ' );
3031cdf0e10cSrcweir         appendFixedInt( nX+nW, aTilingObj );
3032cdf0e10cSrcweir         aTilingObj.append( ' ' );
3033cdf0e10cSrcweir         appendFixedInt( nY+nH, aTilingObj );
3034cdf0e10cSrcweir         aTilingObj.append( "]\n"
3035cdf0e10cSrcweir                            "/XStep " );
3036cdf0e10cSrcweir         appendFixedInt( it->m_aCellSize.Width(), aTilingObj );
3037cdf0e10cSrcweir         aTilingObj.append( "\n"
3038cdf0e10cSrcweir                            "/YStep " );
3039cdf0e10cSrcweir         appendFixedInt( it->m_aCellSize.Height(), aTilingObj );
3040cdf0e10cSrcweir         aTilingObj.append( "\n" );
3041cdf0e10cSrcweir         if( it->m_aTransform.matrix[0] != 1.0 ||
3042cdf0e10cSrcweir             it->m_aTransform.matrix[1] != 0.0 ||
3043cdf0e10cSrcweir             it->m_aTransform.matrix[3] != 0.0 ||
3044cdf0e10cSrcweir             it->m_aTransform.matrix[4] != 1.0 ||
3045cdf0e10cSrcweir             it->m_aTransform.matrix[2] != 0.0 ||
3046cdf0e10cSrcweir             it->m_aTransform.matrix[5] != 0.0 )
3047cdf0e10cSrcweir         {
3048cdf0e10cSrcweir             aTilingObj.append( "/Matrix [" );
3049cdf0e10cSrcweir             // TODO: scaling, mirroring on y, etc
3050cdf0e10cSrcweir             appendDouble( it->m_aTransform.matrix[0], aTilingObj );
3051cdf0e10cSrcweir             aTilingObj.append( ' ' );
3052cdf0e10cSrcweir             appendDouble( it->m_aTransform.matrix[1], aTilingObj );
3053cdf0e10cSrcweir             aTilingObj.append( ' ' );
3054cdf0e10cSrcweir             appendDouble( it->m_aTransform.matrix[3], aTilingObj );
3055cdf0e10cSrcweir             aTilingObj.append( ' ' );
3056cdf0e10cSrcweir             appendDouble( it->m_aTransform.matrix[4], aTilingObj );
3057cdf0e10cSrcweir             aTilingObj.append( ' ' );
3058cdf0e10cSrcweir             appendDouble( it->m_aTransform.matrix[2], aTilingObj );
3059cdf0e10cSrcweir             aTilingObj.append( ' ' );
3060cdf0e10cSrcweir             appendDouble( it->m_aTransform.matrix[5], aTilingObj );
3061cdf0e10cSrcweir             aTilingObj.append( "]\n" );
3062cdf0e10cSrcweir         }
3063cdf0e10cSrcweir         aTilingObj.append( "/Resources" );
3064cdf0e10cSrcweir         it->m_aResources.append( aTilingObj, getFontDictObject() );
3065cdf0e10cSrcweir         if( bDeflate )
3066cdf0e10cSrcweir             aTilingObj.append( "/Filter/FlateDecode" );
3067cdf0e10cSrcweir         aTilingObj.append( "/Length " );
3068cdf0e10cSrcweir         aTilingObj.append( (sal_Int32)nTilingStreamSize );
3069cdf0e10cSrcweir         aTilingObj.append( ">>\nstream\n" );
3070cdf0e10cSrcweir         CHECK_RETURN( updateObject( it->m_nObject ) );
3071cdf0e10cSrcweir         CHECK_RETURN( writeBuffer( aTilingObj.getStr(), aTilingObj.getLength() ) );
3072cdf0e10cSrcweir         checkAndEnableStreamEncryption( it->m_nObject );
3073cdf0e10cSrcweir         nTilingStreamSize = writeBuffer( it->m_pTilingStream->GetData(), nTilingStreamSize );
3074cdf0e10cSrcweir         delete it->m_pTilingStream;
3075cdf0e10cSrcweir         it->m_pTilingStream = NULL;
3076cdf0e10cSrcweir         if( nTilingStreamSize == 0 )
3077cdf0e10cSrcweir             return false;
3078cdf0e10cSrcweir         disableStreamEncryption();
3079cdf0e10cSrcweir         aTilingObj.setLength( 0 );
3080cdf0e10cSrcweir         aTilingObj.append( "\nendstream\nendobj\n\n" );
3081cdf0e10cSrcweir         CHECK_RETURN( writeBuffer( aTilingObj.getStr(), aTilingObj.getLength() ) );
3082cdf0e10cSrcweir     }
3083cdf0e10cSrcweir     return true;
3084cdf0e10cSrcweir }
3085cdf0e10cSrcweir 
3086cdf0e10cSrcweir sal_Int32 PDFWriterImpl::emitBuiltinFont( const ImplFontData* pFont, sal_Int32 nFontObject )
3087cdf0e10cSrcweir {
3088cdf0e10cSrcweir     const ImplPdfBuiltinFontData* pFD = GetPdfFontData( pFont );
3089cdf0e10cSrcweir     if( !pFD )
3090cdf0e10cSrcweir         return 0;
3091cdf0e10cSrcweir     const BuiltinFont* pBuiltinFont = pFD->GetBuiltinFont();
3092cdf0e10cSrcweir 
3093cdf0e10cSrcweir     OStringBuffer aLine( 1024 );
3094cdf0e10cSrcweir 
3095cdf0e10cSrcweir     if( nFontObject <= 0 )
3096cdf0e10cSrcweir         nFontObject = createObject();
3097cdf0e10cSrcweir     CHECK_RETURN( updateObject( nFontObject ) );
3098cdf0e10cSrcweir     aLine.append( nFontObject );
3099cdf0e10cSrcweir     aLine.append( " 0 obj\n"
3100cdf0e10cSrcweir                   "<</Type/Font/Subtype/Type1/BaseFont/" );
3101cdf0e10cSrcweir     appendName( pBuiltinFont->m_pPSName, aLine );
3102cdf0e10cSrcweir     aLine.append( "\n" );
3103cdf0e10cSrcweir     if( pBuiltinFont->m_eCharSet == RTL_TEXTENCODING_MS_1252 )
3104cdf0e10cSrcweir          aLine.append( "/Encoding/WinAnsiEncoding\n" );
3105cdf0e10cSrcweir     aLine.append( ">>\nendobj\n\n" );
3106cdf0e10cSrcweir     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
3107cdf0e10cSrcweir     return nFontObject;
3108cdf0e10cSrcweir }
3109cdf0e10cSrcweir 
3110cdf0e10cSrcweir std::map< sal_Int32, sal_Int32 > PDFWriterImpl::emitSystemFont( const ImplFontData* pFont, EmbedFont& rEmbed )
3111cdf0e10cSrcweir {
3112cdf0e10cSrcweir     std::map< sal_Int32, sal_Int32 > aRet;
3113cdf0e10cSrcweir     if( isBuiltinFont( pFont ) )
3114cdf0e10cSrcweir     {
3115cdf0e10cSrcweir         aRet[ rEmbed.m_nNormalFontID ] = emitBuiltinFont( pFont );
3116cdf0e10cSrcweir         return aRet;
3117cdf0e10cSrcweir     }
3118cdf0e10cSrcweir 
3119cdf0e10cSrcweir     sal_Int32 nFontObject = 0;
3120cdf0e10cSrcweir     sal_Int32 nFontDescriptor = 0;
3121cdf0e10cSrcweir     rtl::OString aSubType( "/Type1" );
3122cdf0e10cSrcweir     FontSubsetInfo aInfo;
3123cdf0e10cSrcweir     // fill in dummy values
3124cdf0e10cSrcweir     aInfo.m_nAscent = 1000;
3125cdf0e10cSrcweir 	aInfo.m_nDescent = 200;
3126cdf0e10cSrcweir 	aInfo.m_nCapHeight = 1000;
3127cdf0e10cSrcweir 	aInfo.m_aFontBBox = Rectangle( Point( -200, -200 ), Size( 1700, 1700 ) );
3128cdf0e10cSrcweir     aInfo.m_aPSName = pFont->maName;
3129cdf0e10cSrcweir     sal_Int32 pWidths[256];
3130cdf0e10cSrcweir     rtl_zeroMemory( pWidths, sizeof(pWidths) );
3131cdf0e10cSrcweir     if( pFont->IsEmbeddable() )
3132cdf0e10cSrcweir     {
3133cdf0e10cSrcweir         const unsigned char* pFontData = NULL;
3134cdf0e10cSrcweir         long nFontLen = 0;
3135cdf0e10cSrcweir         sal_Ucs nEncodedCodes[256];
3136cdf0e10cSrcweir         sal_Int32 pEncWidths[256];
3137cdf0e10cSrcweir         if( (pFontData = (const unsigned char*)m_pReferenceDevice->mpGraphics->GetEmbedFontData( pFont, nEncodedCodes, pEncWidths, aInfo, &nFontLen )) != NULL )
3138cdf0e10cSrcweir         {
3139cdf0e10cSrcweir             m_pReferenceDevice->mpGraphics->FreeEmbedFontData( pFontData, nFontLen );
3140cdf0e10cSrcweir             for( int i = 0; i < 256; i++ )
3141cdf0e10cSrcweir             {
3142cdf0e10cSrcweir                 if( nEncodedCodes[i] >= 32 && nEncodedCodes[i] < 256 )
3143cdf0e10cSrcweir                 {
3144cdf0e10cSrcweir                     pWidths[i] = pEncWidths[ i ];
3145cdf0e10cSrcweir                 }
3146cdf0e10cSrcweir             }
3147cdf0e10cSrcweir         }
3148cdf0e10cSrcweir     }
3149cdf0e10cSrcweir     else if( pFont->mbSubsettable )
3150cdf0e10cSrcweir     {
3151cdf0e10cSrcweir         aSubType = rtl::OString( "/TrueType" );
3152cdf0e10cSrcweir         Int32Vector aGlyphWidths;
3153cdf0e10cSrcweir         Ucs2UIntMap aUnicodeMap;
3154cdf0e10cSrcweir         m_pReferenceDevice->mpGraphics->GetGlyphWidths( pFont, false, aGlyphWidths, aUnicodeMap );
3155cdf0e10cSrcweir 
3156cdf0e10cSrcweir         OUString aTmpName;
3157cdf0e10cSrcweir         osl_createTempFile( NULL, NULL, &aTmpName.pData );
3158cdf0e10cSrcweir         sal_Int32 pGlyphIDs[ 256 ];
3159cdf0e10cSrcweir         sal_uInt8 pEncoding[ 256 ];
3160cdf0e10cSrcweir         sal_Ucs   pUnicodes[ 256 ];
3161cdf0e10cSrcweir         sal_Int32 pDuWidths[ 256 ];
3162cdf0e10cSrcweir 
3163cdf0e10cSrcweir         memset( pGlyphIDs, 0, sizeof( pGlyphIDs ) );
3164cdf0e10cSrcweir         memset( pEncoding, 0, sizeof( pEncoding ) );
3165cdf0e10cSrcweir         memset( pUnicodes, 0, sizeof( pUnicodes ) );
3166cdf0e10cSrcweir         memset( pDuWidths, 0, sizeof( pDuWidths ) );
3167cdf0e10cSrcweir 
3168cdf0e10cSrcweir         for( sal_Ucs c = 32; c < 256; c++ )
3169cdf0e10cSrcweir         {
3170cdf0e10cSrcweir             pUnicodes[c] = c;
3171cdf0e10cSrcweir             pEncoding[c] = c;
3172cdf0e10cSrcweir             pGlyphIDs[c] = 0;
3173cdf0e10cSrcweir             if( aUnicodeMap.find( c ) != aUnicodeMap.end() )
3174cdf0e10cSrcweir                 pWidths[ c ] = aGlyphWidths[ aUnicodeMap[ c ] ];
3175cdf0e10cSrcweir         }
3176cdf0e10cSrcweir 
3177cdf0e10cSrcweir         m_pReferenceDevice->mpGraphics->CreateFontSubset( aTmpName, pFont, pGlyphIDs, pEncoding, pDuWidths, 256, aInfo );
3178cdf0e10cSrcweir         osl_removeFile( aTmpName.pData );
3179cdf0e10cSrcweir     }
3180cdf0e10cSrcweir     else
3181cdf0e10cSrcweir     {
3182cdf0e10cSrcweir         DBG_ERROR( "system font neither embeddable nor subsettable" );
3183cdf0e10cSrcweir     }
3184cdf0e10cSrcweir 
3185cdf0e10cSrcweir     // write font descriptor
3186cdf0e10cSrcweir     nFontDescriptor = emitFontDescriptor( pFont, aInfo, 0, 0 );
3187cdf0e10cSrcweir     if( nFontDescriptor )
3188cdf0e10cSrcweir     {
3189cdf0e10cSrcweir         // write font object
3190cdf0e10cSrcweir         sal_Int32 nObject = createObject();
3191cdf0e10cSrcweir         if( updateObject( nObject ) )
3192cdf0e10cSrcweir         {
3193cdf0e10cSrcweir             OStringBuffer aLine( 1024 );
3194cdf0e10cSrcweir             aLine.append( nObject );
3195cdf0e10cSrcweir             aLine.append( " 0 obj\n"
3196cdf0e10cSrcweir                           "<</Type/Font/Subtype" );
3197cdf0e10cSrcweir             aLine.append( aSubType );
3198cdf0e10cSrcweir             aLine.append( "/BaseFont/" );
3199cdf0e10cSrcweir             appendName( aInfo.m_aPSName, aLine );
3200cdf0e10cSrcweir             aLine.append( "\n" );
3201cdf0e10cSrcweir             if( !pFont->mbSymbolFlag )
3202cdf0e10cSrcweir                 aLine.append( "/Encoding/WinAnsiEncoding\n" );
3203cdf0e10cSrcweir             aLine.append( "/FirstChar 32 /LastChar 255\n"
3204cdf0e10cSrcweir                           "/Widths[" );
3205cdf0e10cSrcweir             for( int i = 32; i < 256; i++ )
3206cdf0e10cSrcweir             {
3207cdf0e10cSrcweir                 aLine.append( pWidths[i] );
3208cdf0e10cSrcweir                 aLine.append( ((i&15) == 15) ? "\n" : " " );
3209cdf0e10cSrcweir             }
3210cdf0e10cSrcweir             aLine.append( "]\n"
3211cdf0e10cSrcweir                           "/FontDescriptor " );
3212cdf0e10cSrcweir             aLine.append( nFontDescriptor );
3213cdf0e10cSrcweir             aLine.append( " 0 R>>\n"
3214cdf0e10cSrcweir                           "endobj\n\n" );
3215cdf0e10cSrcweir             writeBuffer( aLine.getStr(), aLine.getLength() );
3216cdf0e10cSrcweir 
3217cdf0e10cSrcweir             nFontObject = nObject;
3218cdf0e10cSrcweir             aRet[ rEmbed.m_nNormalFontID ] = nObject;
3219cdf0e10cSrcweir         }
3220cdf0e10cSrcweir     }
3221cdf0e10cSrcweir 
3222cdf0e10cSrcweir     return aRet;
3223cdf0e10cSrcweir }
3224cdf0e10cSrcweir 
3225cdf0e10cSrcweir typedef int ThreeInts[3];
3226cdf0e10cSrcweir static bool getPfbSegmentLengths( const unsigned char* pFontBytes, int nByteLen,
3227cdf0e10cSrcweir 	ThreeInts& rSegmentLengths )
3228cdf0e10cSrcweir {
3229cdf0e10cSrcweir 	if( !pFontBytes || (nByteLen < 0) )
3230cdf0e10cSrcweir 		return false;
3231cdf0e10cSrcweir 	const unsigned char* pPtr = pFontBytes;
3232cdf0e10cSrcweir 	const unsigned char* pEnd = pFontBytes + nByteLen;
3233cdf0e10cSrcweir 
3234cdf0e10cSrcweir 	for( int i = 0; i < 3; ++i) {
3235cdf0e10cSrcweir 		// read segment1 header
3236cdf0e10cSrcweir 		if( pPtr+6 >= pEnd )
3237cdf0e10cSrcweir 			return false;
3238cdf0e10cSrcweir 		if( (pPtr[0] != 0x80) || (pPtr[1] >= 0x03) )
3239cdf0e10cSrcweir 			return false;
3240cdf0e10cSrcweir 		const int nLen = (pPtr[5]<<24) + (pPtr[4]<<16) + (pPtr[3]<<8) + pPtr[2];
3241cdf0e10cSrcweir 		if( nLen <= 0)
3242cdf0e10cSrcweir 			return false;
3243cdf0e10cSrcweir 		rSegmentLengths[i] = nLen;
3244cdf0e10cSrcweir 		pPtr += nLen + 6;
3245cdf0e10cSrcweir 	}
3246cdf0e10cSrcweir 
3247cdf0e10cSrcweir 	// read segment-end header
3248cdf0e10cSrcweir 	if( pPtr+2 >= pEnd )
3249cdf0e10cSrcweir 		return false;
3250cdf0e10cSrcweir 	if( (pPtr[0] != 0x80) || (pPtr[1] != 0x03) )
3251cdf0e10cSrcweir 		return false;
3252cdf0e10cSrcweir 
3253cdf0e10cSrcweir 	return true;
3254cdf0e10cSrcweir }
3255cdf0e10cSrcweir 
3256cdf0e10cSrcweir struct FontException : public std::exception
3257cdf0e10cSrcweir {
3258cdf0e10cSrcweir };
3259cdf0e10cSrcweir 
3260cdf0e10cSrcweir // TODO: always subset instead of embedding the full font => this method becomes obsolete then
3261cdf0e10cSrcweir std::map< sal_Int32, sal_Int32 > PDFWriterImpl::emitEmbeddedFont( const ImplFontData* pFont, EmbedFont& rEmbed )
3262cdf0e10cSrcweir {
3263cdf0e10cSrcweir     std::map< sal_Int32, sal_Int32 > aRet;
3264cdf0e10cSrcweir     if( isBuiltinFont( pFont ) )
3265cdf0e10cSrcweir     {
3266cdf0e10cSrcweir         aRet[ rEmbed.m_nNormalFontID ] = emitBuiltinFont( pFont );
3267cdf0e10cSrcweir         return aRet;
3268cdf0e10cSrcweir     }
3269cdf0e10cSrcweir 
3270cdf0e10cSrcweir     sal_Int32 nFontObject = 0;
3271cdf0e10cSrcweir     sal_Int32 nStreamObject = 0;
3272cdf0e10cSrcweir     sal_Int32 nFontDescriptor = 0;
3273cdf0e10cSrcweir 
3274cdf0e10cSrcweir     // prepare font encoding
3275cdf0e10cSrcweir     const Ucs2SIntMap* pEncoding = m_pReferenceDevice->mpGraphics->GetFontEncodingVector( pFont, NULL );
3276cdf0e10cSrcweir     sal_Int32 nToUnicodeStream = 0;
3277cdf0e10cSrcweir     sal_uInt8 nEncoding[256];
3278cdf0e10cSrcweir     sal_Ucs nEncodedCodes[256];
3279cdf0e10cSrcweir     std::vector<sal_Ucs> aUnicodes;
3280cdf0e10cSrcweir     aUnicodes.reserve( 256 );
3281cdf0e10cSrcweir     sal_Int32 pUnicodesPerGlyph[256];
3282cdf0e10cSrcweir     sal_Int32 pEncToUnicodeIndex[256];
3283cdf0e10cSrcweir     if( pEncoding )
3284cdf0e10cSrcweir     {
3285cdf0e10cSrcweir         rtl_zeroMemory( nEncoding, sizeof(nEncoding) );
3286cdf0e10cSrcweir         rtl_zeroMemory( nEncodedCodes, sizeof(nEncodedCodes) );
3287cdf0e10cSrcweir         rtl_zeroMemory( pUnicodesPerGlyph, sizeof(pUnicodesPerGlyph) );
3288cdf0e10cSrcweir         rtl_zeroMemory( pEncToUnicodeIndex, sizeof(pEncToUnicodeIndex) );
3289cdf0e10cSrcweir         for( Ucs2SIntMap::const_iterator it = pEncoding->begin(); it != pEncoding->end(); ++it )
3290cdf0e10cSrcweir         {
3291cdf0e10cSrcweir             if( it->second != -1 )
3292cdf0e10cSrcweir             {
3293cdf0e10cSrcweir                 sal_Int32 nCode = (sal_Int32)(it->second & 0x000000ff);
3294cdf0e10cSrcweir                 nEncoding[ nCode ] = static_cast<sal_uInt8>( nCode );
3295cdf0e10cSrcweir                 nEncodedCodes[ nCode ] = it->first;
3296cdf0e10cSrcweir                 pEncToUnicodeIndex[ nCode ] = static_cast<sal_Int32>(aUnicodes.size());
3297cdf0e10cSrcweir                 aUnicodes.push_back( it->first );
3298cdf0e10cSrcweir                 pUnicodesPerGlyph[ nCode ] = 1;
3299cdf0e10cSrcweir             }
3300cdf0e10cSrcweir         }
3301cdf0e10cSrcweir     }
3302cdf0e10cSrcweir 
3303cdf0e10cSrcweir     FontSubsetInfo aInfo;
3304cdf0e10cSrcweir     sal_Int32 pWidths[256];
3305cdf0e10cSrcweir     const unsigned char* pFontData = NULL;
3306cdf0e10cSrcweir     long nFontLen = 0;
3307cdf0e10cSrcweir     sal_Int32 nLength1, nLength2;
3308cdf0e10cSrcweir     try
3309cdf0e10cSrcweir     {
3310cdf0e10cSrcweir         if( (pFontData = (const unsigned char*)m_pReferenceDevice->mpGraphics->GetEmbedFontData( pFont, nEncodedCodes, pWidths, aInfo, &nFontLen )) != NULL )
3311cdf0e10cSrcweir         {
3312cdf0e10cSrcweir             if( (aInfo.m_nFontType & FontSubsetInfo::ANY_TYPE1) == 0 )
3313cdf0e10cSrcweir                 throw FontException();
3314cdf0e10cSrcweir             // see whether it is pfb or pfa; if it is a pfb, fill ranges
3315cdf0e10cSrcweir             // of 6 bytes that are not part of the font program
3316cdf0e10cSrcweir             std::list< int > aSections;
3317cdf0e10cSrcweir             std::list< int >::const_iterator it;
3318cdf0e10cSrcweir             int nIndex = 0;
3319cdf0e10cSrcweir             while( pFontData[nIndex] == 0x80 && nIndex < nFontLen-1 )
3320cdf0e10cSrcweir             {
3321cdf0e10cSrcweir                 aSections.push_back( nIndex );
3322cdf0e10cSrcweir                 if( pFontData[nIndex+1] == 0x03 )
3323cdf0e10cSrcweir                     break;
3324cdf0e10cSrcweir                 sal_Int32 nBytes =
3325cdf0e10cSrcweir                 ((sal_Int32)pFontData[nIndex+2])			|
3326cdf0e10cSrcweir                 ((sal_Int32)pFontData[nIndex+3]) << 8		|
3327cdf0e10cSrcweir                 ((sal_Int32)pFontData[nIndex+4]) << 16		|
3328cdf0e10cSrcweir                 ((sal_Int32)pFontData[nIndex+5]) << 24;
3329cdf0e10cSrcweir                 nIndex += nBytes+6;
3330cdf0e10cSrcweir             }
3331cdf0e10cSrcweir 
3332cdf0e10cSrcweir             // search for eexec
3333cdf0e10cSrcweir             // TODO: use getPfbSegmentLengths() if possible to skip the search thingies below
3334cdf0e10cSrcweir             nIndex = 0;
3335cdf0e10cSrcweir             int nEndAsciiIndex;
3336cdf0e10cSrcweir             int nBeginBinaryIndex;
3337cdf0e10cSrcweir             int nEndBinaryIndex;
3338cdf0e10cSrcweir             do
3339cdf0e10cSrcweir             {
3340cdf0e10cSrcweir                 while( nIndex < nFontLen-4 &&
3341cdf0e10cSrcweir                     ( pFontData[nIndex] != 'e'	||
3342cdf0e10cSrcweir                         pFontData[nIndex+1] != 'e' ||
3343cdf0e10cSrcweir                         pFontData[nIndex+2] != 'x' ||
3344cdf0e10cSrcweir                         pFontData[nIndex+3] != 'e' ||
3345cdf0e10cSrcweir                         pFontData[nIndex+4] != 'c'
3346cdf0e10cSrcweir                         )
3347cdf0e10cSrcweir                     )
3348cdf0e10cSrcweir                 nIndex++;
3349cdf0e10cSrcweir                 // check whether we are in a excluded section
3350cdf0e10cSrcweir                 for( it = aSections.begin(); it != aSections.end() && (nIndex < *it || nIndex > ((*it) + 5) ); ++it )
3351cdf0e10cSrcweir                     ;
3352cdf0e10cSrcweir             } while( it != aSections.end() && nIndex < nFontLen-4 );
3353cdf0e10cSrcweir             // this should end the ascii part
3354cdf0e10cSrcweir             if( nIndex > nFontLen-5 )
3355cdf0e10cSrcweir                 throw FontException();
3356cdf0e10cSrcweir 
3357cdf0e10cSrcweir             nEndAsciiIndex = nIndex+4;
3358cdf0e10cSrcweir             // now count backwards until we can account for 512 '0'
3359cdf0e10cSrcweir             // which is the endmarker of the (hopefully) binary data
3360cdf0e10cSrcweir             // do not count the pfb header sections
3361cdf0e10cSrcweir             int nFound = 0;
3362cdf0e10cSrcweir             nIndex =  nFontLen-1;
3363cdf0e10cSrcweir             while( nIndex > 0 && nFound < 512 )
3364cdf0e10cSrcweir             {
3365cdf0e10cSrcweir                 for( it = aSections.begin(); it != aSections.end() && (nIndex < *it || nIndex > ((*it) + 5) ); ++it )
3366cdf0e10cSrcweir                     ;
3367cdf0e10cSrcweir                 if( it == aSections.end() )
3368cdf0e10cSrcweir                 {
3369cdf0e10cSrcweir                     // inside the 512 '0' block there may only be whitespace
3370cdf0e10cSrcweir                     // according to T1 spec; probably it would be to simple
3371cdf0e10cSrcweir                     // if all fonts complied
3372cdf0e10cSrcweir                     if( pFontData[nIndex] == '0' )
3373cdf0e10cSrcweir                         nFound++;
3374cdf0e10cSrcweir                         else if( nFound > 0					&&
3375cdf0e10cSrcweir                             pFontData[nIndex] != '\r'		&&
3376cdf0e10cSrcweir                         pFontData[nIndex] != '\t'		&&
3377cdf0e10cSrcweir                         pFontData[nIndex] != '\n'		&&
3378cdf0e10cSrcweir                         pFontData[nIndex] != ' ' )
3379cdf0e10cSrcweir                         break;
3380cdf0e10cSrcweir                 }
3381cdf0e10cSrcweir                 nIndex--;
3382cdf0e10cSrcweir             }
3383cdf0e10cSrcweir 
3384cdf0e10cSrcweir             if( nIndex < 1 || nIndex <= nEndAsciiIndex )
3385cdf0e10cSrcweir                 throw FontException();
3386cdf0e10cSrcweir 
3387cdf0e10cSrcweir             // nLength3 is the rest of the file - excluding any section headers
3388cdf0e10cSrcweir             // nIndex now points to the first of the 512 '0' characters marking the
3389cdf0e10cSrcweir             // fixed content portion
3390cdf0e10cSrcweir             sal_Int32 nLength3 = nFontLen - nIndex;
3391cdf0e10cSrcweir             for( it = aSections.begin(); it != aSections.end(); ++it )
3392cdf0e10cSrcweir             {
3393cdf0e10cSrcweir                 // special case: nIndex inside a section marker
3394457fd29fSEike Rathke                 if( nIndex >= (*it) && (*it)+6 > nIndex )
3395457fd29fSEike Rathke                     nLength3 -= (*it)+6 - nIndex;
3396457fd29fSEike Rathke                 else if( *it >= nIndex  )
3397cdf0e10cSrcweir                 {
3398cdf0e10cSrcweir                     if( *it < nFontLen - 6 )
3399cdf0e10cSrcweir                         nLength3 -= 6;
3400cdf0e10cSrcweir                     else // the last section 0x8003 is only 2 bytes after all
3401cdf0e10cSrcweir                         nLength3 -= (nFontLen - *it);
3402cdf0e10cSrcweir                 }
3403cdf0e10cSrcweir             }
3404cdf0e10cSrcweir 
3405cdf0e10cSrcweir             // there may be whitespace to ignore before the 512 '0'
3406cdf0e10cSrcweir             while( pFontData[nIndex] == '\r' || pFontData[nIndex] == '\n' )
3407cdf0e10cSrcweir             {
3408cdf0e10cSrcweir                 nIndex--;
3409cdf0e10cSrcweir                 for( it = aSections.begin(); it != aSections.end() && (nIndex < *it || nIndex > ((*it) + 5) ); ++it )
3410cdf0e10cSrcweir                     ;
3411cdf0e10cSrcweir                 if( it != aSections.end() )
3412cdf0e10cSrcweir                 {
3413cdf0e10cSrcweir                     nIndex = (*it)-1;
3414cdf0e10cSrcweir                     break; // this is surely a binary boundary, in ascii case it wouldn't matter
3415cdf0e10cSrcweir                 }
3416cdf0e10cSrcweir             }
3417cdf0e10cSrcweir             nEndBinaryIndex = nIndex;
3418cdf0e10cSrcweir 
3419cdf0e10cSrcweir             // search for beginning of binary section
3420cdf0e10cSrcweir             nBeginBinaryIndex = nEndAsciiIndex;
3421cdf0e10cSrcweir             do
3422cdf0e10cSrcweir             {
3423cdf0e10cSrcweir                 nBeginBinaryIndex++;
3424cdf0e10cSrcweir                 for( it = aSections.begin(); it != aSections.end() && (nBeginBinaryIndex < *it || nBeginBinaryIndex > ((*it) + 5) ); ++it )
3425cdf0e10cSrcweir                     ;
3426cdf0e10cSrcweir                     } while( nBeginBinaryIndex < nEndBinaryIndex &&
3427cdf0e10cSrcweir                         ( pFontData[nBeginBinaryIndex] == '\r'	||
3428cdf0e10cSrcweir                             pFontData[nBeginBinaryIndex] == '\n'	||
3429cdf0e10cSrcweir                             it != aSections.end() ) );
3430cdf0e10cSrcweir 
3431cdf0e10cSrcweir                     // it seems to be vital to copy the exact whitespace between binary data
3432cdf0e10cSrcweir                     // and eexec, else a invalid font results. so make nEndAsciiIndex
3433cdf0e10cSrcweir                     // always immediate in front of nBeginBinaryIndex
3434cdf0e10cSrcweir                     nEndAsciiIndex = nBeginBinaryIndex-1;
3435cdf0e10cSrcweir                     for( it = aSections.begin(); it != aSections.end() && (nEndAsciiIndex < *it || nEndAsciiIndex > ((*it)+5)); ++it )
3436cdf0e10cSrcweir                         ;
3437cdf0e10cSrcweir                     if( it != aSections.end() )
3438cdf0e10cSrcweir                         nEndAsciiIndex = (*it)-1;
3439cdf0e10cSrcweir 
3440cdf0e10cSrcweir                     nLength1 = nEndAsciiIndex+1; // including the last character
3441cdf0e10cSrcweir                     for( it = aSections.begin(); it != aSections.end() && *it < nEndAsciiIndex; ++it )
3442cdf0e10cSrcweir                         nLength1 -= 6; // decrease by pfb section size
3443cdf0e10cSrcweir 
3444cdf0e10cSrcweir                     // if the first four bytes are all ascii hex characters, then binary data
3445cdf0e10cSrcweir                     // has to be converted to real binary data
3446cdf0e10cSrcweir                     for( nIndex = 0; nIndex < 4 &&
3447cdf0e10cSrcweir                         ( ( pFontData[ nBeginBinaryIndex+nIndex ] >= '0' && pFontData[ nBeginBinaryIndex+nIndex ] <= '9' ) ||
3448cdf0e10cSrcweir                             ( pFontData[ nBeginBinaryIndex+nIndex ] >= 'a' && pFontData[ nBeginBinaryIndex+nIndex ] <= 'f' ) ||
3449cdf0e10cSrcweir                             ( pFontData[ nBeginBinaryIndex+nIndex ] >= 'A' && pFontData[ nBeginBinaryIndex+nIndex ] <= 'F' )
3450cdf0e10cSrcweir                             ); ++nIndex )
3451cdf0e10cSrcweir                     ;
3452cdf0e10cSrcweir                     bool bConvertHexData = true;
3453cdf0e10cSrcweir                     if( nIndex < 4 )
3454cdf0e10cSrcweir                     {
3455cdf0e10cSrcweir                         bConvertHexData = false;
3456cdf0e10cSrcweir                         nLength2 = nEndBinaryIndex - nBeginBinaryIndex + 1; // include the last byte
3457cdf0e10cSrcweir                         for( it = aSections.begin(); it != aSections.end(); ++it )
3458cdf0e10cSrcweir                             if( *it > nBeginBinaryIndex && *it < nEndBinaryIndex )
3459cdf0e10cSrcweir                             nLength2 -= 6;
3460cdf0e10cSrcweir                     }
3461cdf0e10cSrcweir                     else
3462cdf0e10cSrcweir                     {
3463cdf0e10cSrcweir                         // count the hex ascii characters to get nLength2
3464cdf0e10cSrcweir                         nLength2 = 0;
3465cdf0e10cSrcweir                         int nNextSectionIndex = 0;
3466cdf0e10cSrcweir                         for( it = aSections.begin(); it != aSections.end() && *it < nBeginBinaryIndex; ++it )
3467cdf0e10cSrcweir                             ;
3468cdf0e10cSrcweir                         if( it != aSections.end() )
3469cdf0e10cSrcweir                             nNextSectionIndex = *it;
3470cdf0e10cSrcweir                         for( nIndex = nBeginBinaryIndex; nIndex <= nEndBinaryIndex; nIndex++ )
3471cdf0e10cSrcweir                         {
3472cdf0e10cSrcweir                             if( nIndex == nNextSectionIndex )
3473cdf0e10cSrcweir                             {
3474cdf0e10cSrcweir                                 nIndex += 6;
3475cdf0e10cSrcweir                                 ++it;
3476cdf0e10cSrcweir                                 nNextSectionIndex = (it == aSections.end() ? 0 : *it );
3477cdf0e10cSrcweir                             }
3478cdf0e10cSrcweir                             if( ( pFontData[ nIndex ] >= '0' && pFontData[ nIndex ] <= '9' ) ||
3479cdf0e10cSrcweir                                 ( pFontData[ nIndex ] >= 'a' && pFontData[ nIndex ] <= 'f' ) ||
3480cdf0e10cSrcweir                             ( pFontData[ nIndex ] >= 'A' && pFontData[ nIndex ] <= 'F' ) )
3481cdf0e10cSrcweir                             nLength2++;
3482cdf0e10cSrcweir                         }
3483cdf0e10cSrcweir                         DBG_ASSERT( !(nLength2 & 1), "uneven number of hex chars in binary pfa section" );
3484cdf0e10cSrcweir                         nLength2 /= 2;
3485cdf0e10cSrcweir                     }
3486cdf0e10cSrcweir 
3487cdf0e10cSrcweir                     // now we can actually write the font stream !
3488cdf0e10cSrcweir                     #if OSL_DEBUG_LEVEL > 1
3489cdf0e10cSrcweir                     emitComment( " PDFWriterImpl::emitEmbeddedFont" );
3490cdf0e10cSrcweir                     #endif
3491cdf0e10cSrcweir                     OStringBuffer aLine( 512 );
3492cdf0e10cSrcweir                     nStreamObject = createObject();
3493cdf0e10cSrcweir                     if( !updateObject(nStreamObject))
3494cdf0e10cSrcweir                         throw FontException();
3495cdf0e10cSrcweir                     sal_Int32 nStreamLengthObject = createObject();
3496cdf0e10cSrcweir                     aLine.append( nStreamObject );
3497cdf0e10cSrcweir                     aLine.append( " 0 obj\n"
3498cdf0e10cSrcweir                         "<</Length " );
3499cdf0e10cSrcweir                     aLine.append( nStreamLengthObject );
3500cdf0e10cSrcweir                     aLine.append( " 0 R"
3501cdf0e10cSrcweir                         #ifndef DEBUG_DISABLE_PDFCOMPRESSION
3502cdf0e10cSrcweir                         "/Filter/FlateDecode"
3503cdf0e10cSrcweir                         #endif
3504cdf0e10cSrcweir                         "/Length1 " );
3505cdf0e10cSrcweir                     aLine.append( nLength1 );
3506cdf0e10cSrcweir                     aLine.append( " /Length2 " );
3507cdf0e10cSrcweir                     aLine.append( nLength2 );
3508cdf0e10cSrcweir                     aLine.append( " /Length3 ");
3509cdf0e10cSrcweir                     aLine.append( nLength3 );
3510cdf0e10cSrcweir                     aLine.append( ">>\n"
3511cdf0e10cSrcweir                         "stream\n" );
3512cdf0e10cSrcweir                     if( !writeBuffer( aLine.getStr(), aLine.getLength() ) )
3513cdf0e10cSrcweir                         throw FontException();
3514cdf0e10cSrcweir 
3515cdf0e10cSrcweir                     sal_uInt64 nBeginStreamPos = 0;
3516cdf0e10cSrcweir                     osl_getFilePos( m_aFile, &nBeginStreamPos );
3517cdf0e10cSrcweir 
3518cdf0e10cSrcweir                     beginCompression();
3519cdf0e10cSrcweir                     checkAndEnableStreamEncryption( nStreamObject );
3520cdf0e10cSrcweir 
3521cdf0e10cSrcweir                     // write ascii section
3522cdf0e10cSrcweir                     if( aSections.begin() == aSections.end() )
3523cdf0e10cSrcweir                     {
3524cdf0e10cSrcweir                         if( ! writeBuffer( pFontData, nEndAsciiIndex+1 ) )
3525cdf0e10cSrcweir                             throw FontException();
3526cdf0e10cSrcweir                     }
3527cdf0e10cSrcweir                     else
3528cdf0e10cSrcweir                     {
3529cdf0e10cSrcweir                         // first section always starts at 0
3530cdf0e10cSrcweir                         it = aSections.begin();
3531cdf0e10cSrcweir                         nIndex = (*it)+6;
3532cdf0e10cSrcweir                         ++it;
3533cdf0e10cSrcweir                         while( *it < nEndAsciiIndex )
3534cdf0e10cSrcweir                         {
3535cdf0e10cSrcweir                             if( ! writeBuffer( pFontData+nIndex, (*it)-nIndex ) )
3536cdf0e10cSrcweir                                 throw FontException();
3537cdf0e10cSrcweir                             nIndex = (*it)+6;
3538cdf0e10cSrcweir                             ++it;
3539cdf0e10cSrcweir                         }
3540cdf0e10cSrcweir                         // write partial last section
3541cdf0e10cSrcweir                         if( ! writeBuffer( pFontData+nIndex, nEndAsciiIndex-nIndex+1 ) )
3542cdf0e10cSrcweir                             throw FontException();
3543cdf0e10cSrcweir                     }
3544cdf0e10cSrcweir 
3545cdf0e10cSrcweir                     // write binary section
3546cdf0e10cSrcweir                     if( ! bConvertHexData )
3547cdf0e10cSrcweir                     {
3548cdf0e10cSrcweir                         if( aSections.begin() == aSections.end() )
3549cdf0e10cSrcweir                         {
3550cdf0e10cSrcweir                             if( ! writeBuffer( pFontData+nBeginBinaryIndex, nFontLen-nBeginBinaryIndex ) )
3551cdf0e10cSrcweir                                 throw FontException();
3552cdf0e10cSrcweir                         }
3553cdf0e10cSrcweir                         else
3554cdf0e10cSrcweir                         {
3555cdf0e10cSrcweir                             for( it = aSections.begin(); *it < nBeginBinaryIndex; ++it )
3556cdf0e10cSrcweir                                 ;
3557cdf0e10cSrcweir                             // write first partial section
3558cdf0e10cSrcweir                             if( ! writeBuffer( pFontData+nBeginBinaryIndex, (*it) - nBeginBinaryIndex ) )
3559cdf0e10cSrcweir                                 throw FontException();
3560cdf0e10cSrcweir                             // write following sections
3561cdf0e10cSrcweir                             while( it != aSections.end() )
3562cdf0e10cSrcweir                             {
3563cdf0e10cSrcweir                                 nIndex = (*it)+6;
3564cdf0e10cSrcweir                                 ++it;
3565cdf0e10cSrcweir                                 if( nIndex < nFontLen ) // last section marker is usually the EOF which has only 2 bytes
3566cdf0e10cSrcweir                                 {
3567cdf0e10cSrcweir                                     sal_Int32 nSectionLen = (it == aSections.end()) ? nFontLen - nIndex : (*it) - nIndex;
3568cdf0e10cSrcweir                                     if( ! writeBuffer( pFontData+nIndex, nSectionLen ) )
3569cdf0e10cSrcweir                                         throw FontException();
3570cdf0e10cSrcweir                                 }
3571cdf0e10cSrcweir                             }
3572cdf0e10cSrcweir                         }
3573cdf0e10cSrcweir                     }
3574cdf0e10cSrcweir                     else
3575cdf0e10cSrcweir                     {
3576cdf0e10cSrcweir                         boost::shared_array<unsigned char> pWriteBuffer( new unsigned char[ nLength2 ] );
3577cdf0e10cSrcweir                         rtl_zeroMemory( pWriteBuffer.get(), nLength2 );
3578cdf0e10cSrcweir                         int nWriteIndex = 0;
3579cdf0e10cSrcweir 
3580cdf0e10cSrcweir                         int nNextSectionIndex = 0;
3581cdf0e10cSrcweir                         for( it = aSections.begin(); it != aSections.end() && *it < nBeginBinaryIndex; ++it )
3582cdf0e10cSrcweir                             ;
3583cdf0e10cSrcweir                         if( it != aSections.end() )
3584cdf0e10cSrcweir                             nNextSectionIndex = *it;
3585cdf0e10cSrcweir                         for( nIndex = nBeginBinaryIndex; nIndex <= nEndBinaryIndex; nIndex++ )
3586cdf0e10cSrcweir                         {
3587cdf0e10cSrcweir                             if( nIndex == nNextSectionIndex )
3588cdf0e10cSrcweir                             {
3589cdf0e10cSrcweir                                 nIndex += 6;
3590cdf0e10cSrcweir                                 ++it;
3591cdf0e10cSrcweir                                 nNextSectionIndex = (it == aSections.end() ? nFontLen : *it );
3592cdf0e10cSrcweir                             }
3593cdf0e10cSrcweir                             unsigned char cNibble = 0x80;
3594cdf0e10cSrcweir                             if( pFontData[ nIndex ] >= '0' && pFontData[ nIndex ] <= '9' )
3595cdf0e10cSrcweir                                 cNibble = pFontData[nIndex] - '0';
3596cdf0e10cSrcweir                             else if( pFontData[ nIndex ] >= 'a' && pFontData[ nIndex ] <= 'f' )
3597cdf0e10cSrcweir                                 cNibble = pFontData[nIndex] - 'a' + 10;
3598cdf0e10cSrcweir                             else if( pFontData[ nIndex ] >= 'A' && pFontData[ nIndex ] <= 'F' )
3599cdf0e10cSrcweir                                 cNibble = pFontData[nIndex] - 'A' + 10;
3600cdf0e10cSrcweir                             if( cNibble != 0x80 )
3601cdf0e10cSrcweir                             {
3602cdf0e10cSrcweir                                 if( !(nWriteIndex & 1 ) )
3603cdf0e10cSrcweir                                     cNibble <<= 4;
3604cdf0e10cSrcweir                                 pWriteBuffer.get()[ nWriteIndex/2 ] |= cNibble;
3605cdf0e10cSrcweir                                 nWriteIndex++;
3606cdf0e10cSrcweir                             }
3607cdf0e10cSrcweir                         }
3608cdf0e10cSrcweir                         if( ! writeBuffer( pWriteBuffer.get(), nLength2 ) )
3609cdf0e10cSrcweir                             throw FontException();
3610cdf0e10cSrcweir                         if( aSections.empty() )
3611cdf0e10cSrcweir                         {
3612cdf0e10cSrcweir                             if( ! writeBuffer( pFontData+nIndex, nFontLen-nIndex ) )
3613cdf0e10cSrcweir                                 throw FontException();
3614cdf0e10cSrcweir                         }
3615cdf0e10cSrcweir                         else
3616cdf0e10cSrcweir                         {
3617cdf0e10cSrcweir                             // write rest of this section
3618cdf0e10cSrcweir                             if( nIndex < nNextSectionIndex )
3619cdf0e10cSrcweir                             {
3620cdf0e10cSrcweir                                 if( ! writeBuffer( pFontData+nIndex, nNextSectionIndex - nIndex ) )
3621cdf0e10cSrcweir                                     throw FontException();
3622cdf0e10cSrcweir                             }
3623cdf0e10cSrcweir                             // write following sections
3624cdf0e10cSrcweir                             while( it != aSections.end() )
3625cdf0e10cSrcweir                             {
3626cdf0e10cSrcweir                                 nIndex = (*it)+6;
3627cdf0e10cSrcweir                                 ++it;
3628cdf0e10cSrcweir                                 if( nIndex < nFontLen ) // last section marker is usually the EOF which has only 2 bytes
3629cdf0e10cSrcweir                                 {
3630cdf0e10cSrcweir                                     sal_Int32 nSectionLen = (it == aSections.end()) ? nFontLen - nIndex : (*it) - nIndex;
3631cdf0e10cSrcweir                                     if( ! writeBuffer( pFontData+nIndex, nSectionLen ) )
3632cdf0e10cSrcweir                                         throw FontException();
3633cdf0e10cSrcweir                                 }
3634cdf0e10cSrcweir                             }
3635cdf0e10cSrcweir                         }
3636cdf0e10cSrcweir                     }
3637cdf0e10cSrcweir                     endCompression();
3638cdf0e10cSrcweir                     disableStreamEncryption();
3639cdf0e10cSrcweir 
3640cdf0e10cSrcweir 
3641cdf0e10cSrcweir                     sal_uInt64 nEndStreamPos = 0;
3642cdf0e10cSrcweir                     osl_getFilePos( m_aFile, &nEndStreamPos );
3643cdf0e10cSrcweir 
3644cdf0e10cSrcweir                     // and finally close the stream
3645cdf0e10cSrcweir                     aLine.setLength( 0 );
3646cdf0e10cSrcweir                     aLine.append( "\nendstream\nendobj\n\n" );
3647cdf0e10cSrcweir                     if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) )
3648cdf0e10cSrcweir                         throw FontException();
3649cdf0e10cSrcweir 
3650cdf0e10cSrcweir                     // write stream length object
3651cdf0e10cSrcweir                     aLine.setLength( 0 );
3652cdf0e10cSrcweir                     if( ! updateObject( nStreamLengthObject ) )
3653cdf0e10cSrcweir                         throw FontException();
3654cdf0e10cSrcweir                     aLine.append( nStreamLengthObject );
3655cdf0e10cSrcweir                     aLine.append( " 0 obj\n" );
3656cdf0e10cSrcweir                     aLine.append( (sal_Int64)(nEndStreamPos-nBeginStreamPos ) );
3657cdf0e10cSrcweir                     aLine.append( "\nendobj\n\n" );
3658cdf0e10cSrcweir                     if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) )
3659cdf0e10cSrcweir                         throw FontException();
3660cdf0e10cSrcweir         }
3661cdf0e10cSrcweir         else
3662cdf0e10cSrcweir         {
3663cdf0e10cSrcweir             rtl::OStringBuffer aErrorComment( 256 );
3664cdf0e10cSrcweir             aErrorComment.append( "GetEmbedFontData failed for font \"" );
3665cdf0e10cSrcweir             aErrorComment.append( OUStringToOString( pFont->GetFamilyName(), RTL_TEXTENCODING_UTF8 ) );
3666cdf0e10cSrcweir             aErrorComment.append( '\"' );
3667cdf0e10cSrcweir             if( pFont->GetSlant() == ITALIC_NORMAL )
3668cdf0e10cSrcweir                 aErrorComment.append( " italic" );
3669cdf0e10cSrcweir             else if( pFont->GetSlant() == ITALIC_OBLIQUE )
3670cdf0e10cSrcweir                 aErrorComment.append( " oblique" );
3671cdf0e10cSrcweir             aErrorComment.append( " weight=" );
3672cdf0e10cSrcweir             aErrorComment.append( sal_Int32(pFont->GetWeight()) );
3673cdf0e10cSrcweir             emitComment( aErrorComment.getStr() );
3674cdf0e10cSrcweir         }
3675cdf0e10cSrcweir 
3676cdf0e10cSrcweir         if( nStreamObject )
3677cdf0e10cSrcweir             // write font descriptor
3678cdf0e10cSrcweir         nFontDescriptor = emitFontDescriptor( pFont, aInfo, 0, nStreamObject );
3679cdf0e10cSrcweir 
3680cdf0e10cSrcweir         if( nFontDescriptor )
3681cdf0e10cSrcweir         {
3682cdf0e10cSrcweir             if( pEncoding )
3683cdf0e10cSrcweir                 nToUnicodeStream = createToUnicodeCMap( nEncoding, &aUnicodes[0], pUnicodesPerGlyph, pEncToUnicodeIndex, sizeof(nEncoding)/sizeof(nEncoding[0]) );
3684cdf0e10cSrcweir 
3685cdf0e10cSrcweir             // write font object
3686cdf0e10cSrcweir             sal_Int32 nObject = createObject();
3687cdf0e10cSrcweir             if( ! updateObject( nObject ) )
3688cdf0e10cSrcweir                 throw FontException();
3689cdf0e10cSrcweir 
3690cdf0e10cSrcweir             OStringBuffer aLine( 1024 );
3691cdf0e10cSrcweir             aLine.append( nObject );
3692cdf0e10cSrcweir             aLine.append( " 0 obj\n"
3693cdf0e10cSrcweir                 "<</Type/Font/Subtype/Type1/BaseFont/" );
3694cdf0e10cSrcweir             appendName( aInfo.m_aPSName, aLine );
3695cdf0e10cSrcweir             aLine.append( "\n" );
3696cdf0e10cSrcweir             if( !pFont->mbSymbolFlag &&  pEncoding == 0 )
3697cdf0e10cSrcweir                 aLine.append( "/Encoding/WinAnsiEncoding\n" );
3698cdf0e10cSrcweir             if( nToUnicodeStream )
3699cdf0e10cSrcweir             {
3700cdf0e10cSrcweir                 aLine.append( "/ToUnicode " );
3701cdf0e10cSrcweir                 aLine.append( nToUnicodeStream );
3702cdf0e10cSrcweir                 aLine.append( " 0 R\n" );
3703cdf0e10cSrcweir             }
3704cdf0e10cSrcweir             aLine.append( "/FirstChar 0 /LastChar 255\n"
3705cdf0e10cSrcweir                 "/Widths[" );
3706cdf0e10cSrcweir             for( int i = 0; i < 256; i++ )
3707cdf0e10cSrcweir             {
3708cdf0e10cSrcweir                 aLine.append( pWidths[i] );
3709cdf0e10cSrcweir                 aLine.append( ((i&15) == 15) ? "\n" : " " );
3710cdf0e10cSrcweir             }
3711cdf0e10cSrcweir             aLine.append( "]\n"
3712cdf0e10cSrcweir                 "/FontDescriptor " );
3713cdf0e10cSrcweir             aLine.append( nFontDescriptor );
3714cdf0e10cSrcweir             aLine.append( " 0 R>>\n"
3715cdf0e10cSrcweir                 "endobj\n\n" );
3716cdf0e10cSrcweir             if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) )
3717cdf0e10cSrcweir                 throw FontException();
3718cdf0e10cSrcweir 
3719cdf0e10cSrcweir             nFontObject = nObject;
3720cdf0e10cSrcweir 
3721cdf0e10cSrcweir             aRet[ rEmbed.m_nNormalFontID ] = nObject;
3722cdf0e10cSrcweir 
3723cdf0e10cSrcweir             // write additional encodings
3724cdf0e10cSrcweir             for( std::list< EmbedEncoding >::iterator enc_it = rEmbed.m_aExtendedEncodings.begin(); enc_it != rEmbed.m_aExtendedEncodings.end(); ++enc_it )
3725cdf0e10cSrcweir             {
3726cdf0e10cSrcweir                 sal_Int32 aEncWidths[ 256 ];
3727cdf0e10cSrcweir                 // emit encoding dict
3728cdf0e10cSrcweir                 sal_Int32 nEncObject = createObject();
3729cdf0e10cSrcweir                 if( ! updateObject( nEncObject ) )
3730cdf0e10cSrcweir                     throw FontException();
3731cdf0e10cSrcweir 
3732cdf0e10cSrcweir                 OutputDevice* pRef = getReferenceDevice();
3733cdf0e10cSrcweir                 pRef->Push( PUSH_FONT | PUSH_MAPMODE );
3734cdf0e10cSrcweir                 pRef->SetMapMode( MapMode( MAP_PIXEL ) );
3735cdf0e10cSrcweir                 Font aFont( pFont->GetFamilyName(), pFont->GetStyleName(), Size( 0, 1000 ) );
3736cdf0e10cSrcweir                 aFont.SetWeight( pFont->GetWeight() );
3737cdf0e10cSrcweir                 aFont.SetItalic( pFont->GetSlant() );
3738cdf0e10cSrcweir                 aFont.SetPitch( pFont->GetPitch() );
3739cdf0e10cSrcweir                 pRef->SetFont( aFont );
3740cdf0e10cSrcweir                 pRef->ImplNewFont();
3741cdf0e10cSrcweir 
3742cdf0e10cSrcweir                 aLine.setLength( 0 );
3743cdf0e10cSrcweir                 aLine.append( nEncObject );
3744cdf0e10cSrcweir                 aLine.append( " 0 obj\n"
3745cdf0e10cSrcweir                     "<</Type/Encoding/Differences[ 0\n" );
3746cdf0e10cSrcweir                 int nEncoded = 0;
3747cdf0e10cSrcweir                 aUnicodes.clear();
3748cdf0e10cSrcweir                 for( std::vector< EmbedCode >::iterator str_it = enc_it->m_aEncVector.begin(); str_it != enc_it->m_aEncVector.end(); ++str_it )
3749cdf0e10cSrcweir                 {
3750cdf0e10cSrcweir                     String aStr( str_it->m_aUnicode );
3751cdf0e10cSrcweir                     aEncWidths[nEncoded] = pRef->GetTextWidth( aStr );
3752cdf0e10cSrcweir                     nEncodedCodes[nEncoded] = str_it->m_aUnicode;
3753cdf0e10cSrcweir                     nEncoding[nEncoded] = sal::static_int_cast<sal_uInt8>(nEncoded);
3754cdf0e10cSrcweir                     pEncToUnicodeIndex[nEncoded] = static_cast<sal_Int32>(aUnicodes.size());
3755cdf0e10cSrcweir                     aUnicodes.push_back( nEncodedCodes[nEncoded] );
3756cdf0e10cSrcweir                     pUnicodesPerGlyph[nEncoded] = 1;
3757cdf0e10cSrcweir 
3758cdf0e10cSrcweir                     aLine.append( " /" );
3759cdf0e10cSrcweir                     aLine.append( str_it->m_aName );
3760cdf0e10cSrcweir                     if( !((++nEncoded) & 15) )
3761cdf0e10cSrcweir                         aLine.append( "\n" );
3762cdf0e10cSrcweir                 }
3763cdf0e10cSrcweir                 aLine.append( "]>>\n"
3764cdf0e10cSrcweir                     "endobj\n\n" );
3765cdf0e10cSrcweir 
3766cdf0e10cSrcweir                 pRef->Pop();
3767cdf0e10cSrcweir 
3768cdf0e10cSrcweir                 if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) )
3769cdf0e10cSrcweir                     throw FontException();
3770cdf0e10cSrcweir 
3771cdf0e10cSrcweir                 nToUnicodeStream = createToUnicodeCMap( nEncoding, &aUnicodes[0], pUnicodesPerGlyph, pEncToUnicodeIndex, nEncoded );
3772cdf0e10cSrcweir 
3773cdf0e10cSrcweir                 nObject = createObject();
3774cdf0e10cSrcweir                 if( ! updateObject( nObject ) )
3775cdf0e10cSrcweir                     throw FontException();
3776cdf0e10cSrcweir 
3777cdf0e10cSrcweir                 aLine.setLength( 0 );
3778cdf0e10cSrcweir                 aLine.append( nObject );
3779cdf0e10cSrcweir                 aLine.append( " 0 obj\n"
3780cdf0e10cSrcweir                     "<</Type/Font/Subtype/Type1/BaseFont/" );
3781cdf0e10cSrcweir                 appendName( aInfo.m_aPSName, aLine );
3782cdf0e10cSrcweir                 aLine.append( "\n" );
3783cdf0e10cSrcweir                 aLine.append( "/Encoding " );
3784cdf0e10cSrcweir                 aLine.append( nEncObject );
3785cdf0e10cSrcweir                 aLine.append( " 0 R\n" );
3786cdf0e10cSrcweir                 if( nToUnicodeStream )
3787cdf0e10cSrcweir                 {
3788cdf0e10cSrcweir                     aLine.append( "/ToUnicode " );
3789cdf0e10cSrcweir                     aLine.append( nToUnicodeStream );
3790cdf0e10cSrcweir                     aLine.append( " 0 R\n" );
3791cdf0e10cSrcweir                 }
3792cdf0e10cSrcweir                 aLine.append( "/FirstChar 0\n"
3793cdf0e10cSrcweir                     "/LastChar " );
3794cdf0e10cSrcweir                 aLine.append( (sal_Int32)(nEncoded-1) );
3795cdf0e10cSrcweir                 aLine.append( "\n"
3796cdf0e10cSrcweir                     "/Widths[" );
3797cdf0e10cSrcweir                 for( int i = 0; i < nEncoded; i++ )
3798cdf0e10cSrcweir                 {
3799cdf0e10cSrcweir                     aLine.append( aEncWidths[i] );
3800cdf0e10cSrcweir                     aLine.append( ((i&15) == 15) ? "\n" : " " );
3801cdf0e10cSrcweir                 }
3802cdf0e10cSrcweir                 aLine.append( " ]\n"
3803cdf0e10cSrcweir                     "/FontDescriptor " );
3804cdf0e10cSrcweir                 aLine.append( nFontDescriptor );
3805cdf0e10cSrcweir                 aLine.append( " 0 R>>\n"
3806cdf0e10cSrcweir                     "endobj\n\n" );
3807cdf0e10cSrcweir                 if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) )
3808cdf0e10cSrcweir                     throw FontException();
3809cdf0e10cSrcweir 
3810cdf0e10cSrcweir                 aRet[ enc_it->m_nFontID ] = nObject;
3811cdf0e10cSrcweir             }
3812cdf0e10cSrcweir         }
3813cdf0e10cSrcweir     }
3814cdf0e10cSrcweir     catch( FontException& )
3815cdf0e10cSrcweir     {
3816cdf0e10cSrcweir         // these do nothing in case there was no compression or encryption ongoing
3817cdf0e10cSrcweir         endCompression();
3818cdf0e10cSrcweir         disableStreamEncryption();
3819cdf0e10cSrcweir     }
3820cdf0e10cSrcweir 
3821cdf0e10cSrcweir     if( pFontData )
3822cdf0e10cSrcweir         m_pReferenceDevice->mpGraphics->FreeEmbedFontData( pFontData, nFontLen );
3823cdf0e10cSrcweir 
3824cdf0e10cSrcweir     return aRet;
3825cdf0e10cSrcweir }
3826cdf0e10cSrcweir 
3827cdf0e10cSrcweir static void appendSubsetName( int nSubsetID, const OUString& rPSName, OStringBuffer& rBuffer )
3828cdf0e10cSrcweir {
3829cdf0e10cSrcweir     if( nSubsetID )
3830cdf0e10cSrcweir     {
3831cdf0e10cSrcweir         for( int i = 0; i < 6; i++ )
3832cdf0e10cSrcweir         {
3833cdf0e10cSrcweir             int nOffset = (nSubsetID % 26);
3834cdf0e10cSrcweir             nSubsetID /= 26;
3835cdf0e10cSrcweir             rBuffer.append( (sal_Char)('A'+nOffset) );
3836cdf0e10cSrcweir         }
3837cdf0e10cSrcweir         rBuffer.append( '+' );
3838cdf0e10cSrcweir     }
3839cdf0e10cSrcweir     appendName( rPSName, rBuffer );
3840cdf0e10cSrcweir }
3841cdf0e10cSrcweir 
3842cdf0e10cSrcweir sal_Int32 PDFWriterImpl::createToUnicodeCMap( sal_uInt8* pEncoding,
3843cdf0e10cSrcweir                                               sal_Ucs* pUnicodes,
3844cdf0e10cSrcweir                                               sal_Int32* pUnicodesPerGlyph,
3845cdf0e10cSrcweir                                               sal_Int32* pEncToUnicodeIndex,
3846cdf0e10cSrcweir                                               int nGlyphs )
3847cdf0e10cSrcweir {
3848cdf0e10cSrcweir     int nMapped = 0, n = 0;
3849cdf0e10cSrcweir     for( n = 0; n < nGlyphs; n++ )
3850cdf0e10cSrcweir         if( pUnicodes[pEncToUnicodeIndex[n]] && pUnicodesPerGlyph[n] )
3851cdf0e10cSrcweir             nMapped++;
3852cdf0e10cSrcweir 
3853cdf0e10cSrcweir     if( nMapped == 0 )
3854cdf0e10cSrcweir         return 0;
3855cdf0e10cSrcweir 
3856cdf0e10cSrcweir     sal_Int32 nStream = createObject();
3857cdf0e10cSrcweir     CHECK_RETURN( updateObject( nStream ) );
3858cdf0e10cSrcweir 
3859cdf0e10cSrcweir     OStringBuffer aContents( 1024 );
3860cdf0e10cSrcweir     aContents.append(
3861cdf0e10cSrcweir                      "/CIDInit/ProcSet findresource begin\n"
3862cdf0e10cSrcweir                      "12 dict begin\n"
3863cdf0e10cSrcweir                      "begincmap\n"
3864cdf0e10cSrcweir                      "/CIDSystemInfo<<\n"
3865cdf0e10cSrcweir                      "/Registry (Adobe)\n"
3866cdf0e10cSrcweir                      "/Ordering (UCS)\n"
3867cdf0e10cSrcweir                      "/Supplement 0\n"
3868cdf0e10cSrcweir                      ">> def\n"
3869cdf0e10cSrcweir                      "/CMapName/Adobe-Identity-UCS def\n"
3870cdf0e10cSrcweir                      "/CMapType 2 def\n"
3871cdf0e10cSrcweir                      "1 begincodespacerange\n"
3872cdf0e10cSrcweir                      "<00> <FF>\n"
3873cdf0e10cSrcweir                      "endcodespacerange\n"
3874cdf0e10cSrcweir                      );
3875cdf0e10cSrcweir     int nCount = 0;
3876cdf0e10cSrcweir     for( n = 0; n < nGlyphs; n++ )
3877cdf0e10cSrcweir     {
3878cdf0e10cSrcweir         if( pUnicodes[pEncToUnicodeIndex[n]] && pUnicodesPerGlyph[n] )
3879cdf0e10cSrcweir         {
3880cdf0e10cSrcweir             if( (nCount % 100) == 0 )
3881cdf0e10cSrcweir             {
3882cdf0e10cSrcweir                 if( nCount )
3883cdf0e10cSrcweir                     aContents.append( "endbfchar\n" );
3884cdf0e10cSrcweir                 aContents.append( (sal_Int32)((nMapped-nCount > 100) ? 100 : nMapped-nCount ) );
3885cdf0e10cSrcweir                 aContents.append( " beginbfchar\n" );
3886cdf0e10cSrcweir             }
3887cdf0e10cSrcweir             aContents.append( '<' );
3888cdf0e10cSrcweir             appendHex( (sal_Int8)pEncoding[n], aContents );
3889cdf0e10cSrcweir             aContents.append( "> <" );
3890cdf0e10cSrcweir             // TODO: handle unicodes>U+FFFF
3891cdf0e10cSrcweir             sal_Int32 nIndex = pEncToUnicodeIndex[n];
3892cdf0e10cSrcweir 	        for( sal_Int32 j = 0; j < pUnicodesPerGlyph[n]; j++ )
3893cdf0e10cSrcweir 	        {
3894cdf0e10cSrcweir                 appendHex( (sal_Int8)(pUnicodes[nIndex + j] / 256), aContents );
3895cdf0e10cSrcweir                 appendHex( (sal_Int8)(pUnicodes[nIndex + j] & 255), aContents );
3896cdf0e10cSrcweir             }
3897cdf0e10cSrcweir             aContents.append( ">\n" );
3898cdf0e10cSrcweir             nCount++;
3899cdf0e10cSrcweir         }
3900cdf0e10cSrcweir     }
3901cdf0e10cSrcweir     aContents.append( "endbfchar\n"
3902cdf0e10cSrcweir                       "endcmap\n"
3903cdf0e10cSrcweir                       "CMapName currentdict /CMap defineresource pop\n"
3904cdf0e10cSrcweir                       "end\n"
3905cdf0e10cSrcweir                       "end\n" );
3906cdf0e10cSrcweir #ifndef DEBUG_DISABLE_PDFCOMPRESSION
3907cdf0e10cSrcweir     ZCodec* pCodec = new ZCodec( 0x4000, 0x4000 );
3908cdf0e10cSrcweir     SvMemoryStream aStream;
3909cdf0e10cSrcweir     pCodec->BeginCompression();
3910cdf0e10cSrcweir     pCodec->Write( aStream, (const sal_uInt8*)aContents.getStr(), aContents.getLength() );
3911cdf0e10cSrcweir     pCodec->EndCompression();
3912cdf0e10cSrcweir     delete pCodec;
3913cdf0e10cSrcweir #endif
3914cdf0e10cSrcweir 
3915cdf0e10cSrcweir     #if OSL_DEBUG_LEVEL > 1
3916cdf0e10cSrcweir     emitComment( "PDFWriterImpl::createToUnicodeCMap" );
3917cdf0e10cSrcweir     #endif
3918cdf0e10cSrcweir     OStringBuffer aLine( 40 );
3919cdf0e10cSrcweir 
3920cdf0e10cSrcweir     aLine.append( nStream );
3921cdf0e10cSrcweir     aLine.append( " 0 obj\n<</Length " );
3922cdf0e10cSrcweir #ifndef DEBUG_DISABLE_PDFCOMPRESSION
3923cdf0e10cSrcweir     sal_Int32 nLen = (sal_Int32)aStream.Tell();
3924cdf0e10cSrcweir     aStream.Seek( 0 );
3925cdf0e10cSrcweir     aLine.append( nLen );
3926cdf0e10cSrcweir     aLine.append( "/Filter/FlateDecode" );
3927cdf0e10cSrcweir #else
3928cdf0e10cSrcweir     aLine.append( aContents.getLength() );
3929cdf0e10cSrcweir #endif
3930cdf0e10cSrcweir     aLine.append( ">>\nstream\n" );
3931cdf0e10cSrcweir     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
3932cdf0e10cSrcweir     checkAndEnableStreamEncryption( nStream );
3933cdf0e10cSrcweir #ifndef DEBUG_DISABLE_PDFCOMPRESSION
3934cdf0e10cSrcweir     CHECK_RETURN( writeBuffer( aStream.GetData(), nLen ) );
3935cdf0e10cSrcweir #else
3936cdf0e10cSrcweir     CHECK_RETURN( writeBuffer( aContents.getStr(), aContents.getLength() ) );
3937cdf0e10cSrcweir #endif
3938cdf0e10cSrcweir     disableStreamEncryption();
3939cdf0e10cSrcweir     aLine.setLength( 0 );
3940cdf0e10cSrcweir     aLine.append( "\nendstream\n"
3941cdf0e10cSrcweir                   "endobj\n\n" );
3942cdf0e10cSrcweir     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
3943cdf0e10cSrcweir     return nStream;
3944cdf0e10cSrcweir }
3945cdf0e10cSrcweir 
3946cdf0e10cSrcweir sal_Int32 PDFWriterImpl::emitFontDescriptor( const ImplFontData* pFont, FontSubsetInfo& rInfo, sal_Int32 nSubsetID, sal_Int32 nFontStream )
3947cdf0e10cSrcweir {
3948cdf0e10cSrcweir     OStringBuffer aLine( 1024 );
3949cdf0e10cSrcweir     // get font flags, see PDF reference 1.4 p. 358
3950cdf0e10cSrcweir     // possibly characters outside Adobe standard encoding
3951cdf0e10cSrcweir     // so set Symbolic flag
3952cdf0e10cSrcweir     sal_Int32 nFontFlags = (1<<2);
3953cdf0e10cSrcweir     if( pFont->GetSlant() == ITALIC_NORMAL || pFont->GetSlant() == ITALIC_OBLIQUE )
3954cdf0e10cSrcweir         nFontFlags |= (1 << 6);
3955cdf0e10cSrcweir     if( pFont->GetPitch() == PITCH_FIXED )
3956cdf0e10cSrcweir         nFontFlags |= 1;
3957cdf0e10cSrcweir     if( pFont->GetFamilyType() == FAMILY_SCRIPT )
3958cdf0e10cSrcweir         nFontFlags |= (1 << 3);
3959cdf0e10cSrcweir     else if( pFont->GetFamilyType() == FAMILY_ROMAN )
3960cdf0e10cSrcweir         nFontFlags |= (1 << 1);
3961cdf0e10cSrcweir 
3962cdf0e10cSrcweir     sal_Int32 nFontDescriptor = createObject();
3963cdf0e10cSrcweir     CHECK_RETURN( updateObject( nFontDescriptor ) );
3964cdf0e10cSrcweir     aLine.setLength( 0 );
3965cdf0e10cSrcweir     aLine.append( nFontDescriptor );
3966cdf0e10cSrcweir     aLine.append( " 0 obj\n"
3967cdf0e10cSrcweir                   "<</Type/FontDescriptor/FontName/" );
3968cdf0e10cSrcweir     appendSubsetName( nSubsetID, rInfo.m_aPSName, aLine );
3969cdf0e10cSrcweir     aLine.append( "\n"
3970cdf0e10cSrcweir                   "/Flags " );
3971cdf0e10cSrcweir     aLine.append( nFontFlags );
3972cdf0e10cSrcweir     aLine.append( "\n"
3973cdf0e10cSrcweir                   "/FontBBox[" );
3974cdf0e10cSrcweir     // note: Top and Bottom are reversed in VCL and PDF rectangles
3975cdf0e10cSrcweir     aLine.append( (sal_Int32)rInfo.m_aFontBBox.TopLeft().X() );
3976cdf0e10cSrcweir     aLine.append( ' ' );
3977cdf0e10cSrcweir     aLine.append( (sal_Int32)rInfo.m_aFontBBox.TopLeft().Y() );
3978cdf0e10cSrcweir     aLine.append( ' ' );
3979cdf0e10cSrcweir     aLine.append( (sal_Int32)rInfo.m_aFontBBox.BottomRight().X() );
3980cdf0e10cSrcweir     aLine.append( ' ' );
3981cdf0e10cSrcweir     aLine.append( (sal_Int32)(rInfo.m_aFontBBox.BottomRight().Y()+1) );
3982cdf0e10cSrcweir     aLine.append( "]/ItalicAngle " );
3983cdf0e10cSrcweir     if( pFont->GetSlant() == ITALIC_OBLIQUE || pFont->GetSlant() == ITALIC_NORMAL )
3984cdf0e10cSrcweir         aLine.append( "-30" );
3985cdf0e10cSrcweir     else
3986cdf0e10cSrcweir         aLine.append( "0" );
3987cdf0e10cSrcweir     aLine.append( "\n"
3988cdf0e10cSrcweir                   "/Ascent " );
3989cdf0e10cSrcweir     aLine.append( (sal_Int32)rInfo.m_nAscent );
3990cdf0e10cSrcweir     aLine.append( "\n"
3991cdf0e10cSrcweir                   "/Descent " );
3992cdf0e10cSrcweir     aLine.append( (sal_Int32)-rInfo.m_nDescent );
3993cdf0e10cSrcweir     aLine.append( "\n"
3994cdf0e10cSrcweir                   "/CapHeight " );
3995cdf0e10cSrcweir     aLine.append( (sal_Int32)rInfo.m_nCapHeight );
3996cdf0e10cSrcweir     // According to PDF reference 1.4 StemV is required
3997cdf0e10cSrcweir     // seems a tad strange to me, but well ...
3998cdf0e10cSrcweir     aLine.append( "\n"
3999cdf0e10cSrcweir                   "/StemV 80\n" );
4000cdf0e10cSrcweir     if( nFontStream )
4001cdf0e10cSrcweir     {
4002cdf0e10cSrcweir         aLine.append( "/FontFile" );
4003cdf0e10cSrcweir         switch( rInfo.m_nFontType )
4004cdf0e10cSrcweir         {
4005cdf0e10cSrcweir             case FontSubsetInfo::SFNT_TTF:
4006cdf0e10cSrcweir                 aLine.append( '2' );
4007cdf0e10cSrcweir                 break;
4008cdf0e10cSrcweir             case FontSubsetInfo::TYPE1_PFA:
4009cdf0e10cSrcweir             case FontSubsetInfo::TYPE1_PFB:
4010cdf0e10cSrcweir             case FontSubsetInfo::ANY_TYPE1:
4011cdf0e10cSrcweir                 break;
4012cdf0e10cSrcweir             default:
4013cdf0e10cSrcweir                 DBG_ERROR( "unknown fonttype in PDF font descriptor" );
4014cdf0e10cSrcweir                 return 0;
4015cdf0e10cSrcweir         }
4016cdf0e10cSrcweir         aLine.append( ' ' );
4017cdf0e10cSrcweir         aLine.append( nFontStream );
4018cdf0e10cSrcweir         aLine.append( " 0 R\n" );
4019cdf0e10cSrcweir     }
4020cdf0e10cSrcweir     aLine.append( ">>\n"
4021cdf0e10cSrcweir                   "endobj\n\n" );
4022cdf0e10cSrcweir     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
4023cdf0e10cSrcweir 
4024cdf0e10cSrcweir     return nFontDescriptor;
4025cdf0e10cSrcweir }
4026cdf0e10cSrcweir 
4027cdf0e10cSrcweir void PDFWriterImpl::appendBuiltinFontsToDict( OStringBuffer& rDict ) const
4028cdf0e10cSrcweir {
4029cdf0e10cSrcweir     for( std::map< sal_Int32, sal_Int32 >::const_iterator it =
4030cdf0e10cSrcweir          m_aBuiltinFontToObjectMap.begin(); it != m_aBuiltinFontToObjectMap.end(); ++it )
4031cdf0e10cSrcweir     {
4032cdf0e10cSrcweir         rDict.append( m_aBuiltinFonts[it->first].getNameObject() );
4033cdf0e10cSrcweir         rDict.append( ' ' );
4034cdf0e10cSrcweir         rDict.append( it->second );
4035cdf0e10cSrcweir         rDict.append( " 0 R" );
4036cdf0e10cSrcweir     }
4037cdf0e10cSrcweir }
4038cdf0e10cSrcweir 
4039cdf0e10cSrcweir bool PDFWriterImpl::emitFonts()
4040cdf0e10cSrcweir {
4041cdf0e10cSrcweir     if( ! m_pReferenceDevice->ImplGetGraphics() )
4042cdf0e10cSrcweir         return false;
4043cdf0e10cSrcweir 
4044cdf0e10cSrcweir     OStringBuffer aLine( 1024 );
4045cdf0e10cSrcweir 
4046cdf0e10cSrcweir     std::map< sal_Int32, sal_Int32 > aFontIDToObject;
4047cdf0e10cSrcweir 
4048cdf0e10cSrcweir     OUString aTmpName;
4049cdf0e10cSrcweir     osl_createTempFile( NULL, NULL, &aTmpName.pData );
4050cdf0e10cSrcweir     for( FontSubsetData::iterator it = m_aSubsets.begin(); it != m_aSubsets.end(); ++it )
4051cdf0e10cSrcweir     {
4052cdf0e10cSrcweir         for( FontEmitList::iterator lit = it->second.m_aSubsets.begin(); lit != it->second.m_aSubsets.end(); ++lit )
4053cdf0e10cSrcweir         {
4054cdf0e10cSrcweir             sal_Int32 pGlyphIDs[ 256 ];
4055cdf0e10cSrcweir             sal_Int32 pWidths[ 256 ];
4056cdf0e10cSrcweir             sal_uInt8 pEncoding[ 256 ];
4057cdf0e10cSrcweir             sal_Int32 pEncToUnicodeIndex[ 256 ];
4058cdf0e10cSrcweir             sal_Int32 pUnicodesPerGlyph[ 256 ];
4059cdf0e10cSrcweir             std::vector<sal_Ucs> aUnicodes;
4060cdf0e10cSrcweir             aUnicodes.reserve( 256 );
4061cdf0e10cSrcweir             int nGlyphs = 1;
4062cdf0e10cSrcweir             // fill arrays and prepare encoding index map
4063cdf0e10cSrcweir             sal_Int32 nToUnicodeStream = 0;
4064cdf0e10cSrcweir 
4065cdf0e10cSrcweir             rtl_zeroMemory( pGlyphIDs, sizeof( pGlyphIDs ) );
4066cdf0e10cSrcweir             rtl_zeroMemory( pEncoding, sizeof( pEncoding ) );
4067cdf0e10cSrcweir             rtl_zeroMemory( pUnicodesPerGlyph, sizeof( pUnicodesPerGlyph ) );
4068cdf0e10cSrcweir             rtl_zeroMemory( pEncToUnicodeIndex, sizeof( pEncToUnicodeIndex ) );
4069cdf0e10cSrcweir             for( FontEmitMapping::iterator fit = lit->m_aMapping.begin(); fit != lit->m_aMapping.end();++fit )
4070cdf0e10cSrcweir             {
4071cdf0e10cSrcweir                 sal_uInt8 nEnc = fit->second.getGlyphId();
4072cdf0e10cSrcweir 
4073cdf0e10cSrcweir                 DBG_ASSERT( pGlyphIDs[nEnc] == 0 && pEncoding[nEnc] == 0, "duplicate glyph" );
4074cdf0e10cSrcweir                 DBG_ASSERT( nEnc <= lit->m_aMapping.size(), "invalid glyph encoding" );
4075cdf0e10cSrcweir 
4076cdf0e10cSrcweir                 pGlyphIDs[ nEnc ] = fit->first;
4077cdf0e10cSrcweir                 pEncoding[ nEnc ] = nEnc;
4078cdf0e10cSrcweir                 pEncToUnicodeIndex[ nEnc ] = static_cast<sal_Int32>(aUnicodes.size());
4079cdf0e10cSrcweir                 pUnicodesPerGlyph[ nEnc ] = fit->second.countCodes();
4080cdf0e10cSrcweir                 for( sal_Int32 n = 0; n < pUnicodesPerGlyph[ nEnc ]; n++ )
4081cdf0e10cSrcweir                     aUnicodes.push_back( fit->second.getCode( n ) );
4082cdf0e10cSrcweir                 if( fit->second.getCode(0) )
4083cdf0e10cSrcweir                     nToUnicodeStream = 1;
4084cdf0e10cSrcweir                 if( nGlyphs < 256 )
4085cdf0e10cSrcweir                     nGlyphs++;
4086cdf0e10cSrcweir                 else
4087cdf0e10cSrcweir                 {
4088cdf0e10cSrcweir                     DBG_ERROR( "too many glyphs for subset" );
4089cdf0e10cSrcweir                 }
4090cdf0e10cSrcweir             }
4091cdf0e10cSrcweir             FontSubsetInfo aSubsetInfo;
4092cdf0e10cSrcweir             if( m_pReferenceDevice->mpGraphics->CreateFontSubset( aTmpName, it->first, pGlyphIDs, pEncoding, pWidths, nGlyphs, aSubsetInfo ) )
4093cdf0e10cSrcweir             {
4094cdf0e10cSrcweir                 // create font stream
4095cdf0e10cSrcweir                 oslFileHandle aFontFile;
4096cdf0e10cSrcweir                 CHECK_RETURN( (osl_File_E_None == osl_openFile( aTmpName.pData, &aFontFile, osl_File_OpenFlag_Read ) ) );
4097cdf0e10cSrcweir                 // get file size
4098cdf0e10cSrcweir                 sal_uInt64 nLength1;
4099cdf0e10cSrcweir                 CHECK_RETURN( (osl_File_E_None == osl_setFilePos( aFontFile, osl_Pos_End, 0 ) ) );
4100cdf0e10cSrcweir                 CHECK_RETURN( (osl_File_E_None == osl_getFilePos( aFontFile, &nLength1 ) ) );
4101cdf0e10cSrcweir                 CHECK_RETURN( (osl_File_E_None == osl_setFilePos( aFontFile, osl_Pos_Absolut, 0 ) ) );
4102cdf0e10cSrcweir 
4103cdf0e10cSrcweir                 #if OSL_DEBUG_LEVEL > 1
4104cdf0e10cSrcweir                 emitComment( "PDFWriterImpl::emitFonts" );
4105cdf0e10cSrcweir                 #endif
4106cdf0e10cSrcweir                 sal_Int32 nFontStream = createObject();
4107cdf0e10cSrcweir                 sal_Int32 nStreamLengthObject = createObject();
4108cdf0e10cSrcweir                 CHECK_RETURN( updateObject( nFontStream ) );
4109cdf0e10cSrcweir                 aLine.setLength( 0 );
4110cdf0e10cSrcweir                 aLine.append( nFontStream );
4111cdf0e10cSrcweir                 aLine.append( " 0 obj\n"
4112cdf0e10cSrcweir                              "<</Length " );
4113cdf0e10cSrcweir                 aLine.append( (sal_Int32)nStreamLengthObject );
4114cdf0e10cSrcweir                 aLine.append( " 0 R"
4115cdf0e10cSrcweir                              #ifndef DEBUG_DISABLE_PDFCOMPRESSION
4116cdf0e10cSrcweir                              "/Filter/FlateDecode"
4117cdf0e10cSrcweir                              #endif
4118cdf0e10cSrcweir                              "/Length1 " );
4119cdf0e10cSrcweir 
4120cdf0e10cSrcweir                 sal_uInt64 nStartPos = 0;
4121cdf0e10cSrcweir                 if( aSubsetInfo.m_nFontType == FontSubsetInfo::SFNT_TTF )
4122cdf0e10cSrcweir                 {
4123cdf0e10cSrcweir                     aLine.append( (sal_Int32)nLength1 );
4124cdf0e10cSrcweir 
4125cdf0e10cSrcweir                     aLine.append( ">>\n"
4126cdf0e10cSrcweir                                  "stream\n" );
4127cdf0e10cSrcweir                     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
4128cdf0e10cSrcweir                     CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nStartPos ) ) );
4129cdf0e10cSrcweir 
4130cdf0e10cSrcweir                     // copy font file
4131cdf0e10cSrcweir                     beginCompression();
4132cdf0e10cSrcweir                     checkAndEnableStreamEncryption( nFontStream );
4133cdf0e10cSrcweir                     sal_Bool bEOF = sal_False;
4134cdf0e10cSrcweir                     do
4135cdf0e10cSrcweir                     {
4136cdf0e10cSrcweir                         char buf[8192];
4137cdf0e10cSrcweir                         sal_uInt64 nRead;
4138cdf0e10cSrcweir                         CHECK_RETURN( (osl_File_E_None == osl_readFile( aFontFile, buf, sizeof( buf ), &nRead ) ) );
4139cdf0e10cSrcweir                         CHECK_RETURN( writeBuffer( buf, nRead ) );
4140cdf0e10cSrcweir                         CHECK_RETURN( (osl_File_E_None == osl_isEndOfFile( aFontFile, &bEOF ) ) );
4141cdf0e10cSrcweir                     } while( ! bEOF );
4142cdf0e10cSrcweir                 }
4143cdf0e10cSrcweir                 else if( (aSubsetInfo.m_nFontType & FontSubsetInfo::CFF_FONT) != 0 )
4144cdf0e10cSrcweir                 {
4145cdf0e10cSrcweir                     // TODO: implement
4146cdf0e10cSrcweir                     DBG_ERROR( "PDFWriterImpl does not support CFF-font subsets yet!" );
4147cdf0e10cSrcweir                 }
4148cdf0e10cSrcweir                 else if( (aSubsetInfo.m_nFontType & FontSubsetInfo::TYPE1_PFB) != 0 ) // TODO: also support PFA?
4149cdf0e10cSrcweir                 {
4150cdf0e10cSrcweir                     boost::shared_array<unsigned char> pBuffer( new unsigned char[ nLength1 ] );
4151cdf0e10cSrcweir 
4152cdf0e10cSrcweir                     sal_uInt64 nBytesRead = 0;
4153cdf0e10cSrcweir                     CHECK_RETURN( (osl_File_E_None == osl_readFile( aFontFile, pBuffer.get(), nLength1, &nBytesRead ) ) );
4154cdf0e10cSrcweir                     DBG_ASSERT( nBytesRead==nLength1, "PDF-FontSubset read incomplete!" );
4155cdf0e10cSrcweir                     CHECK_RETURN( (osl_File_E_None == osl_setFilePos( aFontFile, osl_Pos_Absolut, 0 ) ) );
4156cdf0e10cSrcweir                     // get the PFB-segment lengths
4157cdf0e10cSrcweir                     ThreeInts aSegmentLengths = {0,0,0};
4158cdf0e10cSrcweir                     getPfbSegmentLengths( pBuffer.get(), (int)nBytesRead, aSegmentLengths );
4159cdf0e10cSrcweir                     // the lengths below are mandatory for PDF-exported Type1 fonts
4160cdf0e10cSrcweir                     // because the PFB segment headers get stripped! WhyOhWhy.
4161cdf0e10cSrcweir                     aLine.append( (sal_Int32)aSegmentLengths[0] );
4162cdf0e10cSrcweir                     aLine.append( "/Length2 " );
4163cdf0e10cSrcweir                     aLine.append( (sal_Int32)aSegmentLengths[1] );
4164cdf0e10cSrcweir                     aLine.append( "/Length3 " );
4165cdf0e10cSrcweir                     aLine.append( (sal_Int32)aSegmentLengths[2] );
4166cdf0e10cSrcweir 
4167cdf0e10cSrcweir                     aLine.append( ">>\n"
4168cdf0e10cSrcweir                                  "stream\n" );
4169cdf0e10cSrcweir                     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
4170cdf0e10cSrcweir                     CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nStartPos ) ) );
4171cdf0e10cSrcweir 
4172cdf0e10cSrcweir                     // emit PFB-sections without section headers
4173cdf0e10cSrcweir                     beginCompression();
4174cdf0e10cSrcweir                     checkAndEnableStreamEncryption( nFontStream );
4175cdf0e10cSrcweir                     CHECK_RETURN( writeBuffer( &pBuffer[6], aSegmentLengths[0] ) );
4176cdf0e10cSrcweir                     CHECK_RETURN( writeBuffer( &pBuffer[12] + aSegmentLengths[0], aSegmentLengths[1] ) );
4177cdf0e10cSrcweir                     CHECK_RETURN( writeBuffer( &pBuffer[18] + aSegmentLengths[0] + aSegmentLengths[1], aSegmentLengths[2] ) );
4178cdf0e10cSrcweir                 }
4179cdf0e10cSrcweir                 else
4180cdf0e10cSrcweir                 {
4181cdf0e10cSrcweir                     fprintf( stderr, "PDF: CreateFontSubset result in not yet supported format=%d\n",aSubsetInfo.m_nFontType);
4182cdf0e10cSrcweir                     aLine.append( "0 >>\nstream\n" );
4183cdf0e10cSrcweir                 }
4184cdf0e10cSrcweir 
4185cdf0e10cSrcweir                 endCompression();
4186cdf0e10cSrcweir                 disableStreamEncryption();
4187cdf0e10cSrcweir                 // close the file
4188cdf0e10cSrcweir                 osl_closeFile( aFontFile );
4189cdf0e10cSrcweir 
4190cdf0e10cSrcweir                 sal_uInt64 nEndPos = 0;
4191cdf0e10cSrcweir                 CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nEndPos ) ) );
4192cdf0e10cSrcweir                 // end the stream
4193cdf0e10cSrcweir                 aLine.setLength( 0 );
4194cdf0e10cSrcweir                 aLine.append( "\nendstream\nendobj\n\n" );
4195cdf0e10cSrcweir                 CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
4196cdf0e10cSrcweir 
4197cdf0e10cSrcweir                 // emit stream length object
4198cdf0e10cSrcweir                 CHECK_RETURN( updateObject( nStreamLengthObject ) );
4199cdf0e10cSrcweir                 aLine.setLength( 0 );
4200cdf0e10cSrcweir                 aLine.append( nStreamLengthObject );
4201cdf0e10cSrcweir                 aLine.append( " 0 obj\n" );
4202cdf0e10cSrcweir                 aLine.append( (sal_Int64)(nEndPos-nStartPos) );
4203cdf0e10cSrcweir                 aLine.append( "\nendobj\n\n" );
4204cdf0e10cSrcweir                 CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
4205cdf0e10cSrcweir 
4206cdf0e10cSrcweir                 // write font descriptor
4207cdf0e10cSrcweir                 sal_Int32 nFontDescriptor = emitFontDescriptor( it->first, aSubsetInfo, lit->m_nFontID, nFontStream );
4208cdf0e10cSrcweir 
4209cdf0e10cSrcweir                 if( nToUnicodeStream )
4210cdf0e10cSrcweir                     nToUnicodeStream = createToUnicodeCMap( pEncoding, &aUnicodes[0], pUnicodesPerGlyph, pEncToUnicodeIndex, nGlyphs );
4211cdf0e10cSrcweir 
4212cdf0e10cSrcweir                 sal_Int32 nFontObject = createObject();
4213cdf0e10cSrcweir                 CHECK_RETURN( updateObject( nFontObject ) );
4214cdf0e10cSrcweir                 aLine.setLength( 0 );
4215cdf0e10cSrcweir                 aLine.append( nFontObject );
4216cdf0e10cSrcweir 
4217cdf0e10cSrcweir                 aLine.append( " 0 obj\n" );
4218cdf0e10cSrcweir                 aLine.append( ((aSubsetInfo.m_nFontType & FontSubsetInfo::ANY_TYPE1) != 0) ?
4219cdf0e10cSrcweir                              "<</Type/Font/Subtype/Type1/BaseFont/" :
4220cdf0e10cSrcweir                              "<</Type/Font/Subtype/TrueType/BaseFont/" );
4221cdf0e10cSrcweir                 appendSubsetName( lit->m_nFontID, aSubsetInfo.m_aPSName, aLine );
4222cdf0e10cSrcweir                 aLine.append( "\n"
4223cdf0e10cSrcweir                              "/FirstChar 0\n"
4224cdf0e10cSrcweir                              "/LastChar " );
4225cdf0e10cSrcweir                 aLine.append( (sal_Int32)(nGlyphs-1) );
4226cdf0e10cSrcweir                 aLine.append( "\n"
4227cdf0e10cSrcweir                              "/Widths[" );
4228cdf0e10cSrcweir                 for( int i = 0; i < nGlyphs; i++ )
4229cdf0e10cSrcweir                 {
4230cdf0e10cSrcweir                     aLine.append( pWidths[ i ] );
4231cdf0e10cSrcweir                     aLine.append( ((i & 15) == 15) ? "\n" : " " );
4232cdf0e10cSrcweir                 }
4233cdf0e10cSrcweir                 aLine.append( "]\n"
4234cdf0e10cSrcweir                              "/FontDescriptor " );
4235cdf0e10cSrcweir                 aLine.append( nFontDescriptor );
4236cdf0e10cSrcweir                 aLine.append( " 0 R\n" );
4237cdf0e10cSrcweir                 if( nToUnicodeStream )
4238cdf0e10cSrcweir                 {
4239cdf0e10cSrcweir                     aLine.append( "/ToUnicode " );
4240cdf0e10cSrcweir                     aLine.append( nToUnicodeStream );
4241cdf0e10cSrcweir                     aLine.append( " 0 R\n" );
4242cdf0e10cSrcweir                 }
4243cdf0e10cSrcweir                 aLine.append( ">>\n"
4244cdf0e10cSrcweir                              "endobj\n\n" );
4245cdf0e10cSrcweir                 CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
4246cdf0e10cSrcweir 
4247cdf0e10cSrcweir                 aFontIDToObject[ lit->m_nFontID ] = nFontObject;
4248cdf0e10cSrcweir             }
4249cdf0e10cSrcweir             else
4250cdf0e10cSrcweir             {
4251cdf0e10cSrcweir                 const ImplFontData* pFont = it->first;
4252cdf0e10cSrcweir                 rtl::OStringBuffer aErrorComment( 256 );
4253cdf0e10cSrcweir                 aErrorComment.append( "CreateFontSubset failed for font \"" );
4254cdf0e10cSrcweir                 aErrorComment.append( OUStringToOString( pFont->GetFamilyName(), RTL_TEXTENCODING_UTF8 ) );
4255cdf0e10cSrcweir                 aErrorComment.append( '\"' );
4256cdf0e10cSrcweir                 if( pFont->GetSlant() == ITALIC_NORMAL )
4257cdf0e10cSrcweir                     aErrorComment.append( " italic" );
4258cdf0e10cSrcweir                 else if( pFont->GetSlant() == ITALIC_OBLIQUE )
4259cdf0e10cSrcweir                     aErrorComment.append( " oblique" );
4260cdf0e10cSrcweir                 aErrorComment.append( " weight=" );
4261cdf0e10cSrcweir                 aErrorComment.append( sal_Int32(pFont->GetWeight()) );
4262cdf0e10cSrcweir                 emitComment( aErrorComment.getStr() );
4263cdf0e10cSrcweir             }
4264cdf0e10cSrcweir         }
4265cdf0e10cSrcweir     }
4266cdf0e10cSrcweir     osl_removeFile( aTmpName.pData );
4267cdf0e10cSrcweir 
4268cdf0e10cSrcweir     // emit embedded fonts
4269cdf0e10cSrcweir     for( FontEmbedData::iterator eit = m_aEmbeddedFonts.begin(); eit != m_aEmbeddedFonts.end(); ++eit )
4270cdf0e10cSrcweir     {
4271cdf0e10cSrcweir         std::map< sal_Int32, sal_Int32 > aObjects = emitEmbeddedFont( eit->first, eit->second );
4272cdf0e10cSrcweir         for( std::map< sal_Int32, sal_Int32 >::iterator fit = aObjects.begin(); fit != aObjects.end(); ++fit )
4273cdf0e10cSrcweir         {
4274cdf0e10cSrcweir             CHECK_RETURN( fit->second );
4275cdf0e10cSrcweir             aFontIDToObject[ fit->first ] = fit->second;
4276cdf0e10cSrcweir         }
4277cdf0e10cSrcweir     }
4278cdf0e10cSrcweir 
4279cdf0e10cSrcweir     // emit system fonts
4280cdf0e10cSrcweir     for( FontEmbedData::iterator sit = m_aSystemFonts.begin(); sit != m_aSystemFonts.end(); ++sit )
4281cdf0e10cSrcweir     {
4282cdf0e10cSrcweir         std::map< sal_Int32, sal_Int32 > aObjects = emitSystemFont( sit->first, sit->second );
4283cdf0e10cSrcweir         for( std::map< sal_Int32, sal_Int32 >::iterator fit = aObjects.begin(); fit != aObjects.end(); ++fit )
4284cdf0e10cSrcweir         {
4285cdf0e10cSrcweir             CHECK_RETURN( fit->second );
4286cdf0e10cSrcweir             aFontIDToObject[ fit->first ] = fit->second;
4287cdf0e10cSrcweir         }
4288cdf0e10cSrcweir     }
4289cdf0e10cSrcweir 
4290cdf0e10cSrcweir     OStringBuffer aFontDict( 1024 );
4291cdf0e10cSrcweir     aFontDict.append( getFontDictObject() );
4292cdf0e10cSrcweir     aFontDict.append( " 0 obj\n"
4293cdf0e10cSrcweir                      "<<" );
4294cdf0e10cSrcweir     int ni = 0;
4295cdf0e10cSrcweir     for( std::map< sal_Int32, sal_Int32 >::iterator mit = aFontIDToObject.begin(); mit != aFontIDToObject.end(); ++mit )
4296cdf0e10cSrcweir     {
4297cdf0e10cSrcweir         aFontDict.append( "/F" );
4298cdf0e10cSrcweir         aFontDict.append( mit->first );
4299cdf0e10cSrcweir         aFontDict.append( ' ' );
4300cdf0e10cSrcweir         aFontDict.append( mit->second );
4301cdf0e10cSrcweir         aFontDict.append( " 0 R" );
4302cdf0e10cSrcweir         if( ((++ni) & 7) == 0 )
4303cdf0e10cSrcweir             aFontDict.append( '\n' );
4304cdf0e10cSrcweir     }
4305cdf0e10cSrcweir     // emit builtin font for widget apperances / variable text
4306cdf0e10cSrcweir     for( std::map< sal_Int32, sal_Int32 >::iterator it = m_aBuiltinFontToObjectMap.begin();
4307cdf0e10cSrcweir         it != m_aBuiltinFontToObjectMap.end(); ++it )
4308cdf0e10cSrcweir     {
4309cdf0e10cSrcweir         ImplPdfBuiltinFontData aData(m_aBuiltinFonts[it->first]);
4310cdf0e10cSrcweir         it->second = emitBuiltinFont( &aData, it->second );
4311cdf0e10cSrcweir     }
4312cdf0e10cSrcweir     appendBuiltinFontsToDict( aFontDict );
4313cdf0e10cSrcweir     aFontDict.append( "\n>>\nendobj\n\n" );
4314cdf0e10cSrcweir 
4315cdf0e10cSrcweir     CHECK_RETURN( updateObject( getFontDictObject() ) );
4316cdf0e10cSrcweir     CHECK_RETURN( writeBuffer( aFontDict.getStr(), aFontDict.getLength() ) );
4317cdf0e10cSrcweir     return true;
4318cdf0e10cSrcweir }
4319cdf0e10cSrcweir 
4320cdf0e10cSrcweir sal_Int32 PDFWriterImpl::emitResources()
4321cdf0e10cSrcweir {
4322cdf0e10cSrcweir     // emit shadings
4323cdf0e10cSrcweir     if( ! m_aGradients.empty() )
4324cdf0e10cSrcweir         CHECK_RETURN( emitGradients() );
4325cdf0e10cSrcweir     // emit tilings
4326cdf0e10cSrcweir     if( ! m_aTilings.empty() )
4327cdf0e10cSrcweir         CHECK_RETURN( emitTilings() );
4328cdf0e10cSrcweir 
4329cdf0e10cSrcweir     // emit font dict
4330cdf0e10cSrcweir     CHECK_RETURN( emitFonts() );
4331cdf0e10cSrcweir 
4332cdf0e10cSrcweir     // emit Resource dict
4333cdf0e10cSrcweir     OStringBuffer aLine( 512 );
4334cdf0e10cSrcweir     sal_Int32 nResourceDict = getResourceDictObj();
4335cdf0e10cSrcweir     CHECK_RETURN( updateObject( nResourceDict ) );
4336cdf0e10cSrcweir     aLine.setLength( 0 );
4337cdf0e10cSrcweir     aLine.append( nResourceDict );
4338cdf0e10cSrcweir     aLine.append( " 0 obj\n" );
4339cdf0e10cSrcweir     m_aGlobalResourceDict.append( aLine, getFontDictObject() );
4340cdf0e10cSrcweir     aLine.append( "endobj\n\n" );
4341cdf0e10cSrcweir     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
4342cdf0e10cSrcweir     return nResourceDict;
4343cdf0e10cSrcweir }
4344cdf0e10cSrcweir 
4345cdf0e10cSrcweir sal_Int32 PDFWriterImpl::updateOutlineItemCount( std::vector< sal_Int32 >& rCounts,
4346cdf0e10cSrcweir                                                  sal_Int32 nItemLevel,
4347cdf0e10cSrcweir                                                  sal_Int32 nCurrentItemId )
4348cdf0e10cSrcweir {
4349cdf0e10cSrcweir     /* The /Count number of an item is
4350cdf0e10cSrcweir        positive: the number of visible subitems
4351cdf0e10cSrcweir        negative: the negative number of subitems that will become visible if
4352cdf0e10cSrcweir                  the item gets opened
4353cdf0e10cSrcweir        see PDF ref 1.4 p 478
4354cdf0e10cSrcweir     */
4355cdf0e10cSrcweir 
4356cdf0e10cSrcweir     sal_Int32 nCount = 0;
4357cdf0e10cSrcweir 
4358cdf0e10cSrcweir     if( m_aContext.OpenBookmarkLevels < 0           || // all levels arevisible
4359cdf0e10cSrcweir         m_aContext.OpenBookmarkLevels >= nItemLevel    // this level is visible
4360cdf0e10cSrcweir       )
4361cdf0e10cSrcweir     {
4362cdf0e10cSrcweir         PDFOutlineEntry& rItem = m_aOutline[ nCurrentItemId ];
4363cdf0e10cSrcweir         sal_Int32 nChildren = rItem.m_aChildren.size();
4364cdf0e10cSrcweir         for( sal_Int32 i = 0; i < nChildren; i++ )
4365cdf0e10cSrcweir             nCount += updateOutlineItemCount( rCounts, nItemLevel+1, rItem.m_aChildren[i] );
4366cdf0e10cSrcweir         rCounts[nCurrentItemId] = nCount;
4367cdf0e10cSrcweir         // return 1 (this item) + visible sub items
4368cdf0e10cSrcweir         if( nCount < 0 )
4369cdf0e10cSrcweir             nCount = 0;
4370cdf0e10cSrcweir         nCount++;
4371cdf0e10cSrcweir     }
4372cdf0e10cSrcweir     else
4373cdf0e10cSrcweir     {
4374cdf0e10cSrcweir         // this bookmark level is invisible
4375cdf0e10cSrcweir         PDFOutlineEntry& rItem = m_aOutline[ nCurrentItemId ];
4376cdf0e10cSrcweir         sal_Int32 nChildren = rItem.m_aChildren.size();
4377cdf0e10cSrcweir         rCounts[ nCurrentItemId ] = -sal_Int32(rItem.m_aChildren.size());
4378cdf0e10cSrcweir         for( sal_Int32 i = 0; i < nChildren; i++ )
4379cdf0e10cSrcweir             updateOutlineItemCount( rCounts, nItemLevel+1, rItem.m_aChildren[i] );
4380cdf0e10cSrcweir         nCount = -1;
4381cdf0e10cSrcweir     }
4382cdf0e10cSrcweir 
4383cdf0e10cSrcweir     return nCount;
4384cdf0e10cSrcweir }
4385cdf0e10cSrcweir 
4386cdf0e10cSrcweir sal_Int32 PDFWriterImpl::emitOutline()
4387cdf0e10cSrcweir {
4388cdf0e10cSrcweir     int i, nItems = m_aOutline.size();
4389cdf0e10cSrcweir 
4390cdf0e10cSrcweir     // do we have an outline at all ?
4391cdf0e10cSrcweir     if( nItems < 2 )
4392cdf0e10cSrcweir         return 0;
4393cdf0e10cSrcweir 
4394cdf0e10cSrcweir     // reserve object numbers for all outline items
4395cdf0e10cSrcweir     for( i = 0; i < nItems; ++i )
4396cdf0e10cSrcweir         m_aOutline[i].m_nObject = createObject();
4397cdf0e10cSrcweir 
4398cdf0e10cSrcweir     // update all parent, next and prev object ids
4399cdf0e10cSrcweir     for( i = 0; i < nItems; ++i )
4400cdf0e10cSrcweir     {
4401cdf0e10cSrcweir         PDFOutlineEntry& rItem = m_aOutline[i];
4402cdf0e10cSrcweir         int nChildren = rItem.m_aChildren.size();
4403cdf0e10cSrcweir 
4404cdf0e10cSrcweir         if( nChildren )
4405cdf0e10cSrcweir         {
4406cdf0e10cSrcweir             for( int n = 0; n < nChildren; ++n )
4407cdf0e10cSrcweir             {
4408cdf0e10cSrcweir                 PDFOutlineEntry& rChild = m_aOutline[ rItem.m_aChildren[n] ];
4409cdf0e10cSrcweir 
4410cdf0e10cSrcweir                 rChild.m_nParentObject = rItem.m_nObject;
4411cdf0e10cSrcweir                 rChild.m_nPrevObject = (n > 0) ? m_aOutline[ rItem.m_aChildren[n-1] ].m_nObject : 0;
4412cdf0e10cSrcweir                 rChild.m_nNextObject = (n < nChildren-1) ? m_aOutline[ rItem.m_aChildren[n+1] ].m_nObject : 0;
4413cdf0e10cSrcweir             }
4414cdf0e10cSrcweir 
4415cdf0e10cSrcweir         }
4416cdf0e10cSrcweir     }
4417cdf0e10cSrcweir 
4418cdf0e10cSrcweir     // calculate Count entries for all items
4419cdf0e10cSrcweir     std::vector< sal_Int32 > aCounts( nItems );
4420cdf0e10cSrcweir     updateOutlineItemCount( aCounts, 0, 0 );
4421cdf0e10cSrcweir 
4422cdf0e10cSrcweir     // emit hierarchy
4423cdf0e10cSrcweir     for( i = 0; i < nItems; ++i )
4424cdf0e10cSrcweir     {
4425cdf0e10cSrcweir         PDFOutlineEntry& rItem = m_aOutline[i];
4426cdf0e10cSrcweir         OStringBuffer aLine( 1024 );
4427cdf0e10cSrcweir 
4428cdf0e10cSrcweir         CHECK_RETURN( updateObject( rItem.m_nObject ) );
4429cdf0e10cSrcweir         aLine.append( rItem.m_nObject );
4430cdf0e10cSrcweir         aLine.append( " 0 obj\n" );
4431cdf0e10cSrcweir         aLine.append( "<<" );
4432cdf0e10cSrcweir         // number of visible children (all levels)
4433cdf0e10cSrcweir         if( i > 0 || aCounts[0] > 0 )
4434cdf0e10cSrcweir         {
4435cdf0e10cSrcweir             aLine.append( "/Count " );
4436cdf0e10cSrcweir             aLine.append( aCounts[i] );
4437cdf0e10cSrcweir         }
4438cdf0e10cSrcweir         if( ! rItem.m_aChildren.empty() )
4439cdf0e10cSrcweir         {
4440cdf0e10cSrcweir             // children list: First, Last
4441cdf0e10cSrcweir             aLine.append( "/First " );
4442cdf0e10cSrcweir             aLine.append( m_aOutline[rItem.m_aChildren.front()].m_nObject );
4443cdf0e10cSrcweir             aLine.append( " 0 R/Last " );
4444cdf0e10cSrcweir             aLine.append( m_aOutline[rItem.m_aChildren.back()].m_nObject );
4445cdf0e10cSrcweir             aLine.append( " 0 R\n" );
4446cdf0e10cSrcweir         }
4447cdf0e10cSrcweir         if( i > 0 )
4448cdf0e10cSrcweir         {
4449cdf0e10cSrcweir             // Title, Dest, Parent, Prev, Next
4450cdf0e10cSrcweir             aLine.append( "/Title" );
4451cdf0e10cSrcweir             appendUnicodeTextStringEncrypt( rItem.m_aTitle, rItem.m_nObject, aLine );
4452cdf0e10cSrcweir             aLine.append( "\n" );
4453cdf0e10cSrcweir             // Dest is not required
4454cdf0e10cSrcweir             if( rItem.m_nDestID >= 0 && rItem.m_nDestID < (sal_Int32)m_aDests.size() )
4455cdf0e10cSrcweir             {
4456cdf0e10cSrcweir                 aLine.append( "/Dest" );
4457cdf0e10cSrcweir                 appendDest( rItem.m_nDestID, aLine );
4458cdf0e10cSrcweir             }
4459cdf0e10cSrcweir             aLine.append( "/Parent " );
4460cdf0e10cSrcweir             aLine.append( rItem.m_nParentObject );
4461cdf0e10cSrcweir             aLine.append( " 0 R" );
4462cdf0e10cSrcweir             if( rItem.m_nPrevObject )
4463cdf0e10cSrcweir             {
4464cdf0e10cSrcweir                 aLine.append( "/Prev " );
4465cdf0e10cSrcweir                 aLine.append( rItem.m_nPrevObject );
4466cdf0e10cSrcweir                 aLine.append( " 0 R" );
4467cdf0e10cSrcweir             }
4468cdf0e10cSrcweir             if( rItem.m_nNextObject )
4469cdf0e10cSrcweir             {
4470cdf0e10cSrcweir                 aLine.append( "/Next " );
4471cdf0e10cSrcweir                 aLine.append( rItem.m_nNextObject );
4472cdf0e10cSrcweir                 aLine.append( " 0 R" );
4473cdf0e10cSrcweir             }
4474cdf0e10cSrcweir         }
4475cdf0e10cSrcweir         aLine.append( ">>\nendobj\n\n" );
4476cdf0e10cSrcweir         CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
4477cdf0e10cSrcweir     }
4478cdf0e10cSrcweir 
4479cdf0e10cSrcweir     return m_aOutline[0].m_nObject;
4480cdf0e10cSrcweir }
4481cdf0e10cSrcweir 
4482cdf0e10cSrcweir #undef CHECK_RETURN
4483cdf0e10cSrcweir #define CHECK_RETURN( x ) if( !x ) return false
4484cdf0e10cSrcweir 
4485cdf0e10cSrcweir bool PDFWriterImpl::appendDest( sal_Int32 nDestID, OStringBuffer& rBuffer )
4486cdf0e10cSrcweir {
4487cdf0e10cSrcweir     if( nDestID < 0 || nDestID >= (sal_Int32)m_aDests.size() )
4488cdf0e10cSrcweir     {
4489cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
4490cdf0e10cSrcweir         fprintf( stderr, "ERROR: invalid dest %d requested\n", (int)nDestID );
4491cdf0e10cSrcweir #endif
4492cdf0e10cSrcweir         return false;
4493cdf0e10cSrcweir     }
4494cdf0e10cSrcweir 
4495cdf0e10cSrcweir 
4496cdf0e10cSrcweir     const PDFDest& rDest		= m_aDests[ nDestID ];
4497cdf0e10cSrcweir     const PDFPage& rDestPage	= m_aPages[ rDest.m_nPage ];
4498cdf0e10cSrcweir 
4499cdf0e10cSrcweir     rBuffer.append( '[' );
4500cdf0e10cSrcweir     rBuffer.append( rDestPage.m_nPageObject );
4501cdf0e10cSrcweir     rBuffer.append( " 0 R" );
4502cdf0e10cSrcweir 
4503cdf0e10cSrcweir     switch( rDest.m_eType )
4504cdf0e10cSrcweir     {
4505cdf0e10cSrcweir         case PDFWriter::XYZ:
4506cdf0e10cSrcweir         default:
4507cdf0e10cSrcweir             rBuffer.append( "/XYZ " );
4508cdf0e10cSrcweir             appendFixedInt( rDest.m_aRect.Left(), rBuffer );
4509cdf0e10cSrcweir             rBuffer.append( ' ' );
4510cdf0e10cSrcweir             appendFixedInt( rDest.m_aRect.Bottom(), rBuffer );
4511cdf0e10cSrcweir             rBuffer.append( " 0" );
4512cdf0e10cSrcweir             break;
4513cdf0e10cSrcweir         case PDFWriter::Fit:
4514cdf0e10cSrcweir             rBuffer.append( "/Fit" );
4515cdf0e10cSrcweir             break;
4516cdf0e10cSrcweir         case PDFWriter::FitRectangle:
4517cdf0e10cSrcweir             rBuffer.append( "/FitR " );
4518cdf0e10cSrcweir             appendFixedInt( rDest.m_aRect.Left(), rBuffer );
4519cdf0e10cSrcweir             rBuffer.append( ' ' );
4520cdf0e10cSrcweir             appendFixedInt( rDest.m_aRect.Top(), rBuffer );
4521cdf0e10cSrcweir             rBuffer.append( ' ' );
4522cdf0e10cSrcweir             appendFixedInt( rDest.m_aRect.Right(), rBuffer );
4523cdf0e10cSrcweir             rBuffer.append( ' ' );
4524cdf0e10cSrcweir             appendFixedInt( rDest.m_aRect.Bottom(), rBuffer );
4525cdf0e10cSrcweir             break;
4526cdf0e10cSrcweir         case PDFWriter::FitHorizontal:
4527cdf0e10cSrcweir             rBuffer.append( "/FitH " );
4528cdf0e10cSrcweir             appendFixedInt( rDest.m_aRect.Bottom(), rBuffer );
4529cdf0e10cSrcweir             break;
4530cdf0e10cSrcweir         case PDFWriter::FitVertical:
4531cdf0e10cSrcweir             rBuffer.append( "/FitV " );
4532cdf0e10cSrcweir             appendFixedInt( rDest.m_aRect.Left(), rBuffer );
4533cdf0e10cSrcweir             break;
4534cdf0e10cSrcweir         case PDFWriter::FitPageBoundingBox:
4535cdf0e10cSrcweir             rBuffer.append( "/FitB" );
4536cdf0e10cSrcweir             break;
4537cdf0e10cSrcweir         case PDFWriter::FitPageBoundingBoxHorizontal:
4538cdf0e10cSrcweir             rBuffer.append( "/FitBH " );
4539cdf0e10cSrcweir             appendFixedInt( rDest.m_aRect.Bottom(), rBuffer );
4540cdf0e10cSrcweir             break;
4541cdf0e10cSrcweir         case PDFWriter::FitPageBoundingBoxVertical:
4542cdf0e10cSrcweir             rBuffer.append( "/FitBV " );
4543cdf0e10cSrcweir             appendFixedInt( rDest.m_aRect.Left(), rBuffer );
4544cdf0e10cSrcweir             break;
4545cdf0e10cSrcweir     }
4546cdf0e10cSrcweir     rBuffer.append( ']' );
4547cdf0e10cSrcweir 
4548cdf0e10cSrcweir     return true;
4549cdf0e10cSrcweir }
4550cdf0e10cSrcweir 
4551cdf0e10cSrcweir bool PDFWriterImpl::emitLinkAnnotations()
4552cdf0e10cSrcweir {
4553cdf0e10cSrcweir     int nAnnots = m_aLinks.size();
4554cdf0e10cSrcweir     for( int i = 0; i < nAnnots; i++ )
4555cdf0e10cSrcweir     {
4556cdf0e10cSrcweir         const PDFLink& rLink			= m_aLinks[i];
4557cdf0e10cSrcweir         if( ! updateObject( rLink.m_nObject ) )
4558cdf0e10cSrcweir             continue;
4559cdf0e10cSrcweir 
4560cdf0e10cSrcweir         OStringBuffer aLine( 1024 );
4561cdf0e10cSrcweir         aLine.append( rLink.m_nObject );
4562cdf0e10cSrcweir         aLine.append( " 0 obj\n" );
4563cdf0e10cSrcweir //i59651  key /F set bits Print to 1 rest to 0. We don't set NoZoom NoRotate to 1, since it's a 'should'
4564cdf0e10cSrcweir // see PDF 8.4.2 and ISO 19005-1:2005 6.5.3
4565cdf0e10cSrcweir         aLine.append( "<</Type/Annot" );
4566cdf0e10cSrcweir         if( m_bIsPDF_A1 )
4567cdf0e10cSrcweir             aLine.append( "/F 4" );
4568cdf0e10cSrcweir         aLine.append( "/Subtype/Link/Border[0 0 0]/Rect[" );
4569cdf0e10cSrcweir 
4570cdf0e10cSrcweir         appendFixedInt( rLink.m_aRect.Left()-7, aLine );//the +7 to have a better shape of the border rectangle
4571cdf0e10cSrcweir         aLine.append( ' ' );
4572cdf0e10cSrcweir         appendFixedInt( rLink.m_aRect.Top(), aLine );
4573cdf0e10cSrcweir         aLine.append( ' ' );
4574cdf0e10cSrcweir         appendFixedInt( rLink.m_aRect.Right()+7, aLine );//the +7 to have a better shape of the border rectangle
4575cdf0e10cSrcweir         aLine.append( ' ' );
4576cdf0e10cSrcweir         appendFixedInt( rLink.m_aRect.Bottom(), aLine );
4577cdf0e10cSrcweir         aLine.append( "]" );
4578cdf0e10cSrcweir         if( rLink.m_nDest >= 0 )
4579cdf0e10cSrcweir         {
4580cdf0e10cSrcweir             aLine.append( "/Dest" );
4581cdf0e10cSrcweir             appendDest( rLink.m_nDest, aLine );
4582cdf0e10cSrcweir         }
4583cdf0e10cSrcweir         else
4584cdf0e10cSrcweir         {
4585cdf0e10cSrcweir /*--->i56629
4586cdf0e10cSrcweir destination is external to the document, so
4587cdf0e10cSrcweir we check in the following sequence:
4588cdf0e10cSrcweir 
4589cdf0e10cSrcweir  if target type is neither .pdf, nor .od[tpgs], then
4590cdf0e10cSrcweir           check if relative or absolute and act accordingly (use URI or 'launch application' as requested)
4591cdf0e10cSrcweir                              end processing
4592cdf0e10cSrcweir  else if target is .od[tpgs]: then
4593cdf0e10cSrcweir       if conversion of type from od[tpgs]  to pdf is requested, convert it and this becomes the new target file
4594cdf0e10cSrcweir       processing continue
4595cdf0e10cSrcweir 
4596cdf0e10cSrcweir  if (new)target is .pdf : then
4597cdf0e10cSrcweir      if GotToR is requested, then
4598cdf0e10cSrcweir            convert the target in GoToR where the fragment of the URI is
4599cdf0e10cSrcweir            considered the named destination in the target file, set relative or absolute as requested
4600cdf0e10cSrcweir      else strip the fragment from URL and then set URI or 'launch application' as requested
4601cdf0e10cSrcweir */
4602cdf0e10cSrcweir //
4603cdf0e10cSrcweir // FIXME: check if the decode mechanisms for URL processing throughout this implementation
4604cdf0e10cSrcweir // are the correct one!!
4605cdf0e10cSrcweir //
4606cdf0e10cSrcweir // extract target file type
4607cdf0e10cSrcweir             INetURLObject aDocumentURL( m_aContext.BaseURL );
4608cdf0e10cSrcweir             INetURLObject aTargetURL( rLink.m_aURL );
4609cdf0e10cSrcweir             sal_Int32   nChangeFileExtensionToPDF = 0;
4610cdf0e10cSrcweir             sal_Int32   nSetGoToRMode = 0;
4611cdf0e10cSrcweir             sal_Bool    bTargetHasPDFExtension = sal_False;
4612cdf0e10cSrcweir             INetProtocol eTargetProtocol = aTargetURL.GetProtocol();
4613cdf0e10cSrcweir 			sal_Bool    bIsUNCPath = sal_False;
4614cdf0e10cSrcweir // check if the protocol is a known one, or if there is no protocol at all (on target only)
4615cdf0e10cSrcweir // if there is no protocol, make the target relative to the current document directory
4616cdf0e10cSrcweir // getting the needed URL information from the current document path
4617cdf0e10cSrcweir             if( eTargetProtocol == INET_PROT_NOT_VALID )
4618cdf0e10cSrcweir             {
4619cdf0e10cSrcweir 				if( rLink.m_aURL.getLength() > 4 && rLink.m_aURL.compareToAscii( "\\\\\\\\", 4 ) == 0)
4620cdf0e10cSrcweir 				{
4621cdf0e10cSrcweir 					bIsUNCPath = sal_True;
4622cdf0e10cSrcweir 				}
4623cdf0e10cSrcweir 				else
4624cdf0e10cSrcweir 				{
4625cdf0e10cSrcweir 					INetURLObject aNewBase( aDocumentURL );//duplicate document URL
4626cdf0e10cSrcweir 					aNewBase.removeSegment(); //remove last segment from it, obtaining the base URL of the
4627cdf0e10cSrcweir 											  //target document
4628cdf0e10cSrcweir 					aNewBase.insertName( rLink.m_aURL );
4629cdf0e10cSrcweir 					aTargetURL = aNewBase;//reassign the new target URL
4630cdf0e10cSrcweir //recompute the target protocol, with the new URL
4631cdf0e10cSrcweir //normal URL processing resumes
4632cdf0e10cSrcweir 					eTargetProtocol = aTargetURL.GetProtocol();
4633cdf0e10cSrcweir 				}
4634cdf0e10cSrcweir             }
4635cdf0e10cSrcweir 
4636cdf0e10cSrcweir             rtl::OUString aFileExtension = aTargetURL.GetFileExtension();
4637cdf0e10cSrcweir 
4638cdf0e10cSrcweir // Check if the URL ends in '/': if yes it's a directory,
4639cdf0e10cSrcweir // it will be forced to a URI link.
4640cdf0e10cSrcweir // possibly a malformed URI, leave it as it is, force as URI
4641cdf0e10cSrcweir             if( aTargetURL.hasFinalSlash() )
4642cdf0e10cSrcweir                 m_aContext.DefaultLinkAction = PDFWriter::URIAction;
4643cdf0e10cSrcweir 
4644cdf0e10cSrcweir             if( aFileExtension.getLength() > 0 )
4645cdf0e10cSrcweir             {
4646cdf0e10cSrcweir                 if( m_aContext.ConvertOOoTargetToPDFTarget )
4647cdf0e10cSrcweir                 {
4648cdf0e10cSrcweir //examine the file type (.odm .odt. .odp, odg, ods)
4649cdf0e10cSrcweir                     if( aFileExtension.equalsIgnoreAsciiCase(rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "odm" ) ) ) )
4650cdf0e10cSrcweir                         nChangeFileExtensionToPDF++;
4651cdf0e10cSrcweir                     if( aFileExtension.equalsIgnoreAsciiCase(rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "odt" ) ) ) )
4652cdf0e10cSrcweir                         nChangeFileExtensionToPDF++;
4653cdf0e10cSrcweir                     else if( aFileExtension.equalsIgnoreAsciiCase(rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "odp" ) ) ) )
4654cdf0e10cSrcweir                         nChangeFileExtensionToPDF++;
4655cdf0e10cSrcweir                     else if( aFileExtension.equalsIgnoreAsciiCase(rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "odg" ) ) ) )
4656cdf0e10cSrcweir                         nChangeFileExtensionToPDF++;
4657cdf0e10cSrcweir                     else if( aFileExtension.equalsIgnoreAsciiCase(rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ods" ) ) ) )
4658cdf0e10cSrcweir                         nChangeFileExtensionToPDF++;
4659cdf0e10cSrcweir                     if( nChangeFileExtensionToPDF )
4660cdf0e10cSrcweir                         aTargetURL.setExtension(rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "pdf" ) ) );
4661cdf0e10cSrcweir                 }
4662cdf0e10cSrcweir //check if extension is pdf, see if GoToR should be forced
4663cdf0e10cSrcweir                 bTargetHasPDFExtension = aTargetURL.GetFileExtension().equalsIgnoreAsciiCase(rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "pdf" ) ) );
4664cdf0e10cSrcweir                 if( m_aContext.ForcePDFAction && bTargetHasPDFExtension )
4665cdf0e10cSrcweir                     nSetGoToRMode++;
4666cdf0e10cSrcweir             }
4667cdf0e10cSrcweir //prepare the URL, if relative or not
4668cdf0e10cSrcweir             INetProtocol eBaseProtocol = aDocumentURL.GetProtocol();
4669cdf0e10cSrcweir //queue the string common to all types of actions
4670cdf0e10cSrcweir             aLine.append( "/A<</Type/Action/S");
4671cdf0e10cSrcweir 			if( bIsUNCPath ) // handle Win UNC paths
4672cdf0e10cSrcweir 			{
4673cdf0e10cSrcweir 				aLine.append( "/Launch/Win<</F" );
4674cdf0e10cSrcweir 				// INetURLObject is not good with UNC paths, use original path
4675cdf0e10cSrcweir 				appendLiteralStringEncrypt(  rLink.m_aURL, rLink.m_nObject, aLine, osl_getThreadTextEncoding() );
4676cdf0e10cSrcweir 				aLine.append( ">>" );
4677cdf0e10cSrcweir 			}
4678cdf0e10cSrcweir 			else
4679cdf0e10cSrcweir 			{
4680cdf0e10cSrcweir 			    bool bSetRelative = false;
4681cdf0e10cSrcweir 			    bool bFileSpec = false;
4682cdf0e10cSrcweir //check if relative file link is requested and if the protocol is 'file://'
4683cdf0e10cSrcweir 				if( m_aContext.RelFsys && eBaseProtocol == eTargetProtocol && eTargetProtocol == INET_PROT_FILE )
4684cdf0e10cSrcweir 					bSetRelative = true;
4685cdf0e10cSrcweir 
4686cdf0e10cSrcweir 				rtl::OUString aFragment = aTargetURL.GetMark( INetURLObject::NO_DECODE /*DECODE_WITH_CHARSET*/ ); //fragment as is,
4687cdf0e10cSrcweir 				if( nSetGoToRMode == 0 )
4688cdf0e10cSrcweir 				{
4689cdf0e10cSrcweir 					switch( m_aContext.DefaultLinkAction )
4690cdf0e10cSrcweir 					{
4691cdf0e10cSrcweir 					default:
4692cdf0e10cSrcweir 					case PDFWriter::URIAction :
4693cdf0e10cSrcweir 					case PDFWriter::URIActionDestination :
4694cdf0e10cSrcweir 						aLine.append( "/URI/URI" );
4695cdf0e10cSrcweir 						break;
4696cdf0e10cSrcweir 					case PDFWriter::LaunchAction:
4697cdf0e10cSrcweir // now:
4698cdf0e10cSrcweir // if a launch action is requested and the hyperlink target has a fragment
4699cdf0e10cSrcweir // and the target file does not have a pdf extension, or it's not a 'file:://' protocol
4700cdf0e10cSrcweir // then force the uri action on it
4701cdf0e10cSrcweir // This code will permit the correct opening of application on web pages, the one that
4702cdf0e10cSrcweir // normally have fragments (but I may be wrong...)
4703cdf0e10cSrcweir // and will force the use of URI when the protocol is not file://
4704cdf0e10cSrcweir 						if( (aFragment.getLength() > 0 && !bTargetHasPDFExtension) ||
4705cdf0e10cSrcweir 										eTargetProtocol != INET_PROT_FILE )
4706cdf0e10cSrcweir 							aLine.append( "/URI/URI" );
4707cdf0e10cSrcweir 						else
4708cdf0e10cSrcweir 						{
4709cdf0e10cSrcweir 							aLine.append( "/Launch/F" );
4710cdf0e10cSrcweir 							bFileSpec = true;
4711cdf0e10cSrcweir 						}
4712cdf0e10cSrcweir 						break;
4713cdf0e10cSrcweir 					}
4714cdf0e10cSrcweir 				}
4715cdf0e10cSrcweir //fragment are encoded in the same way as in the named destination processing
4716cdf0e10cSrcweir 				if( nSetGoToRMode )
4717cdf0e10cSrcweir 				{//add the fragment
4718cdf0e10cSrcweir 				    rtl::OUString aURLNoMark = aTargetURL.GetURLNoMark( INetURLObject::DECODE_WITH_CHARSET );
4719cdf0e10cSrcweir 					aLine.append("/GoToR");
4720cdf0e10cSrcweir 					aLine.append("/F");
4721cdf0e10cSrcweir 					bFileSpec = true;
4722cdf0e10cSrcweir 					appendLiteralStringEncrypt( bSetRelative ? INetURLObject::GetRelURL( m_aContext.BaseURL, aURLNoMark,
4723cdf0e10cSrcweir 																						 INetURLObject::WAS_ENCODED,
4724cdf0e10cSrcweir 																						 INetURLObject::DECODE_WITH_CHARSET ) :
4725cdf0e10cSrcweir 																   aURLNoMark, rLink.m_nObject, aLine, osl_getThreadTextEncoding() );
4726cdf0e10cSrcweir 					if( aFragment.getLength() > 0 )
4727cdf0e10cSrcweir 					{
4728cdf0e10cSrcweir 						aLine.append("/D/");
4729cdf0e10cSrcweir 						appendDestinationName( aFragment , aLine );
4730cdf0e10cSrcweir 					}
4731cdf0e10cSrcweir 				}
4732cdf0e10cSrcweir 				else
4733cdf0e10cSrcweir 				{
4734cdf0e10cSrcweir // change the fragment to accomodate the bookmark (only if the file extension is PDF and
4735cdf0e10cSrcweir // the requested action is of the correct type)
4736cdf0e10cSrcweir 					if(m_aContext.DefaultLinkAction == PDFWriter::URIActionDestination &&
4737cdf0e10cSrcweir 							   bTargetHasPDFExtension && aFragment.getLength() > 0 )
4738cdf0e10cSrcweir 					{
4739cdf0e10cSrcweir 						OStringBuffer aLineLoc( 1024 );
4740cdf0e10cSrcweir 						appendDestinationName( aFragment , aLineLoc );
4741cdf0e10cSrcweir //substitute the fragment
4742cdf0e10cSrcweir 						aTargetURL.SetMark( aLineLoc.getStr() );
4743cdf0e10cSrcweir 					}
4744cdf0e10cSrcweir 					rtl::OUString aURL = aTargetURL.GetMainURL( bFileSpec ? INetURLObject::DECODE_WITH_CHARSET : INetURLObject::NO_DECODE );
4745cdf0e10cSrcweir // check if we have a URL available, if the string is empty, set it as the original one
4746cdf0e10cSrcweir //                 if( aURL.getLength() == 0 )
4747cdf0e10cSrcweir //                     appendLiteralStringEncrypt( rLink.m_aURL , rLink.m_nObject, aLine );
4748cdf0e10cSrcweir //                 else
4749cdf0e10cSrcweir 						appendLiteralStringEncrypt( bSetRelative ? INetURLObject::GetRelURL( m_aContext.BaseURL, aURL,
4750cdf0e10cSrcweir 						                                                                    INetURLObject::WAS_ENCODED,
4751cdf0e10cSrcweir 						                                                                    bFileSpec ? INetURLObject::DECODE_WITH_CHARSET : INetURLObject::NO_DECODE
4752cdf0e10cSrcweir 						                                                                    ) :
4753cdf0e10cSrcweir 																   aURL , rLink.m_nObject, aLine, osl_getThreadTextEncoding() );
4754cdf0e10cSrcweir 				}
4755cdf0e10cSrcweir //<--- i56629
4756cdf0e10cSrcweir 			}
4757cdf0e10cSrcweir             aLine.append( ">>\n" );
4758cdf0e10cSrcweir         }
4759cdf0e10cSrcweir         if( rLink.m_nStructParent > 0 )
4760cdf0e10cSrcweir         {
4761cdf0e10cSrcweir             aLine.append( "/StructParent " );
4762cdf0e10cSrcweir             aLine.append( rLink.m_nStructParent );
4763cdf0e10cSrcweir         }
4764cdf0e10cSrcweir         aLine.append( ">>\nendobj\n\n" );
4765cdf0e10cSrcweir         CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
4766cdf0e10cSrcweir     }
4767cdf0e10cSrcweir 
4768cdf0e10cSrcweir     return true;
4769cdf0e10cSrcweir }
4770cdf0e10cSrcweir 
4771cdf0e10cSrcweir bool PDFWriterImpl::emitNoteAnnotations()
4772cdf0e10cSrcweir {
4773cdf0e10cSrcweir     // emit note annotations
4774cdf0e10cSrcweir     int nAnnots = m_aNotes.size();
4775cdf0e10cSrcweir     for( int i = 0; i < nAnnots; i++ )
4776cdf0e10cSrcweir     {
4777cdf0e10cSrcweir         const PDFNoteEntry& rNote		= m_aNotes[i];
4778cdf0e10cSrcweir         if( ! updateObject( rNote.m_nObject ) )
4779cdf0e10cSrcweir             return false;
4780cdf0e10cSrcweir 
4781cdf0e10cSrcweir         OStringBuffer aLine( 1024 );
4782cdf0e10cSrcweir         aLine.append( rNote.m_nObject );
4783cdf0e10cSrcweir         aLine.append( " 0 obj\n" );
4784cdf0e10cSrcweir //i59651  key /F set bits Print to 1 rest to 0. We don't set NoZoom NoRotate to 1, since it's a 'should'
4785cdf0e10cSrcweir // see PDF 8.4.2 and ISO 19005-1:2005 6.5.3
4786cdf0e10cSrcweir         aLine.append( "<</Type/Annot" );
4787cdf0e10cSrcweir         if( m_bIsPDF_A1 )
4788cdf0e10cSrcweir             aLine.append( "/F 4" );
4789cdf0e10cSrcweir         aLine.append( "/Subtype/Text/Rect[" );
4790cdf0e10cSrcweir 
4791cdf0e10cSrcweir         appendFixedInt( rNote.m_aRect.Left(), aLine );
4792cdf0e10cSrcweir         aLine.append( ' ' );
4793cdf0e10cSrcweir         appendFixedInt( rNote.m_aRect.Top(), aLine );
4794cdf0e10cSrcweir         aLine.append( ' ' );
4795cdf0e10cSrcweir         appendFixedInt( rNote.m_aRect.Right(), aLine );
4796cdf0e10cSrcweir         aLine.append( ' ' );
4797cdf0e10cSrcweir         appendFixedInt( rNote.m_aRect.Bottom(), aLine );
4798cdf0e10cSrcweir         aLine.append( "]" );
4799cdf0e10cSrcweir 
4800cdf0e10cSrcweir         // contents of the note (type text string)
4801cdf0e10cSrcweir         aLine.append( "/Contents\n" );
4802cdf0e10cSrcweir         appendUnicodeTextStringEncrypt( rNote.m_aContents.Contents, rNote.m_nObject, aLine );
4803cdf0e10cSrcweir         aLine.append( "\n" );
4804cdf0e10cSrcweir 
4805cdf0e10cSrcweir         // optional title
4806cdf0e10cSrcweir         if( rNote.m_aContents.Title.Len() )
4807cdf0e10cSrcweir         {
4808cdf0e10cSrcweir             aLine.append( "/T" );
4809cdf0e10cSrcweir             appendUnicodeTextStringEncrypt( rNote.m_aContents.Title, rNote.m_nObject, aLine );
4810cdf0e10cSrcweir             aLine.append( "\n" );
4811cdf0e10cSrcweir         }
4812cdf0e10cSrcweir 
4813cdf0e10cSrcweir         aLine.append( ">>\nendobj\n\n" );
4814cdf0e10cSrcweir         CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
4815cdf0e10cSrcweir     }
4816cdf0e10cSrcweir     return true;
4817cdf0e10cSrcweir }
4818cdf0e10cSrcweir 
4819cdf0e10cSrcweir Font PDFWriterImpl::replaceFont( const Font& rControlFont, const Font&  rAppSetFont )
4820cdf0e10cSrcweir {
4821cdf0e10cSrcweir     bool bAdjustSize = false;
4822cdf0e10cSrcweir 
4823cdf0e10cSrcweir     Font aFont( rControlFont );
4824cdf0e10cSrcweir     if( ! aFont.GetName().Len() )
4825cdf0e10cSrcweir     {
4826cdf0e10cSrcweir         aFont = rAppSetFont;
4827cdf0e10cSrcweir         if( rControlFont.GetHeight() )
4828cdf0e10cSrcweir             aFont.SetSize( Size( 0, rControlFont.GetHeight() ) );
4829cdf0e10cSrcweir         else
4830cdf0e10cSrcweir             bAdjustSize = true;
4831cdf0e10cSrcweir         if( rControlFont.GetItalic() != ITALIC_DONTKNOW )
4832cdf0e10cSrcweir             aFont.SetItalic( rControlFont.GetItalic() );
4833cdf0e10cSrcweir         if( rControlFont.GetWeight() != WEIGHT_DONTKNOW )
4834cdf0e10cSrcweir             aFont.SetWeight( rControlFont.GetWeight() );
4835cdf0e10cSrcweir     }
4836cdf0e10cSrcweir     else if( ! aFont.GetHeight() )
4837cdf0e10cSrcweir     {
4838cdf0e10cSrcweir         aFont.SetSize( rAppSetFont.GetSize() );
4839cdf0e10cSrcweir         bAdjustSize = true;
4840cdf0e10cSrcweir     }
4841cdf0e10cSrcweir     if( bAdjustSize )
4842cdf0e10cSrcweir     {
4843cdf0e10cSrcweir         Size aFontSize = aFont.GetSize();
4844cdf0e10cSrcweir         OutputDevice* pDefDev = Application::GetDefaultDevice();
4845cdf0e10cSrcweir         aFontSize = OutputDevice::LogicToLogic( aFontSize, pDefDev->GetMapMode(), getMapMode() );
4846cdf0e10cSrcweir         aFont.SetSize( aFontSize );
4847cdf0e10cSrcweir     }
4848cdf0e10cSrcweir     return aFont;
4849cdf0e10cSrcweir }
4850cdf0e10cSrcweir 
4851cdf0e10cSrcweir sal_Int32 PDFWriterImpl::getBestBuiltinFont( const Font& rFont )
4852cdf0e10cSrcweir {
4853cdf0e10cSrcweir     sal_Int32 nBest = 4; // default to Helvetica
4854cdf0e10cSrcweir     OUString aFontName( rFont.GetName() );
4855cdf0e10cSrcweir     aFontName = aFontName.toAsciiLowerCase();
4856cdf0e10cSrcweir 
4857cdf0e10cSrcweir     if( aFontName.indexOf( OUString( RTL_CONSTASCII_USTRINGPARAM( "times" ) ) ) != -1 )
4858cdf0e10cSrcweir         nBest = 8;
4859cdf0e10cSrcweir     else if( aFontName.indexOf( OUString( RTL_CONSTASCII_USTRINGPARAM( "courier" ) ) ) != -1 )
4860cdf0e10cSrcweir         nBest = 0;
4861cdf0e10cSrcweir     else if( aFontName.indexOf( OUString( RTL_CONSTASCII_USTRINGPARAM( "dingbats" ) ) ) != -1 )
4862cdf0e10cSrcweir         nBest = 13;
4863cdf0e10cSrcweir     else if( aFontName.indexOf( OUString( RTL_CONSTASCII_USTRINGPARAM( "symbol" ) ) ) != -1 )
4864cdf0e10cSrcweir         nBest = 12;
4865cdf0e10cSrcweir     if( nBest < 12 )
4866cdf0e10cSrcweir     {
4867cdf0e10cSrcweir         if( rFont.GetItalic() == ITALIC_OBLIQUE || rFont.GetItalic() == ITALIC_NORMAL )
4868cdf0e10cSrcweir             nBest += 1;
4869cdf0e10cSrcweir         if( rFont.GetWeight() > WEIGHT_MEDIUM )
4870cdf0e10cSrcweir             nBest += 2;
4871cdf0e10cSrcweir     }
4872cdf0e10cSrcweir 
4873cdf0e10cSrcweir     if( m_aBuiltinFontToObjectMap.find( nBest ) == m_aBuiltinFontToObjectMap.end() )
4874cdf0e10cSrcweir         m_aBuiltinFontToObjectMap[ nBest ] = createObject();
4875cdf0e10cSrcweir 
4876cdf0e10cSrcweir     return nBest;
4877cdf0e10cSrcweir }
4878cdf0e10cSrcweir 
4879cdf0e10cSrcweir static inline const Color& replaceColor( const Color& rCol1, const Color& rCol2 )
4880cdf0e10cSrcweir {
4881cdf0e10cSrcweir     return (rCol1 == Color( COL_TRANSPARENT )) ? rCol2 : rCol1;
4882cdf0e10cSrcweir }
4883cdf0e10cSrcweir 
4884cdf0e10cSrcweir void PDFWriterImpl::createDefaultPushButtonAppearance( PDFWidget& rButton, const PDFWriter::PushButtonWidget& rWidget )
4885cdf0e10cSrcweir {
4886cdf0e10cSrcweir     const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
4887cdf0e10cSrcweir 
4888cdf0e10cSrcweir     // save graphics state
4889cdf0e10cSrcweir     push( sal::static_int_cast<sal_uInt16>(~0U) );
4890cdf0e10cSrcweir 
4891cdf0e10cSrcweir     // transform relative to control's coordinates since an
4892cdf0e10cSrcweir     // appearance stream is a form XObject
4893cdf0e10cSrcweir     // this relies on the m_aRect member of rButton NOT already being transformed
4894cdf0e10cSrcweir     // to default user space
4895cdf0e10cSrcweir     if( rWidget.Background || rWidget.Border )
4896cdf0e10cSrcweir     {
4897cdf0e10cSrcweir         setLineColor( rWidget.Border ? replaceColor( rWidget.BorderColor, rSettings.GetLightColor() ) : Color( COL_TRANSPARENT ) );
4898cdf0e10cSrcweir         setFillColor( rWidget.Background ? replaceColor( rWidget.BackgroundColor, rSettings.GetDialogColor() ) : Color( COL_TRANSPARENT ) );
4899cdf0e10cSrcweir         drawRectangle( rWidget.Location );
4900cdf0e10cSrcweir     }
4901cdf0e10cSrcweir     // prepare font to use
4902cdf0e10cSrcweir     Font aFont = replaceFont( rWidget.TextFont, rSettings.GetPushButtonFont() );
4903cdf0e10cSrcweir     setFont( aFont );
4904cdf0e10cSrcweir     setTextColor( replaceColor( rWidget.TextColor, rSettings.GetButtonTextColor() ) );
4905cdf0e10cSrcweir 
4906cdf0e10cSrcweir     drawText( rButton.m_aRect, rButton.m_aText, rButton.m_nTextStyle );
4907cdf0e10cSrcweir 
4908cdf0e10cSrcweir     // create DA string while local mapmode is still in place
4909cdf0e10cSrcweir     // (that is before endRedirect())
4910cdf0e10cSrcweir     OStringBuffer aDA( 256 );
4911cdf0e10cSrcweir     appendNonStrokingColor( replaceColor( rWidget.TextColor, rSettings.GetButtonTextColor() ), aDA );
4912cdf0e10cSrcweir     Font aDummyFont( String( RTL_CONSTASCII_USTRINGPARAM( "Helvetica" ) ), aFont.GetSize() );
4913cdf0e10cSrcweir     sal_Int32 nDummyBuiltin = getBestBuiltinFont( aDummyFont );
4914cdf0e10cSrcweir     aDA.append( ' ' );
4915cdf0e10cSrcweir     aDA.append( m_aBuiltinFonts[nDummyBuiltin].getNameObject() );
4916cdf0e10cSrcweir     aDA.append( ' ' );
4917cdf0e10cSrcweir     m_aPages[m_nCurrentPage].appendMappedLength( sal_Int32( aFont.GetHeight() ), aDA );
4918cdf0e10cSrcweir     aDA.append( " Tf" );
4919cdf0e10cSrcweir     rButton.m_aDAString = aDA.makeStringAndClear();
4920cdf0e10cSrcweir 
4921cdf0e10cSrcweir     pop();
4922cdf0e10cSrcweir 
4923cdf0e10cSrcweir     rButton.m_aAppearances[ "N" ][ "Standard" ] = new SvMemoryStream();
4924cdf0e10cSrcweir 
4925cdf0e10cSrcweir     /* seems like a bad hack but at least works in both AR5 and 6:
4926cdf0e10cSrcweir        we draw the button ourselves and tell AR
4927cdf0e10cSrcweir        the button would be totally transparent with no text
4928cdf0e10cSrcweir 
4929cdf0e10cSrcweir        One would expect that simply setting a normal appearance
4930cdf0e10cSrcweir        should suffice, but no, as soon as the user actually presses
4931cdf0e10cSrcweir        the button and an action is tied to it (gasp! a button that
4932cdf0e10cSrcweir        does something) the appearance gets replaced by some crap that AR
4933cdf0e10cSrcweir        creates on the fly even if no DA or MK is given. On AR6 at least
4934cdf0e10cSrcweir        the DA and MK work as expected, but on AR5 this creates a region
4935cdf0e10cSrcweir        filled with the background color but nor text. Urgh.
4936cdf0e10cSrcweir     */
4937cdf0e10cSrcweir     rButton.m_aMKDict = "/BC [] /BG [] /CA";
4938cdf0e10cSrcweir     rButton.m_aMKDictCAString = "";
4939cdf0e10cSrcweir }
4940cdf0e10cSrcweir 
4941cdf0e10cSrcweir Font PDFWriterImpl::drawFieldBorder( PDFWidget& rIntern,
4942cdf0e10cSrcweir                                      const PDFWriter::AnyWidget& rWidget,
4943cdf0e10cSrcweir                                      const StyleSettings& rSettings )
4944cdf0e10cSrcweir {
4945cdf0e10cSrcweir     Font aFont = replaceFont( rWidget.TextFont, rSettings.GetFieldFont() );
4946cdf0e10cSrcweir 
4947cdf0e10cSrcweir     if( rWidget.Background || rWidget.Border )
4948cdf0e10cSrcweir     {
4949cdf0e10cSrcweir         if( rWidget.Border && rWidget.BorderColor == Color( COL_TRANSPARENT ) )
4950cdf0e10cSrcweir         {
4951cdf0e10cSrcweir             sal_Int32 nDelta = getReferenceDevice()->ImplGetDPIX() / 500;
4952cdf0e10cSrcweir             if( nDelta < 1 )
4953cdf0e10cSrcweir                 nDelta = 1;
4954cdf0e10cSrcweir             setLineColor( Color( COL_TRANSPARENT ) );
4955cdf0e10cSrcweir             Rectangle aRect = rIntern.m_aRect;
4956cdf0e10cSrcweir             setFillColor( rSettings.GetLightBorderColor() );
4957cdf0e10cSrcweir             drawRectangle( aRect );
4958cdf0e10cSrcweir             aRect.Left()  += nDelta; aRect.Top()     += nDelta;
4959cdf0e10cSrcweir             aRect.Right() -= nDelta; aRect.Bottom()  -= nDelta;
4960cdf0e10cSrcweir             setFillColor( rSettings.GetFieldColor() );
4961cdf0e10cSrcweir             drawRectangle( aRect );
4962cdf0e10cSrcweir             setFillColor( rSettings.GetLightColor() );
4963cdf0e10cSrcweir             drawRectangle( Rectangle( Point( aRect.Left(), aRect.Bottom()-nDelta ), aRect.BottomRight() ) );
4964cdf0e10cSrcweir             drawRectangle( Rectangle( Point( aRect.Right()-nDelta, aRect.Top() ), aRect.BottomRight() ) );
4965cdf0e10cSrcweir             setFillColor( rSettings.GetDarkShadowColor() );
4966cdf0e10cSrcweir             drawRectangle( Rectangle( aRect.TopLeft(), Point( aRect.Left()+nDelta, aRect.Bottom() ) ) );
4967cdf0e10cSrcweir             drawRectangle( Rectangle( aRect.TopLeft(), Point( aRect.Right(), aRect.Top()+nDelta ) ) );
4968cdf0e10cSrcweir         }
4969cdf0e10cSrcweir         else
4970cdf0e10cSrcweir         {
4971cdf0e10cSrcweir             setLineColor( rWidget.Border ? replaceColor( rWidget.BorderColor, rSettings.GetShadowColor() ) : Color( COL_TRANSPARENT ) );
4972cdf0e10cSrcweir             setFillColor( rWidget.Background ? replaceColor( rWidget.BackgroundColor, rSettings.GetFieldColor() ) : Color( COL_TRANSPARENT ) );
4973cdf0e10cSrcweir             drawRectangle( rIntern.m_aRect );
4974cdf0e10cSrcweir         }
4975cdf0e10cSrcweir 
4976cdf0e10cSrcweir         if( rWidget.Border )
4977cdf0e10cSrcweir         {
4978cdf0e10cSrcweir             // adjust edit area accounting for border
4979cdf0e10cSrcweir             sal_Int32 nDelta = aFont.GetHeight()/4;
4980cdf0e10cSrcweir             if( nDelta < 1 )
4981cdf0e10cSrcweir                 nDelta = 1;
4982cdf0e10cSrcweir             rIntern.m_aRect.Left()	+= nDelta;
4983cdf0e10cSrcweir             rIntern.m_aRect.Top()	+= nDelta;
4984cdf0e10cSrcweir             rIntern.m_aRect.Right()	-= nDelta;
4985cdf0e10cSrcweir             rIntern.m_aRect.Bottom()-= nDelta;
4986cdf0e10cSrcweir         }
4987cdf0e10cSrcweir     }
4988cdf0e10cSrcweir     return aFont;
4989cdf0e10cSrcweir }
4990cdf0e10cSrcweir 
4991cdf0e10cSrcweir void PDFWriterImpl::createDefaultEditAppearance( PDFWidget& rEdit, const PDFWriter::EditWidget& rWidget )
4992cdf0e10cSrcweir {
4993cdf0e10cSrcweir     const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
4994cdf0e10cSrcweir     SvMemoryStream* pEditStream = new SvMemoryStream( 1024, 1024 );
4995cdf0e10cSrcweir 
4996cdf0e10cSrcweir     push( sal::static_int_cast<sal_uInt16>(~0U) );
4997cdf0e10cSrcweir 
4998cdf0e10cSrcweir     // prepare font to use, draw field border
4999cdf0e10cSrcweir     Font aFont = drawFieldBorder( rEdit, rWidget, rSettings );
5000cdf0e10cSrcweir     sal_Int32 nBest = m_aContext.FieldsUseSystemFonts ? getSystemFont( aFont ): getBestBuiltinFont( aFont );
5001cdf0e10cSrcweir 
5002cdf0e10cSrcweir     // prepare DA string
5003cdf0e10cSrcweir     OStringBuffer aDA( 32 );
5004cdf0e10cSrcweir     appendNonStrokingColor( replaceColor( rWidget.TextColor, rSettings.GetFieldTextColor() ), aDA );
5005cdf0e10cSrcweir     aDA.append( ' ' );
5006cdf0e10cSrcweir     if( m_aContext.FieldsUseSystemFonts )
5007cdf0e10cSrcweir     {
5008cdf0e10cSrcweir         aDA.append( "/F" );
5009cdf0e10cSrcweir         aDA.append( nBest );
5010cdf0e10cSrcweir 
5011cdf0e10cSrcweir         OStringBuffer aDR( 32 );
5012cdf0e10cSrcweir         aDR.append( "/Font " );
5013cdf0e10cSrcweir         aDR.append( getFontDictObject() );
5014cdf0e10cSrcweir         aDR.append( " 0 R" );
5015cdf0e10cSrcweir         rEdit.m_aDRDict = aDR.makeStringAndClear();
5016cdf0e10cSrcweir     }
5017cdf0e10cSrcweir     else
5018cdf0e10cSrcweir         aDA.append( m_aBuiltinFonts[nBest].getNameObject() );
5019cdf0e10cSrcweir     aDA.append( ' ' );
5020cdf0e10cSrcweir     m_aPages[ m_nCurrentPage ].appendMappedLength( sal_Int32( aFont.GetHeight() ), aDA );
5021cdf0e10cSrcweir     aDA.append( " Tf" );
5022cdf0e10cSrcweir 
5023cdf0e10cSrcweir     /*  create an empty appearance stream, let the viewer create
5024cdf0e10cSrcweir         the appearance at runtime. This is because AR5 seems to
5025cdf0e10cSrcweir         paint the widget appearance always, and a dynamically created
5026cdf0e10cSrcweir         appearance on top of it. AR6 is well behaved in that regard, so
5027cdf0e10cSrcweir         that behaviour seems to be a bug. Anyway this empty appearance
5028cdf0e10cSrcweir         relies on /NeedAppearances in the AcroForm dictionary set to "true"
5029cdf0e10cSrcweir      */
5030cdf0e10cSrcweir     beginRedirect( pEditStream, rEdit.m_aRect );
5031cdf0e10cSrcweir     OStringBuffer aAppearance( 32 );
5032cdf0e10cSrcweir     aAppearance.append( "/Tx BMC\nEMC\n" );
5033cdf0e10cSrcweir     writeBuffer( aAppearance.getStr(), aAppearance.getLength() );
5034cdf0e10cSrcweir 
5035cdf0e10cSrcweir     endRedirect();
5036cdf0e10cSrcweir     pop();
5037cdf0e10cSrcweir 
5038cdf0e10cSrcweir     rEdit.m_aAppearances[ "N" ][ "Standard" ] = pEditStream;
5039cdf0e10cSrcweir 
5040cdf0e10cSrcweir     rEdit.m_aDAString = aDA.makeStringAndClear();
5041cdf0e10cSrcweir }
5042cdf0e10cSrcweir 
5043cdf0e10cSrcweir void PDFWriterImpl::createDefaultListBoxAppearance( PDFWidget& rBox, const PDFWriter::ListBoxWidget& rWidget )
5044cdf0e10cSrcweir {
5045cdf0e10cSrcweir     const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
5046cdf0e10cSrcweir     SvMemoryStream* pListBoxStream = new SvMemoryStream( 1024, 1024 );
5047cdf0e10cSrcweir 
5048cdf0e10cSrcweir     push( sal::static_int_cast<sal_uInt16>(~0U) );
5049cdf0e10cSrcweir 
5050cdf0e10cSrcweir     // prepare font to use, draw field border
5051cdf0e10cSrcweir     Font aFont = drawFieldBorder( rBox, rWidget, rSettings );
5052cdf0e10cSrcweir     sal_Int32 nBest = m_aContext.FieldsUseSystemFonts ? getSystemFont( aFont ): getBestBuiltinFont( aFont );
5053cdf0e10cSrcweir 
5054cdf0e10cSrcweir     beginRedirect( pListBoxStream, rBox.m_aRect );
5055cdf0e10cSrcweir     OStringBuffer aAppearance( 64 );
5056cdf0e10cSrcweir 
5057cdf0e10cSrcweir #if 0
5058cdf0e10cSrcweir     if( ! rWidget.DropDown )
5059cdf0e10cSrcweir     {
5060cdf0e10cSrcweir         // prepare linewidth for DA string hack, see below
5061cdf0e10cSrcweir         Size aFontSize = lcl_convert( m_aGraphicsStack.front().m_aMapMode,
5062cdf0e10cSrcweir                                       m_aMapMode,
5063cdf0e10cSrcweir                                       getReferenceDevice(),
5064cdf0e10cSrcweir                                       Size( 0, aFont.GetHeight() ) );
5065cdf0e10cSrcweir         sal_Int32 nLW = aFontSize.Height() / 40;
5066cdf0e10cSrcweir         appendFixedInt( nLW > 0 ? nLW : 1, aAppearance );
5067cdf0e10cSrcweir         aAppearance.append( " w\n" );
5068cdf0e10cSrcweir         writeBuffer( aAppearance.getStr(), aAppearance.getLength() );
5069cdf0e10cSrcweir         aAppearance.setLength( 0 );
5070cdf0e10cSrcweir     }
5071cdf0e10cSrcweir #endif
5072cdf0e10cSrcweir 
5073cdf0e10cSrcweir     setLineColor( Color( COL_TRANSPARENT ) );
5074cdf0e10cSrcweir     setFillColor( replaceColor( rWidget.BackgroundColor, rSettings.GetFieldColor() ) );
5075cdf0e10cSrcweir     drawRectangle( rBox.m_aRect );
5076cdf0e10cSrcweir 
5077cdf0e10cSrcweir     // empty appearance, see createDefaultEditAppearance for reference
5078cdf0e10cSrcweir     aAppearance.append( "/Tx BMC\nEMC\n" );
5079cdf0e10cSrcweir     writeBuffer( aAppearance.getStr(), aAppearance.getLength() );
5080cdf0e10cSrcweir 
5081cdf0e10cSrcweir     endRedirect();
5082cdf0e10cSrcweir     pop();
5083cdf0e10cSrcweir 
5084cdf0e10cSrcweir     rBox.m_aAppearances[ "N" ][ "Standard" ] = pListBoxStream;
5085cdf0e10cSrcweir 
5086cdf0e10cSrcweir     // prepare DA string
5087cdf0e10cSrcweir     OStringBuffer aDA( 256 );
5088cdf0e10cSrcweir #if 0
5089cdf0e10cSrcweir     if( !rWidget.DropDown )
5090cdf0e10cSrcweir     {
5091cdf0e10cSrcweir         /* another of AR5's peculiarities: the selected item of a choice
5092cdf0e10cSrcweir            field is highlighted using the non stroking color - same as the
5093cdf0e10cSrcweir            text color. so workaround that by using text rendering mode 2
5094cdf0e10cSrcweir            (fill, then stroke) and set the stroking color
5095cdf0e10cSrcweir          */
5096cdf0e10cSrcweir         appendStrokingColor( replaceColor( rWidget.BackgroundColor, rSettings.GetFieldColor() ), aDA );
5097cdf0e10cSrcweir         aDA.append( " 2 Tr " );
5098cdf0e10cSrcweir     }
5099cdf0e10cSrcweir #endif
5100cdf0e10cSrcweir     // prepare DA string
5101cdf0e10cSrcweir     appendNonStrokingColor( replaceColor( rWidget.TextColor, rSettings.GetFieldTextColor() ), aDA );
5102cdf0e10cSrcweir     aDA.append( ' ' );
5103cdf0e10cSrcweir     if( m_aContext.FieldsUseSystemFonts )
5104cdf0e10cSrcweir     {
5105cdf0e10cSrcweir         aDA.append( "/F" );
5106cdf0e10cSrcweir         aDA.append( nBest );
5107cdf0e10cSrcweir 
5108cdf0e10cSrcweir         OStringBuffer aDR( 32 );
5109cdf0e10cSrcweir         aDR.append( "/Font " );
5110cdf0e10cSrcweir         aDR.append( getFontDictObject() );
5111cdf0e10cSrcweir         aDR.append( " 0 R" );
5112cdf0e10cSrcweir         rBox.m_aDRDict = aDR.makeStringAndClear();
5113cdf0e10cSrcweir     }
5114cdf0e10cSrcweir     else
5115cdf0e10cSrcweir         aDA.append( m_aBuiltinFonts[nBest].getNameObject() );
5116cdf0e10cSrcweir     aDA.append( ' ' );
5117cdf0e10cSrcweir     m_aPages[ m_nCurrentPage ].appendMappedLength( sal_Int32( aFont.GetHeight() ), aDA );
5118cdf0e10cSrcweir     aDA.append( " Tf" );
5119cdf0e10cSrcweir     rBox.m_aDAString = aDA.makeStringAndClear();
5120cdf0e10cSrcweir }
5121cdf0e10cSrcweir 
5122cdf0e10cSrcweir void PDFWriterImpl::createDefaultCheckBoxAppearance( PDFWidget& rBox, const PDFWriter::CheckBoxWidget& rWidget )
5123cdf0e10cSrcweir {
5124cdf0e10cSrcweir     const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
5125cdf0e10cSrcweir 
5126cdf0e10cSrcweir     // save graphics state
5127cdf0e10cSrcweir     push( sal::static_int_cast<sal_uInt16>(~0U) );
5128cdf0e10cSrcweir 
5129cdf0e10cSrcweir     if( rWidget.Background || rWidget.Border )
5130cdf0e10cSrcweir     {
5131cdf0e10cSrcweir         setLineColor( rWidget.Border ? replaceColor( rWidget.BorderColor, rSettings.GetCheckedColor() ) : Color( COL_TRANSPARENT ) );
5132cdf0e10cSrcweir         setFillColor( rWidget.Background ? replaceColor( rWidget.BackgroundColor, rSettings.GetFieldColor() ) : Color( COL_TRANSPARENT ) );
5133cdf0e10cSrcweir         drawRectangle( rBox.m_aRect );
5134cdf0e10cSrcweir     }
5135cdf0e10cSrcweir 
5136cdf0e10cSrcweir     Font aFont = replaceFont( rWidget.TextFont, rSettings.GetRadioCheckFont() );
5137cdf0e10cSrcweir     setFont( aFont );
5138cdf0e10cSrcweir     Size aFontSize = aFont.GetSize();
5139cdf0e10cSrcweir     if( aFontSize.Height() > rBox.m_aRect.GetHeight() )
5140cdf0e10cSrcweir         aFontSize.Height() = rBox.m_aRect.GetHeight();
5141cdf0e10cSrcweir     sal_Int32 nDelta = aFontSize.Height()/10;
5142cdf0e10cSrcweir     if( nDelta < 1 )
5143cdf0e10cSrcweir         nDelta = 1;
5144cdf0e10cSrcweir 
5145cdf0e10cSrcweir     Rectangle aCheckRect, aTextRect;
5146cdf0e10cSrcweir     if( rWidget.ButtonIsLeft )
5147cdf0e10cSrcweir     {
5148cdf0e10cSrcweir         aCheckRect.Left()	= rBox.m_aRect.Left() + nDelta;
5149cdf0e10cSrcweir         aCheckRect.Top()	= rBox.m_aRect.Top() + (rBox.m_aRect.GetHeight()-aFontSize.Height())/2;
5150cdf0e10cSrcweir         aCheckRect.Right()	= aCheckRect.Left() + aFontSize.Height();
5151cdf0e10cSrcweir         aCheckRect.Bottom()	= aCheckRect.Top() + aFontSize.Height();
5152cdf0e10cSrcweir 
5153cdf0e10cSrcweir         // #i74206# handle small controls without text area
5154cdf0e10cSrcweir         while( aCheckRect.GetWidth() > rBox.m_aRect.GetWidth() && aCheckRect.GetWidth() > nDelta )
5155cdf0e10cSrcweir         {
5156cdf0e10cSrcweir             aCheckRect.Right()  -= nDelta;
5157cdf0e10cSrcweir             aCheckRect.Top()    += nDelta/2;
5158cdf0e10cSrcweir             aCheckRect.Bottom() -= nDelta - (nDelta/2);
5159cdf0e10cSrcweir         }
5160cdf0e10cSrcweir 
5161cdf0e10cSrcweir         aTextRect.Left()	= rBox.m_aRect.Left() + aCheckRect.GetWidth()+5*nDelta;
5162cdf0e10cSrcweir         aTextRect.Top()		= rBox.m_aRect.Top();
5163cdf0e10cSrcweir         aTextRect.Right()	= aTextRect.Left() + rBox.m_aRect.GetWidth() - aCheckRect.GetWidth()-6*nDelta;
5164cdf0e10cSrcweir         aTextRect.Bottom()	= rBox.m_aRect.Bottom();
5165cdf0e10cSrcweir     }
5166cdf0e10cSrcweir     else
5167cdf0e10cSrcweir     {
5168cdf0e10cSrcweir         aCheckRect.Left()	= rBox.m_aRect.Right() - nDelta - aFontSize.Height();
5169cdf0e10cSrcweir         aCheckRect.Top()	= rBox.m_aRect.Top() + (rBox.m_aRect.GetHeight()-aFontSize.Height())/2;
5170cdf0e10cSrcweir         aCheckRect.Right()	= aCheckRect.Left() + aFontSize.Height();
5171cdf0e10cSrcweir         aCheckRect.Bottom()	= aCheckRect.Top() + aFontSize.Height();
5172cdf0e10cSrcweir 
5173cdf0e10cSrcweir         // #i74206# handle small controls without text area
5174cdf0e10cSrcweir         while( aCheckRect.GetWidth() > rBox.m_aRect.GetWidth() && aCheckRect.GetWidth() > nDelta )
5175cdf0e10cSrcweir         {
5176cdf0e10cSrcweir             aCheckRect.Left()   += nDelta;
5177cdf0e10cSrcweir             aCheckRect.Top()    += nDelta/2;
5178cdf0e10cSrcweir             aCheckRect.Bottom() -= nDelta - (nDelta/2);
5179cdf0e10cSrcweir         }
5180cdf0e10cSrcweir 
5181cdf0e10cSrcweir         aTextRect.Left()	= rBox.m_aRect.Left();
5182cdf0e10cSrcweir         aTextRect.Top()		= rBox.m_aRect.Top();
5183cdf0e10cSrcweir         aTextRect.Right()	= aTextRect.Left() + rBox.m_aRect.GetWidth() - aCheckRect.GetWidth()-6*nDelta;
5184cdf0e10cSrcweir         aTextRect.Bottom()	= rBox.m_aRect.Bottom();
5185cdf0e10cSrcweir     }
5186cdf0e10cSrcweir     setLineColor( Color( COL_BLACK ) );
5187cdf0e10cSrcweir     setFillColor( Color( COL_TRANSPARENT ) );
5188cdf0e10cSrcweir     OStringBuffer aLW( 32 );
5189cdf0e10cSrcweir     aLW.append( "q " );
5190cdf0e10cSrcweir     m_aPages[m_nCurrentPage].appendMappedLength( nDelta, aLW );
5191cdf0e10cSrcweir     aLW.append( " w " );
5192cdf0e10cSrcweir     writeBuffer( aLW.getStr(), aLW.getLength() );
5193cdf0e10cSrcweir     drawRectangle( aCheckRect );
5194cdf0e10cSrcweir     writeBuffer( " Q\n", 3 );
5195cdf0e10cSrcweir     setTextColor( replaceColor( rWidget.TextColor, rSettings.GetRadioCheckTextColor() ) );
5196cdf0e10cSrcweir     drawText( aTextRect, rBox.m_aText, rBox.m_nTextStyle );
5197cdf0e10cSrcweir 
5198cdf0e10cSrcweir     pop();
5199cdf0e10cSrcweir 
5200cdf0e10cSrcweir     OStringBuffer aDA( 256 );
5201cdf0e10cSrcweir     appendNonStrokingColor( replaceColor( rWidget.TextColor, rSettings.GetRadioCheckTextColor() ), aDA );
5202cdf0e10cSrcweir     sal_Int32 nBest = getBestBuiltinFont( Font( String( RTL_CONSTASCII_USTRINGPARAM( "ZapfDingbats" ) ), aFont.GetSize() ) );
5203cdf0e10cSrcweir     aDA.append( ' ' );
5204cdf0e10cSrcweir     aDA.append( m_aBuiltinFonts[nBest].getNameObject() );
5205cdf0e10cSrcweir     aDA.append( " 0 Tf" );
5206cdf0e10cSrcweir     rBox.m_aDAString = aDA.makeStringAndClear();
5207cdf0e10cSrcweir     rBox.m_aMKDict = "/CA";
5208cdf0e10cSrcweir     rBox.m_aMKDictCAString = "8";
5209cdf0e10cSrcweir     rBox.m_aRect = aCheckRect;
5210cdf0e10cSrcweir 
5211cdf0e10cSrcweir     // create appearance streams
5212cdf0e10cSrcweir     sal_Char cMark = '8';
5213cdf0e10cSrcweir     sal_Int32 nCharXOffset = 1000-m_aBuiltinFonts[13].m_aWidths[sal_Int32(cMark)];
5214cdf0e10cSrcweir     nCharXOffset *= aCheckRect.GetHeight();
5215cdf0e10cSrcweir     nCharXOffset /= 2000;
5216cdf0e10cSrcweir     sal_Int32 nCharYOffset = 1000-
5217cdf0e10cSrcweir         (m_aBuiltinFonts[13].m_nAscent+m_aBuiltinFonts[13].m_nDescent); // descent is negative
5218cdf0e10cSrcweir     nCharYOffset *= aCheckRect.GetHeight();
5219cdf0e10cSrcweir     nCharYOffset /= 2000;
5220cdf0e10cSrcweir 
5221cdf0e10cSrcweir     SvMemoryStream* pCheckStream = new SvMemoryStream( 256, 256 );
5222cdf0e10cSrcweir     beginRedirect( pCheckStream, aCheckRect );
5223cdf0e10cSrcweir     aDA.append( "/Tx BMC\nq BT\n" );
5224cdf0e10cSrcweir     appendNonStrokingColor( replaceColor( rWidget.TextColor, rSettings.GetRadioCheckTextColor() ), aDA );
5225cdf0e10cSrcweir     aDA.append( ' ' );
5226cdf0e10cSrcweir     aDA.append( m_aBuiltinFonts[nBest].getNameObject() );
5227cdf0e10cSrcweir     aDA.append( ' ' );
5228cdf0e10cSrcweir     m_aPages[ m_nCurrentPage ].appendMappedLength( sal_Int32( aCheckRect.GetHeight() ), aDA );
5229cdf0e10cSrcweir     aDA.append( " Tf\n" );
5230cdf0e10cSrcweir     m_aPages[ m_nCurrentPage ].appendMappedLength( nCharXOffset, aDA );
5231cdf0e10cSrcweir 	aDA.append( " " );
5232cdf0e10cSrcweir 	m_aPages[ m_nCurrentPage ].appendMappedLength( nCharYOffset, aDA );
5233cdf0e10cSrcweir 	aDA.append( " Td (" );
5234cdf0e10cSrcweir 	aDA.append( cMark );
5235cdf0e10cSrcweir 	aDA.append( ") Tj\nET\nQ\nEMC\n" );
5236cdf0e10cSrcweir     writeBuffer( aDA.getStr(), aDA.getLength() );
5237cdf0e10cSrcweir     endRedirect();
5238cdf0e10cSrcweir     rBox.m_aAppearances[ "N" ][ "Yes" ] = pCheckStream;
5239cdf0e10cSrcweir 
5240cdf0e10cSrcweir     SvMemoryStream* pUncheckStream = new SvMemoryStream( 256, 256 );
5241cdf0e10cSrcweir     beginRedirect( pUncheckStream, aCheckRect );
5242cdf0e10cSrcweir     writeBuffer( "/Tx BMC\nEMC\n", 12 );
5243cdf0e10cSrcweir     endRedirect();
5244cdf0e10cSrcweir     rBox.m_aAppearances[ "N" ][ "Off" ] = pUncheckStream;
5245cdf0e10cSrcweir }
5246cdf0e10cSrcweir 
5247cdf0e10cSrcweir void PDFWriterImpl::createDefaultRadioButtonAppearance( PDFWidget& rBox, const PDFWriter::RadioButtonWidget& rWidget )
5248cdf0e10cSrcweir {
5249cdf0e10cSrcweir     const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
5250cdf0e10cSrcweir 
5251cdf0e10cSrcweir     // save graphics state
5252cdf0e10cSrcweir     push( sal::static_int_cast<sal_uInt16>(~0U) );
5253cdf0e10cSrcweir 
5254cdf0e10cSrcweir     if( rWidget.Background || rWidget.Border )
5255cdf0e10cSrcweir     {
5256cdf0e10cSrcweir         setLineColor( rWidget.Border ? replaceColor( rWidget.BorderColor, rSettings.GetCheckedColor() ) : Color( COL_TRANSPARENT ) );
5257cdf0e10cSrcweir         setFillColor( rWidget.Background ? replaceColor( rWidget.BackgroundColor, rSettings.GetFieldColor() ) : Color( COL_TRANSPARENT ) );
5258cdf0e10cSrcweir         drawRectangle( rBox.m_aRect );
5259cdf0e10cSrcweir     }
5260cdf0e10cSrcweir 
5261cdf0e10cSrcweir     Font aFont = replaceFont( rWidget.TextFont, rSettings.GetRadioCheckFont() );
5262cdf0e10cSrcweir     setFont( aFont );
5263cdf0e10cSrcweir     Size aFontSize = aFont.GetSize();
5264cdf0e10cSrcweir     if( aFontSize.Height() > rBox.m_aRect.GetHeight() )
5265cdf0e10cSrcweir         aFontSize.Height() = rBox.m_aRect.GetHeight();
5266cdf0e10cSrcweir     sal_Int32 nDelta = aFontSize.Height()/10;
5267cdf0e10cSrcweir     if( nDelta < 1 )
5268cdf0e10cSrcweir         nDelta = 1;
5269cdf0e10cSrcweir 
5270cdf0e10cSrcweir     Rectangle aCheckRect, aTextRect;
5271cdf0e10cSrcweir     if( rWidget.ButtonIsLeft )
5272cdf0e10cSrcweir     {
5273cdf0e10cSrcweir         aCheckRect.Left()	= rBox.m_aRect.Left() + nDelta;
5274cdf0e10cSrcweir         aCheckRect.Top()	= rBox.m_aRect.Top() + (rBox.m_aRect.GetHeight()-aFontSize.Height())/2;
5275cdf0e10cSrcweir         aCheckRect.Right()	= aCheckRect.Left() + aFontSize.Height();
5276cdf0e10cSrcweir         aCheckRect.Bottom()	= aCheckRect.Top() + aFontSize.Height();
5277cdf0e10cSrcweir 
5278cdf0e10cSrcweir         // #i74206# handle small controls without text area
5279cdf0e10cSrcweir         while( aCheckRect.GetWidth() > rBox.m_aRect.GetWidth() && aCheckRect.GetWidth() > nDelta )
5280cdf0e10cSrcweir         {
5281cdf0e10cSrcweir             aCheckRect.Right()  -= nDelta;
5282cdf0e10cSrcweir             aCheckRect.Top()    += nDelta/2;
5283cdf0e10cSrcweir             aCheckRect.Bottom() -= nDelta - (nDelta/2);
5284cdf0e10cSrcweir         }
5285cdf0e10cSrcweir 
5286cdf0e10cSrcweir         aTextRect.Left()	= rBox.m_aRect.Left() + aCheckRect.GetWidth()+5*nDelta;
5287cdf0e10cSrcweir         aTextRect.Top()		= rBox.m_aRect.Top();
5288cdf0e10cSrcweir         aTextRect.Right()	= aTextRect.Left() + rBox.m_aRect.GetWidth() - aCheckRect.GetWidth()-6*nDelta;
5289cdf0e10cSrcweir         aTextRect.Bottom()	= rBox.m_aRect.Bottom();
5290cdf0e10cSrcweir     }
5291cdf0e10cSrcweir     else
5292cdf0e10cSrcweir     {
5293cdf0e10cSrcweir         aCheckRect.Left()	= rBox.m_aRect.Right() - nDelta - aFontSize.Height();
5294cdf0e10cSrcweir         aCheckRect.Top()	= rBox.m_aRect.Top() + (rBox.m_aRect.GetHeight()-aFontSize.Height())/2;
5295cdf0e10cSrcweir         aCheckRect.Right()	= aCheckRect.Left() + aFontSize.Height();
5296cdf0e10cSrcweir         aCheckRect.Bottom()	= aCheckRect.Top() + aFontSize.Height();
5297cdf0e10cSrcweir 
5298cdf0e10cSrcweir         // #i74206# handle small controls without text area
5299cdf0e10cSrcweir         while( aCheckRect.GetWidth() > rBox.m_aRect.GetWidth() && aCheckRect.GetWidth() > nDelta )
5300cdf0e10cSrcweir         {
5301cdf0e10cSrcweir             aCheckRect.Left()   += nDelta;
5302cdf0e10cSrcweir             aCheckRect.Top()    += nDelta/2;
5303cdf0e10cSrcweir             aCheckRect.Bottom() -= nDelta - (nDelta/2);
5304cdf0e10cSrcweir         }
5305cdf0e10cSrcweir 
5306cdf0e10cSrcweir         aTextRect.Left()	= rBox.m_aRect.Left();
5307cdf0e10cSrcweir         aTextRect.Top()		= rBox.m_aRect.Top();
5308cdf0e10cSrcweir         aTextRect.Right()	= aTextRect.Left() + rBox.m_aRect.GetWidth() - aCheckRect.GetWidth()-6*nDelta;
5309cdf0e10cSrcweir         aTextRect.Bottom()	= rBox.m_aRect.Bottom();
5310cdf0e10cSrcweir     }
5311cdf0e10cSrcweir     setLineColor( Color( COL_BLACK ) );
5312cdf0e10cSrcweir     setFillColor( Color( COL_TRANSPARENT ) );
5313cdf0e10cSrcweir     OStringBuffer aLW( 32 );
5314cdf0e10cSrcweir     aLW.append( "q " );
5315cdf0e10cSrcweir     m_aPages[ m_nCurrentPage ].appendMappedLength( nDelta, aLW );
5316cdf0e10cSrcweir     aLW.append( " w " );
5317cdf0e10cSrcweir     writeBuffer( aLW.getStr(), aLW.getLength() );
5318cdf0e10cSrcweir     drawEllipse( aCheckRect );
5319cdf0e10cSrcweir     writeBuffer( " Q\n", 3 );
5320cdf0e10cSrcweir     setTextColor( replaceColor( rWidget.TextColor, rSettings.GetRadioCheckTextColor() ) );
5321cdf0e10cSrcweir     drawText( aTextRect, rBox.m_aText, rBox.m_nTextStyle );
5322cdf0e10cSrcweir 
5323cdf0e10cSrcweir     pop();
5324cdf0e10cSrcweir 
5325cdf0e10cSrcweir     OStringBuffer aDA( 256 );
5326cdf0e10cSrcweir     appendNonStrokingColor( replaceColor( rWidget.TextColor, rSettings.GetRadioCheckTextColor() ), aDA );
5327cdf0e10cSrcweir     sal_Int32 nBest = getBestBuiltinFont( Font( String( RTL_CONSTASCII_USTRINGPARAM( "ZapfDingbats" ) ), aFont.GetSize() ) );
5328cdf0e10cSrcweir     aDA.append( ' ' );
5329cdf0e10cSrcweir     aDA.append( m_aBuiltinFonts[nBest].getNameObject() );
5330cdf0e10cSrcweir     aDA.append( " 0 Tf" );
5331cdf0e10cSrcweir     rBox.m_aDAString = aDA.makeStringAndClear();
5332cdf0e10cSrcweir //to encrypt this (el)
5333cdf0e10cSrcweir     rBox.m_aMKDict = "/CA";
5334cdf0e10cSrcweir //after this assignement, to m_aMKDic cannot be added anything
5335cdf0e10cSrcweir     rBox.m_aMKDictCAString = "l";
5336cdf0e10cSrcweir 
5337cdf0e10cSrcweir     rBox.m_aRect = aCheckRect;
5338cdf0e10cSrcweir 
5339cdf0e10cSrcweir     // create appearance streams
5340cdf0e10cSrcweir     push( sal::static_int_cast<sal_uInt16>(~0U) );
5341cdf0e10cSrcweir     SvMemoryStream* pCheckStream = new SvMemoryStream( 256, 256 );
5342cdf0e10cSrcweir 
5343cdf0e10cSrcweir     beginRedirect( pCheckStream, aCheckRect );
5344cdf0e10cSrcweir     aDA.append( "/Tx BMC\nq BT\n" );
5345cdf0e10cSrcweir     appendNonStrokingColor( replaceColor( rWidget.TextColor, rSettings.GetRadioCheckTextColor() ), aDA );
5346cdf0e10cSrcweir     aDA.append( ' ' );
5347cdf0e10cSrcweir     aDA.append( m_aBuiltinFonts[nBest].getNameObject() );
5348cdf0e10cSrcweir     aDA.append( ' ' );
5349cdf0e10cSrcweir     m_aPages[m_nCurrentPage].appendMappedLength( sal_Int32( aCheckRect.GetHeight() ), aDA );
5350cdf0e10cSrcweir     aDA.append( " Tf\n0 0 Td\nET\nQ\n" );
5351cdf0e10cSrcweir     writeBuffer( aDA.getStr(), aDA.getLength() );
5352cdf0e10cSrcweir     setFillColor( replaceColor( rWidget.TextColor, rSettings.GetRadioCheckTextColor() ) );
5353cdf0e10cSrcweir     setLineColor( Color( COL_TRANSPARENT ) );
5354cdf0e10cSrcweir     aCheckRect.Left()	+= 3*nDelta;
5355cdf0e10cSrcweir     aCheckRect.Top()	+= 3*nDelta;
5356cdf0e10cSrcweir     aCheckRect.Bottom()	-= 3*nDelta;
5357cdf0e10cSrcweir     aCheckRect.Right()	-= 3*nDelta;
5358cdf0e10cSrcweir     drawEllipse( aCheckRect );
5359cdf0e10cSrcweir     writeBuffer( "\nEMC\n", 5 );
5360cdf0e10cSrcweir     endRedirect();
5361cdf0e10cSrcweir 
5362cdf0e10cSrcweir     pop();
5363cdf0e10cSrcweir     rBox.m_aAppearances[ "N" ][ "Yes" ] = pCheckStream;
5364cdf0e10cSrcweir 
5365cdf0e10cSrcweir     SvMemoryStream* pUncheckStream = new SvMemoryStream( 256, 256 );
5366cdf0e10cSrcweir     beginRedirect( pUncheckStream, aCheckRect );
5367cdf0e10cSrcweir     writeBuffer( "/Tx BMC\nEMC\n", 12 );
5368cdf0e10cSrcweir     endRedirect();
5369cdf0e10cSrcweir     rBox.m_aAppearances[ "N" ][ "Off" ] = pUncheckStream;
5370cdf0e10cSrcweir }
5371cdf0e10cSrcweir 
5372cdf0e10cSrcweir bool PDFWriterImpl::emitAppearances( PDFWidget& rWidget, OStringBuffer& rAnnotDict )
5373cdf0e10cSrcweir {
5374cdf0e10cSrcweir 
5375cdf0e10cSrcweir     // TODO: check and insert default streams
5376cdf0e10cSrcweir     rtl::OString aStandardAppearance;
5377cdf0e10cSrcweir     switch( rWidget.m_eType )
5378cdf0e10cSrcweir     {
5379cdf0e10cSrcweir         case PDFWriter::CheckBox:
5380cdf0e10cSrcweir             aStandardAppearance = OUStringToOString( rWidget.m_aValue, RTL_TEXTENCODING_ASCII_US );
5381cdf0e10cSrcweir             break;
5382cdf0e10cSrcweir         default:
5383cdf0e10cSrcweir             break;
5384cdf0e10cSrcweir     }
5385cdf0e10cSrcweir 
5386cdf0e10cSrcweir     if( rWidget.m_aAppearances.size() )
5387cdf0e10cSrcweir     {
5388cdf0e10cSrcweir         rAnnotDict.append( "/AP<<\n" );
5389cdf0e10cSrcweir         for( PDFAppearanceMap::iterator dict_it = rWidget.m_aAppearances.begin(); dict_it != rWidget.m_aAppearances.end(); ++dict_it )
5390cdf0e10cSrcweir         {
5391cdf0e10cSrcweir             rAnnotDict.append( "/" );
5392cdf0e10cSrcweir             rAnnotDict.append( dict_it->first );
5393cdf0e10cSrcweir             bool bUseSubDict = (dict_it->second.size() > 1);
5394cdf0e10cSrcweir             rAnnotDict.append( bUseSubDict ? "<<" : " " );
5395cdf0e10cSrcweir 
5396cdf0e10cSrcweir             for( PDFAppearanceStreams::const_iterator stream_it = dict_it->second.begin();
5397cdf0e10cSrcweir                  stream_it != dict_it->second.end(); ++stream_it )
5398cdf0e10cSrcweir             {
5399cdf0e10cSrcweir                 SvMemoryStream* pApppearanceStream = stream_it->second;
5400cdf0e10cSrcweir                 dict_it->second[ stream_it->first ] = NULL;
5401cdf0e10cSrcweir 
5402cdf0e10cSrcweir                 bool bDeflate = compressStream( pApppearanceStream );
5403cdf0e10cSrcweir 
5404cdf0e10cSrcweir                 pApppearanceStream->Seek( STREAM_SEEK_TO_END );
5405cdf0e10cSrcweir                 sal_Int64 nStreamLen = pApppearanceStream->Tell();
5406cdf0e10cSrcweir                 pApppearanceStream->Seek( STREAM_SEEK_TO_BEGIN );
5407cdf0e10cSrcweir                 sal_Int32 nObject = createObject();
5408cdf0e10cSrcweir                 CHECK_RETURN( updateObject( nObject ) );
5409cdf0e10cSrcweir                 #if OSL_DEBUG_LEVEL > 1
5410cdf0e10cSrcweir                 emitComment( "PDFWriterImpl::emitAppearances" );
5411cdf0e10cSrcweir                 #endif
5412cdf0e10cSrcweir                 OStringBuffer aLine;
5413cdf0e10cSrcweir                 aLine.append( nObject );
5414cdf0e10cSrcweir 
5415cdf0e10cSrcweir                 aLine.append( " 0 obj\n"
5416cdf0e10cSrcweir                               "<</Type/XObject\n"
5417cdf0e10cSrcweir                               "/Subtype/Form\n"
5418cdf0e10cSrcweir                               "/BBox[0 0 " );
5419cdf0e10cSrcweir                 appendFixedInt( rWidget.m_aRect.GetWidth()-1, aLine );
5420cdf0e10cSrcweir                 aLine.append( " " );
5421cdf0e10cSrcweir                 appendFixedInt( rWidget.m_aRect.GetHeight()-1, aLine );
5422cdf0e10cSrcweir                 aLine.append( "]\n"
5423cdf0e10cSrcweir                               "/Resources " );
5424cdf0e10cSrcweir                 aLine.append( getResourceDictObj() );
5425cdf0e10cSrcweir                 aLine.append( " 0 R\n"
5426cdf0e10cSrcweir                               "/Length " );
5427cdf0e10cSrcweir                 aLine.append( nStreamLen );
5428cdf0e10cSrcweir                 aLine.append( "\n" );
5429cdf0e10cSrcweir                 if( bDeflate )
5430cdf0e10cSrcweir                     aLine.append( "/Filter/FlateDecode\n" );
5431cdf0e10cSrcweir                 aLine.append( ">>\nstream\n" );
5432cdf0e10cSrcweir                 CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
5433cdf0e10cSrcweir                 checkAndEnableStreamEncryption( nObject );
5434cdf0e10cSrcweir                 CHECK_RETURN( writeBuffer( pApppearanceStream->GetData(), nStreamLen ) );
5435cdf0e10cSrcweir                 disableStreamEncryption();
5436cdf0e10cSrcweir                 CHECK_RETURN( writeBuffer( "\nendstream\nendobj\n\n", 19 ) );
5437cdf0e10cSrcweir 
5438cdf0e10cSrcweir                 if( bUseSubDict )
5439cdf0e10cSrcweir                 {
5440cdf0e10cSrcweir                     rAnnotDict.append( " /" );
5441cdf0e10cSrcweir                     rAnnotDict.append( stream_it->first );
5442cdf0e10cSrcweir                     rAnnotDict.append( " " );
5443cdf0e10cSrcweir                 }
5444cdf0e10cSrcweir                 rAnnotDict.append( nObject );
5445cdf0e10cSrcweir                 rAnnotDict.append( " 0 R" );
5446cdf0e10cSrcweir 
5447cdf0e10cSrcweir                 delete pApppearanceStream;
5448cdf0e10cSrcweir             }
5449cdf0e10cSrcweir 
5450cdf0e10cSrcweir             rAnnotDict.append( bUseSubDict ? ">>\n" : "\n" );
5451cdf0e10cSrcweir         }
5452cdf0e10cSrcweir         rAnnotDict.append( ">>\n" );
5453cdf0e10cSrcweir         if( aStandardAppearance.getLength() )
5454cdf0e10cSrcweir         {
5455cdf0e10cSrcweir             rAnnotDict.append( "/AS /" );
5456cdf0e10cSrcweir             rAnnotDict.append( aStandardAppearance );
5457cdf0e10cSrcweir             rAnnotDict.append( "\n" );
5458cdf0e10cSrcweir         }
5459cdf0e10cSrcweir     }
5460cdf0e10cSrcweir 
5461cdf0e10cSrcweir     return true;
5462cdf0e10cSrcweir }
5463cdf0e10cSrcweir 
5464cdf0e10cSrcweir bool PDFWriterImpl::emitWidgetAnnotations()
5465cdf0e10cSrcweir {
5466cdf0e10cSrcweir     ensureUniqueRadioOnValues();
5467cdf0e10cSrcweir 
5468cdf0e10cSrcweir     int nAnnots = m_aWidgets.size();
5469cdf0e10cSrcweir     for( int a = 0; a < nAnnots; a++ )
5470cdf0e10cSrcweir     {
5471cdf0e10cSrcweir         PDFWidget& rWidget = m_aWidgets[a];
5472cdf0e10cSrcweir 
5473cdf0e10cSrcweir         OStringBuffer aLine( 1024 );
5474cdf0e10cSrcweir         OStringBuffer aValue( 256 );
5475cdf0e10cSrcweir         aLine.append( rWidget.m_nObject );
5476cdf0e10cSrcweir         aLine.append( " 0 obj\n"
5477cdf0e10cSrcweir                       "<<" );
5478cdf0e10cSrcweir         if( rWidget.m_eType != PDFWriter::Hierarchy )
5479cdf0e10cSrcweir         {
5480cdf0e10cSrcweir             // emit widget annotation only for terminal fields
5481cdf0e10cSrcweir             if( rWidget.m_aKids.empty() )
5482cdf0e10cSrcweir             {
5483cdf0e10cSrcweir                 aLine.append( "/Type/Annot/Subtype/Widget/F 4\n"
5484cdf0e10cSrcweir                               "/Rect[" );
5485cdf0e10cSrcweir                 appendFixedInt( rWidget.m_aRect.Left()-1, aLine );
5486cdf0e10cSrcweir                 aLine.append( ' ' );
5487cdf0e10cSrcweir                 appendFixedInt( rWidget.m_aRect.Top()+1, aLine );
5488cdf0e10cSrcweir                 aLine.append( ' ' );
5489cdf0e10cSrcweir                 appendFixedInt( rWidget.m_aRect.Right()+1, aLine );
5490cdf0e10cSrcweir                 aLine.append( ' ' );
5491cdf0e10cSrcweir                 appendFixedInt( rWidget.m_aRect.Bottom()-1, aLine );
5492cdf0e10cSrcweir                 aLine.append( "]\n" );
5493cdf0e10cSrcweir             }
5494cdf0e10cSrcweir             aLine.append( "/FT/" );
5495cdf0e10cSrcweir             switch( rWidget.m_eType )
5496cdf0e10cSrcweir             {
5497cdf0e10cSrcweir                 case PDFWriter::RadioButton:
5498cdf0e10cSrcweir                 case PDFWriter::CheckBox:
5499cdf0e10cSrcweir                     // for radio buttons only the RadioButton field, not the
5500cdf0e10cSrcweir                     // CheckBox children should have a value, else acrobat reader
5501cdf0e10cSrcweir                     // does not always check the right button
5502cdf0e10cSrcweir                     // of course real check boxes (not belonging to a readio group)
5503cdf0e10cSrcweir                     // need their values, too
5504cdf0e10cSrcweir                     if( rWidget.m_eType == PDFWriter::RadioButton || rWidget.m_nRadioGroup < 0 )
5505cdf0e10cSrcweir                     {
5506cdf0e10cSrcweir                         aValue.append( "/" );
5507cdf0e10cSrcweir                         // check for radio group with all buttons unpressed
5508cdf0e10cSrcweir                         if( rWidget.m_aValue.getLength() == 0 )
5509cdf0e10cSrcweir                             aValue.append( "Off" );
5510cdf0e10cSrcweir                         else
5511cdf0e10cSrcweir                             appendName( rWidget.m_aValue, aValue );
5512cdf0e10cSrcweir                     }
5513cdf0e10cSrcweir                 case PDFWriter::PushButton:
5514cdf0e10cSrcweir                     aLine.append( "Btn" );
5515cdf0e10cSrcweir                     break;
5516cdf0e10cSrcweir                 case PDFWriter::ListBox:
5517cdf0e10cSrcweir                     if( rWidget.m_nFlags & 0x200000 ) // multiselect
5518cdf0e10cSrcweir                     {
5519cdf0e10cSrcweir                         aValue.append( "[" );
5520cdf0e10cSrcweir                         for( unsigned int i = 0; i < rWidget.m_aSelectedEntries.size(); i++ )
5521cdf0e10cSrcweir                         {
5522cdf0e10cSrcweir                             sal_Int32 nEntry = rWidget.m_aSelectedEntries[i];
5523cdf0e10cSrcweir                             if( nEntry >= 0 && nEntry < sal_Int32(rWidget.m_aListEntries.size()) )
5524cdf0e10cSrcweir                                 appendUnicodeTextStringEncrypt( rWidget.m_aListEntries[ nEntry ], rWidget.m_nObject, aValue );
5525cdf0e10cSrcweir                         }
5526cdf0e10cSrcweir                         aValue.append( "]" );
5527cdf0e10cSrcweir                     }
5528cdf0e10cSrcweir                     else if( rWidget.m_aSelectedEntries.size() > 0 &&
5529cdf0e10cSrcweir                              rWidget.m_aSelectedEntries[0] >= 0 &&
5530cdf0e10cSrcweir                              rWidget.m_aSelectedEntries[0] < sal_Int32(rWidget.m_aListEntries.size()) )
5531cdf0e10cSrcweir                     {
5532cdf0e10cSrcweir                         appendUnicodeTextStringEncrypt( rWidget.m_aListEntries[ rWidget.m_aSelectedEntries[0] ], rWidget.m_nObject, aValue );
5533cdf0e10cSrcweir                     }
5534cdf0e10cSrcweir                     else
5535cdf0e10cSrcweir                         appendUnicodeTextStringEncrypt( rtl::OUString(), rWidget.m_nObject, aValue );
5536cdf0e10cSrcweir                     aLine.append( "Ch" );
5537cdf0e10cSrcweir                     break;
5538cdf0e10cSrcweir                 case PDFWriter::ComboBox:
5539cdf0e10cSrcweir                     appendUnicodeTextStringEncrypt( rWidget.m_aValue, rWidget.m_nObject, aValue );
5540cdf0e10cSrcweir                     aLine.append( "Ch" );
5541cdf0e10cSrcweir                     break;
5542cdf0e10cSrcweir                 case PDFWriter::Edit:
5543cdf0e10cSrcweir                     aLine.append( "Tx" );
5544cdf0e10cSrcweir                     appendUnicodeTextStringEncrypt( rWidget.m_aValue, rWidget.m_nObject, aValue );
5545cdf0e10cSrcweir                     break;
5546cdf0e10cSrcweir                 case PDFWriter::Hierarchy: // make the compiler happy
5547cdf0e10cSrcweir                     break;
5548cdf0e10cSrcweir             }
5549cdf0e10cSrcweir             aLine.append( "\n" );
5550cdf0e10cSrcweir             aLine.append( "/P " );
5551cdf0e10cSrcweir             aLine.append( m_aPages[ rWidget.m_nPage ].m_nPageObject );
5552cdf0e10cSrcweir             aLine.append( " 0 R\n" );
5553cdf0e10cSrcweir         }
5554cdf0e10cSrcweir         if( rWidget.m_nParent )
5555cdf0e10cSrcweir         {
5556cdf0e10cSrcweir             aLine.append( "/Parent " );
5557cdf0e10cSrcweir             aLine.append( rWidget.m_nParent );
5558cdf0e10cSrcweir             aLine.append( " 0 R\n" );
5559cdf0e10cSrcweir         }
5560cdf0e10cSrcweir         if( rWidget.m_aKids.size() )
5561cdf0e10cSrcweir         {
5562cdf0e10cSrcweir             aLine.append( "/Kids[" );
5563cdf0e10cSrcweir             for( unsigned int i = 0; i < rWidget.m_aKids.size(); i++ )
5564cdf0e10cSrcweir             {
5565cdf0e10cSrcweir                 aLine.append( rWidget.m_aKids[i] );
5566cdf0e10cSrcweir                 aLine.append( " 0 R" );
5567cdf0e10cSrcweir                 aLine.append( ( (i&15) == 15 ) ? "\n" : " " );
5568cdf0e10cSrcweir             }
5569cdf0e10cSrcweir             aLine.append( "]\n" );
5570cdf0e10cSrcweir         }
5571cdf0e10cSrcweir         if( rWidget.m_aName.getLength() )
5572cdf0e10cSrcweir         {
5573cdf0e10cSrcweir             aLine.append( "/T" );
5574cdf0e10cSrcweir             appendLiteralStringEncrypt( rWidget.m_aName, rWidget.m_nObject, aLine );
5575cdf0e10cSrcweir             aLine.append( "\n" );
5576cdf0e10cSrcweir         }
5577cdf0e10cSrcweir         if( m_aContext.Version > PDFWriter::PDF_1_2 && rWidget.m_aDescription.getLength() )
5578cdf0e10cSrcweir         {
5579cdf0e10cSrcweir             // the alternate field name should be unicode able since it is
5580cdf0e10cSrcweir             // supposed to be used in UI
5581cdf0e10cSrcweir             aLine.append( "/TU" );
5582cdf0e10cSrcweir             appendUnicodeTextStringEncrypt( rWidget.m_aDescription, rWidget.m_nObject, aLine );
5583cdf0e10cSrcweir             aLine.append( "\n" );
5584cdf0e10cSrcweir         }
5585cdf0e10cSrcweir 
5586cdf0e10cSrcweir         if( rWidget.m_nFlags )
5587cdf0e10cSrcweir         {
5588cdf0e10cSrcweir             aLine.append( "/Ff " );
5589cdf0e10cSrcweir             aLine.append( rWidget.m_nFlags );
5590cdf0e10cSrcweir             aLine.append( "\n" );
5591cdf0e10cSrcweir         }
5592cdf0e10cSrcweir         if( aValue.getLength() )
5593cdf0e10cSrcweir         {
5594cdf0e10cSrcweir             OString aVal = aValue.makeStringAndClear();
5595cdf0e10cSrcweir             aLine.append( "/V " );
5596cdf0e10cSrcweir             aLine.append( aVal );
5597cdf0e10cSrcweir             aLine.append( "\n"
5598cdf0e10cSrcweir                           "/DV " );
5599cdf0e10cSrcweir             aLine.append( aVal );
5600cdf0e10cSrcweir             aLine.append( "\n" );
5601cdf0e10cSrcweir         }
5602cdf0e10cSrcweir         if( rWidget.m_eType == PDFWriter::ListBox || rWidget.m_eType == PDFWriter::ComboBox )
5603cdf0e10cSrcweir         {
5604cdf0e10cSrcweir             sal_Int32 nTI = -1;
5605cdf0e10cSrcweir             aLine.append( "/Opt[\n" );
5606cdf0e10cSrcweir             sal_Int32 i = 0;
5607cdf0e10cSrcweir             for( std::vector< OUString >::const_iterator it = rWidget.m_aListEntries.begin(); it != rWidget.m_aListEntries.end(); ++it, ++i )
5608cdf0e10cSrcweir             {
5609cdf0e10cSrcweir                 appendUnicodeTextStringEncrypt( *it, rWidget.m_nObject, aLine );
5610cdf0e10cSrcweir                 aLine.append( "\n" );
5611cdf0e10cSrcweir                 if( *it == rWidget.m_aValue )
5612cdf0e10cSrcweir                     nTI = i;
5613cdf0e10cSrcweir             }
5614cdf0e10cSrcweir             aLine.append( "]\n" );
5615cdf0e10cSrcweir             if( nTI > 0 )
5616cdf0e10cSrcweir             {
5617cdf0e10cSrcweir                 aLine.append( "/TI " );
5618cdf0e10cSrcweir                 aLine.append( nTI );
5619cdf0e10cSrcweir                 aLine.append( "\n" );
5620cdf0e10cSrcweir                 if( rWidget.m_nFlags & 0x200000 ) // Multiselect
5621cdf0e10cSrcweir                 {
5622cdf0e10cSrcweir                     aLine.append( "/I [" );
5623cdf0e10cSrcweir                     aLine.append( nTI );
5624cdf0e10cSrcweir                     aLine.append( "]\n" );
5625cdf0e10cSrcweir                 }
5626cdf0e10cSrcweir             }
5627cdf0e10cSrcweir         }
5628cdf0e10cSrcweir         if( rWidget.m_eType == PDFWriter::Edit && rWidget.m_nMaxLen > 0 )
5629cdf0e10cSrcweir         {
5630cdf0e10cSrcweir             aLine.append( "/MaxLen " );
5631cdf0e10cSrcweir             aLine.append( rWidget.m_nMaxLen );
5632cdf0e10cSrcweir             aLine.append( "\n" );
5633cdf0e10cSrcweir         }
5634cdf0e10cSrcweir         if( rWidget.m_eType == PDFWriter::PushButton )
5635cdf0e10cSrcweir         {
5636cdf0e10cSrcweir             if(!m_bIsPDF_A1)
5637cdf0e10cSrcweir             {
5638cdf0e10cSrcweir                 OStringBuffer aDest;
5639cdf0e10cSrcweir                 if( rWidget.m_nDest != -1 && appendDest( m_aDestinationIdTranslation[ rWidget.m_nDest ], aDest ) )
5640cdf0e10cSrcweir                 {
5641cdf0e10cSrcweir                     aLine.append( "/AA<</D<</Type/Action/S/GoTo/D " );
5642cdf0e10cSrcweir                     aLine.append( aDest.makeStringAndClear() );
5643cdf0e10cSrcweir                     aLine.append( ">>>>\n" );
5644cdf0e10cSrcweir                 }
5645cdf0e10cSrcweir                 else if( rWidget.m_aListEntries.empty() )
5646cdf0e10cSrcweir                 {
5647cdf0e10cSrcweir                     // create a reset form action
5648cdf0e10cSrcweir                     aLine.append( "/AA<</D<</Type/Action/S/ResetForm>>>>\n" );
5649cdf0e10cSrcweir                 }
5650cdf0e10cSrcweir                 else if( rWidget.m_bSubmit )
5651cdf0e10cSrcweir                 {
5652cdf0e10cSrcweir                     // create a submit form action
5653cdf0e10cSrcweir                     aLine.append( "/AA<</D<</Type/Action/S/SubmitForm/F" );
5654cdf0e10cSrcweir                     appendLiteralStringEncrypt( rWidget.m_aListEntries.front(), rWidget.m_nObject, aLine, osl_getThreadTextEncoding() );
5655cdf0e10cSrcweir                     aLine.append( "/Flags " );
5656cdf0e10cSrcweir 
5657cdf0e10cSrcweir                     sal_Int32 nFlags = 0;
5658cdf0e10cSrcweir                     switch( m_aContext.SubmitFormat )
5659cdf0e10cSrcweir                     {
5660cdf0e10cSrcweir                     case PDFWriter::HTML:
5661cdf0e10cSrcweir                         nFlags |= 4;
5662cdf0e10cSrcweir                         break;
5663cdf0e10cSrcweir                     case PDFWriter::XML:
5664cdf0e10cSrcweir                         if( m_aContext.Version > PDFWriter::PDF_1_3 )
5665cdf0e10cSrcweir                             nFlags |= 32;
5666cdf0e10cSrcweir                         break;
5667cdf0e10cSrcweir                     case PDFWriter::PDF:
5668cdf0e10cSrcweir                         if( m_aContext.Version > PDFWriter::PDF_1_3 )
5669cdf0e10cSrcweir                             nFlags |= 256;
5670cdf0e10cSrcweir                         break;
5671cdf0e10cSrcweir                     case PDFWriter::FDF:
5672cdf0e10cSrcweir                     default:
5673cdf0e10cSrcweir                         break;
5674cdf0e10cSrcweir                     }
5675cdf0e10cSrcweir                     if( rWidget.m_bSubmitGet )
5676cdf0e10cSrcweir                         nFlags |= 8;
5677cdf0e10cSrcweir                     aLine.append( nFlags );
5678cdf0e10cSrcweir                     aLine.append( ">>>>\n" );
5679cdf0e10cSrcweir                 }
5680cdf0e10cSrcweir                 else
5681cdf0e10cSrcweir                 {
5682cdf0e10cSrcweir                     // create a URI action
5683cdf0e10cSrcweir                     aLine.append( "/AA<</D<</Type/Action/S/URI/URI(" );
5684cdf0e10cSrcweir                     aLine.append( OUStringToOString( rWidget.m_aListEntries.front(), RTL_TEXTENCODING_ASCII_US ) );
5685cdf0e10cSrcweir                     aLine.append( ")>>>>\n" );
5686cdf0e10cSrcweir                 }
5687cdf0e10cSrcweir             }
5688cdf0e10cSrcweir             else
5689cdf0e10cSrcweir                 m_aErrors.insert( PDFWriter::Warning_FormAction_Omitted_PDFA );
5690cdf0e10cSrcweir         }
5691cdf0e10cSrcweir         if( rWidget.m_aDAString.getLength() )
5692cdf0e10cSrcweir         {
5693cdf0e10cSrcweir             if( rWidget.m_aDRDict.getLength() )
5694cdf0e10cSrcweir             {
5695cdf0e10cSrcweir                 aLine.append( "/DR<<" );
5696cdf0e10cSrcweir                 aLine.append( rWidget.m_aDRDict );
5697cdf0e10cSrcweir                 aLine.append( ">>\n" );
5698cdf0e10cSrcweir             }
5699cdf0e10cSrcweir             else
5700cdf0e10cSrcweir             {
5701cdf0e10cSrcweir                 aLine.append( "/DR<</Font<<" );
5702cdf0e10cSrcweir                 appendBuiltinFontsToDict( aLine );
5703cdf0e10cSrcweir                 aLine.append( ">>>>\n" );
5704cdf0e10cSrcweir             }
5705cdf0e10cSrcweir             aLine.append( "/DA" );
5706cdf0e10cSrcweir             appendLiteralStringEncrypt( rWidget.m_aDAString, rWidget.m_nObject, aLine );
5707cdf0e10cSrcweir             aLine.append( "\n" );
5708cdf0e10cSrcweir             if( rWidget.m_nTextStyle & TEXT_DRAW_CENTER )
5709cdf0e10cSrcweir                 aLine.append( "/Q 1\n" );
5710cdf0e10cSrcweir             else if( rWidget.m_nTextStyle & TEXT_DRAW_RIGHT )
5711cdf0e10cSrcweir                 aLine.append( "/Q 2\n" );
5712cdf0e10cSrcweir         }
5713cdf0e10cSrcweir         // appearance charactristics for terminal fields
5714cdf0e10cSrcweir         // which are supposed to have an appearance constructed
5715cdf0e10cSrcweir         // by the viewer application
5716cdf0e10cSrcweir         if( rWidget.m_aMKDict.getLength() )
5717cdf0e10cSrcweir         {
5718cdf0e10cSrcweir             aLine.append( "/MK<<" );
5719cdf0e10cSrcweir             aLine.append( rWidget.m_aMKDict );
5720cdf0e10cSrcweir //add the CA string, encrypting it
5721cdf0e10cSrcweir             appendLiteralStringEncrypt(rWidget.m_aMKDictCAString, rWidget.m_nObject, aLine);
5722cdf0e10cSrcweir             aLine.append( ">>\n" );
5723cdf0e10cSrcweir         }
5724cdf0e10cSrcweir 
5725cdf0e10cSrcweir         CHECK_RETURN( emitAppearances( rWidget, aLine ) );
5726cdf0e10cSrcweir 
5727cdf0e10cSrcweir         aLine.append( ">>\n"
5728cdf0e10cSrcweir                       "endobj\n\n" );
5729cdf0e10cSrcweir         CHECK_RETURN( updateObject( rWidget.m_nObject ) );
5730cdf0e10cSrcweir         CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
5731cdf0e10cSrcweir     }
5732cdf0e10cSrcweir     return true;
5733cdf0e10cSrcweir }
5734cdf0e10cSrcweir 
5735cdf0e10cSrcweir bool PDFWriterImpl::emitAnnotations()
5736cdf0e10cSrcweir {
5737cdf0e10cSrcweir     if( m_aPages.size() < 1 )
5738cdf0e10cSrcweir         return false;
5739cdf0e10cSrcweir 
5740cdf0e10cSrcweir     CHECK_RETURN( emitLinkAnnotations() );
5741cdf0e10cSrcweir 
5742cdf0e10cSrcweir     CHECK_RETURN( emitNoteAnnotations() );
5743cdf0e10cSrcweir 
5744cdf0e10cSrcweir     CHECK_RETURN( emitWidgetAnnotations() );
5745cdf0e10cSrcweir 
5746cdf0e10cSrcweir     return true;
5747cdf0e10cSrcweir }
5748cdf0e10cSrcweir 
5749cdf0e10cSrcweir #undef CHECK_RETURN
5750cdf0e10cSrcweir #define CHECK_RETURN( x ) if( !x ) return false
5751cdf0e10cSrcweir 
5752cdf0e10cSrcweir bool PDFWriterImpl::emitCatalog()
5753cdf0e10cSrcweir {
5754cdf0e10cSrcweir     // build page tree
5755cdf0e10cSrcweir     // currently there is only one node that contains all leaves
5756cdf0e10cSrcweir 
5757cdf0e10cSrcweir     // first create a page tree node id
5758cdf0e10cSrcweir     sal_Int32 nTreeNode = createObject();
5759cdf0e10cSrcweir 
5760cdf0e10cSrcweir     // emit global resource dictionary (page emit needs it)
5761cdf0e10cSrcweir     CHECK_RETURN( emitResources() );
5762cdf0e10cSrcweir 
5763cdf0e10cSrcweir     // emit all pages
5764cdf0e10cSrcweir     for( std::vector<PDFPage>::iterator it = m_aPages.begin(); it != m_aPages.end(); ++it )
5765cdf0e10cSrcweir         if( ! it->emit( nTreeNode ) )
5766cdf0e10cSrcweir             return false;
5767cdf0e10cSrcweir 
5768cdf0e10cSrcweir     sal_Int32 nNamedDestinationsDictionary = emitNamedDestinations();
5769cdf0e10cSrcweir 
5770cdf0e10cSrcweir     sal_Int32 nOutlineDict = emitOutline();
5771cdf0e10cSrcweir 
5772cdf0e10cSrcweir     //emit Output intent i59651
5773cdf0e10cSrcweir     sal_Int32 nOutputIntentObject = emitOutputIntent();
5774cdf0e10cSrcweir 
5775cdf0e10cSrcweir     //emit metadata
5776cdf0e10cSrcweir     sal_Int32 nMetadataObject = emitDocumentMetadata();
5777cdf0e10cSrcweir 
5778cdf0e10cSrcweir     sal_Int32 nStructureDict = 0;
5779cdf0e10cSrcweir     if(m_aStructure.size() > 1)
5780cdf0e10cSrcweir     {
5781cdf0e10cSrcweir ///check if dummy structure containers are needed
5782cdf0e10cSrcweir         addInternalStructureContainer(m_aStructure[0]);
5783cdf0e10cSrcweir         nStructureDict = m_aStructure[0].m_nObject = createObject();
5784cdf0e10cSrcweir         emitStructure( m_aStructure[ 0 ] );
5785cdf0e10cSrcweir     }
5786cdf0e10cSrcweir 
5787cdf0e10cSrcweir     // adjust tree node file offset
5788cdf0e10cSrcweir     if( ! updateObject( nTreeNode ) )
5789cdf0e10cSrcweir         return false;
5790cdf0e10cSrcweir 
5791cdf0e10cSrcweir     // emit tree node
5792cdf0e10cSrcweir     OStringBuffer aLine( 2048 );
5793cdf0e10cSrcweir     aLine.append( nTreeNode );
5794cdf0e10cSrcweir     aLine.append( " 0 obj\n" );
5795cdf0e10cSrcweir     aLine.append( "<</Type/Pages\n" );
5796cdf0e10cSrcweir     aLine.append( "/Resources " );
5797cdf0e10cSrcweir     aLine.append( getResourceDictObj() );
5798cdf0e10cSrcweir     aLine.append( " 0 R\n" );
5799cdf0e10cSrcweir 
5800cdf0e10cSrcweir     switch( m_eInheritedOrientation )
5801cdf0e10cSrcweir     {
5802cdf0e10cSrcweir         case PDFWriter::Landscape: aLine.append( "/Rotate 90\n" );break;
5803cdf0e10cSrcweir         case PDFWriter::Seascape: aLine.append( "/Rotate -90\n" );break;
5804cdf0e10cSrcweir 
5805cdf0e10cSrcweir         case PDFWriter::Inherit: // actually Inherit would be a bug, but insignificant
5806cdf0e10cSrcweir         case PDFWriter::Portrait:
5807cdf0e10cSrcweir         default:
5808cdf0e10cSrcweir             break;
5809cdf0e10cSrcweir     }
5810cdf0e10cSrcweir     sal_Int32 nMediaBoxWidth = 0;
5811cdf0e10cSrcweir     sal_Int32 nMediaBoxHeight = 0;
5812cdf0e10cSrcweir     if( m_aPages.empty() ) // sanity check, this should not happen
5813cdf0e10cSrcweir     {
5814cdf0e10cSrcweir         nMediaBoxWidth = m_nInheritedPageWidth;
5815cdf0e10cSrcweir         nMediaBoxHeight = m_nInheritedPageHeight;
5816cdf0e10cSrcweir     }
5817cdf0e10cSrcweir     else
5818cdf0e10cSrcweir     {
5819cdf0e10cSrcweir         for( std::vector<PDFPage>::const_iterator iter = m_aPages.begin(); iter != m_aPages.end(); ++iter )
5820cdf0e10cSrcweir         {
5821cdf0e10cSrcweir             if( iter->m_nPageWidth > nMediaBoxWidth )
5822cdf0e10cSrcweir                 nMediaBoxWidth = iter->m_nPageWidth;
5823cdf0e10cSrcweir             if( iter->m_nPageHeight > nMediaBoxHeight )
5824cdf0e10cSrcweir                 nMediaBoxHeight = iter->m_nPageHeight;
5825cdf0e10cSrcweir         }
5826cdf0e10cSrcweir     }
5827cdf0e10cSrcweir     aLine.append( "/MediaBox[ 0 0 " );
5828cdf0e10cSrcweir     aLine.append( nMediaBoxWidth );
5829cdf0e10cSrcweir     aLine.append( ' ' );
5830cdf0e10cSrcweir     aLine.append( nMediaBoxHeight );
5831cdf0e10cSrcweir     aLine.append( " ]\n"
5832cdf0e10cSrcweir                   "/Kids[ " );
5833cdf0e10cSrcweir     unsigned int i = 0;
5834cdf0e10cSrcweir     for( std::vector<PDFPage>::const_iterator iter = m_aPages.begin(); iter != m_aPages.end(); ++iter, i++ )
5835cdf0e10cSrcweir     {
5836cdf0e10cSrcweir         aLine.append( iter->m_nPageObject );
5837cdf0e10cSrcweir         aLine.append( " 0 R" );
5838cdf0e10cSrcweir         aLine.append( ( (i&15) == 15 ) ? "\n" : " " );
5839cdf0e10cSrcweir     }
5840cdf0e10cSrcweir     aLine.append( "]\n"
5841cdf0e10cSrcweir                   "/Count " );
5842cdf0e10cSrcweir     aLine.append( (sal_Int32)m_aPages.size() );
5843cdf0e10cSrcweir     aLine.append( ">>\n"
5844cdf0e10cSrcweir                   "endobj\n\n" );
5845cdf0e10cSrcweir     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
5846cdf0e10cSrcweir 
5847cdf0e10cSrcweir     // emit annotation objects
5848cdf0e10cSrcweir     CHECK_RETURN( emitAnnotations() );
5849cdf0e10cSrcweir 
5850cdf0e10cSrcweir     // emit Catalog
5851cdf0e10cSrcweir     m_nCatalogObject = createObject();
5852cdf0e10cSrcweir     if( ! updateObject( m_nCatalogObject ) )
5853cdf0e10cSrcweir         return false;
5854cdf0e10cSrcweir     aLine.setLength( 0 );
5855cdf0e10cSrcweir     aLine.append( m_nCatalogObject );
5856cdf0e10cSrcweir     aLine.append( " 0 obj\n"
5857cdf0e10cSrcweir                   "<</Type/Catalog/Pages " );
5858cdf0e10cSrcweir     aLine.append( nTreeNode );
5859cdf0e10cSrcweir     aLine.append( " 0 R\n" );
5860cdf0e10cSrcweir //--->i56629
5861cdf0e10cSrcweir //check if there are named destinations to emit (root must be inside the catalog)
5862cdf0e10cSrcweir     if( nNamedDestinationsDictionary )
5863cdf0e10cSrcweir     {
5864cdf0e10cSrcweir         aLine.append("/Dests ");
5865cdf0e10cSrcweir         aLine.append( nNamedDestinationsDictionary );
5866cdf0e10cSrcweir         aLine.append( " 0 R\n" );
5867cdf0e10cSrcweir     }
5868cdf0e10cSrcweir //<----
5869cdf0e10cSrcweir     if( m_aContext.PageLayout != PDFWriter::DefaultLayout )
5870cdf0e10cSrcweir         switch(  m_aContext.PageLayout )
5871cdf0e10cSrcweir         {
5872cdf0e10cSrcweir         default :
5873cdf0e10cSrcweir         case  PDFWriter::SinglePage :
5874cdf0e10cSrcweir             aLine.append( "/PageLayout/SinglePage\n" );
5875cdf0e10cSrcweir             break;
5876cdf0e10cSrcweir         case  PDFWriter::Continuous :
5877cdf0e10cSrcweir             aLine.append( "/PageLayout/OneColumn\n" );
5878cdf0e10cSrcweir             break;
5879cdf0e10cSrcweir         case  PDFWriter::ContinuousFacing :
5880cdf0e10cSrcweir //the flag m_aContext.FirstPageLeft below is used to set the page on the left side
5881cdf0e10cSrcweir             aLine.append( "/PageLayout/TwoColumnRight\n" );//odd page on the right side
5882cdf0e10cSrcweir             break;
5883cdf0e10cSrcweir         }
5884cdf0e10cSrcweir     if( m_aContext.PDFDocumentMode != PDFWriter::ModeDefault && !m_aContext.OpenInFullScreenMode )
5885cdf0e10cSrcweir         switch(  m_aContext.PDFDocumentMode )
5886cdf0e10cSrcweir         {
5887cdf0e10cSrcweir         default :
5888cdf0e10cSrcweir             aLine.append( "/PageMode/UseNone\n" );
5889cdf0e10cSrcweir             break;
5890cdf0e10cSrcweir         case PDFWriter::UseOutlines :
5891cdf0e10cSrcweir             aLine.append( "/PageMode/UseOutlines\n" ); //document is opened with outline pane open
5892cdf0e10cSrcweir             break;
5893cdf0e10cSrcweir         case PDFWriter::UseThumbs :
5894cdf0e10cSrcweir             aLine.append( "/PageMode/UseThumbs\n" ); //document is opened with thumbnails pane open
5895cdf0e10cSrcweir             break;
5896cdf0e10cSrcweir         }
5897cdf0e10cSrcweir     else if( m_aContext.OpenInFullScreenMode )
5898cdf0e10cSrcweir         aLine.append( "/PageMode/FullScreen\n" ); //document is opened full screen
5899cdf0e10cSrcweir 
5900cdf0e10cSrcweir     OStringBuffer aInitPageRef;
5901cdf0e10cSrcweir     if( m_aContext.InitialPage >= 0 && m_aContext.InitialPage < (sal_Int32)m_aPages.size() )
5902cdf0e10cSrcweir     {
5903cdf0e10cSrcweir         aInitPageRef.append( m_aPages[m_aContext.InitialPage].m_nPageObject );
5904cdf0e10cSrcweir         aInitPageRef.append( " 0 R" );
5905cdf0e10cSrcweir     }
5906cdf0e10cSrcweir     else
5907cdf0e10cSrcweir         aInitPageRef.append( "0" );
5908cdf0e10cSrcweir     switch( m_aContext.PDFDocumentAction )
5909cdf0e10cSrcweir     {
5910cdf0e10cSrcweir     case PDFWriter::ActionDefault :     //do nothing, this is the Acrobat default
5911cdf0e10cSrcweir     default:
5912cdf0e10cSrcweir         if( aInitPageRef.getLength() > 1 )
5913cdf0e10cSrcweir         {
5914cdf0e10cSrcweir             aLine.append( "/OpenAction[" );
5915cdf0e10cSrcweir             aLine.append( aInitPageRef );
5916cdf0e10cSrcweir             aLine.append( " /XYZ null null 0]\n" );
5917cdf0e10cSrcweir         }
5918cdf0e10cSrcweir         break;
5919cdf0e10cSrcweir     case PDFWriter::FitInWindow :
5920cdf0e10cSrcweir         aLine.append( "/OpenAction[" );
5921cdf0e10cSrcweir         aLine.append( aInitPageRef );
5922cdf0e10cSrcweir         aLine.append( " /Fit]\n" ); //Open fit page
5923cdf0e10cSrcweir         break;
5924cdf0e10cSrcweir     case PDFWriter::FitWidth :
5925cdf0e10cSrcweir         aLine.append( "/OpenAction[" );
5926cdf0e10cSrcweir         aLine.append( aInitPageRef );
5927cdf0e10cSrcweir         aLine.append( " /FitH " );
5928cdf0e10cSrcweir         aLine.append( m_nInheritedPageHeight );//Open fit width
5929cdf0e10cSrcweir         aLine.append( "]\n" );
5930cdf0e10cSrcweir         break;
5931cdf0e10cSrcweir     case PDFWriter::FitVisible :
5932cdf0e10cSrcweir         aLine.append( "/OpenAction[" );
5933cdf0e10cSrcweir         aLine.append( aInitPageRef );
5934cdf0e10cSrcweir         aLine.append( " /FitBH " );
5935cdf0e10cSrcweir         aLine.append( m_nInheritedPageHeight );//Open fit visible
5936cdf0e10cSrcweir         aLine.append( "]\n" );
5937cdf0e10cSrcweir         break;
5938cdf0e10cSrcweir     case PDFWriter::ActionZoom :
5939cdf0e10cSrcweir         aLine.append( "/OpenAction[" );
5940cdf0e10cSrcweir         aLine.append( aInitPageRef );
5941cdf0e10cSrcweir         aLine.append( " /XYZ null null " );
5942cdf0e10cSrcweir         if( m_aContext.Zoom >= 50 && m_aContext.Zoom <= 1600 )
5943cdf0e10cSrcweir             aLine.append( (double)m_aContext.Zoom/100.0 );
5944cdf0e10cSrcweir         else
5945cdf0e10cSrcweir             aLine.append( "0" );
5946cdf0e10cSrcweir         aLine.append( "]\n" );
5947cdf0e10cSrcweir         break;
5948cdf0e10cSrcweir     }
5949cdf0e10cSrcweir // viewer preferences, if we had some, then emit
5950cdf0e10cSrcweir     if( m_aContext.HideViewerToolbar ||
5951cdf0e10cSrcweir         ( m_aContext.Version > PDFWriter::PDF_1_3 && m_aContext.DocumentInfo.Title.Len() && m_aContext.DisplayPDFDocumentTitle ) ||
5952cdf0e10cSrcweir         m_aContext.HideViewerMenubar ||
5953cdf0e10cSrcweir         m_aContext.HideViewerWindowControls || m_aContext.FitWindow ||
5954cdf0e10cSrcweir         m_aContext.CenterWindow || (m_aContext.FirstPageLeft  &&  m_aContext.PageLayout == PDFWriter::ContinuousFacing ) ||
5955cdf0e10cSrcweir         m_aContext.OpenInFullScreenMode )
5956cdf0e10cSrcweir     {
5957cdf0e10cSrcweir         aLine.append( "/ViewerPreferences<<" );
5958cdf0e10cSrcweir         if( m_aContext.HideViewerToolbar )
5959cdf0e10cSrcweir             aLine.append( "/HideToolbar true\n" );
5960cdf0e10cSrcweir         if( m_aContext.HideViewerMenubar )
5961cdf0e10cSrcweir             aLine.append( "/HideMenubar true\n" );
5962cdf0e10cSrcweir         if( m_aContext.HideViewerWindowControls )
5963cdf0e10cSrcweir             aLine.append( "/HideWindowUI true\n" );
5964cdf0e10cSrcweir         if( m_aContext.FitWindow )
5965cdf0e10cSrcweir             aLine.append( "/FitWindow true\n" );
5966cdf0e10cSrcweir         if( m_aContext.CenterWindow )
5967cdf0e10cSrcweir             aLine.append( "/CenterWindow true\n" );
5968cdf0e10cSrcweir         if( m_aContext.Version > PDFWriter::PDF_1_3 && m_aContext.DocumentInfo.Title.Len() && m_aContext.DisplayPDFDocumentTitle )
5969cdf0e10cSrcweir             aLine.append( "/DisplayDocTitle true\n" );
5970cdf0e10cSrcweir         if( m_aContext.FirstPageLeft &&  m_aContext.PageLayout == PDFWriter::ContinuousFacing )
5971cdf0e10cSrcweir             aLine.append( "/Direction/R2L\n" );
5972cdf0e10cSrcweir         if( m_aContext.OpenInFullScreenMode )
5973cdf0e10cSrcweir             switch( m_aContext.PDFDocumentMode )
5974cdf0e10cSrcweir             {
5975cdf0e10cSrcweir             default :
5976cdf0e10cSrcweir             case PDFWriter::ModeDefault :
5977cdf0e10cSrcweir                 aLine.append( "/NonFullScreenPageMode/UseNone\n" );
5978cdf0e10cSrcweir                 break;
5979cdf0e10cSrcweir             case PDFWriter::UseOutlines :
5980cdf0e10cSrcweir                 aLine.append( "/NonFullScreenPageMode/UseOutlines\n" );
5981cdf0e10cSrcweir                 break;
5982cdf0e10cSrcweir             case PDFWriter::UseThumbs :
5983cdf0e10cSrcweir                 aLine.append( "/NonFullScreenPageMode/UseThumbs\n" );
5984cdf0e10cSrcweir                 break;
5985cdf0e10cSrcweir             }
5986cdf0e10cSrcweir         aLine.append( ">>\n" );
5987cdf0e10cSrcweir     }
5988cdf0e10cSrcweir 
5989cdf0e10cSrcweir     if( nOutlineDict )
5990cdf0e10cSrcweir     {
5991cdf0e10cSrcweir         aLine.append( "/Outlines " );
5992cdf0e10cSrcweir         aLine.append( nOutlineDict );
5993cdf0e10cSrcweir         aLine.append( " 0 R\n" );
5994cdf0e10cSrcweir     }
5995cdf0e10cSrcweir     if( nStructureDict )
5996cdf0e10cSrcweir     {
5997cdf0e10cSrcweir         aLine.append( "/StructTreeRoot " );
5998cdf0e10cSrcweir         aLine.append( nStructureDict );
5999cdf0e10cSrcweir         aLine.append( " 0 R\n" );
6000cdf0e10cSrcweir     }
6001cdf0e10cSrcweir     if( m_aContext.DocumentLocale.Language.getLength() > 0 )
6002cdf0e10cSrcweir     {
6003cdf0e10cSrcweir         OUStringBuffer aLocBuf( 16 );
6004cdf0e10cSrcweir         aLocBuf.append( m_aContext.DocumentLocale.Language.toAsciiLowerCase() );
6005cdf0e10cSrcweir         if( m_aContext.DocumentLocale.Country.getLength() > 0 )
6006cdf0e10cSrcweir         {
6007cdf0e10cSrcweir             aLocBuf.append( sal_Unicode('-') );
6008cdf0e10cSrcweir             aLocBuf.append( m_aContext.DocumentLocale.Country );
6009cdf0e10cSrcweir         }
6010cdf0e10cSrcweir         aLine.append( "/Lang" );
6011cdf0e10cSrcweir         appendLiteralStringEncrypt( aLocBuf.makeStringAndClear(), m_nCatalogObject, aLine );
6012cdf0e10cSrcweir         aLine.append( "\n" );
6013cdf0e10cSrcweir     }
6014cdf0e10cSrcweir     if( m_aContext.Tagged && m_aContext.Version > PDFWriter::PDF_1_3 )
6015cdf0e10cSrcweir     {
6016cdf0e10cSrcweir         aLine.append( "/MarkInfo<</Marked true>>\n" );
6017cdf0e10cSrcweir     }
6018cdf0e10cSrcweir     if( m_aWidgets.size() > 0 )
6019cdf0e10cSrcweir     {
6020cdf0e10cSrcweir         aLine.append( "/AcroForm<</Fields[\n" );
6021cdf0e10cSrcweir         int nWidgets = m_aWidgets.size();
6022cdf0e10cSrcweir         int nOut = 0;
6023cdf0e10cSrcweir         for( int j = 0; j < nWidgets; j++ )
6024cdf0e10cSrcweir         {
6025cdf0e10cSrcweir             // output only root fields
6026cdf0e10cSrcweir             if( m_aWidgets[j].m_nParent < 1 )
6027cdf0e10cSrcweir             {
6028cdf0e10cSrcweir                 aLine.append( m_aWidgets[j].m_nObject );
6029cdf0e10cSrcweir                 aLine.append( (nOut++ % 5)==4 ? " 0 R\n" : " 0 R " );
6030cdf0e10cSrcweir             }
6031cdf0e10cSrcweir         }
6032cdf0e10cSrcweir         aLine.append( "\n]/DR " );
6033cdf0e10cSrcweir         aLine.append( getResourceDictObj() );
6034cdf0e10cSrcweir         aLine.append( " 0 R" );
6035cdf0e10cSrcweir         if( m_bIsPDF_A1 )
6036cdf0e10cSrcweir             aLine.append( ">>\n" );
6037cdf0e10cSrcweir         else
6038cdf0e10cSrcweir             aLine.append( "/NeedAppearances true>>\n" );
6039cdf0e10cSrcweir     }
6040cdf0e10cSrcweir //--->i59651
6041cdf0e10cSrcweir //check if there is a Metadata object
6042cdf0e10cSrcweir     if( nOutputIntentObject )
6043cdf0e10cSrcweir     {
6044cdf0e10cSrcweir         aLine.append("/OutputIntents[");
6045cdf0e10cSrcweir         aLine.append( nOutputIntentObject );
6046cdf0e10cSrcweir         aLine.append( " 0 R]" );
6047cdf0e10cSrcweir     }
6048cdf0e10cSrcweir     if( nMetadataObject )
6049cdf0e10cSrcweir     {
6050cdf0e10cSrcweir         aLine.append("/Metadata ");
6051cdf0e10cSrcweir         aLine.append( nMetadataObject );
6052cdf0e10cSrcweir         aLine.append( " 0 R" );
6053cdf0e10cSrcweir     }
6054cdf0e10cSrcweir //<----
6055cdf0e10cSrcweir     aLine.append( ">>\n"
6056cdf0e10cSrcweir                   "endobj\n\n" );
6057cdf0e10cSrcweir     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
6058cdf0e10cSrcweir 
6059cdf0e10cSrcweir     return true;
6060cdf0e10cSrcweir }
6061cdf0e10cSrcweir 
6062cdf0e10cSrcweir sal_Int32 PDFWriterImpl::emitInfoDict( )
6063cdf0e10cSrcweir {
6064cdf0e10cSrcweir     sal_Int32 nObject = createObject();
6065cdf0e10cSrcweir 
6066cdf0e10cSrcweir     if( updateObject( nObject ) )
6067cdf0e10cSrcweir     {
6068cdf0e10cSrcweir         OStringBuffer aLine( 1024 );
6069cdf0e10cSrcweir         aLine.append( nObject );
6070cdf0e10cSrcweir         aLine.append( " 0 obj\n"
6071cdf0e10cSrcweir                       "<<" );
6072cdf0e10cSrcweir         if( m_aContext.DocumentInfo.Title.Len() )
6073cdf0e10cSrcweir         {
6074cdf0e10cSrcweir             aLine.append( "/Title" );
6075cdf0e10cSrcweir             appendUnicodeTextStringEncrypt( m_aContext.DocumentInfo.Title, nObject, aLine );
6076cdf0e10cSrcweir             aLine.append( "\n" );
6077cdf0e10cSrcweir         }
6078cdf0e10cSrcweir         if( m_aContext.DocumentInfo.Author.Len() )
6079cdf0e10cSrcweir         {
6080cdf0e10cSrcweir             aLine.append( "/Author" );
6081cdf0e10cSrcweir             appendUnicodeTextStringEncrypt( m_aContext.DocumentInfo.Author, nObject, aLine );
6082cdf0e10cSrcweir             aLine.append( "\n" );
6083cdf0e10cSrcweir         }
6084cdf0e10cSrcweir         if( m_aContext.DocumentInfo.Subject.Len() )
6085cdf0e10cSrcweir         {
6086cdf0e10cSrcweir             aLine.append( "/Subject" );
6087cdf0e10cSrcweir             appendUnicodeTextStringEncrypt( m_aContext.DocumentInfo.Subject, nObject, aLine );
6088cdf0e10cSrcweir             aLine.append( "\n" );
6089cdf0e10cSrcweir         }
6090cdf0e10cSrcweir         if( m_aContext.DocumentInfo.Keywords.Len() )
6091cdf0e10cSrcweir         {
6092cdf0e10cSrcweir             aLine.append( "/Keywords" );
6093cdf0e10cSrcweir             appendUnicodeTextStringEncrypt( m_aContext.DocumentInfo.Keywords, nObject, aLine );
6094cdf0e10cSrcweir             aLine.append( "\n" );
6095cdf0e10cSrcweir         }
6096cdf0e10cSrcweir         if( m_aContext.DocumentInfo.Creator.Len() )
6097cdf0e10cSrcweir         {
6098cdf0e10cSrcweir             aLine.append( "/Creator" );
6099cdf0e10cSrcweir             appendUnicodeTextStringEncrypt( m_aContext.DocumentInfo.Creator, nObject, aLine );
6100cdf0e10cSrcweir             aLine.append( "\n" );
6101cdf0e10cSrcweir         }
6102cdf0e10cSrcweir         if( m_aContext.DocumentInfo.Producer.Len() )
6103cdf0e10cSrcweir         {
6104cdf0e10cSrcweir             aLine.append( "/Producer" );
6105cdf0e10cSrcweir             appendUnicodeTextStringEncrypt( m_aContext.DocumentInfo.Producer, nObject, aLine );
6106cdf0e10cSrcweir             aLine.append( "\n" );
6107cdf0e10cSrcweir         }
6108cdf0e10cSrcweir 
6109cdf0e10cSrcweir          aLine.append( "/CreationDate" );
6110cdf0e10cSrcweir          appendLiteralStringEncrypt( m_aCreationDateString, nObject, aLine );
6111cdf0e10cSrcweir         aLine.append( ">>\nendobj\n\n" );
6112cdf0e10cSrcweir         if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) )
6113cdf0e10cSrcweir             nObject = 0;
6114cdf0e10cSrcweir     }
6115cdf0e10cSrcweir     else
6116cdf0e10cSrcweir         nObject = 0;
6117cdf0e10cSrcweir 
6118cdf0e10cSrcweir     return nObject;
6119cdf0e10cSrcweir }
6120cdf0e10cSrcweir 
6121cdf0e10cSrcweir //--->i56629
6122cdf0e10cSrcweir // Part of this function may be shared with method appendDest.
6123cdf0e10cSrcweir //
6124cdf0e10cSrcweir sal_Int32 PDFWriterImpl::emitNamedDestinations()
6125cdf0e10cSrcweir {
6126cdf0e10cSrcweir     sal_Int32  nCount = m_aNamedDests.size();
6127cdf0e10cSrcweir     if( nCount <= 0 )
6128cdf0e10cSrcweir         return 0;//define internal error
6129cdf0e10cSrcweir 
6130cdf0e10cSrcweir //get the object number for all the destinations
6131cdf0e10cSrcweir     sal_Int32 nObject = createObject();
6132cdf0e10cSrcweir 
6133cdf0e10cSrcweir     if( updateObject( nObject ) )
6134cdf0e10cSrcweir     {
6135cdf0e10cSrcweir //emit the dictionary
6136cdf0e10cSrcweir         OStringBuffer aLine( 1024 );
6137cdf0e10cSrcweir         aLine.append( nObject );
6138cdf0e10cSrcweir         aLine.append( " 0 obj\n"
6139cdf0e10cSrcweir                       "<<" );
6140cdf0e10cSrcweir 
6141cdf0e10cSrcweir         sal_Int32  nDestID;
6142cdf0e10cSrcweir         for( nDestID = 0; nDestID < nCount; nDestID++ )
6143cdf0e10cSrcweir         {
6144cdf0e10cSrcweir             const PDFNamedDest& rDest   = m_aNamedDests[ nDestID ];
6145cdf0e10cSrcweir // In order to correctly function both under an Internet browser and
6146cdf0e10cSrcweir // directly with a reader (provided the reader has the feature) we
6147cdf0e10cSrcweir // need to set the name of the destination the same way it will be encoded
6148cdf0e10cSrcweir // in an Internet link
6149cdf0e10cSrcweir             INetURLObject aLocalURL(
6150cdf0e10cSrcweir                 OUString( RTL_CONSTASCII_USTRINGPARAM( "http://ahost.ax" ) ) ); //dummy location, won't be used
6151cdf0e10cSrcweir             aLocalURL.SetMark( rDest.m_aDestName );
6152cdf0e10cSrcweir 
6153cdf0e10cSrcweir             const rtl::OUString aName   = aLocalURL.GetMark( INetURLObject::NO_DECODE ); //same coding as
6154cdf0e10cSrcweir             // in link creation ( see PDFWriterImpl::emitLinkAnnotations )
6155cdf0e10cSrcweir             const PDFPage& rDestPage    = m_aPages[ rDest.m_nPage ];
6156cdf0e10cSrcweir 
6157cdf0e10cSrcweir             aLine.append( '/' );
6158cdf0e10cSrcweir             appendDestinationName( aName, aLine ); // this conversion must be done when forming the link to target ( see in emitCatalog )
6159cdf0e10cSrcweir             aLine.append( '[' ); // the '[' can be emitted immediately, because the appendDestinationName function
6160cdf0e10cSrcweir                                  //maps the preceeding character properly
6161cdf0e10cSrcweir             aLine.append( rDestPage.m_nPageObject );
6162cdf0e10cSrcweir             aLine.append( " 0 R" );
6163cdf0e10cSrcweir 
6164cdf0e10cSrcweir             switch( rDest.m_eType )
6165cdf0e10cSrcweir             {
6166cdf0e10cSrcweir             case PDFWriter::XYZ:
6167cdf0e10cSrcweir             default:
6168cdf0e10cSrcweir                 aLine.append( "/XYZ " );
6169cdf0e10cSrcweir                 appendFixedInt( rDest.m_aRect.Left(), aLine );
6170cdf0e10cSrcweir                 aLine.append( ' ' );
6171cdf0e10cSrcweir                 appendFixedInt( rDest.m_aRect.Bottom(), aLine );
6172cdf0e10cSrcweir                 aLine.append( " 0" );
6173cdf0e10cSrcweir                 break;
6174cdf0e10cSrcweir             case PDFWriter::Fit:
6175cdf0e10cSrcweir                 aLine.append( "/Fit" );
6176cdf0e10cSrcweir                 break;
6177cdf0e10cSrcweir             case PDFWriter::FitRectangle:
6178cdf0e10cSrcweir                 aLine.append( "/FitR " );
6179cdf0e10cSrcweir                 appendFixedInt( rDest.m_aRect.Left(), aLine );
6180cdf0e10cSrcweir                 aLine.append( ' ' );
6181cdf0e10cSrcweir                 appendFixedInt( rDest.m_aRect.Top(), aLine );
6182cdf0e10cSrcweir                 aLine.append( ' ' );
6183cdf0e10cSrcweir                 appendFixedInt( rDest.m_aRect.Right(), aLine );
6184cdf0e10cSrcweir                 aLine.append( ' ' );
6185cdf0e10cSrcweir                 appendFixedInt( rDest.m_aRect.Bottom(), aLine );
6186cdf0e10cSrcweir                 break;
6187cdf0e10cSrcweir             case PDFWriter::FitHorizontal:
6188cdf0e10cSrcweir                 aLine.append( "/FitH " );
6189cdf0e10cSrcweir                 appendFixedInt( rDest.m_aRect.Bottom(), aLine );
6190cdf0e10cSrcweir                 break;
6191cdf0e10cSrcweir             case PDFWriter::FitVertical:
6192cdf0e10cSrcweir                 aLine.append( "/FitV " );
6193cdf0e10cSrcweir                 appendFixedInt( rDest.m_aRect.Left(), aLine );
6194cdf0e10cSrcweir                 break;
6195cdf0e10cSrcweir             case PDFWriter::FitPageBoundingBox:
6196cdf0e10cSrcweir                 aLine.append( "/FitB" );
6197cdf0e10cSrcweir                 break;
6198cdf0e10cSrcweir             case PDFWriter::FitPageBoundingBoxHorizontal:
6199cdf0e10cSrcweir                 aLine.append( "/FitBH " );
6200cdf0e10cSrcweir                 appendFixedInt( rDest.m_aRect.Bottom(), aLine );
6201cdf0e10cSrcweir                 break;
6202cdf0e10cSrcweir             case PDFWriter::FitPageBoundingBoxVertical:
6203cdf0e10cSrcweir                 aLine.append( "/FitBV " );
6204cdf0e10cSrcweir                 appendFixedInt( rDest.m_aRect.Left(), aLine );
6205cdf0e10cSrcweir                 break;
6206cdf0e10cSrcweir             }
6207cdf0e10cSrcweir             aLine.append( "]\n" );
6208cdf0e10cSrcweir         }
6209cdf0e10cSrcweir //close
6210cdf0e10cSrcweir 
6211cdf0e10cSrcweir         aLine.append( ">>\nendobj\n\n" );
6212cdf0e10cSrcweir         if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) )
6213cdf0e10cSrcweir             nObject = 0;
6214cdf0e10cSrcweir     }
6215cdf0e10cSrcweir     else
6216cdf0e10cSrcweir         nObject = 0;
6217cdf0e10cSrcweir 
6218cdf0e10cSrcweir     return nObject;
6219cdf0e10cSrcweir }
6220cdf0e10cSrcweir //<--- i56629
6221cdf0e10cSrcweir 
6222cdf0e10cSrcweir //--->i59651
6223cdf0e10cSrcweir // emits the output intent dictionary
6224cdf0e10cSrcweir 
6225cdf0e10cSrcweir sal_Int32 PDFWriterImpl::emitOutputIntent()
6226cdf0e10cSrcweir {
6227cdf0e10cSrcweir     if( !m_bIsPDF_A1 )
6228cdf0e10cSrcweir         return 0;
6229cdf0e10cSrcweir 
6230cdf0e10cSrcweir //emit the sRGB standard profile, in ICC format, in a stream, per IEC61966-2.1
6231cdf0e10cSrcweir 
6232cdf0e10cSrcweir     OStringBuffer aLine( 1024 );
6233cdf0e10cSrcweir     sal_Int32 nICCObject = createObject();
6234cdf0e10cSrcweir     sal_Int32 nStreamLengthObject = createObject();
6235cdf0e10cSrcweir 
6236cdf0e10cSrcweir     aLine.append( nICCObject );
6237cdf0e10cSrcweir // sRGB has 3 colors, hence /N 3 below (PDF 1.4 table 4.16)
6238cdf0e10cSrcweir     aLine.append( " 0 obj\n<</N 3/Length " );
6239cdf0e10cSrcweir     aLine.append( nStreamLengthObject );
6240cdf0e10cSrcweir     aLine.append( " 0 R" );
6241cdf0e10cSrcweir #ifndef DEBUG_DISABLE_PDFCOMPRESSION
6242cdf0e10cSrcweir     aLine.append( "/Filter/FlateDecode" );
6243cdf0e10cSrcweir #endif
6244cdf0e10cSrcweir     aLine.append( ">>\nstream\n" );
6245cdf0e10cSrcweir     CHECK_RETURN( updateObject( nICCObject ) );
6246cdf0e10cSrcweir     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
6247cdf0e10cSrcweir //get file position
6248cdf0e10cSrcweir     sal_uInt64 nBeginStreamPos = 0;
6249cdf0e10cSrcweir     osl_getFilePos( m_aFile, &nBeginStreamPos );
6250cdf0e10cSrcweir     beginCompression();
6251cdf0e10cSrcweir     checkAndEnableStreamEncryption( nICCObject );
6252cdf0e10cSrcweir     sal_Int32 nStreamSize = writeBuffer( nsRGB_ICC_profile, (sal_Int32) sizeof( nsRGB_ICC_profile ) );
6253cdf0e10cSrcweir     disableStreamEncryption();
6254cdf0e10cSrcweir     endCompression();
6255cdf0e10cSrcweir     sal_uInt64 nEndStreamPos = 0;
6256cdf0e10cSrcweir     osl_getFilePos( m_aFile, &nEndStreamPos );
6257cdf0e10cSrcweir 
6258cdf0e10cSrcweir     if( nStreamSize == 0 )
6259cdf0e10cSrcweir         return 0;
6260cdf0e10cSrcweir     if( ! writeBuffer( "\nendstream\nendobj\n\n", 19 ) )
6261cdf0e10cSrcweir         return 0 ;
6262cdf0e10cSrcweir     aLine.setLength( 0 );
6263cdf0e10cSrcweir 
6264cdf0e10cSrcweir //emit the stream length   object
6265cdf0e10cSrcweir     CHECK_RETURN( updateObject( nStreamLengthObject ) );
6266cdf0e10cSrcweir     aLine.setLength( 0 );
6267cdf0e10cSrcweir     aLine.append( nStreamLengthObject );
6268cdf0e10cSrcweir     aLine.append( " 0 obj\n" );
6269cdf0e10cSrcweir     aLine.append( (sal_Int64)(nEndStreamPos-nBeginStreamPos) );
6270cdf0e10cSrcweir     aLine.append( "\nendobj\n\n" );
6271cdf0e10cSrcweir     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
6272cdf0e10cSrcweir     aLine.setLength( 0 );
6273cdf0e10cSrcweir 
6274cdf0e10cSrcweir //emit the OutputIntent dictionary
6275cdf0e10cSrcweir     sal_Int32 nOIObject = createObject();
6276cdf0e10cSrcweir     CHECK_RETURN( updateObject( nOIObject ) );
6277cdf0e10cSrcweir     aLine.append( nOIObject );
6278cdf0e10cSrcweir     aLine.append( " 0 obj\n"
6279cdf0e10cSrcweir                   "<</Type/OutputIntent/S/GTS_PDFA1/OutputConditionIdentifier");
6280cdf0e10cSrcweir 
6281cdf0e10cSrcweir     rtl::OUString aComment( RTL_CONSTASCII_USTRINGPARAM( "sRGB IEC61966-2.1" ) );
6282cdf0e10cSrcweir     appendLiteralStringEncrypt( aComment ,nOIObject, aLine );
6283cdf0e10cSrcweir     aLine.append("/DestOutputProfile ");
6284cdf0e10cSrcweir     aLine.append( nICCObject );
6285cdf0e10cSrcweir     aLine.append( " 0 R>>\nendobj\n\n" );;
6286cdf0e10cSrcweir     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
6287cdf0e10cSrcweir 
6288cdf0e10cSrcweir     return nOIObject;
6289cdf0e10cSrcweir }
6290cdf0e10cSrcweir 
6291cdf0e10cSrcweir // formats the string for the XML stream
6292cdf0e10cSrcweir static void escapeStringXML( const rtl::OUString& rStr, rtl::OUString &rValue)
6293cdf0e10cSrcweir {
6294cdf0e10cSrcweir     const sal_Unicode* pUni = rStr.getStr();
6295cdf0e10cSrcweir     int nLen = rStr.getLength();
6296cdf0e10cSrcweir     for( ; nLen; nLen--, pUni++ )
6297cdf0e10cSrcweir     {
6298cdf0e10cSrcweir         switch( *pUni )
6299cdf0e10cSrcweir         {
6300cdf0e10cSrcweir         case sal_Unicode('&'):
6301cdf0e10cSrcweir             rValue += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "&amp;" ) );
6302cdf0e10cSrcweir         break;
6303cdf0e10cSrcweir         case sal_Unicode('<'):
6304cdf0e10cSrcweir             rValue += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "&lt;" ) );
6305cdf0e10cSrcweir         break;
6306cdf0e10cSrcweir         case sal_Unicode('>'):
6307cdf0e10cSrcweir             rValue += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "&gt;" ) );
6308cdf0e10cSrcweir         break;
6309cdf0e10cSrcweir         case sal_Unicode('\''):
6310cdf0e10cSrcweir             rValue += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "&apos;" ) );
6311cdf0e10cSrcweir         break;
6312cdf0e10cSrcweir         case sal_Unicode('"'):
6313cdf0e10cSrcweir             rValue += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "&quot;" ) );
6314cdf0e10cSrcweir         break;
6315cdf0e10cSrcweir         default:
6316cdf0e10cSrcweir             rValue += rtl::OUString( *pUni );
6317cdf0e10cSrcweir             break;
6318cdf0e10cSrcweir         }
6319cdf0e10cSrcweir     }
6320cdf0e10cSrcweir }
6321cdf0e10cSrcweir 
6322cdf0e10cSrcweir // emits the document metadata
6323cdf0e10cSrcweir //
6324cdf0e10cSrcweir sal_Int32 PDFWriterImpl::emitDocumentMetadata()
6325cdf0e10cSrcweir {
6326cdf0e10cSrcweir     if( !m_bIsPDF_A1 )
6327cdf0e10cSrcweir         return 0;
6328cdf0e10cSrcweir 
6329cdf0e10cSrcweir     //get the object number for all the destinations
6330cdf0e10cSrcweir     sal_Int32 nObject = createObject();
6331cdf0e10cSrcweir 
6332cdf0e10cSrcweir     if( updateObject( nObject ) )
6333cdf0e10cSrcweir     {
6334cdf0e10cSrcweir // the following string are written in UTF-8 unicode
6335cdf0e10cSrcweir         OStringBuffer aMetadataStream( 8192 );
6336cdf0e10cSrcweir 
6337cdf0e10cSrcweir         aMetadataStream.append( "<?xpacket begin=\"" );
6338cdf0e10cSrcweir // this lines writes Unicode “zero width non-breaking space character” (U+FEFF) (aka byte-order mark ) used
6339cdf0e10cSrcweir // as a byte-order marker.
6340cdf0e10cSrcweir         aMetadataStream.append( OUStringToOString( OUString( sal_Unicode( 0xFEFF ) ), RTL_TEXTENCODING_UTF8 ) );
6341cdf0e10cSrcweir         aMetadataStream.append( "\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>\n" );
6342cdf0e10cSrcweir         aMetadataStream.append( "<x:xmpmeta xmlns:x=\"adobe:ns:meta/\">\n" );
6343cdf0e10cSrcweir         aMetadataStream.append( " <rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n" );
6344cdf0e10cSrcweir //PDF/A part ( ISO 19005-1:2005 - 6.7.11 )
6345cdf0e10cSrcweir         aMetadataStream.append( "  <rdf:Description rdf:about=\"\"\n" );
6346cdf0e10cSrcweir         aMetadataStream.append( "      xmlns:pdfaid=\"http://www.aiim.org/pdfa/ns/id/\">\n" );
6347cdf0e10cSrcweir         aMetadataStream.append( "   <pdfaid:part>1</pdfaid:part>\n" );
6348cdf0e10cSrcweir         aMetadataStream.append( "   <pdfaid:conformance>A</pdfaid:conformance>\n" );
6349cdf0e10cSrcweir         aMetadataStream.append( "  </rdf:Description>\n" );
6350cdf0e10cSrcweir //... Dublin Core properties go here
6351cdf0e10cSrcweir         if( m_aContext.DocumentInfo.Title.Len() ||
6352cdf0e10cSrcweir             m_aContext.DocumentInfo.Author.Len() ||
6353cdf0e10cSrcweir             m_aContext.DocumentInfo.Subject.Len() )
6354cdf0e10cSrcweir         {
6355cdf0e10cSrcweir             aMetadataStream.append( "  <rdf:Description rdf:about=\"\"\n" );
6356cdf0e10cSrcweir             aMetadataStream.append( "      xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n" );
6357cdf0e10cSrcweir             if( m_aContext.DocumentInfo.Title.Len() )
6358cdf0e10cSrcweir             {
6359cdf0e10cSrcweir // this is according to PDF/A-1, technical corrigendum 1 (2007-04-01)
6360cdf0e10cSrcweir                 aMetadataStream.append( "   <dc:title>\n" );
6361cdf0e10cSrcweir                 aMetadataStream.append( "    <rdf:Alt>\n" );
6362cdf0e10cSrcweir                 aMetadataStream.append( "     <rdf:li xml:lang=\"x-default\">" );
6363cdf0e10cSrcweir                 rtl::OUString aTitle;
6364cdf0e10cSrcweir                 escapeStringXML( m_aContext.DocumentInfo.Title, aTitle );
6365cdf0e10cSrcweir                 aMetadataStream.append( OUStringToOString( aTitle, RTL_TEXTENCODING_UTF8 )  );
6366cdf0e10cSrcweir                 aMetadataStream.append( "</rdf:li>\n" );
6367cdf0e10cSrcweir                 aMetadataStream.append( "    </rdf:Alt>\n" );
6368cdf0e10cSrcweir                 aMetadataStream.append( "   </dc:title>\n" );
6369cdf0e10cSrcweir             }
6370cdf0e10cSrcweir             if( m_aContext.DocumentInfo.Author.Len() )
6371cdf0e10cSrcweir             {
6372cdf0e10cSrcweir                 aMetadataStream.append( "   <dc:creator>\n" );
6373cdf0e10cSrcweir                 aMetadataStream.append( "    <rdf:Seq>\n" );
6374cdf0e10cSrcweir                 aMetadataStream.append( "     <rdf:li>" );
6375cdf0e10cSrcweir                 rtl::OUString aAuthor;
6376cdf0e10cSrcweir                 escapeStringXML( m_aContext.DocumentInfo.Author, aAuthor );
6377cdf0e10cSrcweir                 aMetadataStream.append( OUStringToOString( aAuthor , RTL_TEXTENCODING_UTF8 )  );
6378cdf0e10cSrcweir                 aMetadataStream.append( "</rdf:li>\n" );
6379cdf0e10cSrcweir                 aMetadataStream.append( "    </rdf:Seq>\n" );
6380cdf0e10cSrcweir                 aMetadataStream.append( "   </dc:creator>\n" );
6381cdf0e10cSrcweir             }
6382cdf0e10cSrcweir             if( m_aContext.DocumentInfo.Subject.Len() )
6383cdf0e10cSrcweir             {
6384cdf0e10cSrcweir // this is according to PDF/A-1, technical corrigendum 1 (2007-04-01)
6385cdf0e10cSrcweir                 aMetadataStream.append( "   <dc:description>\n" );
6386cdf0e10cSrcweir                 aMetadataStream.append( "    <rdf:Alt>\n" );
6387cdf0e10cSrcweir                 aMetadataStream.append( "     <rdf:li xml:lang=\"x-default\">" );
6388cdf0e10cSrcweir                 rtl::OUString aSubject;
6389cdf0e10cSrcweir                 escapeStringXML( m_aContext.DocumentInfo.Subject, aSubject );
6390cdf0e10cSrcweir                 aMetadataStream.append( OUStringToOString( aSubject , RTL_TEXTENCODING_UTF8 )  );
6391cdf0e10cSrcweir                 aMetadataStream.append( "</rdf:li>\n" );
6392cdf0e10cSrcweir                 aMetadataStream.append( "    </rdf:Alt>\n" );
6393cdf0e10cSrcweir                 aMetadataStream.append( "   </dc:description>\n" );
6394cdf0e10cSrcweir             }
6395cdf0e10cSrcweir             aMetadataStream.append( "  </rdf:Description>\n" );
6396cdf0e10cSrcweir         }
6397cdf0e10cSrcweir 
6398cdf0e10cSrcweir //... PDF properties go here
6399cdf0e10cSrcweir         if( m_aContext.DocumentInfo.Producer.Len() ||
6400cdf0e10cSrcweir             m_aContext.DocumentInfo.Keywords.Len() )
6401cdf0e10cSrcweir         {
6402cdf0e10cSrcweir             aMetadataStream.append( "  <rdf:Description rdf:about=\"\"\n" );
6403cdf0e10cSrcweir             aMetadataStream.append( "     xmlns:pdf=\"http://ns.adobe.com/pdf/1.3/\">\n" );
6404cdf0e10cSrcweir             if( m_aContext.DocumentInfo.Producer.Len() )
6405cdf0e10cSrcweir             {
6406cdf0e10cSrcweir                 aMetadataStream.append( "   <pdf:Producer>" );
6407cdf0e10cSrcweir                 rtl::OUString aProducer;
6408cdf0e10cSrcweir                 escapeStringXML( m_aContext.DocumentInfo.Producer, aProducer );
6409cdf0e10cSrcweir                 aMetadataStream.append( OUStringToOString( aProducer , RTL_TEXTENCODING_UTF8 )  );
6410cdf0e10cSrcweir                 aMetadataStream.append( "</pdf:Producer>\n" );
6411cdf0e10cSrcweir             }
6412cdf0e10cSrcweir             if( m_aContext.DocumentInfo.Keywords.Len() )
6413cdf0e10cSrcweir             {
6414cdf0e10cSrcweir                 aMetadataStream.append( "   <pdf:Keywords>" );
6415cdf0e10cSrcweir                 rtl::OUString aKeywords;
6416cdf0e10cSrcweir                 escapeStringXML( m_aContext.DocumentInfo.Keywords, aKeywords );
6417cdf0e10cSrcweir                 aMetadataStream.append( OUStringToOString( aKeywords , RTL_TEXTENCODING_UTF8 )  );
6418cdf0e10cSrcweir                 aMetadataStream.append( "</pdf:Keywords>\n" );
6419cdf0e10cSrcweir             }
6420cdf0e10cSrcweir             aMetadataStream.append( "  </rdf:Description>\n" );
6421cdf0e10cSrcweir         }
6422cdf0e10cSrcweir 
6423cdf0e10cSrcweir         aMetadataStream.append( "  <rdf:Description rdf:about=\"\"\n" );
6424cdf0e10cSrcweir         aMetadataStream.append( "    xmlns:xmp=\"http://ns.adobe.com/xap/1.0/\">\n" );
6425cdf0e10cSrcweir         if( m_aContext.DocumentInfo.Creator.Len() )
6426cdf0e10cSrcweir         {
6427cdf0e10cSrcweir             aMetadataStream.append( "   <xmp:CreatorTool>" );
6428cdf0e10cSrcweir             rtl::OUString aCreator;
6429cdf0e10cSrcweir             escapeStringXML( m_aContext.DocumentInfo.Creator, aCreator );
6430cdf0e10cSrcweir             aMetadataStream.append( OUStringToOString( aCreator , RTL_TEXTENCODING_UTF8 )  );
6431cdf0e10cSrcweir             aMetadataStream.append( "</xmp:CreatorTool>\n" );
6432cdf0e10cSrcweir         }
6433cdf0e10cSrcweir //creation date
6434cdf0e10cSrcweir         aMetadataStream.append( "   <xmp:CreateDate>" );
6435cdf0e10cSrcweir         aMetadataStream.append( m_aCreationMetaDateString );
6436cdf0e10cSrcweir         aMetadataStream.append( "</xmp:CreateDate>\n" );
6437cdf0e10cSrcweir 
6438cdf0e10cSrcweir         aMetadataStream.append( "  </rdf:Description>\n" );
6439cdf0e10cSrcweir         aMetadataStream.append( " </rdf:RDF>\n" );
6440cdf0e10cSrcweir         aMetadataStream.append( "</x:xmpmeta>\n" );
6441cdf0e10cSrcweir 
6442cdf0e10cSrcweir //add the padding
6443cdf0e10cSrcweir         for( sal_Int32 nSpaces = 1; nSpaces <= 2100; nSpaces++ )
6444cdf0e10cSrcweir         {
6445cdf0e10cSrcweir             aMetadataStream.append( " " );
6446cdf0e10cSrcweir             if( nSpaces % 100 == 0 )
6447cdf0e10cSrcweir                 aMetadataStream.append( "\n" );
6448cdf0e10cSrcweir         }
6449cdf0e10cSrcweir 
6450cdf0e10cSrcweir         aMetadataStream.append( "<?xpacket end=\"w\"?>\n" );
6451cdf0e10cSrcweir 
6452cdf0e10cSrcweir         OStringBuffer aMetadataObj( 1024 );
6453cdf0e10cSrcweir 
6454cdf0e10cSrcweir         aMetadataObj.append( nObject );
6455cdf0e10cSrcweir         aMetadataObj.append( " 0 obj\n" );
6456cdf0e10cSrcweir 
6457cdf0e10cSrcweir         aMetadataObj.append( "<</Type/Metadata/Subtype/XML/Length " );
6458cdf0e10cSrcweir 
6459cdf0e10cSrcweir         aMetadataObj.append( (sal_Int32) aMetadataStream.getLength() );
6460cdf0e10cSrcweir         aMetadataObj.append( ">>\nstream\n" );
6461cdf0e10cSrcweir         CHECK_RETURN( writeBuffer( aMetadataObj.getStr(), aMetadataObj.getLength() ) );
6462cdf0e10cSrcweir //emit the stream
6463cdf0e10cSrcweir         CHECK_RETURN( writeBuffer( aMetadataStream.getStr(), aMetadataStream.getLength() ) );
6464cdf0e10cSrcweir 
6465cdf0e10cSrcweir         aMetadataObj.setLength( 0 );
6466cdf0e10cSrcweir         aMetadataObj.append( "\nendstream\nendobj\n\n" );
6467cdf0e10cSrcweir         if( ! writeBuffer( aMetadataObj.getStr(), aMetadataObj.getLength() ) )
6468cdf0e10cSrcweir             nObject = 0;
6469cdf0e10cSrcweir     }
6470cdf0e10cSrcweir     else
6471cdf0e10cSrcweir         nObject = 0;
6472cdf0e10cSrcweir 
6473cdf0e10cSrcweir     return nObject;
6474cdf0e10cSrcweir }
6475cdf0e10cSrcweir //<---i59651
6476cdf0e10cSrcweir 
6477cdf0e10cSrcweir bool PDFWriterImpl::emitTrailer()
6478cdf0e10cSrcweir {
6479cdf0e10cSrcweir     // emit doc info
6480cdf0e10cSrcweir     OString aInfoValuesOut;
6481cdf0e10cSrcweir     sal_Int32 nDocInfoObject = emitInfoDict( );
6482cdf0e10cSrcweir 
6483cdf0e10cSrcweir     sal_Int32 nSecObject = 0;
6484cdf0e10cSrcweir 
6485cdf0e10cSrcweir 	if( m_aContext.Encryption.Encrypt() )
6486cdf0e10cSrcweir 	{
6487cdf0e10cSrcweir //emit the security information
6488cdf0e10cSrcweir //must be emitted as indirect dictionary object, since
6489cdf0e10cSrcweir //Acrobat Reader 5 works only with this kind of implementation
6490cdf0e10cSrcweir 		nSecObject = createObject();
6491cdf0e10cSrcweir 
6492cdf0e10cSrcweir 		if( updateObject( nSecObject ) )
6493cdf0e10cSrcweir 		{
6494cdf0e10cSrcweir 			OStringBuffer aLineS( 1024 );
6495cdf0e10cSrcweir 			aLineS.append( nSecObject );
6496cdf0e10cSrcweir 			aLineS.append( " 0 obj\n"
6497cdf0e10cSrcweir 						   "<</Filter/Standard/V " );
6498cdf0e10cSrcweir 			// check the version
6499cdf0e10cSrcweir 			if( m_aContext.Encryption.Security128bit )
6500cdf0e10cSrcweir 				aLineS.append( "2/Length 128/R 3" );
6501cdf0e10cSrcweir 			else
6502cdf0e10cSrcweir 				aLineS.append( "1/R 2" );
6503cdf0e10cSrcweir 
6504cdf0e10cSrcweir 			// emit the owner password, must not be encrypted
6505cdf0e10cSrcweir 			aLineS.append( "/O(" );
6506cdf0e10cSrcweir 			appendLiteralString( (const sal_Char*)&m_aContext.Encryption.OValue[0], sal_Int32(m_aContext.Encryption.OValue.size()), aLineS );
6507cdf0e10cSrcweir 			aLineS.append( ")/U(" );
6508cdf0e10cSrcweir 			appendLiteralString( (const sal_Char*)&m_aContext.Encryption.UValue[0], sal_Int32(m_aContext.Encryption.UValue.size()), aLineS );
6509cdf0e10cSrcweir 			aLineS.append( ")/P " );// the permission set
6510cdf0e10cSrcweir 			aLineS.append( m_nAccessPermissions );
6511cdf0e10cSrcweir 			aLineS.append( ">>\nendobj\n\n" );
6512cdf0e10cSrcweir 			if( !writeBuffer( aLineS.getStr(), aLineS.getLength() ) )
6513cdf0e10cSrcweir 				nSecObject = 0;
6514cdf0e10cSrcweir 		}
6515cdf0e10cSrcweir 		else
6516cdf0e10cSrcweir 			nSecObject = 0;
6517cdf0e10cSrcweir 	}
6518cdf0e10cSrcweir     // emit xref table
6519cdf0e10cSrcweir     // remember start
6520cdf0e10cSrcweir     sal_uInt64 nXRefOffset = 0;
6521cdf0e10cSrcweir     CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nXRefOffset )) );
6522cdf0e10cSrcweir     CHECK_RETURN( writeBuffer( "xref\n", 5 ) );
6523cdf0e10cSrcweir 
6524cdf0e10cSrcweir     sal_Int32 nObjects = m_aObjects.size();
6525cdf0e10cSrcweir     OStringBuffer aLine;
6526cdf0e10cSrcweir     aLine.append( "0 " );
6527cdf0e10cSrcweir     aLine.append( (sal_Int32)(nObjects+1) );
6528cdf0e10cSrcweir     aLine.append( "\n" );
6529cdf0e10cSrcweir     aLine.append( "0000000000 65535 f \n" );
6530cdf0e10cSrcweir     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
6531cdf0e10cSrcweir 
6532cdf0e10cSrcweir     for( sal_Int32 i = 0; i < nObjects; i++ )
6533cdf0e10cSrcweir     {
6534cdf0e10cSrcweir         aLine.setLength( 0 );
6535cdf0e10cSrcweir         OString aOffset = OString::valueOf( (sal_Int64)m_aObjects[i] );
6536cdf0e10cSrcweir         for( sal_Int32 j = 0; j < (10-aOffset.getLength()); j++ )
6537cdf0e10cSrcweir             aLine.append( '0' );
6538cdf0e10cSrcweir         aLine.append( aOffset );
6539cdf0e10cSrcweir         aLine.append( " 00000 n \n" );
6540cdf0e10cSrcweir         DBG_ASSERT( aLine.getLength() == 20, "invalid xref entry" );
6541cdf0e10cSrcweir         CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
6542cdf0e10cSrcweir     }
6543cdf0e10cSrcweir 
6544cdf0e10cSrcweir     // prepare document checksum
6545cdf0e10cSrcweir     OStringBuffer aDocChecksum( 2*RTL_DIGEST_LENGTH_MD5+1 );
6546cdf0e10cSrcweir     if( m_aDocDigest )
6547cdf0e10cSrcweir     {
6548cdf0e10cSrcweir         sal_uInt8 nMD5Sum[ RTL_DIGEST_LENGTH_MD5 ];
6549cdf0e10cSrcweir         rtl_digest_getMD5( m_aDocDigest, nMD5Sum, sizeof(nMD5Sum) );
6550cdf0e10cSrcweir         for( unsigned int i = 0; i < RTL_DIGEST_LENGTH_MD5; i++ )
6551cdf0e10cSrcweir             appendHex( nMD5Sum[i], aDocChecksum );
6552cdf0e10cSrcweir     }
6553cdf0e10cSrcweir     // document id set in setDocInfo method
6554cdf0e10cSrcweir     // emit trailer
6555cdf0e10cSrcweir     aLine.setLength( 0 );
6556cdf0e10cSrcweir     aLine.append( "trailer\n"
6557cdf0e10cSrcweir                   "<</Size " );
6558cdf0e10cSrcweir     aLine.append( (sal_Int32)(nObjects+1) );
6559cdf0e10cSrcweir     aLine.append( "/Root " );
6560cdf0e10cSrcweir     aLine.append( m_nCatalogObject );
6561cdf0e10cSrcweir     aLine.append( " 0 R\n" );
6562cdf0e10cSrcweir     if( nSecObject |= 0 )
6563cdf0e10cSrcweir     {
6564cdf0e10cSrcweir         aLine.append( "/Encrypt ");
6565cdf0e10cSrcweir         aLine.append( nSecObject );
6566cdf0e10cSrcweir         aLine.append( " 0 R\n" );
6567cdf0e10cSrcweir     }
6568cdf0e10cSrcweir     if( nDocInfoObject )
6569cdf0e10cSrcweir     {
6570cdf0e10cSrcweir         aLine.append( "/Info " );
6571cdf0e10cSrcweir         aLine.append( nDocInfoObject );
6572cdf0e10cSrcweir         aLine.append( " 0 R\n" );
6573cdf0e10cSrcweir     }
6574cdf0e10cSrcweir     if( ! m_aContext.Encryption.DocumentIdentifier.empty() )
6575cdf0e10cSrcweir     {
6576cdf0e10cSrcweir         aLine.append( "/ID [ <" );
6577cdf0e10cSrcweir         for( std::vector< sal_uInt8 >::const_iterator it = m_aContext.Encryption.DocumentIdentifier.begin();
6578cdf0e10cSrcweir              it != m_aContext.Encryption.DocumentIdentifier.end(); ++it )
6579cdf0e10cSrcweir         {
6580cdf0e10cSrcweir             appendHex( sal_Int8(*it), aLine );
6581cdf0e10cSrcweir         }
6582cdf0e10cSrcweir         aLine.append( ">\n"
6583cdf0e10cSrcweir                       "<" );
6584cdf0e10cSrcweir         for( std::vector< sal_uInt8 >::const_iterator it = m_aContext.Encryption.DocumentIdentifier.begin();
6585cdf0e10cSrcweir              it != m_aContext.Encryption.DocumentIdentifier.end(); ++it )
6586cdf0e10cSrcweir         {
6587cdf0e10cSrcweir             appendHex( sal_Int8(*it), aLine );
6588cdf0e10cSrcweir         }
6589cdf0e10cSrcweir         aLine.append( "> ]\n" );
6590cdf0e10cSrcweir     }
6591cdf0e10cSrcweir     if( aDocChecksum.getLength() )
6592cdf0e10cSrcweir     {
6593cdf0e10cSrcweir         aLine.append( "/DocChecksum /" );
6594cdf0e10cSrcweir         aLine.append( aDocChecksum );
6595cdf0e10cSrcweir         aLine.append( "\n" );
6596cdf0e10cSrcweir     }
6597cdf0e10cSrcweir     if( m_aAdditionalStreams.size() > 0 )
6598cdf0e10cSrcweir     {
6599cdf0e10cSrcweir         aLine.append( "/AdditionalStreams [" );
6600cdf0e10cSrcweir         for( unsigned int i = 0; i < m_aAdditionalStreams.size(); i++ )
6601cdf0e10cSrcweir         {
6602cdf0e10cSrcweir             aLine.append( "/" );
6603cdf0e10cSrcweir             appendName( m_aAdditionalStreams[i].m_aMimeType, aLine );
6604cdf0e10cSrcweir             aLine.append( " " );
6605cdf0e10cSrcweir             aLine.append( m_aAdditionalStreams[i].m_nStreamObject );
6606cdf0e10cSrcweir             aLine.append( " 0 R\n" );
6607cdf0e10cSrcweir         }
6608cdf0e10cSrcweir         aLine.append( "]\n" );
6609cdf0e10cSrcweir     }
6610cdf0e10cSrcweir     aLine.append( ">>\n"
6611cdf0e10cSrcweir                   "startxref\n" );
6612cdf0e10cSrcweir     aLine.append( (sal_Int64)nXRefOffset );
6613cdf0e10cSrcweir     aLine.append( "\n"
6614cdf0e10cSrcweir                   "%%EOF\n" );
6615cdf0e10cSrcweir     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
6616cdf0e10cSrcweir 
6617cdf0e10cSrcweir     return true;
6618cdf0e10cSrcweir }
6619cdf0e10cSrcweir 
6620cdf0e10cSrcweir struct AnnotationSortEntry
6621cdf0e10cSrcweir {
6622cdf0e10cSrcweir     sal_Int32 nTabOrder;
6623cdf0e10cSrcweir     sal_Int32 nObject;
6624cdf0e10cSrcweir     sal_Int32 nWidgetIndex;
6625cdf0e10cSrcweir 
6626cdf0e10cSrcweir     AnnotationSortEntry( sal_Int32 nTab, sal_Int32 nObj, sal_Int32 nI ) :
6627cdf0e10cSrcweir         nTabOrder( nTab ),
6628cdf0e10cSrcweir         nObject( nObj ),
6629cdf0e10cSrcweir         nWidgetIndex( nI )
6630cdf0e10cSrcweir     {}
6631cdf0e10cSrcweir };
6632cdf0e10cSrcweir 
6633cdf0e10cSrcweir struct AnnotSortContainer
6634cdf0e10cSrcweir {
6635cdf0e10cSrcweir     std::set< sal_Int32 >               aObjects;
6636cdf0e10cSrcweir     std::vector< AnnotationSortEntry >    aSortedAnnots;
6637cdf0e10cSrcweir };
6638cdf0e10cSrcweir 
6639cdf0e10cSrcweir struct AnnotSorterLess
6640cdf0e10cSrcweir {
6641cdf0e10cSrcweir     std::vector< PDFWriterImpl::PDFWidget >& m_rWidgets;
6642cdf0e10cSrcweir 
6643cdf0e10cSrcweir     AnnotSorterLess( std::vector< PDFWriterImpl::PDFWidget >& rWidgets ) : m_rWidgets( rWidgets ) {}
6644cdf0e10cSrcweir 
6645cdf0e10cSrcweir     bool operator()( const AnnotationSortEntry& rLeft, const AnnotationSortEntry& rRight )
6646cdf0e10cSrcweir     {
6647cdf0e10cSrcweir         if( rLeft.nTabOrder < rRight.nTabOrder )
6648cdf0e10cSrcweir             return true;
6649cdf0e10cSrcweir         if( rRight.nTabOrder < rLeft.nTabOrder )
6650cdf0e10cSrcweir             return false;
6651cdf0e10cSrcweir         if( rLeft.nWidgetIndex < 0 && rRight.nWidgetIndex < 0 )
6652cdf0e10cSrcweir             return false;
6653cdf0e10cSrcweir         if( rRight.nWidgetIndex < 0 )
6654cdf0e10cSrcweir             return true;
6655cdf0e10cSrcweir         if( rLeft.nWidgetIndex < 0 )
6656cdf0e10cSrcweir             return false;
6657cdf0e10cSrcweir         // remember: widget rects are in PDF coordinates, so they are ordered down up
6658cdf0e10cSrcweir         if( m_rWidgets[ rLeft.nWidgetIndex ].m_aRect.Top() >
6659cdf0e10cSrcweir             m_rWidgets[ rRight.nWidgetIndex ].m_aRect.Top() )
6660cdf0e10cSrcweir             return true;
6661cdf0e10cSrcweir         if( m_rWidgets[ rRight.nWidgetIndex ].m_aRect.Top() >
6662cdf0e10cSrcweir             m_rWidgets[ rLeft.nWidgetIndex ].m_aRect.Top() )
6663cdf0e10cSrcweir             return false;
6664cdf0e10cSrcweir         if( m_rWidgets[ rLeft.nWidgetIndex ].m_aRect.Left() <
6665cdf0e10cSrcweir             m_rWidgets[ rRight.nWidgetIndex ].m_aRect.Left() )
6666cdf0e10cSrcweir             return true;
6667cdf0e10cSrcweir         return false;
6668cdf0e10cSrcweir     }
6669cdf0e10cSrcweir };
6670cdf0e10cSrcweir 
6671cdf0e10cSrcweir void PDFWriterImpl::sortWidgets()
6672cdf0e10cSrcweir {
6673cdf0e10cSrcweir     // sort widget annotations on each page as per their
6674cdf0e10cSrcweir     // TabOrder attribute
6675cdf0e10cSrcweir     std::hash_map< sal_Int32, AnnotSortContainer > sorted;
6676cdf0e10cSrcweir     int nWidgets = m_aWidgets.size();
6677cdf0e10cSrcweir     for( int nW = 0; nW < nWidgets; nW++ )
6678cdf0e10cSrcweir     {
6679cdf0e10cSrcweir         const PDFWidget& rWidget = m_aWidgets[nW];
6680cdf0e10cSrcweir         if( rWidget.m_nPage >= 0 )
6681cdf0e10cSrcweir         {
6682cdf0e10cSrcweir             AnnotSortContainer& rCont = sorted[ rWidget.m_nPage ];
6683cdf0e10cSrcweir             // optimize vector allocation
6684cdf0e10cSrcweir             if( rCont.aSortedAnnots.empty() )
6685cdf0e10cSrcweir                 rCont.aSortedAnnots.reserve( m_aPages[ rWidget.m_nPage ].m_aAnnotations.size() );
6686cdf0e10cSrcweir             // insert widget to tab sorter
6687cdf0e10cSrcweir             // RadioButtons are not page annotations, only their individual check boxes are
6688cdf0e10cSrcweir             if( rWidget.m_eType != PDFWriter::RadioButton )
6689cdf0e10cSrcweir             {
6690cdf0e10cSrcweir                 rCont.aObjects.insert( rWidget.m_nObject );
6691cdf0e10cSrcweir                 rCont.aSortedAnnots.push_back( AnnotationSortEntry( rWidget.m_nTabOrder, rWidget.m_nObject, nW ) );
6692cdf0e10cSrcweir             }
6693cdf0e10cSrcweir         }
6694cdf0e10cSrcweir     }
6695cdf0e10cSrcweir     for( std::hash_map< sal_Int32, AnnotSortContainer >::iterator it = sorted.begin(); it != sorted.end(); ++it )
6696cdf0e10cSrcweir     {
6697cdf0e10cSrcweir         // append entries for non widget annotations
6698cdf0e10cSrcweir         PDFPage& rPage = m_aPages[ it->first ];
6699cdf0e10cSrcweir         unsigned int nAnnots = rPage.m_aAnnotations.size();
6700cdf0e10cSrcweir         for( unsigned int nA = 0; nA < nAnnots; nA++ )
6701cdf0e10cSrcweir             if( it->second.aObjects.find( rPage.m_aAnnotations[nA] ) == it->second.aObjects.end())
6702cdf0e10cSrcweir                 it->second.aSortedAnnots.push_back( AnnotationSortEntry( 10000, rPage.m_aAnnotations[nA], -1 ) );
6703cdf0e10cSrcweir 
6704cdf0e10cSrcweir         AnnotSorterLess aLess( m_aWidgets );
6705cdf0e10cSrcweir         std::stable_sort( it->second.aSortedAnnots.begin(), it->second.aSortedAnnots.end(), aLess );
6706cdf0e10cSrcweir         // sanity check
6707cdf0e10cSrcweir         if( it->second.aSortedAnnots.size() == nAnnots)
6708cdf0e10cSrcweir         {
6709cdf0e10cSrcweir             for( unsigned int nA = 0; nA < nAnnots; nA++ )
6710cdf0e10cSrcweir                 rPage.m_aAnnotations[nA] = it->second.aSortedAnnots[nA].nObject;
6711cdf0e10cSrcweir         }
6712cdf0e10cSrcweir         else
6713cdf0e10cSrcweir         {
6714cdf0e10cSrcweir             DBG_ASSERT( 0, "wrong number of sorted annotations" );
6715cdf0e10cSrcweir             #if OSL_DEBUG_LEVEL > 0
6716cdf0e10cSrcweir             fprintf( stderr, "PDFWriterImpl::sortWidgets(): wrong number of sorted assertions on page nr %ld\n"
6717cdf0e10cSrcweir 					 "    %ld sorted and %ld unsorted\n", (long int)it->first, (long int)it->second.aSortedAnnots.size(), (long int)nAnnots );
6718cdf0e10cSrcweir             #endif
6719cdf0e10cSrcweir         }
6720cdf0e10cSrcweir     }
6721cdf0e10cSrcweir 
6722cdf0e10cSrcweir     // FIXME: implement tab order in structure tree for PDF 1.5
6723cdf0e10cSrcweir }
6724cdf0e10cSrcweir 
6725cdf0e10cSrcweir namespace vcl {
6726cdf0e10cSrcweir class PDFStreamIf :
6727cdf0e10cSrcweir 		public cppu::WeakImplHelper1< com::sun::star::io::XOutputStream	>
6728cdf0e10cSrcweir {
6729cdf0e10cSrcweir     PDFWriterImpl*  m_pWriter;
6730cdf0e10cSrcweir     bool            m_bWrite;
6731cdf0e10cSrcweir     public:
6732cdf0e10cSrcweir     PDFStreamIf( PDFWriterImpl* pWriter ) : m_pWriter( pWriter ), m_bWrite( true ) {}
6733cdf0e10cSrcweir     virtual ~PDFStreamIf();
6734cdf0e10cSrcweir 
6735cdf0e10cSrcweir     virtual void SAL_CALL writeBytes( const com::sun::star::uno::Sequence< sal_Int8 >& aData ) throw();
6736cdf0e10cSrcweir     virtual void SAL_CALL flush() throw();
6737cdf0e10cSrcweir     virtual void SAL_CALL closeOutput() throw();
6738cdf0e10cSrcweir };
6739cdf0e10cSrcweir }
6740cdf0e10cSrcweir 
6741cdf0e10cSrcweir PDFStreamIf::~PDFStreamIf()
6742cdf0e10cSrcweir {
6743cdf0e10cSrcweir }
6744cdf0e10cSrcweir 
6745cdf0e10cSrcweir void SAL_CALL  PDFStreamIf::writeBytes( const com::sun::star::uno::Sequence< sal_Int8 >& aData ) throw()
6746cdf0e10cSrcweir {
6747cdf0e10cSrcweir     if( m_bWrite )
6748cdf0e10cSrcweir     {
6749cdf0e10cSrcweir         sal_Int32 nBytes = aData.getLength();
6750cdf0e10cSrcweir         if( nBytes > 0 )
6751cdf0e10cSrcweir             m_pWriter->writeBuffer( aData.getConstArray(), nBytes );
6752cdf0e10cSrcweir     }
6753cdf0e10cSrcweir }
6754cdf0e10cSrcweir 
6755cdf0e10cSrcweir void SAL_CALL PDFStreamIf::flush() throw()
6756cdf0e10cSrcweir {
6757cdf0e10cSrcweir }
6758cdf0e10cSrcweir 
6759cdf0e10cSrcweir void SAL_CALL PDFStreamIf::closeOutput() throw()
6760cdf0e10cSrcweir {
6761cdf0e10cSrcweir     m_bWrite = false;
6762cdf0e10cSrcweir }
6763cdf0e10cSrcweir 
6764cdf0e10cSrcweir bool PDFWriterImpl::emitAdditionalStreams()
6765cdf0e10cSrcweir {
6766cdf0e10cSrcweir     unsigned int nStreams = m_aAdditionalStreams.size();
6767cdf0e10cSrcweir     for( unsigned int i = 0; i < nStreams; i++ )
6768cdf0e10cSrcweir     {
6769cdf0e10cSrcweir         PDFAddStream& rStream = m_aAdditionalStreams[i];
6770cdf0e10cSrcweir         rStream.m_nStreamObject = createObject();
6771cdf0e10cSrcweir         sal_Int32 nSizeObject = createObject();
6772cdf0e10cSrcweir 
6773cdf0e10cSrcweir         if( ! updateObject( rStream.m_nStreamObject ) )
6774cdf0e10cSrcweir             return false;
6775cdf0e10cSrcweir 
6776cdf0e10cSrcweir         OStringBuffer aLine;
6777cdf0e10cSrcweir         aLine.append( rStream.m_nStreamObject );
6778cdf0e10cSrcweir         aLine.append( " 0 obj\n<</Length " );
6779cdf0e10cSrcweir         aLine.append( nSizeObject );
6780cdf0e10cSrcweir         aLine.append( " 0 R" );
6781cdf0e10cSrcweir         if( rStream.m_bCompress )
6782cdf0e10cSrcweir             aLine.append( "/Filter/FlateDecode" );
6783cdf0e10cSrcweir         aLine.append( ">>\nstream\n" );
6784cdf0e10cSrcweir         if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) )
6785cdf0e10cSrcweir             return false;
6786cdf0e10cSrcweir         sal_uInt64 nBeginStreamPos = 0, nEndStreamPos = 0;
6787cdf0e10cSrcweir         if( osl_File_E_None != osl_getFilePos( m_aFile, &nBeginStreamPos ) )
6788cdf0e10cSrcweir         {
6789cdf0e10cSrcweir             osl_closeFile( m_aFile );
6790cdf0e10cSrcweir             m_bOpen = false;
6791cdf0e10cSrcweir         }
6792cdf0e10cSrcweir         if( rStream.m_bCompress )
6793cdf0e10cSrcweir             beginCompression();
6794cdf0e10cSrcweir 
6795cdf0e10cSrcweir         checkAndEnableStreamEncryption( rStream.m_nStreamObject );
6796cdf0e10cSrcweir         com::sun::star::uno::Reference< com::sun::star::io::XOutputStream > xStream( new PDFStreamIf( this ) );
6797cdf0e10cSrcweir         rStream.m_pStream->write( xStream );
6798cdf0e10cSrcweir         xStream.clear();
6799cdf0e10cSrcweir         delete rStream.m_pStream;
6800cdf0e10cSrcweir         rStream.m_pStream = NULL;
6801cdf0e10cSrcweir         disableStreamEncryption();
6802cdf0e10cSrcweir 
6803cdf0e10cSrcweir         if( rStream.m_bCompress )
6804cdf0e10cSrcweir             endCompression();
6805cdf0e10cSrcweir 
6806cdf0e10cSrcweir         if( osl_File_E_None != osl_getFilePos( m_aFile, &nEndStreamPos ) )
6807cdf0e10cSrcweir         {
6808cdf0e10cSrcweir             osl_closeFile( m_aFile );
6809cdf0e10cSrcweir             m_bOpen = false;
6810cdf0e10cSrcweir             return false;
6811cdf0e10cSrcweir         }
6812cdf0e10cSrcweir         if( ! writeBuffer( "\nendstream\nendobj\n\n", 19 ) )
6813cdf0e10cSrcweir             return false ;
6814cdf0e10cSrcweir         // emit stream length object
6815cdf0e10cSrcweir         if( ! updateObject( nSizeObject ) )
6816cdf0e10cSrcweir             return false;
6817cdf0e10cSrcweir         aLine.setLength( 0 );
6818cdf0e10cSrcweir         aLine.append( nSizeObject );
6819cdf0e10cSrcweir         aLine.append( " 0 obj\n" );
6820cdf0e10cSrcweir         aLine.append( (sal_Int64)(nEndStreamPos-nBeginStreamPos) );
6821cdf0e10cSrcweir         aLine.append( "\nendobj\n\n" );
6822cdf0e10cSrcweir         if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) )
6823cdf0e10cSrcweir             return false;
6824cdf0e10cSrcweir     }
6825cdf0e10cSrcweir     return true;
6826cdf0e10cSrcweir }
6827cdf0e10cSrcweir 
6828cdf0e10cSrcweir bool PDFWriterImpl::emit()
6829cdf0e10cSrcweir {
6830cdf0e10cSrcweir     endPage();
6831cdf0e10cSrcweir 
6832cdf0e10cSrcweir     // resort structure tree and annotations if necessary
6833cdf0e10cSrcweir     // needed for widget tab order
6834cdf0e10cSrcweir     sortWidgets();
6835cdf0e10cSrcweir 
6836cdf0e10cSrcweir     // emit additional streams
6837cdf0e10cSrcweir     CHECK_RETURN( emitAdditionalStreams() );
6838cdf0e10cSrcweir 
6839cdf0e10cSrcweir     // emit catalog
6840cdf0e10cSrcweir     CHECK_RETURN( emitCatalog() );
6841cdf0e10cSrcweir 
6842cdf0e10cSrcweir     // emit trailer
6843cdf0e10cSrcweir     CHECK_RETURN( emitTrailer() );
6844cdf0e10cSrcweir 
6845cdf0e10cSrcweir     osl_closeFile( m_aFile );
6846cdf0e10cSrcweir     m_bOpen = false;
6847cdf0e10cSrcweir 
6848cdf0e10cSrcweir     return true;
6849cdf0e10cSrcweir }
6850cdf0e10cSrcweir 
6851cdf0e10cSrcweir std::set< PDFWriter::ErrorCode > PDFWriterImpl::getErrors()
6852cdf0e10cSrcweir {
6853cdf0e10cSrcweir     return m_aErrors;
6854cdf0e10cSrcweir }
6855cdf0e10cSrcweir 
6856cdf0e10cSrcweir sal_Int32 PDFWriterImpl::getSystemFont( const Font& i_rFont )
6857cdf0e10cSrcweir {
6858cdf0e10cSrcweir     getReferenceDevice()->Push();
6859cdf0e10cSrcweir     getReferenceDevice()->SetFont( i_rFont );
6860cdf0e10cSrcweir     getReferenceDevice()->ImplNewFont();
6861cdf0e10cSrcweir 
6862cdf0e10cSrcweir     const ImplFontData* pDevFont = m_pReferenceDevice->mpFontEntry->maFontSelData.mpFontData;
6863cdf0e10cSrcweir     sal_Int32 nFontID = 0;
6864cdf0e10cSrcweir     FontEmbedData::iterator it = m_aSystemFonts.find( pDevFont );
6865cdf0e10cSrcweir     if( it != m_aSystemFonts.end() )
6866cdf0e10cSrcweir         nFontID = it->second.m_nNormalFontID;
6867cdf0e10cSrcweir     else
6868cdf0e10cSrcweir     {
6869cdf0e10cSrcweir         nFontID = m_nNextFID++;
6870cdf0e10cSrcweir         m_aSystemFonts[ pDevFont ] = EmbedFont();
6871cdf0e10cSrcweir         m_aSystemFonts[ pDevFont ].m_nNormalFontID = nFontID;
6872cdf0e10cSrcweir     }
6873cdf0e10cSrcweir 
6874cdf0e10cSrcweir     getReferenceDevice()->Pop();
6875cdf0e10cSrcweir     getReferenceDevice()->ImplNewFont();
6876cdf0e10cSrcweir 
6877cdf0e10cSrcweir     return nFontID;
6878cdf0e10cSrcweir }
6879cdf0e10cSrcweir 
6880cdf0e10cSrcweir void PDFWriterImpl::registerGlyphs( int nGlyphs,
6881cdf0e10cSrcweir                                     sal_GlyphId* pGlyphs,
6882cdf0e10cSrcweir                                     sal_Int32* pGlyphWidths,
6883cdf0e10cSrcweir                                     sal_Ucs* pUnicodes,
6884cdf0e10cSrcweir                                     sal_Int32* pUnicodesPerGlyph,
6885cdf0e10cSrcweir                                     sal_uInt8* pMappedGlyphs,
6886cdf0e10cSrcweir                                     sal_Int32* pMappedFontObjects,
6887cdf0e10cSrcweir                                     const ImplFontData* pFallbackFonts[] )
6888cdf0e10cSrcweir {
6889cdf0e10cSrcweir     const ImplFontData* pDevFont = m_pReferenceDevice->mpFontEntry->maFontSelData.mpFontData;
6890cdf0e10cSrcweir     sal_Ucs* pCurUnicode = pUnicodes;
6891cdf0e10cSrcweir     for( int i = 0; i < nGlyphs; pCurUnicode += pUnicodesPerGlyph[i] , i++ )
6892cdf0e10cSrcweir     {
6893cdf0e10cSrcweir         const int nFontGlyphId = pGlyphs[i] & (GF_IDXMASK | GF_ISCHAR | GF_GSUB);
6894cdf0e10cSrcweir         const ImplFontData* pCurrentFont = pFallbackFonts[i] ? pFallbackFonts[i] : pDevFont;
6895cdf0e10cSrcweir 
6896cdf0e10cSrcweir         if( isBuiltinFont( pCurrentFont ) )
6897cdf0e10cSrcweir         {
6898cdf0e10cSrcweir             sal_Int32 nFontID = 0;
6899cdf0e10cSrcweir             FontEmbedData::iterator it = m_aEmbeddedFonts.find( pCurrentFont );
6900cdf0e10cSrcweir             if( it != m_aEmbeddedFonts.end() )
6901cdf0e10cSrcweir                 nFontID = it->second.m_nNormalFontID;
6902cdf0e10cSrcweir             else
6903cdf0e10cSrcweir             {
6904cdf0e10cSrcweir                 nFontID = m_nNextFID++;
6905cdf0e10cSrcweir                 m_aEmbeddedFonts[ pCurrentFont ] = EmbedFont();
6906cdf0e10cSrcweir                 m_aEmbeddedFonts[ pCurrentFont ].m_nNormalFontID = nFontID;
6907cdf0e10cSrcweir             }
6908cdf0e10cSrcweir 
6909cdf0e10cSrcweir             pGlyphWidths[ i ] = 0;
6910cdf0e10cSrcweir             pMappedGlyphs[ i ] = sal::static_int_cast<sal_Int8>( nFontGlyphId );
6911cdf0e10cSrcweir             pMappedFontObjects[ i ] = nFontID;
6912cdf0e10cSrcweir             const ImplPdfBuiltinFontData* pFD = GetPdfFontData( pCurrentFont );
6913cdf0e10cSrcweir             if( pFD )
6914cdf0e10cSrcweir             {
6915cdf0e10cSrcweir                 const BuiltinFont* pBuiltinFont = pFD->GetBuiltinFont();
6916cdf0e10cSrcweir                 pGlyphWidths[i] = pBuiltinFont->m_aWidths[ nFontGlyphId & 0x00ff ];
6917cdf0e10cSrcweir             }
6918cdf0e10cSrcweir         }
6919cdf0e10cSrcweir         else if( pCurrentFont->mbSubsettable )
6920cdf0e10cSrcweir         {
6921cdf0e10cSrcweir             FontSubset& rSubset = m_aSubsets[ pCurrentFont ];
6922cdf0e10cSrcweir             // search for font specific glyphID
6923cdf0e10cSrcweir             FontMapping::iterator it = rSubset.m_aMapping.find( nFontGlyphId );
6924cdf0e10cSrcweir             if( it != rSubset.m_aMapping.end() )
6925cdf0e10cSrcweir             {
6926cdf0e10cSrcweir                 pMappedFontObjects[i] = it->second.m_nFontID;
6927cdf0e10cSrcweir                 pMappedGlyphs[i] = it->second.m_nSubsetGlyphID;
6928cdf0e10cSrcweir             }
6929cdf0e10cSrcweir             else
6930cdf0e10cSrcweir             {
6931cdf0e10cSrcweir                 // create new subset if necessary
6932cdf0e10cSrcweir                 if( rSubset.m_aSubsets.empty()
6933cdf0e10cSrcweir                 || (rSubset.m_aSubsets.back().m_aMapping.size() > 254) )
6934cdf0e10cSrcweir                 {
6935cdf0e10cSrcweir                     rSubset.m_aSubsets.push_back( FontEmit( m_nNextFID++ ) );
6936cdf0e10cSrcweir                 }
6937cdf0e10cSrcweir 
6938cdf0e10cSrcweir                 // copy font id
6939cdf0e10cSrcweir                 pMappedFontObjects[i] = rSubset.m_aSubsets.back().m_nFontID;
6940cdf0e10cSrcweir                 // create new glyph in subset
6941cdf0e10cSrcweir                 sal_uInt8 nNewId = sal::static_int_cast<sal_uInt8>(rSubset.m_aSubsets.back().m_aMapping.size()+1);
6942cdf0e10cSrcweir                 pMappedGlyphs[i] = nNewId;
6943cdf0e10cSrcweir 
6944cdf0e10cSrcweir                 // add new glyph to emitted font subset
6945cdf0e10cSrcweir                 GlyphEmit& rNewGlyphEmit = rSubset.m_aSubsets.back().m_aMapping[ nFontGlyphId ];
6946cdf0e10cSrcweir                 rNewGlyphEmit.setGlyphId( nNewId );
6947cdf0e10cSrcweir                 for( sal_Int32 n = 0; n < pUnicodesPerGlyph[i]; n++ )
6948cdf0e10cSrcweir                     rNewGlyphEmit.addCode( pCurUnicode[n] );
6949cdf0e10cSrcweir 
6950cdf0e10cSrcweir                 // add new glyph to font mapping
6951cdf0e10cSrcweir                 Glyph& rNewGlyph = rSubset.m_aMapping[ nFontGlyphId ];
6952cdf0e10cSrcweir                 rNewGlyph.m_nFontID = pMappedFontObjects[i];
6953cdf0e10cSrcweir                 rNewGlyph.m_nSubsetGlyphID = nNewId;
6954cdf0e10cSrcweir             }
6955cdf0e10cSrcweir             getReferenceDevice()->ImplGetGraphics();
6956cdf0e10cSrcweir             const bool bVertical = ((pGlyphs[i] & GF_ROTMASK) != 0);
6957cdf0e10cSrcweir             pGlyphWidths[i] = m_aFontCache.getGlyphWidth( pCurrentFont,
6958cdf0e10cSrcweir                                                           nFontGlyphId,
6959cdf0e10cSrcweir                                                           bVertical,
6960cdf0e10cSrcweir                                                           m_pReferenceDevice->mpGraphics );
6961cdf0e10cSrcweir         }
6962cdf0e10cSrcweir         else if( pCurrentFont->IsEmbeddable() )
6963cdf0e10cSrcweir         {
6964cdf0e10cSrcweir             sal_Int32 nFontID = 0;
6965cdf0e10cSrcweir             FontEmbedData::iterator it = m_aEmbeddedFonts.find( pCurrentFont );
6966cdf0e10cSrcweir             if( it != m_aEmbeddedFonts.end() )
6967cdf0e10cSrcweir                 nFontID = it->second.m_nNormalFontID;
6968cdf0e10cSrcweir             else
6969cdf0e10cSrcweir             {
6970cdf0e10cSrcweir                 nFontID = m_nNextFID++;
6971cdf0e10cSrcweir                 m_aEmbeddedFonts[ pCurrentFont ] = EmbedFont();
6972cdf0e10cSrcweir                 m_aEmbeddedFonts[ pCurrentFont ].m_nNormalFontID = nFontID;
6973cdf0e10cSrcweir             }
6974cdf0e10cSrcweir             EmbedFont& rEmbedFont = m_aEmbeddedFonts[pCurrentFont];
6975cdf0e10cSrcweir 
6976cdf0e10cSrcweir             const Ucs2SIntMap* pEncoding = NULL;
6977cdf0e10cSrcweir             const Ucs2OStrMap* pNonEncoded = NULL;
6978cdf0e10cSrcweir             getReferenceDevice()->ImplGetGraphics();
6979cdf0e10cSrcweir             pEncoding = m_pReferenceDevice->mpGraphics->GetFontEncodingVector( pCurrentFont, &pNonEncoded );
6980cdf0e10cSrcweir 
6981cdf0e10cSrcweir             Ucs2SIntMap::const_iterator enc_it;
6982cdf0e10cSrcweir             Ucs2OStrMap::const_iterator nonenc_it;
6983cdf0e10cSrcweir 
6984cdf0e10cSrcweir             sal_Int32 nCurFontID = nFontID;
6985cdf0e10cSrcweir             sal_Ucs cChar = *pCurUnicode;
6986cdf0e10cSrcweir             if( pEncoding )
6987cdf0e10cSrcweir             {
6988cdf0e10cSrcweir                 enc_it = pEncoding->find( cChar );
6989cdf0e10cSrcweir                 if( enc_it != pEncoding->end() && enc_it->second > 0 )
6990cdf0e10cSrcweir                 {
6991cdf0e10cSrcweir                     DBG_ASSERT( (enc_it->second & 0xffffff00) == 0, "Invalid character code" );
6992cdf0e10cSrcweir                     cChar = (sal_Ucs)enc_it->second;
6993cdf0e10cSrcweir                 }
6994cdf0e10cSrcweir                 else if( (enc_it == pEncoding->end() || enc_it->second == -1) &&
6995cdf0e10cSrcweir                          pNonEncoded &&
6996cdf0e10cSrcweir                          (nonenc_it = pNonEncoded->find( cChar )) != pNonEncoded->end() )
6997cdf0e10cSrcweir                 {
6998cdf0e10cSrcweir                     nCurFontID = 0;
6999cdf0e10cSrcweir                     // find non encoded glyph
7000cdf0e10cSrcweir                     for( std::list< EmbedEncoding >::iterator nec_it = rEmbedFont.m_aExtendedEncodings.begin(); nec_it != rEmbedFont.m_aExtendedEncodings.end(); ++nec_it )
7001cdf0e10cSrcweir                     {
7002cdf0e10cSrcweir                         if( nec_it->m_aCMap.find( cChar ) != nec_it->m_aCMap.end() )
7003cdf0e10cSrcweir                         {
7004cdf0e10cSrcweir                             nCurFontID = nec_it->m_nFontID;
7005cdf0e10cSrcweir                             cChar = (sal_Ucs)nec_it->m_aCMap[ cChar ];
7006cdf0e10cSrcweir                             break;
7007cdf0e10cSrcweir                         }
7008cdf0e10cSrcweir                     }
7009cdf0e10cSrcweir                     if( nCurFontID == 0 ) // new nonencoded glyph
7010cdf0e10cSrcweir                     {
7011cdf0e10cSrcweir                         if( rEmbedFont.m_aExtendedEncodings.empty() || rEmbedFont.m_aExtendedEncodings.back().m_aEncVector.size() == 255 )
7012cdf0e10cSrcweir                         {
7013cdf0e10cSrcweir                             rEmbedFont.m_aExtendedEncodings.push_back( EmbedEncoding() );
7014cdf0e10cSrcweir                             rEmbedFont.m_aExtendedEncodings.back().m_nFontID = m_nNextFID++;
7015cdf0e10cSrcweir                         }
7016cdf0e10cSrcweir                         EmbedEncoding& rEncoding = rEmbedFont.m_aExtendedEncodings.back();
7017cdf0e10cSrcweir                         rEncoding.m_aEncVector.push_back( EmbedCode() );
7018cdf0e10cSrcweir                         rEncoding.m_aEncVector.back().m_aUnicode = cChar;
7019cdf0e10cSrcweir                         rEncoding.m_aEncVector.back().m_aName = nonenc_it->second;
7020cdf0e10cSrcweir                         rEncoding.m_aCMap[ cChar ] = (sal_Int8)(rEncoding.m_aEncVector.size()-1);
7021cdf0e10cSrcweir                         nCurFontID = rEncoding.m_nFontID;
7022cdf0e10cSrcweir                         cChar = (sal_Ucs)rEncoding.m_aCMap[ cChar ];
7023cdf0e10cSrcweir                     }
7024cdf0e10cSrcweir                 }
7025cdf0e10cSrcweir                 else
7026cdf0e10cSrcweir                     pEncoding = NULL;
7027cdf0e10cSrcweir             }
7028cdf0e10cSrcweir             if( ! pEncoding )
7029cdf0e10cSrcweir             {
7030cdf0e10cSrcweir                 if( cChar & 0xff00 )
7031cdf0e10cSrcweir                 {
7032cdf0e10cSrcweir                     // some characters can be used by conversion
7033cdf0e10cSrcweir                     if( cChar >= 0xf000 && cChar <= 0xf0ff ) // symbol encoding in private use area
7034cdf0e10cSrcweir                         cChar -= 0xf000;
7035cdf0e10cSrcweir                     else
7036cdf0e10cSrcweir                     {
7037cdf0e10cSrcweir                         String aString(cChar);
7038cdf0e10cSrcweir                         ByteString aChar( aString, RTL_TEXTENCODING_MS_1252 );
7039cdf0e10cSrcweir                         cChar = ((sal_Ucs)aChar.GetChar( 0 )) & 0x00ff;
7040cdf0e10cSrcweir                     }
7041cdf0e10cSrcweir                 }
7042cdf0e10cSrcweir             }
7043cdf0e10cSrcweir 
7044cdf0e10cSrcweir             pMappedGlyphs[ i ] = (sal_Int8)cChar;
7045cdf0e10cSrcweir             pMappedFontObjects[ i ] = nCurFontID;
7046cdf0e10cSrcweir             pGlyphWidths[ i ] = m_aFontCache.getGlyphWidth( pCurrentFont,
7047cdf0e10cSrcweir                                                             (pEncoding ? *pCurUnicode : cChar) | GF_ISCHAR,
7048cdf0e10cSrcweir                                                             false,
7049cdf0e10cSrcweir                                                             m_pReferenceDevice->mpGraphics );
7050cdf0e10cSrcweir         }
7051cdf0e10cSrcweir     }
7052cdf0e10cSrcweir }
7053cdf0e10cSrcweir 
7054cdf0e10cSrcweir void PDFWriterImpl::drawRelief( SalLayout& rLayout, const String& rText, bool bTextLines )
7055cdf0e10cSrcweir {
7056cdf0e10cSrcweir     push( PUSH_ALL );
7057cdf0e10cSrcweir 
7058cdf0e10cSrcweir     FontRelief eRelief = m_aCurrentPDFState.m_aFont.GetRelief();
7059cdf0e10cSrcweir 
7060cdf0e10cSrcweir     Color aTextColor = m_aCurrentPDFState.m_aFont.GetColor();
7061cdf0e10cSrcweir     Color aTextLineColor = m_aCurrentPDFState.m_aTextLineColor;
7062cdf0e10cSrcweir     Color aOverlineColor = m_aCurrentPDFState.m_aOverlineColor;
7063cdf0e10cSrcweir     Color aReliefColor( COL_LIGHTGRAY );
7064cdf0e10cSrcweir     if( aTextColor == COL_BLACK )
7065cdf0e10cSrcweir         aTextColor = Color( COL_WHITE );
7066cdf0e10cSrcweir     if( aTextLineColor == COL_BLACK )
7067cdf0e10cSrcweir         aTextLineColor = Color( COL_WHITE );
7068cdf0e10cSrcweir     if( aOverlineColor == COL_BLACK )
7069cdf0e10cSrcweir         aOverlineColor = Color( COL_WHITE );
7070cdf0e10cSrcweir     if( aTextColor == COL_WHITE )
7071cdf0e10cSrcweir         aReliefColor = Color( COL_BLACK );
7072cdf0e10cSrcweir 
7073cdf0e10cSrcweir     Font aSetFont = m_aCurrentPDFState.m_aFont;
7074cdf0e10cSrcweir     aSetFont.SetRelief( RELIEF_NONE );
7075cdf0e10cSrcweir     aSetFont.SetShadow( sal_False );
7076cdf0e10cSrcweir 
7077cdf0e10cSrcweir     aSetFont.SetColor( aReliefColor );
7078cdf0e10cSrcweir     setTextLineColor( aReliefColor );
7079cdf0e10cSrcweir     setOverlineColor( aReliefColor );
7080cdf0e10cSrcweir     setFont( aSetFont );
7081cdf0e10cSrcweir     long nOff = 1 + getReferenceDevice()->mnDPIX/300;
7082cdf0e10cSrcweir     if( eRelief == RELIEF_ENGRAVED )
7083cdf0e10cSrcweir         nOff = -nOff;
7084cdf0e10cSrcweir 
7085cdf0e10cSrcweir     rLayout.DrawOffset() += Point( nOff, nOff );
7086cdf0e10cSrcweir     updateGraphicsState();
7087cdf0e10cSrcweir     drawLayout( rLayout, rText, bTextLines );
7088cdf0e10cSrcweir 
7089cdf0e10cSrcweir     rLayout.DrawOffset() -= Point( nOff, nOff );
7090cdf0e10cSrcweir     setTextLineColor( aTextLineColor );
7091cdf0e10cSrcweir     setOverlineColor( aOverlineColor );
7092cdf0e10cSrcweir     aSetFont.SetColor( aTextColor );
7093cdf0e10cSrcweir     setFont( aSetFont );
7094cdf0e10cSrcweir     updateGraphicsState();
7095cdf0e10cSrcweir     drawLayout( rLayout, rText, bTextLines );
7096cdf0e10cSrcweir 
7097cdf0e10cSrcweir     // clean up the mess
7098cdf0e10cSrcweir     pop();
7099cdf0e10cSrcweir }
7100cdf0e10cSrcweir 
7101cdf0e10cSrcweir void PDFWriterImpl::drawShadow( SalLayout& rLayout, const String& rText, bool bTextLines )
7102cdf0e10cSrcweir {
7103cdf0e10cSrcweir     Font aSaveFont = m_aCurrentPDFState.m_aFont;
7104cdf0e10cSrcweir     Color aSaveTextLineColor = m_aCurrentPDFState.m_aTextLineColor;
7105cdf0e10cSrcweir     Color aSaveOverlineColor = m_aCurrentPDFState.m_aOverlineColor;
7106cdf0e10cSrcweir 
7107cdf0e10cSrcweir     Font& rFont = m_aCurrentPDFState.m_aFont;
7108cdf0e10cSrcweir     if( rFont.GetColor() == Color( COL_BLACK ) || rFont.GetColor().GetLuminance() < 8 )
7109cdf0e10cSrcweir         rFont.SetColor( Color( COL_LIGHTGRAY ) );
7110cdf0e10cSrcweir     else
7111cdf0e10cSrcweir         rFont.SetColor( Color( COL_BLACK ) );
7112cdf0e10cSrcweir     rFont.SetShadow( sal_False );
7113cdf0e10cSrcweir     rFont.SetOutline( sal_False );
7114cdf0e10cSrcweir     setFont( rFont );
7115cdf0e10cSrcweir     setTextLineColor( rFont.GetColor() );
7116cdf0e10cSrcweir     setOverlineColor( rFont.GetColor() );
7117cdf0e10cSrcweir     updateGraphicsState();
7118cdf0e10cSrcweir 
7119cdf0e10cSrcweir     long nOff = 1 + ((m_pReferenceDevice->mpFontEntry->mnLineHeight-24)/24);
7120cdf0e10cSrcweir     if( rFont.IsOutline() )
7121cdf0e10cSrcweir         nOff++;
7122cdf0e10cSrcweir     rLayout.DrawBase() += Point( nOff, nOff );
7123cdf0e10cSrcweir     drawLayout( rLayout, rText, bTextLines );
7124cdf0e10cSrcweir     rLayout.DrawBase() -= Point( nOff, nOff );
7125cdf0e10cSrcweir 
7126cdf0e10cSrcweir     setFont( aSaveFont );
7127cdf0e10cSrcweir     setTextLineColor( aSaveTextLineColor );
7128cdf0e10cSrcweir     setOverlineColor( aSaveOverlineColor );
7129cdf0e10cSrcweir     updateGraphicsState();
7130cdf0e10cSrcweir }
7131cdf0e10cSrcweir 
7132cdf0e10cSrcweir void PDFWriterImpl::drawVerticalGlyphs(
7133cdf0e10cSrcweir         const std::vector<PDFWriterImpl::PDFGlyph>& rGlyphs,
7134cdf0e10cSrcweir         OStringBuffer& rLine,
7135cdf0e10cSrcweir         const Point& rAlignOffset,
7136cdf0e10cSrcweir         const Matrix3& rRotScale,
7137cdf0e10cSrcweir         double fAngle,
7138cdf0e10cSrcweir         double fXScale,
7139cdf0e10cSrcweir         double fSkew,
7140cdf0e10cSrcweir         sal_Int32 nFontHeight )
7141cdf0e10cSrcweir {
7142cdf0e10cSrcweir     long nXOffset = 0;
7143cdf0e10cSrcweir     Point aCurPos( rGlyphs[0].m_aPos );
7144cdf0e10cSrcweir     aCurPos = m_pReferenceDevice->PixelToLogic( aCurPos );
7145cdf0e10cSrcweir     aCurPos += rAlignOffset;
7146cdf0e10cSrcweir     for( size_t i = 0; i < rGlyphs.size(); i++ )
7147cdf0e10cSrcweir     {
7148cdf0e10cSrcweir         // have to emit each glyph on its own
7149cdf0e10cSrcweir         double fDeltaAngle = 0.0;
7150cdf0e10cSrcweir         double fYScale = 1.0;
7151cdf0e10cSrcweir         double fTempXScale = fXScale;
7152cdf0e10cSrcweir         double fSkewB = fSkew;
7153cdf0e10cSrcweir         double fSkewA = 0.0;
7154cdf0e10cSrcweir 
7155cdf0e10cSrcweir         Point aDeltaPos;
7156cdf0e10cSrcweir         if( ( rGlyphs[i].m_nGlyphId & GF_ROTMASK ) == GF_ROTL )
7157cdf0e10cSrcweir         {
7158cdf0e10cSrcweir             fDeltaAngle = M_PI/2.0;
7159cdf0e10cSrcweir             aDeltaPos.X() = m_pReferenceDevice->GetFontMetric().GetAscent();
7160cdf0e10cSrcweir             aDeltaPos.Y() = (int)((double)m_pReferenceDevice->GetFontMetric().GetDescent() * fXScale);
7161cdf0e10cSrcweir             fYScale = fXScale;
7162cdf0e10cSrcweir             fTempXScale = 1.0;
7163cdf0e10cSrcweir             fSkewA = -fSkewB;
7164cdf0e10cSrcweir             fSkewB = 0.0;
7165cdf0e10cSrcweir         }
7166cdf0e10cSrcweir         else if( ( rGlyphs[i].m_nGlyphId & GF_ROTMASK ) == GF_ROTR )
7167cdf0e10cSrcweir         {
7168cdf0e10cSrcweir             fDeltaAngle = -M_PI/2.0;
7169cdf0e10cSrcweir             aDeltaPos.X() = (int)((double)m_pReferenceDevice->GetFontMetric().GetDescent()*fXScale);
7170cdf0e10cSrcweir             aDeltaPos.Y() = -m_pReferenceDevice->GetFontMetric().GetAscent();
7171cdf0e10cSrcweir             fYScale = fXScale;
7172cdf0e10cSrcweir             fTempXScale = 1.0;
7173cdf0e10cSrcweir             fSkewA = fSkewB;
7174cdf0e10cSrcweir             fSkewB = 0.0;
7175cdf0e10cSrcweir         }
7176cdf0e10cSrcweir         aDeltaPos += (m_pReferenceDevice->PixelToLogic( Point( (int)((double)nXOffset/fXScale), 0 ) ) - m_pReferenceDevice->PixelToLogic( Point() ) );
7177cdf0e10cSrcweir         if( i < rGlyphs.size()-1 )
7178*3c19fd8cSZhe Wang 		// [Bug 120627] the text on the Y axis is reversed when export ppt file to PDF format
7179*3c19fd8cSZhe Wang 		{
7180*3c19fd8cSZhe Wang 			long nOffsetX = rGlyphs[i+1].m_aPos.X() - rGlyphs[i].m_aPos.X();
7181*3c19fd8cSZhe Wang 			long nOffsetY = rGlyphs[i+1].m_aPos.Y() - rGlyphs[i].m_aPos.Y();
7182*3c19fd8cSZhe Wang 			nXOffset += (int)sqrt(double(nOffsetX*nOffsetX + nOffsetY*nOffsetY));
7183*3c19fd8cSZhe Wang 		}
7184cdf0e10cSrcweir         if( ! rGlyphs[i].m_nGlyphId )
7185cdf0e10cSrcweir             continue;
7186cdf0e10cSrcweir 
7187cdf0e10cSrcweir         aDeltaPos = rRotScale.transform( aDeltaPos );
7188cdf0e10cSrcweir 
7189cdf0e10cSrcweir         Matrix3 aMat;
7190cdf0e10cSrcweir         if( fSkewB != 0.0 || fSkewA != 0.0 )
7191cdf0e10cSrcweir             aMat.skew( fSkewA, fSkewB );
7192cdf0e10cSrcweir         aMat.scale( fTempXScale, fYScale );
7193cdf0e10cSrcweir         aMat.rotate( fAngle+fDeltaAngle );
7194cdf0e10cSrcweir         aMat.translate( aCurPos.X()+aDeltaPos.X(), aCurPos.Y()+aDeltaPos.Y() );
7195cdf0e10cSrcweir         aMat.append( m_aPages.back(), rLine );
7196cdf0e10cSrcweir         rLine.append( " Tm" );
7197cdf0e10cSrcweir         if( i == 0 || rGlyphs[i-1].m_nMappedFontId != rGlyphs[i].m_nMappedFontId )
7198cdf0e10cSrcweir         {
7199cdf0e10cSrcweir             rLine.append( " /F" );
7200cdf0e10cSrcweir             rLine.append( rGlyphs[i].m_nMappedFontId );
7201cdf0e10cSrcweir             rLine.append( ' ' );
7202cdf0e10cSrcweir             m_aPages.back().appendMappedLength( nFontHeight, rLine, true );
7203cdf0e10cSrcweir             rLine.append( " Tf" );
7204cdf0e10cSrcweir         }
7205cdf0e10cSrcweir         rLine.append( "<" );
7206cdf0e10cSrcweir         appendHex( rGlyphs[i].m_nMappedGlyphId, rLine );
7207cdf0e10cSrcweir         rLine.append( ">Tj\n" );
7208cdf0e10cSrcweir     }
7209cdf0e10cSrcweir }
7210cdf0e10cSrcweir 
7211cdf0e10cSrcweir void PDFWriterImpl::drawHorizontalGlyphs(
7212cdf0e10cSrcweir         const std::vector<PDFWriterImpl::PDFGlyph>& rGlyphs,
7213cdf0e10cSrcweir         OStringBuffer& rLine,
7214cdf0e10cSrcweir         const Point& rAlignOffset,
7215cdf0e10cSrcweir         double fAngle,
7216cdf0e10cSrcweir         double fXScale,
7217cdf0e10cSrcweir         double fSkew,
7218cdf0e10cSrcweir         sal_Int32 nFontHeight,
7219cdf0e10cSrcweir         sal_Int32 nPixelFontHeight
7220cdf0e10cSrcweir         )
7221cdf0e10cSrcweir {
7222cdf0e10cSrcweir     // horizontal (= normal) case
7223cdf0e10cSrcweir 
7224cdf0e10cSrcweir     // fill in  run end indices
7225cdf0e10cSrcweir     // end is marked by index of the first glyph of the next run
7226cdf0e10cSrcweir     // a run is marked by same mapped font id and same Y position
7227cdf0e10cSrcweir     std::vector< sal_uInt32 > aRunEnds;
7228cdf0e10cSrcweir     aRunEnds.reserve( rGlyphs.size() );
7229cdf0e10cSrcweir     for( size_t i = 1; i < rGlyphs.size(); i++ )
7230cdf0e10cSrcweir     {
7231cdf0e10cSrcweir         if( rGlyphs[i].m_nMappedFontId != rGlyphs[i-1].m_nMappedFontId ||
7232cdf0e10cSrcweir             rGlyphs[i].m_aPos.Y() != rGlyphs[i-1].m_aPos.Y() )
7233cdf0e10cSrcweir         {
7234cdf0e10cSrcweir             aRunEnds.push_back(i);
7235cdf0e10cSrcweir         }
7236cdf0e10cSrcweir     }
7237cdf0e10cSrcweir     // last run ends at last glyph
7238cdf0e10cSrcweir     aRunEnds.push_back( rGlyphs.size() );
7239cdf0e10cSrcweir 
7240cdf0e10cSrcweir     // loop over runs of the same font
7241cdf0e10cSrcweir     sal_uInt32 nBeginRun = 0;
7242cdf0e10cSrcweir     for( size_t nRun = 0; nRun < aRunEnds.size(); nRun++ )
7243cdf0e10cSrcweir     {
7244cdf0e10cSrcweir         // setup text matrix
7245cdf0e10cSrcweir         Point aCurPos = rGlyphs[nBeginRun].m_aPos;
7246cdf0e10cSrcweir         // back transformation to current coordinate system
7247cdf0e10cSrcweir         aCurPos = m_pReferenceDevice->PixelToLogic( aCurPos );
7248cdf0e10cSrcweir         aCurPos += rAlignOffset;
7249cdf0e10cSrcweir         // the first run can be set with "Td" operator
7250cdf0e10cSrcweir         // subsequent use of that operator would move
7251cdf0e10cSrcweir         // the texline matrix relative to what was set before
7252cdf0e10cSrcweir         // making use of that would drive us into rounding issues
7253cdf0e10cSrcweir         Matrix3 aMat;
7254cdf0e10cSrcweir         if( nRun == 0 && fAngle == 0.0 && fXScale == 1.0 && fSkew == 0.0 )
7255cdf0e10cSrcweir         {
7256cdf0e10cSrcweir             m_aPages.back().appendPoint( aCurPos, rLine, false );
7257cdf0e10cSrcweir             rLine.append( " Td " );
7258cdf0e10cSrcweir         }
7259cdf0e10cSrcweir         else
7260cdf0e10cSrcweir         {
7261cdf0e10cSrcweir             if( fSkew != 0.0 )
7262cdf0e10cSrcweir                 aMat.skew( 0.0, fSkew );
7263cdf0e10cSrcweir             aMat.scale( fXScale, 1.0 );
7264cdf0e10cSrcweir             aMat.rotate( fAngle );
7265cdf0e10cSrcweir             aMat.translate( aCurPos.X(), aCurPos.Y() );
7266cdf0e10cSrcweir             aMat.append( m_aPages.back(), rLine );
7267cdf0e10cSrcweir             rLine.append( " Tm\n" );
7268cdf0e10cSrcweir         }
7269cdf0e10cSrcweir         // set up correct font
7270cdf0e10cSrcweir         rLine.append( "/F" );
7271cdf0e10cSrcweir         rLine.append( rGlyphs[nBeginRun].m_nMappedFontId );
7272cdf0e10cSrcweir         rLine.append( ' ' );
7273cdf0e10cSrcweir         m_aPages.back().appendMappedLength( nFontHeight, rLine, true );
7274cdf0e10cSrcweir         rLine.append( " Tf" );
7275cdf0e10cSrcweir 
7276cdf0e10cSrcweir         // output glyphs using Tj or TJ
7277cdf0e10cSrcweir         OStringBuffer aKernedLine( 256 ), aUnkernedLine( 256 );
7278cdf0e10cSrcweir         aKernedLine.append( "[<" );
7279cdf0e10cSrcweir         aUnkernedLine.append( '<' );
7280cdf0e10cSrcweir         appendHex( rGlyphs[nBeginRun].m_nMappedGlyphId, aKernedLine );
7281cdf0e10cSrcweir         appendHex( rGlyphs[nBeginRun].m_nMappedGlyphId, aUnkernedLine );
7282cdf0e10cSrcweir 
7283cdf0e10cSrcweir         aMat.invert();
7284cdf0e10cSrcweir         bool bNeedKern = false;
7285cdf0e10cSrcweir         for( sal_uInt32 nPos = nBeginRun+1; nPos < aRunEnds[nRun]; nPos++ )
7286cdf0e10cSrcweir         {
7287cdf0e10cSrcweir             appendHex( rGlyphs[nPos].m_nMappedGlyphId, aUnkernedLine );
7288cdf0e10cSrcweir             // check if default glyph positioning is sufficient
7289cdf0e10cSrcweir             const Point aThisPos = aMat.transform( rGlyphs[nPos].m_aPos );
7290cdf0e10cSrcweir             const Point aPrevPos = aMat.transform( rGlyphs[nPos-1].m_aPos );
7291cdf0e10cSrcweir             double fAdvance = aThisPos.X() - aPrevPos.X();
7292cdf0e10cSrcweir             fAdvance *= 1000.0 / nPixelFontHeight;
7293cdf0e10cSrcweir             const sal_Int32 nAdjustment = (sal_Int32)(rGlyphs[nPos-1].m_nNativeWidth - fAdvance + 0.5);
7294cdf0e10cSrcweir             if( nAdjustment != 0 )
7295cdf0e10cSrcweir             {
7296cdf0e10cSrcweir                 // apply individual glyph positioning
7297cdf0e10cSrcweir                 bNeedKern = true;
7298cdf0e10cSrcweir                 aKernedLine.append( ">" );
7299cdf0e10cSrcweir                 aKernedLine.append( nAdjustment );
7300cdf0e10cSrcweir                 aKernedLine.append( "<" );
7301cdf0e10cSrcweir             }
7302cdf0e10cSrcweir             appendHex( rGlyphs[nPos].m_nMappedGlyphId, aKernedLine );
7303cdf0e10cSrcweir         }
7304cdf0e10cSrcweir         aKernedLine.append( ">]TJ\n" );
7305cdf0e10cSrcweir         aUnkernedLine.append( ">Tj\n" );
7306cdf0e10cSrcweir         rLine.append( bNeedKern ? aKernedLine : aUnkernedLine );
7307cdf0e10cSrcweir 
7308cdf0e10cSrcweir         // set beginning of next run
7309cdf0e10cSrcweir         nBeginRun = aRunEnds[nRun];
7310cdf0e10cSrcweir     }
7311cdf0e10cSrcweir }
7312cdf0e10cSrcweir 
7313cdf0e10cSrcweir void PDFWriterImpl::drawLayout( SalLayout& rLayout, const String& rText, bool bTextLines )
7314cdf0e10cSrcweir {
7315cdf0e10cSrcweir     // relief takes precedence over shadow (see outdev3.cxx)
7316cdf0e10cSrcweir     if(  m_aCurrentPDFState.m_aFont.GetRelief() != RELIEF_NONE )
7317cdf0e10cSrcweir     {
7318cdf0e10cSrcweir         drawRelief( rLayout, rText, bTextLines );
7319cdf0e10cSrcweir         return;
7320cdf0e10cSrcweir     }
7321cdf0e10cSrcweir     else if( m_aCurrentPDFState.m_aFont.IsShadow() )
7322cdf0e10cSrcweir         drawShadow( rLayout, rText, bTextLines );
7323cdf0e10cSrcweir 
7324cdf0e10cSrcweir     OStringBuffer aLine( 512 );
7325cdf0e10cSrcweir 
7326cdf0e10cSrcweir     const int nMaxGlyphs = 256;
7327cdf0e10cSrcweir 
7328cdf0e10cSrcweir     sal_GlyphId pGlyphs[nMaxGlyphs];
7329cdf0e10cSrcweir     sal_Int32 pGlyphWidths[nMaxGlyphs];
7330cdf0e10cSrcweir     sal_uInt8 pMappedGlyphs[nMaxGlyphs];
7331cdf0e10cSrcweir     sal_Int32 pMappedFontObjects[nMaxGlyphs];
7332cdf0e10cSrcweir     std::vector<sal_Ucs> aUnicodes;
7333cdf0e10cSrcweir     aUnicodes.reserve( nMaxGlyphs );
7334cdf0e10cSrcweir     sal_Int32 pUnicodesPerGlyph[nMaxGlyphs];
7335cdf0e10cSrcweir     int pCharPosAry[nMaxGlyphs];
7336cdf0e10cSrcweir     sal_Int32 nAdvanceWidths[nMaxGlyphs];
7337cdf0e10cSrcweir     const ImplFontData* pFallbackFonts[nMaxGlyphs];
7338cdf0e10cSrcweir     bool bVertical = m_aCurrentPDFState.m_aFont.IsVertical();
7339cdf0e10cSrcweir     int nGlyphs;
7340cdf0e10cSrcweir     int nIndex = 0;
7341cdf0e10cSrcweir     int nMinCharPos = 0, nMaxCharPos = rText.Len()-1;
7342cdf0e10cSrcweir     double fXScale = 1.0;
7343cdf0e10cSrcweir     double fSkew = 0.0;
7344cdf0e10cSrcweir     sal_Int32 nPixelFontHeight = m_pReferenceDevice->mpFontEntry->maFontSelData.mnHeight;
7345cdf0e10cSrcweir     TextAlign eAlign = m_aCurrentPDFState.m_aFont.GetAlign();
7346cdf0e10cSrcweir 
7347cdf0e10cSrcweir     // transform font height back to current units
7348cdf0e10cSrcweir     // note: the layout calculates in outdevs device pixel !!
7349cdf0e10cSrcweir     sal_Int32 nFontHeight = m_pReferenceDevice->ImplDevicePixelToLogicHeight( nPixelFontHeight );
7350cdf0e10cSrcweir     if( m_aCurrentPDFState.m_aFont.GetWidth() )
7351cdf0e10cSrcweir     {
7352cdf0e10cSrcweir         Font aFont( m_aCurrentPDFState.m_aFont );
7353cdf0e10cSrcweir         aFont.SetWidth( 0 );
7354cdf0e10cSrcweir         FontMetric aMetric = m_pReferenceDevice->GetFontMetric( aFont );
7355cdf0e10cSrcweir         if( aMetric.GetWidth() != m_aCurrentPDFState.m_aFont.GetWidth() )
7356cdf0e10cSrcweir         {
7357cdf0e10cSrcweir             fXScale =
7358cdf0e10cSrcweir                 (double)m_aCurrentPDFState.m_aFont.GetWidth() /
7359cdf0e10cSrcweir                 (double)aMetric.GetWidth();
7360cdf0e10cSrcweir         }
7361cdf0e10cSrcweir         // force state before GetFontMetric
7362cdf0e10cSrcweir         m_pReferenceDevice->ImplNewFont();
7363cdf0e10cSrcweir     }
7364cdf0e10cSrcweir 
7365cdf0e10cSrcweir     // perform artificial italics if necessary
7366cdf0e10cSrcweir     if( ( m_aCurrentPDFState.m_aFont.GetItalic() == ITALIC_NORMAL ||
7367cdf0e10cSrcweir           m_aCurrentPDFState.m_aFont.GetItalic() == ITALIC_OBLIQUE ) &&
7368cdf0e10cSrcweir         !( m_pReferenceDevice->mpFontEntry->maFontSelData.mpFontData->GetSlant() == ITALIC_NORMAL ||
7369cdf0e10cSrcweir            m_pReferenceDevice->mpFontEntry->maFontSelData.mpFontData->GetSlant() == ITALIC_OBLIQUE )
7370cdf0e10cSrcweir         )
7371cdf0e10cSrcweir     {
7372cdf0e10cSrcweir         fSkew = M_PI/12.0;
7373cdf0e10cSrcweir     }
7374cdf0e10cSrcweir 
7375cdf0e10cSrcweir     // if the mapmode is distorted we need to adjust for that also
7376cdf0e10cSrcweir     if( m_aCurrentPDFState.m_aMapMode.GetScaleX() != m_aCurrentPDFState.m_aMapMode.GetScaleY() )
7377cdf0e10cSrcweir     {
7378cdf0e10cSrcweir         fXScale *= double(m_aCurrentPDFState.m_aMapMode.GetScaleX()) / double(m_aCurrentPDFState.m_aMapMode.GetScaleY());
7379cdf0e10cSrcweir     }
7380cdf0e10cSrcweir 
7381cdf0e10cSrcweir     int nAngle = m_aCurrentPDFState.m_aFont.GetOrientation();
7382cdf0e10cSrcweir     // normalize angles
7383cdf0e10cSrcweir     while( nAngle < 0 )
7384cdf0e10cSrcweir         nAngle += 3600;
7385cdf0e10cSrcweir     nAngle = nAngle % 3600;
7386cdf0e10cSrcweir     double fAngle = (double)nAngle * M_PI / 1800.0;
7387cdf0e10cSrcweir 
7388cdf0e10cSrcweir     Matrix3 aRotScale;
7389cdf0e10cSrcweir     aRotScale.scale( fXScale, 1.0 );
7390cdf0e10cSrcweir     if( fAngle != 0.0 )
7391cdf0e10cSrcweir         aRotScale.rotate( -fAngle );
7392cdf0e10cSrcweir 
7393cdf0e10cSrcweir     bool bPop = false;
7394cdf0e10cSrcweir     bool bABold = false;
7395cdf0e10cSrcweir     // artificial bold necessary ?
7396cdf0e10cSrcweir     if( m_pReferenceDevice->mpFontEntry->maFontSelData.mpFontData->GetWeight() <= WEIGHT_MEDIUM &&
7397cdf0e10cSrcweir         m_pReferenceDevice->mpFontEntry->maFontSelData.GetWeight() > WEIGHT_MEDIUM )
7398cdf0e10cSrcweir     {
7399cdf0e10cSrcweir         if( ! bPop )
7400cdf0e10cSrcweir             aLine.append( "q " );
7401cdf0e10cSrcweir         bPop = true;
7402cdf0e10cSrcweir         bABold = true;
7403cdf0e10cSrcweir     }
7404cdf0e10cSrcweir     // setup text colors (if necessary)
7405cdf0e10cSrcweir     Color aStrokeColor( COL_TRANSPARENT );
7406cdf0e10cSrcweir     Color aNonStrokeColor( COL_TRANSPARENT );
7407cdf0e10cSrcweir 
7408cdf0e10cSrcweir     if( m_aCurrentPDFState.m_aFont.IsOutline() )
7409cdf0e10cSrcweir     {
7410cdf0e10cSrcweir         aStrokeColor = m_aCurrentPDFState.m_aFont.GetColor();
7411cdf0e10cSrcweir         aNonStrokeColor = Color( COL_WHITE );
7412cdf0e10cSrcweir     }
7413cdf0e10cSrcweir     else
7414cdf0e10cSrcweir         aNonStrokeColor = m_aCurrentPDFState.m_aFont.GetColor();
7415cdf0e10cSrcweir     if( bABold )
7416cdf0e10cSrcweir         aStrokeColor = m_aCurrentPDFState.m_aFont.GetColor();
7417cdf0e10cSrcweir 
7418cdf0e10cSrcweir     if( aStrokeColor != Color( COL_TRANSPARENT ) && aStrokeColor != m_aCurrentPDFState.m_aLineColor )
7419cdf0e10cSrcweir     {
7420cdf0e10cSrcweir         if( ! bPop )
7421cdf0e10cSrcweir             aLine.append( "q " );
7422cdf0e10cSrcweir         bPop = true;
7423cdf0e10cSrcweir         appendStrokingColor( aStrokeColor, aLine );
7424cdf0e10cSrcweir         aLine.append( "\n" );
7425cdf0e10cSrcweir     }
7426cdf0e10cSrcweir     if( aNonStrokeColor != Color( COL_TRANSPARENT ) && aNonStrokeColor != m_aCurrentPDFState.m_aFillColor )
7427cdf0e10cSrcweir     {
7428cdf0e10cSrcweir         if( ! bPop )
7429cdf0e10cSrcweir             aLine.append( "q " );
7430cdf0e10cSrcweir         bPop = true;
7431cdf0e10cSrcweir         appendNonStrokingColor( aNonStrokeColor, aLine );
7432cdf0e10cSrcweir         aLine.append( "\n" );
7433cdf0e10cSrcweir     }
7434cdf0e10cSrcweir 
7435cdf0e10cSrcweir     // begin text object
7436cdf0e10cSrcweir     aLine.append( "BT\n" );
7437cdf0e10cSrcweir     // outline attribute ?
7438cdf0e10cSrcweir     if( m_aCurrentPDFState.m_aFont.IsOutline() || bABold )
7439cdf0e10cSrcweir     {
7440cdf0e10cSrcweir         // set correct text mode, set stroke width
7441cdf0e10cSrcweir         aLine.append( "2 Tr " ); // fill, then stroke
7442cdf0e10cSrcweir 
7443cdf0e10cSrcweir         if( m_aCurrentPDFState.m_aFont.IsOutline() )
7444cdf0e10cSrcweir         {
7445cdf0e10cSrcweir             // unclear what to do in case of outline and artificial bold
7446cdf0e10cSrcweir             // for the time being outline wins
7447cdf0e10cSrcweir             aLine.append( "0.25 w \n" );
7448cdf0e10cSrcweir         }
7449cdf0e10cSrcweir         else
7450cdf0e10cSrcweir         {
7451cdf0e10cSrcweir             double fW = (double)m_aCurrentPDFState.m_aFont.GetHeight() / 30.0;
7452cdf0e10cSrcweir             m_aPages.back().appendMappedLength( fW, aLine );
7453cdf0e10cSrcweir             aLine.append ( " w\n" );
7454cdf0e10cSrcweir         }
7455cdf0e10cSrcweir     }
7456cdf0e10cSrcweir 
7457cdf0e10cSrcweir     FontMetric aRefDevFontMetric = m_pReferenceDevice->GetFontMetric();
7458cdf0e10cSrcweir 
7459cdf0e10cSrcweir     // collect the glyphs into a single array
7460cdf0e10cSrcweir     const int nTmpMaxGlyphs = rLayout.GetOrientation() ? 1 : nMaxGlyphs; // #i97991# temporary workaround for #i87686#
7461cdf0e10cSrcweir     std::vector< PDFGlyph > aGlyphs;
7462cdf0e10cSrcweir     aGlyphs.reserve( nTmpMaxGlyphs );
7463cdf0e10cSrcweir     // first get all the glyphs and register them; coordinates still in Pixel
7464cdf0e10cSrcweir     Point aGNGlyphPos;
7465cdf0e10cSrcweir     while( (nGlyphs = rLayout.GetNextGlyphs( nTmpMaxGlyphs, pGlyphs, aGNGlyphPos, nIndex, nAdvanceWidths, pCharPosAry )) != 0 )
7466cdf0e10cSrcweir     {
7467cdf0e10cSrcweir         aUnicodes.clear();
7468cdf0e10cSrcweir         for( int i = 0; i < nGlyphs; i++ )
7469cdf0e10cSrcweir         {
7470cdf0e10cSrcweir             pFallbackFonts[i] = rLayout.GetFallbackFontData( pGlyphs[i] );
7471cdf0e10cSrcweir 
7472cdf0e10cSrcweir             // default case: 1 glyph is one unicode
7473cdf0e10cSrcweir             pUnicodesPerGlyph[i] = 1;
7474cdf0e10cSrcweir             if( (pGlyphs[i] & GF_ISCHAR) )
7475cdf0e10cSrcweir             {
7476cdf0e10cSrcweir                 aUnicodes.push_back( static_cast<sal_Ucs>(pGlyphs[i] & GF_IDXMASK) );
7477cdf0e10cSrcweir             }
7478cdf0e10cSrcweir             else if( pCharPosAry[i] >= nMinCharPos && pCharPosAry[i] <= nMaxCharPos )
7479cdf0e10cSrcweir             {
7480cdf0e10cSrcweir                 int nChars = 1;
7481cdf0e10cSrcweir                 aUnicodes.push_back( rText.GetChar( sal::static_int_cast<xub_StrLen>(pCharPosAry[i]) ) );
7482cdf0e10cSrcweir                 pUnicodesPerGlyph[i] = 1;
7483cdf0e10cSrcweir                 // try to handle ligatures and such
7484cdf0e10cSrcweir                 if( i < nGlyphs-1 )
7485cdf0e10cSrcweir                 {
7486cdf0e10cSrcweir                     nChars = pCharPosAry[i+1] - pCharPosAry[i];
7487cdf0e10cSrcweir                     // #i115618# fix for simple RTL+CTL cases
7488cdf0e10cSrcweir                     // TODO: sanitize for RTL ligatures, more complex CTL, etc.
7489cdf0e10cSrcweir                     if( nChars < 0 )
7490cdf0e10cSrcweir                         nChars = -nChars;
7491cdf0e10cSrcweir 		    else if( nChars == 0 )
7492cdf0e10cSrcweir                         nChars = 1;
7493cdf0e10cSrcweir                     pUnicodesPerGlyph[i] = nChars;
7494cdf0e10cSrcweir                     for( int n = 1; n < nChars; n++ )
7495cdf0e10cSrcweir                         aUnicodes.push_back( rText.GetChar( sal::static_int_cast<xub_StrLen>(pCharPosAry[i]+n) ) );
7496cdf0e10cSrcweir                 }
7497cdf0e10cSrcweir                 // #i36691# hack that is needed because currently the pGlyphs[]
7498cdf0e10cSrcweir                 // argument is ignored for embeddable fonts and so the layout
7499cdf0e10cSrcweir                 // engine's glyph work is ignored (i.e. char mirroring)
7500cdf0e10cSrcweir                 // TODO: a real solution would be to map the layout engine's
7501cdf0e10cSrcweir                 // glyphid (i.e. FreeType's synthetic glyphid for a Type1 font)
7502cdf0e10cSrcweir                 // back to unicode and then to embeddable font's encoding
7503cdf0e10cSrcweir                 if( getReferenceDevice()->GetLayoutMode() & TEXT_LAYOUT_BIDI_RTL )
7504cdf0e10cSrcweir                 {
7505cdf0e10cSrcweir                     size_t nI = aUnicodes.size()-1;
7506cdf0e10cSrcweir                     for( int n = 0; n < nChars; n++, nI-- )
7507cdf0e10cSrcweir                         aUnicodes[nI] = static_cast<sal_Ucs>(GetMirroredChar(aUnicodes[nI]));
7508cdf0e10cSrcweir                 }
7509cdf0e10cSrcweir             }
7510cdf0e10cSrcweir             else
7511cdf0e10cSrcweir                 aUnicodes.push_back( 0 );
7512cdf0e10cSrcweir             // note: in case of ctl one character may result
7513cdf0e10cSrcweir             // in multiple glyphs. The current SalLayout
7514cdf0e10cSrcweir             // implementations set -1 then to indicate that no direct
7515cdf0e10cSrcweir             // mapping is possible
7516cdf0e10cSrcweir         }
7517cdf0e10cSrcweir 
7518cdf0e10cSrcweir         registerGlyphs( nGlyphs, pGlyphs, pGlyphWidths, &aUnicodes[0], pUnicodesPerGlyph, pMappedGlyphs, pMappedFontObjects, pFallbackFonts );
7519cdf0e10cSrcweir 
7520cdf0e10cSrcweir         for( int i = 0; i < nGlyphs; i++ )
7521cdf0e10cSrcweir         {
7522cdf0e10cSrcweir             aGlyphs.push_back( PDFGlyph( aGNGlyphPos,
7523cdf0e10cSrcweir                                          pGlyphWidths[i],
7524cdf0e10cSrcweir                                          pGlyphs[i],
7525cdf0e10cSrcweir                                          pMappedFontObjects[i],
7526cdf0e10cSrcweir                                          pMappedGlyphs[i] ) );
7527cdf0e10cSrcweir             if( bVertical )
7528cdf0e10cSrcweir                 aGNGlyphPos.Y() += nAdvanceWidths[i]/rLayout.GetUnitsPerPixel();
7529cdf0e10cSrcweir             else
7530cdf0e10cSrcweir                 aGNGlyphPos.X() += nAdvanceWidths[i]/rLayout.GetUnitsPerPixel();
7531cdf0e10cSrcweir         }
7532cdf0e10cSrcweir     }
7533cdf0e10cSrcweir 
7534cdf0e10cSrcweir     Point aAlignOffset;
7535cdf0e10cSrcweir     if ( eAlign == ALIGN_BOTTOM )
7536cdf0e10cSrcweir         aAlignOffset.Y() -= aRefDevFontMetric.GetDescent();
7537cdf0e10cSrcweir     else if ( eAlign == ALIGN_TOP )
7538cdf0e10cSrcweir         aAlignOffset.Y() += aRefDevFontMetric.GetAscent();
7539cdf0e10cSrcweir     if( aAlignOffset.X() || aAlignOffset.Y() )
7540cdf0e10cSrcweir         aAlignOffset = aRotScale.transform( aAlignOffset );
7541cdf0e10cSrcweir 
7542cdf0e10cSrcweir     /* #159153# do not emit an empty glyph vector; this can happen if e.g. the original
7543cdf0e10cSrcweir        string contained only on of the UTF16 BOMs
7544cdf0e10cSrcweir     */
7545cdf0e10cSrcweir     if( ! aGlyphs.empty() )
7546cdf0e10cSrcweir     {
7547cdf0e10cSrcweir         if( bVertical )
7548cdf0e10cSrcweir             drawVerticalGlyphs( aGlyphs, aLine, aAlignOffset, aRotScale, fAngle, fXScale, fSkew, nFontHeight );
7549cdf0e10cSrcweir         else
7550cdf0e10cSrcweir             drawHorizontalGlyphs( aGlyphs, aLine, aAlignOffset, fAngle, fXScale, fSkew, nFontHeight, nPixelFontHeight );
7551cdf0e10cSrcweir     }
7552cdf0e10cSrcweir 
7553cdf0e10cSrcweir     // end textobject
7554cdf0e10cSrcweir     aLine.append( "ET\n" );
7555cdf0e10cSrcweir     if( bPop )
7556cdf0e10cSrcweir         aLine.append( "Q\n" );
7557cdf0e10cSrcweir 
7558cdf0e10cSrcweir     writeBuffer( aLine.getStr(), aLine.getLength() );
7559cdf0e10cSrcweir 
7560cdf0e10cSrcweir     // draw eventual textlines
7561cdf0e10cSrcweir     FontStrikeout eStrikeout = m_aCurrentPDFState.m_aFont.GetStrikeout();
7562cdf0e10cSrcweir     FontUnderline eUnderline = m_aCurrentPDFState.m_aFont.GetUnderline();
7563cdf0e10cSrcweir     FontUnderline eOverline  = m_aCurrentPDFState.m_aFont.GetOverline();
7564cdf0e10cSrcweir     if( bTextLines &&
7565cdf0e10cSrcweir         (
7566cdf0e10cSrcweir          ( eUnderline != UNDERLINE_NONE && eUnderline != UNDERLINE_DONTKNOW ) ||
7567cdf0e10cSrcweir          ( eOverline  != UNDERLINE_NONE && eOverline  != UNDERLINE_DONTKNOW ) ||
7568cdf0e10cSrcweir          ( eStrikeout != STRIKEOUT_NONE && eStrikeout != STRIKEOUT_DONTKNOW )
7569cdf0e10cSrcweir          )
7570cdf0e10cSrcweir         )
7571cdf0e10cSrcweir     {
7572cdf0e10cSrcweir         sal_Bool bUnderlineAbove = OutputDevice::ImplIsUnderlineAbove( m_aCurrentPDFState.m_aFont );
7573cdf0e10cSrcweir         if( m_aCurrentPDFState.m_aFont.IsWordLineMode() )
7574cdf0e10cSrcweir         {
7575cdf0e10cSrcweir             Point aPos, aStartPt;
7576cdf0e10cSrcweir             sal_Int32 nWidth = 0, nAdvance=0;
7577cdf0e10cSrcweir             for( int nStart = 0;;)
7578cdf0e10cSrcweir             {
7579cdf0e10cSrcweir                 sal_GlyphId nGlyphIndex;
7580cdf0e10cSrcweir                 if( !rLayout.GetNextGlyphs( 1, &nGlyphIndex, aPos, nStart, &nAdvance ) )
7581cdf0e10cSrcweir                     break;
7582cdf0e10cSrcweir 
7583cdf0e10cSrcweir                 if( !rLayout.IsSpacingGlyph( nGlyphIndex ) )
7584cdf0e10cSrcweir                 {
7585cdf0e10cSrcweir                     if( !nWidth )
7586cdf0e10cSrcweir                         aStartPt = aPos;
7587cdf0e10cSrcweir 
7588cdf0e10cSrcweir                     nWidth += nAdvance;
7589cdf0e10cSrcweir                 }
7590cdf0e10cSrcweir                 else if( nWidth > 0 )
7591cdf0e10cSrcweir                 {
7592cdf0e10cSrcweir                     drawTextLine( m_pReferenceDevice->PixelToLogic( aStartPt ),
7593cdf0e10cSrcweir                                   m_pReferenceDevice->ImplDevicePixelToLogicWidth( nWidth ),
7594cdf0e10cSrcweir                                   eStrikeout, eUnderline, eOverline, bUnderlineAbove );
7595cdf0e10cSrcweir                     nWidth = 0;
7596cdf0e10cSrcweir                 }
7597cdf0e10cSrcweir             }
7598cdf0e10cSrcweir 
7599cdf0e10cSrcweir             if( nWidth > 0 )
7600cdf0e10cSrcweir             {
7601cdf0e10cSrcweir                 drawTextLine( m_pReferenceDevice->PixelToLogic( aStartPt ),
7602cdf0e10cSrcweir                               m_pReferenceDevice->ImplDevicePixelToLogicWidth( nWidth ),
7603cdf0e10cSrcweir                               eStrikeout, eUnderline, eOverline, bUnderlineAbove );
7604cdf0e10cSrcweir             }
7605cdf0e10cSrcweir         }
7606cdf0e10cSrcweir         else
7607cdf0e10cSrcweir         {
7608cdf0e10cSrcweir             Point aStartPt = rLayout.GetDrawPosition();
7609cdf0e10cSrcweir             int nWidth = rLayout.GetTextWidth() / rLayout.GetUnitsPerPixel();
7610cdf0e10cSrcweir             drawTextLine( m_pReferenceDevice->PixelToLogic( aStartPt ),
7611cdf0e10cSrcweir                           m_pReferenceDevice->ImplDevicePixelToLogicWidth( nWidth ),
7612cdf0e10cSrcweir                           eStrikeout, eUnderline, eOverline, bUnderlineAbove );
7613cdf0e10cSrcweir         }
7614cdf0e10cSrcweir     }
7615cdf0e10cSrcweir 
7616cdf0e10cSrcweir     // write eventual emphasis marks
7617cdf0e10cSrcweir     if( m_aCurrentPDFState.m_aFont.GetEmphasisMark() & EMPHASISMARK_STYLE )
7618cdf0e10cSrcweir     {
7619cdf0e10cSrcweir         PolyPolygon 			aEmphPoly;
7620cdf0e10cSrcweir         Rectangle				aEmphRect1;
7621cdf0e10cSrcweir         Rectangle				aEmphRect2;
7622cdf0e10cSrcweir         long					nEmphYOff;
7623cdf0e10cSrcweir         long					nEmphWidth;
7624cdf0e10cSrcweir         long					nEmphHeight;
7625cdf0e10cSrcweir         sal_Bool					bEmphPolyLine;
7626cdf0e10cSrcweir         FontEmphasisMark		nEmphMark;
7627cdf0e10cSrcweir 
7628cdf0e10cSrcweir         push( PUSH_ALL );
7629cdf0e10cSrcweir 
7630cdf0e10cSrcweir         aLine.setLength( 0 );
7631cdf0e10cSrcweir         aLine.append( "q\n" );
7632cdf0e10cSrcweir 
7633cdf0e10cSrcweir         nEmphMark = m_pReferenceDevice->ImplGetEmphasisMarkStyle( m_aCurrentPDFState.m_aFont );
7634cdf0e10cSrcweir         if ( nEmphMark & EMPHASISMARK_POS_BELOW )
7635cdf0e10cSrcweir             nEmphHeight = m_pReferenceDevice->mnEmphasisDescent;
7636cdf0e10cSrcweir         else
7637cdf0e10cSrcweir             nEmphHeight = m_pReferenceDevice->mnEmphasisAscent;
7638cdf0e10cSrcweir         m_pReferenceDevice->ImplGetEmphasisMark( aEmphPoly,
7639cdf0e10cSrcweir                                                  bEmphPolyLine,
7640cdf0e10cSrcweir                                                  aEmphRect1,
7641cdf0e10cSrcweir                                                  aEmphRect2,
7642cdf0e10cSrcweir                                                  nEmphYOff,
7643cdf0e10cSrcweir                                                  nEmphWidth,
7644cdf0e10cSrcweir                                                  nEmphMark,
7645cdf0e10cSrcweir                                                  m_pReferenceDevice->ImplDevicePixelToLogicWidth(nEmphHeight),
7646cdf0e10cSrcweir                                                  m_pReferenceDevice->mpFontEntry->mnOrientation );
7647cdf0e10cSrcweir         if ( bEmphPolyLine )
7648cdf0e10cSrcweir         {
7649cdf0e10cSrcweir             setLineColor( m_aCurrentPDFState.m_aFont.GetColor() );
7650cdf0e10cSrcweir             setFillColor( Color( COL_TRANSPARENT ) );
7651cdf0e10cSrcweir         }
7652cdf0e10cSrcweir         else
7653cdf0e10cSrcweir         {
7654cdf0e10cSrcweir             setFillColor( m_aCurrentPDFState.m_aFont.GetColor() );
7655cdf0e10cSrcweir             setLineColor( Color( COL_TRANSPARENT ) );
7656cdf0e10cSrcweir         }
7657cdf0e10cSrcweir         writeBuffer( aLine.getStr(), aLine.getLength() );
7658cdf0e10cSrcweir 
7659cdf0e10cSrcweir         Point aOffset = Point(0,0);
7660cdf0e10cSrcweir 
7661cdf0e10cSrcweir         if ( nEmphMark & EMPHASISMARK_POS_BELOW )
7662cdf0e10cSrcweir             aOffset.Y() += m_pReferenceDevice->mpFontEntry->maMetric.mnDescent + nEmphYOff;
7663cdf0e10cSrcweir         else
7664cdf0e10cSrcweir             aOffset.Y() -= m_pReferenceDevice->mpFontEntry->maMetric.mnAscent + nEmphYOff;
7665cdf0e10cSrcweir 
7666cdf0e10cSrcweir         long nEmphWidth2     = nEmphWidth / 2;
7667cdf0e10cSrcweir         long nEmphHeight2    = nEmphHeight / 2;
7668cdf0e10cSrcweir         aOffset += Point( nEmphWidth2, nEmphHeight2 );
7669cdf0e10cSrcweir 
7670cdf0e10cSrcweir         if ( eAlign == ALIGN_BOTTOM )
7671cdf0e10cSrcweir             aOffset.Y() -= m_pReferenceDevice->mpFontEntry->maMetric.mnDescent;
7672cdf0e10cSrcweir         else if ( eAlign == ALIGN_TOP )
7673cdf0e10cSrcweir             aOffset.Y() += m_pReferenceDevice->mpFontEntry->maMetric.mnAscent;
7674cdf0e10cSrcweir 
7675cdf0e10cSrcweir         for( int nStart = 0;;)
7676cdf0e10cSrcweir         {
7677cdf0e10cSrcweir             Point aPos;
7678cdf0e10cSrcweir             sal_GlyphId nGlyphIndex;
7679cdf0e10cSrcweir             sal_Int32 nAdvance;
7680cdf0e10cSrcweir             if( !rLayout.GetNextGlyphs( 1, &nGlyphIndex, aPos, nStart, &nAdvance ) )
7681cdf0e10cSrcweir                 break;
7682cdf0e10cSrcweir 
7683cdf0e10cSrcweir             if( !rLayout.IsSpacingGlyph( nGlyphIndex ) )
7684cdf0e10cSrcweir             {
7685cdf0e10cSrcweir                 Point aAdjOffset = aOffset;
7686cdf0e10cSrcweir                 aAdjOffset.X() += (nAdvance - nEmphWidth) / 2;
7687cdf0e10cSrcweir                 aAdjOffset = aRotScale.transform( aAdjOffset );
7688cdf0e10cSrcweir 
7689cdf0e10cSrcweir                 aAdjOffset -= Point( nEmphWidth2, nEmphHeight2 );
7690cdf0e10cSrcweir 
7691cdf0e10cSrcweir                 aPos += aAdjOffset;
7692cdf0e10cSrcweir                 aPos = m_pReferenceDevice->PixelToLogic( aPos );
7693cdf0e10cSrcweir                 drawEmphasisMark( aPos.X(), aPos.Y(),
7694cdf0e10cSrcweir                                   aEmphPoly, bEmphPolyLine,
7695cdf0e10cSrcweir                                   aEmphRect1, aEmphRect2 );
7696cdf0e10cSrcweir             }
7697cdf0e10cSrcweir         }
7698cdf0e10cSrcweir 
7699cdf0e10cSrcweir         writeBuffer( "Q\n", 2 );
7700cdf0e10cSrcweir         pop();
7701cdf0e10cSrcweir     }
7702cdf0e10cSrcweir 
7703cdf0e10cSrcweir }
7704cdf0e10cSrcweir 
7705cdf0e10cSrcweir void PDFWriterImpl::drawEmphasisMark( long nX, long nY,
7706cdf0e10cSrcweir                                       const PolyPolygon& rPolyPoly, sal_Bool bPolyLine,
7707cdf0e10cSrcweir                                       const Rectangle& rRect1, const Rectangle& rRect2 )
7708cdf0e10cSrcweir {
7709cdf0e10cSrcweir     // TODO: pass nWidth as width of this mark
7710cdf0e10cSrcweir     // long nWidth = 0;
7711cdf0e10cSrcweir 
7712cdf0e10cSrcweir     if ( rPolyPoly.Count() )
7713cdf0e10cSrcweir     {
7714cdf0e10cSrcweir         if ( bPolyLine )
7715cdf0e10cSrcweir         {
7716cdf0e10cSrcweir             Polygon aPoly = rPolyPoly.GetObject( 0 );
7717cdf0e10cSrcweir             aPoly.Move( nX, nY );
7718cdf0e10cSrcweir             drawPolyLine( aPoly );
7719cdf0e10cSrcweir         }
7720cdf0e10cSrcweir         else
7721cdf0e10cSrcweir         {
7722cdf0e10cSrcweir             PolyPolygon aPolyPoly = rPolyPoly;
7723cdf0e10cSrcweir             aPolyPoly.Move( nX, nY );
7724cdf0e10cSrcweir             drawPolyPolygon( aPolyPoly );
7725cdf0e10cSrcweir         }
7726cdf0e10cSrcweir     }
7727cdf0e10cSrcweir 
7728cdf0e10cSrcweir     if ( !rRect1.IsEmpty() )
7729cdf0e10cSrcweir     {
7730cdf0e10cSrcweir         Rectangle aRect( Point( nX+rRect1.Left(),
7731cdf0e10cSrcweir                                 nY+rRect1.Top() ), rRect1.GetSize() );
7732cdf0e10cSrcweir         drawRectangle( aRect );
7733cdf0e10cSrcweir     }
7734cdf0e10cSrcweir 
7735cdf0e10cSrcweir     if ( !rRect2.IsEmpty() )
7736cdf0e10cSrcweir     {
7737cdf0e10cSrcweir         Rectangle aRect( Point( nX+rRect2.Left(),
7738cdf0e10cSrcweir                                 nY+rRect2.Top() ), rRect2.GetSize() );
7739cdf0e10cSrcweir 
7740cdf0e10cSrcweir         drawRectangle( aRect );
7741cdf0e10cSrcweir     }
7742cdf0e10cSrcweir }
7743cdf0e10cSrcweir 
7744cdf0e10cSrcweir void PDFWriterImpl::drawText( const Point& rPos, const String& rText, xub_StrLen nIndex, xub_StrLen nLen, bool bTextLines )
7745cdf0e10cSrcweir {
7746cdf0e10cSrcweir     MARK( "drawText" );
7747cdf0e10cSrcweir 
7748cdf0e10cSrcweir     updateGraphicsState();
7749cdf0e10cSrcweir 
7750cdf0e10cSrcweir     // get a layout from the OuputDevice's SalGraphics
7751cdf0e10cSrcweir     // this also enforces font substitution and sets the font on SalGraphics
7752cdf0e10cSrcweir     SalLayout* pLayout = m_pReferenceDevice->ImplLayout( rText, nIndex, nLen, rPos );
7753cdf0e10cSrcweir     if( pLayout )
7754cdf0e10cSrcweir     {
7755cdf0e10cSrcweir         drawLayout( *pLayout, rText, bTextLines );
7756cdf0e10cSrcweir         pLayout->Release();
7757cdf0e10cSrcweir     }
7758cdf0e10cSrcweir }
7759cdf0e10cSrcweir 
7760cdf0e10cSrcweir void PDFWriterImpl::drawTextArray( const Point& rPos, const String& rText, const sal_Int32* pDXArray, xub_StrLen nIndex, xub_StrLen nLen, bool bTextLines )
7761cdf0e10cSrcweir {
7762cdf0e10cSrcweir     MARK( "drawText with array" );
7763cdf0e10cSrcweir 
7764cdf0e10cSrcweir     updateGraphicsState();
7765cdf0e10cSrcweir 
7766cdf0e10cSrcweir     // get a layout from the OuputDevice's SalGraphics
7767cdf0e10cSrcweir     // this also enforces font substitution and sets the font on SalGraphics
7768cdf0e10cSrcweir     SalLayout* pLayout = m_pReferenceDevice->ImplLayout( rText, nIndex, nLen, rPos, 0, pDXArray );
7769cdf0e10cSrcweir     if( pLayout )
7770cdf0e10cSrcweir     {
7771cdf0e10cSrcweir         drawLayout( *pLayout, rText, bTextLines );
7772cdf0e10cSrcweir         pLayout->Release();
7773cdf0e10cSrcweir     }
7774cdf0e10cSrcweir }
7775cdf0e10cSrcweir 
7776cdf0e10cSrcweir void PDFWriterImpl::drawStretchText( const Point& rPos, sal_uLong nWidth, const String& rText, xub_StrLen nIndex, xub_StrLen nLen, bool bTextLines )
7777cdf0e10cSrcweir {
7778cdf0e10cSrcweir     MARK( "drawStretchText" );
7779cdf0e10cSrcweir 
7780cdf0e10cSrcweir     updateGraphicsState();
7781cdf0e10cSrcweir 
7782cdf0e10cSrcweir     // get a layout from the OuputDevice's SalGraphics
7783cdf0e10cSrcweir     // this also enforces font substitution and sets the font on SalGraphics
7784cdf0e10cSrcweir     SalLayout* pLayout = m_pReferenceDevice->ImplLayout( rText, nIndex, nLen, rPos, nWidth );
7785cdf0e10cSrcweir     if( pLayout )
7786cdf0e10cSrcweir     {
7787cdf0e10cSrcweir         drawLayout( *pLayout, rText, bTextLines );
7788cdf0e10cSrcweir         pLayout->Release();
7789cdf0e10cSrcweir     }
7790cdf0e10cSrcweir }
7791cdf0e10cSrcweir 
7792cdf0e10cSrcweir void PDFWriterImpl::drawText( const Rectangle& rRect, const String& rOrigStr, sal_uInt16 nStyle, bool bTextLines )
7793cdf0e10cSrcweir {
7794cdf0e10cSrcweir     long        nWidth          = rRect.GetWidth();
7795cdf0e10cSrcweir     long        nHeight         = rRect.GetHeight();
7796cdf0e10cSrcweir 
7797cdf0e10cSrcweir     if ( nWidth <= 0 || nHeight <= 0 )
7798cdf0e10cSrcweir         return;
7799cdf0e10cSrcweir 
7800cdf0e10cSrcweir     MARK( "drawText with rectangle" );
7801cdf0e10cSrcweir 
7802cdf0e10cSrcweir     updateGraphicsState();
7803cdf0e10cSrcweir 
7804cdf0e10cSrcweir     // clip with rectangle
7805cdf0e10cSrcweir     OStringBuffer aLine;
7806cdf0e10cSrcweir     aLine.append( "q " );
7807cdf0e10cSrcweir     m_aPages.back().appendRect( rRect, aLine );
7808cdf0e10cSrcweir     aLine.append( " W* n\n" );
7809cdf0e10cSrcweir     writeBuffer( aLine.getStr(), aLine.getLength() );
7810cdf0e10cSrcweir 
7811cdf0e10cSrcweir     // if disabled text is needed, put in here
7812cdf0e10cSrcweir 
7813cdf0e10cSrcweir     Point       aPos            = rRect.TopLeft();
7814cdf0e10cSrcweir 
7815cdf0e10cSrcweir     long		nTextHeight		= m_pReferenceDevice->GetTextHeight();
7816cdf0e10cSrcweir     xub_StrLen  nMnemonicPos    = STRING_NOTFOUND;
7817cdf0e10cSrcweir 
7818cdf0e10cSrcweir     String aStr = rOrigStr;
7819cdf0e10cSrcweir     if ( nStyle & TEXT_DRAW_MNEMONIC )
7820cdf0e10cSrcweir         aStr = m_pReferenceDevice->GetNonMnemonicString( aStr, nMnemonicPos );
7821cdf0e10cSrcweir 
7822cdf0e10cSrcweir     // multiline text
7823cdf0e10cSrcweir     if ( nStyle & TEXT_DRAW_MULTILINE )
7824cdf0e10cSrcweir     {
7825cdf0e10cSrcweir         XubString               aLastLine;
7826cdf0e10cSrcweir         ImplMultiTextLineInfo   aMultiLineInfo;
7827cdf0e10cSrcweir         ImplTextLineInfo*       pLineInfo;
7828cdf0e10cSrcweir         long                    nMaxTextWidth;
7829cdf0e10cSrcweir         xub_StrLen              i;
7830cdf0e10cSrcweir         xub_StrLen              nLines;
7831cdf0e10cSrcweir         xub_StrLen              nFormatLines;
7832cdf0e10cSrcweir 
7833cdf0e10cSrcweir         if ( nTextHeight )
7834cdf0e10cSrcweir         {
7835cdf0e10cSrcweir             ::vcl::DefaultTextLayout aLayout( *m_pReferenceDevice );
7836cdf0e10cSrcweir             nMaxTextWidth = OutputDevice::ImplGetTextLines( aMultiLineInfo, nWidth, aStr, nStyle, aLayout );
7837cdf0e10cSrcweir             nLines = (xub_StrLen)(nHeight/nTextHeight);
7838cdf0e10cSrcweir             nFormatLines = aMultiLineInfo.Count();
7839cdf0e10cSrcweir             if ( !nLines )
7840cdf0e10cSrcweir                 nLines = 1;
7841cdf0e10cSrcweir             if ( nFormatLines > nLines )
7842cdf0e10cSrcweir             {
7843cdf0e10cSrcweir                 if ( nStyle & TEXT_DRAW_ENDELLIPSIS )
7844cdf0e10cSrcweir                 {
7845cdf0e10cSrcweir                     // handle last line
7846cdf0e10cSrcweir                     nFormatLines = nLines-1;
7847cdf0e10cSrcweir 
7848cdf0e10cSrcweir                     pLineInfo = aMultiLineInfo.GetLine( nFormatLines );
7849cdf0e10cSrcweir                     aLastLine = aStr.Copy( pLineInfo->GetIndex() );
7850cdf0e10cSrcweir                     aLastLine.ConvertLineEnd( LINEEND_LF );
7851cdf0e10cSrcweir                     // replace line feed by space
7852cdf0e10cSrcweir                     xub_StrLen nLastLineLen = aLastLine.Len();
7853cdf0e10cSrcweir                     for ( i = 0; i < nLastLineLen; i++ )
7854cdf0e10cSrcweir                     {
7855cdf0e10cSrcweir                         if ( aLastLine.GetChar( i ) == _LF )
7856cdf0e10cSrcweir                             aLastLine.SetChar( i, ' ' );
7857cdf0e10cSrcweir                     }
7858cdf0e10cSrcweir                     aLastLine = m_pReferenceDevice->GetEllipsisString( aLastLine, nWidth, nStyle );
7859cdf0e10cSrcweir                     nStyle &= ~(TEXT_DRAW_VCENTER | TEXT_DRAW_BOTTOM);
7860cdf0e10cSrcweir                     nStyle |= TEXT_DRAW_TOP;
7861cdf0e10cSrcweir                 }
7862cdf0e10cSrcweir             }
7863cdf0e10cSrcweir 
7864cdf0e10cSrcweir             // vertical alignment
7865cdf0e10cSrcweir             if ( nStyle & TEXT_DRAW_BOTTOM )
7866cdf0e10cSrcweir                 aPos.Y() += nHeight-(nFormatLines*nTextHeight);
7867cdf0e10cSrcweir             else if ( nStyle & TEXT_DRAW_VCENTER )
7868cdf0e10cSrcweir                 aPos.Y() += (nHeight-(nFormatLines*nTextHeight))/2;
7869cdf0e10cSrcweir 
7870cdf0e10cSrcweir             // draw all lines excluding the last
7871cdf0e10cSrcweir             for ( i = 0; i < nFormatLines; i++ )
7872cdf0e10cSrcweir             {
7873cdf0e10cSrcweir                 pLineInfo = aMultiLineInfo.GetLine( i );
7874cdf0e10cSrcweir                 if ( nStyle & TEXT_DRAW_RIGHT )
7875cdf0e10cSrcweir                     aPos.X() += nWidth-pLineInfo->GetWidth();
7876cdf0e10cSrcweir                 else if ( nStyle & TEXT_DRAW_CENTER )
7877cdf0e10cSrcweir                     aPos.X() += (nWidth-pLineInfo->GetWidth())/2;
7878cdf0e10cSrcweir                 xub_StrLen nIndex   = pLineInfo->GetIndex();
7879cdf0e10cSrcweir                 xub_StrLen nLineLen = pLineInfo->GetLen();
7880cdf0e10cSrcweir                 drawText( aPos, aStr, nIndex, nLineLen, bTextLines );
7881cdf0e10cSrcweir                 // mnemonics should not appear in documents,
7882cdf0e10cSrcweir                 // if the need arises, put them in here
7883cdf0e10cSrcweir                 aPos.Y() += nTextHeight;
7884cdf0e10cSrcweir                 aPos.X() = rRect.Left();
7885cdf0e10cSrcweir             }
7886cdf0e10cSrcweir 
7887cdf0e10cSrcweir 
7888cdf0e10cSrcweir             // output last line left adjusted since it was shortened
7889cdf0e10cSrcweir             if ( aLastLine.Len() )
7890cdf0e10cSrcweir                 drawText( aPos, aLastLine, 0, STRING_LEN, bTextLines );
7891cdf0e10cSrcweir         }
7892cdf0e10cSrcweir     }
7893cdf0e10cSrcweir     else
7894cdf0e10cSrcweir     {
7895cdf0e10cSrcweir         long nTextWidth = m_pReferenceDevice->GetTextWidth( aStr );
7896cdf0e10cSrcweir 
7897cdf0e10cSrcweir         // Evt. Text kuerzen
7898cdf0e10cSrcweir         if ( nTextWidth > nWidth )
7899cdf0e10cSrcweir         {
7900cdf0e10cSrcweir             if ( nStyle & (TEXT_DRAW_ENDELLIPSIS | TEXT_DRAW_PATHELLIPSIS | TEXT_DRAW_NEWSELLIPSIS) )
7901cdf0e10cSrcweir             {
7902cdf0e10cSrcweir                 aStr = m_pReferenceDevice->GetEllipsisString( aStr, nWidth, nStyle );
7903cdf0e10cSrcweir                 nStyle &= ~(TEXT_DRAW_CENTER | TEXT_DRAW_RIGHT);
7904cdf0e10cSrcweir                 nStyle |= TEXT_DRAW_LEFT;
7905cdf0e10cSrcweir                 nTextWidth = m_pReferenceDevice->GetTextWidth( aStr );
7906cdf0e10cSrcweir             }
7907cdf0e10cSrcweir         }
7908cdf0e10cSrcweir 
7909cdf0e10cSrcweir         // vertical alignment
7910cdf0e10cSrcweir         if ( nStyle & TEXT_DRAW_RIGHT )
7911cdf0e10cSrcweir             aPos.X() += nWidth-nTextWidth;
7912cdf0e10cSrcweir         else if ( nStyle & TEXT_DRAW_CENTER )
7913cdf0e10cSrcweir             aPos.X() += (nWidth-nTextWidth)/2;
7914cdf0e10cSrcweir 
7915cdf0e10cSrcweir         if ( nStyle & TEXT_DRAW_BOTTOM )
7916cdf0e10cSrcweir             aPos.Y() += nHeight-nTextHeight;
7917cdf0e10cSrcweir         else if ( nStyle & TEXT_DRAW_VCENTER )
7918cdf0e10cSrcweir             aPos.Y() += (nHeight-nTextHeight)/2;
7919cdf0e10cSrcweir 
7920cdf0e10cSrcweir         // mnemonics should be inserted here if the need arises
7921cdf0e10cSrcweir 
7922cdf0e10cSrcweir         // draw the actual text
7923cdf0e10cSrcweir         drawText( aPos, aStr, 0, STRING_LEN, bTextLines );
7924cdf0e10cSrcweir     }
7925cdf0e10cSrcweir 
7926cdf0e10cSrcweir     // reset clip region to original value
7927cdf0e10cSrcweir     aLine.setLength( 0 );
7928cdf0e10cSrcweir     aLine.append( "Q\n" );
7929cdf0e10cSrcweir     writeBuffer( aLine.getStr(), aLine.getLength() );
7930cdf0e10cSrcweir }
7931cdf0e10cSrcweir 
7932cdf0e10cSrcweir void PDFWriterImpl::drawLine( const Point& rStart, const Point& rStop )
7933cdf0e10cSrcweir {
7934cdf0e10cSrcweir     MARK( "drawLine" );
7935cdf0e10cSrcweir 
7936cdf0e10cSrcweir     updateGraphicsState();
7937cdf0e10cSrcweir 
7938cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) )
7939cdf0e10cSrcweir         return;
7940cdf0e10cSrcweir 
7941cdf0e10cSrcweir     OStringBuffer aLine;
7942cdf0e10cSrcweir     m_aPages.back().appendPoint( rStart, aLine );
7943cdf0e10cSrcweir     aLine.append( " m " );
7944cdf0e10cSrcweir     m_aPages.back().appendPoint( rStop, aLine );
7945cdf0e10cSrcweir     aLine.append( " l S\n" );
7946cdf0e10cSrcweir 
7947cdf0e10cSrcweir     writeBuffer( aLine.getStr(), aLine.getLength() );
7948cdf0e10cSrcweir }
7949cdf0e10cSrcweir 
7950cdf0e10cSrcweir void PDFWriterImpl::drawLine( const Point& rStart, const Point& rStop, const LineInfo& rInfo )
7951cdf0e10cSrcweir {
7952cdf0e10cSrcweir     MARK( "drawLine with LineInfo" );
7953cdf0e10cSrcweir     updateGraphicsState();
7954cdf0e10cSrcweir 
7955cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) )
7956cdf0e10cSrcweir         return;
7957cdf0e10cSrcweir 
7958cdf0e10cSrcweir     if( rInfo.GetStyle() == LINE_SOLID && rInfo.GetWidth() < 2 )
7959cdf0e10cSrcweir     {
7960cdf0e10cSrcweir         drawLine( rStart, rStop );
7961cdf0e10cSrcweir         return;
7962cdf0e10cSrcweir     }
7963cdf0e10cSrcweir 
7964cdf0e10cSrcweir     OStringBuffer aLine;
7965cdf0e10cSrcweir 
7966cdf0e10cSrcweir     aLine.append( "q " );
7967cdf0e10cSrcweir     if( m_aPages.back().appendLineInfo( rInfo, aLine ) )
7968cdf0e10cSrcweir     {
7969cdf0e10cSrcweir         m_aPages.back().appendPoint( rStart, aLine );
7970cdf0e10cSrcweir         aLine.append( " m " );
7971cdf0e10cSrcweir         m_aPages.back().appendPoint( rStop, aLine );
7972cdf0e10cSrcweir         aLine.append( " l S Q\n" );
7973cdf0e10cSrcweir 
7974cdf0e10cSrcweir         writeBuffer( aLine.getStr(), aLine.getLength() );
7975cdf0e10cSrcweir     }
7976cdf0e10cSrcweir     else
7977cdf0e10cSrcweir     {
7978cdf0e10cSrcweir         PDFWriter::ExtLineInfo aInfo;
7979cdf0e10cSrcweir         convertLineInfoToExtLineInfo( rInfo, aInfo );
7980cdf0e10cSrcweir         Point aPolyPoints[2] = { rStart, rStop };
7981cdf0e10cSrcweir         Polygon aPoly( 2, aPolyPoints );
7982cdf0e10cSrcweir         drawPolyLine( aPoly, aInfo );
7983cdf0e10cSrcweir     }
7984cdf0e10cSrcweir }
7985cdf0e10cSrcweir 
7986cdf0e10cSrcweir void PDFWriterImpl::drawWaveLine( const Point& rStart, const Point& rStop, sal_Int32 nDelta, sal_Int32 nLineWidth )
7987cdf0e10cSrcweir {
7988cdf0e10cSrcweir     Point aDiff( rStop-rStart );
7989cdf0e10cSrcweir     double fLen = sqrt( (double)(aDiff.X()*aDiff.X() + aDiff.Y()*aDiff.Y()) );
7990cdf0e10cSrcweir     if( fLen < 1.0 )
7991cdf0e10cSrcweir         return;
7992cdf0e10cSrcweir 
7993cdf0e10cSrcweir     MARK( "drawWaveLine" );
7994cdf0e10cSrcweir     updateGraphicsState();
7995cdf0e10cSrcweir 
7996cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) )
7997cdf0e10cSrcweir         return;
7998cdf0e10cSrcweir 
7999cdf0e10cSrcweir     OStringBuffer aLine( 512 );
8000cdf0e10cSrcweir     aLine.append( "q " );
8001cdf0e10cSrcweir     m_aPages.back().appendMappedLength( nLineWidth, aLine, true );
8002cdf0e10cSrcweir     aLine.append( " w " );
8003cdf0e10cSrcweir 
8004cdf0e10cSrcweir     appendDouble( (double)aDiff.X()/fLen, aLine );
8005cdf0e10cSrcweir     aLine.append( ' ' );
8006cdf0e10cSrcweir     appendDouble( -(double)aDiff.Y()/fLen, aLine );
8007cdf0e10cSrcweir     aLine.append( ' ' );
8008cdf0e10cSrcweir     appendDouble( (double)aDiff.Y()/fLen, aLine );
8009cdf0e10cSrcweir     aLine.append( ' ' );
8010cdf0e10cSrcweir     appendDouble( (double)aDiff.X()/fLen, aLine );
8011cdf0e10cSrcweir     aLine.append( ' ' );
8012cdf0e10cSrcweir     m_aPages.back().appendPoint( rStart, aLine );
8013cdf0e10cSrcweir     aLine.append( " cm " );
8014cdf0e10cSrcweir     m_aPages.back().appendWaveLine( (sal_Int32)fLen, 0, nDelta, aLine );
8015cdf0e10cSrcweir     aLine.append( "Q\n" );
8016cdf0e10cSrcweir     writeBuffer( aLine.getStr(), aLine.getLength() );
8017cdf0e10cSrcweir }
8018cdf0e10cSrcweir 
8019cdf0e10cSrcweir #define WCONV( x ) m_pReferenceDevice->ImplDevicePixelToLogicWidth( x )
8020cdf0e10cSrcweir #define HCONV( x ) m_pReferenceDevice->ImplDevicePixelToLogicHeight( x )
8021cdf0e10cSrcweir 
8022cdf0e10cSrcweir void PDFWriterImpl::drawWaveTextLine( OStringBuffer& aLine, long nWidth, FontUnderline eTextLine, Color aColor, bool bIsAbove )
8023cdf0e10cSrcweir {
8024cdf0e10cSrcweir     // note: units in pFontEntry are ref device pixel
8025cdf0e10cSrcweir     ImplFontEntry*	pFontEntry = m_pReferenceDevice->mpFontEntry;
8026cdf0e10cSrcweir     long			nLineHeight = 0;
8027cdf0e10cSrcweir     long			nLinePos = 0;
8028cdf0e10cSrcweir 
8029cdf0e10cSrcweir     appendStrokingColor( aColor, aLine );
8030cdf0e10cSrcweir     aLine.append( "\n" );
8031cdf0e10cSrcweir 
8032cdf0e10cSrcweir     if ( bIsAbove )
8033cdf0e10cSrcweir     {
8034cdf0e10cSrcweir         if ( !pFontEntry->maMetric.mnAboveWUnderlineSize )
8035cdf0e10cSrcweir             m_pReferenceDevice->ImplInitAboveTextLineSize();
8036cdf0e10cSrcweir         nLineHeight = HCONV( pFontEntry->maMetric.mnAboveWUnderlineSize );
8037cdf0e10cSrcweir         nLinePos = HCONV( pFontEntry->maMetric.mnAboveWUnderlineOffset );
8038cdf0e10cSrcweir     }
8039cdf0e10cSrcweir     else
8040cdf0e10cSrcweir     {
8041cdf0e10cSrcweir         if ( !pFontEntry->maMetric.mnWUnderlineSize )
8042cdf0e10cSrcweir             m_pReferenceDevice->ImplInitTextLineSize();
8043cdf0e10cSrcweir         nLineHeight = HCONV( pFontEntry->maMetric.mnWUnderlineSize );
8044cdf0e10cSrcweir         nLinePos = HCONV( pFontEntry->maMetric.mnWUnderlineOffset );
8045cdf0e10cSrcweir     }
8046cdf0e10cSrcweir     if ( (eTextLine == UNDERLINE_SMALLWAVE) && (nLineHeight > 3) )
8047cdf0e10cSrcweir         nLineHeight = 3;
8048cdf0e10cSrcweir 
8049cdf0e10cSrcweir     long nLineWidth = getReferenceDevice()->mnDPIX/450;
8050cdf0e10cSrcweir     if ( ! nLineWidth )
8051cdf0e10cSrcweir         nLineWidth = 1;
8052cdf0e10cSrcweir 
8053cdf0e10cSrcweir     if ( eTextLine == UNDERLINE_BOLDWAVE )
8054cdf0e10cSrcweir         nLineWidth = 3*nLineWidth;
8055cdf0e10cSrcweir 
8056cdf0e10cSrcweir     m_aPages.back().appendMappedLength( (sal_Int32)nLineWidth, aLine );
8057cdf0e10cSrcweir     aLine.append( " w " );
8058cdf0e10cSrcweir 
8059cdf0e10cSrcweir     if ( eTextLine == UNDERLINE_DOUBLEWAVE )
8060cdf0e10cSrcweir     {
8061cdf0e10cSrcweir         long nOrgLineHeight = nLineHeight;
8062cdf0e10cSrcweir         nLineHeight /= 3;
8063cdf0e10cSrcweir         if ( nLineHeight < 2 )
8064cdf0e10cSrcweir         {
8065cdf0e10cSrcweir             if ( nOrgLineHeight > 1 )
8066cdf0e10cSrcweir                 nLineHeight = 2;
8067cdf0e10cSrcweir             else
8068cdf0e10cSrcweir                 nLineHeight = 1;
8069cdf0e10cSrcweir         }
8070cdf0e10cSrcweir         long nLineDY = nOrgLineHeight-(nLineHeight*2);
8071cdf0e10cSrcweir         if ( nLineDY < nLineWidth )
8072cdf0e10cSrcweir             nLineDY = nLineWidth;
8073cdf0e10cSrcweir         long nLineDY2 = nLineDY/2;
8074cdf0e10cSrcweir         if ( !nLineDY2 )
8075cdf0e10cSrcweir             nLineDY2 = 1;
8076cdf0e10cSrcweir 
8077cdf0e10cSrcweir         nLinePos -= nLineWidth-nLineDY2;
8078cdf0e10cSrcweir 
8079cdf0e10cSrcweir         m_aPages.back().appendWaveLine( nWidth, -nLinePos, 2*nLineHeight, aLine );
8080cdf0e10cSrcweir 
8081cdf0e10cSrcweir         nLinePos += nLineWidth+nLineDY;
8082cdf0e10cSrcweir         m_aPages.back().appendWaveLine( nWidth, -nLinePos, 2*nLineHeight, aLine );
8083cdf0e10cSrcweir     }
8084cdf0e10cSrcweir     else
8085cdf0e10cSrcweir     {
8086cdf0e10cSrcweir         if ( eTextLine != UNDERLINE_BOLDWAVE )
8087cdf0e10cSrcweir             nLinePos -= nLineWidth/2;
8088cdf0e10cSrcweir         m_aPages.back().appendWaveLine( nWidth, -nLinePos, nLineHeight, aLine );
8089cdf0e10cSrcweir     }
8090cdf0e10cSrcweir }
8091cdf0e10cSrcweir 
8092cdf0e10cSrcweir void PDFWriterImpl::drawStraightTextLine( OStringBuffer& aLine, long nWidth, FontUnderline eTextLine, Color aColor, bool bIsAbove )
8093cdf0e10cSrcweir {
8094cdf0e10cSrcweir     // note: units in pFontEntry are ref device pixel
8095cdf0e10cSrcweir     ImplFontEntry*	pFontEntry = m_pReferenceDevice->mpFontEntry;
8096cdf0e10cSrcweir     long			nLineHeight = 0;
8097cdf0e10cSrcweir     long			nLinePos  = 0;
8098cdf0e10cSrcweir     long			nLinePos2 = 0;
8099cdf0e10cSrcweir 
8100cdf0e10cSrcweir     if ( eTextLine > UNDERLINE_BOLDWAVE )
8101cdf0e10cSrcweir         eTextLine = UNDERLINE_SINGLE;
8102cdf0e10cSrcweir 
8103cdf0e10cSrcweir     switch ( eTextLine )
8104cdf0e10cSrcweir     {
8105cdf0e10cSrcweir         case UNDERLINE_SINGLE:
8106cdf0e10cSrcweir         case UNDERLINE_DOTTED:
8107cdf0e10cSrcweir         case UNDERLINE_DASH:
8108cdf0e10cSrcweir         case UNDERLINE_LONGDASH:
8109cdf0e10cSrcweir         case UNDERLINE_DASHDOT:
8110cdf0e10cSrcweir         case UNDERLINE_DASHDOTDOT:
8111cdf0e10cSrcweir             if ( bIsAbove )
8112cdf0e10cSrcweir             {
8113cdf0e10cSrcweir                 if ( !pFontEntry->maMetric.mnAboveUnderlineSize )
8114cdf0e10cSrcweir                     m_pReferenceDevice->ImplInitAboveTextLineSize();
8115cdf0e10cSrcweir                 nLineHeight = HCONV( pFontEntry->maMetric.mnAboveUnderlineSize );
8116cdf0e10cSrcweir                 nLinePos    = HCONV( pFontEntry->maMetric.mnAboveUnderlineOffset );
8117cdf0e10cSrcweir             }
8118cdf0e10cSrcweir             else
8119cdf0e10cSrcweir             {
8120cdf0e10cSrcweir                 if ( !pFontEntry->maMetric.mnUnderlineSize )
8121cdf0e10cSrcweir                     m_pReferenceDevice->ImplInitTextLineSize();
8122cdf0e10cSrcweir                 nLineHeight = HCONV( pFontEntry->maMetric.mnUnderlineSize );
8123cdf0e10cSrcweir                 nLinePos    = HCONV( pFontEntry->maMetric.mnUnderlineOffset );
8124cdf0e10cSrcweir             }
8125cdf0e10cSrcweir             break;
8126cdf0e10cSrcweir         case UNDERLINE_BOLD:
8127cdf0e10cSrcweir         case UNDERLINE_BOLDDOTTED:
8128cdf0e10cSrcweir         case UNDERLINE_BOLDDASH:
8129cdf0e10cSrcweir         case UNDERLINE_BOLDLONGDASH:
8130cdf0e10cSrcweir         case UNDERLINE_BOLDDASHDOT:
8131cdf0e10cSrcweir         case UNDERLINE_BOLDDASHDOTDOT:
8132cdf0e10cSrcweir             if ( bIsAbove )
8133cdf0e10cSrcweir             {
8134cdf0e10cSrcweir                 if ( !pFontEntry->maMetric.mnAboveBUnderlineSize )
8135cdf0e10cSrcweir                     m_pReferenceDevice->ImplInitAboveTextLineSize();
8136cdf0e10cSrcweir                 nLineHeight = HCONV( pFontEntry->maMetric.mnAboveBUnderlineSize );
8137cdf0e10cSrcweir                 nLinePos    = HCONV( pFontEntry->maMetric.mnAboveBUnderlineOffset );
8138cdf0e10cSrcweir             }
8139cdf0e10cSrcweir             else
8140cdf0e10cSrcweir             {
8141cdf0e10cSrcweir                 if ( !pFontEntry->maMetric.mnBUnderlineSize )
8142cdf0e10cSrcweir                     m_pReferenceDevice->ImplInitTextLineSize();
8143cdf0e10cSrcweir                 nLineHeight = HCONV( pFontEntry->maMetric.mnBUnderlineSize );
8144cdf0e10cSrcweir                 nLinePos    = HCONV( pFontEntry->maMetric.mnBUnderlineOffset );
8145cdf0e10cSrcweir                 nLinePos += nLineHeight/2;
8146cdf0e10cSrcweir             }
8147cdf0e10cSrcweir             break;
8148cdf0e10cSrcweir         case UNDERLINE_DOUBLE:
8149cdf0e10cSrcweir             if ( bIsAbove )
8150cdf0e10cSrcweir             {
8151cdf0e10cSrcweir                 if ( !pFontEntry->maMetric.mnAboveDUnderlineSize )
8152cdf0e10cSrcweir                     m_pReferenceDevice->ImplInitAboveTextLineSize();
8153cdf0e10cSrcweir                 nLineHeight = HCONV( pFontEntry->maMetric.mnAboveDUnderlineSize );
8154cdf0e10cSrcweir                 nLinePos    = HCONV( pFontEntry->maMetric.mnAboveDUnderlineOffset1 );
8155cdf0e10cSrcweir                 nLinePos2   = HCONV( pFontEntry->maMetric.mnAboveDUnderlineOffset2 );
8156cdf0e10cSrcweir             }
8157cdf0e10cSrcweir             else
8158cdf0e10cSrcweir             {
8159cdf0e10cSrcweir                 if ( !pFontEntry->maMetric.mnDUnderlineSize )
8160cdf0e10cSrcweir                     m_pReferenceDevice->ImplInitTextLineSize();
8161cdf0e10cSrcweir                 nLineHeight = HCONV( pFontEntry->maMetric.mnDUnderlineSize );
8162cdf0e10cSrcweir                 nLinePos    = HCONV( pFontEntry->maMetric.mnDUnderlineOffset1 );
8163cdf0e10cSrcweir                 nLinePos2   = HCONV( pFontEntry->maMetric.mnDUnderlineOffset2 );
8164cdf0e10cSrcweir             }
8165cdf0e10cSrcweir         default:
8166cdf0e10cSrcweir             break;
8167cdf0e10cSrcweir     }
8168cdf0e10cSrcweir 
8169cdf0e10cSrcweir     if ( nLineHeight )
8170cdf0e10cSrcweir     {
8171cdf0e10cSrcweir         m_aPages.back().appendMappedLength( (sal_Int32)nLineHeight, aLine, true );
8172cdf0e10cSrcweir         aLine.append( " w " );
8173cdf0e10cSrcweir         appendStrokingColor( aColor, aLine );
8174cdf0e10cSrcweir         aLine.append( "\n" );
8175cdf0e10cSrcweir 
8176cdf0e10cSrcweir         switch ( eTextLine )
8177cdf0e10cSrcweir         {
8178cdf0e10cSrcweir             case UNDERLINE_DOTTED:
8179cdf0e10cSrcweir             case UNDERLINE_BOLDDOTTED:
8180cdf0e10cSrcweir                 aLine.append( "[ " );
8181cdf0e10cSrcweir                 m_aPages.back().appendMappedLength( (sal_Int32)nLineHeight, aLine, false );
8182cdf0e10cSrcweir                 aLine.append( " ] 0 d\n" );
8183cdf0e10cSrcweir                 break;
8184cdf0e10cSrcweir             case UNDERLINE_DASH:
8185cdf0e10cSrcweir             case UNDERLINE_LONGDASH:
8186cdf0e10cSrcweir             case UNDERLINE_BOLDDASH:
8187cdf0e10cSrcweir             case UNDERLINE_BOLDLONGDASH:
8188cdf0e10cSrcweir                 {
8189cdf0e10cSrcweir                     sal_Int32 nDashLength = 4*nLineHeight;
8190cdf0e10cSrcweir                     sal_Int32 nVoidLength = 2*nLineHeight;
8191cdf0e10cSrcweir                     if ( ( eTextLine == UNDERLINE_LONGDASH ) || ( eTextLine == UNDERLINE_BOLDLONGDASH ) )
8192cdf0e10cSrcweir                         nDashLength = 8*nLineHeight;
8193cdf0e10cSrcweir 
8194cdf0e10cSrcweir                     aLine.append( "[ " );
8195cdf0e10cSrcweir                     m_aPages.back().appendMappedLength( nDashLength, aLine, false );
8196cdf0e10cSrcweir                     aLine.append( ' ' );
8197cdf0e10cSrcweir                     m_aPages.back().appendMappedLength( nVoidLength, aLine, false );
8198cdf0e10cSrcweir                     aLine.append( " ] 0 d\n" );
8199cdf0e10cSrcweir                 }
8200cdf0e10cSrcweir                 break;
8201cdf0e10cSrcweir             case UNDERLINE_DASHDOT:
8202cdf0e10cSrcweir             case UNDERLINE_BOLDDASHDOT:
8203cdf0e10cSrcweir                 {
8204cdf0e10cSrcweir                     sal_Int32 nDashLength = 4*nLineHeight;
8205cdf0e10cSrcweir                     sal_Int32 nVoidLength = 2*nLineHeight;
8206cdf0e10cSrcweir                     aLine.append( "[ " );
8207cdf0e10cSrcweir                     m_aPages.back().appendMappedLength( nDashLength, aLine, false );
8208cdf0e10cSrcweir                     aLine.append( ' ' );
8209cdf0e10cSrcweir                     m_aPages.back().appendMappedLength( nVoidLength, aLine, false );
8210cdf0e10cSrcweir                     aLine.append( ' ' );
8211cdf0e10cSrcweir                     m_aPages.back().appendMappedLength( (sal_Int32)nLineHeight, aLine, false );
8212cdf0e10cSrcweir                     aLine.append( ' ' );
8213cdf0e10cSrcweir                     m_aPages.back().appendMappedLength( nVoidLength, aLine, false );
8214cdf0e10cSrcweir                     aLine.append( " ] 0 d\n" );
8215cdf0e10cSrcweir                 }
8216cdf0e10cSrcweir                 break;
8217cdf0e10cSrcweir             case UNDERLINE_DASHDOTDOT:
8218cdf0e10cSrcweir             case UNDERLINE_BOLDDASHDOTDOT:
8219cdf0e10cSrcweir                 {
8220cdf0e10cSrcweir                     sal_Int32 nDashLength = 4*nLineHeight;
8221cdf0e10cSrcweir                     sal_Int32 nVoidLength = 2*nLineHeight;
8222cdf0e10cSrcweir                     aLine.append( "[ " );
8223cdf0e10cSrcweir                     m_aPages.back().appendMappedLength( nDashLength, aLine, false );
8224cdf0e10cSrcweir                     aLine.append( ' ' );
8225cdf0e10cSrcweir                     m_aPages.back().appendMappedLength( nVoidLength, aLine, false );
8226cdf0e10cSrcweir                     aLine.append( ' ' );
8227cdf0e10cSrcweir                     m_aPages.back().appendMappedLength( (sal_Int32)nLineHeight, aLine, false );
8228cdf0e10cSrcweir                     aLine.append( ' ' );
8229cdf0e10cSrcweir                     m_aPages.back().appendMappedLength( nVoidLength, aLine, false );
8230cdf0e10cSrcweir                     aLine.append( ' ' );
8231cdf0e10cSrcweir                     m_aPages.back().appendMappedLength( (sal_Int32)nLineHeight, aLine, false );
8232cdf0e10cSrcweir                     aLine.append( ' ' );
8233cdf0e10cSrcweir                     m_aPages.back().appendMappedLength( nVoidLength, aLine, false );
8234cdf0e10cSrcweir                     aLine.append( " ] 0 d\n" );
8235cdf0e10cSrcweir                 }
8236cdf0e10cSrcweir                 break;
8237cdf0e10cSrcweir             default:
8238cdf0e10cSrcweir                 break;
8239cdf0e10cSrcweir         }
8240cdf0e10cSrcweir 
8241cdf0e10cSrcweir         aLine.append( "0 " );
8242cdf0e10cSrcweir         m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos), aLine, true );
8243cdf0e10cSrcweir         aLine.append( " m " );
8244cdf0e10cSrcweir         m_aPages.back().appendMappedLength( (sal_Int32)nWidth, aLine, false );
8245cdf0e10cSrcweir         aLine.append( ' ' );
8246cdf0e10cSrcweir         m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos), aLine, true );
8247cdf0e10cSrcweir         aLine.append( " l S\n" );
8248cdf0e10cSrcweir         if ( eTextLine == UNDERLINE_DOUBLE )
8249cdf0e10cSrcweir         {
8250cdf0e10cSrcweir             aLine.append( "0 " );
8251cdf0e10cSrcweir             m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos2-nLineHeight), aLine, true );
8252cdf0e10cSrcweir             aLine.append( " m " );
8253cdf0e10cSrcweir             m_aPages.back().appendMappedLength( (sal_Int32)nWidth, aLine, false );
8254cdf0e10cSrcweir             aLine.append( ' ' );
8255cdf0e10cSrcweir             m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos2-nLineHeight), aLine, true );
8256cdf0e10cSrcweir             aLine.append( " l S\n" );
8257cdf0e10cSrcweir         }
8258cdf0e10cSrcweir     }
8259cdf0e10cSrcweir }
8260cdf0e10cSrcweir 
8261cdf0e10cSrcweir void PDFWriterImpl::drawStrikeoutLine( OStringBuffer& aLine, long nWidth, FontStrikeout eStrikeout, Color aColor )
8262cdf0e10cSrcweir {
8263cdf0e10cSrcweir     // note: units in pFontEntry are ref device pixel
8264cdf0e10cSrcweir     ImplFontEntry*	pFontEntry = m_pReferenceDevice->mpFontEntry;
8265cdf0e10cSrcweir     long			nLineHeight = 0;
8266cdf0e10cSrcweir     long			nLinePos  = 0;
8267cdf0e10cSrcweir     long			nLinePos2 = 0;
8268cdf0e10cSrcweir 
8269cdf0e10cSrcweir     if ( eStrikeout > STRIKEOUT_X )
8270cdf0e10cSrcweir         eStrikeout = STRIKEOUT_SINGLE;
8271cdf0e10cSrcweir 
8272cdf0e10cSrcweir     switch ( eStrikeout )
8273cdf0e10cSrcweir     {
8274cdf0e10cSrcweir         case STRIKEOUT_SINGLE:
8275cdf0e10cSrcweir             if ( !pFontEntry->maMetric.mnStrikeoutSize )
8276cdf0e10cSrcweir                 m_pReferenceDevice->ImplInitTextLineSize();
8277cdf0e10cSrcweir             nLineHeight = HCONV( pFontEntry->maMetric.mnStrikeoutSize );
8278cdf0e10cSrcweir             nLinePos    = HCONV( pFontEntry->maMetric.mnStrikeoutOffset );
8279cdf0e10cSrcweir             break;
8280cdf0e10cSrcweir         case STRIKEOUT_BOLD:
8281cdf0e10cSrcweir             if ( !pFontEntry->maMetric.mnBStrikeoutSize )
8282cdf0e10cSrcweir                 m_pReferenceDevice->ImplInitTextLineSize();
8283cdf0e10cSrcweir             nLineHeight = HCONV( pFontEntry->maMetric.mnBStrikeoutSize );
8284cdf0e10cSrcweir             nLinePos    = HCONV( pFontEntry->maMetric.mnBStrikeoutOffset );
8285cdf0e10cSrcweir             break;
8286cdf0e10cSrcweir         case STRIKEOUT_DOUBLE:
8287cdf0e10cSrcweir             if ( !pFontEntry->maMetric.mnDStrikeoutSize )
8288cdf0e10cSrcweir                 m_pReferenceDevice->ImplInitTextLineSize();
8289cdf0e10cSrcweir             nLineHeight = HCONV( pFontEntry->maMetric.mnDStrikeoutSize );
8290cdf0e10cSrcweir             nLinePos    = HCONV( pFontEntry->maMetric.mnDStrikeoutOffset1 );
8291cdf0e10cSrcweir             nLinePos2   = HCONV( pFontEntry->maMetric.mnDStrikeoutOffset2 );
8292cdf0e10cSrcweir             break;
8293cdf0e10cSrcweir         default:
8294cdf0e10cSrcweir             break;
8295cdf0e10cSrcweir     }
8296cdf0e10cSrcweir 
8297cdf0e10cSrcweir     if ( nLineHeight )
8298cdf0e10cSrcweir     {
8299cdf0e10cSrcweir         m_aPages.back().appendMappedLength( (sal_Int32)nLineHeight, aLine, true );
8300cdf0e10cSrcweir         aLine.append( " w " );
8301cdf0e10cSrcweir         appendStrokingColor( aColor, aLine );
8302cdf0e10cSrcweir         aLine.append( "\n" );
8303cdf0e10cSrcweir 
8304cdf0e10cSrcweir         aLine.append( "0 " );
8305cdf0e10cSrcweir         m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos), aLine, true );
8306cdf0e10cSrcweir         aLine.append( " m " );
8307cdf0e10cSrcweir         m_aPages.back().appendMappedLength( (sal_Int32)nWidth, aLine, true );
8308cdf0e10cSrcweir         aLine.append( ' ' );
8309cdf0e10cSrcweir         m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos), aLine, true );
8310cdf0e10cSrcweir         aLine.append( " l S\n" );
8311cdf0e10cSrcweir 
8312cdf0e10cSrcweir         if ( eStrikeout == STRIKEOUT_DOUBLE )
8313cdf0e10cSrcweir         {
8314cdf0e10cSrcweir             aLine.append( "0 " );
8315cdf0e10cSrcweir             m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos2-nLineHeight), aLine, true );
8316cdf0e10cSrcweir             aLine.append( " m " );
8317cdf0e10cSrcweir             m_aPages.back().appendMappedLength( (sal_Int32)nWidth, aLine, true );
8318cdf0e10cSrcweir             aLine.append( ' ' );
8319cdf0e10cSrcweir             m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos2-nLineHeight), aLine, true );
8320cdf0e10cSrcweir             aLine.append( " l S\n" );
8321cdf0e10cSrcweir         }
8322cdf0e10cSrcweir     }
8323cdf0e10cSrcweir }
8324cdf0e10cSrcweir 
8325cdf0e10cSrcweir void PDFWriterImpl::drawStrikeoutChar( const Point& rPos, long nWidth, FontStrikeout eStrikeout )
8326cdf0e10cSrcweir {
8327cdf0e10cSrcweir     String aStrikeoutChar = String::CreateFromAscii( eStrikeout == STRIKEOUT_SLASH ? "/" : "X" );
8328cdf0e10cSrcweir     String aStrikeout = aStrikeoutChar;
8329cdf0e10cSrcweir     while( m_pReferenceDevice->GetTextWidth( aStrikeout ) < nWidth )
8330cdf0e10cSrcweir         aStrikeout.Append( aStrikeout );
8331cdf0e10cSrcweir 
8332cdf0e10cSrcweir     // do not get broader than nWidth modulo 1 character
8333cdf0e10cSrcweir     while( m_pReferenceDevice->GetTextWidth( aStrikeout ) >= nWidth )
8334cdf0e10cSrcweir         aStrikeout.Erase( 0, 1 );
8335cdf0e10cSrcweir     aStrikeout.Append( aStrikeoutChar );
8336cdf0e10cSrcweir     sal_Bool bShadow = m_aCurrentPDFState.m_aFont.IsShadow();
8337cdf0e10cSrcweir     if ( bShadow )
8338cdf0e10cSrcweir     {
8339cdf0e10cSrcweir         Font aFont = m_aCurrentPDFState.m_aFont;
8340cdf0e10cSrcweir         aFont.SetShadow( sal_False );
8341cdf0e10cSrcweir         setFont( aFont );
8342cdf0e10cSrcweir         updateGraphicsState();
8343cdf0e10cSrcweir     }
8344cdf0e10cSrcweir 
8345cdf0e10cSrcweir     // strikeout string is left aligned non-CTL text
8346cdf0e10cSrcweir     sal_uLong nOrigTLM = m_pReferenceDevice->GetLayoutMode();
8347cdf0e10cSrcweir     m_pReferenceDevice->SetLayoutMode( TEXT_LAYOUT_BIDI_STRONG|TEXT_LAYOUT_COMPLEX_DISABLED );
8348cdf0e10cSrcweir     drawText( rPos, aStrikeout, 0, aStrikeout.Len(), false );
8349cdf0e10cSrcweir     m_pReferenceDevice->SetLayoutMode( nOrigTLM );
8350cdf0e10cSrcweir 
8351cdf0e10cSrcweir     if ( bShadow )
8352cdf0e10cSrcweir     {
8353cdf0e10cSrcweir         Font aFont = m_aCurrentPDFState.m_aFont;
8354cdf0e10cSrcweir         aFont.SetShadow( sal_True );
8355cdf0e10cSrcweir         setFont( aFont );
8356cdf0e10cSrcweir         updateGraphicsState();
8357cdf0e10cSrcweir     }
8358cdf0e10cSrcweir }
8359cdf0e10cSrcweir 
8360cdf0e10cSrcweir void PDFWriterImpl::drawTextLine( const Point& rPos, long nWidth, FontStrikeout eStrikeout, FontUnderline eUnderline, FontUnderline eOverline, bool bUnderlineAbove )
8361cdf0e10cSrcweir {
8362cdf0e10cSrcweir     if ( !nWidth ||
8363cdf0e10cSrcweir          ( ((eStrikeout == STRIKEOUT_NONE)||(eStrikeout == STRIKEOUT_DONTKNOW)) &&
8364cdf0e10cSrcweir            ((eUnderline == UNDERLINE_NONE)||(eUnderline == UNDERLINE_DONTKNOW)) &&
8365cdf0e10cSrcweir            ((eOverline  == UNDERLINE_NONE)||(eOverline  == UNDERLINE_DONTKNOW)) ) )
8366cdf0e10cSrcweir         return;
8367cdf0e10cSrcweir 
8368cdf0e10cSrcweir     MARK( "drawTextLine" );
8369cdf0e10cSrcweir     updateGraphicsState();
8370cdf0e10cSrcweir 
8371cdf0e10cSrcweir     // note: units in pFontEntry are ref device pixel
8372cdf0e10cSrcweir     ImplFontEntry*	pFontEntry = m_pReferenceDevice->mpFontEntry;
8373cdf0e10cSrcweir     Color			aUnderlineColor = m_aCurrentPDFState.m_aTextLineColor;
8374cdf0e10cSrcweir     Color			aOverlineColor  = m_aCurrentPDFState.m_aOverlineColor;
8375cdf0e10cSrcweir     Color			aStrikeoutColor = m_aCurrentPDFState.m_aFont.GetColor();
8376cdf0e10cSrcweir     bool			bStrikeoutDone = false;
8377cdf0e10cSrcweir     bool			bUnderlineDone = false;
8378cdf0e10cSrcweir     bool			bOverlineDone  = false;
8379cdf0e10cSrcweir 
8380cdf0e10cSrcweir     if ( (eStrikeout == STRIKEOUT_SLASH) || (eStrikeout == STRIKEOUT_X) )
8381cdf0e10cSrcweir     {
8382cdf0e10cSrcweir         drawStrikeoutChar( rPos, nWidth, eStrikeout );
8383cdf0e10cSrcweir         bStrikeoutDone = true;
8384cdf0e10cSrcweir     }
8385cdf0e10cSrcweir 
8386cdf0e10cSrcweir     Point aPos( rPos );
8387cdf0e10cSrcweir     TextAlign eAlign = m_aCurrentPDFState.m_aFont.GetAlign();
8388cdf0e10cSrcweir     if( eAlign == ALIGN_TOP )
8389cdf0e10cSrcweir         aPos.Y() += HCONV( pFontEntry->maMetric.mnAscent );
8390cdf0e10cSrcweir     else if( eAlign == ALIGN_BOTTOM )
8391cdf0e10cSrcweir         aPos.Y() -= HCONV( pFontEntry->maMetric.mnDescent );
8392cdf0e10cSrcweir 
8393cdf0e10cSrcweir     OStringBuffer aLine( 512 );
8394cdf0e10cSrcweir     // save GS
8395cdf0e10cSrcweir     aLine.append( "q " );
8396cdf0e10cSrcweir 
8397cdf0e10cSrcweir     // rotate and translate matrix
8398cdf0e10cSrcweir     double fAngle = (double)m_aCurrentPDFState.m_aFont.GetOrientation() * M_PI / 1800.0;
8399cdf0e10cSrcweir     Matrix3 aMat;
8400cdf0e10cSrcweir     aMat.rotate( fAngle );
8401cdf0e10cSrcweir     aMat.translate( aPos.X(), aPos.Y() );
8402cdf0e10cSrcweir     aMat.append( m_aPages.back(), aLine );
8403cdf0e10cSrcweir     aLine.append( " cm\n" );
8404cdf0e10cSrcweir 
8405cdf0e10cSrcweir     if ( aUnderlineColor.GetTransparency() != 0 )
8406cdf0e10cSrcweir         aUnderlineColor = aStrikeoutColor;
8407cdf0e10cSrcweir 
8408cdf0e10cSrcweir     if ( (eUnderline == UNDERLINE_SMALLWAVE) ||
8409cdf0e10cSrcweir          (eUnderline == UNDERLINE_WAVE) ||
8410cdf0e10cSrcweir          (eUnderline == UNDERLINE_DOUBLEWAVE) ||
8411cdf0e10cSrcweir          (eUnderline == UNDERLINE_BOLDWAVE) )
8412cdf0e10cSrcweir     {
8413cdf0e10cSrcweir         drawWaveTextLine( aLine, nWidth, eUnderline, aUnderlineColor, bUnderlineAbove );
8414cdf0e10cSrcweir         bUnderlineDone = true;
8415cdf0e10cSrcweir     }
8416cdf0e10cSrcweir 
8417cdf0e10cSrcweir     if ( (eOverline == UNDERLINE_SMALLWAVE) ||
8418cdf0e10cSrcweir          (eOverline == UNDERLINE_WAVE) ||
8419cdf0e10cSrcweir          (eOverline == UNDERLINE_DOUBLEWAVE) ||
8420cdf0e10cSrcweir          (eOverline == UNDERLINE_BOLDWAVE) )
8421cdf0e10cSrcweir     {
8422cdf0e10cSrcweir         drawWaveTextLine( aLine, nWidth, eOverline, aOverlineColor, true );
8423cdf0e10cSrcweir         bOverlineDone = true;
8424cdf0e10cSrcweir     }
8425cdf0e10cSrcweir 
8426cdf0e10cSrcweir     if ( !bUnderlineDone )
8427cdf0e10cSrcweir     {
8428cdf0e10cSrcweir         drawStraightTextLine( aLine, nWidth, eUnderline, aUnderlineColor, bUnderlineAbove );
8429cdf0e10cSrcweir     }
8430cdf0e10cSrcweir 
8431cdf0e10cSrcweir     if ( !bOverlineDone )
8432cdf0e10cSrcweir     {
8433cdf0e10cSrcweir         drawStraightTextLine( aLine, nWidth, eOverline, aOverlineColor, true );
8434cdf0e10cSrcweir     }
8435cdf0e10cSrcweir 
8436cdf0e10cSrcweir     if ( !bStrikeoutDone )
8437cdf0e10cSrcweir     {
8438cdf0e10cSrcweir         drawStrikeoutLine( aLine, nWidth, eStrikeout, aStrikeoutColor );
8439cdf0e10cSrcweir     }
8440cdf0e10cSrcweir 
8441cdf0e10cSrcweir     aLine.append( "Q\n" );
8442cdf0e10cSrcweir     writeBuffer( aLine.getStr(), aLine.getLength() );
8443cdf0e10cSrcweir }
8444cdf0e10cSrcweir 
8445cdf0e10cSrcweir void PDFWriterImpl::drawPolygon( const Polygon& rPoly )
8446cdf0e10cSrcweir {
8447cdf0e10cSrcweir     MARK( "drawPolygon" );
8448cdf0e10cSrcweir 
8449cdf0e10cSrcweir     updateGraphicsState();
8450cdf0e10cSrcweir 
8451cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) &&
8452cdf0e10cSrcweir         m_aGraphicsStack.front().m_aFillColor == Color( COL_TRANSPARENT ) )
8453cdf0e10cSrcweir         return;
8454cdf0e10cSrcweir 
8455cdf0e10cSrcweir     int nPoints = rPoly.GetSize();
8456cdf0e10cSrcweir     OStringBuffer aLine( 20 * nPoints );
8457cdf0e10cSrcweir     m_aPages.back().appendPolygon( rPoly, aLine );
8458cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) &&
8459cdf0e10cSrcweir         m_aGraphicsStack.front().m_aFillColor != Color( COL_TRANSPARENT ) )
8460cdf0e10cSrcweir         aLine.append( "B*\n" );
8461cdf0e10cSrcweir     else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
8462cdf0e10cSrcweir         aLine.append( "S\n" );
8463cdf0e10cSrcweir     else
8464cdf0e10cSrcweir         aLine.append( "f*\n" );
8465cdf0e10cSrcweir 
8466cdf0e10cSrcweir     writeBuffer( aLine.getStr(), aLine.getLength() );
8467cdf0e10cSrcweir }
8468cdf0e10cSrcweir 
8469cdf0e10cSrcweir void PDFWriterImpl::drawPolyPolygon( const PolyPolygon& rPolyPoly )
8470cdf0e10cSrcweir {
8471cdf0e10cSrcweir     MARK( "drawPolyPolygon" );
8472cdf0e10cSrcweir 
8473cdf0e10cSrcweir     updateGraphicsState();
8474cdf0e10cSrcweir 
8475cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) &&
8476cdf0e10cSrcweir         m_aGraphicsStack.front().m_aFillColor == Color( COL_TRANSPARENT ) )
8477cdf0e10cSrcweir         return;
8478cdf0e10cSrcweir 
8479cdf0e10cSrcweir     int nPolygons = rPolyPoly.Count();
8480cdf0e10cSrcweir 
8481cdf0e10cSrcweir     OStringBuffer aLine( 40 * nPolygons );
8482cdf0e10cSrcweir     m_aPages.back().appendPolyPolygon( rPolyPoly, aLine );
8483cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) &&
8484cdf0e10cSrcweir         m_aGraphicsStack.front().m_aFillColor != Color( COL_TRANSPARENT ) )
8485cdf0e10cSrcweir         aLine.append( "B*\n" );
8486cdf0e10cSrcweir     else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
8487cdf0e10cSrcweir         aLine.append( "S\n" );
8488cdf0e10cSrcweir     else
8489cdf0e10cSrcweir         aLine.append( "f*\n" );
8490cdf0e10cSrcweir 
8491cdf0e10cSrcweir     writeBuffer( aLine.getStr(), aLine.getLength() );
8492cdf0e10cSrcweir }
8493cdf0e10cSrcweir 
8494cdf0e10cSrcweir void PDFWriterImpl::drawTransparent( const PolyPolygon& rPolyPoly, sal_uInt32 nTransparentPercent )
8495cdf0e10cSrcweir {
8496cdf0e10cSrcweir     DBG_ASSERT( nTransparentPercent <= 100, "invalid alpha value" );
8497cdf0e10cSrcweir     nTransparentPercent = nTransparentPercent % 100;
8498cdf0e10cSrcweir 
8499cdf0e10cSrcweir     MARK( "drawTransparent" );
8500cdf0e10cSrcweir 
8501cdf0e10cSrcweir     updateGraphicsState();
8502cdf0e10cSrcweir 
8503cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) &&
8504cdf0e10cSrcweir         m_aGraphicsStack.front().m_aFillColor == Color( COL_TRANSPARENT ) )
8505cdf0e10cSrcweir         return;
8506cdf0e10cSrcweir 
8507cdf0e10cSrcweir     if( m_bIsPDF_A1 || m_aContext.Version < PDFWriter::PDF_1_4 )
8508cdf0e10cSrcweir     {
8509cdf0e10cSrcweir         m_aErrors.insert( m_bIsPDF_A1 ?
8510cdf0e10cSrcweir                           PDFWriter::Warning_Transparency_Omitted_PDFA :
8511cdf0e10cSrcweir                           PDFWriter::Warning_Transparency_Omitted_PDF13 );
8512cdf0e10cSrcweir 
8513cdf0e10cSrcweir         drawPolyPolygon( rPolyPoly );
8514cdf0e10cSrcweir         return;
8515cdf0e10cSrcweir     }
8516cdf0e10cSrcweir 
8517cdf0e10cSrcweir     // create XObject
8518cdf0e10cSrcweir     m_aTransparentObjects.push_back( TransparencyEmit() );
8519cdf0e10cSrcweir     // FIXME: polygons with beziers may yield incorrect bound rect
8520cdf0e10cSrcweir     m_aTransparentObjects.back().m_aBoundRect	  = rPolyPoly.GetBoundRect();
8521cdf0e10cSrcweir     // convert rectangle to default user space
8522cdf0e10cSrcweir     m_aPages.back().convertRect( m_aTransparentObjects.back().m_aBoundRect );
8523cdf0e10cSrcweir     m_aTransparentObjects.back().m_nObject		    = createObject();
8524cdf0e10cSrcweir     m_aTransparentObjects.back().m_nExtGStateObject = createObject();
8525cdf0e10cSrcweir     m_aTransparentObjects.back().m_fAlpha		    = (double)(100-nTransparentPercent) / 100.0;
8526cdf0e10cSrcweir     m_aTransparentObjects.back().m_pContentStream   = new SvMemoryStream( 256, 256 );
8527cdf0e10cSrcweir     // create XObject's content stream
8528cdf0e10cSrcweir     OStringBuffer aContent( 256 );
8529cdf0e10cSrcweir     m_aPages.back().appendPolyPolygon( rPolyPoly, aContent );
8530cdf0e10cSrcweir     if( m_aCurrentPDFState.m_aLineColor != Color( COL_TRANSPARENT ) &&
8531cdf0e10cSrcweir         m_aCurrentPDFState.m_aFillColor != Color( COL_TRANSPARENT ) )
8532cdf0e10cSrcweir         aContent.append( " B*\n" );
8533cdf0e10cSrcweir     else if( m_aCurrentPDFState.m_aLineColor != Color( COL_TRANSPARENT ) )
8534cdf0e10cSrcweir         aContent.append( " S\n" );
8535cdf0e10cSrcweir     else
8536cdf0e10cSrcweir         aContent.append( " f*\n" );
8537cdf0e10cSrcweir     m_aTransparentObjects.back().m_pContentStream->Write( aContent.getStr(), aContent.getLength() );
8538cdf0e10cSrcweir 
8539cdf0e10cSrcweir     OStringBuffer aObjName( 16 );
8540cdf0e10cSrcweir     aObjName.append( "Tr" );
8541cdf0e10cSrcweir     aObjName.append( m_aTransparentObjects.back().m_nObject );
8542cdf0e10cSrcweir     OString aTrName( aObjName.makeStringAndClear() );
8543cdf0e10cSrcweir     aObjName.append( "EGS" );
8544cdf0e10cSrcweir     aObjName.append( m_aTransparentObjects.back().m_nExtGStateObject );
8545cdf0e10cSrcweir     OString aExtName( aObjName.makeStringAndClear() );
8546cdf0e10cSrcweir 
8547cdf0e10cSrcweir     OStringBuffer aLine( 80 );
8548cdf0e10cSrcweir     // insert XObject
8549cdf0e10cSrcweir     aLine.append( "q /" );
8550cdf0e10cSrcweir     aLine.append( aExtName );
8551cdf0e10cSrcweir     aLine.append( " gs /" );
8552cdf0e10cSrcweir     aLine.append( aTrName );
8553cdf0e10cSrcweir     aLine.append( " Do Q\n" );
8554cdf0e10cSrcweir     writeBuffer( aLine.getStr(), aLine.getLength() );
8555cdf0e10cSrcweir 
8556cdf0e10cSrcweir     pushResource( ResXObject, aTrName, m_aTransparentObjects.back().m_nObject );
8557cdf0e10cSrcweir     pushResource( ResExtGState, aExtName, m_aTransparentObjects.back().m_nExtGStateObject );
8558cdf0e10cSrcweir }
8559cdf0e10cSrcweir 
8560cdf0e10cSrcweir void PDFWriterImpl::pushResource( ResourceKind eKind, const OString& rResource, sal_Int32 nObject )
8561cdf0e10cSrcweir {
8562cdf0e10cSrcweir     if( nObject >= 0 )
8563cdf0e10cSrcweir     {
8564cdf0e10cSrcweir         switch( eKind )
8565cdf0e10cSrcweir         {
8566cdf0e10cSrcweir             case ResXObject:
8567cdf0e10cSrcweir                 m_aGlobalResourceDict.m_aXObjects[ rResource ] = nObject;
8568cdf0e10cSrcweir                 if( ! m_aOutputStreams.empty() )
8569cdf0e10cSrcweir                     m_aOutputStreams.front().m_aResourceDict.m_aXObjects[ rResource ] = nObject;
8570cdf0e10cSrcweir                 break;
8571cdf0e10cSrcweir             case ResExtGState:
8572cdf0e10cSrcweir                 m_aGlobalResourceDict.m_aExtGStates[ rResource ] = nObject;
8573cdf0e10cSrcweir                 if( ! m_aOutputStreams.empty() )
8574cdf0e10cSrcweir                     m_aOutputStreams.front().m_aResourceDict.m_aExtGStates[ rResource ] = nObject;
8575cdf0e10cSrcweir                 break;
8576cdf0e10cSrcweir             case ResShading:
8577cdf0e10cSrcweir                 m_aGlobalResourceDict.m_aShadings[ rResource ] = nObject;
8578cdf0e10cSrcweir                 if( ! m_aOutputStreams.empty() )
8579cdf0e10cSrcweir                     m_aOutputStreams.front().m_aResourceDict.m_aShadings[ rResource ] = nObject;
8580cdf0e10cSrcweir                 break;
8581cdf0e10cSrcweir             case ResPattern:
8582cdf0e10cSrcweir                 m_aGlobalResourceDict.m_aPatterns[ rResource ] = nObject;
8583cdf0e10cSrcweir                 if( ! m_aOutputStreams.empty() )
8584cdf0e10cSrcweir                     m_aOutputStreams.front().m_aResourceDict.m_aPatterns[ rResource ] = nObject;
8585cdf0e10cSrcweir                 break;
8586cdf0e10cSrcweir         }
8587cdf0e10cSrcweir     }
8588cdf0e10cSrcweir }
8589cdf0e10cSrcweir 
8590cdf0e10cSrcweir void PDFWriterImpl::beginRedirect( SvStream* pStream, const Rectangle& rTargetRect )
8591cdf0e10cSrcweir {
8592cdf0e10cSrcweir     push( PUSH_ALL );
8593cdf0e10cSrcweir 
8594cdf0e10cSrcweir     // force reemitting clip region
8595cdf0e10cSrcweir     clearClipRegion();
8596cdf0e10cSrcweir     updateGraphicsState();
8597cdf0e10cSrcweir 
8598cdf0e10cSrcweir     m_aOutputStreams.push_front( StreamRedirect() );
8599cdf0e10cSrcweir     m_aOutputStreams.front().m_pStream = pStream;
8600cdf0e10cSrcweir     m_aOutputStreams.front().m_aMapMode = m_aMapMode;
8601cdf0e10cSrcweir 
8602cdf0e10cSrcweir     if( !rTargetRect.IsEmpty() )
8603cdf0e10cSrcweir     {
8604cdf0e10cSrcweir         m_aOutputStreams.front().m_aTargetRect =
8605cdf0e10cSrcweir             lcl_convert( m_aGraphicsStack.front().m_aMapMode,
8606cdf0e10cSrcweir                          m_aMapMode,
8607cdf0e10cSrcweir                          getReferenceDevice(),
8608cdf0e10cSrcweir                          rTargetRect );
8609cdf0e10cSrcweir         Point aDelta = m_aOutputStreams.front().m_aTargetRect.BottomLeft();
8610cdf0e10cSrcweir         long nPageHeight = pointToPixel(m_aPages[m_nCurrentPage].getHeight());
8611cdf0e10cSrcweir         aDelta.Y() = -(nPageHeight - m_aOutputStreams.front().m_aTargetRect.Bottom());
8612cdf0e10cSrcweir         m_aMapMode.SetOrigin( m_aMapMode.GetOrigin() + aDelta );
8613cdf0e10cSrcweir     }
8614cdf0e10cSrcweir 
8615cdf0e10cSrcweir     // setup graphics state for independent object stream
8616cdf0e10cSrcweir 
8617cdf0e10cSrcweir     // force reemitting colors
8618cdf0e10cSrcweir     m_aCurrentPDFState.m_aLineColor = Color( COL_TRANSPARENT );
8619cdf0e10cSrcweir     m_aCurrentPDFState.m_aFillColor = Color( COL_TRANSPARENT );
8620cdf0e10cSrcweir }
8621cdf0e10cSrcweir 
8622cdf0e10cSrcweir Rectangle PDFWriterImpl::getRedirectTargetRect() const
8623cdf0e10cSrcweir {
8624cdf0e10cSrcweir     return m_aOutputStreams.empty() ? Rectangle() : m_aOutputStreams.front().m_aTargetRect;
8625cdf0e10cSrcweir }
8626cdf0e10cSrcweir 
8627cdf0e10cSrcweir SvStream* PDFWriterImpl::endRedirect()
8628cdf0e10cSrcweir {
8629cdf0e10cSrcweir     SvStream* pStream = NULL;
8630cdf0e10cSrcweir     if( ! m_aOutputStreams.empty() )
8631cdf0e10cSrcweir     {
8632cdf0e10cSrcweir         pStream		= m_aOutputStreams.front().m_pStream;
8633cdf0e10cSrcweir         m_aMapMode	= m_aOutputStreams.front().m_aMapMode;
8634cdf0e10cSrcweir         m_aOutputStreams.pop_front();
8635cdf0e10cSrcweir     }
8636cdf0e10cSrcweir 
8637cdf0e10cSrcweir     pop();
8638cdf0e10cSrcweir     // force reemitting colors and clip region
8639cdf0e10cSrcweir     clearClipRegion();
8640cdf0e10cSrcweir     m_aCurrentPDFState.m_bClipRegion = m_aGraphicsStack.front().m_bClipRegion;
8641cdf0e10cSrcweir     m_aCurrentPDFState.m_aClipRegion = m_aGraphicsStack.front().m_aClipRegion;
8642cdf0e10cSrcweir     m_aCurrentPDFState.m_aLineColor = Color( COL_TRANSPARENT );
8643cdf0e10cSrcweir     m_aCurrentPDFState.m_aFillColor = Color( COL_TRANSPARENT );
8644cdf0e10cSrcweir 
8645cdf0e10cSrcweir     updateGraphicsState();
8646cdf0e10cSrcweir 
8647cdf0e10cSrcweir     return pStream;
8648cdf0e10cSrcweir }
8649cdf0e10cSrcweir 
8650cdf0e10cSrcweir void PDFWriterImpl::beginTransparencyGroup()
8651cdf0e10cSrcweir {
8652cdf0e10cSrcweir     updateGraphicsState();
8653cdf0e10cSrcweir     if( m_aContext.Version >= PDFWriter::PDF_1_4 )
8654cdf0e10cSrcweir         beginRedirect( new SvMemoryStream( 1024, 1024 ), Rectangle() );
8655cdf0e10cSrcweir }
8656cdf0e10cSrcweir 
8657cdf0e10cSrcweir void PDFWriterImpl::endTransparencyGroup( const Rectangle& rBoundingBox, sal_uInt32 nTransparentPercent )
8658cdf0e10cSrcweir {
8659cdf0e10cSrcweir     DBG_ASSERT( nTransparentPercent <= 100, "invalid alpha value" );
8660cdf0e10cSrcweir     nTransparentPercent = nTransparentPercent % 100;
8661cdf0e10cSrcweir 
8662cdf0e10cSrcweir     if( m_aContext.Version >= PDFWriter::PDF_1_4 )
8663cdf0e10cSrcweir     {
8664cdf0e10cSrcweir         // create XObject
8665cdf0e10cSrcweir         m_aTransparentObjects.push_back( TransparencyEmit() );
8666cdf0e10cSrcweir         m_aTransparentObjects.back().m_aBoundRect	= rBoundingBox;
8667cdf0e10cSrcweir         // convert rectangle to default user space
8668cdf0e10cSrcweir         m_aPages.back().convertRect( m_aTransparentObjects.back().m_aBoundRect );
8669cdf0e10cSrcweir         m_aTransparentObjects.back().m_nObject		= createObject();
8670cdf0e10cSrcweir         m_aTransparentObjects.back().m_fAlpha		= (double)(100-nTransparentPercent) / 100.0;
8671cdf0e10cSrcweir         // get XObject's content stream
8672cdf0e10cSrcweir         m_aTransparentObjects.back().m_pContentStream = static_cast<SvMemoryStream*>(endRedirect());
8673cdf0e10cSrcweir         m_aTransparentObjects.back().m_nExtGStateObject = createObject();
8674cdf0e10cSrcweir 
8675cdf0e10cSrcweir         OStringBuffer aObjName( 16 );
8676cdf0e10cSrcweir         aObjName.append( "Tr" );
8677cdf0e10cSrcweir         aObjName.append( m_aTransparentObjects.back().m_nObject );
8678cdf0e10cSrcweir         OString aTrName( aObjName.makeStringAndClear() );
8679cdf0e10cSrcweir         aObjName.append( "EGS" );
8680cdf0e10cSrcweir         aObjName.append( m_aTransparentObjects.back().m_nExtGStateObject );
8681cdf0e10cSrcweir         OString aExtName( aObjName.makeStringAndClear() );
8682cdf0e10cSrcweir 
8683cdf0e10cSrcweir         OStringBuffer aLine( 80 );
8684cdf0e10cSrcweir         // insert XObject
8685cdf0e10cSrcweir         aLine.append( "q /" );
8686cdf0e10cSrcweir         aLine.append( aExtName );
8687cdf0e10cSrcweir         aLine.append( " gs /" );
8688cdf0e10cSrcweir         aLine.append( aTrName );
8689cdf0e10cSrcweir         aLine.append( " Do Q\n" );
8690cdf0e10cSrcweir         writeBuffer( aLine.getStr(), aLine.getLength() );
8691cdf0e10cSrcweir 
8692cdf0e10cSrcweir         pushResource( ResXObject, aTrName, m_aTransparentObjects.back().m_nObject );
8693cdf0e10cSrcweir         pushResource( ResExtGState, aExtName, m_aTransparentObjects.back().m_nExtGStateObject );
8694cdf0e10cSrcweir     }
8695cdf0e10cSrcweir }
8696cdf0e10cSrcweir 
8697cdf0e10cSrcweir void PDFWriterImpl::endTransparencyGroup( const Rectangle& rBoundingBox, const Bitmap& rAlphaMask )
8698cdf0e10cSrcweir {
8699cdf0e10cSrcweir     if( m_aContext.Version >= PDFWriter::PDF_1_4 )
8700cdf0e10cSrcweir     {
8701cdf0e10cSrcweir         // create XObject
8702cdf0e10cSrcweir         m_aTransparentObjects.push_back( TransparencyEmit() );
8703cdf0e10cSrcweir         m_aTransparentObjects.back().m_aBoundRect	= rBoundingBox;
8704cdf0e10cSrcweir         // convert rectangle to default user space
8705cdf0e10cSrcweir         m_aPages.back().convertRect( m_aTransparentObjects.back().m_aBoundRect );
8706cdf0e10cSrcweir         m_aTransparentObjects.back().m_nObject		= createObject();
8707cdf0e10cSrcweir         m_aTransparentObjects.back().m_fAlpha		= 0.0;
8708cdf0e10cSrcweir         // get XObject's content stream
8709cdf0e10cSrcweir         m_aTransparentObjects.back().m_pContentStream = static_cast<SvMemoryStream*>(endRedirect());
8710cdf0e10cSrcweir         m_aTransparentObjects.back().m_nExtGStateObject = createObject();
8711cdf0e10cSrcweir 
8712cdf0e10cSrcweir         // draw soft mask
8713cdf0e10cSrcweir         beginRedirect( new SvMemoryStream( 1024, 1024 ), Rectangle() );
8714cdf0e10cSrcweir         drawBitmap( rBoundingBox.TopLeft(), rBoundingBox.GetSize(), rAlphaMask );
8715cdf0e10cSrcweir         m_aTransparentObjects.back().m_pSoftMaskStream = static_cast<SvMemoryStream*>(endRedirect());
8716cdf0e10cSrcweir 
8717cdf0e10cSrcweir         OStringBuffer aObjName( 16 );
8718cdf0e10cSrcweir         aObjName.append( "Tr" );
8719cdf0e10cSrcweir         aObjName.append( m_aTransparentObjects.back().m_nObject );
8720cdf0e10cSrcweir         OString aTrName( aObjName.makeStringAndClear() );
8721cdf0e10cSrcweir         aObjName.append( "EGS" );
8722cdf0e10cSrcweir         aObjName.append( m_aTransparentObjects.back().m_nExtGStateObject );
8723cdf0e10cSrcweir         OString aExtName( aObjName.makeStringAndClear() );
8724cdf0e10cSrcweir 
8725cdf0e10cSrcweir         OStringBuffer aLine( 80 );
8726cdf0e10cSrcweir         // insert XObject
8727cdf0e10cSrcweir         aLine.append( "q /" );
8728cdf0e10cSrcweir         aLine.append( aExtName );
8729cdf0e10cSrcweir         aLine.append( " gs /" );
8730cdf0e10cSrcweir         aLine.append( aTrName );
8731cdf0e10cSrcweir         aLine.append( " Do Q\n" );
8732cdf0e10cSrcweir         writeBuffer( aLine.getStr(), aLine.getLength() );
8733cdf0e10cSrcweir 
8734cdf0e10cSrcweir         pushResource( ResXObject, aTrName, m_aTransparentObjects.back().m_nObject );
8735cdf0e10cSrcweir         pushResource( ResExtGState, aExtName, m_aTransparentObjects.back().m_nExtGStateObject );
8736cdf0e10cSrcweir     }
8737cdf0e10cSrcweir }
8738cdf0e10cSrcweir 
8739cdf0e10cSrcweir void PDFWriterImpl::drawRectangle( const Rectangle& rRect )
8740cdf0e10cSrcweir {
8741cdf0e10cSrcweir     MARK( "drawRectangle" );
8742cdf0e10cSrcweir 
8743cdf0e10cSrcweir     updateGraphicsState();
8744cdf0e10cSrcweir 
8745cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) &&
8746cdf0e10cSrcweir         m_aGraphicsStack.front().m_aFillColor == Color( COL_TRANSPARENT ) )
8747cdf0e10cSrcweir         return;
8748cdf0e10cSrcweir 
8749cdf0e10cSrcweir     OStringBuffer aLine( 40 );
8750cdf0e10cSrcweir     m_aPages.back().appendRect( rRect, aLine );
8751cdf0e10cSrcweir 
8752cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) &&
8753cdf0e10cSrcweir         m_aGraphicsStack.front().m_aFillColor != Color( COL_TRANSPARENT ) )
8754cdf0e10cSrcweir         aLine.append( " B*\n" );
8755cdf0e10cSrcweir     else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
8756cdf0e10cSrcweir         aLine.append( " S\n" );
8757cdf0e10cSrcweir     else
8758cdf0e10cSrcweir         aLine.append( " f*\n" );
8759cdf0e10cSrcweir 
8760cdf0e10cSrcweir     writeBuffer( aLine.getStr(), aLine.getLength() );
8761cdf0e10cSrcweir }
8762cdf0e10cSrcweir 
8763cdf0e10cSrcweir void PDFWriterImpl::drawRectangle( const Rectangle& rRect, sal_uInt32 nHorzRound, sal_uInt32 nVertRound )
8764cdf0e10cSrcweir {
8765cdf0e10cSrcweir     MARK( "drawRectangle with rounded edges" );
8766cdf0e10cSrcweir 
8767cdf0e10cSrcweir     if( !nHorzRound && !nVertRound )
8768cdf0e10cSrcweir         drawRectangle( rRect );
8769cdf0e10cSrcweir 
8770cdf0e10cSrcweir     updateGraphicsState();
8771cdf0e10cSrcweir 
8772cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) &&
8773cdf0e10cSrcweir         m_aGraphicsStack.front().m_aFillColor == Color( COL_TRANSPARENT ) )
8774cdf0e10cSrcweir         return;
8775cdf0e10cSrcweir 
8776cdf0e10cSrcweir     if( nHorzRound > (sal_uInt32)rRect.GetWidth()/2 )
8777cdf0e10cSrcweir         nHorzRound = rRect.GetWidth()/2;
8778cdf0e10cSrcweir     if( nVertRound > (sal_uInt32)rRect.GetHeight()/2 )
8779cdf0e10cSrcweir         nVertRound = rRect.GetHeight()/2;
8780cdf0e10cSrcweir 
8781cdf0e10cSrcweir     Point aPoints[16];
8782cdf0e10cSrcweir     const double kappa = 0.5522847498;
8783cdf0e10cSrcweir     const sal_uInt32 kx = (sal_uInt32)((kappa*(double)nHorzRound)+0.5);
8784cdf0e10cSrcweir     const sal_uInt32 ky = (sal_uInt32)((kappa*(double)nVertRound)+0.5);
8785cdf0e10cSrcweir 
8786cdf0e10cSrcweir     aPoints[1]  = Point( rRect.TopLeft().X() + nHorzRound, rRect.TopLeft().Y() );
8787cdf0e10cSrcweir     aPoints[0]  = Point( aPoints[1].X() - kx, aPoints[1].Y() );
8788cdf0e10cSrcweir     aPoints[2]  = Point( rRect.TopRight().X()+1 - nHorzRound, aPoints[1].Y() );
8789cdf0e10cSrcweir     aPoints[3]  = Point( aPoints[2].X()+kx, aPoints[2].Y() );
8790cdf0e10cSrcweir 
8791cdf0e10cSrcweir     aPoints[5]  = Point( rRect.TopRight().X()+1, rRect.TopRight().Y()+nVertRound );
8792cdf0e10cSrcweir     aPoints[4]  = Point( aPoints[5].X(), aPoints[5].Y()-ky );
8793cdf0e10cSrcweir     aPoints[6]  = Point( aPoints[5].X(), rRect.BottomRight().Y()+1 - nVertRound );
8794cdf0e10cSrcweir     aPoints[7]  = Point( aPoints[6].X(), aPoints[6].Y()+ky );
8795cdf0e10cSrcweir 
8796cdf0e10cSrcweir     aPoints[9]  = Point( rRect.BottomRight().X()+1-nHorzRound, rRect.BottomRight().Y()+1 );
8797cdf0e10cSrcweir     aPoints[8]  = Point( aPoints[9].X()+kx, aPoints[9].Y() );
8798cdf0e10cSrcweir     aPoints[10] = Point( rRect.BottomLeft().X() + nHorzRound, aPoints[9].Y() );
8799cdf0e10cSrcweir     aPoints[11] = Point( aPoints[10].X()-kx, aPoints[10].Y() );
8800cdf0e10cSrcweir 
8801cdf0e10cSrcweir     aPoints[13] = Point( rRect.BottomLeft().X(), rRect.BottomLeft().Y()+1-nVertRound );
8802cdf0e10cSrcweir     aPoints[12] = Point( aPoints[13].X(), aPoints[13].Y()+ky );
8803cdf0e10cSrcweir     aPoints[14] = Point( rRect.TopLeft().X(), rRect.TopLeft().Y()+nVertRound );
8804cdf0e10cSrcweir     aPoints[15] = Point( aPoints[14].X(), aPoints[14].Y()-ky );
8805cdf0e10cSrcweir 
8806cdf0e10cSrcweir 
8807cdf0e10cSrcweir     OStringBuffer aLine( 80 );
8808cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[1], aLine );
8809cdf0e10cSrcweir     aLine.append( " m " );
8810cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[2], aLine );
8811cdf0e10cSrcweir     aLine.append( " l " );
8812cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[3], aLine );
8813cdf0e10cSrcweir     aLine.append( ' ' );
8814cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[4], aLine );
8815cdf0e10cSrcweir     aLine.append( ' ' );
8816cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[5], aLine );
8817cdf0e10cSrcweir     aLine.append( " c\n" );
8818cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[6], aLine );
8819cdf0e10cSrcweir     aLine.append( " l " );
8820cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[7], aLine );
8821cdf0e10cSrcweir     aLine.append( ' ' );
8822cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[8], aLine );
8823cdf0e10cSrcweir     aLine.append( ' ' );
8824cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[9], aLine );
8825cdf0e10cSrcweir     aLine.append( " c\n" );
8826cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[10], aLine );
8827cdf0e10cSrcweir     aLine.append( " l " );
8828cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[11], aLine );
8829cdf0e10cSrcweir     aLine.append( ' ' );
8830cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[12], aLine );
8831cdf0e10cSrcweir     aLine.append( ' ' );
8832cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[13], aLine );
8833cdf0e10cSrcweir     aLine.append( " c\n" );
8834cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[14], aLine );
8835cdf0e10cSrcweir     aLine.append( " l " );
8836cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[15], aLine );
8837cdf0e10cSrcweir     aLine.append( ' ' );
8838cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[0], aLine );
8839cdf0e10cSrcweir     aLine.append( ' ' );
8840cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[1], aLine );
8841cdf0e10cSrcweir     aLine.append( " c " );
8842cdf0e10cSrcweir 
8843cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) &&
8844cdf0e10cSrcweir         m_aGraphicsStack.front().m_aFillColor != Color( COL_TRANSPARENT ) )
8845cdf0e10cSrcweir         aLine.append( "b*\n" );
8846cdf0e10cSrcweir     else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
8847cdf0e10cSrcweir         aLine.append( "s\n" );
8848cdf0e10cSrcweir     else
8849cdf0e10cSrcweir         aLine.append( "f*\n" );
8850cdf0e10cSrcweir 
8851cdf0e10cSrcweir     writeBuffer( aLine.getStr(), aLine.getLength() );
8852cdf0e10cSrcweir }
8853cdf0e10cSrcweir 
8854cdf0e10cSrcweir void PDFWriterImpl::drawEllipse( const Rectangle& rRect )
8855cdf0e10cSrcweir {
8856cdf0e10cSrcweir     MARK( "drawEllipse" );
8857cdf0e10cSrcweir 
8858cdf0e10cSrcweir     updateGraphicsState();
8859cdf0e10cSrcweir 
8860cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) &&
8861cdf0e10cSrcweir         m_aGraphicsStack.front().m_aFillColor == Color( COL_TRANSPARENT ) )
8862cdf0e10cSrcweir         return;
8863cdf0e10cSrcweir 
8864cdf0e10cSrcweir     Point aPoints[12];
8865cdf0e10cSrcweir     const double kappa = 0.5522847498;
8866cdf0e10cSrcweir     const sal_uInt32 kx = (sal_uInt32)((kappa*(double)rRect.GetWidth()/2.0)+0.5);
8867cdf0e10cSrcweir     const sal_uInt32 ky = (sal_uInt32)((kappa*(double)rRect.GetHeight()/2.0)+0.5);
8868cdf0e10cSrcweir 
8869cdf0e10cSrcweir     aPoints[1]  = Point( rRect.TopLeft().X() + rRect.GetWidth()/2, rRect.TopLeft().Y() );
8870cdf0e10cSrcweir     aPoints[0]  = Point( aPoints[1].X() - kx, aPoints[1].Y() );
8871cdf0e10cSrcweir     aPoints[2]  = Point( aPoints[1].X() + kx, aPoints[1].Y() );
8872cdf0e10cSrcweir 
8873cdf0e10cSrcweir     aPoints[4]  = Point( rRect.TopRight().X()+1, rRect.TopRight().Y() + rRect.GetHeight()/2 );
8874cdf0e10cSrcweir     aPoints[3]  = Point( aPoints[4].X(), aPoints[4].Y() - ky );
8875cdf0e10cSrcweir     aPoints[5]  = Point( aPoints[4].X(), aPoints[4].Y() + ky );
8876cdf0e10cSrcweir 
8877cdf0e10cSrcweir     aPoints[7]  = Point( rRect.BottomLeft().X() + rRect.GetWidth()/2, rRect.BottomLeft().Y()+1 );
8878cdf0e10cSrcweir     aPoints[6]  = Point( aPoints[7].X() + kx, aPoints[7].Y() );
8879cdf0e10cSrcweir     aPoints[8]  = Point( aPoints[7].X() - kx, aPoints[7].Y() );
8880cdf0e10cSrcweir 
8881cdf0e10cSrcweir     aPoints[10] = Point( rRect.TopLeft().X(), rRect.TopLeft().Y() + rRect.GetHeight()/2 );
8882cdf0e10cSrcweir     aPoints[9]  = Point( aPoints[10].X(), aPoints[10].Y() + ky );
8883cdf0e10cSrcweir     aPoints[11] = Point( aPoints[10].X(), aPoints[10].Y() - ky );
8884cdf0e10cSrcweir 
8885cdf0e10cSrcweir     OStringBuffer aLine( 80 );
8886cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[1], aLine );
8887cdf0e10cSrcweir     aLine.append( " m " );
8888cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[2], aLine );
8889cdf0e10cSrcweir     aLine.append( ' ' );
8890cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[3], aLine );
8891cdf0e10cSrcweir     aLine.append( ' ' );
8892cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[4], aLine );
8893cdf0e10cSrcweir     aLine.append( " c\n" );
8894cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[5], aLine );
8895cdf0e10cSrcweir     aLine.append( ' ' );
8896cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[6], aLine );
8897cdf0e10cSrcweir     aLine.append( ' ' );
8898cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[7], aLine );
8899cdf0e10cSrcweir     aLine.append( " c\n" );
8900cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[8], aLine );
8901cdf0e10cSrcweir     aLine.append( ' ' );
8902cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[9], aLine );
8903cdf0e10cSrcweir     aLine.append( ' ' );
8904cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[10], aLine );
8905cdf0e10cSrcweir     aLine.append( " c\n" );
8906cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[11], aLine );
8907cdf0e10cSrcweir     aLine.append( ' ' );
8908cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[0], aLine );
8909cdf0e10cSrcweir     aLine.append( ' ' );
8910cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[1], aLine );
8911cdf0e10cSrcweir     aLine.append( " c " );
8912cdf0e10cSrcweir 
8913cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) &&
8914cdf0e10cSrcweir         m_aGraphicsStack.front().m_aFillColor != Color( COL_TRANSPARENT ) )
8915cdf0e10cSrcweir         aLine.append( "b*\n" );
8916cdf0e10cSrcweir     else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
8917cdf0e10cSrcweir         aLine.append( "s\n" );
8918cdf0e10cSrcweir     else
8919cdf0e10cSrcweir         aLine.append( "f*\n" );
8920cdf0e10cSrcweir 
8921cdf0e10cSrcweir     writeBuffer( aLine.getStr(), aLine.getLength() );
8922cdf0e10cSrcweir }
8923cdf0e10cSrcweir 
8924cdf0e10cSrcweir static double calcAngle( const Rectangle& rRect, const Point& rPoint )
8925cdf0e10cSrcweir {
8926cdf0e10cSrcweir     Point aOrigin((rRect.Left()+rRect.Right()+1)/2,
8927cdf0e10cSrcweir                   (rRect.Top()+rRect.Bottom()+1)/2);
8928cdf0e10cSrcweir     Point aPoint = rPoint - aOrigin;
8929cdf0e10cSrcweir 
8930cdf0e10cSrcweir     double fX = (double)aPoint.X();
8931cdf0e10cSrcweir     double fY = (double)-aPoint.Y();
8932cdf0e10cSrcweir 
8933cdf0e10cSrcweir     if( rRect.GetWidth() > rRect.GetHeight() )
8934cdf0e10cSrcweir         fY = fY*((double)rRect.GetWidth()/(double)rRect.GetHeight());
8935cdf0e10cSrcweir     else if( rRect.GetHeight() > rRect.GetWidth() )
8936cdf0e10cSrcweir         fX = fX*((double)rRect.GetHeight()/(double)rRect.GetWidth());
8937cdf0e10cSrcweir     return atan2( fY, fX );
8938cdf0e10cSrcweir }
8939cdf0e10cSrcweir 
8940cdf0e10cSrcweir void PDFWriterImpl::drawArc( const Rectangle& rRect, const Point& rStart, const Point& rStop, bool bWithPie, bool bWithChord )
8941cdf0e10cSrcweir {
8942cdf0e10cSrcweir     MARK( "drawArc" );
8943cdf0e10cSrcweir 
8944cdf0e10cSrcweir     updateGraphicsState();
8945cdf0e10cSrcweir 
8946cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) &&
8947cdf0e10cSrcweir         m_aGraphicsStack.front().m_aFillColor == Color( COL_TRANSPARENT ) )
8948cdf0e10cSrcweir         return;
8949cdf0e10cSrcweir 
8950cdf0e10cSrcweir     // calculate start and stop angles
8951cdf0e10cSrcweir     const double fStartAngle = calcAngle( rRect, rStart );
8952cdf0e10cSrcweir     double fStopAngle  = calcAngle( rRect, rStop );
8953cdf0e10cSrcweir     while( fStopAngle < fStartAngle )
8954cdf0e10cSrcweir         fStopAngle += 2.0*M_PI;
8955cdf0e10cSrcweir     const int nFragments = (int)((fStopAngle-fStartAngle)/(M_PI/2.0))+1;
8956cdf0e10cSrcweir     const double fFragmentDelta = (fStopAngle-fStartAngle)/(double)nFragments;
8957cdf0e10cSrcweir     const double kappa = fabs( 4.0 * (1.0-cos(fFragmentDelta/2.0))/sin(fFragmentDelta/2.0) / 3.0);
8958cdf0e10cSrcweir     const double halfWidth = (double)rRect.GetWidth()/2.0;
8959cdf0e10cSrcweir     const double halfHeight = (double)rRect.GetHeight()/2.0;
8960cdf0e10cSrcweir 
8961cdf0e10cSrcweir     const Point aCenter( (rRect.Left()+rRect.Right()+1)/2,
8962cdf0e10cSrcweir                          (rRect.Top()+rRect.Bottom()+1)/2 );
8963cdf0e10cSrcweir 
8964cdf0e10cSrcweir     OStringBuffer aLine( 30*nFragments );
8965cdf0e10cSrcweir     Point aPoint( (int)(halfWidth * cos(fStartAngle) ),
8966cdf0e10cSrcweir                   -(int)(halfHeight * sin(fStartAngle) ) );
8967cdf0e10cSrcweir     aPoint += aCenter;
8968cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoint, aLine );
8969cdf0e10cSrcweir     aLine.append( " m " );
8970cdf0e10cSrcweir     if( !basegfx::fTools::equal(fStartAngle, fStopAngle) )
8971cdf0e10cSrcweir     {
8972cdf0e10cSrcweir         for( int i = 0; i < nFragments; i++ )
8973cdf0e10cSrcweir         {
8974cdf0e10cSrcweir             const double fStartFragment = fStartAngle + (double)i*fFragmentDelta;
8975cdf0e10cSrcweir             const double fStopFragment = fStartFragment + fFragmentDelta;
8976cdf0e10cSrcweir             aPoint = Point( (int)(halfWidth * (cos(fStartFragment) - kappa*sin(fStartFragment) ) ),
8977cdf0e10cSrcweir                             -(int)(halfHeight * (sin(fStartFragment) + kappa*cos(fStartFragment) ) ) );
8978cdf0e10cSrcweir             aPoint += aCenter;
8979cdf0e10cSrcweir             m_aPages.back().appendPoint( aPoint, aLine );
8980cdf0e10cSrcweir             aLine.append( ' ' );
8981cdf0e10cSrcweir 
8982cdf0e10cSrcweir             aPoint = Point( (int)(halfWidth * (cos(fStopFragment) + kappa*sin(fStopFragment) ) ),
8983cdf0e10cSrcweir                             -(int)(halfHeight * (sin(fStopFragment) - kappa*cos(fStopFragment) ) ) );
8984cdf0e10cSrcweir             aPoint += aCenter;
8985cdf0e10cSrcweir             m_aPages.back().appendPoint( aPoint, aLine );
8986cdf0e10cSrcweir             aLine.append( ' ' );
8987cdf0e10cSrcweir 
8988cdf0e10cSrcweir             aPoint = Point( (int)(halfWidth * cos(fStopFragment) ),
8989cdf0e10cSrcweir                             -(int)(halfHeight * sin(fStopFragment) ) );
8990cdf0e10cSrcweir             aPoint += aCenter;
8991cdf0e10cSrcweir             m_aPages.back().appendPoint( aPoint, aLine );
8992cdf0e10cSrcweir             aLine.append( " c\n" );
8993cdf0e10cSrcweir         }
8994cdf0e10cSrcweir     }
8995cdf0e10cSrcweir     if( bWithChord || bWithPie )
8996cdf0e10cSrcweir     {
8997cdf0e10cSrcweir         if( bWithPie )
8998cdf0e10cSrcweir         {
8999cdf0e10cSrcweir             m_aPages.back().appendPoint( aCenter, aLine );
9000cdf0e10cSrcweir             aLine.append( " l " );
9001cdf0e10cSrcweir         }
9002cdf0e10cSrcweir         aLine.append( "h " );
9003cdf0e10cSrcweir     }
9004cdf0e10cSrcweir     if( ! bWithChord && ! bWithPie )
9005cdf0e10cSrcweir         aLine.append( "S\n" );
9006cdf0e10cSrcweir     else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) &&
9007cdf0e10cSrcweir         m_aGraphicsStack.front().m_aFillColor != Color( COL_TRANSPARENT ) )
9008cdf0e10cSrcweir         aLine.append( "B*\n" );
9009cdf0e10cSrcweir     else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
9010cdf0e10cSrcweir         aLine.append( "S\n" );
9011cdf0e10cSrcweir     else
9012cdf0e10cSrcweir         aLine.append( "f*\n" );
9013cdf0e10cSrcweir 
9014cdf0e10cSrcweir     writeBuffer( aLine.getStr(), aLine.getLength() );
9015cdf0e10cSrcweir }
9016cdf0e10cSrcweir 
9017cdf0e10cSrcweir void PDFWriterImpl::drawPolyLine( const Polygon& rPoly )
9018cdf0e10cSrcweir {
9019cdf0e10cSrcweir     MARK( "drawPolyLine" );
9020cdf0e10cSrcweir 
9021cdf0e10cSrcweir     sal_uInt16 nPoints = rPoly.GetSize();
9022cdf0e10cSrcweir     if( nPoints < 2 )
9023cdf0e10cSrcweir         return;
9024cdf0e10cSrcweir 
9025cdf0e10cSrcweir     updateGraphicsState();
9026cdf0e10cSrcweir 
9027cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) )
9028cdf0e10cSrcweir         return;
9029cdf0e10cSrcweir 
9030cdf0e10cSrcweir     OStringBuffer aLine( 20 * nPoints );
9031cdf0e10cSrcweir     m_aPages.back().appendPolygon( rPoly, aLine, rPoly[0] == rPoly[nPoints-1] );
9032cdf0e10cSrcweir     aLine.append( "S\n" );
9033cdf0e10cSrcweir 
9034cdf0e10cSrcweir     writeBuffer( aLine.getStr(), aLine.getLength() );
9035cdf0e10cSrcweir }
9036cdf0e10cSrcweir 
9037cdf0e10cSrcweir void PDFWriterImpl::drawPolyLine( const Polygon& rPoly, const LineInfo& rInfo )
9038cdf0e10cSrcweir {
9039cdf0e10cSrcweir     MARK( "drawPolyLine with LineInfo" );
9040cdf0e10cSrcweir 
9041cdf0e10cSrcweir     updateGraphicsState();
9042cdf0e10cSrcweir 
9043cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) )
9044cdf0e10cSrcweir         return;
9045cdf0e10cSrcweir 
9046cdf0e10cSrcweir     OStringBuffer aLine;
9047cdf0e10cSrcweir     aLine.append( "q " );
9048cdf0e10cSrcweir     if( m_aPages.back().appendLineInfo( rInfo, aLine ) )
9049cdf0e10cSrcweir     {
9050cdf0e10cSrcweir         writeBuffer( aLine.getStr(), aLine.getLength() );
9051cdf0e10cSrcweir         drawPolyLine( rPoly );
9052cdf0e10cSrcweir         writeBuffer( "Q\n", 2 );
9053cdf0e10cSrcweir     }
9054cdf0e10cSrcweir     else
9055cdf0e10cSrcweir     {
9056cdf0e10cSrcweir         PDFWriter::ExtLineInfo aInfo;
9057cdf0e10cSrcweir         convertLineInfoToExtLineInfo( rInfo, aInfo );
9058cdf0e10cSrcweir         drawPolyLine( rPoly, aInfo );
9059cdf0e10cSrcweir     }
9060cdf0e10cSrcweir }
9061cdf0e10cSrcweir 
9062cdf0e10cSrcweir void PDFWriterImpl::convertLineInfoToExtLineInfo( const LineInfo& rIn, PDFWriter::ExtLineInfo& rOut )
9063cdf0e10cSrcweir {
9064cdf0e10cSrcweir     DBG_ASSERT( rIn.GetStyle() == LINE_DASH, "invalid conversion" );
9065cdf0e10cSrcweir     rOut.m_fLineWidth           = rIn.GetWidth();
9066cdf0e10cSrcweir     rOut.m_fTransparency        = 0.0;
9067cdf0e10cSrcweir     rOut.m_eCap                 = PDFWriter::capButt;
9068cdf0e10cSrcweir     rOut.m_eJoin                = PDFWriter::joinMiter;
9069cdf0e10cSrcweir     rOut.m_fMiterLimit          = 10;
9070cdf0e10cSrcweir     rOut.m_aDashArray.clear();
9071cdf0e10cSrcweir 
90725aaf853bSArmin Le Grand     // add DashDot to DashArray
90735aaf853bSArmin Le Grand     const int nDashes     = rIn.GetDashCount();
90745aaf853bSArmin Le Grand     const int nDashLen    = rIn.GetDashLen();
90755aaf853bSArmin Le Grand     const int nDistance   = rIn.GetDistance();
90765aaf853bSArmin Le Grand 
9077cdf0e10cSrcweir     for( int n  = 0; n < nDashes; n++ )
9078cdf0e10cSrcweir     {
9079cdf0e10cSrcweir         rOut.m_aDashArray.push_back( nDashLen );
9080cdf0e10cSrcweir         rOut.m_aDashArray.push_back( nDistance );
9081cdf0e10cSrcweir     }
90825aaf853bSArmin Le Grand 
90835aaf853bSArmin Le Grand     const int nDots       = rIn.GetDotCount();
90845aaf853bSArmin Le Grand     const int nDotLen     = rIn.GetDotLen();
90855aaf853bSArmin Le Grand 
9086cdf0e10cSrcweir     for( int n  = 0; n < nDots; n++ )
9087cdf0e10cSrcweir     {
9088cdf0e10cSrcweir         rOut.m_aDashArray.push_back( nDotLen );
9089cdf0e10cSrcweir         rOut.m_aDashArray.push_back( nDistance );
9090cdf0e10cSrcweir     }
90915aaf853bSArmin Le Grand 
90925aaf853bSArmin Le Grand     // add LineJoin
90935aaf853bSArmin Le Grand     switch(rIn.GetLineJoin())
90945aaf853bSArmin Le Grand     {
90955aaf853bSArmin Le Grand         case basegfx::B2DLINEJOIN_BEVEL :
90965aaf853bSArmin Le Grand         {
90975aaf853bSArmin Le Grand             rOut.m_eJoin = PDFWriter::joinBevel;
90985aaf853bSArmin Le Grand             break;
90995aaf853bSArmin Le Grand         }
91005aaf853bSArmin Le Grand         default : // basegfx::B2DLINEJOIN_NONE :
91015aaf853bSArmin Le Grand         // Pdf has no 'none' lineJoin, default is miter
91025aaf853bSArmin Le Grand         case basegfx::B2DLINEJOIN_MIDDLE :
91035aaf853bSArmin Le Grand         case basegfx::B2DLINEJOIN_MITER :
91045aaf853bSArmin Le Grand         {
91055aaf853bSArmin Le Grand             rOut.m_eJoin = PDFWriter::joinMiter;
91065aaf853bSArmin Le Grand             break;
91075aaf853bSArmin Le Grand         }
91085aaf853bSArmin Le Grand         case basegfx::B2DLINEJOIN_ROUND :
91095aaf853bSArmin Le Grand         {
91105aaf853bSArmin Le Grand             rOut.m_eJoin = PDFWriter::joinRound;
91115aaf853bSArmin Le Grand             break;
91125aaf853bSArmin Le Grand         }
91135aaf853bSArmin Le Grand     }
91145aaf853bSArmin Le Grand 
91155aaf853bSArmin Le Grand     // add LineCap
91165aaf853bSArmin Le Grand     switch(rIn.GetLineCap())
91175aaf853bSArmin Le Grand     {
91185aaf853bSArmin Le Grand         default: /* com::sun::star::drawing::LineCap_BUTT */
91195aaf853bSArmin Le Grand         {
91205aaf853bSArmin Le Grand             rOut.m_eCap = PDFWriter::capButt;
91215aaf853bSArmin Le Grand             break;
91225aaf853bSArmin Le Grand         }
91235aaf853bSArmin Le Grand         case com::sun::star::drawing::LineCap_ROUND:
91245aaf853bSArmin Le Grand         {
91255aaf853bSArmin Le Grand             rOut.m_eCap = PDFWriter::capRound;
91265aaf853bSArmin Le Grand             break;
91275aaf853bSArmin Le Grand         }
91285aaf853bSArmin Le Grand         case com::sun::star::drawing::LineCap_SQUARE:
91295aaf853bSArmin Le Grand         {
91305aaf853bSArmin Le Grand             rOut.m_eCap = PDFWriter::capSquare;
91315aaf853bSArmin Le Grand             break;
91325aaf853bSArmin Le Grand         }
91335aaf853bSArmin Le Grand     }
9134cdf0e10cSrcweir }
9135cdf0e10cSrcweir 
9136cdf0e10cSrcweir void PDFWriterImpl::drawPolyLine( const Polygon& rPoly, const PDFWriter::ExtLineInfo& rInfo )
9137cdf0e10cSrcweir {
9138cdf0e10cSrcweir     MARK( "drawPolyLine with ExtLineInfo" );
9139cdf0e10cSrcweir 
9140cdf0e10cSrcweir     updateGraphicsState();
9141cdf0e10cSrcweir 
9142cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) )
9143cdf0e10cSrcweir         return;
9144cdf0e10cSrcweir 
9145cdf0e10cSrcweir     if( rInfo.m_fTransparency >= 1.0 )
9146cdf0e10cSrcweir         return;
9147cdf0e10cSrcweir 
9148cdf0e10cSrcweir     if( rInfo.m_fTransparency != 0.0 )
9149cdf0e10cSrcweir         beginTransparencyGroup();
9150cdf0e10cSrcweir 
9151cdf0e10cSrcweir     OStringBuffer aLine;
9152cdf0e10cSrcweir     aLine.append( "q " );
9153cdf0e10cSrcweir     m_aPages.back().appendMappedLength( rInfo.m_fLineWidth, aLine );
9154cdf0e10cSrcweir     aLine.append( " w" );
9155cdf0e10cSrcweir     if( rInfo.m_aDashArray.size() < 10 ) // implmentation limit of acrobat reader
9156cdf0e10cSrcweir     {
9157cdf0e10cSrcweir         switch( rInfo.m_eCap )
9158cdf0e10cSrcweir         {
9159cdf0e10cSrcweir             default:
9160cdf0e10cSrcweir             case PDFWriter::capButt:   aLine.append( " 0 J" );break;
9161cdf0e10cSrcweir             case PDFWriter::capRound:  aLine.append( " 1 J" );break;
9162cdf0e10cSrcweir             case PDFWriter::capSquare: aLine.append( " 2 J" );break;
9163cdf0e10cSrcweir         }
9164cdf0e10cSrcweir         switch( rInfo.m_eJoin )
9165cdf0e10cSrcweir         {
9166cdf0e10cSrcweir             default:
9167cdf0e10cSrcweir             case PDFWriter::joinMiter:
9168cdf0e10cSrcweir             {
9169cdf0e10cSrcweir                 double fLimit = rInfo.m_fMiterLimit;
9170cdf0e10cSrcweir                 if( rInfo.m_fLineWidth < rInfo.m_fMiterLimit )
9171cdf0e10cSrcweir                     fLimit = fLimit / rInfo.m_fLineWidth;
9172cdf0e10cSrcweir                 if( fLimit < 1.0 )
9173cdf0e10cSrcweir                     fLimit = 1.0;
9174cdf0e10cSrcweir                 aLine.append( " 0 j " );
9175cdf0e10cSrcweir                 appendDouble( fLimit, aLine );
9176cdf0e10cSrcweir                 aLine.append( " M" );
9177cdf0e10cSrcweir             }
9178cdf0e10cSrcweir             break;
9179cdf0e10cSrcweir             case PDFWriter::joinRound:  aLine.append( " 1 j" );break;
9180cdf0e10cSrcweir             case PDFWriter::joinBevel:  aLine.append( " 2 j" );break;
9181cdf0e10cSrcweir         }
9182cdf0e10cSrcweir         if( rInfo.m_aDashArray.size() > 0 )
9183cdf0e10cSrcweir         {
9184cdf0e10cSrcweir             aLine.append( " [ " );
9185cdf0e10cSrcweir             for( std::vector<double>::const_iterator it = rInfo.m_aDashArray.begin();
9186cdf0e10cSrcweir                  it != rInfo.m_aDashArray.end(); ++it )
9187cdf0e10cSrcweir             {
9188cdf0e10cSrcweir                 m_aPages.back().appendMappedLength( *it, aLine );
9189cdf0e10cSrcweir                 aLine.append( ' ' );
9190cdf0e10cSrcweir             }
9191cdf0e10cSrcweir             aLine.append( "] 0 d" );
9192cdf0e10cSrcweir         }
9193cdf0e10cSrcweir         aLine.append( "\n" );
9194cdf0e10cSrcweir         writeBuffer( aLine.getStr(), aLine.getLength() );
9195cdf0e10cSrcweir         drawPolyLine( rPoly );
9196cdf0e10cSrcweir     }
9197cdf0e10cSrcweir     else
9198cdf0e10cSrcweir     {
9199cdf0e10cSrcweir         basegfx::B2DPolygon aPoly(rPoly.getB2DPolygon());
9200cdf0e10cSrcweir         basegfx::B2DPolyPolygon aPolyPoly;
9201cdf0e10cSrcweir 
9202cdf0e10cSrcweir 		basegfx::tools::applyLineDashing(aPoly, rInfo.m_aDashArray, &aPolyPoly);
9203cdf0e10cSrcweir 
9204cdf0e10cSrcweir 		// Old applyLineDashing subdivided the polygon. New one will create bezier curve segments.
9205cdf0e10cSrcweir 		// To mimic old behaviour, apply subdivide here. If beziers shall be written (better quality)
9206cdf0e10cSrcweir 		// this line needs to be removed and the loop below adapted accordingly
9207cdf0e10cSrcweir 		aPolyPoly = basegfx::tools::adaptiveSubdivideByAngle(aPolyPoly);
9208cdf0e10cSrcweir 
9209cdf0e10cSrcweir 		const sal_uInt32 nPolygonCount(aPolyPoly.count());
9210cdf0e10cSrcweir 
9211cdf0e10cSrcweir 		for( sal_uInt32 nPoly = 0; nPoly < nPolygonCount; nPoly++ )
9212cdf0e10cSrcweir         {
9213cdf0e10cSrcweir             aLine.append( (nPoly != 0 && (nPoly & 7) == 0) ? "\n" : " " );
9214cdf0e10cSrcweir             aPoly = aPolyPoly.getB2DPolygon( nPoly );
9215cdf0e10cSrcweir 			const sal_uInt32 nPointCount(aPoly.count());
9216cdf0e10cSrcweir 
9217cdf0e10cSrcweir 			if(nPointCount)
9218cdf0e10cSrcweir 			{
9219cdf0e10cSrcweir 				const sal_uInt32 nEdgeCount(aPoly.isClosed() ? nPointCount : nPointCount - 1);
9220cdf0e10cSrcweir 				basegfx::B2DPoint aCurrent(aPoly.getB2DPoint(0));
9221cdf0e10cSrcweir 
9222cdf0e10cSrcweir 				for(sal_uInt32 a(0); a < nEdgeCount; a++)
9223cdf0e10cSrcweir 				{
9224cdf0e10cSrcweir                     if( a > 0 )
9225cdf0e10cSrcweir                         aLine.append( " " );
9226cdf0e10cSrcweir 					const sal_uInt32 nNextIndex((a + 1) % nPointCount);
9227cdf0e10cSrcweir 					const basegfx::B2DPoint aNext(aPoly.getB2DPoint(nNextIndex));
9228cdf0e10cSrcweir 
9229cdf0e10cSrcweir 					m_aPages.back().appendPoint( Point( FRound(aCurrent.getX()),
9230cdf0e10cSrcweir 														FRound(aCurrent.getY()) ),
9231cdf0e10cSrcweir 												 aLine );
9232cdf0e10cSrcweir 					aLine.append( " m " );
9233cdf0e10cSrcweir 					m_aPages.back().appendPoint( Point( FRound(aNext.getX()),
9234cdf0e10cSrcweir 														FRound(aNext.getY()) ),
9235cdf0e10cSrcweir 												 aLine );
9236cdf0e10cSrcweir 					aLine.append( " l" );
9237cdf0e10cSrcweir 
9238cdf0e10cSrcweir 					// prepare next edge
9239cdf0e10cSrcweir 					aCurrent = aNext;
9240cdf0e10cSrcweir 				}
9241cdf0e10cSrcweir 			}
9242cdf0e10cSrcweir         }
9243cdf0e10cSrcweir         aLine.append( " S " );
9244cdf0e10cSrcweir         writeBuffer( aLine.getStr(), aLine.getLength() );
9245cdf0e10cSrcweir     }
9246cdf0e10cSrcweir     writeBuffer( "Q\n", 2 );
9247cdf0e10cSrcweir 
9248cdf0e10cSrcweir     if( rInfo.m_fTransparency != 0.0 )
9249cdf0e10cSrcweir     {
9250cdf0e10cSrcweir         // FIXME: actually this may be incorrect with bezier polygons
9251cdf0e10cSrcweir         Rectangle aBoundRect( rPoly.GetBoundRect() );
9252cdf0e10cSrcweir         // avoid clipping with thick lines
9253cdf0e10cSrcweir         if( rInfo.m_fLineWidth > 0.0 )
9254cdf0e10cSrcweir         {
9255cdf0e10cSrcweir             sal_Int32 nLW = sal_Int32(rInfo.m_fLineWidth);
9256cdf0e10cSrcweir             aBoundRect.Top()    -= nLW;
9257cdf0e10cSrcweir             aBoundRect.Left()   -= nLW;
9258cdf0e10cSrcweir             aBoundRect.Right()  += nLW;
9259cdf0e10cSrcweir             aBoundRect.Bottom() += nLW;
9260cdf0e10cSrcweir         }
9261cdf0e10cSrcweir         endTransparencyGroup( aBoundRect, (sal_uInt16)(100.0*rInfo.m_fTransparency) );
9262cdf0e10cSrcweir     }
9263cdf0e10cSrcweir }
9264cdf0e10cSrcweir 
9265cdf0e10cSrcweir void PDFWriterImpl::drawPixel( const Point& rPoint, const Color& rColor )
9266cdf0e10cSrcweir {
9267cdf0e10cSrcweir     MARK( "drawPixel" );
9268cdf0e10cSrcweir 
9269cdf0e10cSrcweir     Color aColor = ( rColor == Color( COL_TRANSPARENT ) ? m_aGraphicsStack.front().m_aLineColor : rColor );
9270cdf0e10cSrcweir 
9271cdf0e10cSrcweir     if( aColor == Color( COL_TRANSPARENT ) )
9272cdf0e10cSrcweir         return;
9273cdf0e10cSrcweir 
9274cdf0e10cSrcweir     // pixels are drawn in line color, so have to set
9275cdf0e10cSrcweir     // the nonstroking color to line color
9276cdf0e10cSrcweir     Color aOldFillColor = m_aGraphicsStack.front().m_aFillColor;
9277cdf0e10cSrcweir     setFillColor( aColor );
9278cdf0e10cSrcweir 
9279cdf0e10cSrcweir     updateGraphicsState();
9280cdf0e10cSrcweir 
9281cdf0e10cSrcweir     OStringBuffer aLine( 20 );
9282cdf0e10cSrcweir     m_aPages.back().appendPoint( rPoint, aLine );
9283cdf0e10cSrcweir     aLine.append( ' ' );
9284cdf0e10cSrcweir     appendDouble( 1.0/double(getReferenceDevice()->ImplGetDPIX()), aLine );
9285cdf0e10cSrcweir     aLine.append( ' ' );
9286cdf0e10cSrcweir     appendDouble( 1.0/double(getReferenceDevice()->ImplGetDPIY()), aLine );
9287cdf0e10cSrcweir     aLine.append( " re f\n" );
9288cdf0e10cSrcweir     writeBuffer( aLine.getStr(), aLine.getLength() );
9289cdf0e10cSrcweir 
9290cdf0e10cSrcweir     setFillColor( aOldFillColor );
9291cdf0e10cSrcweir }
9292cdf0e10cSrcweir 
9293cdf0e10cSrcweir void PDFWriterImpl::drawPixel( const Polygon& rPoints, const Color* pColors )
9294cdf0e10cSrcweir {
9295cdf0e10cSrcweir     MARK( "drawPixel with Polygon" );
9296cdf0e10cSrcweir 
9297cdf0e10cSrcweir     updateGraphicsState();
9298cdf0e10cSrcweir 
9299cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) && ! pColors )
9300cdf0e10cSrcweir         return;
9301cdf0e10cSrcweir 
9302cdf0e10cSrcweir     sal_uInt16 nPoints = rPoints.GetSize();
9303cdf0e10cSrcweir     OStringBuffer aLine( nPoints*40 );
9304cdf0e10cSrcweir     aLine.append( "q " );
9305cdf0e10cSrcweir     if( ! pColors )
9306cdf0e10cSrcweir     {
9307cdf0e10cSrcweir         appendNonStrokingColor( m_aGraphicsStack.front().m_aLineColor, aLine );
9308cdf0e10cSrcweir         aLine.append( ' ' );
9309cdf0e10cSrcweir     }
9310cdf0e10cSrcweir 
9311cdf0e10cSrcweir     OStringBuffer aPixel(32);
9312cdf0e10cSrcweir     aPixel.append( ' ' );
9313cdf0e10cSrcweir     appendDouble( 1.0/double(getReferenceDevice()->ImplGetDPIX()), aPixel );
9314cdf0e10cSrcweir     aPixel.append( ' ' );
9315cdf0e10cSrcweir     appendDouble( 1.0/double(getReferenceDevice()->ImplGetDPIY()), aPixel );
9316cdf0e10cSrcweir     OString aPixelStr = aPixel.makeStringAndClear();
9317cdf0e10cSrcweir     for( sal_uInt16 i = 0; i < nPoints; i++ )
9318cdf0e10cSrcweir     {
9319cdf0e10cSrcweir         if( pColors )
9320cdf0e10cSrcweir         {
9321cdf0e10cSrcweir             if( pColors[i] == Color( COL_TRANSPARENT ) )
9322cdf0e10cSrcweir                 continue;
9323cdf0e10cSrcweir 
9324cdf0e10cSrcweir             appendNonStrokingColor( pColors[i], aLine );
9325cdf0e10cSrcweir             aLine.append( ' ' );
9326cdf0e10cSrcweir         }
9327cdf0e10cSrcweir         m_aPages.back().appendPoint( rPoints[i], aLine );
9328cdf0e10cSrcweir         aLine.append( aPixelStr );
9329cdf0e10cSrcweir         aLine.append( " re f\n" );
9330cdf0e10cSrcweir     }
9331cdf0e10cSrcweir     aLine.append( "Q\n" );
9332cdf0e10cSrcweir     writeBuffer( aLine.getStr(), aLine.getLength() );
9333cdf0e10cSrcweir }
9334cdf0e10cSrcweir 
9335cdf0e10cSrcweir class AccessReleaser
9336cdf0e10cSrcweir {
9337cdf0e10cSrcweir     BitmapReadAccess* m_pAccess;
9338cdf0e10cSrcweir public:
9339cdf0e10cSrcweir     AccessReleaser( BitmapReadAccess* pAccess ) : m_pAccess( pAccess ){}
9340cdf0e10cSrcweir     ~AccessReleaser() { delete m_pAccess; }
9341cdf0e10cSrcweir };
9342cdf0e10cSrcweir 
9343cdf0e10cSrcweir bool PDFWriterImpl::writeTransparentObject( TransparencyEmit& rObject )
9344cdf0e10cSrcweir {
9345cdf0e10cSrcweir     CHECK_RETURN( updateObject( rObject.m_nObject ) );
9346cdf0e10cSrcweir 
9347cdf0e10cSrcweir     bool bFlateFilter = compressStream( rObject.m_pContentStream );
9348cdf0e10cSrcweir     rObject.m_pContentStream->Seek( STREAM_SEEK_TO_END );
9349cdf0e10cSrcweir     sal_uLong nSize = rObject.m_pContentStream->Tell();
9350cdf0e10cSrcweir     rObject.m_pContentStream->Seek( STREAM_SEEK_TO_BEGIN );
9351cdf0e10cSrcweir     #if OSL_DEBUG_LEVEL > 1
9352cdf0e10cSrcweir     emitComment( "PDFWriterImpl::writeTransparentObject" );
9353cdf0e10cSrcweir     #endif
9354cdf0e10cSrcweir     OStringBuffer aLine( 512 );
9355cdf0e10cSrcweir     CHECK_RETURN( updateObject( rObject.m_nObject ) );
9356cdf0e10cSrcweir     aLine.append( rObject.m_nObject );
9357cdf0e10cSrcweir     aLine.append( " 0 obj\n"
9358cdf0e10cSrcweir                   "<</Type/XObject\n"
9359cdf0e10cSrcweir                   "/Subtype/Form\n"
9360cdf0e10cSrcweir                   "/BBox[ " );
9361cdf0e10cSrcweir     appendFixedInt( rObject.m_aBoundRect.Left(), aLine );
9362cdf0e10cSrcweir     aLine.append( ' ' );
9363cdf0e10cSrcweir     appendFixedInt( rObject.m_aBoundRect.Top(), aLine );
9364cdf0e10cSrcweir     aLine.append( ' ' );
9365cdf0e10cSrcweir     appendFixedInt( rObject.m_aBoundRect.Right(), aLine );
9366cdf0e10cSrcweir     aLine.append( ' ' );
9367cdf0e10cSrcweir     appendFixedInt( rObject.m_aBoundRect.Bottom()+1, aLine );
9368cdf0e10cSrcweir     aLine.append( " ]\n" );
9369cdf0e10cSrcweir     if( ! rObject.m_pSoftMaskStream )
9370cdf0e10cSrcweir     {
9371cdf0e10cSrcweir         if( ! m_bIsPDF_A1 )
9372cdf0e10cSrcweir         {
9373cdf0e10cSrcweir             aLine.append( "/Group<</S/Transparency/CS/DeviceRGB/K true>>\n" );
9374cdf0e10cSrcweir         }
9375cdf0e10cSrcweir     }
9376cdf0e10cSrcweir     /* #i42884# the PDF reference recommends that each Form XObject
9377cdf0e10cSrcweir     *  should have a resource dict; alas if that is the same object
9378cdf0e10cSrcweir     *  as the one of the page it triggers an endless recursion in
9379cdf0e10cSrcweir     *  acroread 5 (6 and up have that fixed). Since we have only one
9380cdf0e10cSrcweir     *  resource dict anyway, let's use the one from the page by NOT
9381cdf0e10cSrcweir     *  emitting a Resources entry.
9382cdf0e10cSrcweir     */
9383cdf0e10cSrcweir     #if 0
9384cdf0e10cSrcweir     aLine.append( "   /Resources " );
9385cdf0e10cSrcweir     aLine.append( getResourceDictObj() );
9386cdf0e10cSrcweir     aLine.append( " 0 R\n" );
9387cdf0e10cSrcweir     #endif
9388cdf0e10cSrcweir 
9389cdf0e10cSrcweir     aLine.append( "/Length " );
9390cdf0e10cSrcweir     aLine.append( (sal_Int32)(nSize) );
9391cdf0e10cSrcweir     aLine.append( "\n" );
9392cdf0e10cSrcweir     if( bFlateFilter )
9393cdf0e10cSrcweir         aLine.append( "/Filter/FlateDecode\n" );
9394cdf0e10cSrcweir     aLine.append( ">>\n"
9395cdf0e10cSrcweir                   "stream\n" );
9396cdf0e10cSrcweir     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
9397cdf0e10cSrcweir     checkAndEnableStreamEncryption( rObject.m_nObject );
9398cdf0e10cSrcweir     CHECK_RETURN( writeBuffer( rObject.m_pContentStream->GetData(), nSize ) );
9399cdf0e10cSrcweir     disableStreamEncryption();
9400cdf0e10cSrcweir     aLine.setLength( 0 );
9401cdf0e10cSrcweir     aLine.append( "\n"
9402cdf0e10cSrcweir                   "endstream\n"
9403cdf0e10cSrcweir                   "endobj\n\n" );
9404cdf0e10cSrcweir     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
9405cdf0e10cSrcweir 
9406cdf0e10cSrcweir     // write ExtGState dict for this XObject
9407cdf0e10cSrcweir     aLine.setLength( 0 );
9408cdf0e10cSrcweir     aLine.append( rObject.m_nExtGStateObject );
9409cdf0e10cSrcweir     aLine.append( " 0 obj\n"
9410cdf0e10cSrcweir                   "<<" );
9411cdf0e10cSrcweir     if( ! rObject.m_pSoftMaskStream )
9412cdf0e10cSrcweir     {
9413cdf0e10cSrcweir //i59651
9414cdf0e10cSrcweir         if( m_bIsPDF_A1 )
9415cdf0e10cSrcweir         {
9416cdf0e10cSrcweir             aLine.append( "/CA 1.0/ca 1.0" );
9417cdf0e10cSrcweir             m_aErrors.insert( PDFWriter::Warning_Transparency_Omitted_PDFA );
9418cdf0e10cSrcweir         }
9419cdf0e10cSrcweir         else
9420cdf0e10cSrcweir         {
9421cdf0e10cSrcweir             aLine.append(  "/CA " );
9422cdf0e10cSrcweir             appendDouble( rObject.m_fAlpha, aLine );
9423cdf0e10cSrcweir             aLine.append( "\n"
9424cdf0e10cSrcweir                           "   /ca " );
9425cdf0e10cSrcweir             appendDouble( rObject.m_fAlpha, aLine );
9426cdf0e10cSrcweir         }
9427cdf0e10cSrcweir         aLine.append( "\n" );
9428cdf0e10cSrcweir     }
9429cdf0e10cSrcweir     else
9430cdf0e10cSrcweir     {
9431cdf0e10cSrcweir         if( m_bIsPDF_A1 )
9432cdf0e10cSrcweir         {
9433cdf0e10cSrcweir             aLine.append( "/SMask/None" );
9434cdf0e10cSrcweir             m_aErrors.insert( PDFWriter::Warning_Transparency_Omitted_PDFA );
9435cdf0e10cSrcweir         }
9436cdf0e10cSrcweir         else
9437cdf0e10cSrcweir         {
9438cdf0e10cSrcweir             rObject.m_pSoftMaskStream->Seek( STREAM_SEEK_TO_END );
9439cdf0e10cSrcweir             sal_Int32 nMaskSize = (sal_Int32)rObject.m_pSoftMaskStream->Tell();
9440cdf0e10cSrcweir             rObject.m_pSoftMaskStream->Seek( STREAM_SEEK_TO_BEGIN );
9441cdf0e10cSrcweir             sal_Int32 nMaskObject = createObject();
9442cdf0e10cSrcweir             aLine.append( "/SMask<</Type/Mask/S/Luminosity/G " );
9443cdf0e10cSrcweir             aLine.append( nMaskObject );
9444cdf0e10cSrcweir             aLine.append( " 0 R>>\n" );
9445cdf0e10cSrcweir 
9446cdf0e10cSrcweir             OStringBuffer aMask;
9447cdf0e10cSrcweir             aMask.append( nMaskObject );
9448cdf0e10cSrcweir             aMask.append( " 0 obj\n"
9449cdf0e10cSrcweir                           "<</Type/XObject\n"
9450cdf0e10cSrcweir                           "/Subtype/Form\n"
9451cdf0e10cSrcweir                           "/BBox[" );
9452cdf0e10cSrcweir             appendFixedInt( rObject.m_aBoundRect.Left(), aMask );
9453cdf0e10cSrcweir             aMask.append( ' ' );
9454cdf0e10cSrcweir             appendFixedInt( rObject.m_aBoundRect.Top(), aMask );
9455cdf0e10cSrcweir             aMask.append( ' ' );
9456cdf0e10cSrcweir             appendFixedInt( rObject.m_aBoundRect.Right(), aMask );
9457cdf0e10cSrcweir             aMask.append( ' ' );
9458cdf0e10cSrcweir             appendFixedInt( rObject.m_aBoundRect.Bottom()+1, aMask );
9459cdf0e10cSrcweir             aMask.append( "]\n" );
9460cdf0e10cSrcweir 
9461cdf0e10cSrcweir             /* #i42884# see above */
9462cdf0e10cSrcweir #if 0
9463cdf0e10cSrcweir             aLine.append( "/Resources " );
9464cdf0e10cSrcweir             aMask.append( getResourceDictObj() );
9465cdf0e10cSrcweir             aMask.append( " 0 R\n" );
9466cdf0e10cSrcweir #endif
9467cdf0e10cSrcweir 
9468cdf0e10cSrcweir             aMask.append( "/Group<</S/Transparency/CS/DeviceRGB>>\n" );
9469cdf0e10cSrcweir             aMask.append( "/Length " );
9470cdf0e10cSrcweir             aMask.append( nMaskSize );
9471cdf0e10cSrcweir             aMask.append( ">>\n"
9472cdf0e10cSrcweir                           "stream\n" );
9473cdf0e10cSrcweir             CHECK_RETURN( updateObject( nMaskObject ) );
9474cdf0e10cSrcweir             checkAndEnableStreamEncryption(  nMaskObject );
9475cdf0e10cSrcweir             CHECK_RETURN( writeBuffer( aMask.getStr(), aMask.getLength() ) );
9476cdf0e10cSrcweir             CHECK_RETURN( writeBuffer( rObject.m_pSoftMaskStream->GetData(), nMaskSize ) );
9477cdf0e10cSrcweir             disableStreamEncryption();
9478cdf0e10cSrcweir             aMask.setLength( 0 );
9479cdf0e10cSrcweir             aMask.append( "\nendstream\n"
9480cdf0e10cSrcweir                           "endobj\n\n" );
9481cdf0e10cSrcweir             CHECK_RETURN( writeBuffer( aMask.getStr(), aMask.getLength() ) );
9482cdf0e10cSrcweir         }
9483cdf0e10cSrcweir     }
9484cdf0e10cSrcweir     aLine.append( ">>\n"
9485cdf0e10cSrcweir                   "endobj\n\n" );
9486cdf0e10cSrcweir     CHECK_RETURN( updateObject( rObject.m_nExtGStateObject ) );
9487cdf0e10cSrcweir     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
9488cdf0e10cSrcweir 
9489cdf0e10cSrcweir     return true;
9490cdf0e10cSrcweir }
9491cdf0e10cSrcweir 
9492cdf0e10cSrcweir bool PDFWriterImpl::writeGradientFunction( GradientEmit& rObject )
9493cdf0e10cSrcweir {
9494cdf0e10cSrcweir     sal_Int32 nFunctionObject = createObject();
9495cdf0e10cSrcweir     CHECK_RETURN( updateObject( nFunctionObject ) );
9496cdf0e10cSrcweir 
9497cdf0e10cSrcweir     VirtualDevice aDev;
9498cdf0e10cSrcweir     aDev.SetOutputSizePixel( rObject.m_aSize );
9499cdf0e10cSrcweir     aDev.SetMapMode( MapMode( MAP_PIXEL ) );
9500cdf0e10cSrcweir     if( m_aContext.ColorMode == PDFWriter::DrawGreyscale )
9501cdf0e10cSrcweir         aDev.SetDrawMode( aDev.GetDrawMode() |
9502cdf0e10cSrcweir                           ( DRAWMODE_GRAYLINE | DRAWMODE_GRAYFILL | DRAWMODE_GRAYTEXT |
9503cdf0e10cSrcweir                             DRAWMODE_GRAYBITMAP | DRAWMODE_GRAYGRADIENT ) );
9504cdf0e10cSrcweir     aDev.DrawGradient( Rectangle( Point( 0, 0 ), rObject.m_aSize ), rObject.m_aGradient );
9505cdf0e10cSrcweir 
9506cdf0e10cSrcweir     Bitmap aSample = aDev.GetBitmap( Point( 0, 0 ), rObject.m_aSize );
9507cdf0e10cSrcweir     BitmapReadAccess* pAccess = aSample.AcquireReadAccess();
9508cdf0e10cSrcweir     AccessReleaser aReleaser( pAccess );
9509cdf0e10cSrcweir 
9510cdf0e10cSrcweir     Size aSize = aSample.GetSizePixel();
9511cdf0e10cSrcweir 
9512cdf0e10cSrcweir     sal_Int32 nStreamLengthObject = createObject();
9513cdf0e10cSrcweir     #if OSL_DEBUG_LEVEL > 1
9514cdf0e10cSrcweir     emitComment( "PDFWriterImpl::writeGradientFunction" );
9515cdf0e10cSrcweir     #endif
9516cdf0e10cSrcweir     OStringBuffer aLine( 120 );
9517cdf0e10cSrcweir     aLine.append( nFunctionObject );
9518cdf0e10cSrcweir     aLine.append( " 0 obj\n"
9519cdf0e10cSrcweir                   "<</FunctionType 0\n"
9520cdf0e10cSrcweir                   "/Domain[ 0 1 0 1 ]\n"
9521cdf0e10cSrcweir                   "/Size[ " );
9522cdf0e10cSrcweir     aLine.append( (sal_Int32)aSize.Width() );
9523cdf0e10cSrcweir     aLine.append( ' ' );
9524cdf0e10cSrcweir     aLine.append( (sal_Int32)aSize.Height() );
9525cdf0e10cSrcweir     aLine.append( " ]\n"
9526cdf0e10cSrcweir                   "/BitsPerSample 8\n"
9527cdf0e10cSrcweir                   "/Range[ 0 1 0 1 0 1 ]\n"
9528cdf0e10cSrcweir                   "/Order 3\n"
9529cdf0e10cSrcweir                   "/Length " );
9530cdf0e10cSrcweir     aLine.append( nStreamLengthObject );
9531cdf0e10cSrcweir     aLine.append( " 0 R\n"
9532cdf0e10cSrcweir #ifndef DEBUG_DISABLE_PDFCOMPRESSION
9533cdf0e10cSrcweir                   "/Filter/FlateDecode"
9534cdf0e10cSrcweir #endif
9535cdf0e10cSrcweir                   ">>\n"
9536cdf0e10cSrcweir                   "stream\n" );
9537cdf0e10cSrcweir     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
9538cdf0e10cSrcweir 
9539cdf0e10cSrcweir     sal_uInt64 nStartStreamPos = 0;
9540cdf0e10cSrcweir     CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nStartStreamPos )) );
9541cdf0e10cSrcweir 
9542cdf0e10cSrcweir     checkAndEnableStreamEncryption( nFunctionObject );
9543cdf0e10cSrcweir     beginCompression();
9544cdf0e10cSrcweir     for( int y = aSize.Height()-1; y >= 0; y-- )
9545cdf0e10cSrcweir     {
9546cdf0e10cSrcweir         for( int x = 0; x < aSize.Width(); x++ )
9547cdf0e10cSrcweir         {
9548cdf0e10cSrcweir             sal_uInt8 aCol[3];
9549cdf0e10cSrcweir             BitmapColor aColor = pAccess->GetColor( y, x );
9550cdf0e10cSrcweir             aCol[0] = aColor.GetRed();
9551cdf0e10cSrcweir             aCol[1] = aColor.GetGreen();
9552cdf0e10cSrcweir             aCol[2] = aColor.GetBlue();
9553cdf0e10cSrcweir             CHECK_RETURN( writeBuffer( aCol, 3 ) );
9554cdf0e10cSrcweir         }
9555cdf0e10cSrcweir     }
9556cdf0e10cSrcweir     endCompression();
9557cdf0e10cSrcweir     disableStreamEncryption();
9558cdf0e10cSrcweir 
9559cdf0e10cSrcweir     sal_uInt64 nEndStreamPos = 0;
9560cdf0e10cSrcweir     CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nEndStreamPos )) );
9561cdf0e10cSrcweir 
9562cdf0e10cSrcweir     aLine.setLength( 0 );
9563cdf0e10cSrcweir     aLine.append( "\nendstream\nendobj\n\n" );
9564cdf0e10cSrcweir     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
9565cdf0e10cSrcweir 
9566cdf0e10cSrcweir     // write stream length
9567cdf0e10cSrcweir     CHECK_RETURN( updateObject( nStreamLengthObject ) );
9568cdf0e10cSrcweir     aLine.setLength( 0 );
9569cdf0e10cSrcweir     aLine.append( nStreamLengthObject );
9570cdf0e10cSrcweir     aLine.append( " 0 obj\n" );
9571cdf0e10cSrcweir     aLine.append( (sal_Int64)(nEndStreamPos-nStartStreamPos) );
9572cdf0e10cSrcweir     aLine.append( "\nendobj\n\n" );
9573cdf0e10cSrcweir     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
9574cdf0e10cSrcweir 
9575cdf0e10cSrcweir     CHECK_RETURN( updateObject( rObject.m_nObject ) );
9576cdf0e10cSrcweir     aLine.setLength( 0 );
9577cdf0e10cSrcweir     aLine.append( rObject.m_nObject );
9578cdf0e10cSrcweir     aLine.append( " 0 obj\n"
9579cdf0e10cSrcweir                   "<</ShadingType 1\n"
9580cdf0e10cSrcweir                   "/ColorSpace/DeviceRGB\n"
9581cdf0e10cSrcweir                   "/AntiAlias true\n"
9582cdf0e10cSrcweir                   "/Domain[ 0 1 0 1 ]\n"
9583cdf0e10cSrcweir                   "/Matrix[ " );
9584cdf0e10cSrcweir     aLine.append( (sal_Int32)aSize.Width() );
9585cdf0e10cSrcweir     aLine.append( " 0 0 " );
9586cdf0e10cSrcweir     aLine.append( (sal_Int32)aSize.Height() );
9587cdf0e10cSrcweir     aLine.append( " 0 0 ]\n"
9588cdf0e10cSrcweir                   "/Function " );
9589cdf0e10cSrcweir     aLine.append( nFunctionObject );
9590cdf0e10cSrcweir     aLine.append( " 0 R\n"
9591cdf0e10cSrcweir                   ">>\n"
9592cdf0e10cSrcweir                   "endobj\n\n" );
9593cdf0e10cSrcweir     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
9594cdf0e10cSrcweir 
9595cdf0e10cSrcweir     return true;
9596cdf0e10cSrcweir }
9597cdf0e10cSrcweir 
9598cdf0e10cSrcweir bool PDFWriterImpl::writeJPG( JPGEmit& rObject )
9599cdf0e10cSrcweir {
9600cdf0e10cSrcweir     CHECK_RETURN( rObject.m_pStream );
9601cdf0e10cSrcweir     CHECK_RETURN( updateObject( rObject.m_nObject ) );
9602cdf0e10cSrcweir 
9603cdf0e10cSrcweir     sal_Int32 nLength = 0;
9604cdf0e10cSrcweir     rObject.m_pStream->Seek( STREAM_SEEK_TO_END );
9605cdf0e10cSrcweir     nLength = rObject.m_pStream->Tell();
9606cdf0e10cSrcweir     rObject.m_pStream->Seek( STREAM_SEEK_TO_BEGIN );
9607cdf0e10cSrcweir 
9608cdf0e10cSrcweir     sal_Int32 nMaskObject = 0;
9609cdf0e10cSrcweir     if( !!rObject.m_aMask )
9610cdf0e10cSrcweir     {
9611cdf0e10cSrcweir         if( rObject.m_aMask.GetBitCount() == 1 ||
9612cdf0e10cSrcweir             ( rObject.m_aMask.GetBitCount() == 8 && m_aContext.Version >= PDFWriter::PDF_1_4 && !m_bIsPDF_A1 )//i59651
9613cdf0e10cSrcweir             )
9614cdf0e10cSrcweir         {
9615cdf0e10cSrcweir             nMaskObject = createObject();
9616cdf0e10cSrcweir         }
9617cdf0e10cSrcweir         else if( m_bIsPDF_A1 )
9618cdf0e10cSrcweir             m_aErrors.insert( PDFWriter::Warning_Transparency_Omitted_PDFA );
9619cdf0e10cSrcweir         else if( m_aContext.Version < PDFWriter::PDF_1_4 )
9620cdf0e10cSrcweir             m_aErrors.insert( PDFWriter::Warning_Transparency_Omitted_PDF13 );
9621cdf0e10cSrcweir 
9622cdf0e10cSrcweir     }
9623cdf0e10cSrcweir     #if OSL_DEBUG_LEVEL > 1
9624cdf0e10cSrcweir     emitComment( "PDFWriterImpl::writeJPG" );
9625cdf0e10cSrcweir     #endif
9626cdf0e10cSrcweir 
9627cdf0e10cSrcweir     OStringBuffer aLine(200);
9628cdf0e10cSrcweir     aLine.append( rObject.m_nObject );
9629cdf0e10cSrcweir     aLine.append( " 0 obj\n"
9630cdf0e10cSrcweir                   "<</Type/XObject/Subtype/Image/Width " );
9631cdf0e10cSrcweir     aLine.append( (sal_Int32)rObject.m_aID.m_aPixelSize.Width() );
9632cdf0e10cSrcweir     aLine.append( " /Height " );
9633cdf0e10cSrcweir     aLine.append( (sal_Int32)rObject.m_aID.m_aPixelSize.Height() );
9634cdf0e10cSrcweir     aLine.append( " /BitsPerComponent 8 " );
9635cdf0e10cSrcweir     if( rObject.m_bTrueColor )
9636cdf0e10cSrcweir         aLine.append( "/ColorSpace/DeviceRGB" );
9637cdf0e10cSrcweir     else
9638cdf0e10cSrcweir         aLine.append( "/ColorSpace/DeviceGray" );
9639cdf0e10cSrcweir     aLine.append( "/Filter/DCTDecode/Length " );
9640cdf0e10cSrcweir     aLine.append( nLength );
9641cdf0e10cSrcweir     if( nMaskObject )
9642cdf0e10cSrcweir     {
9643cdf0e10cSrcweir         aLine.append( rObject.m_aMask.GetBitCount() == 1 ? " /Mask " : " /SMask " );
9644cdf0e10cSrcweir         aLine.append( nMaskObject );
9645cdf0e10cSrcweir         aLine.append( " 0 R " );
9646cdf0e10cSrcweir     }
9647cdf0e10cSrcweir     aLine.append( ">>\nstream\n" );
9648cdf0e10cSrcweir     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
9649cdf0e10cSrcweir 
9650cdf0e10cSrcweir     checkAndEnableStreamEncryption( rObject.m_nObject );
9651cdf0e10cSrcweir     CHECK_RETURN( writeBuffer( rObject.m_pStream->GetData(), nLength ) );
9652cdf0e10cSrcweir     disableStreamEncryption();
9653cdf0e10cSrcweir 
9654cdf0e10cSrcweir     aLine.setLength( 0 );
9655cdf0e10cSrcweir     aLine.append( "\nendstream\nendobj\n\n" );
9656cdf0e10cSrcweir     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
9657cdf0e10cSrcweir 
9658cdf0e10cSrcweir     if( nMaskObject )
9659cdf0e10cSrcweir     {
9660cdf0e10cSrcweir         BitmapEmit aEmit;
9661cdf0e10cSrcweir         aEmit.m_nObject = nMaskObject;
9662cdf0e10cSrcweir         if( rObject.m_aMask.GetBitCount() == 1 )
9663cdf0e10cSrcweir             aEmit.m_aBitmap = BitmapEx( rObject.m_aMask, rObject.m_aMask );
9664cdf0e10cSrcweir         else if( rObject.m_aMask.GetBitCount() == 8 )
9665cdf0e10cSrcweir             aEmit.m_aBitmap = BitmapEx( rObject.m_aMask, AlphaMask( rObject.m_aMask ) );
9666cdf0e10cSrcweir         writeBitmapObject( aEmit, true );
9667cdf0e10cSrcweir     }
9668cdf0e10cSrcweir 
9669cdf0e10cSrcweir     return true;
9670cdf0e10cSrcweir }
9671cdf0e10cSrcweir 
9672cdf0e10cSrcweir bool PDFWriterImpl::writeBitmapObject( BitmapEmit& rObject, bool bMask )
9673cdf0e10cSrcweir {
9674cdf0e10cSrcweir     CHECK_RETURN( updateObject( rObject.m_nObject ) );
9675cdf0e10cSrcweir 
9676cdf0e10cSrcweir     Bitmap	aBitmap;
9677cdf0e10cSrcweir     Color	aTransparentColor( COL_TRANSPARENT );
9678cdf0e10cSrcweir     bool	bWriteMask = false;
9679cdf0e10cSrcweir     if( ! bMask )
9680cdf0e10cSrcweir     {
9681cdf0e10cSrcweir         aBitmap = rObject.m_aBitmap.GetBitmap();
9682cdf0e10cSrcweir         if( rObject.m_aBitmap.IsAlpha() )
9683cdf0e10cSrcweir         {
9684cdf0e10cSrcweir             if( m_aContext.Version >= PDFWriter::PDF_1_4 )
9685cdf0e10cSrcweir                 bWriteMask = true;
9686cdf0e10cSrcweir             // else draw without alpha channel
9687cdf0e10cSrcweir         }
9688cdf0e10cSrcweir         else
9689cdf0e10cSrcweir         {
9690cdf0e10cSrcweir             switch( rObject.m_aBitmap.GetTransparentType() )
9691cdf0e10cSrcweir             {
9692cdf0e10cSrcweir                 case TRANSPARENT_NONE:
9693cdf0e10cSrcweir                     // comes from drawMask function
9694cdf0e10cSrcweir                     if( aBitmap.GetBitCount() == 1 && rObject.m_bDrawMask )
9695cdf0e10cSrcweir                         bMask = true;
9696cdf0e10cSrcweir                     break;
9697cdf0e10cSrcweir                 case TRANSPARENT_COLOR:
9698cdf0e10cSrcweir                     aTransparentColor = rObject.m_aBitmap.GetTransparentColor();
9699cdf0e10cSrcweir                     break;
9700cdf0e10cSrcweir                 case TRANSPARENT_BITMAP:
9701cdf0e10cSrcweir                     bWriteMask = true;
9702cdf0e10cSrcweir                     break;
9703cdf0e10cSrcweir             }
9704cdf0e10cSrcweir         }
9705cdf0e10cSrcweir     }
9706cdf0e10cSrcweir     else
9707cdf0e10cSrcweir     {
9708cdf0e10cSrcweir         if( m_aContext.Version < PDFWriter::PDF_1_4 || ! rObject.m_aBitmap.IsAlpha() )
9709cdf0e10cSrcweir         {
9710cdf0e10cSrcweir             aBitmap = rObject.m_aBitmap.GetMask();
9711cdf0e10cSrcweir             aBitmap.Convert( BMP_CONVERSION_1BIT_THRESHOLD );
9712cdf0e10cSrcweir             DBG_ASSERT( aBitmap.GetBitCount() == 1, "mask conversion failed" );
9713cdf0e10cSrcweir         }
9714cdf0e10cSrcweir         else if( aBitmap.GetBitCount() != 8 )
9715cdf0e10cSrcweir         {
9716cdf0e10cSrcweir             aBitmap = rObject.m_aBitmap.GetAlpha().GetBitmap();
9717cdf0e10cSrcweir             aBitmap.Convert( BMP_CONVERSION_8BIT_GREYS );
9718cdf0e10cSrcweir             DBG_ASSERT( aBitmap.GetBitCount() == 8, "alpha mask conversion failed" );
9719cdf0e10cSrcweir         }
9720cdf0e10cSrcweir     }
9721cdf0e10cSrcweir 
9722cdf0e10cSrcweir     BitmapReadAccess* pAccess = aBitmap.AcquireReadAccess();
9723cdf0e10cSrcweir     AccessReleaser aReleaser( pAccess );
9724cdf0e10cSrcweir 
9725cdf0e10cSrcweir     bool bTrueColor;
9726cdf0e10cSrcweir     sal_Int32 nBitsPerComponent;
9727cdf0e10cSrcweir     switch( aBitmap.GetBitCount() )
9728cdf0e10cSrcweir     {
9729cdf0e10cSrcweir         case 1:
9730cdf0e10cSrcweir         case 2:
9731cdf0e10cSrcweir         case 4:
9732cdf0e10cSrcweir         case 8:
9733cdf0e10cSrcweir             bTrueColor = false;
9734cdf0e10cSrcweir             nBitsPerComponent = aBitmap.GetBitCount();
9735cdf0e10cSrcweir             break;
9736cdf0e10cSrcweir         default:
9737cdf0e10cSrcweir             bTrueColor = true;
9738cdf0e10cSrcweir             nBitsPerComponent = 8;
9739cdf0e10cSrcweir             break;
9740cdf0e10cSrcweir     }
9741cdf0e10cSrcweir 
9742cdf0e10cSrcweir     sal_Int32 nStreamLengthObject	= createObject();
9743cdf0e10cSrcweir     sal_Int32 nMaskObject			= 0;
9744cdf0e10cSrcweir 
9745cdf0e10cSrcweir     #if OSL_DEBUG_LEVEL > 1
9746cdf0e10cSrcweir     emitComment( "PDFWriterImpl::writeBitmapObject" );
9747cdf0e10cSrcweir     #endif
9748cdf0e10cSrcweir     OStringBuffer aLine(1024);
9749cdf0e10cSrcweir     aLine.append( rObject.m_nObject );
9750cdf0e10cSrcweir     aLine.append( " 0 obj\n"
9751cdf0e10cSrcweir                   "<</Type/XObject/Subtype/Image/Width " );
9752cdf0e10cSrcweir     aLine.append( (sal_Int32)aBitmap.GetSizePixel().Width() );
9753cdf0e10cSrcweir     aLine.append( "/Height " );
9754cdf0e10cSrcweir     aLine.append( (sal_Int32)aBitmap.GetSizePixel().Height() );
9755cdf0e10cSrcweir     aLine.append( "/BitsPerComponent " );
9756cdf0e10cSrcweir     aLine.append( nBitsPerComponent );
9757cdf0e10cSrcweir     aLine.append( "/Length " );
9758cdf0e10cSrcweir     aLine.append( nStreamLengthObject );
9759cdf0e10cSrcweir     aLine.append( " 0 R\n" );
9760cdf0e10cSrcweir #ifndef DEBUG_DISABLE_PDFCOMPRESSION
9761cdf0e10cSrcweir     if( nBitsPerComponent != 1 )
9762cdf0e10cSrcweir     {
9763cdf0e10cSrcweir         aLine.append( "/Filter/FlateDecode" );
9764cdf0e10cSrcweir     }
9765cdf0e10cSrcweir     else
9766cdf0e10cSrcweir     {
9767cdf0e10cSrcweir         aLine.append( "/Filter/CCITTFaxDecode/DecodeParms<</K -1/BlackIs1 true/Columns " );
9768cdf0e10cSrcweir         aLine.append( (sal_Int32)aBitmap.GetSizePixel().Width() );
9769cdf0e10cSrcweir         aLine.append( ">>\n" );
9770cdf0e10cSrcweir     }
9771cdf0e10cSrcweir #endif
9772cdf0e10cSrcweir     if( ! bMask )
9773cdf0e10cSrcweir     {
9774cdf0e10cSrcweir         aLine.append( "/ColorSpace" );
9775cdf0e10cSrcweir         if( bTrueColor )
9776cdf0e10cSrcweir             aLine.append( "/DeviceRGB\n" );
9777cdf0e10cSrcweir         else if( aBitmap.HasGreyPalette() )
9778cdf0e10cSrcweir         {
9779cdf0e10cSrcweir             aLine.append( "/DeviceGray\n" );
9780cdf0e10cSrcweir             if( aBitmap.GetBitCount() == 1 )
9781cdf0e10cSrcweir             {
9782cdf0e10cSrcweir                 // #i47395# 1 bit bitmaps occasionally have an inverted grey palette
9783cdf0e10cSrcweir                 sal_Int32 nBlackIndex = pAccess->GetBestPaletteIndex( BitmapColor( Color( COL_BLACK ) ) );
9784cdf0e10cSrcweir                 DBG_ASSERT( nBlackIndex == 0 || nBlackIndex == 1, "wrong black index" );
9785cdf0e10cSrcweir                 if( nBlackIndex == 1 )
9786cdf0e10cSrcweir                     aLine.append( "/Decode[1 0]\n" );
9787cdf0e10cSrcweir             }
9788cdf0e10cSrcweir         }
9789cdf0e10cSrcweir         else
9790cdf0e10cSrcweir         {
9791cdf0e10cSrcweir             aLine.append( "[ /Indexed/DeviceRGB " );
9792cdf0e10cSrcweir             aLine.append( (sal_Int32)(pAccess->GetPaletteEntryCount()-1) );
9793cdf0e10cSrcweir             aLine.append( "\n<" );
9794cdf0e10cSrcweir 			if( m_aContext.Encryption.Encrypt() )
9795cdf0e10cSrcweir 			{
9796cdf0e10cSrcweir 				enableStringEncryption( rObject.m_nObject );
9797cdf0e10cSrcweir 				//check encryption buffer size
9798cdf0e10cSrcweir 				if( checkEncryptionBufferSize( pAccess->GetPaletteEntryCount()*3 ) )
9799cdf0e10cSrcweir 				{
9800cdf0e10cSrcweir 					int	nChar = 0;
9801cdf0e10cSrcweir 					//fill the encryption buffer
9802cdf0e10cSrcweir 					for( sal_uInt16 i = 0; i < pAccess->GetPaletteEntryCount(); i++ )
9803cdf0e10cSrcweir 					{
9804cdf0e10cSrcweir 						const BitmapColor& rColor = pAccess->GetPaletteColor( i );
9805cdf0e10cSrcweir 						m_pEncryptionBuffer[nChar++] = rColor.GetRed();
9806cdf0e10cSrcweir 						m_pEncryptionBuffer[nChar++] = rColor.GetGreen();
9807cdf0e10cSrcweir 						m_pEncryptionBuffer[nChar++] = rColor.GetBlue();
9808cdf0e10cSrcweir 					}
9809cdf0e10cSrcweir 					//encrypt the colorspace lookup table
9810cdf0e10cSrcweir 					rtl_cipher_encodeARCFOUR( m_aCipher, m_pEncryptionBuffer, nChar, m_pEncryptionBuffer, nChar );
9811cdf0e10cSrcweir 					//now queue the data for output
9812cdf0e10cSrcweir                     nChar = 0;
9813cdf0e10cSrcweir 					for( sal_uInt16 i = 0; i < pAccess->GetPaletteEntryCount(); i++ )
9814cdf0e10cSrcweir 					{
9815cdf0e10cSrcweir 						appendHex(m_pEncryptionBuffer[nChar++], aLine );
9816cdf0e10cSrcweir 						appendHex(m_pEncryptionBuffer[nChar++], aLine );
9817cdf0e10cSrcweir 						appendHex(m_pEncryptionBuffer[nChar++], aLine );
9818cdf0e10cSrcweir 					}
9819cdf0e10cSrcweir 				}
9820cdf0e10cSrcweir 			}
9821cdf0e10cSrcweir 			else //no encryption requested (PDF/A-1a program flow drops here)
9822cdf0e10cSrcweir 			{
9823cdf0e10cSrcweir 				for( sal_uInt16 i = 0; i < pAccess->GetPaletteEntryCount(); i++ )
9824cdf0e10cSrcweir 				{
9825cdf0e10cSrcweir 					const BitmapColor& rColor = pAccess->GetPaletteColor( i );
9826cdf0e10cSrcweir 					appendHex( rColor.GetRed(), aLine );
9827cdf0e10cSrcweir 					appendHex( rColor.GetGreen(), aLine );
9828cdf0e10cSrcweir 					appendHex( rColor.GetBlue(), aLine );
9829cdf0e10cSrcweir 				}
9830cdf0e10cSrcweir 			}
9831cdf0e10cSrcweir             aLine.append( ">\n]\n" );
9832cdf0e10cSrcweir         }
9833cdf0e10cSrcweir     }
9834cdf0e10cSrcweir     else
9835cdf0e10cSrcweir     {
9836cdf0e10cSrcweir         if( aBitmap.GetBitCount() == 1 )
9837cdf0e10cSrcweir         {
9838cdf0e10cSrcweir             aLine.append( "/ImageMask true\n" );
9839cdf0e10cSrcweir             sal_Int32 nBlackIndex = pAccess->GetBestPaletteIndex( BitmapColor( Color( COL_BLACK ) ) );
9840cdf0e10cSrcweir             DBG_ASSERT( nBlackIndex == 0 || nBlackIndex == 1, "wrong black index" );
9841cdf0e10cSrcweir             if( nBlackIndex )
9842cdf0e10cSrcweir                 aLine.append( "/Decode[ 1 0 ]\n" );
9843cdf0e10cSrcweir             else
9844cdf0e10cSrcweir                 aLine.append( "/Decode[ 0 1 ]\n" );
9845cdf0e10cSrcweir         }
9846cdf0e10cSrcweir         else if( aBitmap.GetBitCount() == 8 )
9847cdf0e10cSrcweir         {
9848cdf0e10cSrcweir             aLine.append( "/ColorSpace/DeviceGray\n"
9849cdf0e10cSrcweir                           "/Decode [ 1 0 ]\n" );
9850cdf0e10cSrcweir         }
9851cdf0e10cSrcweir     }
9852cdf0e10cSrcweir 
9853cdf0e10cSrcweir     if( ! bMask && m_aContext.Version > PDFWriter::PDF_1_2 && !m_bIsPDF_A1 )//i59651
9854cdf0e10cSrcweir     {
9855cdf0e10cSrcweir         if( bWriteMask )
9856cdf0e10cSrcweir         {
9857cdf0e10cSrcweir             nMaskObject = createObject();
9858cdf0e10cSrcweir             if( rObject.m_aBitmap.IsAlpha() && m_aContext.Version > PDFWriter::PDF_1_3 )
9859cdf0e10cSrcweir                 aLine.append( "/SMask " );
9860cdf0e10cSrcweir             else
9861cdf0e10cSrcweir                 aLine.append( "/Mask " );
9862cdf0e10cSrcweir             aLine.append( nMaskObject );
9863cdf0e10cSrcweir             aLine.append( " 0 R\n" );
9864cdf0e10cSrcweir         }
9865cdf0e10cSrcweir         else if( aTransparentColor != Color( COL_TRANSPARENT ) )
9866cdf0e10cSrcweir         {
9867cdf0e10cSrcweir             aLine.append( "/Mask[ " );
9868cdf0e10cSrcweir             if( bTrueColor )
9869cdf0e10cSrcweir             {
9870cdf0e10cSrcweir                 aLine.append( (sal_Int32)aTransparentColor.GetRed() );
9871cdf0e10cSrcweir                 aLine.append( ' ' );
9872cdf0e10cSrcweir                 aLine.append( (sal_Int32)aTransparentColor.GetRed() );
9873cdf0e10cSrcweir                 aLine.append( ' ' );
9874cdf0e10cSrcweir                 aLine.append( (sal_Int32)aTransparentColor.GetGreen() );
9875cdf0e10cSrcweir                 aLine.append( ' ' );
9876cdf0e10cSrcweir                 aLine.append( (sal_Int32)aTransparentColor.GetGreen() );
9877cdf0e10cSrcweir                 aLine.append( ' ' );
9878cdf0e10cSrcweir                 aLine.append( (sal_Int32)aTransparentColor.GetBlue() );
9879cdf0e10cSrcweir                 aLine.append( ' ' );
9880cdf0e10cSrcweir                 aLine.append( (sal_Int32)aTransparentColor.GetBlue() );
9881cdf0e10cSrcweir             }
9882cdf0e10cSrcweir             else
9883cdf0e10cSrcweir             {
9884cdf0e10cSrcweir                 sal_Int32 nIndex = pAccess->GetBestPaletteIndex( BitmapColor( aTransparentColor ) );
9885cdf0e10cSrcweir                 aLine.append( nIndex );
9886cdf0e10cSrcweir             }
9887cdf0e10cSrcweir             aLine.append( " ]\n" );
9888cdf0e10cSrcweir         }
9889cdf0e10cSrcweir     }
9890cdf0e10cSrcweir     else if( m_bIsPDF_A1 && (bWriteMask || aTransparentColor != Color( COL_TRANSPARENT )) )
9891cdf0e10cSrcweir         m_aErrors.insert( PDFWriter::Warning_Transparency_Omitted_PDFA );
9892cdf0e10cSrcweir 
9893cdf0e10cSrcweir     aLine.append( ">>\n"
9894cdf0e10cSrcweir                   "stream\n" );
9895cdf0e10cSrcweir     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
9896cdf0e10cSrcweir     sal_uInt64 nStartPos = 0;
9897cdf0e10cSrcweir     CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nStartPos )) );
9898cdf0e10cSrcweir 
9899cdf0e10cSrcweir     checkAndEnableStreamEncryption( rObject.m_nObject );
9900cdf0e10cSrcweir #ifndef DEBUG_DISABLE_PDFCOMPRESSION
9901cdf0e10cSrcweir     if( nBitsPerComponent == 1 )
9902cdf0e10cSrcweir     {
9903cdf0e10cSrcweir         writeG4Stream( pAccess );
9904cdf0e10cSrcweir     }
9905cdf0e10cSrcweir     else
9906cdf0e10cSrcweir #endif
9907cdf0e10cSrcweir     {
9908cdf0e10cSrcweir         beginCompression();
9909cdf0e10cSrcweir         if( ! bTrueColor || pAccess->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB )
9910cdf0e10cSrcweir         {
9911cdf0e10cSrcweir             const int nScanLineBytes = 1 + ( pAccess->GetBitCount() * ( pAccess->Width() - 1 ) / 8U );
9912cdf0e10cSrcweir 
9913cdf0e10cSrcweir             for( int i = 0; i < pAccess->Height(); i++ )
9914cdf0e10cSrcweir             {
9915cdf0e10cSrcweir                 CHECK_RETURN( writeBuffer( pAccess->GetScanline( i ), nScanLineBytes ) );
9916cdf0e10cSrcweir             }
9917cdf0e10cSrcweir         }
9918cdf0e10cSrcweir         else
9919cdf0e10cSrcweir         {
9920cdf0e10cSrcweir             const int nScanLineBytes = pAccess->Width()*3;
9921cdf0e10cSrcweir             boost::shared_array<sal_uInt8> pCol( new sal_uInt8[ nScanLineBytes ] );
9922cdf0e10cSrcweir             for( int y = 0; y < pAccess->Height(); y++ )
9923cdf0e10cSrcweir             {
9924cdf0e10cSrcweir                 for( int x = 0; x < pAccess->Width(); x++ )
9925cdf0e10cSrcweir                 {
9926cdf0e10cSrcweir                     BitmapColor aColor = pAccess->GetColor( y, x );
9927cdf0e10cSrcweir                     pCol[3*x+0] = aColor.GetRed();
9928cdf0e10cSrcweir                     pCol[3*x+1] = aColor.GetGreen();
9929cdf0e10cSrcweir                     pCol[3*x+2] = aColor.GetBlue();
9930cdf0e10cSrcweir                 }
9931cdf0e10cSrcweir                 CHECK_RETURN( writeBuffer( pCol.get(), nScanLineBytes ) );
9932cdf0e10cSrcweir             }
9933cdf0e10cSrcweir         }
9934cdf0e10cSrcweir         endCompression();
9935cdf0e10cSrcweir     }
9936cdf0e10cSrcweir     disableStreamEncryption();
9937cdf0e10cSrcweir 
9938cdf0e10cSrcweir     sal_uInt64 nEndPos = 0;
9939cdf0e10cSrcweir     CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nEndPos )) );
9940cdf0e10cSrcweir     aLine.setLength( 0 );
9941cdf0e10cSrcweir     aLine.append( "\nendstream\nendobj\n\n" );
9942cdf0e10cSrcweir     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
9943cdf0e10cSrcweir     CHECK_RETURN( updateObject( nStreamLengthObject ) );
9944cdf0e10cSrcweir     aLine.setLength( 0 );
9945cdf0e10cSrcweir     aLine.append( nStreamLengthObject );
9946cdf0e10cSrcweir     aLine.append( " 0 obj\n" );
9947cdf0e10cSrcweir     aLine.append( (sal_Int64)(nEndPos-nStartPos) );
9948cdf0e10cSrcweir     aLine.append( "\nendobj\n\n" );
9949cdf0e10cSrcweir     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
9950cdf0e10cSrcweir 
9951cdf0e10cSrcweir     if( nMaskObject )
9952cdf0e10cSrcweir     {
9953cdf0e10cSrcweir         BitmapEmit aEmit;
9954cdf0e10cSrcweir         aEmit.m_nObject				= nMaskObject;
9955cdf0e10cSrcweir         aEmit.m_aBitmap				= rObject.m_aBitmap;
9956cdf0e10cSrcweir         return writeBitmapObject( aEmit, true );
9957cdf0e10cSrcweir     }
9958cdf0e10cSrcweir 
9959cdf0e10cSrcweir     return true;
9960cdf0e10cSrcweir }
9961cdf0e10cSrcweir 
9962cdf0e10cSrcweir void PDFWriterImpl::drawJPGBitmap( SvStream& rDCTData, bool bIsTrueColor, const Size& rSizePixel, const Rectangle& rTargetArea, const Bitmap& rMask )
9963cdf0e10cSrcweir {
9964cdf0e10cSrcweir     MARK( "drawJPGBitmap" );
9965cdf0e10cSrcweir 
9966cdf0e10cSrcweir     OStringBuffer aLine( 80 );
9967cdf0e10cSrcweir     updateGraphicsState();
9968cdf0e10cSrcweir 
9969cdf0e10cSrcweir     // #i40055# sanity check
9970cdf0e10cSrcweir     if( ! (rTargetArea.GetWidth() && rTargetArea.GetHeight() ) )
9971cdf0e10cSrcweir         return;
9972cdf0e10cSrcweir     if( ! (rSizePixel.Width() && rSizePixel.Height()) )
9973cdf0e10cSrcweir         return;
9974cdf0e10cSrcweir 
9975cdf0e10cSrcweir     rDCTData.Seek( 0 );
9976cdf0e10cSrcweir     if( bIsTrueColor && m_aContext.ColorMode == PDFWriter::DrawGreyscale )
9977cdf0e10cSrcweir     {
9978cdf0e10cSrcweir         // need to convert to grayscale;
9979cdf0e10cSrcweir         // load stream to bitmap and draw the bitmap instead
9980cdf0e10cSrcweir         Graphic aGraphic;
9981cdf0e10cSrcweir         GraphicConverter::Import( rDCTData, aGraphic, CVT_JPG );
9982cdf0e10cSrcweir         Bitmap aBmp( aGraphic.GetBitmap() );
9983cdf0e10cSrcweir         if( !!rMask && rMask.GetSizePixel() == aBmp.GetSizePixel() )
9984cdf0e10cSrcweir         {
9985cdf0e10cSrcweir             BitmapEx aBmpEx( aBmp, rMask );
9986cdf0e10cSrcweir             drawBitmap( rTargetArea.TopLeft(), rTargetArea.GetSize(), aBmpEx );
9987cdf0e10cSrcweir         }
9988cdf0e10cSrcweir         else
9989cdf0e10cSrcweir             drawBitmap( rTargetArea.TopLeft(), rTargetArea.GetSize(), aBmp );
9990cdf0e10cSrcweir         return;
9991cdf0e10cSrcweir     }
9992cdf0e10cSrcweir 
9993cdf0e10cSrcweir     SvMemoryStream* pStream = new SvMemoryStream;
9994cdf0e10cSrcweir     *pStream << rDCTData;
9995cdf0e10cSrcweir     pStream->Seek( STREAM_SEEK_TO_END );
9996cdf0e10cSrcweir 
9997cdf0e10cSrcweir     BitmapID aID;
9998cdf0e10cSrcweir     aID.m_aPixelSize	= rSizePixel;
9999cdf0e10cSrcweir     aID.m_nSize			= pStream->Tell();
10000cdf0e10cSrcweir     pStream->Seek( STREAM_SEEK_TO_BEGIN );
10001cdf0e10cSrcweir     aID.m_nChecksum		= rtl_crc32( 0, pStream->GetData(), aID.m_nSize );
10002cdf0e10cSrcweir     if( ! rMask.IsEmpty() )
10003cdf0e10cSrcweir         aID.m_nMaskChecksum	= rMask.GetChecksum();
10004cdf0e10cSrcweir 
10005cdf0e10cSrcweir     std::list< JPGEmit >::const_iterator it;
10006cdf0e10cSrcweir     for( it = m_aJPGs.begin(); it != m_aJPGs.end() && ! (aID == it->m_aID); ++it )
10007cdf0e10cSrcweir         ;
10008cdf0e10cSrcweir     if( it == m_aJPGs.end() )
10009cdf0e10cSrcweir     {
10010cdf0e10cSrcweir         m_aJPGs.push_front( JPGEmit() );
10011cdf0e10cSrcweir         JPGEmit& rEmit = m_aJPGs.front();
10012cdf0e10cSrcweir         rEmit.m_nObject		= createObject();
10013cdf0e10cSrcweir         rEmit.m_aID			= aID;
10014cdf0e10cSrcweir         rEmit.m_pStream		= pStream;
10015cdf0e10cSrcweir         rEmit.m_bTrueColor  = bIsTrueColor;
10016cdf0e10cSrcweir         if( !! rMask && rMask.GetSizePixel() == rSizePixel )
10017cdf0e10cSrcweir             rEmit.m_aMask	= rMask;
10018cdf0e10cSrcweir 
10019cdf0e10cSrcweir         it = m_aJPGs.begin();
10020cdf0e10cSrcweir     }
10021cdf0e10cSrcweir     else
10022cdf0e10cSrcweir         delete pStream;
10023cdf0e10cSrcweir 
10024cdf0e10cSrcweir     aLine.append( "q " );
10025cdf0e10cSrcweir     sal_Int32 nCheckWidth = 0;
10026cdf0e10cSrcweir     m_aPages.back().appendMappedLength( (sal_Int32)rTargetArea.GetWidth(), aLine, false, &nCheckWidth );
10027cdf0e10cSrcweir     aLine.append( " 0 0 " );
10028cdf0e10cSrcweir     sal_Int32 nCheckHeight = 0;
10029cdf0e10cSrcweir     m_aPages.back().appendMappedLength( (sal_Int32)rTargetArea.GetHeight(), aLine, true, &nCheckHeight );
10030cdf0e10cSrcweir     aLine.append( ' ' );
10031cdf0e10cSrcweir     m_aPages.back().appendPoint( rTargetArea.BottomLeft(), aLine );
10032cdf0e10cSrcweir     aLine.append( " cm\n/Im" );
10033cdf0e10cSrcweir     aLine.append( it->m_nObject );
10034cdf0e10cSrcweir     aLine.append( " Do Q\n" );
10035cdf0e10cSrcweir     if( nCheckWidth == 0 || nCheckHeight == 0 )
10036cdf0e10cSrcweir     {
10037cdf0e10cSrcweir         // #i97512# avoid invalid current matrix
10038cdf0e10cSrcweir         aLine.setLength( 0 );
10039cdf0e10cSrcweir         aLine.append( "\n%jpeg image /Im" );
10040cdf0e10cSrcweir         aLine.append( it->m_nObject );
10041cdf0e10cSrcweir         aLine.append( " scaled to zero size, omitted\n" );
10042cdf0e10cSrcweir     }
10043cdf0e10cSrcweir     writeBuffer( aLine.getStr(), aLine.getLength() );
10044cdf0e10cSrcweir 
10045cdf0e10cSrcweir     OStringBuffer aObjName( 16 );
10046cdf0e10cSrcweir     aObjName.append( "Im" );
10047cdf0e10cSrcweir     aObjName.append( it->m_nObject );
10048cdf0e10cSrcweir     pushResource( ResXObject, aObjName.makeStringAndClear(), it->m_nObject );
10049cdf0e10cSrcweir 
10050cdf0e10cSrcweir }
10051cdf0e10cSrcweir 
10052cdf0e10cSrcweir void PDFWriterImpl::drawBitmap( const Point& rDestPoint, const Size& rDestSize, const BitmapEmit& rBitmap, const Color& rFillColor )
10053cdf0e10cSrcweir {
10054cdf0e10cSrcweir     OStringBuffer aLine( 80 );
10055cdf0e10cSrcweir     updateGraphicsState();
10056cdf0e10cSrcweir 
10057cdf0e10cSrcweir     aLine.append( "q " );
10058cdf0e10cSrcweir     if( rFillColor != Color( COL_TRANSPARENT ) )
10059cdf0e10cSrcweir     {
10060cdf0e10cSrcweir         appendNonStrokingColor( rFillColor, aLine );
10061cdf0e10cSrcweir         aLine.append( ' ' );
10062cdf0e10cSrcweir     }
10063cdf0e10cSrcweir     sal_Int32 nCheckWidth = 0;
10064cdf0e10cSrcweir     m_aPages.back().appendMappedLength( (sal_Int32)rDestSize.Width(), aLine, false, &nCheckWidth );
10065cdf0e10cSrcweir     aLine.append( " 0 0 " );
10066cdf0e10cSrcweir     sal_Int32 nCheckHeight = 0;
10067cdf0e10cSrcweir     m_aPages.back().appendMappedLength( (sal_Int32)rDestSize.Height(), aLine, true, &nCheckHeight );
10068cdf0e10cSrcweir     aLine.append( ' ' );
10069cdf0e10cSrcweir     m_aPages.back().appendPoint( rDestPoint + Point( 0, rDestSize.Height()-1 ), aLine );
10070cdf0e10cSrcweir     aLine.append( " cm\n/Im" );
10071cdf0e10cSrcweir     aLine.append( rBitmap.m_nObject );
10072cdf0e10cSrcweir     aLine.append( " Do Q\n" );
10073cdf0e10cSrcweir     if( nCheckWidth == 0 || nCheckHeight == 0 )
10074cdf0e10cSrcweir     {
10075cdf0e10cSrcweir         // #i97512# avoid invalid current matrix
10076cdf0e10cSrcweir         aLine.setLength( 0 );
10077cdf0e10cSrcweir         aLine.append( "\n%bitmap image /Im" );
10078cdf0e10cSrcweir         aLine.append( rBitmap.m_nObject );
10079cdf0e10cSrcweir         aLine.append( " scaled to zero size, omitted\n" );
10080cdf0e10cSrcweir     }
10081cdf0e10cSrcweir     writeBuffer( aLine.getStr(), aLine.getLength() );
10082cdf0e10cSrcweir }
10083cdf0e10cSrcweir 
10084cdf0e10cSrcweir const PDFWriterImpl::BitmapEmit& PDFWriterImpl::createBitmapEmit( const BitmapEx& i_rBitmap, bool bDrawMask )
10085cdf0e10cSrcweir {
10086cdf0e10cSrcweir     BitmapEx aBitmap( i_rBitmap );
10087cdf0e10cSrcweir     if( m_aContext.ColorMode == PDFWriter::DrawGreyscale )
10088cdf0e10cSrcweir     {
10089cdf0e10cSrcweir         BmpConversion eConv = BMP_CONVERSION_8BIT_GREYS;
10090cdf0e10cSrcweir         int nDepth = aBitmap.GetBitmap().GetBitCount();
10091cdf0e10cSrcweir         if( nDepth <= 4 )
10092cdf0e10cSrcweir             eConv = BMP_CONVERSION_4BIT_GREYS;
10093cdf0e10cSrcweir         if( nDepth > 1 )
10094cdf0e10cSrcweir             aBitmap.Convert( eConv );
10095cdf0e10cSrcweir     }
10096cdf0e10cSrcweir     BitmapID aID;
10097cdf0e10cSrcweir     aID.m_aPixelSize		= aBitmap.GetSizePixel();
10098cdf0e10cSrcweir     aID.m_nSize				= aBitmap.GetBitCount();
10099cdf0e10cSrcweir     aID.m_nChecksum			= aBitmap.GetBitmap().GetChecksum();
10100cdf0e10cSrcweir     aID.m_nMaskChecksum		= 0;
10101cdf0e10cSrcweir     if( aBitmap.IsAlpha() )
10102cdf0e10cSrcweir         aID.m_nMaskChecksum = aBitmap.GetAlpha().GetChecksum();
10103cdf0e10cSrcweir     else
10104cdf0e10cSrcweir     {
10105cdf0e10cSrcweir         Bitmap aMask = aBitmap.GetMask();
10106cdf0e10cSrcweir         if( ! aMask.IsEmpty() )
10107cdf0e10cSrcweir             aID.m_nMaskChecksum = aMask.GetChecksum();
10108cdf0e10cSrcweir     }
10109cdf0e10cSrcweir     std::list< BitmapEmit >::const_iterator it;
10110cdf0e10cSrcweir     for( it = m_aBitmaps.begin(); it != m_aBitmaps.end(); ++it )
10111cdf0e10cSrcweir     {
10112cdf0e10cSrcweir         if( aID == it->m_aID )
10113cdf0e10cSrcweir             break;
10114cdf0e10cSrcweir     }
10115cdf0e10cSrcweir     if( it == m_aBitmaps.end() )
10116cdf0e10cSrcweir     {
10117cdf0e10cSrcweir         m_aBitmaps.push_front( BitmapEmit() );
10118cdf0e10cSrcweir         m_aBitmaps.front().m_aID		= aID;
10119cdf0e10cSrcweir         m_aBitmaps.front().m_aBitmap	= aBitmap;
10120cdf0e10cSrcweir         m_aBitmaps.front().m_nObject	= createObject();
10121cdf0e10cSrcweir         m_aBitmaps.front().m_bDrawMask	= bDrawMask;
10122cdf0e10cSrcweir         it = m_aBitmaps.begin();
10123cdf0e10cSrcweir     }
10124cdf0e10cSrcweir 
10125cdf0e10cSrcweir     OStringBuffer aObjName( 16 );
10126cdf0e10cSrcweir     aObjName.append( "Im" );
10127cdf0e10cSrcweir     aObjName.append( it->m_nObject );
10128cdf0e10cSrcweir     pushResource( ResXObject, aObjName.makeStringAndClear(), it->m_nObject );
10129cdf0e10cSrcweir 
10130cdf0e10cSrcweir     return *it;
10131cdf0e10cSrcweir }
10132cdf0e10cSrcweir 
10133cdf0e10cSrcweir void PDFWriterImpl::drawBitmap( const Point& rDestPoint, const Size& rDestSize, const Bitmap& rBitmap )
10134cdf0e10cSrcweir {
10135cdf0e10cSrcweir     MARK( "drawBitmap (Bitmap)" );
10136cdf0e10cSrcweir 
10137cdf0e10cSrcweir     // #i40055# sanity check
10138cdf0e10cSrcweir     if( ! (rDestSize.Width() && rDestSize.Height()) )
10139cdf0e10cSrcweir         return;
10140cdf0e10cSrcweir 
10141cdf0e10cSrcweir     const BitmapEmit& rEmit = createBitmapEmit( BitmapEx( rBitmap ) );
10142cdf0e10cSrcweir     drawBitmap( rDestPoint, rDestSize, rEmit, Color( COL_TRANSPARENT ) );
10143cdf0e10cSrcweir }
10144cdf0e10cSrcweir 
10145cdf0e10cSrcweir void PDFWriterImpl::drawBitmap( const Point& rDestPoint, const Size& rDestSize, const BitmapEx& rBitmap )
10146cdf0e10cSrcweir {
10147cdf0e10cSrcweir     MARK( "drawBitmap (BitmapEx)" );
10148cdf0e10cSrcweir 
10149cdf0e10cSrcweir     // #i40055# sanity check
10150cdf0e10cSrcweir     if( ! (rDestSize.Width() && rDestSize.Height()) )
10151cdf0e10cSrcweir         return;
10152cdf0e10cSrcweir 
10153cdf0e10cSrcweir     const BitmapEmit& rEmit = createBitmapEmit( rBitmap );
10154cdf0e10cSrcweir     drawBitmap( rDestPoint, rDestSize, rEmit, Color( COL_TRANSPARENT ) );
10155cdf0e10cSrcweir }
10156cdf0e10cSrcweir 
10157cdf0e10cSrcweir void PDFWriterImpl::drawMask( const Point& rDestPoint, const Size& rDestSize, const Bitmap& rBitmap, const Color& rFillColor )
10158cdf0e10cSrcweir {
10159cdf0e10cSrcweir     MARK( "drawMask" );
10160cdf0e10cSrcweir 
10161cdf0e10cSrcweir     // #i40055# sanity check
10162cdf0e10cSrcweir     if( ! (rDestSize.Width() && rDestSize.Height()) )
10163cdf0e10cSrcweir         return;
10164cdf0e10cSrcweir 
10165cdf0e10cSrcweir     Bitmap aBitmap( rBitmap );
10166cdf0e10cSrcweir     if( aBitmap.GetBitCount() > 1 )
10167cdf0e10cSrcweir         aBitmap.Convert( BMP_CONVERSION_1BIT_THRESHOLD );
10168cdf0e10cSrcweir     DBG_ASSERT( aBitmap.GetBitCount() == 1, "mask conversion failed" );
10169cdf0e10cSrcweir 
10170cdf0e10cSrcweir     const BitmapEmit& rEmit = createBitmapEmit( BitmapEx( aBitmap ), true );
10171cdf0e10cSrcweir     drawBitmap( rDestPoint, rDestSize, rEmit, rFillColor );
10172cdf0e10cSrcweir }
10173cdf0e10cSrcweir 
10174cdf0e10cSrcweir sal_Int32 PDFWriterImpl::createGradient( const Gradient& rGradient, const Size& rSize )
10175cdf0e10cSrcweir {
10176cdf0e10cSrcweir     Size aPtSize( lcl_convert( m_aGraphicsStack.front().m_aMapMode,
10177cdf0e10cSrcweir                                MapMode( MAP_POINT ),
10178cdf0e10cSrcweir                                getReferenceDevice(),
10179cdf0e10cSrcweir                                rSize ) );
10180cdf0e10cSrcweir     // check if we already have this gradient
10181cdf0e10cSrcweir     std::list<GradientEmit>::iterator it;
10182cdf0e10cSrcweir     // rounding to point will generally lose some pixels
10183cdf0e10cSrcweir     // round up to point boundary
10184cdf0e10cSrcweir     aPtSize.Width()++;
10185cdf0e10cSrcweir     aPtSize.Height()++;
10186cdf0e10cSrcweir     for( it = m_aGradients.begin(); it != m_aGradients.end(); ++it )
10187cdf0e10cSrcweir     {
10188cdf0e10cSrcweir         if( it->m_aGradient == rGradient )
10189cdf0e10cSrcweir         {
10190cdf0e10cSrcweir             if( it->m_aSize == aPtSize )
10191cdf0e10cSrcweir                 break;
10192cdf0e10cSrcweir         }
10193cdf0e10cSrcweir     }
10194cdf0e10cSrcweir     if( it == m_aGradients.end() )
10195cdf0e10cSrcweir     {
10196cdf0e10cSrcweir         m_aGradients.push_front( GradientEmit() );
10197cdf0e10cSrcweir         m_aGradients.front().m_aGradient	= rGradient;
10198cdf0e10cSrcweir         m_aGradients.front().m_nObject	    = createObject();
10199cdf0e10cSrcweir         m_aGradients.front().m_aSize		= aPtSize;
10200cdf0e10cSrcweir         it = m_aGradients.begin();
10201cdf0e10cSrcweir     }
10202cdf0e10cSrcweir 
10203cdf0e10cSrcweir     OStringBuffer aObjName( 16 );
10204cdf0e10cSrcweir     aObjName.append( 'P' );
10205cdf0e10cSrcweir     aObjName.append( it->m_nObject );
10206cdf0e10cSrcweir     pushResource( ResShading, aObjName.makeStringAndClear(), it->m_nObject );
10207cdf0e10cSrcweir 
10208cdf0e10cSrcweir     return it->m_nObject;
10209cdf0e10cSrcweir }
10210cdf0e10cSrcweir 
10211cdf0e10cSrcweir void PDFWriterImpl::drawGradient( const Rectangle& rRect, const Gradient& rGradient )
10212cdf0e10cSrcweir {
10213cdf0e10cSrcweir     MARK( "drawGradient (Rectangle)" );
10214cdf0e10cSrcweir 
10215cdf0e10cSrcweir     if( m_aContext.Version == PDFWriter::PDF_1_2 )
10216cdf0e10cSrcweir     {
10217cdf0e10cSrcweir         drawRectangle( rRect );
10218cdf0e10cSrcweir         return;
10219cdf0e10cSrcweir     }
10220cdf0e10cSrcweir 
10221cdf0e10cSrcweir     sal_Int32 nGradient = createGradient( rGradient, rRect.GetSize() );
10222cdf0e10cSrcweir 
10223cdf0e10cSrcweir     Point aTranslate( rRect.BottomLeft() );
10224cdf0e10cSrcweir     aTranslate += Point( 0, 1 );
10225cdf0e10cSrcweir 
10226cdf0e10cSrcweir     updateGraphicsState();
10227cdf0e10cSrcweir 
10228cdf0e10cSrcweir     OStringBuffer aLine( 80 );
10229cdf0e10cSrcweir     aLine.append( "q 1 0 0 1 " );
10230cdf0e10cSrcweir     m_aPages.back().appendPoint( aTranslate, aLine );
10231cdf0e10cSrcweir     aLine.append( " cm " );
10232cdf0e10cSrcweir     // if a stroke is appended reset the clip region before stroke
10233cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
10234cdf0e10cSrcweir         aLine.append( "q " );
10235cdf0e10cSrcweir     aLine.append( "0 0 " );
10236cdf0e10cSrcweir     m_aPages.back().appendMappedLength( (sal_Int32)rRect.GetWidth(), aLine, false );
10237cdf0e10cSrcweir     aLine.append( ' ' );
10238cdf0e10cSrcweir     m_aPages.back().appendMappedLength( (sal_Int32)rRect.GetHeight(), aLine, true );
10239cdf0e10cSrcweir     aLine.append( " re W n\n" );
10240cdf0e10cSrcweir 
10241cdf0e10cSrcweir     aLine.append( "/P" );
10242cdf0e10cSrcweir     aLine.append( nGradient );
10243cdf0e10cSrcweir     aLine.append( " sh " );
10244cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
10245cdf0e10cSrcweir     {
10246cdf0e10cSrcweir         aLine.append( "Q 0 0 " );
10247cdf0e10cSrcweir         m_aPages.back().appendMappedLength( (sal_Int32)rRect.GetWidth(), aLine, false );
10248cdf0e10cSrcweir         aLine.append( ' ' );
10249cdf0e10cSrcweir         m_aPages.back().appendMappedLength( (sal_Int32)rRect.GetHeight(), aLine, true );
10250cdf0e10cSrcweir         aLine.append( " re S " );
10251cdf0e10cSrcweir     }
10252cdf0e10cSrcweir     aLine.append( "Q\n" );
10253cdf0e10cSrcweir     writeBuffer( aLine.getStr(), aLine.getLength() );
10254cdf0e10cSrcweir }
10255cdf0e10cSrcweir 
10256cdf0e10cSrcweir void PDFWriterImpl::drawGradient( const PolyPolygon& rPolyPoly, const Gradient& rGradient )
10257cdf0e10cSrcweir {
10258cdf0e10cSrcweir     MARK( "drawGradient (PolyPolygon)" );
10259cdf0e10cSrcweir 
10260cdf0e10cSrcweir     if( m_aContext.Version == PDFWriter::PDF_1_2 )
10261cdf0e10cSrcweir     {
10262cdf0e10cSrcweir         drawPolyPolygon( rPolyPoly );
10263cdf0e10cSrcweir         return;
10264cdf0e10cSrcweir     }
10265cdf0e10cSrcweir 
10266cdf0e10cSrcweir     Rectangle aBoundRect = rPolyPoly.GetBoundRect();
10267cdf0e10cSrcweir     sal_Int32 nGradient = createGradient( rGradient, aBoundRect.GetSize() );
10268cdf0e10cSrcweir 
10269cdf0e10cSrcweir     updateGraphicsState();
10270cdf0e10cSrcweir 
10271cdf0e10cSrcweir     Point aTranslate = aBoundRect.BottomLeft();
10272cdf0e10cSrcweir     int nPolygons = rPolyPoly.Count();
10273cdf0e10cSrcweir 
10274cdf0e10cSrcweir     OStringBuffer aLine( 80*nPolygons );
10275cdf0e10cSrcweir     aLine.append( "q " );
10276cdf0e10cSrcweir     // set PolyPolygon as clip path
10277cdf0e10cSrcweir     m_aPages.back().appendPolyPolygon( rPolyPoly, aLine );
10278cdf0e10cSrcweir     aLine.append( "W* n\n" );
10279cdf0e10cSrcweir     aLine.append( "1 0 0 1 " );
10280cdf0e10cSrcweir     m_aPages.back().appendPoint( aTranslate, aLine );
10281cdf0e10cSrcweir     aLine.append( " cm\n" );
10282cdf0e10cSrcweir     aLine.append( "/P" );
10283cdf0e10cSrcweir     aLine.append( nGradient );
10284cdf0e10cSrcweir     aLine.append( " sh Q\n" );
10285cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
10286cdf0e10cSrcweir     {
10287cdf0e10cSrcweir         // and draw the surrounding path
10288cdf0e10cSrcweir         m_aPages.back().appendPolyPolygon( rPolyPoly, aLine );
10289cdf0e10cSrcweir         aLine.append( "S\n" );
10290cdf0e10cSrcweir     }
10291cdf0e10cSrcweir     writeBuffer( aLine.getStr(), aLine.getLength() );
10292cdf0e10cSrcweir }
10293cdf0e10cSrcweir 
10294cdf0e10cSrcweir void PDFWriterImpl::drawHatch( const PolyPolygon& rPolyPoly, const Hatch& rHatch )
10295cdf0e10cSrcweir {
10296cdf0e10cSrcweir     MARK( "drawHatch" );
10297cdf0e10cSrcweir 
10298cdf0e10cSrcweir     updateGraphicsState();
10299cdf0e10cSrcweir 
10300cdf0e10cSrcweir 	if( rPolyPoly.Count() )
10301cdf0e10cSrcweir 	{
10302cdf0e10cSrcweir 		PolyPolygon		aPolyPoly( rPolyPoly );
10303cdf0e10cSrcweir 
10304cdf0e10cSrcweir 		aPolyPoly.Optimize( POLY_OPTIMIZE_NO_SAME );
10305cdf0e10cSrcweir 		push( PUSH_LINECOLOR );
10306cdf0e10cSrcweir 		setLineColor( rHatch.GetColor() );
10307cdf0e10cSrcweir 		getReferenceDevice()->ImplDrawHatch( aPolyPoly, rHatch, sal_False );
10308cdf0e10cSrcweir 		pop();
10309cdf0e10cSrcweir 	}
10310cdf0e10cSrcweir }
10311cdf0e10cSrcweir 
10312cdf0e10cSrcweir void PDFWriterImpl::drawWallpaper( const Rectangle& rRect, const Wallpaper& rWall )
10313cdf0e10cSrcweir {
10314cdf0e10cSrcweir     MARK( "drawWallpaper" );
10315cdf0e10cSrcweir 
10316cdf0e10cSrcweir     bool bDrawColor			= false;
10317cdf0e10cSrcweir     bool bDrawGradient		= false;
10318cdf0e10cSrcweir     bool bDrawBitmap		= false;
10319cdf0e10cSrcweir 
10320cdf0e10cSrcweir     BitmapEx aBitmap;
10321cdf0e10cSrcweir     Point aBmpPos = rRect.TopLeft();
10322cdf0e10cSrcweir     Size aBmpSize;
10323cdf0e10cSrcweir     if( rWall.IsBitmap() )
10324cdf0e10cSrcweir     {
10325cdf0e10cSrcweir         aBitmap = rWall.GetBitmap();
10326cdf0e10cSrcweir 		aBmpSize = lcl_convert( aBitmap.GetPrefMapMode(),
10327cdf0e10cSrcweir                                 getMapMode(),
10328cdf0e10cSrcweir                                 getReferenceDevice(),
10329cdf0e10cSrcweir                                 aBitmap.GetPrefSize() );
10330cdf0e10cSrcweir         Rectangle aRect( rRect );
10331cdf0e10cSrcweir         if( rWall.IsRect() )
10332cdf0e10cSrcweir         {
10333cdf0e10cSrcweir             aRect = rWall.GetRect();
10334cdf0e10cSrcweir             aBmpPos = aRect.TopLeft();
10335cdf0e10cSrcweir             aBmpSize = aRect.GetSize();
10336cdf0e10cSrcweir         }
10337cdf0e10cSrcweir         if( rWall.GetStyle() != WALLPAPER_SCALE )
10338cdf0e10cSrcweir         {
10339cdf0e10cSrcweir             if( rWall.GetStyle() != WALLPAPER_TILE )
10340cdf0e10cSrcweir             {
10341cdf0e10cSrcweir                 bDrawBitmap		= true;
10342cdf0e10cSrcweir                 if( rWall.IsGradient() )
10343cdf0e10cSrcweir                     bDrawGradient = true;
10344cdf0e10cSrcweir                 else
10345cdf0e10cSrcweir                     bDrawColor = true;
10346cdf0e10cSrcweir                 switch( rWall.GetStyle() )
10347cdf0e10cSrcweir                 {
10348cdf0e10cSrcweir                     case WALLPAPER_TOPLEFT:
10349cdf0e10cSrcweir                         break;
10350cdf0e10cSrcweir                     case WALLPAPER_TOP:
10351cdf0e10cSrcweir                         aBmpPos.X() += (aRect.GetWidth()-aBmpSize.Width())/2;
10352cdf0e10cSrcweir                         break;
10353cdf0e10cSrcweir                     case WALLPAPER_LEFT:
10354cdf0e10cSrcweir                         aBmpPos.Y() += (aRect.GetHeight()-aBmpSize.Height())/2;
10355cdf0e10cSrcweir                         break;
10356cdf0e10cSrcweir                     case WALLPAPER_TOPRIGHT:
10357cdf0e10cSrcweir                         aBmpPos.X() += aRect.GetWidth()-aBmpSize.Width();
10358cdf0e10cSrcweir                         break;
10359cdf0e10cSrcweir                     case WALLPAPER_CENTER:
10360cdf0e10cSrcweir                         aBmpPos.X() += (aRect.GetWidth()-aBmpSize.Width())/2;
10361cdf0e10cSrcweir                         aBmpPos.Y() += (aRect.GetHeight()-aBmpSize.Height())/2;
10362cdf0e10cSrcweir                         break;
10363cdf0e10cSrcweir                     case WALLPAPER_RIGHT:
10364cdf0e10cSrcweir                         aBmpPos.X() += aRect.GetWidth()-aBmpSize.Width();
10365cdf0e10cSrcweir                         aBmpPos.Y() += (aRect.GetHeight()-aBmpSize.Height())/2;
10366cdf0e10cSrcweir                         break;
10367cdf0e10cSrcweir                     case WALLPAPER_BOTTOMLEFT:
10368cdf0e10cSrcweir                         aBmpPos.Y() += aRect.GetHeight()-aBmpSize.Height();
10369cdf0e10cSrcweir                         break;
10370cdf0e10cSrcweir                     case WALLPAPER_BOTTOM:
10371cdf0e10cSrcweir                         aBmpPos.X() += (aRect.GetWidth()-aBmpSize.Width())/2;
10372cdf0e10cSrcweir                         aBmpPos.Y() += aRect.GetHeight()-aBmpSize.Height();
10373cdf0e10cSrcweir                         break;
10374cdf0e10cSrcweir                     case WALLPAPER_BOTTOMRIGHT:
10375cdf0e10cSrcweir                         aBmpPos.X() += aRect.GetWidth()-aBmpSize.Width();
10376cdf0e10cSrcweir                         aBmpPos.Y() += aRect.GetHeight()-aBmpSize.Height();
10377cdf0e10cSrcweir                         break;
10378cdf0e10cSrcweir                     default: ;
10379cdf0e10cSrcweir                 }
10380cdf0e10cSrcweir             }
10381cdf0e10cSrcweir             else
10382cdf0e10cSrcweir             {
10383cdf0e10cSrcweir                 // push the bitmap
10384cdf0e10cSrcweir                 const BitmapEmit& rEmit = createBitmapEmit( BitmapEx( aBitmap ) );
10385cdf0e10cSrcweir 
10386cdf0e10cSrcweir                 // convert to page coordinates; this needs to be done here
10387cdf0e10cSrcweir                 // since the emit does not know the page anymore
10388cdf0e10cSrcweir                 Rectangle aConvertRect( aBmpPos, aBmpSize );
10389cdf0e10cSrcweir                 m_aPages.back().convertRect( aConvertRect );
10390cdf0e10cSrcweir 
10391cdf0e10cSrcweir                 OStringBuffer aNameBuf(16);
10392cdf0e10cSrcweir                 aNameBuf.append( "Im" );
10393cdf0e10cSrcweir                 aNameBuf.append( rEmit.m_nObject );
10394cdf0e10cSrcweir                 OString aImageName( aNameBuf.makeStringAndClear() );
10395cdf0e10cSrcweir 
10396cdf0e10cSrcweir                 // push the pattern
10397cdf0e10cSrcweir                 OStringBuffer aTilingStream( 32 );
10398cdf0e10cSrcweir                 appendFixedInt( aConvertRect.GetWidth(), aTilingStream );
10399cdf0e10cSrcweir                 aTilingStream.append( " 0 0 " );
10400cdf0e10cSrcweir                 appendFixedInt( aConvertRect.GetHeight(), aTilingStream );
10401cdf0e10cSrcweir                 aTilingStream.append( " 0 0 cm\n/" );
10402cdf0e10cSrcweir                 aTilingStream.append( aImageName );
10403cdf0e10cSrcweir                 aTilingStream.append( " Do\n" );
10404cdf0e10cSrcweir 
10405cdf0e10cSrcweir                 m_aTilings.push_back( TilingEmit() );
10406cdf0e10cSrcweir                 m_aTilings.back().m_nObject			= createObject();
10407cdf0e10cSrcweir                 m_aTilings.back().m_aRectangle		= Rectangle( Point( 0, 0 ), aConvertRect.GetSize() );
10408cdf0e10cSrcweir                 m_aTilings.back().m_pTilingStream   = new SvMemoryStream();
10409cdf0e10cSrcweir                 m_aTilings.back().m_pTilingStream->Write( aTilingStream.getStr(), aTilingStream.getLength() );
10410cdf0e10cSrcweir                 // phase the tiling so wallpaper begins on upper left
10411cdf0e10cSrcweir                 m_aTilings.back().m_aTransform.matrix[2] = double(aConvertRect.Left() % aConvertRect.GetWidth()) / fDivisor;
10412cdf0e10cSrcweir                 m_aTilings.back().m_aTransform.matrix[5] = double(aConvertRect.Top() % aConvertRect.GetHeight()) / fDivisor;
10413cdf0e10cSrcweir                 m_aTilings.back().m_aResources.m_aXObjects[aImageName] = rEmit.m_nObject;
10414cdf0e10cSrcweir 
10415cdf0e10cSrcweir                 updateGraphicsState();
10416cdf0e10cSrcweir 
10417cdf0e10cSrcweir                 OStringBuffer aObjName( 16 );
10418cdf0e10cSrcweir                 aObjName.append( 'P' );
10419cdf0e10cSrcweir                 aObjName.append( m_aTilings.back().m_nObject );
10420cdf0e10cSrcweir                 OString aPatternName( aObjName.makeStringAndClear() );
10421cdf0e10cSrcweir                 pushResource( ResPattern, aPatternName, m_aTilings.back().m_nObject );
10422cdf0e10cSrcweir 
10423cdf0e10cSrcweir                 // fill a rRect with the pattern
10424cdf0e10cSrcweir                 OStringBuffer aLine( 100 );
10425cdf0e10cSrcweir                 aLine.append( "q /Pattern cs /" );
10426cdf0e10cSrcweir                 aLine.append( aPatternName );
10427cdf0e10cSrcweir                 aLine.append( " scn " );
10428cdf0e10cSrcweir                 m_aPages.back().appendRect( rRect, aLine );
10429cdf0e10cSrcweir                 aLine.append( " f Q\n" );
10430cdf0e10cSrcweir                 writeBuffer( aLine.getStr(), aLine.getLength() );
10431cdf0e10cSrcweir             }
10432cdf0e10cSrcweir         }
10433cdf0e10cSrcweir         else
10434cdf0e10cSrcweir         {
10435cdf0e10cSrcweir             aBmpPos		= aRect.TopLeft();
10436cdf0e10cSrcweir             aBmpSize	= aRect.GetSize();
10437cdf0e10cSrcweir             bDrawBitmap	= true;
10438cdf0e10cSrcweir         }
10439cdf0e10cSrcweir 
10440cdf0e10cSrcweir         if( aBitmap.IsTransparent() )
10441cdf0e10cSrcweir         {
10442cdf0e10cSrcweir             if( rWall.IsGradient() )
10443cdf0e10cSrcweir                 bDrawGradient = true;
10444cdf0e10cSrcweir             else
10445cdf0e10cSrcweir                 bDrawColor = true;
10446cdf0e10cSrcweir         }
10447cdf0e10cSrcweir     }
10448cdf0e10cSrcweir     else if( rWall.IsGradient() )
10449cdf0e10cSrcweir         bDrawGradient = true;
10450cdf0e10cSrcweir     else
10451cdf0e10cSrcweir         bDrawColor = true;
10452cdf0e10cSrcweir 
10453cdf0e10cSrcweir     if( bDrawGradient )
10454cdf0e10cSrcweir     {
10455cdf0e10cSrcweir         drawGradient( rRect, rWall.GetGradient() );
10456cdf0e10cSrcweir     }
10457cdf0e10cSrcweir     if( bDrawColor )
10458cdf0e10cSrcweir     {
10459cdf0e10cSrcweir         Color aOldLineColor = m_aGraphicsStack.front().m_aLineColor;
10460cdf0e10cSrcweir         Color aOldFillColor = m_aGraphicsStack.front().m_aFillColor;
10461cdf0e10cSrcweir         setLineColor( Color( COL_TRANSPARENT ) );
10462cdf0e10cSrcweir         setFillColor( rWall.GetColor() );
10463cdf0e10cSrcweir         drawRectangle( rRect );
10464cdf0e10cSrcweir         setLineColor( aOldLineColor );
10465cdf0e10cSrcweir         setFillColor( aOldFillColor );
10466cdf0e10cSrcweir     }
10467cdf0e10cSrcweir     if( bDrawBitmap )
10468cdf0e10cSrcweir     {
10469cdf0e10cSrcweir         // set temporary clip region since aBmpPos and aBmpSize
10470cdf0e10cSrcweir         // may be outside rRect
10471cdf0e10cSrcweir         OStringBuffer aLine( 20 );
10472cdf0e10cSrcweir         aLine.append( "q " );
10473cdf0e10cSrcweir         m_aPages.back().appendRect( rRect, aLine );
10474cdf0e10cSrcweir         aLine.append( " W n\n" );
10475cdf0e10cSrcweir         writeBuffer( aLine.getStr(), aLine.getLength() );
10476cdf0e10cSrcweir         drawBitmap( aBmpPos, aBmpSize, aBitmap );
10477cdf0e10cSrcweir         writeBuffer( "Q\n", 2 );
10478cdf0e10cSrcweir     }
10479cdf0e10cSrcweir }
10480cdf0e10cSrcweir 
10481cdf0e10cSrcweir void PDFWriterImpl::beginPattern( const Rectangle& rCellRect )
10482cdf0e10cSrcweir {
10483cdf0e10cSrcweir     beginRedirect( new SvMemoryStream(), rCellRect );
10484cdf0e10cSrcweir }
10485cdf0e10cSrcweir 
10486cdf0e10cSrcweir sal_Int32 PDFWriterImpl::endPattern( const SvtGraphicFill::Transform& rTransform )
10487cdf0e10cSrcweir {
10488cdf0e10cSrcweir     Rectangle aConvertRect( getRedirectTargetRect() );
10489cdf0e10cSrcweir     DBG_ASSERT( aConvertRect.GetWidth() != 0 && aConvertRect.GetHeight() != 0, "empty cell rectangle in pattern" );
10490cdf0e10cSrcweir 
10491cdf0e10cSrcweir     // get scaling between current mapmode and PDF output
10492cdf0e10cSrcweir     Size aScaling( lcl_convert( m_aGraphicsStack.front().m_aMapMode, m_aMapMode, getReferenceDevice(), Size( 10000, 10000 ) ) );
10493cdf0e10cSrcweir     double fSX = (double(aScaling.Width()) / 10000.0);
10494cdf0e10cSrcweir     double fSY = (double(aScaling.Height()) / 10000.0);
10495cdf0e10cSrcweir 
10496cdf0e10cSrcweir     // transform translation part of matrix
10497cdf0e10cSrcweir     Size aTranslation( (long)rTransform.matrix[2], (long)rTransform.matrix[5] );
10498cdf0e10cSrcweir     aTranslation = lcl_convert( m_aGraphicsStack.front().m_aMapMode, m_aMapMode, getReferenceDevice(), aTranslation );
10499cdf0e10cSrcweir 
10500cdf0e10cSrcweir     sal_Int32 nTilingId = m_aTilings.size();
10501cdf0e10cSrcweir     m_aTilings.push_back( TilingEmit() );
10502cdf0e10cSrcweir     TilingEmit& rTile = m_aTilings.back();
10503cdf0e10cSrcweir     rTile.m_nObject         = createObject();
10504cdf0e10cSrcweir     rTile.m_aResources      = m_aOutputStreams.front().m_aResourceDict;
10505cdf0e10cSrcweir     rTile.m_aTransform.matrix[0] = rTransform.matrix[0] * fSX;
10506cdf0e10cSrcweir     rTile.m_aTransform.matrix[1] = rTransform.matrix[1] * fSY;
10507cdf0e10cSrcweir     rTile.m_aTransform.matrix[2] = aTranslation.Width();
10508cdf0e10cSrcweir     rTile.m_aTransform.matrix[3] = rTransform.matrix[3] * fSX;
10509cdf0e10cSrcweir     rTile.m_aTransform.matrix[4] = rTransform.matrix[4] * fSY;
10510cdf0e10cSrcweir     rTile.m_aTransform.matrix[5] = -aTranslation.Height();
10511cdf0e10cSrcweir     // caution: endRedirect pops the stream, so do this last
10512cdf0e10cSrcweir     rTile.m_pTilingStream   = dynamic_cast<SvMemoryStream*>(endRedirect());
10513cdf0e10cSrcweir     // FIXME: bound rect will not work with rotated matrix
10514cdf0e10cSrcweir     rTile.m_aRectangle      = Rectangle( Point(0,0), aConvertRect.GetSize() );
10515cdf0e10cSrcweir     rTile.m_aCellSize       = aConvertRect.GetSize();
10516cdf0e10cSrcweir 
10517cdf0e10cSrcweir     OStringBuffer aObjName( 16 );
10518cdf0e10cSrcweir     aObjName.append( 'P' );
10519cdf0e10cSrcweir     aObjName.append( rTile.m_nObject );
10520cdf0e10cSrcweir     pushResource( ResPattern, aObjName.makeStringAndClear(), rTile.m_nObject );
10521cdf0e10cSrcweir     return nTilingId;
10522cdf0e10cSrcweir }
10523cdf0e10cSrcweir 
10524cdf0e10cSrcweir void PDFWriterImpl::drawPolyPolygon( const PolyPolygon& rPolyPoly, sal_Int32 nPattern, bool bEOFill )
10525cdf0e10cSrcweir {
10526cdf0e10cSrcweir     if( nPattern < 0 || nPattern >= (sal_Int32)m_aTilings.size() )
10527cdf0e10cSrcweir         return;
10528cdf0e10cSrcweir 
10529cdf0e10cSrcweir     m_aPages.back().endStream();
10530cdf0e10cSrcweir     sal_Int32 nXObject = createObject();
10531cdf0e10cSrcweir     OStringBuffer aNameBuf( 16 );
10532cdf0e10cSrcweir     aNameBuf.append( "Pol" );
10533cdf0e10cSrcweir     aNameBuf.append( nXObject );
10534cdf0e10cSrcweir     OString aObjName( aNameBuf.makeStringAndClear() );
10535cdf0e10cSrcweir     Rectangle aObjRect;
10536cdf0e10cSrcweir     if( updateObject( nXObject ) )
10537cdf0e10cSrcweir     {
10538cdf0e10cSrcweir         // get bounding rect of object
10539cdf0e10cSrcweir         PolyPolygon aSubDiv;
10540cdf0e10cSrcweir         rPolyPoly.AdaptiveSubdivide( aSubDiv );
10541cdf0e10cSrcweir         aObjRect = aSubDiv.GetBoundRect();
10542cdf0e10cSrcweir         Rectangle aConvObjRect( aObjRect );
10543cdf0e10cSrcweir         m_aPages.back().convertRect( aConvObjRect );
10544cdf0e10cSrcweir 
10545cdf0e10cSrcweir         // move polypolygon to bottom left of page
10546cdf0e10cSrcweir         PolyPolygon aLocalPath( rPolyPoly );
10547cdf0e10cSrcweir         sal_Int32 nPgWd = getReferenceDevice()->ImplGetDPIX() * m_aPages.back().getWidth() / 72;
10548cdf0e10cSrcweir         sal_Int32 nPgHt = getReferenceDevice()->ImplGetDPIY() * m_aPages.back().getHeight() / 72;
10549cdf0e10cSrcweir         Size aLogicPgSz = getReferenceDevice()->PixelToLogic( Size( nPgWd, nPgHt ), m_aGraphicsStack.front().m_aMapMode );
10550cdf0e10cSrcweir         sal_Int32 nXOff = aObjRect.Left();
10551cdf0e10cSrcweir         sal_Int32 nYOff = aLogicPgSz.Height() - aObjRect.Bottom();
10552cdf0e10cSrcweir         aLocalPath.Move( -nXOff, nYOff );
10553cdf0e10cSrcweir 
10554cdf0e10cSrcweir         // prepare XObject's content stream
10555cdf0e10cSrcweir         OStringBuffer aStream( 512 );
10556cdf0e10cSrcweir         aStream.append( "/Pattern cs /P" );
10557cdf0e10cSrcweir         aStream.append( m_aTilings[ nPattern ].m_nObject );
10558cdf0e10cSrcweir         aStream.append( " scn\n" );
10559cdf0e10cSrcweir         m_aPages.back().appendPolyPolygon( aLocalPath, aStream );
10560cdf0e10cSrcweir         aStream.append( bEOFill ? "f*" : "f" );
10561cdf0e10cSrcweir         SvMemoryStream aMemStream( aStream.getLength() );
10562cdf0e10cSrcweir         aMemStream.Write( aStream.getStr(), aStream.getLength() );
10563cdf0e10cSrcweir         bool bDeflate = compressStream( &aMemStream );
10564cdf0e10cSrcweir         aMemStream.Seek( STREAM_SEEK_TO_END );
10565cdf0e10cSrcweir         sal_Int32 nStreamLen = (sal_Int32)aMemStream.Tell();
10566cdf0e10cSrcweir         aMemStream.Seek( STREAM_SEEK_TO_BEGIN );
10567cdf0e10cSrcweir 
10568cdf0e10cSrcweir         // add new XObject to global resource dict
10569cdf0e10cSrcweir         m_aGlobalResourceDict.m_aXObjects[ aObjName ] = nXObject;
10570cdf0e10cSrcweir 
10571cdf0e10cSrcweir         // write XObject
10572cdf0e10cSrcweir         OStringBuffer aLine( 512 );
10573cdf0e10cSrcweir         aLine.append( nXObject );
10574cdf0e10cSrcweir         aLine.append( " 0 obj\n"
10575cdf0e10cSrcweir                       "<</Type/XObject/Subtype/Form/BBox[0 0 " );
10576cdf0e10cSrcweir         appendFixedInt( aConvObjRect.GetWidth(), aLine );
10577cdf0e10cSrcweir         aLine.append( ' ' );
10578cdf0e10cSrcweir         appendFixedInt( aConvObjRect.GetHeight(), aLine );
10579cdf0e10cSrcweir         aLine.append( "]/Length " );
10580cdf0e10cSrcweir         aLine.append( nStreamLen );
10581cdf0e10cSrcweir         if( bDeflate )
10582cdf0e10cSrcweir             aLine.append( "/Filter/FlateDecode" );
10583cdf0e10cSrcweir         aLine.append( ">>\n"
10584cdf0e10cSrcweir                       "stream\n" );
10585cdf0e10cSrcweir         writeBuffer( aLine.getStr(), aLine.getLength() );
10586cdf0e10cSrcweir         checkAndEnableStreamEncryption( nXObject );
10587cdf0e10cSrcweir         writeBuffer( aMemStream.GetData(), nStreamLen );
10588cdf0e10cSrcweir         disableStreamEncryption();
10589cdf0e10cSrcweir         writeBuffer( "\nendstream\nendobj\n\n", 19 );
10590cdf0e10cSrcweir     }
10591cdf0e10cSrcweir     m_aPages.back().beginStream();
10592cdf0e10cSrcweir     OStringBuffer aLine( 80 );
10593cdf0e10cSrcweir     aLine.append( "q 1 0 0 1 " );
10594cdf0e10cSrcweir     m_aPages.back().appendPoint( aObjRect.BottomLeft(), aLine );
10595cdf0e10cSrcweir     aLine.append( " cm/" );
10596cdf0e10cSrcweir     aLine.append( aObjName );
10597cdf0e10cSrcweir     aLine.append( " Do Q\n" );
10598cdf0e10cSrcweir     writeBuffer( aLine.getStr(), aLine.getLength() );
10599cdf0e10cSrcweir }
10600cdf0e10cSrcweir 
10601cdf0e10cSrcweir void PDFWriterImpl::updateGraphicsState()
10602cdf0e10cSrcweir {
10603cdf0e10cSrcweir     OStringBuffer aLine( 256 );
10604cdf0e10cSrcweir     GraphicsState& rNewState = m_aGraphicsStack.front();
10605cdf0e10cSrcweir     // first set clip region since it might invalidate everything else
10606cdf0e10cSrcweir 
10607cdf0e10cSrcweir     if( (rNewState.m_nUpdateFlags & GraphicsState::updateClipRegion) )
10608cdf0e10cSrcweir     {
10609cdf0e10cSrcweir         rNewState.m_nUpdateFlags &= ~GraphicsState::updateClipRegion;
10610cdf0e10cSrcweir 
10611cdf0e10cSrcweir         if( m_aCurrentPDFState.m_bClipRegion != rNewState.m_bClipRegion ||
10612cdf0e10cSrcweir             ( rNewState.m_bClipRegion && m_aCurrentPDFState.m_aClipRegion != rNewState.m_aClipRegion ) )
10613cdf0e10cSrcweir         {
10614cdf0e10cSrcweir             if( m_aCurrentPDFState.m_bClipRegion && m_aCurrentPDFState.m_aClipRegion.count() )
10615cdf0e10cSrcweir             {
10616cdf0e10cSrcweir                 aLine.append( "Q " );
10617cdf0e10cSrcweir                 // invalidate everything but the clip region
10618cdf0e10cSrcweir                 m_aCurrentPDFState = GraphicsState();
10619cdf0e10cSrcweir                 rNewState.m_nUpdateFlags = sal::static_int_cast<sal_uInt16>(~GraphicsState::updateClipRegion);
10620cdf0e10cSrcweir             }
10621cdf0e10cSrcweir             if( rNewState.m_bClipRegion && rNewState.m_aClipRegion.count() )
10622cdf0e10cSrcweir             {
10623cdf0e10cSrcweir                 // clip region is always stored in private PDF mapmode
10624cdf0e10cSrcweir                 MapMode aNewMapMode = rNewState.m_aMapMode;
10625cdf0e10cSrcweir                 rNewState.m_aMapMode = m_aMapMode;
10626cdf0e10cSrcweir                 getReferenceDevice()->SetMapMode( rNewState.m_aMapMode );
10627cdf0e10cSrcweir                 m_aCurrentPDFState.m_aMapMode = rNewState.m_aMapMode;
10628cdf0e10cSrcweir 
10629cdf0e10cSrcweir                 aLine.append( "q " );
10630cdf0e10cSrcweir                 m_aPages.back().appendPolyPolygon( rNewState.m_aClipRegion, aLine );
10631cdf0e10cSrcweir                 aLine.append( "W* n\n" );
10632cdf0e10cSrcweir                 rNewState.m_aMapMode = aNewMapMode;
10633cdf0e10cSrcweir                 getReferenceDevice()->SetMapMode( rNewState.m_aMapMode );
10634cdf0e10cSrcweir                 m_aCurrentPDFState.m_aMapMode = rNewState.m_aMapMode;
10635cdf0e10cSrcweir             }
10636cdf0e10cSrcweir         }
10637cdf0e10cSrcweir     }
10638cdf0e10cSrcweir 
10639cdf0e10cSrcweir     if( (rNewState.m_nUpdateFlags & GraphicsState::updateMapMode) )
10640cdf0e10cSrcweir     {
10641cdf0e10cSrcweir         rNewState.m_nUpdateFlags &= ~GraphicsState::updateMapMode;
10642cdf0e10cSrcweir         getReferenceDevice()->SetMapMode( rNewState.m_aMapMode );
10643cdf0e10cSrcweir     }
10644cdf0e10cSrcweir 
10645cdf0e10cSrcweir     if( (rNewState.m_nUpdateFlags & GraphicsState::updateFont) )
10646cdf0e10cSrcweir     {
10647cdf0e10cSrcweir         rNewState.m_nUpdateFlags &= ~GraphicsState::updateFont;
10648cdf0e10cSrcweir         getReferenceDevice()->SetFont( rNewState.m_aFont );
10649cdf0e10cSrcweir         getReferenceDevice()->ImplNewFont();
10650cdf0e10cSrcweir     }
10651cdf0e10cSrcweir 
10652cdf0e10cSrcweir     if( (rNewState.m_nUpdateFlags & GraphicsState::updateLayoutMode) )
10653cdf0e10cSrcweir     {
10654cdf0e10cSrcweir         rNewState.m_nUpdateFlags &= ~GraphicsState::updateLayoutMode;
10655cdf0e10cSrcweir         getReferenceDevice()->SetLayoutMode( rNewState.m_nLayoutMode );
10656cdf0e10cSrcweir     }
10657cdf0e10cSrcweir 
10658cdf0e10cSrcweir     if( (rNewState.m_nUpdateFlags & GraphicsState::updateDigitLanguage) )
10659cdf0e10cSrcweir     {
10660cdf0e10cSrcweir         rNewState.m_nUpdateFlags &= ~GraphicsState::updateDigitLanguage;
10661cdf0e10cSrcweir         getReferenceDevice()->SetDigitLanguage( rNewState.m_aDigitLanguage );
10662cdf0e10cSrcweir     }
10663cdf0e10cSrcweir 
10664cdf0e10cSrcweir     if( (rNewState.m_nUpdateFlags & GraphicsState::updateLineColor) )
10665cdf0e10cSrcweir     {
10666cdf0e10cSrcweir         rNewState.m_nUpdateFlags &= ~GraphicsState::updateLineColor;
10667cdf0e10cSrcweir         if( m_aCurrentPDFState.m_aLineColor != rNewState.m_aLineColor &&
10668cdf0e10cSrcweir             rNewState.m_aLineColor != Color( COL_TRANSPARENT ) )
10669cdf0e10cSrcweir         {
10670cdf0e10cSrcweir             appendStrokingColor( rNewState.m_aLineColor, aLine );
10671cdf0e10cSrcweir             aLine.append( "\n" );
10672cdf0e10cSrcweir         }
10673cdf0e10cSrcweir     }
10674cdf0e10cSrcweir 
10675cdf0e10cSrcweir     if( (rNewState.m_nUpdateFlags & GraphicsState::updateFillColor) )
10676cdf0e10cSrcweir     {
10677cdf0e10cSrcweir         rNewState.m_nUpdateFlags &= ~GraphicsState::updateFillColor;
10678cdf0e10cSrcweir         if( m_aCurrentPDFState.m_aFillColor != rNewState.m_aFillColor &&
10679cdf0e10cSrcweir             rNewState.m_aFillColor != Color( COL_TRANSPARENT ) )
10680cdf0e10cSrcweir         {
10681cdf0e10cSrcweir             appendNonStrokingColor( rNewState.m_aFillColor, aLine );
10682cdf0e10cSrcweir             aLine.append( "\n" );
10683cdf0e10cSrcweir         }
10684cdf0e10cSrcweir     }
10685cdf0e10cSrcweir 
10686cdf0e10cSrcweir     if( (rNewState.m_nUpdateFlags & GraphicsState::updateTransparentPercent) )
10687cdf0e10cSrcweir     {
10688cdf0e10cSrcweir         rNewState.m_nUpdateFlags &= ~GraphicsState::updateTransparentPercent;
10689cdf0e10cSrcweir         if( m_aContext.Version >= PDFWriter::PDF_1_4 && m_aCurrentPDFState.m_nTransparentPercent != rNewState.m_nTransparentPercent )
10690cdf0e10cSrcweir         {
10691cdf0e10cSrcweir             // TODO: switch extended graphicsstate
10692cdf0e10cSrcweir         }
10693cdf0e10cSrcweir     }
10694cdf0e10cSrcweir 
10695cdf0e10cSrcweir     // everything is up to date now
10696cdf0e10cSrcweir     m_aCurrentPDFState = m_aGraphicsStack.front();
10697cdf0e10cSrcweir     if( aLine.getLength() )
10698cdf0e10cSrcweir         writeBuffer( aLine.getStr(), aLine.getLength() );
10699cdf0e10cSrcweir }
10700cdf0e10cSrcweir 
10701cdf0e10cSrcweir /* #i47544# imitate OutputDevice behaviour:
10702cdf0e10cSrcweir *  if a font with a nontransparent color is set, it overwrites the current
10703cdf0e10cSrcweir *  text color. OTOH setting the text color will overwrite the color of the font.
10704cdf0e10cSrcweir */
10705cdf0e10cSrcweir void PDFWriterImpl::setFont( const Font& rFont )
10706cdf0e10cSrcweir {
10707cdf0e10cSrcweir     Color aColor = rFont.GetColor();
10708cdf0e10cSrcweir     if( aColor == Color( COL_TRANSPARENT ) )
10709cdf0e10cSrcweir         aColor = m_aGraphicsStack.front().m_aFont.GetColor();
10710cdf0e10cSrcweir     m_aGraphicsStack.front().m_aFont = rFont;
10711cdf0e10cSrcweir     m_aGraphicsStack.front().m_aFont.SetColor( aColor );
10712cdf0e10cSrcweir     m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsState::updateFont;
10713cdf0e10cSrcweir }
10714cdf0e10cSrcweir 
10715cdf0e10cSrcweir void PDFWriterImpl::push( sal_uInt16 nFlags )
10716cdf0e10cSrcweir {
10717cdf0e10cSrcweir     OSL_ENSURE( m_aGraphicsStack.size() > 0, "invalid graphics stack" );
10718cdf0e10cSrcweir     m_aGraphicsStack.push_front( m_aGraphicsStack.front() );
10719cdf0e10cSrcweir     m_aGraphicsStack.front().m_nFlags = nFlags;
10720cdf0e10cSrcweir }
10721cdf0e10cSrcweir 
10722cdf0e10cSrcweir void PDFWriterImpl::pop()
10723cdf0e10cSrcweir {
10724cdf0e10cSrcweir     OSL_ENSURE( m_aGraphicsStack.size() > 1, "pop without push" );
10725cdf0e10cSrcweir     if( m_aGraphicsStack.size() < 2 )
10726cdf0e10cSrcweir         return;
10727cdf0e10cSrcweir 
10728cdf0e10cSrcweir     GraphicsState aState = m_aGraphicsStack.front();
10729cdf0e10cSrcweir     m_aGraphicsStack.pop_front();
10730cdf0e10cSrcweir     GraphicsState& rOld = m_aGraphicsStack.front();
10731cdf0e10cSrcweir 
10732cdf0e10cSrcweir     // move those parameters back that were not pushed
10733cdf0e10cSrcweir     // in the first place
10734cdf0e10cSrcweir     if( ! (aState.m_nFlags & PUSH_LINECOLOR) )
10735cdf0e10cSrcweir         setLineColor( aState.m_aLineColor );
10736cdf0e10cSrcweir     if( ! (aState.m_nFlags & PUSH_FILLCOLOR) )
10737cdf0e10cSrcweir         setFillColor( aState.m_aFillColor );
10738cdf0e10cSrcweir     if( ! (aState.m_nFlags & PUSH_FONT) )
10739cdf0e10cSrcweir         setFont( aState.m_aFont );
10740cdf0e10cSrcweir     if( ! (aState.m_nFlags & PUSH_TEXTCOLOR) )
10741cdf0e10cSrcweir         setTextColor( aState.m_aFont.GetColor() );
10742cdf0e10cSrcweir     if( ! (aState.m_nFlags & PUSH_MAPMODE) )
10743cdf0e10cSrcweir         setMapMode( aState.m_aMapMode );
10744cdf0e10cSrcweir     if( ! (aState.m_nFlags & PUSH_CLIPREGION) )
10745cdf0e10cSrcweir     {
10746cdf0e10cSrcweir         // do not use setClipRegion here
10747cdf0e10cSrcweir         // it would convert again assuming the current mapmode
10748cdf0e10cSrcweir         rOld.m_aClipRegion = aState.m_aClipRegion;
10749cdf0e10cSrcweir         rOld.m_bClipRegion = aState.m_bClipRegion;
10750cdf0e10cSrcweir     }
10751cdf0e10cSrcweir     if( ! (aState.m_nFlags & PUSH_TEXTLINECOLOR ) )
10752cdf0e10cSrcweir         setTextLineColor( aState.m_aTextLineColor );
10753cdf0e10cSrcweir     if( ! (aState.m_nFlags & PUSH_OVERLINECOLOR ) )
10754cdf0e10cSrcweir         setOverlineColor( aState.m_aOverlineColor );
10755cdf0e10cSrcweir     if( ! (aState.m_nFlags & PUSH_TEXTALIGN ) )
10756cdf0e10cSrcweir         setTextAlign( aState.m_aFont.GetAlign() );
10757cdf0e10cSrcweir     if( ! (aState.m_nFlags & PUSH_TEXTFILLCOLOR) )
10758cdf0e10cSrcweir         setTextFillColor( aState.m_aFont.GetFillColor() );
10759cdf0e10cSrcweir     if( ! (aState.m_nFlags & PUSH_REFPOINT) )
10760cdf0e10cSrcweir     {
10761cdf0e10cSrcweir         // what ?
10762cdf0e10cSrcweir     }
10763cdf0e10cSrcweir     // invalidate graphics state
10764cdf0e10cSrcweir     m_aGraphicsStack.front().m_nUpdateFlags = sal::static_int_cast<sal_uInt16>(~0U);
10765cdf0e10cSrcweir }
10766cdf0e10cSrcweir 
10767cdf0e10cSrcweir void PDFWriterImpl::setMapMode( const MapMode& rMapMode )
10768cdf0e10cSrcweir {
10769cdf0e10cSrcweir     m_aGraphicsStack.front().m_aMapMode = rMapMode;
10770cdf0e10cSrcweir     getReferenceDevice()->SetMapMode( rMapMode );
10771cdf0e10cSrcweir     m_aCurrentPDFState.m_aMapMode = rMapMode;
10772cdf0e10cSrcweir }
10773cdf0e10cSrcweir 
10774cdf0e10cSrcweir void PDFWriterImpl::setClipRegion( const basegfx::B2DPolyPolygon& rRegion )
10775cdf0e10cSrcweir {
10776cdf0e10cSrcweir     basegfx::B2DPolyPolygon aRegion = getReferenceDevice()->LogicToPixel( rRegion, m_aGraphicsStack.front().m_aMapMode );
10777cdf0e10cSrcweir     aRegion = getReferenceDevice()->PixelToLogic( aRegion, m_aMapMode );
10778cdf0e10cSrcweir     m_aGraphicsStack.front().m_aClipRegion = aRegion;
10779cdf0e10cSrcweir     m_aGraphicsStack.front().m_bClipRegion = true;
10780cdf0e10cSrcweir     m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsState::updateClipRegion;
10781cdf0e10cSrcweir }
10782cdf0e10cSrcweir 
10783cdf0e10cSrcweir void PDFWriterImpl::moveClipRegion( sal_Int32 nX, sal_Int32 nY )
10784cdf0e10cSrcweir {
10785cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_bClipRegion && m_aGraphicsStack.front().m_aClipRegion.count() )
10786cdf0e10cSrcweir     {
10787cdf0e10cSrcweir         Point aPoint( lcl_convert( m_aGraphicsStack.front().m_aMapMode,
10788cdf0e10cSrcweir                                    m_aMapMode,
10789cdf0e10cSrcweir                                    getReferenceDevice(),
10790cdf0e10cSrcweir                                    Point( nX, nY ) ) );
10791cdf0e10cSrcweir         aPoint -= lcl_convert( m_aGraphicsStack.front().m_aMapMode,
10792cdf0e10cSrcweir                                m_aMapMode,
10793cdf0e10cSrcweir                                getReferenceDevice(),
10794cdf0e10cSrcweir                                Point() );
10795cdf0e10cSrcweir         basegfx::B2DHomMatrix aMat;
10796cdf0e10cSrcweir         aMat.translate( aPoint.X(), aPoint.Y() );
10797cdf0e10cSrcweir         m_aGraphicsStack.front().m_aClipRegion.transform( aMat );
10798cdf0e10cSrcweir         m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsState::updateClipRegion;
10799cdf0e10cSrcweir     }
10800cdf0e10cSrcweir }
10801cdf0e10cSrcweir 
10802cdf0e10cSrcweir bool PDFWriterImpl::intersectClipRegion( const Rectangle& rRect )
10803cdf0e10cSrcweir {
10804cdf0e10cSrcweir     basegfx::B2DPolyPolygon aRect( basegfx::tools::createPolygonFromRect(
10805cdf0e10cSrcweir         basegfx::B2DRectangle( rRect.Left(), rRect.Top(), rRect.Right(), rRect.Bottom() ) ) );
10806cdf0e10cSrcweir     return intersectClipRegion( aRect );
10807cdf0e10cSrcweir }
10808cdf0e10cSrcweir 
10809cdf0e10cSrcweir 
10810cdf0e10cSrcweir bool PDFWriterImpl::intersectClipRegion( const basegfx::B2DPolyPolygon& rRegion )
10811cdf0e10cSrcweir {
10812cdf0e10cSrcweir     basegfx::B2DPolyPolygon aRegion( getReferenceDevice()->LogicToPixel( rRegion, m_aGraphicsStack.front().m_aMapMode ) );
10813cdf0e10cSrcweir     aRegion = getReferenceDevice()->PixelToLogic( aRegion, m_aMapMode );
10814cdf0e10cSrcweir     m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsState::updateClipRegion;
10815cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_bClipRegion )
10816cdf0e10cSrcweir     {
10817cdf0e10cSrcweir         basegfx::B2DPolyPolygon aOld( basegfx::tools::prepareForPolygonOperation( m_aGraphicsStack.front().m_aClipRegion ) );
10818cdf0e10cSrcweir         aRegion = basegfx::tools::prepareForPolygonOperation( aRegion );
10819cdf0e10cSrcweir         m_aGraphicsStack.front().m_aClipRegion = basegfx::tools::solvePolygonOperationAnd( aOld, aRegion );
10820cdf0e10cSrcweir     }
10821cdf0e10cSrcweir     else
10822cdf0e10cSrcweir     {
10823cdf0e10cSrcweir         m_aGraphicsStack.front().m_aClipRegion = aRegion;
10824cdf0e10cSrcweir         m_aGraphicsStack.front().m_bClipRegion = true;
10825cdf0e10cSrcweir     }
10826cdf0e10cSrcweir     return true;
10827cdf0e10cSrcweir }
10828cdf0e10cSrcweir 
10829cdf0e10cSrcweir void PDFWriterImpl::createNote( const Rectangle& rRect, const PDFNote& rNote, sal_Int32 nPageNr )
10830cdf0e10cSrcweir {
10831cdf0e10cSrcweir     if( nPageNr < 0 )
10832cdf0e10cSrcweir         nPageNr = m_nCurrentPage;
10833cdf0e10cSrcweir 
10834cdf0e10cSrcweir     if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() )
10835cdf0e10cSrcweir         return;
10836cdf0e10cSrcweir 
10837cdf0e10cSrcweir     m_aNotes.push_back( PDFNoteEntry() );
10838cdf0e10cSrcweir     m_aNotes.back().m_nObject		= createObject();
10839cdf0e10cSrcweir     m_aNotes.back().m_aContents		= rNote;
10840cdf0e10cSrcweir     m_aNotes.back().m_aRect			= rRect;
10841cdf0e10cSrcweir     // convert to default user space now, since the mapmode may change
10842cdf0e10cSrcweir     m_aPages[nPageNr].convertRect( m_aNotes.back().m_aRect );
10843cdf0e10cSrcweir 
10844cdf0e10cSrcweir     // insert note to page's annotation list
10845cdf0e10cSrcweir     m_aPages[ nPageNr ].m_aAnnotations.push_back( m_aNotes.back().m_nObject );
10846cdf0e10cSrcweir }
10847cdf0e10cSrcweir 
10848cdf0e10cSrcweir sal_Int32 PDFWriterImpl::createLink( const Rectangle& rRect, sal_Int32 nPageNr )
10849cdf0e10cSrcweir {
10850cdf0e10cSrcweir     if( nPageNr < 0 )
10851cdf0e10cSrcweir         nPageNr = m_nCurrentPage;
10852cdf0e10cSrcweir 
10853cdf0e10cSrcweir     if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() )
10854cdf0e10cSrcweir         return -1;
10855cdf0e10cSrcweir 
10856cdf0e10cSrcweir     sal_Int32 nRet = m_aLinks.size();
10857cdf0e10cSrcweir 
10858cdf0e10cSrcweir     m_aLinks.push_back( PDFLink() );
10859cdf0e10cSrcweir     m_aLinks.back().m_nObject	= createObject();
10860cdf0e10cSrcweir     m_aLinks.back().m_nPage		= nPageNr;
10861cdf0e10cSrcweir     m_aLinks.back().m_aRect		= rRect;
10862cdf0e10cSrcweir     // convert to default user space now, since the mapmode may change
10863cdf0e10cSrcweir     m_aPages[nPageNr].convertRect( m_aLinks.back().m_aRect );
10864cdf0e10cSrcweir 
10865cdf0e10cSrcweir     // insert link to page's annotation list
10866cdf0e10cSrcweir     m_aPages[ nPageNr ].m_aAnnotations.push_back( m_aLinks.back().m_nObject );
10867cdf0e10cSrcweir 
10868cdf0e10cSrcweir     return nRet;
10869cdf0e10cSrcweir }
10870cdf0e10cSrcweir 
10871cdf0e10cSrcweir //--->i56629
10872cdf0e10cSrcweir sal_Int32 PDFWriterImpl::createNamedDest( const rtl::OUString& sDestName, const Rectangle& rRect, sal_Int32 nPageNr, PDFWriter::DestAreaType eType )
10873cdf0e10cSrcweir {
10874cdf0e10cSrcweir     if( nPageNr < 0 )
10875cdf0e10cSrcweir         nPageNr = m_nCurrentPage;
10876cdf0e10cSrcweir 
10877cdf0e10cSrcweir     if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() )
10878cdf0e10cSrcweir         return -1;
10879cdf0e10cSrcweir 
10880cdf0e10cSrcweir     sal_Int32 nRet = m_aNamedDests.size();
10881cdf0e10cSrcweir 
10882cdf0e10cSrcweir     m_aNamedDests.push_back( PDFNamedDest() );
10883cdf0e10cSrcweir     m_aNamedDests.back().m_aDestName = sDestName;
10884cdf0e10cSrcweir     m_aNamedDests.back().m_nPage = nPageNr;
10885cdf0e10cSrcweir     m_aNamedDests.back().m_eType = eType;
10886cdf0e10cSrcweir     m_aNamedDests.back().m_aRect = rRect;
10887cdf0e10cSrcweir     // convert to default user space now, since the mapmode may change
10888cdf0e10cSrcweir     m_aPages[nPageNr].convertRect( m_aNamedDests.back().m_aRect );
10889cdf0e10cSrcweir 
10890cdf0e10cSrcweir     return nRet;
10891cdf0e10cSrcweir }
10892cdf0e10cSrcweir //<---i56629
10893cdf0e10cSrcweir 
10894cdf0e10cSrcweir sal_Int32 PDFWriterImpl::createDest( const Rectangle& rRect, sal_Int32 nPageNr, PDFWriter::DestAreaType eType )
10895cdf0e10cSrcweir {
10896cdf0e10cSrcweir     if( nPageNr < 0 )
10897cdf0e10cSrcweir         nPageNr = m_nCurrentPage;
10898cdf0e10cSrcweir 
10899cdf0e10cSrcweir     if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() )
10900cdf0e10cSrcweir         return -1;
10901cdf0e10cSrcweir 
10902cdf0e10cSrcweir     sal_Int32 nRet = m_aDests.size();
10903cdf0e10cSrcweir 
10904cdf0e10cSrcweir     m_aDests.push_back( PDFDest() );
10905cdf0e10cSrcweir     m_aDests.back().m_nPage = nPageNr;
10906cdf0e10cSrcweir     m_aDests.back().m_eType	= eType;
10907cdf0e10cSrcweir     m_aDests.back().m_aRect = rRect;
10908cdf0e10cSrcweir     // convert to default user space now, since the mapmode may change
10909cdf0e10cSrcweir     m_aPages[nPageNr].convertRect( m_aDests.back().m_aRect );
10910cdf0e10cSrcweir 
10911cdf0e10cSrcweir     return nRet;
10912cdf0e10cSrcweir }
10913cdf0e10cSrcweir 
10914cdf0e10cSrcweir sal_Int32 PDFWriterImpl::registerDestReference( sal_Int32 nDestId, const Rectangle& rRect, sal_Int32 nPageNr, PDFWriter::DestAreaType eType )
10915cdf0e10cSrcweir {
10916cdf0e10cSrcweir     return m_aDestinationIdTranslation[ nDestId ] = createDest( rRect, nPageNr, eType );
10917cdf0e10cSrcweir }
10918cdf0e10cSrcweir 
10919cdf0e10cSrcweir sal_Int32 PDFWriterImpl::setLinkDest( sal_Int32 nLinkId, sal_Int32 nDestId )
10920cdf0e10cSrcweir {
10921cdf0e10cSrcweir     if( nLinkId < 0 || nLinkId >= (sal_Int32)m_aLinks.size() )
10922cdf0e10cSrcweir         return -1;
10923cdf0e10cSrcweir     if( nDestId < 0 || nDestId >= (sal_Int32)m_aDests.size() )
10924cdf0e10cSrcweir         return -2;
10925cdf0e10cSrcweir 
10926cdf0e10cSrcweir     m_aLinks[ nLinkId ].m_nDest = nDestId;
10927cdf0e10cSrcweir 
10928cdf0e10cSrcweir     return 0;
10929cdf0e10cSrcweir }
10930cdf0e10cSrcweir 
10931cdf0e10cSrcweir sal_Int32 PDFWriterImpl::setLinkURL( sal_Int32 nLinkId, const OUString& rURL )
10932cdf0e10cSrcweir {
10933cdf0e10cSrcweir     if( nLinkId < 0 || nLinkId >= (sal_Int32)m_aLinks.size() )
10934cdf0e10cSrcweir         return -1;
10935cdf0e10cSrcweir 
10936cdf0e10cSrcweir     m_aLinks[ nLinkId ].m_nDest	= -1;
10937cdf0e10cSrcweir 
10938cdf0e10cSrcweir     using namespace ::com::sun::star;
10939cdf0e10cSrcweir 
10940cdf0e10cSrcweir     if (!m_xTrans.is())
10941cdf0e10cSrcweir     {
10942cdf0e10cSrcweir         uno::Reference< lang::XMultiServiceFactory > xFact( comphelper::getProcessServiceFactory() );
10943cdf0e10cSrcweir         if( xFact.is() )
10944cdf0e10cSrcweir         {
10945cdf0e10cSrcweir             m_xTrans = uno::Reference < util::XURLTransformer >(
10946cdf0e10cSrcweir                 xFact->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.util.URLTransformer" ) ) ), uno::UNO_QUERY );
10947cdf0e10cSrcweir         }
10948cdf0e10cSrcweir     }
10949cdf0e10cSrcweir 
10950cdf0e10cSrcweir     util::URL aURL;
10951cdf0e10cSrcweir     aURL.Complete = rURL;
10952cdf0e10cSrcweir 
10953cdf0e10cSrcweir     if (m_xTrans.is())
10954cdf0e10cSrcweir         m_xTrans->parseStrict( aURL );
10955cdf0e10cSrcweir 
10956cdf0e10cSrcweir     m_aLinks[ nLinkId ].m_aURL	= aURL.Complete;
10957cdf0e10cSrcweir 
10958cdf0e10cSrcweir     return 0;
10959cdf0e10cSrcweir }
10960cdf0e10cSrcweir 
10961cdf0e10cSrcweir void PDFWriterImpl::setLinkPropertyId( sal_Int32 nLinkId, sal_Int32 nPropertyId )
10962cdf0e10cSrcweir {
10963cdf0e10cSrcweir     m_aLinkPropertyMap[ nPropertyId ] = nLinkId;
10964cdf0e10cSrcweir }
10965cdf0e10cSrcweir 
10966cdf0e10cSrcweir sal_Int32 PDFWriterImpl::createOutlineItem( sal_Int32 nParent, const OUString& rText, sal_Int32 nDestID )
10967cdf0e10cSrcweir {
10968cdf0e10cSrcweir     // create new item
10969cdf0e10cSrcweir     sal_Int32 nNewItem = m_aOutline.size();
10970cdf0e10cSrcweir     m_aOutline.push_back( PDFOutlineEntry() );
10971cdf0e10cSrcweir 
10972cdf0e10cSrcweir     // set item attributes
10973cdf0e10cSrcweir     setOutlineItemParent( nNewItem, nParent );
10974cdf0e10cSrcweir     setOutlineItemText( nNewItem, rText );
10975cdf0e10cSrcweir     setOutlineItemDest( nNewItem, nDestID );
10976cdf0e10cSrcweir 
10977cdf0e10cSrcweir     return nNewItem;
10978cdf0e10cSrcweir }
10979cdf0e10cSrcweir 
10980cdf0e10cSrcweir sal_Int32 PDFWriterImpl::setOutlineItemParent( sal_Int32 nItem, sal_Int32 nNewParent )
10981cdf0e10cSrcweir {
10982cdf0e10cSrcweir     if( nItem < 1 || nItem >= (sal_Int32)m_aOutline.size() )
10983cdf0e10cSrcweir         return -1;
10984cdf0e10cSrcweir 
10985cdf0e10cSrcweir     int nRet = 0;
10986cdf0e10cSrcweir 
10987cdf0e10cSrcweir     if( nNewParent < 0 || nNewParent >= (sal_Int32)m_aOutline.size() || nNewParent == nItem )
10988cdf0e10cSrcweir     {
10989cdf0e10cSrcweir         nNewParent = 0;
10990cdf0e10cSrcweir         nRet = -2;
10991cdf0e10cSrcweir     }
10992cdf0e10cSrcweir     // remove item from previous parent
10993cdf0e10cSrcweir     sal_Int32 nParentID = m_aOutline[ nItem ].m_nParentID;
10994cdf0e10cSrcweir     if( nParentID >= 0 && nParentID < (sal_Int32)m_aOutline.size() )
10995cdf0e10cSrcweir     {
10996cdf0e10cSrcweir         PDFOutlineEntry& rParent = m_aOutline[ nParentID ];
10997cdf0e10cSrcweir 
10998cdf0e10cSrcweir         for( std::vector<sal_Int32>::iterator it = rParent.m_aChildren.begin();
10999cdf0e10cSrcweir              it != rParent.m_aChildren.end(); ++it )
11000cdf0e10cSrcweir         {
11001cdf0e10cSrcweir             if( *it == nItem )
11002cdf0e10cSrcweir             {
11003cdf0e10cSrcweir                 rParent.m_aChildren.erase( it );
11004cdf0e10cSrcweir                 break;
11005cdf0e10cSrcweir             }
11006cdf0e10cSrcweir         }
11007cdf0e10cSrcweir     }
11008cdf0e10cSrcweir 
11009cdf0e10cSrcweir     // insert item to new parent's list of children
11010cdf0e10cSrcweir     m_aOutline[ nNewParent ].m_aChildren.push_back( nItem );
11011cdf0e10cSrcweir 
11012cdf0e10cSrcweir     return nRet;
11013cdf0e10cSrcweir }
11014cdf0e10cSrcweir 
11015cdf0e10cSrcweir sal_Int32 PDFWriterImpl::setOutlineItemText( sal_Int32 nItem, const OUString& rText )
11016cdf0e10cSrcweir {
11017cdf0e10cSrcweir     if( nItem < 1 || nItem >= (sal_Int32)m_aOutline.size() )
11018cdf0e10cSrcweir         return -1;
11019cdf0e10cSrcweir 
11020cdf0e10cSrcweir     m_aOutline[ nItem ].m_aTitle = psp::WhitespaceToSpace( rText );
11021cdf0e10cSrcweir     return 0;
11022cdf0e10cSrcweir }
11023cdf0e10cSrcweir 
11024cdf0e10cSrcweir sal_Int32 PDFWriterImpl::setOutlineItemDest( sal_Int32 nItem, sal_Int32 nDestID )
11025cdf0e10cSrcweir {
11026cdf0e10cSrcweir     if( nItem < 1 || nItem >= (sal_Int32)m_aOutline.size() ) // item does not exist
11027cdf0e10cSrcweir         return -1;
11028cdf0e10cSrcweir     if( nDestID < 0 || nDestID >= (sal_Int32)m_aDests.size() ) // dest does not exist
11029cdf0e10cSrcweir         return -2;
11030cdf0e10cSrcweir     m_aOutline[nItem].m_nDestID = nDestID;
11031cdf0e10cSrcweir     return 0;
11032cdf0e10cSrcweir }
11033cdf0e10cSrcweir 
11034cdf0e10cSrcweir const sal_Char* PDFWriterImpl::getStructureTag( PDFWriter::StructElement eType )
11035cdf0e10cSrcweir {
11036cdf0e10cSrcweir     static std::map< PDFWriter::StructElement, const char* > aTagStrings;
11037cdf0e10cSrcweir     if( aTagStrings.empty() )
11038cdf0e10cSrcweir     {
11039cdf0e10cSrcweir         aTagStrings[ PDFWriter::NonStructElement] = "NonStruct";
11040cdf0e10cSrcweir         aTagStrings[ PDFWriter::Document ]		= "Document";
11041cdf0e10cSrcweir         aTagStrings[ PDFWriter::Part ]			= "Part";
11042cdf0e10cSrcweir         aTagStrings[ PDFWriter::Article ]		= "Art";
11043cdf0e10cSrcweir         aTagStrings[ PDFWriter::Section ]		= "Sect";
11044cdf0e10cSrcweir         aTagStrings[ PDFWriter::Division ]		= "Div";
11045cdf0e10cSrcweir         aTagStrings[ PDFWriter::BlockQuote ]	= "BlockQuote";
11046cdf0e10cSrcweir         aTagStrings[ PDFWriter::Caption ]		= "Caption";
11047cdf0e10cSrcweir         aTagStrings[ PDFWriter::TOC ]			= "TOC";
11048cdf0e10cSrcweir         aTagStrings[ PDFWriter::TOCI ]			= "TOCI";
11049cdf0e10cSrcweir         aTagStrings[ PDFWriter::Index ]			= "Index";
11050cdf0e10cSrcweir         aTagStrings[ PDFWriter::Paragraph ]		= "P";
11051cdf0e10cSrcweir         aTagStrings[ PDFWriter::Heading ]		= "H";
11052cdf0e10cSrcweir         aTagStrings[ PDFWriter::H1 ]			= "H1";
11053cdf0e10cSrcweir         aTagStrings[ PDFWriter::H2 ]			= "H2";
11054cdf0e10cSrcweir         aTagStrings[ PDFWriter::H3 ]			= "H3";
11055cdf0e10cSrcweir         aTagStrings[ PDFWriter::H4 ]			= "H4";
11056cdf0e10cSrcweir         aTagStrings[ PDFWriter::H5 ]			= "H5";
11057cdf0e10cSrcweir         aTagStrings[ PDFWriter::H6 ]			= "H6";
11058cdf0e10cSrcweir         aTagStrings[ PDFWriter::List ]			= "L";
11059cdf0e10cSrcweir         aTagStrings[ PDFWriter::ListItem ]		= "LI";
11060cdf0e10cSrcweir         aTagStrings[ PDFWriter::LILabel ]		= "Lbl";
11061cdf0e10cSrcweir         aTagStrings[ PDFWriter::LIBody ]		= "LBody";
11062cdf0e10cSrcweir         aTagStrings[ PDFWriter::Table ]			= "Table";
11063cdf0e10cSrcweir         aTagStrings[ PDFWriter::TableRow ]		= "TR";
11064cdf0e10cSrcweir         aTagStrings[ PDFWriter::TableHeader ]	= "TH";
11065cdf0e10cSrcweir         aTagStrings[ PDFWriter::TableData ]		= "TD";
11066cdf0e10cSrcweir         aTagStrings[ PDFWriter::Span ]			= "Span";
11067cdf0e10cSrcweir         aTagStrings[ PDFWriter::Quote ]			= "Quote";
11068cdf0e10cSrcweir         aTagStrings[ PDFWriter::Note ]			= "Note";
11069cdf0e10cSrcweir         aTagStrings[ PDFWriter::Reference ]		= "Reference";
11070cdf0e10cSrcweir         aTagStrings[ PDFWriter::BibEntry ]		= "BibEntry";
11071cdf0e10cSrcweir         aTagStrings[ PDFWriter::Code ]			= "Code";
11072cdf0e10cSrcweir         aTagStrings[ PDFWriter::Link ]			= "Link";
11073cdf0e10cSrcweir         aTagStrings[ PDFWriter::Figure ]		= "Figure";
11074cdf0e10cSrcweir         aTagStrings[ PDFWriter::Formula ]		= "Formula";
11075cdf0e10cSrcweir         aTagStrings[ PDFWriter::Form ]			= "Form";
11076cdf0e10cSrcweir     }
11077cdf0e10cSrcweir 
11078cdf0e10cSrcweir     std::map< PDFWriter::StructElement, const char* >::const_iterator it = aTagStrings.find( eType );
11079cdf0e10cSrcweir 
11080cdf0e10cSrcweir     return it != aTagStrings.end() ? it->second : "Div";
11081cdf0e10cSrcweir }
11082cdf0e10cSrcweir 
11083cdf0e10cSrcweir void PDFWriterImpl::beginStructureElementMCSeq()
11084cdf0e10cSrcweir {
11085cdf0e10cSrcweir     if(	m_bEmitStructure &&
11086cdf0e10cSrcweir         m_nCurrentStructElement > 0 && // StructTreeRoot
11087cdf0e10cSrcweir         ! m_aStructure[ m_nCurrentStructElement ].m_bOpenMCSeq // already opened sequence
11088cdf0e10cSrcweir         )
11089cdf0e10cSrcweir     {
11090cdf0e10cSrcweir         PDFStructureElement& rEle = m_aStructure[ m_nCurrentStructElement ];
11091cdf0e10cSrcweir         OStringBuffer aLine( 128 );
11092cdf0e10cSrcweir         sal_Int32 nMCID = m_aPages[ m_nCurrentPage ].m_aMCIDParents.size();
11093cdf0e10cSrcweir         aLine.append( "/" );
11094cdf0e10cSrcweir         if( rEle.m_aAlias.getLength() > 0 )
11095cdf0e10cSrcweir             aLine.append( rEle.m_aAlias );
11096cdf0e10cSrcweir         else
11097cdf0e10cSrcweir             aLine.append( getStructureTag( rEle.m_eType ) );
11098cdf0e10cSrcweir         aLine.append( "<</MCID " );
11099cdf0e10cSrcweir         aLine.append( nMCID );
11100cdf0e10cSrcweir         aLine.append( ">>BDC\n" );
11101cdf0e10cSrcweir         writeBuffer( aLine.getStr(), aLine.getLength() );
11102cdf0e10cSrcweir 
11103cdf0e10cSrcweir         // update the element's content list
11104cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
11105cdf0e10cSrcweir         fprintf( stderr, "beginning marked content id %" SAL_PRIdINT32 " on page object %" SAL_PRIdINT32 ", structure first page = %" SAL_PRIdINT32 "\n",
11106cdf0e10cSrcweir                  nMCID,
11107cdf0e10cSrcweir                  m_aPages[ m_nCurrentPage ].m_nPageObject,
11108cdf0e10cSrcweir                  rEle.m_nFirstPageObject );
11109cdf0e10cSrcweir #endif
11110cdf0e10cSrcweir         rEle.m_aKids.push_back( PDFStructureElementKid( nMCID, m_aPages[m_nCurrentPage].m_nPageObject ) );
11111cdf0e10cSrcweir         // update the page's mcid parent list
11112cdf0e10cSrcweir         m_aPages[ m_nCurrentPage ].m_aMCIDParents.push_back( rEle.m_nObject );
11113cdf0e10cSrcweir         // mark element MC sequence as open
11114cdf0e10cSrcweir         rEle.m_bOpenMCSeq = true;
11115cdf0e10cSrcweir     }
11116cdf0e10cSrcweir     // handle artifacts
11117cdf0e10cSrcweir     else if( ! m_bEmitStructure && m_aContext.Tagged &&
11118cdf0e10cSrcweir                m_nCurrentStructElement > 0 &&
11119cdf0e10cSrcweir                m_aStructure[ m_nCurrentStructElement ].m_eType == PDFWriter::NonStructElement &&
11120cdf0e10cSrcweir              ! m_aStructure[ m_nCurrentStructElement ].m_bOpenMCSeq // already opened sequence
11121cdf0e10cSrcweir              )
11122cdf0e10cSrcweir     {
11123cdf0e10cSrcweir         OStringBuffer aLine( 128 );
11124cdf0e10cSrcweir         aLine.append( "/Artifact BMC\n" );
11125cdf0e10cSrcweir         writeBuffer( aLine.getStr(), aLine.getLength() );
11126cdf0e10cSrcweir         // mark element MC sequence as open
11127cdf0e10cSrcweir         m_aStructure[ m_nCurrentStructElement ].m_bOpenMCSeq = true;
11128cdf0e10cSrcweir     }
11129cdf0e10cSrcweir }
11130cdf0e10cSrcweir 
11131cdf0e10cSrcweir void PDFWriterImpl::endStructureElementMCSeq()
11132cdf0e10cSrcweir {
11133cdf0e10cSrcweir     if( m_nCurrentStructElement > 0 && // StructTreeRoot
11134cdf0e10cSrcweir         ( m_bEmitStructure || m_aStructure[ m_nCurrentStructElement ].m_eType == PDFWriter::NonStructElement ) &&
11135cdf0e10cSrcweir         m_aStructure[ m_nCurrentStructElement ].m_bOpenMCSeq // must have an opened MC sequence
11136cdf0e10cSrcweir         )
11137cdf0e10cSrcweir     {
11138cdf0e10cSrcweir         writeBuffer( "EMC\n", 4 );
11139cdf0e10cSrcweir         m_aStructure[ m_nCurrentStructElement ].m_bOpenMCSeq = false;
11140cdf0e10cSrcweir     }
11141cdf0e10cSrcweir }
11142cdf0e10cSrcweir 
11143cdf0e10cSrcweir bool PDFWriterImpl::checkEmitStructure()
11144cdf0e10cSrcweir {
11145cdf0e10cSrcweir     bool bEmit = false;
11146cdf0e10cSrcweir     if( m_aContext.Tagged )
11147cdf0e10cSrcweir     {
11148cdf0e10cSrcweir         bEmit = true;
11149cdf0e10cSrcweir         sal_Int32 nEle = m_nCurrentStructElement;
11150cdf0e10cSrcweir         while( nEle > 0 && nEle < sal_Int32(m_aStructure.size()) )
11151cdf0e10cSrcweir         {
11152cdf0e10cSrcweir             if( m_aStructure[ nEle ].m_eType == PDFWriter::NonStructElement )
11153cdf0e10cSrcweir             {
11154cdf0e10cSrcweir                 bEmit = false;
11155cdf0e10cSrcweir                 break;
11156cdf0e10cSrcweir             }
11157cdf0e10cSrcweir             nEle = m_aStructure[ nEle ].m_nParentElement;
11158cdf0e10cSrcweir         }
11159cdf0e10cSrcweir     }
11160cdf0e10cSrcweir     return bEmit;
11161cdf0e10cSrcweir }
11162cdf0e10cSrcweir 
11163cdf0e10cSrcweir sal_Int32 PDFWriterImpl::beginStructureElement( PDFWriter::StructElement eType, const rtl::OUString& rAlias )
11164cdf0e10cSrcweir {
11165cdf0e10cSrcweir     if( m_nCurrentPage < 0 )
11166cdf0e10cSrcweir         return -1;
11167cdf0e10cSrcweir 
11168cdf0e10cSrcweir     if( ! m_aContext.Tagged )
11169cdf0e10cSrcweir         return -1;
11170cdf0e10cSrcweir 
11171cdf0e10cSrcweir     // close eventual current MC sequence
11172cdf0e10cSrcweir     endStructureElementMCSeq();
11173cdf0e10cSrcweir 
11174cdf0e10cSrcweir     if( m_nCurrentStructElement == 0 &&
11175cdf0e10cSrcweir         eType != PDFWriter::Document && eType != PDFWriter::NonStructElement )
11176cdf0e10cSrcweir     {
11177cdf0e10cSrcweir         // struct tree root hit, but not beginning document
11178cdf0e10cSrcweir         // this might happen with setCurrentStructureElement
11179cdf0e10cSrcweir         // silently insert structure into document again if one properly exists
11180cdf0e10cSrcweir         if( ! m_aStructure[ 0 ].m_aChildren.empty() )
11181cdf0e10cSrcweir         {
11182cdf0e10cSrcweir             PDFWriter::StructElement childType = PDFWriter::NonStructElement;
11183cdf0e10cSrcweir             sal_Int32 nNewCurElement = 0;
11184cdf0e10cSrcweir             const std::list< sal_Int32 >& rRootChildren = m_aStructure[0].m_aChildren;
11185cdf0e10cSrcweir             for( std::list< sal_Int32 >::const_iterator it = rRootChildren.begin();
11186cdf0e10cSrcweir                  childType != PDFWriter::Document && it != rRootChildren.end(); ++it )
11187cdf0e10cSrcweir             {
11188cdf0e10cSrcweir                 nNewCurElement = *it;
11189cdf0e10cSrcweir                 childType = m_aStructure[ nNewCurElement ].m_eType;
11190cdf0e10cSrcweir             }
11191cdf0e10cSrcweir             if( childType == PDFWriter::Document )
11192cdf0e10cSrcweir             {
11193cdf0e10cSrcweir                 m_nCurrentStructElement = nNewCurElement;
11194cdf0e10cSrcweir                 DBG_ASSERT( 0, "Structure element inserted to StructTreeRoot that is not a document" );
11195cdf0e10cSrcweir             }
11196cdf0e10cSrcweir             else {
11197cdf0e10cSrcweir                 DBG_ERROR( "document structure in disorder !" );
11198cdf0e10cSrcweir             }
11199cdf0e10cSrcweir         }
11200cdf0e10cSrcweir         else {
11201cdf0e10cSrcweir             DBG_ERROR( "PDF document structure MUST be contained in a Document element" );
11202cdf0e10cSrcweir         }
11203cdf0e10cSrcweir     }
11204cdf0e10cSrcweir 
11205cdf0e10cSrcweir     sal_Int32 nNewId = sal_Int32(m_aStructure.size());
11206cdf0e10cSrcweir     m_aStructure.push_back( PDFStructureElement() );
11207cdf0e10cSrcweir     PDFStructureElement& rEle = m_aStructure.back();
11208cdf0e10cSrcweir     rEle.m_eType			= eType;
11209cdf0e10cSrcweir     rEle.m_nOwnElement		= nNewId;
11210cdf0e10cSrcweir     rEle.m_nParentElement	= m_nCurrentStructElement;
11211cdf0e10cSrcweir     rEle.m_nFirstPageObject	= m_aPages[ m_nCurrentPage ].m_nPageObject;
11212cdf0e10cSrcweir     m_aStructure[ m_nCurrentStructElement ].m_aChildren.push_back( nNewId );
11213cdf0e10cSrcweir     m_nCurrentStructElement = nNewId;
11214cdf0e10cSrcweir 
11215cdf0e10cSrcweir     // handle alias names
11216cdf0e10cSrcweir     if( rAlias.getLength() && eType != PDFWriter::NonStructElement )
11217cdf0e10cSrcweir     {
11218cdf0e10cSrcweir         OStringBuffer aNameBuf( rAlias.getLength() );
11219cdf0e10cSrcweir         appendName( rAlias, aNameBuf );
11220cdf0e10cSrcweir         OString aAliasName( aNameBuf.makeStringAndClear() );
11221cdf0e10cSrcweir         rEle.m_aAlias = aAliasName;
11222cdf0e10cSrcweir         m_aRoleMap[ aAliasName ] = getStructureTag( eType );
11223cdf0e10cSrcweir     }
11224cdf0e10cSrcweir 
11225cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
11226cdf0e10cSrcweir     OStringBuffer aLine( "beginStructureElement " );
11227cdf0e10cSrcweir     aLine.append( m_nCurrentStructElement );
11228cdf0e10cSrcweir     aLine.append( ": " );
11229cdf0e10cSrcweir     aLine.append( getStructureTag( eType ) );
11230cdf0e10cSrcweir     if( rEle.m_aAlias.getLength() )
11231cdf0e10cSrcweir     {
11232cdf0e10cSrcweir         aLine.append( " aliased as \"" );
11233cdf0e10cSrcweir         aLine.append( rEle.m_aAlias );
11234cdf0e10cSrcweir         aLine.append( '\"' );
11235cdf0e10cSrcweir     }
11236cdf0e10cSrcweir     emitComment( aLine.getStr() );
11237cdf0e10cSrcweir #endif
11238cdf0e10cSrcweir 
11239cdf0e10cSrcweir     // check whether to emit structure henceforth
11240cdf0e10cSrcweir     m_bEmitStructure = checkEmitStructure();
11241cdf0e10cSrcweir 
11242cdf0e10cSrcweir     if( m_bEmitStructure ) // don't create nonexistant objects
11243cdf0e10cSrcweir     {
11244cdf0e10cSrcweir         rEle.m_nObject		= createObject();
11245cdf0e10cSrcweir         // update parent's kids list
11246cdf0e10cSrcweir         m_aStructure[ rEle.m_nParentElement ].m_aKids.push_back( rEle.m_nObject );
11247cdf0e10cSrcweir     }
11248cdf0e10cSrcweir     return nNewId;
11249cdf0e10cSrcweir }
11250cdf0e10cSrcweir 
11251cdf0e10cSrcweir void PDFWriterImpl::endStructureElement()
11252cdf0e10cSrcweir {
11253cdf0e10cSrcweir     if( m_nCurrentPage < 0 )
11254cdf0e10cSrcweir         return;
11255cdf0e10cSrcweir 
11256cdf0e10cSrcweir     if( ! m_aContext.Tagged )
11257cdf0e10cSrcweir         return;
11258cdf0e10cSrcweir 
11259cdf0e10cSrcweir     if( m_nCurrentStructElement == 0 )
11260cdf0e10cSrcweir     {
11261cdf0e10cSrcweir         // hit the struct tree root, that means there is an endStructureElement
11262cdf0e10cSrcweir         // without corresponding beginStructureElement
11263cdf0e10cSrcweir         return;
11264cdf0e10cSrcweir     }
11265cdf0e10cSrcweir 
11266cdf0e10cSrcweir     // end the marked content sequence
11267cdf0e10cSrcweir     endStructureElementMCSeq();
11268cdf0e10cSrcweir 
11269cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
11270cdf0e10cSrcweir     OStringBuffer aLine( "endStructureElement " );
11271cdf0e10cSrcweir     aLine.append( m_nCurrentStructElement );
11272cdf0e10cSrcweir     aLine.append( ": " );
11273cdf0e10cSrcweir     aLine.append( getStructureTag( m_aStructure[ m_nCurrentStructElement ].m_eType ) );
11274cdf0e10cSrcweir     if( m_aStructure[ m_nCurrentStructElement ].m_aAlias.getLength() )
11275cdf0e10cSrcweir     {
11276cdf0e10cSrcweir         aLine.append( " aliased as \"" );
11277cdf0e10cSrcweir         aLine.append( m_aStructure[ m_nCurrentStructElement ].m_aAlias );
11278cdf0e10cSrcweir         aLine.append( '\"' );
11279cdf0e10cSrcweir     }
11280cdf0e10cSrcweir #endif
11281cdf0e10cSrcweir 
11282cdf0e10cSrcweir     // "end" the structure element, the parent becomes current element
11283cdf0e10cSrcweir     m_nCurrentStructElement = m_aStructure[ m_nCurrentStructElement ].m_nParentElement;
11284cdf0e10cSrcweir 
11285cdf0e10cSrcweir     // check whether to emit structure henceforth
11286cdf0e10cSrcweir     m_bEmitStructure = checkEmitStructure();
11287cdf0e10cSrcweir 
11288cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
11289cdf0e10cSrcweir     if( m_bEmitStructure )
11290cdf0e10cSrcweir         emitComment( aLine.getStr() );
11291cdf0e10cSrcweir #endif
11292cdf0e10cSrcweir }
11293cdf0e10cSrcweir 
11294cdf0e10cSrcweir //---> i94258
11295cdf0e10cSrcweir /*
11296cdf0e10cSrcweir  * This function adds an internal structure list container to overcome the 8191 elements array limitation
11297cdf0e10cSrcweir  * in kids element emission.
11298cdf0e10cSrcweir  * Recursive function
11299cdf0e10cSrcweir  *
11300cdf0e10cSrcweir  */
11301cdf0e10cSrcweir void PDFWriterImpl::addInternalStructureContainer( PDFStructureElement& rEle )
11302cdf0e10cSrcweir {
11303cdf0e10cSrcweir     if( rEle.m_eType == PDFWriter::NonStructElement &&
11304cdf0e10cSrcweir         rEle.m_nOwnElement != rEle.m_nParentElement )
11305cdf0e10cSrcweir         return;
11306cdf0e10cSrcweir 
11307cdf0e10cSrcweir     for( std::list< sal_Int32 >::const_iterator it = rEle.m_aChildren.begin(); it != rEle.m_aChildren.end(); ++it )
11308cdf0e10cSrcweir     {
11309cdf0e10cSrcweir         if( *it > 0 && *it < sal_Int32(m_aStructure.size()) )
11310cdf0e10cSrcweir         {
11311cdf0e10cSrcweir             PDFStructureElement& rChild = m_aStructure[ *it ];
11312cdf0e10cSrcweir             if( rChild.m_eType != PDFWriter::NonStructElement )
11313cdf0e10cSrcweir             {
11314cdf0e10cSrcweir                 //triggered when a child of the rEle element is found
11315cdf0e10cSrcweir                 if( rChild.m_nParentElement == rEle.m_nOwnElement )
11316cdf0e10cSrcweir                     addInternalStructureContainer( rChild );//examine the child
11317cdf0e10cSrcweir                 else
11318cdf0e10cSrcweir                 {
11319cdf0e10cSrcweir                     DBG_ERROR( "PDFWriterImpl::addInternalStructureContainer: invalid child structure element" );
11320cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
11321cdf0e10cSrcweir                     fprintf( stderr, "PDFWriterImpl::addInternalStructureContainer: invalid child structure elemnt with id %" SAL_PRIdINT32 "\n", *it );
11322cdf0e10cSrcweir #endif
11323cdf0e10cSrcweir                 }
11324cdf0e10cSrcweir             }
11325cdf0e10cSrcweir         }
11326cdf0e10cSrcweir         else
11327cdf0e10cSrcweir         {
11328cdf0e10cSrcweir             DBG_ERROR( "PDFWriterImpl::emitStructure: invalid child structure id" );
11329cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
11330cdf0e10cSrcweir             fprintf( stderr, "PDFWriterImpl::addInternalStructureContainer: invalid child structure id %" SAL_PRIdINT32 "\n", *it );
11331cdf0e10cSrcweir #endif
11332cdf0e10cSrcweir         }
11333cdf0e10cSrcweir     }
11334cdf0e10cSrcweir 
11335cdf0e10cSrcweir     if( rEle.m_nOwnElement != rEle.m_nParentElement )
11336cdf0e10cSrcweir     {
11337cdf0e10cSrcweir         if( !rEle.m_aKids.empty() )
11338cdf0e10cSrcweir         {
11339cdf0e10cSrcweir             if( rEle.m_aKids.size() > ncMaxPDFArraySize ) {
11340cdf0e10cSrcweir                 //then we need to add the containers for the kids elements
11341cdf0e10cSrcweir                 // a list to be used for the new kid element
11342cdf0e10cSrcweir                 std::list< PDFStructureElementKid > aNewKids;
11343cdf0e10cSrcweir                 std::list< sal_Int32 > aNewChildren;
11344cdf0e10cSrcweir 
11345cdf0e10cSrcweir                 // add Div in RoleMap, in case no one else did (TODO: is it needed? Is it dangerous?)
11346cdf0e10cSrcweir                 OStringBuffer aNameBuf( "Div" );
11347cdf0e10cSrcweir                 OString aAliasName( aNameBuf.makeStringAndClear() );
11348cdf0e10cSrcweir                 m_aRoleMap[ aAliasName ] = getStructureTag( PDFWriter::Division );
11349cdf0e10cSrcweir 
11350cdf0e10cSrcweir                 while( rEle.m_aKids.size() > ncMaxPDFArraySize )
11351cdf0e10cSrcweir                 {
11352cdf0e10cSrcweir                     sal_Int32 nCurrentStructElement = rEle.m_nOwnElement;
11353cdf0e10cSrcweir                     sal_Int32 nNewId = sal_Int32(m_aStructure.size());
11354cdf0e10cSrcweir                     m_aStructure.push_back( PDFStructureElement() );
11355cdf0e10cSrcweir                     PDFStructureElement& rEleNew = m_aStructure.back();
11356cdf0e10cSrcweir                     rEleNew.m_aAlias            = aAliasName;
11357cdf0e10cSrcweir                     rEleNew.m_eType			    = PDFWriter::Division; // a new Div type container
11358cdf0e10cSrcweir                     rEleNew.m_nOwnElement		= nNewId;
11359cdf0e10cSrcweir                     rEleNew.m_nParentElement	= nCurrentStructElement;
11360cdf0e10cSrcweir                     //inherit the same page as the first child to be reparented
11361cdf0e10cSrcweir                     rEleNew.m_nFirstPageObject	= m_aStructure[ rEle.m_aChildren.front() ].m_nFirstPageObject;
11362cdf0e10cSrcweir                     rEleNew.m_nObject           = createObject();//assign a PDF object number
11363cdf0e10cSrcweir                     //add the object to the kid list of the parent
11364cdf0e10cSrcweir                     aNewKids.push_back( PDFStructureElementKid( rEleNew.m_nObject ) );
11365cdf0e10cSrcweir                     aNewChildren.push_back( nNewId );
11366cdf0e10cSrcweir 
11367cdf0e10cSrcweir                     std::list< sal_Int32 >::iterator aChildEndIt( rEle.m_aChildren.begin() );
11368cdf0e10cSrcweir                     std::list< PDFStructureElementKid >::iterator aKidEndIt( rEle.m_aKids.begin() );
11369cdf0e10cSrcweir                     advance( aChildEndIt, ncMaxPDFArraySize );
11370cdf0e10cSrcweir                     advance( aKidEndIt, ncMaxPDFArraySize );
11371cdf0e10cSrcweir 
11372cdf0e10cSrcweir                     rEleNew.m_aKids.splice( rEleNew.m_aKids.begin(),
11373cdf0e10cSrcweir                                             rEle.m_aKids,
11374cdf0e10cSrcweir                                             rEle.m_aKids.begin(),
11375cdf0e10cSrcweir                                             aKidEndIt );
11376cdf0e10cSrcweir                     rEleNew.m_aChildren.splice( rEleNew.m_aChildren.begin(),
11377cdf0e10cSrcweir                                                 rEle.m_aChildren,
11378cdf0e10cSrcweir                                                 rEle.m_aChildren.begin(),
11379cdf0e10cSrcweir                                                 aChildEndIt );
11380cdf0e10cSrcweir                     // set the kid's new parent
11381cdf0e10cSrcweir                     for( std::list< sal_Int32 >::const_iterator it = rEleNew.m_aChildren.begin();
11382cdf0e10cSrcweir                          it != rEleNew.m_aChildren.end(); ++it )
11383cdf0e10cSrcweir                     {
11384cdf0e10cSrcweir                         m_aStructure[ *it ].m_nParentElement = nNewId;
11385cdf0e10cSrcweir                     }
11386cdf0e10cSrcweir                 }
11387cdf0e10cSrcweir                 //finally add the new kids resulting from the container added
11388cdf0e10cSrcweir                 rEle.m_aKids.insert( rEle.m_aKids.begin(), aNewKids.begin(), aNewKids.end() );
11389cdf0e10cSrcweir                 rEle.m_aChildren.insert( rEle.m_aChildren.begin(), aNewChildren.begin(), aNewChildren.end() );
11390cdf0e10cSrcweir             }
11391cdf0e10cSrcweir         }
11392cdf0e10cSrcweir     }
11393cdf0e10cSrcweir }
11394cdf0e10cSrcweir //<--- i94258
11395cdf0e10cSrcweir 
11396cdf0e10cSrcweir bool PDFWriterImpl::setCurrentStructureElement( sal_Int32 nEle )
11397cdf0e10cSrcweir {
11398cdf0e10cSrcweir     bool bSuccess = false;
11399cdf0e10cSrcweir 
11400cdf0e10cSrcweir     if( m_aContext.Tagged && nEle >= 0 && nEle < sal_Int32(m_aStructure.size()) )
11401cdf0e10cSrcweir     {
11402cdf0e10cSrcweir         // end eventual previous marked content sequence
11403cdf0e10cSrcweir         endStructureElementMCSeq();
11404cdf0e10cSrcweir 
11405cdf0e10cSrcweir         m_nCurrentStructElement = nEle;
11406cdf0e10cSrcweir         m_bEmitStructure = checkEmitStructure();
11407cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
11408cdf0e10cSrcweir         OStringBuffer aLine( "setCurrentStructureElement " );
11409cdf0e10cSrcweir         aLine.append( m_nCurrentStructElement );
11410cdf0e10cSrcweir         aLine.append( ": " );
11411cdf0e10cSrcweir         aLine.append( getStructureTag( m_aStructure[ m_nCurrentStructElement ].m_eType ) );
11412cdf0e10cSrcweir         if( m_aStructure[ m_nCurrentStructElement ].m_aAlias.getLength() )
11413cdf0e10cSrcweir         {
11414cdf0e10cSrcweir             aLine.append( " aliased as \"" );
11415cdf0e10cSrcweir             aLine.append( m_aStructure[ m_nCurrentStructElement ].m_aAlias );
11416cdf0e10cSrcweir             aLine.append( '\"' );
11417cdf0e10cSrcweir         }
11418cdf0e10cSrcweir         if( ! m_bEmitStructure )
11419cdf0e10cSrcweir             aLine.append( " (inside NonStruct)" );
11420cdf0e10cSrcweir         emitComment( aLine.getStr() );
11421cdf0e10cSrcweir #endif
11422cdf0e10cSrcweir         bSuccess = true;
11423cdf0e10cSrcweir     }
11424cdf0e10cSrcweir 
11425cdf0e10cSrcweir     return bSuccess;
11426cdf0e10cSrcweir }
11427cdf0e10cSrcweir 
11428cdf0e10cSrcweir sal_Int32 PDFWriterImpl::getCurrentStructureElement()
11429cdf0e10cSrcweir {
11430cdf0e10cSrcweir     return m_nCurrentStructElement;
11431cdf0e10cSrcweir }
11432cdf0e10cSrcweir 
11433cdf0e10cSrcweir bool PDFWriterImpl::setStructureAttribute( enum PDFWriter::StructAttribute eAttr, enum PDFWriter::StructAttributeValue eVal )
11434cdf0e10cSrcweir {
11435cdf0e10cSrcweir     if( !m_aContext.Tagged )
11436cdf0e10cSrcweir         return false;
11437cdf0e10cSrcweir 
11438cdf0e10cSrcweir     bool bInsert = false;
11439cdf0e10cSrcweir     if( m_nCurrentStructElement > 0 && m_bEmitStructure )
11440cdf0e10cSrcweir     {
11441cdf0e10cSrcweir         PDFWriter::StructElement eType = m_aStructure[ m_nCurrentStructElement ].m_eType;
11442cdf0e10cSrcweir         switch( eAttr )
11443cdf0e10cSrcweir         {
11444cdf0e10cSrcweir             case PDFWriter::Placement:
11445cdf0e10cSrcweir                 if( eVal == PDFWriter::Block		||
11446cdf0e10cSrcweir                     eVal == PDFWriter::Inline		||
11447cdf0e10cSrcweir                     eVal == PDFWriter::Before		||
11448cdf0e10cSrcweir                     eVal == PDFWriter::Start		||
11449cdf0e10cSrcweir                     eVal == PDFWriter::End )
11450cdf0e10cSrcweir                     bInsert = true;
11451cdf0e10cSrcweir                 break;
11452cdf0e10cSrcweir             case PDFWriter::WritingMode:
11453cdf0e10cSrcweir                 if( eVal == PDFWriter::LrTb			||
11454cdf0e10cSrcweir                     eVal == PDFWriter::RlTb			||
11455cdf0e10cSrcweir                     eVal == PDFWriter::TbRl )
11456cdf0e10cSrcweir                 {
11457cdf0e10cSrcweir                     bInsert = true;
11458cdf0e10cSrcweir                 }
11459cdf0e10cSrcweir                 break;
11460cdf0e10cSrcweir             case PDFWriter::TextAlign:
11461cdf0e10cSrcweir                 if( eVal == PDFWriter::Start		||
11462cdf0e10cSrcweir                     eVal == PDFWriter::Center		||
11463cdf0e10cSrcweir                     eVal == PDFWriter::End			||
11464cdf0e10cSrcweir                     eVal == PDFWriter::Justify )
11465cdf0e10cSrcweir                 {
11466cdf0e10cSrcweir                     if( eType == PDFWriter::Paragraph	||
11467cdf0e10cSrcweir                         eType == PDFWriter::Heading		||
11468cdf0e10cSrcweir                         eType == PDFWriter::H1			||
11469cdf0e10cSrcweir                         eType == PDFWriter::H2			||
11470cdf0e10cSrcweir                         eType == PDFWriter::H3			||
11471cdf0e10cSrcweir                         eType == PDFWriter::H4			||
11472cdf0e10cSrcweir                         eType == PDFWriter::H5			||
11473cdf0e10cSrcweir                         eType == PDFWriter::H6			||
11474cdf0e10cSrcweir                         eType == PDFWriter::List		||
11475cdf0e10cSrcweir                         eType == PDFWriter::ListItem	||
11476cdf0e10cSrcweir                         eType == PDFWriter::LILabel		||
11477cdf0e10cSrcweir                         eType == PDFWriter::LIBody		||
11478cdf0e10cSrcweir                         eType == PDFWriter::Table		||
11479cdf0e10cSrcweir                         eType == PDFWriter::TableRow	||
11480cdf0e10cSrcweir                         eType == PDFWriter::TableHeader	||
11481cdf0e10cSrcweir                         eType == PDFWriter::TableData )
11482cdf0e10cSrcweir                     {
11483cdf0e10cSrcweir                         bInsert = true;
11484cdf0e10cSrcweir                     }
11485cdf0e10cSrcweir                 }
11486cdf0e10cSrcweir                 break;
11487cdf0e10cSrcweir             case PDFWriter::Width:
11488cdf0e10cSrcweir             case PDFWriter::Height:
11489cdf0e10cSrcweir                 if( eVal == PDFWriter::Auto )
11490cdf0e10cSrcweir                 {
11491cdf0e10cSrcweir                     if( eType == PDFWriter::Figure		||
11492cdf0e10cSrcweir                         eType == PDFWriter::Formula		||
11493cdf0e10cSrcweir                         eType == PDFWriter::Form		||
11494cdf0e10cSrcweir                         eType == PDFWriter::Table		||
11495cdf0e10cSrcweir                         eType == PDFWriter::TableHeader	||
11496cdf0e10cSrcweir                         eType == PDFWriter::TableData )
11497cdf0e10cSrcweir                     {
11498cdf0e10cSrcweir                         bInsert = true;
11499cdf0e10cSrcweir                     }
11500cdf0e10cSrcweir                 }
11501cdf0e10cSrcweir                 break;
11502cdf0e10cSrcweir             case PDFWriter::BlockAlign:
11503cdf0e10cSrcweir                 if( eVal == PDFWriter::Before		||
11504cdf0e10cSrcweir                     eVal == PDFWriter::Middle		||
11505cdf0e10cSrcweir                     eVal == PDFWriter::After		||
11506cdf0e10cSrcweir                     eVal == PDFWriter::Justify )
11507cdf0e10cSrcweir                 {
11508cdf0e10cSrcweir                     if( eType == PDFWriter::TableHeader	||
11509cdf0e10cSrcweir                         eType == PDFWriter::TableData )
11510cdf0e10cSrcweir                     {
11511cdf0e10cSrcweir                         bInsert = true;
11512cdf0e10cSrcweir                     }
11513cdf0e10cSrcweir                 }
11514cdf0e10cSrcweir                 break;
11515cdf0e10cSrcweir             case PDFWriter::InlineAlign:
11516cdf0e10cSrcweir                 if( eVal == PDFWriter::Start		||
11517cdf0e10cSrcweir                     eVal == PDFWriter::Center		||
11518cdf0e10cSrcweir                     eVal == PDFWriter::End )
11519cdf0e10cSrcweir                 {
11520cdf0e10cSrcweir                     if( eType == PDFWriter::TableHeader	||
11521cdf0e10cSrcweir                         eType == PDFWriter::TableData )
11522cdf0e10cSrcweir                     {
11523cdf0e10cSrcweir                         bInsert = true;
11524cdf0e10cSrcweir                     }
11525cdf0e10cSrcweir                 }
11526cdf0e10cSrcweir                 break;
11527cdf0e10cSrcweir             case PDFWriter::LineHeight:
11528cdf0e10cSrcweir                 if( eVal == PDFWriter::Normal		||
11529cdf0e10cSrcweir                     eVal == PDFWriter::Auto )
11530cdf0e10cSrcweir                 {
11531cdf0e10cSrcweir                     // only for ILSE and BLSE
11532cdf0e10cSrcweir                     if( eType == PDFWriter::Paragraph	||
11533cdf0e10cSrcweir                         eType == PDFWriter::Heading		||
11534cdf0e10cSrcweir                         eType == PDFWriter::H1			||
11535cdf0e10cSrcweir                         eType == PDFWriter::H2			||
11536cdf0e10cSrcweir                         eType == PDFWriter::H3			||
11537cdf0e10cSrcweir                         eType == PDFWriter::H4			||
11538cdf0e10cSrcweir                         eType == PDFWriter::H5			||
11539cdf0e10cSrcweir                         eType == PDFWriter::H6			||
11540cdf0e10cSrcweir                         eType == PDFWriter::List		||
11541cdf0e10cSrcweir                         eType == PDFWriter::ListItem	||
11542cdf0e10cSrcweir                         eType == PDFWriter::LILabel		||
11543cdf0e10cSrcweir                         eType == PDFWriter::LIBody		||
11544cdf0e10cSrcweir                         eType == PDFWriter::Table		||
11545cdf0e10cSrcweir                         eType == PDFWriter::TableRow	||
11546cdf0e10cSrcweir                         eType == PDFWriter::TableHeader	||
11547cdf0e10cSrcweir                         eType == PDFWriter::TableData	||
11548cdf0e10cSrcweir                         eType == PDFWriter::Span		||
11549cdf0e10cSrcweir                         eType == PDFWriter::Quote		||
11550cdf0e10cSrcweir                         eType == PDFWriter::Note		||
11551cdf0e10cSrcweir                         eType == PDFWriter::Reference	||
11552cdf0e10cSrcweir                         eType == PDFWriter::BibEntry	||
11553cdf0e10cSrcweir                         eType == PDFWriter::Code		||
11554cdf0e10cSrcweir                         eType == PDFWriter::Link )
11555cdf0e10cSrcweir                     {
11556cdf0e10cSrcweir                         bInsert = true;
11557cdf0e10cSrcweir                     }
11558cdf0e10cSrcweir                 }
11559cdf0e10cSrcweir                 break;
11560cdf0e10cSrcweir             case PDFWriter::TextDecorationType:
11561cdf0e10cSrcweir                 if( eVal == PDFWriter::NONE			||
11562cdf0e10cSrcweir                     eVal == PDFWriter::Underline	||
11563cdf0e10cSrcweir                     eVal == PDFWriter::Overline		||
11564cdf0e10cSrcweir                     eVal == PDFWriter::LineThrough )
11565cdf0e10cSrcweir                 {
11566cdf0e10cSrcweir                     // only for ILSE and BLSE
11567cdf0e10cSrcweir                     if( eType == PDFWriter::Paragraph	||
11568cdf0e10cSrcweir                         eType == PDFWriter::Heading		||
11569cdf0e10cSrcweir                         eType == PDFWriter::H1			||
11570cdf0e10cSrcweir                         eType == PDFWriter::H2			||
11571cdf0e10cSrcweir                         eType == PDFWriter::H3			||
11572cdf0e10cSrcweir                         eType == PDFWriter::H4			||
11573cdf0e10cSrcweir                         eType == PDFWriter::H5			||
11574cdf0e10cSrcweir                         eType == PDFWriter::H6			||
11575cdf0e10cSrcweir                         eType == PDFWriter::List		||
11576cdf0e10cSrcweir                         eType == PDFWriter::ListItem	||
11577cdf0e10cSrcweir                         eType == PDFWriter::LILabel		||
11578cdf0e10cSrcweir                         eType == PDFWriter::LIBody		||
11579cdf0e10cSrcweir                         eType == PDFWriter::Table		||
11580cdf0e10cSrcweir                         eType == PDFWriter::TableRow	||
11581cdf0e10cSrcweir                         eType == PDFWriter::TableHeader	||
11582cdf0e10cSrcweir                         eType == PDFWriter::TableData	||
11583cdf0e10cSrcweir                         eType == PDFWriter::Span		||
11584cdf0e10cSrcweir                         eType == PDFWriter::Quote		||
11585cdf0e10cSrcweir                         eType == PDFWriter::Note		||
11586cdf0e10cSrcweir                         eType == PDFWriter::Reference	||
11587cdf0e10cSrcweir                         eType == PDFWriter::BibEntry	||
11588cdf0e10cSrcweir                         eType == PDFWriter::Code		||
11589cdf0e10cSrcweir                         eType == PDFWriter::Link )
11590cdf0e10cSrcweir                     {
11591cdf0e10cSrcweir                         bInsert = true;
11592cdf0e10cSrcweir                     }
11593cdf0e10cSrcweir                 }
11594cdf0e10cSrcweir                 break;
11595cdf0e10cSrcweir             case PDFWriter::ListNumbering:
11596cdf0e10cSrcweir                 if( eVal == PDFWriter::NONE			||
11597cdf0e10cSrcweir                     eVal == PDFWriter::Disc			||
11598cdf0e10cSrcweir                     eVal == PDFWriter::Circle		||
11599cdf0e10cSrcweir                     eVal == PDFWriter::Square		||
11600cdf0e10cSrcweir                     eVal == PDFWriter::Decimal		||
11601cdf0e10cSrcweir                     eVal == PDFWriter::UpperRoman	||
11602cdf0e10cSrcweir                     eVal == PDFWriter::LowerRoman	||
11603cdf0e10cSrcweir                     eVal == PDFWriter::UpperAlpha	||
11604cdf0e10cSrcweir                     eVal == PDFWriter::LowerAlpha )
11605cdf0e10cSrcweir                 {
11606cdf0e10cSrcweir                     if( eType == PDFWriter::List )
11607cdf0e10cSrcweir                         bInsert = true;
11608cdf0e10cSrcweir                 }
11609cdf0e10cSrcweir                 break;
11610cdf0e10cSrcweir             default: break;
11611cdf0e10cSrcweir         }
11612cdf0e10cSrcweir     }
11613cdf0e10cSrcweir 
11614cdf0e10cSrcweir     if( bInsert )
11615cdf0e10cSrcweir         m_aStructure[ m_nCurrentStructElement ].m_aAttributes[ eAttr ] = PDFStructureAttribute( eVal );
11616cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
11617cdf0e10cSrcweir     else if( m_nCurrentStructElement > 0 && m_bEmitStructure )
11618cdf0e10cSrcweir         fprintf( stderr, "rejecting setStructureAttribute( %s, %s ) on %s (%s) element\n",
11619cdf0e10cSrcweir                  getAttributeTag( eAttr ),
11620cdf0e10cSrcweir                  getAttributeValueTag( eVal ),
11621cdf0e10cSrcweir                  getStructureTag( m_aStructure[ m_nCurrentStructElement ].m_eType ),
11622cdf0e10cSrcweir                  m_aStructure[ m_nCurrentStructElement ].m_aAlias.getStr()
11623cdf0e10cSrcweir                  );
11624cdf0e10cSrcweir #endif
11625cdf0e10cSrcweir 
11626cdf0e10cSrcweir     return bInsert;
11627cdf0e10cSrcweir }
11628cdf0e10cSrcweir 
11629cdf0e10cSrcweir bool PDFWriterImpl::setStructureAttributeNumerical( enum PDFWriter::StructAttribute eAttr, sal_Int32 nValue )
11630cdf0e10cSrcweir {
11631cdf0e10cSrcweir     if( ! m_aContext.Tagged )
11632cdf0e10cSrcweir         return false;
11633cdf0e10cSrcweir 
11634cdf0e10cSrcweir     bool bInsert = false;
11635cdf0e10cSrcweir     if( m_nCurrentStructElement > 0 && m_bEmitStructure )
11636cdf0e10cSrcweir     {
11637cdf0e10cSrcweir         if( eAttr == PDFWriter::Language )
11638cdf0e10cSrcweir         {
11639cdf0e10cSrcweir             m_aStructure[ m_nCurrentStructElement ].m_aLocale = MsLangId::convertLanguageToLocale( (LanguageType)nValue );
11640cdf0e10cSrcweir             return true;
11641cdf0e10cSrcweir         }
11642cdf0e10cSrcweir 
11643cdf0e10cSrcweir         PDFWriter::StructElement eType = m_aStructure[ m_nCurrentStructElement ].m_eType;
11644cdf0e10cSrcweir         switch( eAttr )
11645cdf0e10cSrcweir         {
11646cdf0e10cSrcweir             case PDFWriter::SpaceBefore:
11647cdf0e10cSrcweir             case PDFWriter::SpaceAfter:
11648cdf0e10cSrcweir             case PDFWriter::StartIndent:
11649cdf0e10cSrcweir             case PDFWriter::EndIndent:
11650cdf0e10cSrcweir                 // just for BLSE
11651cdf0e10cSrcweir                 if( eType == PDFWriter::Paragraph	||
11652cdf0e10cSrcweir                     eType == PDFWriter::Heading		||
11653cdf0e10cSrcweir                     eType == PDFWriter::H1			||
11654cdf0e10cSrcweir                     eType == PDFWriter::H2			||
11655cdf0e10cSrcweir                     eType == PDFWriter::H3			||
11656cdf0e10cSrcweir                     eType == PDFWriter::H4			||
11657cdf0e10cSrcweir                     eType == PDFWriter::H5			||
11658cdf0e10cSrcweir                     eType == PDFWriter::H6			||
11659cdf0e10cSrcweir                     eType == PDFWriter::List		||
11660cdf0e10cSrcweir                     eType == PDFWriter::ListItem	||
11661cdf0e10cSrcweir                     eType == PDFWriter::LILabel		||
11662cdf0e10cSrcweir                     eType == PDFWriter::LIBody		||
11663cdf0e10cSrcweir                     eType == PDFWriter::Table		||
11664cdf0e10cSrcweir                     eType == PDFWriter::TableRow	||
11665cdf0e10cSrcweir                     eType == PDFWriter::TableHeader	||
11666cdf0e10cSrcweir                     eType == PDFWriter::TableData )
11667cdf0e10cSrcweir                 {
11668cdf0e10cSrcweir                     bInsert = true;
11669cdf0e10cSrcweir                 }
11670cdf0e10cSrcweir                 break;
11671cdf0e10cSrcweir             case PDFWriter::TextIndent:
11672cdf0e10cSrcweir                 // paragraph like BLSE and additional elements
11673cdf0e10cSrcweir                 if( eType == PDFWriter::Paragraph	||
11674cdf0e10cSrcweir                     eType == PDFWriter::Heading		||
11675cdf0e10cSrcweir                     eType == PDFWriter::H1			||
11676cdf0e10cSrcweir                     eType == PDFWriter::H2			||
11677cdf0e10cSrcweir                     eType == PDFWriter::H3			||
11678cdf0e10cSrcweir                     eType == PDFWriter::H4			||
11679cdf0e10cSrcweir                     eType == PDFWriter::H5			||
11680cdf0e10cSrcweir                     eType == PDFWriter::H6			||
11681cdf0e10cSrcweir                     eType == PDFWriter::LILabel		||
11682cdf0e10cSrcweir                     eType == PDFWriter::LIBody		||
11683cdf0e10cSrcweir                     eType == PDFWriter::TableHeader	||
11684cdf0e10cSrcweir                     eType == PDFWriter::TableData )
11685cdf0e10cSrcweir                 {
11686cdf0e10cSrcweir                     bInsert = true;
11687cdf0e10cSrcweir                 }
11688cdf0e10cSrcweir                 break;
11689cdf0e10cSrcweir             case PDFWriter::Width:
11690cdf0e10cSrcweir             case PDFWriter::Height:
11691cdf0e10cSrcweir                 if( eType == PDFWriter::Figure		||
11692cdf0e10cSrcweir                     eType == PDFWriter::Formula		||
11693cdf0e10cSrcweir                     eType == PDFWriter::Form		||
11694cdf0e10cSrcweir                     eType == PDFWriter::Table		||
11695cdf0e10cSrcweir                     eType == PDFWriter::TableHeader	||
11696cdf0e10cSrcweir                     eType == PDFWriter::TableData )
11697cdf0e10cSrcweir                 {
11698cdf0e10cSrcweir                     bInsert = true;
11699cdf0e10cSrcweir                 }
11700cdf0e10cSrcweir                 break;
11701cdf0e10cSrcweir             case PDFWriter::LineHeight:
11702cdf0e10cSrcweir             case PDFWriter::BaselineShift:
11703cdf0e10cSrcweir                 // only for ILSE and BLSE
11704cdf0e10cSrcweir                 if( eType == PDFWriter::Paragraph	||
11705cdf0e10cSrcweir                     eType == PDFWriter::Heading		||
11706cdf0e10cSrcweir                     eType == PDFWriter::H1			||
11707cdf0e10cSrcweir                     eType == PDFWriter::H2			||
11708cdf0e10cSrcweir                     eType == PDFWriter::H3			||
11709cdf0e10cSrcweir                     eType == PDFWriter::H4			||
11710cdf0e10cSrcweir                     eType == PDFWriter::H5			||
11711cdf0e10cSrcweir                     eType == PDFWriter::H6			||
11712cdf0e10cSrcweir                     eType == PDFWriter::List		||
11713cdf0e10cSrcweir                     eType == PDFWriter::ListItem	||
11714cdf0e10cSrcweir                     eType == PDFWriter::LILabel		||
11715cdf0e10cSrcweir                     eType == PDFWriter::LIBody		||
11716cdf0e10cSrcweir                     eType == PDFWriter::Table		||
11717cdf0e10cSrcweir                     eType == PDFWriter::TableRow	||
11718cdf0e10cSrcweir                     eType == PDFWriter::TableHeader	||
11719cdf0e10cSrcweir                     eType == PDFWriter::TableData	||
11720cdf0e10cSrcweir                     eType == PDFWriter::Span		||
11721cdf0e10cSrcweir                     eType == PDFWriter::Quote		||
11722cdf0e10cSrcweir                     eType == PDFWriter::Note		||
11723cdf0e10cSrcweir                     eType == PDFWriter::Reference	||
11724cdf0e10cSrcweir                     eType == PDFWriter::BibEntry	||
11725cdf0e10cSrcweir                     eType == PDFWriter::Code		||
11726cdf0e10cSrcweir                     eType == PDFWriter::Link )
11727cdf0e10cSrcweir                 {
11728cdf0e10cSrcweir                         bInsert = true;
11729cdf0e10cSrcweir                 }
11730cdf0e10cSrcweir                 break;
11731cdf0e10cSrcweir             case PDFWriter::RowSpan:
11732cdf0e10cSrcweir             case PDFWriter::ColSpan:
11733cdf0e10cSrcweir                 // only for table cells
11734cdf0e10cSrcweir                 if( eType == PDFWriter::TableHeader	||
11735cdf0e10cSrcweir                     eType == PDFWriter::TableData )
11736cdf0e10cSrcweir                 {
11737cdf0e10cSrcweir                     bInsert = true;
11738cdf0e10cSrcweir                 }
11739cdf0e10cSrcweir                 break;
11740cdf0e10cSrcweir             case PDFWriter::LinkAnnotation:
11741cdf0e10cSrcweir                 if( eType == PDFWriter::Link )
11742cdf0e10cSrcweir                     bInsert = true;
11743cdf0e10cSrcweir                 break;
11744cdf0e10cSrcweir             default: break;
11745cdf0e10cSrcweir         }
11746cdf0e10cSrcweir     }
11747cdf0e10cSrcweir 
11748cdf0e10cSrcweir     if( bInsert )
11749cdf0e10cSrcweir         m_aStructure[ m_nCurrentStructElement ].m_aAttributes[ eAttr ] = PDFStructureAttribute( nValue );
11750cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
11751cdf0e10cSrcweir     else if( m_nCurrentStructElement > 0 && m_bEmitStructure )
11752cdf0e10cSrcweir         fprintf( stderr, "rejecting setStructureAttributeNumerical( %s, %d ) on %s (%s) element\n",
11753cdf0e10cSrcweir                  getAttributeTag( eAttr ),
11754cdf0e10cSrcweir                  (int)nValue,
11755cdf0e10cSrcweir                  getStructureTag( m_aStructure[ m_nCurrentStructElement ].m_eType ),
11756cdf0e10cSrcweir                  m_aStructure[ m_nCurrentStructElement ].m_aAlias.getStr() );
11757cdf0e10cSrcweir #endif
11758cdf0e10cSrcweir 
11759cdf0e10cSrcweir     return bInsert;
11760cdf0e10cSrcweir }
11761cdf0e10cSrcweir 
11762cdf0e10cSrcweir void PDFWriterImpl::setStructureBoundingBox( const Rectangle& rRect )
11763cdf0e10cSrcweir {
11764cdf0e10cSrcweir     sal_Int32 nPageNr = m_nCurrentPage;
11765cdf0e10cSrcweir     if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() || !m_aContext.Tagged )
11766cdf0e10cSrcweir         return;
11767cdf0e10cSrcweir 
11768cdf0e10cSrcweir 
11769cdf0e10cSrcweir     if( m_nCurrentStructElement > 0 && m_bEmitStructure )
11770cdf0e10cSrcweir     {
11771cdf0e10cSrcweir         PDFWriter::StructElement eType = m_aStructure[ m_nCurrentStructElement ].m_eType;
11772cdf0e10cSrcweir         if( eType == PDFWriter::Figure		||
11773cdf0e10cSrcweir             eType == PDFWriter::Formula		||
11774cdf0e10cSrcweir             eType == PDFWriter::Form		||
11775cdf0e10cSrcweir             eType == PDFWriter::Table )
11776cdf0e10cSrcweir         {
11777cdf0e10cSrcweir             m_aStructure[ m_nCurrentStructElement ].m_aBBox = rRect;
11778cdf0e10cSrcweir             // convert to default user space now, since the mapmode may change
11779cdf0e10cSrcweir             m_aPages[nPageNr].convertRect( m_aStructure[ m_nCurrentStructElement ].m_aBBox );
11780cdf0e10cSrcweir         }
11781cdf0e10cSrcweir     }
11782cdf0e10cSrcweir }
11783cdf0e10cSrcweir 
11784cdf0e10cSrcweir void PDFWriterImpl::setActualText( const String& rText )
11785cdf0e10cSrcweir {
11786cdf0e10cSrcweir     if( m_aContext.Tagged && m_nCurrentStructElement > 0 && m_bEmitStructure )
11787cdf0e10cSrcweir     {
11788cdf0e10cSrcweir         m_aStructure[ m_nCurrentStructElement ].m_aActualText = rText;
11789cdf0e10cSrcweir     }
11790cdf0e10cSrcweir }
11791cdf0e10cSrcweir 
11792cdf0e10cSrcweir void PDFWriterImpl::setAlternateText( const String& rText )
11793cdf0e10cSrcweir {
11794cdf0e10cSrcweir     if( m_aContext.Tagged && m_nCurrentStructElement > 0 && m_bEmitStructure )
11795cdf0e10cSrcweir     {
11796cdf0e10cSrcweir         m_aStructure[ m_nCurrentStructElement ].m_aAltText = rText;
11797cdf0e10cSrcweir     }
11798cdf0e10cSrcweir }
11799cdf0e10cSrcweir 
11800cdf0e10cSrcweir void PDFWriterImpl::setAutoAdvanceTime( sal_uInt32 nSeconds, sal_Int32 nPageNr )
11801cdf0e10cSrcweir {
11802cdf0e10cSrcweir     if( nPageNr < 0 )
11803cdf0e10cSrcweir         nPageNr = m_nCurrentPage;
11804cdf0e10cSrcweir 
11805cdf0e10cSrcweir     if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() )
11806cdf0e10cSrcweir         return;
11807cdf0e10cSrcweir 
11808cdf0e10cSrcweir     m_aPages[ nPageNr ].m_nDuration = nSeconds;
11809cdf0e10cSrcweir }
11810cdf0e10cSrcweir 
11811cdf0e10cSrcweir void PDFWriterImpl::setPageTransition( PDFWriter::PageTransition eType, sal_uInt32 nMilliSec, sal_Int32 nPageNr )
11812cdf0e10cSrcweir {
11813cdf0e10cSrcweir     if( nPageNr < 0 )
11814cdf0e10cSrcweir         nPageNr = m_nCurrentPage;
11815cdf0e10cSrcweir 
11816cdf0e10cSrcweir     if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() )
11817cdf0e10cSrcweir         return;
11818cdf0e10cSrcweir 
11819cdf0e10cSrcweir     m_aPages[ nPageNr ].m_eTransition	= eType;
11820cdf0e10cSrcweir     m_aPages[ nPageNr ].m_nTransTime	= nMilliSec;
11821cdf0e10cSrcweir }
11822cdf0e10cSrcweir 
11823cdf0e10cSrcweir void PDFWriterImpl::ensureUniqueRadioOnValues()
11824cdf0e10cSrcweir {
11825cdf0e10cSrcweir     // loop over radio groups
11826cdf0e10cSrcweir     for( std::map<sal_Int32,sal_Int32>::const_iterator group = m_aRadioGroupWidgets.begin();
11827cdf0e10cSrcweir          group != m_aRadioGroupWidgets.end(); ++group )
11828cdf0e10cSrcweir     {
11829cdf0e10cSrcweir         PDFWidget& rGroupWidget = m_aWidgets[ group->second ];
11830cdf0e10cSrcweir         // check whether all kids have a unique OnValue
11831cdf0e10cSrcweir         std::hash_map< OUString, sal_Int32, OUStringHash > aOnValues;
11832cdf0e10cSrcweir         int nChildren = rGroupWidget.m_aKidsIndex.size();
11833cdf0e10cSrcweir         bool bIsUnique = true;
11834cdf0e10cSrcweir         for( int nKid = 0; nKid < nChildren && bIsUnique; nKid++ )
11835cdf0e10cSrcweir         {
11836cdf0e10cSrcweir             int nKidIndex = rGroupWidget.m_aKidsIndex[nKid];
11837cdf0e10cSrcweir             const OUString& rVal = m_aWidgets[nKidIndex].m_aOnValue;
11838cdf0e10cSrcweir             #if OSL_DEBUG_LEVEL > 1
11839cdf0e10cSrcweir             fprintf( stderr, "OnValue: %s\n", OUStringToOString( rVal, RTL_TEXTENCODING_UTF8 ).getStr() );
11840cdf0e10cSrcweir             #endif
11841cdf0e10cSrcweir             if( aOnValues.find( rVal ) == aOnValues.end() )
11842cdf0e10cSrcweir             {
11843cdf0e10cSrcweir                 aOnValues[ rVal ] = 1;
11844cdf0e10cSrcweir             }
11845cdf0e10cSrcweir             else
11846cdf0e10cSrcweir             {
11847cdf0e10cSrcweir                 bIsUnique = false;
11848cdf0e10cSrcweir             }
11849cdf0e10cSrcweir         }
11850cdf0e10cSrcweir         if( ! bIsUnique )
11851cdf0e10cSrcweir         {
11852cdf0e10cSrcweir             #if OSL_DEBUG_LEVEL > 1
11853cdf0e10cSrcweir             fprintf( stderr, "enforcing unique OnValues\n" );
11854cdf0e10cSrcweir             #endif
11855cdf0e10cSrcweir             // make unique by using ascending OnValues
11856cdf0e10cSrcweir             for( int nKid = 0; nKid < nChildren; nKid++ )
11857cdf0e10cSrcweir             {
11858cdf0e10cSrcweir                 int nKidIndex = rGroupWidget.m_aKidsIndex[nKid];
11859cdf0e10cSrcweir                 PDFWidget& rKid = m_aWidgets[nKidIndex];
11860cdf0e10cSrcweir                 rKid.m_aOnValue = OUString::valueOf( sal_Int32(nKid+1) );
11861cdf0e10cSrcweir                 if( ! rKid.m_aValue.equalsAscii( "Off" ) )
11862cdf0e10cSrcweir                     rKid.m_aValue = rKid.m_aOnValue;
11863cdf0e10cSrcweir             }
11864cdf0e10cSrcweir         }
11865cdf0e10cSrcweir         // finally move the "Yes" appearance to the OnValue appearance
11866cdf0e10cSrcweir         for( int nKid = 0; nKid < nChildren; nKid++ )
11867cdf0e10cSrcweir         {
11868cdf0e10cSrcweir             int nKidIndex = rGroupWidget.m_aKidsIndex[nKid];
11869cdf0e10cSrcweir             PDFWidget& rKid = m_aWidgets[nKidIndex];
11870cdf0e10cSrcweir             PDFAppearanceMap::iterator app_it = rKid.m_aAppearances.find( "N" );
11871cdf0e10cSrcweir             if( app_it != rKid.m_aAppearances.end() )
11872cdf0e10cSrcweir             {
11873cdf0e10cSrcweir                 PDFAppearanceStreams::iterator stream_it = app_it->second.find( "Yes" );
11874cdf0e10cSrcweir                 if( stream_it != app_it->second.end() )
11875cdf0e10cSrcweir                 {
11876cdf0e10cSrcweir                     SvMemoryStream* pStream = stream_it->second;
11877cdf0e10cSrcweir                     app_it->second.erase( stream_it );
11878cdf0e10cSrcweir                     OStringBuffer aBuf( rKid.m_aOnValue.getLength()*2 );
11879cdf0e10cSrcweir                     appendName( rKid.m_aOnValue, aBuf );
11880cdf0e10cSrcweir                     (app_it->second)[ aBuf.makeStringAndClear() ] = pStream;
11881cdf0e10cSrcweir                 }
11882cdf0e10cSrcweir                 #if OSL_DEBUG_LEVEL > 1
11883cdf0e10cSrcweir                 else
11884cdf0e10cSrcweir                     fprintf( stderr, "error: RadioButton without \"Yes\" stream\n" );
11885cdf0e10cSrcweir                 #endif
11886cdf0e10cSrcweir             }
11887cdf0e10cSrcweir             // update selected radio button
11888cdf0e10cSrcweir             if( ! rKid.m_aValue.equalsAscii( "Off" ) )
11889cdf0e10cSrcweir             {
11890cdf0e10cSrcweir                 rGroupWidget.m_aValue = rKid.m_aValue;
11891cdf0e10cSrcweir             }
11892cdf0e10cSrcweir         }
11893cdf0e10cSrcweir     }
11894cdf0e10cSrcweir }
11895cdf0e10cSrcweir 
11896cdf0e10cSrcweir sal_Int32 PDFWriterImpl::findRadioGroupWidget( const PDFWriter::RadioButtonWidget& rBtn )
11897cdf0e10cSrcweir {
11898cdf0e10cSrcweir     sal_Int32 nRadioGroupWidget = -1;
11899cdf0e10cSrcweir 
11900cdf0e10cSrcweir     std::map< sal_Int32, sal_Int32 >::const_iterator it = m_aRadioGroupWidgets.find( rBtn.RadioGroup );
11901cdf0e10cSrcweir 
11902cdf0e10cSrcweir     if( it == m_aRadioGroupWidgets.end() )
11903cdf0e10cSrcweir     {
11904cdf0e10cSrcweir         m_aRadioGroupWidgets[ rBtn.RadioGroup ] = nRadioGroupWidget =
11905cdf0e10cSrcweir             sal_Int32(m_aWidgets.size());
11906cdf0e10cSrcweir 
11907cdf0e10cSrcweir         // new group, insert the radiobutton
11908cdf0e10cSrcweir         m_aWidgets.push_back( PDFWidget() );
11909cdf0e10cSrcweir         m_aWidgets.back().m_nObject		= createObject();
11910cdf0e10cSrcweir         m_aWidgets.back().m_nPage		= m_nCurrentPage;
11911cdf0e10cSrcweir         m_aWidgets.back().m_eType		= PDFWriter::RadioButton;
11912cdf0e10cSrcweir         m_aWidgets.back().m_nRadioGroup = rBtn.RadioGroup;
11913cdf0e10cSrcweir         m_aWidgets.back().m_nFlags |= 0x0000C000;   // NoToggleToOff and Radio bits
11914cdf0e10cSrcweir 
11915cdf0e10cSrcweir         createWidgetFieldName( sal_Int32(m_aWidgets.size()-1), rBtn );
11916cdf0e10cSrcweir     }
11917cdf0e10cSrcweir     else
11918cdf0e10cSrcweir         nRadioGroupWidget = it->second;
11919cdf0e10cSrcweir 
11920cdf0e10cSrcweir     return nRadioGroupWidget;
11921cdf0e10cSrcweir }
11922cdf0e10cSrcweir 
11923cdf0e10cSrcweir sal_Int32 PDFWriterImpl::createControl( const PDFWriter::AnyWidget& rControl, sal_Int32 nPageNr )
11924cdf0e10cSrcweir {
11925cdf0e10cSrcweir     if( nPageNr < 0 )
11926cdf0e10cSrcweir         nPageNr = m_nCurrentPage;
11927cdf0e10cSrcweir 
11928cdf0e10cSrcweir     if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() )
11929cdf0e10cSrcweir         return -1;
11930cdf0e10cSrcweir 
11931cdf0e10cSrcweir     sal_Int32 nNewWidget = m_aWidgets.size();
11932cdf0e10cSrcweir     m_aWidgets.push_back( PDFWidget() );
11933cdf0e10cSrcweir 
11934cdf0e10cSrcweir     m_aWidgets.back().m_nObject			= createObject();
11935cdf0e10cSrcweir     m_aWidgets.back().m_aRect				= rControl.Location;
11936cdf0e10cSrcweir     m_aWidgets.back().m_nPage				= nPageNr;
11937cdf0e10cSrcweir     m_aWidgets.back().m_eType				= rControl.getType();
11938cdf0e10cSrcweir 
11939cdf0e10cSrcweir     sal_Int32 nRadioGroupWidget = -1;
11940cdf0e10cSrcweir     // for unknown reasons the radio buttons of a radio group must not have a
11941cdf0e10cSrcweir     // field name, else the buttons are in fact check boxes -
11942cdf0e10cSrcweir     // that is multiple buttons of the radio group can be selected
11943cdf0e10cSrcweir     if( rControl.getType() == PDFWriter::RadioButton )
11944cdf0e10cSrcweir         nRadioGroupWidget = findRadioGroupWidget( static_cast<const PDFWriter::RadioButtonWidget&>(rControl) );
11945cdf0e10cSrcweir     else
11946cdf0e10cSrcweir     {
11947cdf0e10cSrcweir         createWidgetFieldName( nNewWidget, rControl );
11948cdf0e10cSrcweir     }
11949cdf0e10cSrcweir 
11950cdf0e10cSrcweir     // caution: m_aWidgets must not be changed after here or rNewWidget may be invalid
11951cdf0e10cSrcweir     PDFWidget& rNewWidget			= m_aWidgets[nNewWidget];
11952cdf0e10cSrcweir     rNewWidget.m_aDescription		= rControl.Description;
11953cdf0e10cSrcweir     rNewWidget.m_aText				= rControl.Text;
11954cdf0e10cSrcweir     rNewWidget.m_nTextStyle			= rControl.TextStyle &
11955cdf0e10cSrcweir         (  TEXT_DRAW_LEFT | TEXT_DRAW_CENTER | TEXT_DRAW_RIGHT | TEXT_DRAW_TOP |
11956cdf0e10cSrcweir            TEXT_DRAW_VCENTER | TEXT_DRAW_BOTTOM |
11957cdf0e10cSrcweir            TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK  );
11958cdf0e10cSrcweir     rNewWidget.m_nTabOrder          = rControl.TabOrder;
11959cdf0e10cSrcweir 
11960cdf0e10cSrcweir     // various properties are set via the flags (/Ff) property of the field dict
11961cdf0e10cSrcweir     if( rControl.ReadOnly )
11962cdf0e10cSrcweir         rNewWidget.m_nFlags |= 1;
11963cdf0e10cSrcweir     if( rControl.getType() == PDFWriter::PushButton )
11964cdf0e10cSrcweir     {
11965cdf0e10cSrcweir         const PDFWriter::PushButtonWidget& rBtn = static_cast<const PDFWriter::PushButtonWidget&>(rControl);
11966cdf0e10cSrcweir         if( rNewWidget.m_nTextStyle == 0 )
11967cdf0e10cSrcweir             rNewWidget.m_nTextStyle =
11968cdf0e10cSrcweir                 TEXT_DRAW_CENTER | TEXT_DRAW_VCENTER |
11969cdf0e10cSrcweir                 TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK;
11970cdf0e10cSrcweir 
11971cdf0e10cSrcweir         rNewWidget.m_nFlags |= 0x00010000;
11972cdf0e10cSrcweir         if( rBtn.URL.getLength() )
11973cdf0e10cSrcweir             rNewWidget.m_aListEntries.push_back( rBtn.URL );
11974cdf0e10cSrcweir         rNewWidget.m_bSubmit    = rBtn.Submit;
11975cdf0e10cSrcweir         rNewWidget.m_bSubmitGet = rBtn.SubmitGet;
11976cdf0e10cSrcweir         rNewWidget.m_nDest      = rBtn.Dest;
11977cdf0e10cSrcweir         createDefaultPushButtonAppearance( rNewWidget, rBtn );
11978cdf0e10cSrcweir     }
11979cdf0e10cSrcweir     else if( rControl.getType() == PDFWriter::RadioButton )
11980cdf0e10cSrcweir     {
11981cdf0e10cSrcweir         const PDFWriter::RadioButtonWidget& rBtn = static_cast<const PDFWriter::RadioButtonWidget&>(rControl);
11982cdf0e10cSrcweir         if( rNewWidget.m_nTextStyle == 0 )
11983cdf0e10cSrcweir             rNewWidget.m_nTextStyle =
11984cdf0e10cSrcweir                 TEXT_DRAW_VCENTER | TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK;
11985cdf0e10cSrcweir         /*  PDF sees a RadioButton group as one radio button with
11986cdf0e10cSrcweir          *  children which are in turn check boxes
11987cdf0e10cSrcweir          *
11988cdf0e10cSrcweir          *  so we need to create a radio button on demand for a new group
11989cdf0e10cSrcweir          *  and insert a checkbox for each RadioButtonWidget as its child
11990cdf0e10cSrcweir          */
11991cdf0e10cSrcweir         rNewWidget.m_eType			= PDFWriter::CheckBox;
11992cdf0e10cSrcweir         rNewWidget.m_nRadioGroup	= rBtn.RadioGroup;
11993cdf0e10cSrcweir 
11994cdf0e10cSrcweir         DBG_ASSERT( nRadioGroupWidget >= 0 && nRadioGroupWidget < (sal_Int32)m_aWidgets.size(), "no radio group parent" );
11995cdf0e10cSrcweir 
11996cdf0e10cSrcweir         PDFWidget& rRadioButton = m_aWidgets[nRadioGroupWidget];
11997cdf0e10cSrcweir         rRadioButton.m_aKids.push_back( rNewWidget.m_nObject );
11998cdf0e10cSrcweir         rRadioButton.m_aKidsIndex.push_back( nNewWidget );
11999cdf0e10cSrcweir         rNewWidget.m_nParent = rRadioButton.m_nObject;
12000cdf0e10cSrcweir 
12001cdf0e10cSrcweir         rNewWidget.m_aValue     = OUString( RTL_CONSTASCII_USTRINGPARAM( "Off" ) );
12002cdf0e10cSrcweir         rNewWidget.m_aOnValue   = rBtn.OnValue;
12003cdf0e10cSrcweir         if( ! rRadioButton.m_aValue.getLength() && rBtn.Selected )
12004cdf0e10cSrcweir         {
12005cdf0e10cSrcweir             rNewWidget.m_aValue		= rNewWidget.m_aOnValue;
12006cdf0e10cSrcweir             rRadioButton.m_aValue	= rNewWidget.m_aOnValue;
12007cdf0e10cSrcweir         }
12008cdf0e10cSrcweir         createDefaultRadioButtonAppearance( rNewWidget, rBtn );
12009cdf0e10cSrcweir 
12010cdf0e10cSrcweir         // union rect of radio group
12011cdf0e10cSrcweir         Rectangle aRect = rNewWidget.m_aRect;
12012cdf0e10cSrcweir         m_aPages[ nPageNr ].convertRect( aRect );
12013cdf0e10cSrcweir         rRadioButton.m_aRect.Union( aRect );
12014cdf0e10cSrcweir     }
12015cdf0e10cSrcweir     else if( rControl.getType() == PDFWriter::CheckBox )
12016cdf0e10cSrcweir     {
12017cdf0e10cSrcweir         const PDFWriter::CheckBoxWidget& rBox = static_cast<const PDFWriter::CheckBoxWidget&>(rControl);
12018cdf0e10cSrcweir         if( rNewWidget.m_nTextStyle == 0 )
12019cdf0e10cSrcweir             rNewWidget.m_nTextStyle =
12020cdf0e10cSrcweir                 TEXT_DRAW_VCENTER | TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK;
12021cdf0e10cSrcweir 
12022cdf0e10cSrcweir         rNewWidget.m_aValue = OUString::createFromAscii( rBox.Checked ? "Yes" : "Off" );
12023cdf0e10cSrcweir         // create default appearance before m_aRect gets transformed
12024cdf0e10cSrcweir         createDefaultCheckBoxAppearance( rNewWidget, rBox );
12025cdf0e10cSrcweir     }
12026cdf0e10cSrcweir     else if( rControl.getType() == PDFWriter::ListBox )
12027cdf0e10cSrcweir     {
12028cdf0e10cSrcweir         if( rNewWidget.m_nTextStyle == 0 )
12029cdf0e10cSrcweir             rNewWidget.m_nTextStyle = TEXT_DRAW_VCENTER;
12030cdf0e10cSrcweir 
12031cdf0e10cSrcweir         const PDFWriter::ListBoxWidget& rLstBox = static_cast<const PDFWriter::ListBoxWidget&>(rControl);
12032cdf0e10cSrcweir         rNewWidget.m_aListEntries	  = rLstBox.Entries;
12033cdf0e10cSrcweir         rNewWidget.m_aSelectedEntries = rLstBox.SelectedEntries;
12034cdf0e10cSrcweir         rNewWidget.m_aValue			  = rLstBox.Text;
12035cdf0e10cSrcweir         if( rLstBox.DropDown )
12036cdf0e10cSrcweir             rNewWidget.m_nFlags |= 0x00020000;
12037cdf0e10cSrcweir         if( rLstBox.Sort )
12038cdf0e10cSrcweir             rNewWidget.m_nFlags |= 0x00080000;
12039cdf0e10cSrcweir         if( rLstBox.MultiSelect && !rLstBox.DropDown && (int)m_aContext.Version > (int)PDFWriter::PDF_1_3 )
12040cdf0e10cSrcweir             rNewWidget.m_nFlags |= 0x00200000;
12041cdf0e10cSrcweir 
12042cdf0e10cSrcweir         createDefaultListBoxAppearance( rNewWidget, rLstBox );
12043cdf0e10cSrcweir     }
12044cdf0e10cSrcweir     else if( rControl.getType() == PDFWriter::ComboBox )
12045cdf0e10cSrcweir     {
12046cdf0e10cSrcweir         if( rNewWidget.m_nTextStyle == 0 )
12047cdf0e10cSrcweir             rNewWidget.m_nTextStyle = TEXT_DRAW_VCENTER;
12048cdf0e10cSrcweir 
12049cdf0e10cSrcweir         const PDFWriter::ComboBoxWidget& rBox = static_cast<const PDFWriter::ComboBoxWidget&>(rControl);
12050cdf0e10cSrcweir         rNewWidget.m_aValue			= rBox.Text;
12051cdf0e10cSrcweir         rNewWidget.m_aListEntries	= rBox.Entries;
12052cdf0e10cSrcweir         rNewWidget.m_nFlags |= 0x00060000; // combo and edit flag
12053cdf0e10cSrcweir         if( rBox.Sort )
12054cdf0e10cSrcweir             rNewWidget.m_nFlags |= 0x00080000;
12055cdf0e10cSrcweir 
12056cdf0e10cSrcweir         PDFWriter::ListBoxWidget aLBox;
12057cdf0e10cSrcweir         aLBox.Name				= rBox.Name;
12058cdf0e10cSrcweir         aLBox.Description		= rBox.Description;
12059cdf0e10cSrcweir         aLBox.Text				= rBox.Text;
12060cdf0e10cSrcweir         aLBox.TextStyle			= rBox.TextStyle;
12061cdf0e10cSrcweir         aLBox.ReadOnly			= rBox.ReadOnly;
12062cdf0e10cSrcweir         aLBox.Border			= rBox.Border;
12063cdf0e10cSrcweir         aLBox.BorderColor		= rBox.BorderColor;
12064cdf0e10cSrcweir         aLBox.Background		= rBox.Background;
12065cdf0e10cSrcweir         aLBox.BackgroundColor	= rBox.BackgroundColor;
12066cdf0e10cSrcweir         aLBox.TextFont			= rBox.TextFont;
12067cdf0e10cSrcweir         aLBox.TextColor			= rBox.TextColor;
12068cdf0e10cSrcweir         aLBox.DropDown			= true;
12069cdf0e10cSrcweir         aLBox.Sort				= rBox.Sort;
12070cdf0e10cSrcweir         aLBox.MultiSelect		= false;
12071cdf0e10cSrcweir         aLBox.Entries			= rBox.Entries;
12072cdf0e10cSrcweir 
12073cdf0e10cSrcweir         createDefaultListBoxAppearance( rNewWidget, aLBox );
12074cdf0e10cSrcweir     }
12075cdf0e10cSrcweir     else if( rControl.getType() == PDFWriter::Edit )
12076cdf0e10cSrcweir     {
12077cdf0e10cSrcweir         if( rNewWidget.m_nTextStyle == 0 )
12078cdf0e10cSrcweir             rNewWidget.m_nTextStyle = TEXT_DRAW_LEFT | TEXT_DRAW_VCENTER;
12079cdf0e10cSrcweir 
12080cdf0e10cSrcweir         const PDFWriter::EditWidget& rEdit = static_cast<const  PDFWriter::EditWidget&>(rControl);
12081cdf0e10cSrcweir         if( rEdit.MultiLine )
12082cdf0e10cSrcweir         {
12083cdf0e10cSrcweir             rNewWidget.m_nFlags |= 0x00001000;
12084cdf0e10cSrcweir             rNewWidget.m_nTextStyle |= TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK;
12085cdf0e10cSrcweir         }
12086cdf0e10cSrcweir         if( rEdit.Password )
12087cdf0e10cSrcweir             rNewWidget.m_nFlags |= 0x00002000;
12088cdf0e10cSrcweir         if( rEdit.FileSelect && m_aContext.Version > PDFWriter::PDF_1_3 )
12089cdf0e10cSrcweir             rNewWidget.m_nFlags |= 0x00100000;
12090cdf0e10cSrcweir         rNewWidget.m_nMaxLen = rEdit.MaxLen;
12091cdf0e10cSrcweir         rNewWidget.m_aValue = rEdit.Text;
12092cdf0e10cSrcweir 
12093cdf0e10cSrcweir         createDefaultEditAppearance( rNewWidget, rEdit );
12094cdf0e10cSrcweir     }
12095cdf0e10cSrcweir 
12096cdf0e10cSrcweir     // convert to default user space now, since the mapmode may change
12097cdf0e10cSrcweir     // note: create default appearances before m_aRect gets transformed
12098cdf0e10cSrcweir     m_aPages[ nPageNr ].convertRect( rNewWidget.m_aRect );
12099cdf0e10cSrcweir 
12100cdf0e10cSrcweir     // insert widget to page's annotation list
12101cdf0e10cSrcweir     m_aPages[ nPageNr ].m_aAnnotations.push_back( rNewWidget.m_nObject );
12102cdf0e10cSrcweir 
12103cdf0e10cSrcweir     // mark page as having widgets
12104cdf0e10cSrcweir     m_aPages[ nPageNr ].m_bHasWidgets = true;
12105cdf0e10cSrcweir 
12106cdf0e10cSrcweir     return nNewWidget;
12107cdf0e10cSrcweir }
12108cdf0e10cSrcweir 
12109cdf0e10cSrcweir void PDFWriterImpl::beginControlAppearance( sal_Int32 nControl )
12110cdf0e10cSrcweir {
12111cdf0e10cSrcweir     if( nControl < 0 || nControl >= (sal_Int32)m_aWidgets.size() )
12112cdf0e10cSrcweir         return;
12113cdf0e10cSrcweir 
12114cdf0e10cSrcweir     PDFWidget& rWidget = m_aWidgets[ nControl ];
12115cdf0e10cSrcweir     m_nCurrentControl = nControl;
12116cdf0e10cSrcweir 
12117cdf0e10cSrcweir     SvMemoryStream* pControlStream = new SvMemoryStream( 1024, 1024 );
12118cdf0e10cSrcweir     // back conversion of control rect to current MapMode; necessary because
12119cdf0e10cSrcweir     // MapMode between createControl and beginControlAppearance
12120cdf0e10cSrcweir     // could have changed; therefore the widget rectangle is
12121cdf0e10cSrcweir     // already converted
12122cdf0e10cSrcweir     Rectangle aBack( Point( rWidget.m_aRect.Left(), pointToPixel(m_aPages[m_nCurrentPage].getHeight()) - rWidget.m_aRect.Top() - rWidget.m_aRect.GetHeight() ),
12123cdf0e10cSrcweir                      rWidget.m_aRect.GetSize() );
12124cdf0e10cSrcweir     aBack = lcl_convert( m_aMapMode,
12125cdf0e10cSrcweir                          m_aGraphicsStack.front().m_aMapMode,
12126cdf0e10cSrcweir                          getReferenceDevice(),
12127cdf0e10cSrcweir                          aBack );
12128cdf0e10cSrcweir     beginRedirect( pControlStream, aBack );
12129cdf0e10cSrcweir     writeBuffer( "/Tx BMC\n", 8 );
12130cdf0e10cSrcweir }
12131cdf0e10cSrcweir 
12132cdf0e10cSrcweir bool PDFWriterImpl::endControlAppearance( PDFWriter::WidgetState eState )
12133cdf0e10cSrcweir {
12134cdf0e10cSrcweir     bool bRet = false;
12135cdf0e10cSrcweir     if( ! m_aOutputStreams.empty() )
12136cdf0e10cSrcweir         writeBuffer( "\nEMC\n", 5 );
12137cdf0e10cSrcweir     SvMemoryStream* pAppearance = static_cast<SvMemoryStream*>(endRedirect());
12138cdf0e10cSrcweir     if( pAppearance && m_nCurrentControl >= 0 && m_nCurrentControl < (sal_Int32)m_aWidgets.size() )
12139cdf0e10cSrcweir     {
12140cdf0e10cSrcweir         PDFWidget& rWidget = m_aWidgets[ m_nCurrentControl ];
12141cdf0e10cSrcweir         OString aState, aStyle;
12142cdf0e10cSrcweir         switch( rWidget.m_eType )
12143cdf0e10cSrcweir         {
12144cdf0e10cSrcweir             case PDFWriter::PushButton:
12145cdf0e10cSrcweir                 if( eState == PDFWriter::Up || eState == PDFWriter::Down )
12146cdf0e10cSrcweir                 {
12147cdf0e10cSrcweir                     aState = (eState == PDFWriter::Up) ? "N" : "D";
12148cdf0e10cSrcweir                     aStyle = "Standard";
12149cdf0e10cSrcweir                 }
12150cdf0e10cSrcweir                 break;
12151cdf0e10cSrcweir             case PDFWriter::CheckBox:
12152cdf0e10cSrcweir                 if( eState == PDFWriter::Up || eState == PDFWriter::Down )
12153cdf0e10cSrcweir                 {
12154cdf0e10cSrcweir                     aState = "N";
12155cdf0e10cSrcweir                     aStyle = (eState == PDFWriter::Up) ? "Off" : "Yes";
12156cdf0e10cSrcweir                     /* cf PDFReference 3rd ed. V1.4 p539:
12157cdf0e10cSrcweir                        recommended name for on state is "Yes",
12158cdf0e10cSrcweir                        recommended name for off state is "Off"
12159cdf0e10cSrcweir                      */
12160cdf0e10cSrcweir                 }
12161cdf0e10cSrcweir                 break;
12162cdf0e10cSrcweir             case PDFWriter::RadioButton:
12163cdf0e10cSrcweir                 if( eState == PDFWriter::Up || eState == PDFWriter::Down )
12164cdf0e10cSrcweir                 {
12165cdf0e10cSrcweir                     aState = "N";
12166cdf0e10cSrcweir                     if( eState == PDFWriter::Up )
12167cdf0e10cSrcweir                         aStyle = "Off";
12168cdf0e10cSrcweir                     else
12169cdf0e10cSrcweir                     {
12170cdf0e10cSrcweir                         OStringBuffer aBuf( rWidget.m_aOnValue.getLength()*2 );
12171cdf0e10cSrcweir                         appendName( rWidget.m_aOnValue, aBuf );
12172cdf0e10cSrcweir                         aStyle = aBuf.makeStringAndClear();
12173cdf0e10cSrcweir                     }
12174cdf0e10cSrcweir                 }
12175cdf0e10cSrcweir                 break;
12176cdf0e10cSrcweir             case PDFWriter::Edit:
12177cdf0e10cSrcweir                 aState = "N";
12178cdf0e10cSrcweir                 aStyle = "Standard";
12179cdf0e10cSrcweir                 break;
12180cdf0e10cSrcweir             case PDFWriter::ListBox:
12181cdf0e10cSrcweir             case PDFWriter::ComboBox:
12182cdf0e10cSrcweir             case PDFWriter::Hierarchy:
12183cdf0e10cSrcweir                 break;
12184cdf0e10cSrcweir         }
12185cdf0e10cSrcweir         if( aState.getLength() && aStyle.getLength() )
12186cdf0e10cSrcweir         {
12187cdf0e10cSrcweir             // delete eventual existing stream
12188cdf0e10cSrcweir             PDFAppearanceStreams::iterator it =
12189cdf0e10cSrcweir                 rWidget.m_aAppearances[ aState ].find( aStyle );
12190cdf0e10cSrcweir             if( it != rWidget.m_aAppearances[ aState ].end() )
12191cdf0e10cSrcweir                 delete it->second;
12192cdf0e10cSrcweir             rWidget.m_aAppearances[ aState ][ aStyle ] = pAppearance;
12193cdf0e10cSrcweir             bRet = true;
12194cdf0e10cSrcweir         }
12195cdf0e10cSrcweir     }
12196cdf0e10cSrcweir 
12197cdf0e10cSrcweir     if( ! bRet )
12198cdf0e10cSrcweir         delete pAppearance;
12199cdf0e10cSrcweir 
12200cdf0e10cSrcweir     m_nCurrentControl = -1;
12201cdf0e10cSrcweir 
12202cdf0e10cSrcweir     return bRet;
12203cdf0e10cSrcweir }
12204cdf0e10cSrcweir 
12205cdf0e10cSrcweir void PDFWriterImpl::addStream( const String& rMimeType, PDFOutputStream* pStream, bool bCompress )
12206cdf0e10cSrcweir {
12207cdf0e10cSrcweir     if( pStream )
12208cdf0e10cSrcweir     {
12209cdf0e10cSrcweir         m_aAdditionalStreams.push_back( PDFAddStream() );
12210cdf0e10cSrcweir         PDFAddStream& rStream = m_aAdditionalStreams.back();
12211cdf0e10cSrcweir         rStream.m_aMimeType = rMimeType.Len()
12212cdf0e10cSrcweir                               ? OUString( rMimeType )
12213cdf0e10cSrcweir                               : OUString( RTL_CONSTASCII_USTRINGPARAM( "application/octet-stream" ) );
12214cdf0e10cSrcweir         rStream.m_pStream = pStream;
12215cdf0e10cSrcweir         rStream.m_bCompress = bCompress;
12216cdf0e10cSrcweir     }
12217cdf0e10cSrcweir }
12218cdf0e10cSrcweir 
12219cdf0e10cSrcweir 
12220cdf0e10cSrcweir 
12221