xref: /trunk/main/vcl/source/gdi/pdfwriter_impl.cxx (revision a22fd41b3c7115abe997cce40bcadff026a78ca4)
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 
~PDFTestOutputStream()97cdf0e10cSrcweir PDFTestOutputStream::~PDFTestOutputStream()
98cdf0e10cSrcweir {
99cdf0e10cSrcweir }
100cdf0e10cSrcweir 
write(const com::sun::star::uno::Reference<com::sun::star::io::XOutputStream> & xStream)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
doTestCode()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 ) ),
188cc0d486eSmseidel                       String( RTL_CONSTASCII_USTRINGPARAM( "Here's where all things come to an end ... well at least the paragraph 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 
pixelToPoint(sal_Int32 px)501cdf0e10cSrcweir static inline double pixelToPoint( sal_Int32 px ) { return double(px)/fDivisor; }
pixelToPoint(double px)502cdf0e10cSrcweir static inline double pixelToPoint( double px ) { return px/fDivisor; }
pointToPixel(double pt)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 
appendHex(sal_Int8 nInt,OStringBuffer & rBuffer)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 
appendName(const OUString & rStr,OStringBuffer & rBuffer)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
522cc0d486eSmseidel // I guess that 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
531cc0d486eSmseidel          *  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 
appendName(const sal_Char * pStr,OStringBuffer & rBuffer)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
appendLiteralString(const sal_Char * pStr,sal_Int32 nLength,OStringBuffer & rBuffer)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  *
628cc0d486eSmseidel  * Further limitation: it is advisable to use standard ASCII characters for
629cc0d486eSmseidel  * AOO bookmarks.
630cdf0e10cSrcweir */
appendDestinationName(const rtl::OUString & rString,OStringBuffer & rBuffer)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 
appendUnicodeTextString(const rtl::OUString & rString,OStringBuffer & rBuffer)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 
createWidgetFieldName(sal_Int32 i_nWidgetIndex,const PDFWriter::AnyWidget & i_rControl)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 
appendFixedInt(sal_Int32 nValue,OStringBuffer & rBuffer,sal_Int32 nPrecision=nLog10Divisor)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
appendDouble(double fValue,OStringBuffer & rBuffer,sal_Int32 nPrecision=5)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 
appendColor(const Color & rColor,OStringBuffer & rBuffer,bool bConvertToGrey=false)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 
appendStrokingColor(const Color & rColor,OStringBuffer & rBuffer)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 
appendNonStrokingColor(const Color & rColor,OStringBuffer & rBuffer)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 
set(double * pn)952cdf0e10cSrcweir     void set( double *pn ) { for( int i = 0 ; i < 6; i++ ) f[i] = pn[i]; }
953cdf0e10cSrcweir public:
954cdf0e10cSrcweir     Matrix3();
~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 
Matrix3()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 
transform(const Point & rOrig) const980cdf0e10cSrcweir 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 
skew(double alpha,double beta)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 
scale(double sx,double sy)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 
rotate(double angle)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 
translate(double tx,double ty)1032cdf0e10cSrcweir void Matrix3::translate( double tx, double ty )
1033cdf0e10cSrcweir {
1034cdf0e10cSrcweir     f[4] += tx;
1035cdf0e10cSrcweir     f[5] += ty;
1036cdf0e10cSrcweir }
1037cdf0e10cSrcweir 
invert()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 
append(PDFWriterImpl::PDFPage & rPage,OStringBuffer & rBuffer,Point * pBack)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 
appendResourceMap(OStringBuffer & rBuf,const char * pPrefix,const PDFWriterImpl::ResourceMap & rList)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 
append(OStringBuffer & rBuf,sal_Int32 nFontDictObject)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 
PDFPage(PDFWriterImpl * pWriter,sal_Int32 nPageWidth,sal_Int32 nPageHeight,PDFWriter::Orientation eOrientation)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 
~PDFPage()1139cdf0e10cSrcweir PDFWriterImpl::PDFPage::~PDFPage()
1140cdf0e10cSrcweir {
1141cdf0e10cSrcweir }
1142cdf0e10cSrcweir 
beginStream()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 
endStream()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 
emit(sal_Int32 nParentObject)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 >
lcl_convert(const MapMode & _rSource,const MapMode & _rDest,OutputDevice * _pPixelConversion,const GEOMETRY & _rObject)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 
appendPoint(const Point & rPoint,OStringBuffer & rBuffer,bool bNeg,Point * pOutPoint) const1388cdf0e10cSrcweir 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 
appendPixelPoint(const basegfx::B2DPoint & rPoint,OStringBuffer & rBuffer) const1419cdf0e10cSrcweir 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 
appendRect(const Rectangle & rRect,OStringBuffer & rBuffer) const1432cdf0e10cSrcweir 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 
convertRect(Rectangle & rRect) const1442cdf0e10cSrcweir 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 
appendPolygon(const Polygon & rPoly,OStringBuffer & rBuffer,bool bClose) const1459cdf0e10cSrcweir 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 
appendPolygon(const basegfx::B2DPolygon & rPoly,OStringBuffer & rBuffer,bool bClose) const1504cdf0e10cSrcweir 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 
appendPolyPolygon(const PolyPolygon & rPolyPoly,OStringBuffer & rBuffer,bool bClose) const1580cdf0e10cSrcweir 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 
appendPolyPolygon(const basegfx::B2DPolyPolygon & rPolyPoly,OStringBuffer & rBuffer,bool bClose) const1587cdf0e10cSrcweir 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 
appendMappedLength(sal_Int32 nLength,OStringBuffer & rBuffer,bool bVertical,sal_Int32 * pOutLength) const1594cdf0e10cSrcweir 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 
appendMappedLength(double fLength,OStringBuffer & rBuffer,bool bVertical,sal_Int32 * pOutLength,sal_Int32 nPrecision) const1613cdf0e10cSrcweir 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 
appendLineInfo(const LineInfo & rInfo,OStringBuffer & rBuffer) const1625cdf0e10cSrcweir 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 
appendWaveLine(sal_Int32 nWidth,sal_Int32 nY,sal_Int32 nDelta,OStringBuffer & rBuffer) const1694cdf0e10cSrcweir 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 
PDFWriterImpl(const PDFWriter::PDFWriterContext & rContext,const com::sun::star::uno::Reference<com::sun::star::beans::XMaterialHolder> & xEnc,PDFWriter & i_rOuterFace)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 
~PDFWriterImpl()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 
setupDocInfo()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 
computeDocumentIdentifier(std::vector<sal_uInt8> & o_rIdentifier,const vcl::PDFWriter::PDFDocInfo & i_rDocInfo,rtl::OString & o_rCString1,rtl::OString & o_rCString2)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
1936cc0d486eSmseidel     // according to a recommendation 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  */
appendUnicodeTextStringEncrypt(const rtl::OUString & rInString,const sal_Int32 nInObjectNumber,OStringBuffer & rOutBuffer)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 );
2030c1e8cc3aSDon Lewis             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
2035c1e8cc3aSDon Lewis             for( int i = 0; i < nLen; i++ )
2036cdf0e10cSrcweir             {
2037c1e8cc3aSDon Lewis                 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
2045c1e8cc3aSDon Lewis             for(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 
appendLiteralStringEncrypt(rtl::OStringBuffer & rInString,const sal_Int32 nInObjectNumber,rtl::OStringBuffer & rOutBuffer)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 
appendLiteralStringEncrypt(const rtl::OString & rInString,const sal_Int32 nInObjectNumber,rtl::OStringBuffer & rOutBuffer)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 
appendLiteralStringEncrypt(const rtl::OUString & rInString,const sal_Int32 nInObjectNumber,rtl::OStringBuffer & rOutBuffer,rtl_TextEncoding nEnc)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 
emitComment(const char * pComment)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 
compressStream(SvMemoryStream * pStream)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 
beginCompression()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 
endCompression()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 
writeBuffer(const void * pBuffer,sal_uInt64 nBytes)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 
getReferenceDevice()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& );
GetBuiltinFont() const2242cdf0e10cSrcweir     const PDFWriterImpl::BuiltinFont*   GetBuiltinFont() const  { return &mrBuiltin; }
2243cdf0e10cSrcweir 
Clone() const2244cdf0e10cSrcweir     virtual ImplFontData*               Clone() const { return new ImplPdfBuiltinFontData(*this); }
2245cdf0e10cSrcweir     virtual ImplFontEntry*              CreateFontInstance( ImplFontSelectData& ) const;
GetFontId() const2246cdf0e10cSrcweir     virtual sal_IntPtr                  GetFontId() const { return reinterpret_cast<sal_IntPtr>(&mrBuiltin); }
2247cdf0e10cSrcweir };
2248cdf0e10cSrcweir 
GetPdfFontData(const ImplFontData * pFontData)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 
GetDevFontAttributes(const PDFWriterImpl::BuiltinFont & rBuiltin)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 
ImplPdfBuiltinFontData(const PDFWriterImpl::BuiltinFont & rBuiltin)2277cdf0e10cSrcweir ImplPdfBuiltinFontData::ImplPdfBuiltinFontData( const PDFWriterImpl::BuiltinFont& rBuiltin )
2278cdf0e10cSrcweir :   ImplFontData( GetDevFontAttributes(rBuiltin), PDF_FONT_MAGIC ),
2279cdf0e10cSrcweir     mrBuiltin( rBuiltin )
2280cdf0e10cSrcweir {}
2281cdf0e10cSrcweir 
CreateFontInstance(ImplFontSelectData & rFSD) const2282cdf0e10cSrcweir ImplFontEntry* ImplPdfBuiltinFontData::CreateFontInstance( ImplFontSelectData& rFSD ) const
2283cdf0e10cSrcweir {
2284cdf0e10cSrcweir     ImplFontEntry* pEntry = new ImplFontEntry( rFSD );
2285cdf0e10cSrcweir     return pEntry;
2286cdf0e10cSrcweir }
2287cdf0e10cSrcweir 
filterDevFontList(ImplDevFontList * pFontList)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 
isBuiltinFont(const ImplFontData * pFont) const2303cdf0e10cSrcweir bool PDFWriterImpl::isBuiltinFont( const ImplFontData* pFont ) const
2304cdf0e10cSrcweir {
2305cdf0e10cSrcweir     const ImplPdfBuiltinFontData* pFD = GetPdfFontData( pFont );
2306cdf0e10cSrcweir     return (pFD != NULL);
2307cdf0e10cSrcweir }
2308cdf0e10cSrcweir 
getFontMetric(ImplFontSelectData * pSelect,ImplFontMetricData * pMetric) const2309cdf0e10cSrcweir 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 
SetText(const String & rText)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 
PDFSalLayout(PDFWriterImpl & rPDFWriterImpl,const PDFWriterImpl::BuiltinFont & rBuiltinFont,long nPixelPerEM,int nOrientation)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 
LayoutText(ImplLayoutArgs & rArgs)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 
InitFont() const2432cdf0e10cSrcweir void PDFSalLayout::InitFont() const
2433cdf0e10cSrcweir {
2434cdf0e10cSrcweir     // TODO: recreate font with all its attributes
2435cdf0e10cSrcweir }
2436cdf0e10cSrcweir 
2437cdf0e10cSrcweir // -----------------------------------------------------------------------
2438cdf0e10cSrcweir 
DrawText(SalGraphics &) const2439cdf0e10cSrcweir void PDFSalLayout::DrawText( SalGraphics& ) const
2440cdf0e10cSrcweir {
2441cdf0e10cSrcweir     mrPDFWriterImpl.drawLayout( *const_cast<PDFSalLayout*>(this), maOrigText, true );
2442cdf0e10cSrcweir }
2443cdf0e10cSrcweir 
2444cdf0e10cSrcweir // -----------------------------------------------------------------------
2445cdf0e10cSrcweir 
GetTextLayout(ImplLayoutArgs & rArgs,ImplFontSelectData * pSelect)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 
newPage(sal_Int32 nPageWidth,sal_Int32 nPageHeight,PDFWriter::Orientation eOrientation)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 
endPage()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 
createObject()2544cdf0e10cSrcweir sal_Int32 PDFWriterImpl::createObject()
2545cdf0e10cSrcweir {
2546cdf0e10cSrcweir     m_aObjects.push_back( ~0U );
2547cdf0e10cSrcweir     return m_aObjects.size();
2548cdf0e10cSrcweir }
2549cdf0e10cSrcweir 
updateObject(sal_Int32 n)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 
emitStructParentTree(sal_Int32 nObject)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 
getAttributeTag(PDFWriter::StructAttribute eAttr)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 
getAttributeValueTag(PDFWriter::StructAttributeValue eVal)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 
appendStructureAttributeLine(PDFWriter::StructAttribute i_eAttr,const PDFWriterImpl::PDFStructureAttribute & i_rVal,OStringBuffer & o_rLine,bool i_bIsFixedInt)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 
emitStructureAttributes(PDFStructureElement & i_rEle)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 
emitStructure(PDFStructureElement & rEle)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 
emitGradients()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 
emitTilings()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 
emitBuiltinFont(const ImplFontData * pFont,sal_Int32 nFontObject)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 
emitSystemFont(const ImplFontData * pFont,EmbedFont & rEmbed)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 );
3158248a599fSHerbert Dürr         sal_GlyphId aGlyphIds[ 256 ];
3159cdf0e10cSrcweir         sal_uInt8 pEncoding[ 256 ];
3160cdf0e10cSrcweir         sal_Ucs   pUnicodes[ 256 ];
3161cdf0e10cSrcweir         sal_Int32 pDuWidths[ 256 ];
3162cdf0e10cSrcweir 
3163248a599fSHerbert Dürr         memset( aGlyphIds, 0, sizeof( aGlyphIds ) );
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;
3172248a599fSHerbert Dürr             aGlyphIds[c] = 0;
3173cdf0e10cSrcweir             if( aUnicodeMap.find( c ) != aUnicodeMap.end() )
3174cdf0e10cSrcweir                 pWidths[ c ] = aGlyphWidths[ aUnicodeMap[ c ] ];
3175cdf0e10cSrcweir         }
3176cdf0e10cSrcweir 
3177248a599fSHerbert Dürr         m_pReferenceDevice->mpGraphics->CreateFontSubset( aTmpName, pFont, aGlyphIds, 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];
getPfbSegmentLengths(const unsigned char * pFontBytes,int nByteLen,ThreeInts & rSegmentLengths)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
emitEmbeddedFont(const ImplFontData * pFont,EmbedFont & rEmbed)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" );
3696c4e09a47SHerbert Dürr             if( !pFont->IsSymbolFont() )
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 
appendSubsetName(int nSubsetID,const OUString & rPSName,OStringBuffer & rBuffer)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 
createToUnicodeCMap(sal_uInt8 * pEncoding,sal_Ucs * pUnicodes,sal_Int32 * pUnicodesPerGlyph,sal_Int32 * pEncToUnicodeIndex,int nGlyphs)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 
emitFontDescriptor(const ImplFontData * pFont,FontSubsetInfo & rInfo,sal_Int32 nSubsetID,sal_Int32 nFontStream)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 
appendBuiltinFontsToDict(OStringBuffer & rDict) const4027cdf0e10cSrcweir 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 
emitFonts()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         {
4054248a599fSHerbert Dürr             sal_GlyphId aGlyphIds[ 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 
4065248a599fSHerbert Dürr             rtl_zeroMemory( aGlyphIds, sizeof( aGlyphIds ) );
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 
4073248a599fSHerbert Dürr                 DBG_ASSERT( aGlyphIds[nEnc] == 0 && pEncoding[nEnc] == 0, "duplicate glyph" );
4074cdf0e10cSrcweir                 DBG_ASSERT( nEnc <= lit->m_aMapping.size(), "invalid glyph encoding" );
4075cdf0e10cSrcweir 
4076248a599fSHerbert Dürr                 aGlyphIds[ 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;
4092248a599fSHerbert Dürr             if( m_pReferenceDevice->mpGraphics->CreateFontSubset( aTmpName, it->first, aGlyphIds, 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     }
430586e1cf34SPedro Giffuni     // emit builtin font for widget appearances / 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 
emitResources()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 
updateOutlineItemCount(std::vector<sal_Int32> & rCounts,sal_Int32 nItemLevel,sal_Int32 nCurrentItemId)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 are visible
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 
emitOutline()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 
appendDest(sal_Int32 nDestID,OStringBuffer & rBuffer)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 
emitLinkAnnotations()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                 {
473486e1cf34SPedro Giffuni // change the fragment to accommodate 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 
emitNoteAnnotations()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 
replaceFont(const Font & rControlFont,const Font & rAppSetFont)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 
getBestBuiltinFont(const Font & rFont)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 
replaceColor(const Color & rCol1,const Color & rCol2)4879cdf0e10cSrcweir static inline const Color& replaceColor( const Color& rCol1, const Color& rCol2 )
4880cdf0e10cSrcweir {
4881cdf0e10cSrcweir     return (rCol1 == Color( COL_TRANSPARENT )) ? rCol2 : rCol1;
4882cdf0e10cSrcweir }
4883cdf0e10cSrcweir 
createDefaultPushButtonAppearance(PDFWidget & rButton,const PDFWriter::PushButtonWidget & rWidget)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 
drawFieldBorder(PDFWidget & rIntern,const PDFWriter::AnyWidget & rWidget,const StyleSettings & rSettings)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 
createDefaultEditAppearance(PDFWidget & rEdit,const PDFWriter::EditWidget & rWidget)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 
createDefaultListBoxAppearance(PDFWidget & rBox,const PDFWriter::ListBoxWidget & rWidget)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 
createDefaultCheckBoxAppearance(PDFWidget & rBox,const PDFWriter::CheckBoxWidget & rWidget)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 
createDefaultRadioButtonAppearance(PDFWidget & rBox,const PDFWriter::RadioButtonWidget & rWidget)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";
5334cc0d486eSmseidel //after this assignment, 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 
emitAppearances(PDFWidget & rWidget,OStringBuffer & rAnnotDict)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 
emitWidgetAnnotations()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
5502cc0d486eSmseidel                     // of course real check boxes (not belonging to a radio 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         }
5713cc0d486eSmseidel         // appearance characteristics 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 
emitAnnotations()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 
emitCatalog()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 
emitInfoDict()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 //
emitNamedDestinations()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
616086e1cf34SPedro Giffuni                                  //maps the preceding 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 
emitOutputIntent()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 );
6285*a22fd41bSmseidel     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
escapeStringXML(const rtl::OUString & rStr,rtl::OUString & rValue)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 //
emitDocumentMetadata()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 
emitTrailer()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" );
65629105f983SHerbert Dürr     if( nSecObject )
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 
AnnotationSortEntryAnnotationSortEntry6626cdf0e10cSrcweir     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 
AnnotSorterLessAnnotSorterLess6643cdf0e10cSrcweir     AnnotSorterLess( std::vector< PDFWriterImpl::PDFWidget >& rWidgets ) : m_rWidgets( rWidgets ) {}
6644cdf0e10cSrcweir 
operator ()AnnotSorterLess6645cdf0e10cSrcweir     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 
sortWidgets()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:
PDFStreamIf(PDFWriterImpl * pWriter)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 
~PDFStreamIf()6741cdf0e10cSrcweir PDFStreamIf::~PDFStreamIf()
6742cdf0e10cSrcweir {
6743cdf0e10cSrcweir }
6744cdf0e10cSrcweir 
writeBytes(const com::sun::star::uno::Sequence<sal_Int8> & aData)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 
flush()6755cdf0e10cSrcweir void SAL_CALL PDFStreamIf::flush() throw()
6756cdf0e10cSrcweir {
6757cdf0e10cSrcweir }
6758cdf0e10cSrcweir 
closeOutput()6759cdf0e10cSrcweir void SAL_CALL PDFStreamIf::closeOutput() throw()
6760cdf0e10cSrcweir {
6761cdf0e10cSrcweir     m_bWrite = false;
6762cdf0e10cSrcweir }
6763cdf0e10cSrcweir 
emitAdditionalStreams()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 
emit()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 
getErrors()6851cdf0e10cSrcweir std::set< PDFWriter::ErrorCode > PDFWriterImpl::getErrors()
6852cdf0e10cSrcweir {
6853cdf0e10cSrcweir     return m_aErrors;
6854cdf0e10cSrcweir }
6855cdf0e10cSrcweir 
getSystemFont(const Font & i_rFont)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 
registerGlyphs(int nGlyphs,sal_GlyphId * pGlyphs,sal_Int32 * pGlyphWidths,sal_Ucs * pUnicodes,sal_Int32 * pUnicodesPerGlyph,sal_uInt8 * pMappedGlyphs,sal_Int32 * pMappedFontObjects,const ImplFontData * pFallbackFonts[])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 
drawRelief(SalLayout & rLayout,const String & rText,bool bTextLines)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 
drawShadow(SalLayout & rLayout,const String & rText,bool bTextLines)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 
drawVerticalGlyphs(const std::vector<PDFWriterImpl::PDFGlyph> & rGlyphs,OStringBuffer & rLine,const Point & rAlignOffset,const Matrix3 & rRotScale,double fAngle,double fXScale,double fSkew,sal_Int32 nFontHeight)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 )
71783c19fd8cSZhe Wang         {
71793c19fd8cSZhe Wang             long nOffsetX = rGlyphs[i+1].m_aPos.X() - rGlyphs[i].m_aPos.X();
71803c19fd8cSZhe Wang             long nOffsetY = rGlyphs[i+1].m_aPos.Y() - rGlyphs[i].m_aPos.Y();
71813c19fd8cSZhe Wang             nXOffset += (int)sqrt(double(nOffsetX*nOffsetX + nOffsetY*nOffsetY));
71823c19fd8cSZhe Wang         }
7183cdf0e10cSrcweir         if( ! rGlyphs[i].m_nGlyphId )
7184cdf0e10cSrcweir             continue;
7185cdf0e10cSrcweir 
7186cdf0e10cSrcweir         aDeltaPos = rRotScale.transform( aDeltaPos );
7187cdf0e10cSrcweir 
7188cdf0e10cSrcweir         Matrix3 aMat;
7189cdf0e10cSrcweir         if( fSkewB != 0.0 || fSkewA != 0.0 )
7190cdf0e10cSrcweir             aMat.skew( fSkewA, fSkewB );
7191cdf0e10cSrcweir         aMat.scale( fTempXScale, fYScale );
7192cdf0e10cSrcweir         aMat.rotate( fAngle+fDeltaAngle );
7193cdf0e10cSrcweir         aMat.translate( aCurPos.X()+aDeltaPos.X(), aCurPos.Y()+aDeltaPos.Y() );
7194cdf0e10cSrcweir         aMat.append( m_aPages.back(), rLine );
7195cdf0e10cSrcweir         rLine.append( " Tm" );
7196cdf0e10cSrcweir         if( i == 0 || rGlyphs[i-1].m_nMappedFontId != rGlyphs[i].m_nMappedFontId )
7197cdf0e10cSrcweir         {
7198cdf0e10cSrcweir             rLine.append( " /F" );
7199cdf0e10cSrcweir             rLine.append( rGlyphs[i].m_nMappedFontId );
7200cdf0e10cSrcweir             rLine.append( ' ' );
7201cdf0e10cSrcweir             m_aPages.back().appendMappedLength( nFontHeight, rLine, true );
7202cdf0e10cSrcweir             rLine.append( " Tf" );
7203cdf0e10cSrcweir         }
7204cdf0e10cSrcweir         rLine.append( "<" );
7205cdf0e10cSrcweir         appendHex( rGlyphs[i].m_nMappedGlyphId, rLine );
7206cdf0e10cSrcweir         rLine.append( ">Tj\n" );
7207cdf0e10cSrcweir     }
7208cdf0e10cSrcweir }
7209cdf0e10cSrcweir 
drawHorizontalGlyphs(const std::vector<PDFWriterImpl::PDFGlyph> & rGlyphs,OStringBuffer & rLine,const Point & rAlignOffset,double fAngle,double fXScale,double fSkew,sal_Int32 nFontHeight,sal_Int32 nPixelFontHeight)7210cdf0e10cSrcweir void PDFWriterImpl::drawHorizontalGlyphs(
7211cdf0e10cSrcweir         const std::vector<PDFWriterImpl::PDFGlyph>& rGlyphs,
7212cdf0e10cSrcweir         OStringBuffer& rLine,
7213cdf0e10cSrcweir         const Point& rAlignOffset,
7214cdf0e10cSrcweir         double fAngle,
7215cdf0e10cSrcweir         double fXScale,
7216cdf0e10cSrcweir         double fSkew,
7217cdf0e10cSrcweir         sal_Int32 nFontHeight,
7218cdf0e10cSrcweir         sal_Int32 nPixelFontHeight
7219cdf0e10cSrcweir         )
7220cdf0e10cSrcweir {
7221cdf0e10cSrcweir     // horizontal (= normal) case
7222cdf0e10cSrcweir 
7223cdf0e10cSrcweir     // fill in  run end indices
7224cdf0e10cSrcweir     // end is marked by index of the first glyph of the next run
7225cdf0e10cSrcweir     // a run is marked by same mapped font id and same Y position
7226cdf0e10cSrcweir     std::vector< sal_uInt32 > aRunEnds;
7227cdf0e10cSrcweir     aRunEnds.reserve( rGlyphs.size() );
7228cdf0e10cSrcweir     for( size_t i = 1; i < rGlyphs.size(); i++ )
7229cdf0e10cSrcweir     {
7230cdf0e10cSrcweir         if( rGlyphs[i].m_nMappedFontId != rGlyphs[i-1].m_nMappedFontId ||
7231cdf0e10cSrcweir             rGlyphs[i].m_aPos.Y() != rGlyphs[i-1].m_aPos.Y() )
7232cdf0e10cSrcweir         {
7233cdf0e10cSrcweir             aRunEnds.push_back(i);
7234cdf0e10cSrcweir         }
7235cdf0e10cSrcweir     }
7236cdf0e10cSrcweir     // last run ends at last glyph
7237cdf0e10cSrcweir     aRunEnds.push_back( rGlyphs.size() );
7238cdf0e10cSrcweir 
7239cdf0e10cSrcweir     // loop over runs of the same font
7240cdf0e10cSrcweir     sal_uInt32 nBeginRun = 0;
7241cdf0e10cSrcweir     for( size_t nRun = 0; nRun < aRunEnds.size(); nRun++ )
7242cdf0e10cSrcweir     {
7243cdf0e10cSrcweir         // setup text matrix
7244cdf0e10cSrcweir         Point aCurPos = rGlyphs[nBeginRun].m_aPos;
7245cdf0e10cSrcweir         // back transformation to current coordinate system
7246cdf0e10cSrcweir         aCurPos = m_pReferenceDevice->PixelToLogic( aCurPos );
7247cdf0e10cSrcweir         aCurPos += rAlignOffset;
7248cdf0e10cSrcweir         // the first run can be set with "Td" operator
7249cdf0e10cSrcweir         // subsequent use of that operator would move
7250cdf0e10cSrcweir         // the texline matrix relative to what was set before
7251cdf0e10cSrcweir         // making use of that would drive us into rounding issues
7252cdf0e10cSrcweir         Matrix3 aMat;
7253cdf0e10cSrcweir         if( nRun == 0 && fAngle == 0.0 && fXScale == 1.0 && fSkew == 0.0 )
7254cdf0e10cSrcweir         {
7255cdf0e10cSrcweir             m_aPages.back().appendPoint( aCurPos, rLine, false );
7256cdf0e10cSrcweir             rLine.append( " Td " );
7257cdf0e10cSrcweir         }
7258cdf0e10cSrcweir         else
7259cdf0e10cSrcweir         {
7260cdf0e10cSrcweir             if( fSkew != 0.0 )
7261cdf0e10cSrcweir                 aMat.skew( 0.0, fSkew );
7262cdf0e10cSrcweir             aMat.scale( fXScale, 1.0 );
7263cdf0e10cSrcweir             aMat.rotate( fAngle );
7264cdf0e10cSrcweir             aMat.translate( aCurPos.X(), aCurPos.Y() );
7265cdf0e10cSrcweir             aMat.append( m_aPages.back(), rLine );
7266cdf0e10cSrcweir             rLine.append( " Tm\n" );
7267cdf0e10cSrcweir         }
7268cdf0e10cSrcweir         // set up correct font
7269cdf0e10cSrcweir         rLine.append( "/F" );
7270cdf0e10cSrcweir         rLine.append( rGlyphs[nBeginRun].m_nMappedFontId );
7271cdf0e10cSrcweir         rLine.append( ' ' );
7272cdf0e10cSrcweir         m_aPages.back().appendMappedLength( nFontHeight, rLine, true );
7273cdf0e10cSrcweir         rLine.append( " Tf" );
7274cdf0e10cSrcweir 
7275cdf0e10cSrcweir         // output glyphs using Tj or TJ
7276cdf0e10cSrcweir         OStringBuffer aKernedLine( 256 ), aUnkernedLine( 256 );
7277cdf0e10cSrcweir         aKernedLine.append( "[<" );
7278cdf0e10cSrcweir         aUnkernedLine.append( '<' );
7279cdf0e10cSrcweir         appendHex( rGlyphs[nBeginRun].m_nMappedGlyphId, aKernedLine );
7280cdf0e10cSrcweir         appendHex( rGlyphs[nBeginRun].m_nMappedGlyphId, aUnkernedLine );
7281cdf0e10cSrcweir 
7282cdf0e10cSrcweir         aMat.invert();
7283cdf0e10cSrcweir         bool bNeedKern = false;
7284cdf0e10cSrcweir         for( sal_uInt32 nPos = nBeginRun+1; nPos < aRunEnds[nRun]; nPos++ )
7285cdf0e10cSrcweir         {
7286cdf0e10cSrcweir             appendHex( rGlyphs[nPos].m_nMappedGlyphId, aUnkernedLine );
7287cdf0e10cSrcweir             // check if default glyph positioning is sufficient
7288cdf0e10cSrcweir             const Point aThisPos = aMat.transform( rGlyphs[nPos].m_aPos );
7289cdf0e10cSrcweir             const Point aPrevPos = aMat.transform( rGlyphs[nPos-1].m_aPos );
7290cdf0e10cSrcweir             double fAdvance = aThisPos.X() - aPrevPos.X();
7291cdf0e10cSrcweir             fAdvance *= 1000.0 / nPixelFontHeight;
7292cdf0e10cSrcweir             const sal_Int32 nAdjustment = (sal_Int32)(rGlyphs[nPos-1].m_nNativeWidth - fAdvance + 0.5);
7293cdf0e10cSrcweir             if( nAdjustment != 0 )
7294cdf0e10cSrcweir             {
7295cdf0e10cSrcweir                 // apply individual glyph positioning
7296cdf0e10cSrcweir                 bNeedKern = true;
7297cdf0e10cSrcweir                 aKernedLine.append( ">" );
7298cdf0e10cSrcweir                 aKernedLine.append( nAdjustment );
7299cdf0e10cSrcweir                 aKernedLine.append( "<" );
7300cdf0e10cSrcweir             }
7301cdf0e10cSrcweir             appendHex( rGlyphs[nPos].m_nMappedGlyphId, aKernedLine );
7302cdf0e10cSrcweir         }
7303cdf0e10cSrcweir         aKernedLine.append( ">]TJ\n" );
7304cdf0e10cSrcweir         aUnkernedLine.append( ">Tj\n" );
7305cdf0e10cSrcweir         rLine.append( bNeedKern ? aKernedLine : aUnkernedLine );
7306cdf0e10cSrcweir 
7307cdf0e10cSrcweir         // set beginning of next run
7308cdf0e10cSrcweir         nBeginRun = aRunEnds[nRun];
7309cdf0e10cSrcweir     }
7310cdf0e10cSrcweir }
7311cdf0e10cSrcweir 
drawLayout(SalLayout & rLayout,const String & rText,bool bTextLines)7312cdf0e10cSrcweir void PDFWriterImpl::drawLayout( SalLayout& rLayout, const String& rText, bool bTextLines )
7313cdf0e10cSrcweir {
7314cdf0e10cSrcweir     // relief takes precedence over shadow (see outdev3.cxx)
7315cdf0e10cSrcweir     if(  m_aCurrentPDFState.m_aFont.GetRelief() != RELIEF_NONE )
7316cdf0e10cSrcweir     {
7317cdf0e10cSrcweir         drawRelief( rLayout, rText, bTextLines );
7318cdf0e10cSrcweir         return;
7319cdf0e10cSrcweir     }
7320cdf0e10cSrcweir     else if( m_aCurrentPDFState.m_aFont.IsShadow() )
7321cdf0e10cSrcweir         drawShadow( rLayout, rText, bTextLines );
7322cdf0e10cSrcweir 
7323cdf0e10cSrcweir     OStringBuffer aLine( 512 );
7324cdf0e10cSrcweir 
7325cdf0e10cSrcweir     const int nMaxGlyphs = 256;
7326cdf0e10cSrcweir 
7327cdf0e10cSrcweir     sal_GlyphId pGlyphs[nMaxGlyphs];
7328cdf0e10cSrcweir     sal_Int32 pGlyphWidths[nMaxGlyphs];
7329cdf0e10cSrcweir     sal_uInt8 pMappedGlyphs[nMaxGlyphs];
7330cdf0e10cSrcweir     sal_Int32 pMappedFontObjects[nMaxGlyphs];
7331cdf0e10cSrcweir     std::vector<sal_Ucs> aUnicodes;
7332cdf0e10cSrcweir     aUnicodes.reserve( nMaxGlyphs );
7333cdf0e10cSrcweir     sal_Int32 pUnicodesPerGlyph[nMaxGlyphs];
7334cdf0e10cSrcweir     int pCharPosAry[nMaxGlyphs];
7335cdf0e10cSrcweir     sal_Int32 nAdvanceWidths[nMaxGlyphs];
7336cdf0e10cSrcweir     const ImplFontData* pFallbackFonts[nMaxGlyphs];
7337cdf0e10cSrcweir     bool bVertical = m_aCurrentPDFState.m_aFont.IsVertical();
7338cdf0e10cSrcweir     int nGlyphs;
7339cdf0e10cSrcweir     int nIndex = 0;
7340cdf0e10cSrcweir     int nMinCharPos = 0, nMaxCharPos = rText.Len()-1;
7341cdf0e10cSrcweir     double fXScale = 1.0;
7342cdf0e10cSrcweir     double fSkew = 0.0;
7343cdf0e10cSrcweir     sal_Int32 nPixelFontHeight = m_pReferenceDevice->mpFontEntry->maFontSelData.mnHeight;
7344cdf0e10cSrcweir     TextAlign eAlign = m_aCurrentPDFState.m_aFont.GetAlign();
7345cdf0e10cSrcweir 
7346cdf0e10cSrcweir     // transform font height back to current units
7347cdf0e10cSrcweir     // note: the layout calculates in outdevs device pixel !!
7348cdf0e10cSrcweir     sal_Int32 nFontHeight = m_pReferenceDevice->ImplDevicePixelToLogicHeight( nPixelFontHeight );
7349cdf0e10cSrcweir     if( m_aCurrentPDFState.m_aFont.GetWidth() )
7350cdf0e10cSrcweir     {
7351cdf0e10cSrcweir         Font aFont( m_aCurrentPDFState.m_aFont );
7352cdf0e10cSrcweir         aFont.SetWidth( 0 );
7353cdf0e10cSrcweir         FontMetric aMetric = m_pReferenceDevice->GetFontMetric( aFont );
7354cdf0e10cSrcweir         if( aMetric.GetWidth() != m_aCurrentPDFState.m_aFont.GetWidth() )
7355cdf0e10cSrcweir         {
7356cdf0e10cSrcweir             fXScale =
7357cdf0e10cSrcweir                 (double)m_aCurrentPDFState.m_aFont.GetWidth() /
7358cdf0e10cSrcweir                 (double)aMetric.GetWidth();
7359cdf0e10cSrcweir         }
7360cdf0e10cSrcweir         // force state before GetFontMetric
7361cdf0e10cSrcweir         m_pReferenceDevice->ImplNewFont();
7362cdf0e10cSrcweir     }
7363cdf0e10cSrcweir 
7364cdf0e10cSrcweir     // perform artificial italics if necessary
7365cdf0e10cSrcweir     if( ( m_aCurrentPDFState.m_aFont.GetItalic() == ITALIC_NORMAL ||
7366cdf0e10cSrcweir           m_aCurrentPDFState.m_aFont.GetItalic() == ITALIC_OBLIQUE ) &&
7367cdf0e10cSrcweir         !( m_pReferenceDevice->mpFontEntry->maFontSelData.mpFontData->GetSlant() == ITALIC_NORMAL ||
7368cdf0e10cSrcweir            m_pReferenceDevice->mpFontEntry->maFontSelData.mpFontData->GetSlant() == ITALIC_OBLIQUE )
7369cdf0e10cSrcweir         )
7370cdf0e10cSrcweir     {
7371cdf0e10cSrcweir         fSkew = M_PI/12.0;
7372cdf0e10cSrcweir     }
7373cdf0e10cSrcweir 
7374cdf0e10cSrcweir     // if the mapmode is distorted we need to adjust for that also
7375cdf0e10cSrcweir     if( m_aCurrentPDFState.m_aMapMode.GetScaleX() != m_aCurrentPDFState.m_aMapMode.GetScaleY() )
7376cdf0e10cSrcweir     {
7377cdf0e10cSrcweir         fXScale *= double(m_aCurrentPDFState.m_aMapMode.GetScaleX()) / double(m_aCurrentPDFState.m_aMapMode.GetScaleY());
7378cdf0e10cSrcweir     }
7379cdf0e10cSrcweir 
7380cdf0e10cSrcweir     int nAngle = m_aCurrentPDFState.m_aFont.GetOrientation();
7381cdf0e10cSrcweir     // normalize angles
7382cdf0e10cSrcweir     while( nAngle < 0 )
7383cdf0e10cSrcweir         nAngle += 3600;
7384cdf0e10cSrcweir     nAngle = nAngle % 3600;
7385cdf0e10cSrcweir     double fAngle = (double)nAngle * M_PI / 1800.0;
7386cdf0e10cSrcweir 
7387cdf0e10cSrcweir     Matrix3 aRotScale;
7388cdf0e10cSrcweir     aRotScale.scale( fXScale, 1.0 );
7389cdf0e10cSrcweir     if( fAngle != 0.0 )
7390cdf0e10cSrcweir         aRotScale.rotate( -fAngle );
7391cdf0e10cSrcweir 
7392cdf0e10cSrcweir     bool bPop = false;
7393cdf0e10cSrcweir     bool bABold = false;
7394cdf0e10cSrcweir     // artificial bold necessary ?
7395cdf0e10cSrcweir     if( m_pReferenceDevice->mpFontEntry->maFontSelData.mpFontData->GetWeight() <= WEIGHT_MEDIUM &&
7396cdf0e10cSrcweir         m_pReferenceDevice->mpFontEntry->maFontSelData.GetWeight() > WEIGHT_MEDIUM )
7397cdf0e10cSrcweir     {
7398cdf0e10cSrcweir         if( ! bPop )
7399cdf0e10cSrcweir             aLine.append( "q " );
7400cdf0e10cSrcweir         bPop = true;
7401cdf0e10cSrcweir         bABold = true;
7402cdf0e10cSrcweir     }
7403cdf0e10cSrcweir     // setup text colors (if necessary)
7404cdf0e10cSrcweir     Color aStrokeColor( COL_TRANSPARENT );
7405cdf0e10cSrcweir     Color aNonStrokeColor( COL_TRANSPARENT );
7406cdf0e10cSrcweir 
7407cdf0e10cSrcweir     if( m_aCurrentPDFState.m_aFont.IsOutline() )
7408cdf0e10cSrcweir     {
7409cdf0e10cSrcweir         aStrokeColor = m_aCurrentPDFState.m_aFont.GetColor();
7410cdf0e10cSrcweir         aNonStrokeColor = Color( COL_WHITE );
7411cdf0e10cSrcweir     }
7412cdf0e10cSrcweir     else
7413cdf0e10cSrcweir         aNonStrokeColor = m_aCurrentPDFState.m_aFont.GetColor();
7414cdf0e10cSrcweir     if( bABold )
7415cdf0e10cSrcweir         aStrokeColor = m_aCurrentPDFState.m_aFont.GetColor();
7416cdf0e10cSrcweir 
7417cdf0e10cSrcweir     if( aStrokeColor != Color( COL_TRANSPARENT ) && aStrokeColor != m_aCurrentPDFState.m_aLineColor )
7418cdf0e10cSrcweir     {
7419cdf0e10cSrcweir         if( ! bPop )
7420cdf0e10cSrcweir             aLine.append( "q " );
7421cdf0e10cSrcweir         bPop = true;
7422cdf0e10cSrcweir         appendStrokingColor( aStrokeColor, aLine );
7423cdf0e10cSrcweir         aLine.append( "\n" );
7424cdf0e10cSrcweir     }
7425cdf0e10cSrcweir     if( aNonStrokeColor != Color( COL_TRANSPARENT ) && aNonStrokeColor != m_aCurrentPDFState.m_aFillColor )
7426cdf0e10cSrcweir     {
7427cdf0e10cSrcweir         if( ! bPop )
7428cdf0e10cSrcweir             aLine.append( "q " );
7429cdf0e10cSrcweir         bPop = true;
7430cdf0e10cSrcweir         appendNonStrokingColor( aNonStrokeColor, aLine );
7431cdf0e10cSrcweir         aLine.append( "\n" );
7432cdf0e10cSrcweir     }
7433cdf0e10cSrcweir 
7434cdf0e10cSrcweir     // begin text object
7435cdf0e10cSrcweir     aLine.append( "BT\n" );
7436cdf0e10cSrcweir     // outline attribute ?
7437cdf0e10cSrcweir     if( m_aCurrentPDFState.m_aFont.IsOutline() || bABold )
7438cdf0e10cSrcweir     {
7439cdf0e10cSrcweir         // set correct text mode, set stroke width
7440cdf0e10cSrcweir         aLine.append( "2 Tr " ); // fill, then stroke
7441cdf0e10cSrcweir 
7442cdf0e10cSrcweir         if( m_aCurrentPDFState.m_aFont.IsOutline() )
7443cdf0e10cSrcweir         {
7444cdf0e10cSrcweir             // unclear what to do in case of outline and artificial bold
7445cdf0e10cSrcweir             // for the time being outline wins
7446cdf0e10cSrcweir             aLine.append( "0.25 w \n" );
7447cdf0e10cSrcweir         }
7448cdf0e10cSrcweir         else
7449cdf0e10cSrcweir         {
7450cdf0e10cSrcweir             double fW = (double)m_aCurrentPDFState.m_aFont.GetHeight() / 30.0;
7451cdf0e10cSrcweir             m_aPages.back().appendMappedLength( fW, aLine );
7452cdf0e10cSrcweir             aLine.append ( " w\n" );
7453cdf0e10cSrcweir         }
7454cdf0e10cSrcweir     }
7455cdf0e10cSrcweir 
7456cdf0e10cSrcweir     FontMetric aRefDevFontMetric = m_pReferenceDevice->GetFontMetric();
7457cdf0e10cSrcweir 
7458cdf0e10cSrcweir     // collect the glyphs into a single array
7459cdf0e10cSrcweir     const int nTmpMaxGlyphs = rLayout.GetOrientation() ? 1 : nMaxGlyphs; // #i97991# temporary workaround for #i87686#
7460cdf0e10cSrcweir     std::vector< PDFGlyph > aGlyphs;
7461cdf0e10cSrcweir     aGlyphs.reserve( nTmpMaxGlyphs );
7462cdf0e10cSrcweir     // first get all the glyphs and register them; coordinates still in Pixel
7463cdf0e10cSrcweir     Point aGNGlyphPos;
7464cdf0e10cSrcweir     while( (nGlyphs = rLayout.GetNextGlyphs( nTmpMaxGlyphs, pGlyphs, aGNGlyphPos, nIndex, nAdvanceWidths, pCharPosAry )) != 0 )
7465cdf0e10cSrcweir     {
7466cdf0e10cSrcweir         aUnicodes.clear();
7467cdf0e10cSrcweir         for( int i = 0; i < nGlyphs; i++ )
7468cdf0e10cSrcweir         {
7469cdf0e10cSrcweir             pFallbackFonts[i] = rLayout.GetFallbackFontData( pGlyphs[i] );
7470cdf0e10cSrcweir 
7471cdf0e10cSrcweir             // default case: 1 glyph is one unicode
7472cdf0e10cSrcweir             pUnicodesPerGlyph[i] = 1;
7473cdf0e10cSrcweir             if( (pGlyphs[i] & GF_ISCHAR) )
7474cdf0e10cSrcweir             {
7475cdf0e10cSrcweir                 aUnicodes.push_back( static_cast<sal_Ucs>(pGlyphs[i] & GF_IDXMASK) );
7476cdf0e10cSrcweir             }
7477cdf0e10cSrcweir             else if( pCharPosAry[i] >= nMinCharPos && pCharPosAry[i] <= nMaxCharPos )
7478cdf0e10cSrcweir             {
7479cdf0e10cSrcweir                 int nChars = 1;
7480cdf0e10cSrcweir                 aUnicodes.push_back( rText.GetChar( sal::static_int_cast<xub_StrLen>(pCharPosAry[i]) ) );
7481cdf0e10cSrcweir                 pUnicodesPerGlyph[i] = 1;
7482cdf0e10cSrcweir                 // try to handle ligatures and such
7483cdf0e10cSrcweir                 if( i < nGlyphs-1 )
7484cdf0e10cSrcweir                 {
7485cdf0e10cSrcweir                     nChars = pCharPosAry[i+1] - pCharPosAry[i];
7486cdf0e10cSrcweir                     // #i115618# fix for simple RTL+CTL cases
7487cdf0e10cSrcweir                     // TODO: sanitize for RTL ligatures, more complex CTL, etc.
7488cdf0e10cSrcweir                     if( nChars < 0 )
7489cdf0e10cSrcweir                         nChars = -nChars;
7490cdf0e10cSrcweir                     else if( nChars == 0 )
7491cdf0e10cSrcweir                         nChars = 1;
7492cdf0e10cSrcweir                     pUnicodesPerGlyph[i] = nChars;
7493cdf0e10cSrcweir                     for( int n = 1; n < nChars; n++ )
7494cdf0e10cSrcweir                         aUnicodes.push_back( rText.GetChar( sal::static_int_cast<xub_StrLen>(pCharPosAry[i]+n) ) );
7495cdf0e10cSrcweir                 }
7496cdf0e10cSrcweir                 // #i36691# hack that is needed because currently the pGlyphs[]
7497cdf0e10cSrcweir                 // argument is ignored for embeddable fonts and so the layout
7498cdf0e10cSrcweir                 // engine's glyph work is ignored (i.e. char mirroring)
7499cdf0e10cSrcweir                 // TODO: a real solution would be to map the layout engine's
7500cdf0e10cSrcweir                 // glyphid (i.e. FreeType's synthetic glyphid for a Type1 font)
7501cdf0e10cSrcweir                 // back to unicode and then to embeddable font's encoding
7502cdf0e10cSrcweir                 if( getReferenceDevice()->GetLayoutMode() & TEXT_LAYOUT_BIDI_RTL )
7503cdf0e10cSrcweir                 {
7504cdf0e10cSrcweir                     size_t nI = aUnicodes.size()-1;
7505cdf0e10cSrcweir                     for( int n = 0; n < nChars; n++, nI-- )
7506cdf0e10cSrcweir                         aUnicodes[nI] = static_cast<sal_Ucs>(GetMirroredChar(aUnicodes[nI]));
7507cdf0e10cSrcweir                 }
7508cdf0e10cSrcweir             }
7509cdf0e10cSrcweir             else
7510cdf0e10cSrcweir                 aUnicodes.push_back( 0 );
7511cdf0e10cSrcweir             // note: in case of ctl one character may result
7512cdf0e10cSrcweir             // in multiple glyphs. The current SalLayout
7513cdf0e10cSrcweir             // implementations set -1 then to indicate that no direct
7514cdf0e10cSrcweir             // mapping is possible
7515cdf0e10cSrcweir         }
7516cdf0e10cSrcweir 
7517cdf0e10cSrcweir         registerGlyphs( nGlyphs, pGlyphs, pGlyphWidths, &aUnicodes[0], pUnicodesPerGlyph, pMappedGlyphs, pMappedFontObjects, pFallbackFonts );
7518cdf0e10cSrcweir 
7519cdf0e10cSrcweir         for( int i = 0; i < nGlyphs; i++ )
7520cdf0e10cSrcweir         {
7521cdf0e10cSrcweir             aGlyphs.push_back( PDFGlyph( aGNGlyphPos,
7522cdf0e10cSrcweir                                          pGlyphWidths[i],
7523cdf0e10cSrcweir                                          pGlyphs[i],
7524cdf0e10cSrcweir                                          pMappedFontObjects[i],
7525cdf0e10cSrcweir                                          pMappedGlyphs[i] ) );
7526cdf0e10cSrcweir             if( bVertical )
7527cdf0e10cSrcweir                 aGNGlyphPos.Y() += nAdvanceWidths[i]/rLayout.GetUnitsPerPixel();
7528cdf0e10cSrcweir             else
7529cdf0e10cSrcweir                 aGNGlyphPos.X() += nAdvanceWidths[i]/rLayout.GetUnitsPerPixel();
7530cdf0e10cSrcweir         }
7531cdf0e10cSrcweir     }
7532cdf0e10cSrcweir 
7533cdf0e10cSrcweir     Point aAlignOffset;
7534cdf0e10cSrcweir     if ( eAlign == ALIGN_BOTTOM )
7535cdf0e10cSrcweir         aAlignOffset.Y() -= aRefDevFontMetric.GetDescent();
7536cdf0e10cSrcweir     else if ( eAlign == ALIGN_TOP )
7537cdf0e10cSrcweir         aAlignOffset.Y() += aRefDevFontMetric.GetAscent();
7538cdf0e10cSrcweir     if( aAlignOffset.X() || aAlignOffset.Y() )
7539cdf0e10cSrcweir         aAlignOffset = aRotScale.transform( aAlignOffset );
7540cdf0e10cSrcweir 
7541cdf0e10cSrcweir     /* #159153# do not emit an empty glyph vector; this can happen if e.g. the original
7542cdf0e10cSrcweir        string contained only on of the UTF16 BOMs
7543cdf0e10cSrcweir     */
7544cdf0e10cSrcweir     if( ! aGlyphs.empty() )
7545cdf0e10cSrcweir     {
7546cdf0e10cSrcweir         if( bVertical )
7547cdf0e10cSrcweir             drawVerticalGlyphs( aGlyphs, aLine, aAlignOffset, aRotScale, fAngle, fXScale, fSkew, nFontHeight );
7548cdf0e10cSrcweir         else
7549cdf0e10cSrcweir             drawHorizontalGlyphs( aGlyphs, aLine, aAlignOffset, fAngle, fXScale, fSkew, nFontHeight, nPixelFontHeight );
7550cdf0e10cSrcweir     }
7551cdf0e10cSrcweir 
7552cdf0e10cSrcweir     // end textobject
7553cdf0e10cSrcweir     aLine.append( "ET\n" );
7554cdf0e10cSrcweir     if( bPop )
7555cdf0e10cSrcweir         aLine.append( "Q\n" );
7556cdf0e10cSrcweir 
7557cdf0e10cSrcweir     writeBuffer( aLine.getStr(), aLine.getLength() );
7558cdf0e10cSrcweir 
7559cdf0e10cSrcweir     // draw eventual textlines
7560cdf0e10cSrcweir     FontStrikeout eStrikeout = m_aCurrentPDFState.m_aFont.GetStrikeout();
7561cdf0e10cSrcweir     FontUnderline eUnderline = m_aCurrentPDFState.m_aFont.GetUnderline();
7562cdf0e10cSrcweir     FontUnderline eOverline  = m_aCurrentPDFState.m_aFont.GetOverline();
7563cdf0e10cSrcweir     if( bTextLines &&
7564cdf0e10cSrcweir         (
7565cdf0e10cSrcweir          ( eUnderline != UNDERLINE_NONE && eUnderline != UNDERLINE_DONTKNOW ) ||
7566cdf0e10cSrcweir          ( eOverline  != UNDERLINE_NONE && eOverline  != UNDERLINE_DONTKNOW ) ||
7567cdf0e10cSrcweir          ( eStrikeout != STRIKEOUT_NONE && eStrikeout != STRIKEOUT_DONTKNOW )
7568cdf0e10cSrcweir          )
7569cdf0e10cSrcweir         )
7570cdf0e10cSrcweir     {
7571cdf0e10cSrcweir         sal_Bool bUnderlineAbove = OutputDevice::ImplIsUnderlineAbove( m_aCurrentPDFState.m_aFont );
7572cdf0e10cSrcweir         if( m_aCurrentPDFState.m_aFont.IsWordLineMode() )
7573cdf0e10cSrcweir         {
7574cdf0e10cSrcweir             Point aPos, aStartPt;
7575cdf0e10cSrcweir             sal_Int32 nWidth = 0, nAdvance=0;
7576cdf0e10cSrcweir             for( int nStart = 0;;)
7577cdf0e10cSrcweir             {
7578248a599fSHerbert Dürr                 sal_GlyphId aGlyphId;
7579248a599fSHerbert Dürr                 if( !rLayout.GetNextGlyphs( 1, &aGlyphId, aPos, nStart, &nAdvance ) )
7580cdf0e10cSrcweir                     break;
7581cdf0e10cSrcweir 
7582248a599fSHerbert Dürr                 if( !rLayout.IsSpacingGlyph( aGlyphId ) )
7583cdf0e10cSrcweir                 {
7584cdf0e10cSrcweir                     if( !nWidth )
7585cdf0e10cSrcweir                         aStartPt = aPos;
7586cdf0e10cSrcweir 
7587cdf0e10cSrcweir                     nWidth += nAdvance;
7588cdf0e10cSrcweir                 }
7589cdf0e10cSrcweir                 else if( nWidth > 0 )
7590cdf0e10cSrcweir                 {
7591cdf0e10cSrcweir                     drawTextLine( m_pReferenceDevice->PixelToLogic( aStartPt ),
7592cdf0e10cSrcweir                                   m_pReferenceDevice->ImplDevicePixelToLogicWidth( nWidth ),
7593cdf0e10cSrcweir                                   eStrikeout, eUnderline, eOverline, bUnderlineAbove );
7594cdf0e10cSrcweir                     nWidth = 0;
7595cdf0e10cSrcweir                 }
7596cdf0e10cSrcweir             }
7597cdf0e10cSrcweir 
7598cdf0e10cSrcweir             if( nWidth > 0 )
7599cdf0e10cSrcweir             {
7600cdf0e10cSrcweir                 drawTextLine( m_pReferenceDevice->PixelToLogic( aStartPt ),
7601cdf0e10cSrcweir                               m_pReferenceDevice->ImplDevicePixelToLogicWidth( nWidth ),
7602cdf0e10cSrcweir                               eStrikeout, eUnderline, eOverline, bUnderlineAbove );
7603cdf0e10cSrcweir             }
7604cdf0e10cSrcweir         }
7605cdf0e10cSrcweir         else
7606cdf0e10cSrcweir         {
7607cdf0e10cSrcweir             Point aStartPt = rLayout.GetDrawPosition();
7608cdf0e10cSrcweir             int nWidth = rLayout.GetTextWidth() / rLayout.GetUnitsPerPixel();
7609cdf0e10cSrcweir             drawTextLine( m_pReferenceDevice->PixelToLogic( aStartPt ),
7610cdf0e10cSrcweir                           m_pReferenceDevice->ImplDevicePixelToLogicWidth( nWidth ),
7611cdf0e10cSrcweir                           eStrikeout, eUnderline, eOverline, bUnderlineAbove );
7612cdf0e10cSrcweir         }
7613cdf0e10cSrcweir     }
7614cdf0e10cSrcweir 
7615cdf0e10cSrcweir     // write eventual emphasis marks
7616cdf0e10cSrcweir     if( m_aCurrentPDFState.m_aFont.GetEmphasisMark() & EMPHASISMARK_STYLE )
7617cdf0e10cSrcweir     {
7618cdf0e10cSrcweir         PolyPolygon             aEmphPoly;
7619cdf0e10cSrcweir         Rectangle               aEmphRect1;
7620cdf0e10cSrcweir         Rectangle               aEmphRect2;
7621cdf0e10cSrcweir         long                    nEmphYOff;
7622cdf0e10cSrcweir         long                    nEmphWidth;
7623cdf0e10cSrcweir         long                    nEmphHeight;
7624cdf0e10cSrcweir         sal_Bool                    bEmphPolyLine;
7625cdf0e10cSrcweir         FontEmphasisMark        nEmphMark;
7626cdf0e10cSrcweir 
7627cdf0e10cSrcweir         push( PUSH_ALL );
7628cdf0e10cSrcweir 
7629cdf0e10cSrcweir         aLine.setLength( 0 );
7630cdf0e10cSrcweir         aLine.append( "q\n" );
7631cdf0e10cSrcweir 
7632cdf0e10cSrcweir         nEmphMark = m_pReferenceDevice->ImplGetEmphasisMarkStyle( m_aCurrentPDFState.m_aFont );
7633cdf0e10cSrcweir         if ( nEmphMark & EMPHASISMARK_POS_BELOW )
7634cdf0e10cSrcweir             nEmphHeight = m_pReferenceDevice->mnEmphasisDescent;
7635cdf0e10cSrcweir         else
7636cdf0e10cSrcweir             nEmphHeight = m_pReferenceDevice->mnEmphasisAscent;
7637cdf0e10cSrcweir         m_pReferenceDevice->ImplGetEmphasisMark( aEmphPoly,
7638cdf0e10cSrcweir                                                  bEmphPolyLine,
7639cdf0e10cSrcweir                                                  aEmphRect1,
7640cdf0e10cSrcweir                                                  aEmphRect2,
7641cdf0e10cSrcweir                                                  nEmphYOff,
7642cdf0e10cSrcweir                                                  nEmphWidth,
7643cdf0e10cSrcweir                                                  nEmphMark,
7644cdf0e10cSrcweir                                                  m_pReferenceDevice->ImplDevicePixelToLogicWidth(nEmphHeight),
7645cdf0e10cSrcweir                                                  m_pReferenceDevice->mpFontEntry->mnOrientation );
7646cdf0e10cSrcweir         if ( bEmphPolyLine )
7647cdf0e10cSrcweir         {
7648cdf0e10cSrcweir             setLineColor( m_aCurrentPDFState.m_aFont.GetColor() );
7649cdf0e10cSrcweir             setFillColor( Color( COL_TRANSPARENT ) );
7650cdf0e10cSrcweir         }
7651cdf0e10cSrcweir         else
7652cdf0e10cSrcweir         {
7653cdf0e10cSrcweir             setFillColor( m_aCurrentPDFState.m_aFont.GetColor() );
7654cdf0e10cSrcweir             setLineColor( Color( COL_TRANSPARENT ) );
7655cdf0e10cSrcweir         }
7656cdf0e10cSrcweir         writeBuffer( aLine.getStr(), aLine.getLength() );
7657cdf0e10cSrcweir 
7658cdf0e10cSrcweir         Point aOffset = Point(0,0);
7659cdf0e10cSrcweir 
7660cdf0e10cSrcweir         if ( nEmphMark & EMPHASISMARK_POS_BELOW )
7661cdf0e10cSrcweir             aOffset.Y() += m_pReferenceDevice->mpFontEntry->maMetric.mnDescent + nEmphYOff;
7662cdf0e10cSrcweir         else
7663cdf0e10cSrcweir             aOffset.Y() -= m_pReferenceDevice->mpFontEntry->maMetric.mnAscent + nEmphYOff;
7664cdf0e10cSrcweir 
7665cdf0e10cSrcweir         long nEmphWidth2     = nEmphWidth / 2;
7666cdf0e10cSrcweir         long nEmphHeight2    = nEmphHeight / 2;
7667cdf0e10cSrcweir         aOffset += Point( nEmphWidth2, nEmphHeight2 );
7668cdf0e10cSrcweir 
7669cdf0e10cSrcweir         if ( eAlign == ALIGN_BOTTOM )
7670cdf0e10cSrcweir             aOffset.Y() -= m_pReferenceDevice->mpFontEntry->maMetric.mnDescent;
7671cdf0e10cSrcweir         else if ( eAlign == ALIGN_TOP )
7672cdf0e10cSrcweir             aOffset.Y() += m_pReferenceDevice->mpFontEntry->maMetric.mnAscent;
7673cdf0e10cSrcweir 
7674cdf0e10cSrcweir         for( int nStart = 0;;)
7675cdf0e10cSrcweir         {
7676cdf0e10cSrcweir             Point aPos;
7677248a599fSHerbert Dürr             sal_GlyphId aGlyphId;
7678cdf0e10cSrcweir             sal_Int32 nAdvance;
7679248a599fSHerbert Dürr             if( !rLayout.GetNextGlyphs( 1, &aGlyphId, aPos, nStart, &nAdvance ) )
7680cdf0e10cSrcweir                 break;
7681cdf0e10cSrcweir 
7682248a599fSHerbert Dürr             if( !rLayout.IsSpacingGlyph( aGlyphId ) )
7683cdf0e10cSrcweir             {
7684cdf0e10cSrcweir                 Point aAdjOffset = aOffset;
7685cdf0e10cSrcweir                 aAdjOffset.X() += (nAdvance - nEmphWidth) / 2;
7686cdf0e10cSrcweir                 aAdjOffset = aRotScale.transform( aAdjOffset );
7687cdf0e10cSrcweir 
7688cdf0e10cSrcweir                 aAdjOffset -= Point( nEmphWidth2, nEmphHeight2 );
7689cdf0e10cSrcweir 
7690cdf0e10cSrcweir                 aPos += aAdjOffset;
7691cdf0e10cSrcweir                 aPos = m_pReferenceDevice->PixelToLogic( aPos );
7692cdf0e10cSrcweir                 drawEmphasisMark( aPos.X(), aPos.Y(),
7693cdf0e10cSrcweir                                   aEmphPoly, bEmphPolyLine,
7694cdf0e10cSrcweir                                   aEmphRect1, aEmphRect2 );
7695cdf0e10cSrcweir             }
7696cdf0e10cSrcweir         }
7697cdf0e10cSrcweir 
7698cdf0e10cSrcweir         writeBuffer( "Q\n", 2 );
7699cdf0e10cSrcweir         pop();
7700cdf0e10cSrcweir     }
7701cdf0e10cSrcweir 
7702cdf0e10cSrcweir }
7703cdf0e10cSrcweir 
drawEmphasisMark(long nX,long nY,const PolyPolygon & rPolyPoly,sal_Bool bPolyLine,const Rectangle & rRect1,const Rectangle & rRect2)7704cdf0e10cSrcweir void PDFWriterImpl::drawEmphasisMark( long nX, long nY,
7705cdf0e10cSrcweir                                       const PolyPolygon& rPolyPoly, sal_Bool bPolyLine,
7706cdf0e10cSrcweir                                       const Rectangle& rRect1, const Rectangle& rRect2 )
7707cdf0e10cSrcweir {
7708cdf0e10cSrcweir     // TODO: pass nWidth as width of this mark
7709cdf0e10cSrcweir     // long nWidth = 0;
7710cdf0e10cSrcweir 
7711cdf0e10cSrcweir     if ( rPolyPoly.Count() )
7712cdf0e10cSrcweir     {
7713cdf0e10cSrcweir         if ( bPolyLine )
7714cdf0e10cSrcweir         {
7715cdf0e10cSrcweir             Polygon aPoly = rPolyPoly.GetObject( 0 );
7716cdf0e10cSrcweir             aPoly.Move( nX, nY );
7717cdf0e10cSrcweir             drawPolyLine( aPoly );
7718cdf0e10cSrcweir         }
7719cdf0e10cSrcweir         else
7720cdf0e10cSrcweir         {
7721cdf0e10cSrcweir             PolyPolygon aPolyPoly = rPolyPoly;
7722cdf0e10cSrcweir             aPolyPoly.Move( nX, nY );
7723cdf0e10cSrcweir             drawPolyPolygon( aPolyPoly );
7724cdf0e10cSrcweir         }
7725cdf0e10cSrcweir     }
7726cdf0e10cSrcweir 
7727cdf0e10cSrcweir     if ( !rRect1.IsEmpty() )
7728cdf0e10cSrcweir     {
7729cdf0e10cSrcweir         Rectangle aRect( Point( nX+rRect1.Left(),
7730cdf0e10cSrcweir                                 nY+rRect1.Top() ), rRect1.GetSize() );
7731cdf0e10cSrcweir         drawRectangle( aRect );
7732cdf0e10cSrcweir     }
7733cdf0e10cSrcweir 
7734cdf0e10cSrcweir     if ( !rRect2.IsEmpty() )
7735cdf0e10cSrcweir     {
7736cdf0e10cSrcweir         Rectangle aRect( Point( nX+rRect2.Left(),
7737cdf0e10cSrcweir                                 nY+rRect2.Top() ), rRect2.GetSize() );
7738cdf0e10cSrcweir 
7739cdf0e10cSrcweir         drawRectangle( aRect );
7740cdf0e10cSrcweir     }
7741cdf0e10cSrcweir }
7742cdf0e10cSrcweir 
drawText(const Point & rPos,const String & rText,xub_StrLen nIndex,xub_StrLen nLen,bool bTextLines)7743cdf0e10cSrcweir void PDFWriterImpl::drawText( const Point& rPos, const String& rText, xub_StrLen nIndex, xub_StrLen nLen, bool bTextLines )
7744cdf0e10cSrcweir {
7745cdf0e10cSrcweir     MARK( "drawText" );
7746cdf0e10cSrcweir 
7747cdf0e10cSrcweir     updateGraphicsState();
7748cdf0e10cSrcweir 
7749cdf0e10cSrcweir     // get a layout from the OuputDevice's SalGraphics
7750cdf0e10cSrcweir     // this also enforces font substitution and sets the font on SalGraphics
7751cdf0e10cSrcweir     SalLayout* pLayout = m_pReferenceDevice->ImplLayout( rText, nIndex, nLen, rPos );
7752cdf0e10cSrcweir     if( pLayout )
7753cdf0e10cSrcweir     {
7754cdf0e10cSrcweir         drawLayout( *pLayout, rText, bTextLines );
7755cdf0e10cSrcweir         pLayout->Release();
7756cdf0e10cSrcweir     }
7757cdf0e10cSrcweir }
7758cdf0e10cSrcweir 
drawTextArray(const Point & rPos,const String & rText,const sal_Int32 * pDXArray,xub_StrLen nIndex,xub_StrLen nLen,bool bTextLines)7759cdf0e10cSrcweir void PDFWriterImpl::drawTextArray( const Point& rPos, const String& rText, const sal_Int32* pDXArray, xub_StrLen nIndex, xub_StrLen nLen, bool bTextLines )
7760cdf0e10cSrcweir {
7761cdf0e10cSrcweir     MARK( "drawText with array" );
7762cdf0e10cSrcweir 
7763cdf0e10cSrcweir     updateGraphicsState();
7764cdf0e10cSrcweir 
7765cdf0e10cSrcweir     // get a layout from the OuputDevice's SalGraphics
7766cdf0e10cSrcweir     // this also enforces font substitution and sets the font on SalGraphics
7767cdf0e10cSrcweir     SalLayout* pLayout = m_pReferenceDevice->ImplLayout( rText, nIndex, nLen, rPos, 0, pDXArray );
7768cdf0e10cSrcweir     if( pLayout )
7769cdf0e10cSrcweir     {
7770cdf0e10cSrcweir         drawLayout( *pLayout, rText, bTextLines );
7771cdf0e10cSrcweir         pLayout->Release();
7772cdf0e10cSrcweir     }
7773cdf0e10cSrcweir }
7774cdf0e10cSrcweir 
drawStretchText(const Point & rPos,sal_uLong nWidth,const String & rText,xub_StrLen nIndex,xub_StrLen nLen,bool bTextLines)7775cdf0e10cSrcweir void PDFWriterImpl::drawStretchText( const Point& rPos, sal_uLong nWidth, const String& rText, xub_StrLen nIndex, xub_StrLen nLen, bool bTextLines )
7776cdf0e10cSrcweir {
7777cdf0e10cSrcweir     MARK( "drawStretchText" );
7778cdf0e10cSrcweir 
7779cdf0e10cSrcweir     updateGraphicsState();
7780cdf0e10cSrcweir 
7781cdf0e10cSrcweir     // get a layout from the OuputDevice's SalGraphics
7782cdf0e10cSrcweir     // this also enforces font substitution and sets the font on SalGraphics
7783cdf0e10cSrcweir     SalLayout* pLayout = m_pReferenceDevice->ImplLayout( rText, nIndex, nLen, rPos, nWidth );
7784cdf0e10cSrcweir     if( pLayout )
7785cdf0e10cSrcweir     {
7786cdf0e10cSrcweir         drawLayout( *pLayout, rText, bTextLines );
7787cdf0e10cSrcweir         pLayout->Release();
7788cdf0e10cSrcweir     }
7789cdf0e10cSrcweir }
7790cdf0e10cSrcweir 
drawText(const Rectangle & rRect,const String & rOrigStr,sal_uInt16 nStyle,bool bTextLines)7791cdf0e10cSrcweir void PDFWriterImpl::drawText( const Rectangle& rRect, const String& rOrigStr, sal_uInt16 nStyle, bool bTextLines )
7792cdf0e10cSrcweir {
7793cdf0e10cSrcweir     long        nWidth          = rRect.GetWidth();
7794cdf0e10cSrcweir     long        nHeight         = rRect.GetHeight();
7795cdf0e10cSrcweir 
7796cdf0e10cSrcweir     if ( nWidth <= 0 || nHeight <= 0 )
7797cdf0e10cSrcweir         return;
7798cdf0e10cSrcweir 
7799cdf0e10cSrcweir     MARK( "drawText with rectangle" );
7800cdf0e10cSrcweir 
7801cdf0e10cSrcweir     updateGraphicsState();
7802cdf0e10cSrcweir 
7803cdf0e10cSrcweir     // clip with rectangle
7804cdf0e10cSrcweir     OStringBuffer aLine;
7805cdf0e10cSrcweir     aLine.append( "q " );
7806cdf0e10cSrcweir     m_aPages.back().appendRect( rRect, aLine );
7807cdf0e10cSrcweir     aLine.append( " W* n\n" );
7808cdf0e10cSrcweir     writeBuffer( aLine.getStr(), aLine.getLength() );
7809cdf0e10cSrcweir 
7810cdf0e10cSrcweir     // if disabled text is needed, put in here
7811cdf0e10cSrcweir 
7812cdf0e10cSrcweir     Point       aPos            = rRect.TopLeft();
7813cdf0e10cSrcweir 
7814cdf0e10cSrcweir     long        nTextHeight     = m_pReferenceDevice->GetTextHeight();
7815cdf0e10cSrcweir     xub_StrLen  nMnemonicPos    = STRING_NOTFOUND;
7816cdf0e10cSrcweir 
7817cdf0e10cSrcweir     String aStr = rOrigStr;
7818cdf0e10cSrcweir     if ( nStyle & TEXT_DRAW_MNEMONIC )
7819cdf0e10cSrcweir         aStr = m_pReferenceDevice->GetNonMnemonicString( aStr, nMnemonicPos );
7820cdf0e10cSrcweir 
7821cdf0e10cSrcweir     // multiline text
7822cdf0e10cSrcweir     if ( nStyle & TEXT_DRAW_MULTILINE )
7823cdf0e10cSrcweir     {
7824cdf0e10cSrcweir         XubString               aLastLine;
7825cdf0e10cSrcweir         ImplMultiTextLineInfo   aMultiLineInfo;
7826cdf0e10cSrcweir         ImplTextLineInfo*       pLineInfo;
7827cdf0e10cSrcweir         long                    nMaxTextWidth;
7828cdf0e10cSrcweir         xub_StrLen              i;
7829cdf0e10cSrcweir         xub_StrLen              nLines;
7830cdf0e10cSrcweir         xub_StrLen              nFormatLines;
7831cdf0e10cSrcweir 
7832cdf0e10cSrcweir         if ( nTextHeight )
7833cdf0e10cSrcweir         {
7834cdf0e10cSrcweir             ::vcl::DefaultTextLayout aLayout( *m_pReferenceDevice );
7835cdf0e10cSrcweir             nMaxTextWidth = OutputDevice::ImplGetTextLines( aMultiLineInfo, nWidth, aStr, nStyle, aLayout );
7836cdf0e10cSrcweir             nLines = (xub_StrLen)(nHeight/nTextHeight);
7837cdf0e10cSrcweir             nFormatLines = aMultiLineInfo.Count();
7838cdf0e10cSrcweir             if ( !nLines )
7839cdf0e10cSrcweir                 nLines = 1;
7840cdf0e10cSrcweir             if ( nFormatLines > nLines )
7841cdf0e10cSrcweir             {
7842cdf0e10cSrcweir                 if ( nStyle & TEXT_DRAW_ENDELLIPSIS )
7843cdf0e10cSrcweir                 {
7844cdf0e10cSrcweir                     // handle last line
7845cdf0e10cSrcweir                     nFormatLines = nLines-1;
7846cdf0e10cSrcweir 
7847cdf0e10cSrcweir                     pLineInfo = aMultiLineInfo.GetLine( nFormatLines );
7848cdf0e10cSrcweir                     aLastLine = aStr.Copy( pLineInfo->GetIndex() );
7849cdf0e10cSrcweir                     aLastLine.ConvertLineEnd( LINEEND_LF );
7850cdf0e10cSrcweir                     // replace line feed by space
7851cdf0e10cSrcweir                     xub_StrLen nLastLineLen = aLastLine.Len();
7852cdf0e10cSrcweir                     for ( i = 0; i < nLastLineLen; i++ )
7853cdf0e10cSrcweir                     {
7854cdf0e10cSrcweir                         if ( aLastLine.GetChar( i ) == _LF )
7855cdf0e10cSrcweir                             aLastLine.SetChar( i, ' ' );
7856cdf0e10cSrcweir                     }
7857cdf0e10cSrcweir                     aLastLine = m_pReferenceDevice->GetEllipsisString( aLastLine, nWidth, nStyle );
7858cdf0e10cSrcweir                     nStyle &= ~(TEXT_DRAW_VCENTER | TEXT_DRAW_BOTTOM);
7859cdf0e10cSrcweir                     nStyle |= TEXT_DRAW_TOP;
7860cdf0e10cSrcweir                 }
7861cdf0e10cSrcweir             }
7862cdf0e10cSrcweir 
7863cdf0e10cSrcweir             // vertical alignment
7864cdf0e10cSrcweir             if ( nStyle & TEXT_DRAW_BOTTOM )
7865cdf0e10cSrcweir                 aPos.Y() += nHeight-(nFormatLines*nTextHeight);
7866cdf0e10cSrcweir             else if ( nStyle & TEXT_DRAW_VCENTER )
7867cdf0e10cSrcweir                 aPos.Y() += (nHeight-(nFormatLines*nTextHeight))/2;
7868cdf0e10cSrcweir 
7869cdf0e10cSrcweir             // draw all lines excluding the last
7870cdf0e10cSrcweir             for ( i = 0; i < nFormatLines; i++ )
7871cdf0e10cSrcweir             {
7872cdf0e10cSrcweir                 pLineInfo = aMultiLineInfo.GetLine( i );
7873cdf0e10cSrcweir                 if ( nStyle & TEXT_DRAW_RIGHT )
7874cdf0e10cSrcweir                     aPos.X() += nWidth-pLineInfo->GetWidth();
7875cdf0e10cSrcweir                 else if ( nStyle & TEXT_DRAW_CENTER )
7876cdf0e10cSrcweir                     aPos.X() += (nWidth-pLineInfo->GetWidth())/2;
7877cdf0e10cSrcweir                 xub_StrLen nIndex   = pLineInfo->GetIndex();
7878cdf0e10cSrcweir                 xub_StrLen nLineLen = pLineInfo->GetLen();
7879cdf0e10cSrcweir                 drawText( aPos, aStr, nIndex, nLineLen, bTextLines );
7880cdf0e10cSrcweir                 // mnemonics should not appear in documents,
7881cdf0e10cSrcweir                 // if the need arises, put them in here
7882cdf0e10cSrcweir                 aPos.Y() += nTextHeight;
7883cdf0e10cSrcweir                 aPos.X() = rRect.Left();
7884cdf0e10cSrcweir             }
7885cdf0e10cSrcweir 
7886cdf0e10cSrcweir 
7887cdf0e10cSrcweir             // output last line left adjusted since it was shortened
7888cdf0e10cSrcweir             if ( aLastLine.Len() )
7889cdf0e10cSrcweir                 drawText( aPos, aLastLine, 0, STRING_LEN, bTextLines );
7890cdf0e10cSrcweir         }
7891cdf0e10cSrcweir     }
7892cdf0e10cSrcweir     else
7893cdf0e10cSrcweir     {
7894cdf0e10cSrcweir         long nTextWidth = m_pReferenceDevice->GetTextWidth( aStr );
7895cdf0e10cSrcweir 
7896cdf0e10cSrcweir         // Evt. Text kuerzen
7897cdf0e10cSrcweir         if ( nTextWidth > nWidth )
7898cdf0e10cSrcweir         {
7899cdf0e10cSrcweir             if ( nStyle & (TEXT_DRAW_ENDELLIPSIS | TEXT_DRAW_PATHELLIPSIS | TEXT_DRAW_NEWSELLIPSIS) )
7900cdf0e10cSrcweir             {
7901cdf0e10cSrcweir                 aStr = m_pReferenceDevice->GetEllipsisString( aStr, nWidth, nStyle );
7902cdf0e10cSrcweir                 nStyle &= ~(TEXT_DRAW_CENTER | TEXT_DRAW_RIGHT);
7903cdf0e10cSrcweir                 nStyle |= TEXT_DRAW_LEFT;
7904cdf0e10cSrcweir                 nTextWidth = m_pReferenceDevice->GetTextWidth( aStr );
7905cdf0e10cSrcweir             }
7906cdf0e10cSrcweir         }
7907cdf0e10cSrcweir 
7908cdf0e10cSrcweir         // vertical alignment
7909cdf0e10cSrcweir         if ( nStyle & TEXT_DRAW_RIGHT )
7910cdf0e10cSrcweir             aPos.X() += nWidth-nTextWidth;
7911cdf0e10cSrcweir         else if ( nStyle & TEXT_DRAW_CENTER )
7912cdf0e10cSrcweir             aPos.X() += (nWidth-nTextWidth)/2;
7913cdf0e10cSrcweir 
7914cdf0e10cSrcweir         if ( nStyle & TEXT_DRAW_BOTTOM )
7915cdf0e10cSrcweir             aPos.Y() += nHeight-nTextHeight;
7916cdf0e10cSrcweir         else if ( nStyle & TEXT_DRAW_VCENTER )
7917cdf0e10cSrcweir             aPos.Y() += (nHeight-nTextHeight)/2;
7918cdf0e10cSrcweir 
7919cdf0e10cSrcweir         // mnemonics should be inserted here if the need arises
7920cdf0e10cSrcweir 
7921cdf0e10cSrcweir         // draw the actual text
7922cdf0e10cSrcweir         drawText( aPos, aStr, 0, STRING_LEN, bTextLines );
7923cdf0e10cSrcweir     }
7924cdf0e10cSrcweir 
7925cdf0e10cSrcweir     // reset clip region to original value
7926cdf0e10cSrcweir     aLine.setLength( 0 );
7927cdf0e10cSrcweir     aLine.append( "Q\n" );
7928cdf0e10cSrcweir     writeBuffer( aLine.getStr(), aLine.getLength() );
7929cdf0e10cSrcweir }
7930cdf0e10cSrcweir 
drawLine(const Point & rStart,const Point & rStop)7931cdf0e10cSrcweir void PDFWriterImpl::drawLine( const Point& rStart, const Point& rStop )
7932cdf0e10cSrcweir {
7933cdf0e10cSrcweir     MARK( "drawLine" );
7934cdf0e10cSrcweir 
7935cdf0e10cSrcweir     updateGraphicsState();
7936cdf0e10cSrcweir 
7937cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) )
7938cdf0e10cSrcweir         return;
7939cdf0e10cSrcweir 
7940cdf0e10cSrcweir     OStringBuffer aLine;
7941cdf0e10cSrcweir     m_aPages.back().appendPoint( rStart, aLine );
7942cdf0e10cSrcweir     aLine.append( " m " );
7943cdf0e10cSrcweir     m_aPages.back().appendPoint( rStop, aLine );
7944cdf0e10cSrcweir     aLine.append( " l S\n" );
7945cdf0e10cSrcweir 
7946cdf0e10cSrcweir     writeBuffer( aLine.getStr(), aLine.getLength() );
7947cdf0e10cSrcweir }
7948cdf0e10cSrcweir 
drawLine(const Point & rStart,const Point & rStop,const LineInfo & rInfo)7949cdf0e10cSrcweir void PDFWriterImpl::drawLine( const Point& rStart, const Point& rStop, const LineInfo& rInfo )
7950cdf0e10cSrcweir {
7951cdf0e10cSrcweir     MARK( "drawLine with LineInfo" );
7952cdf0e10cSrcweir     updateGraphicsState();
7953cdf0e10cSrcweir 
7954cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) )
7955cdf0e10cSrcweir         return;
7956cdf0e10cSrcweir 
7957cdf0e10cSrcweir     if( rInfo.GetStyle() == LINE_SOLID && rInfo.GetWidth() < 2 )
7958cdf0e10cSrcweir     {
7959cdf0e10cSrcweir         drawLine( rStart, rStop );
7960cdf0e10cSrcweir         return;
7961cdf0e10cSrcweir     }
7962cdf0e10cSrcweir 
7963cdf0e10cSrcweir     OStringBuffer aLine;
7964cdf0e10cSrcweir 
7965cdf0e10cSrcweir     aLine.append( "q " );
7966cdf0e10cSrcweir     if( m_aPages.back().appendLineInfo( rInfo, aLine ) )
7967cdf0e10cSrcweir     {
7968cdf0e10cSrcweir         m_aPages.back().appendPoint( rStart, aLine );
7969cdf0e10cSrcweir         aLine.append( " m " );
7970cdf0e10cSrcweir         m_aPages.back().appendPoint( rStop, aLine );
7971cdf0e10cSrcweir         aLine.append( " l S Q\n" );
7972cdf0e10cSrcweir 
7973cdf0e10cSrcweir         writeBuffer( aLine.getStr(), aLine.getLength() );
7974cdf0e10cSrcweir     }
7975cdf0e10cSrcweir     else
7976cdf0e10cSrcweir     {
7977cdf0e10cSrcweir         PDFWriter::ExtLineInfo aInfo;
7978cdf0e10cSrcweir         convertLineInfoToExtLineInfo( rInfo, aInfo );
7979cdf0e10cSrcweir         Point aPolyPoints[2] = { rStart, rStop };
7980cdf0e10cSrcweir         Polygon aPoly( 2, aPolyPoints );
7981cdf0e10cSrcweir         drawPolyLine( aPoly, aInfo );
7982cdf0e10cSrcweir     }
7983cdf0e10cSrcweir }
7984cdf0e10cSrcweir 
drawWaveLine(const Point & rStart,const Point & rStop,sal_Int32 nDelta,sal_Int32 nLineWidth)7985cdf0e10cSrcweir void PDFWriterImpl::drawWaveLine( const Point& rStart, const Point& rStop, sal_Int32 nDelta, sal_Int32 nLineWidth )
7986cdf0e10cSrcweir {
7987cdf0e10cSrcweir     Point aDiff( rStop-rStart );
7988cdf0e10cSrcweir     double fLen = sqrt( (double)(aDiff.X()*aDiff.X() + aDiff.Y()*aDiff.Y()) );
7989cdf0e10cSrcweir     if( fLen < 1.0 )
7990cdf0e10cSrcweir         return;
7991cdf0e10cSrcweir 
7992cdf0e10cSrcweir     MARK( "drawWaveLine" );
7993cdf0e10cSrcweir     updateGraphicsState();
7994cdf0e10cSrcweir 
7995cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) )
7996cdf0e10cSrcweir         return;
7997cdf0e10cSrcweir 
7998cdf0e10cSrcweir     OStringBuffer aLine( 512 );
7999cdf0e10cSrcweir     aLine.append( "q " );
8000cdf0e10cSrcweir     m_aPages.back().appendMappedLength( nLineWidth, aLine, true );
8001cdf0e10cSrcweir     aLine.append( " w " );
8002cdf0e10cSrcweir 
8003cdf0e10cSrcweir     appendDouble( (double)aDiff.X()/fLen, aLine );
8004cdf0e10cSrcweir     aLine.append( ' ' );
8005cdf0e10cSrcweir     appendDouble( -(double)aDiff.Y()/fLen, aLine );
8006cdf0e10cSrcweir     aLine.append( ' ' );
8007cdf0e10cSrcweir     appendDouble( (double)aDiff.Y()/fLen, aLine );
8008cdf0e10cSrcweir     aLine.append( ' ' );
8009cdf0e10cSrcweir     appendDouble( (double)aDiff.X()/fLen, aLine );
8010cdf0e10cSrcweir     aLine.append( ' ' );
8011cdf0e10cSrcweir     m_aPages.back().appendPoint( rStart, aLine );
8012cdf0e10cSrcweir     aLine.append( " cm " );
8013cdf0e10cSrcweir     m_aPages.back().appendWaveLine( (sal_Int32)fLen, 0, nDelta, aLine );
8014cdf0e10cSrcweir     aLine.append( "Q\n" );
8015cdf0e10cSrcweir     writeBuffer( aLine.getStr(), aLine.getLength() );
8016cdf0e10cSrcweir }
8017cdf0e10cSrcweir 
8018cdf0e10cSrcweir #define WCONV( x ) m_pReferenceDevice->ImplDevicePixelToLogicWidth( x )
8019cdf0e10cSrcweir #define HCONV( x ) m_pReferenceDevice->ImplDevicePixelToLogicHeight( x )
8020cdf0e10cSrcweir 
drawWaveTextLine(OStringBuffer & aLine,long nWidth,FontUnderline eTextLine,Color aColor,bool bIsAbove)8021cdf0e10cSrcweir void PDFWriterImpl::drawWaveTextLine( OStringBuffer& aLine, long nWidth, FontUnderline eTextLine, Color aColor, bool bIsAbove )
8022cdf0e10cSrcweir {
8023cdf0e10cSrcweir     // note: units in pFontEntry are ref device pixel
8024cdf0e10cSrcweir     ImplFontEntry*  pFontEntry = m_pReferenceDevice->mpFontEntry;
8025cdf0e10cSrcweir     long            nLineHeight = 0;
8026cdf0e10cSrcweir     long            nLinePos = 0;
8027cdf0e10cSrcweir 
8028cdf0e10cSrcweir     appendStrokingColor( aColor, aLine );
8029cdf0e10cSrcweir     aLine.append( "\n" );
8030cdf0e10cSrcweir 
8031cdf0e10cSrcweir     if ( bIsAbove )
8032cdf0e10cSrcweir     {
8033cdf0e10cSrcweir         if ( !pFontEntry->maMetric.mnAboveWUnderlineSize )
8034cdf0e10cSrcweir             m_pReferenceDevice->ImplInitAboveTextLineSize();
8035cdf0e10cSrcweir         nLineHeight = HCONV( pFontEntry->maMetric.mnAboveWUnderlineSize );
8036cdf0e10cSrcweir         nLinePos = HCONV( pFontEntry->maMetric.mnAboveWUnderlineOffset );
8037cdf0e10cSrcweir     }
8038cdf0e10cSrcweir     else
8039cdf0e10cSrcweir     {
8040cdf0e10cSrcweir         if ( !pFontEntry->maMetric.mnWUnderlineSize )
8041cdf0e10cSrcweir             m_pReferenceDevice->ImplInitTextLineSize();
8042cdf0e10cSrcweir         nLineHeight = HCONV( pFontEntry->maMetric.mnWUnderlineSize );
8043cdf0e10cSrcweir         nLinePos = HCONV( pFontEntry->maMetric.mnWUnderlineOffset );
8044cdf0e10cSrcweir     }
8045cdf0e10cSrcweir     if ( (eTextLine == UNDERLINE_SMALLWAVE) && (nLineHeight > 3) )
8046cdf0e10cSrcweir         nLineHeight = 3;
8047cdf0e10cSrcweir 
8048cdf0e10cSrcweir     long nLineWidth = getReferenceDevice()->mnDPIX/450;
8049cdf0e10cSrcweir     if ( ! nLineWidth )
8050cdf0e10cSrcweir         nLineWidth = 1;
8051cdf0e10cSrcweir 
8052cdf0e10cSrcweir     if ( eTextLine == UNDERLINE_BOLDWAVE )
8053cdf0e10cSrcweir         nLineWidth = 3*nLineWidth;
8054cdf0e10cSrcweir 
8055cdf0e10cSrcweir     m_aPages.back().appendMappedLength( (sal_Int32)nLineWidth, aLine );
8056cdf0e10cSrcweir     aLine.append( " w " );
8057cdf0e10cSrcweir 
8058cdf0e10cSrcweir     if ( eTextLine == UNDERLINE_DOUBLEWAVE )
8059cdf0e10cSrcweir     {
8060cdf0e10cSrcweir         long nOrgLineHeight = nLineHeight;
8061cdf0e10cSrcweir         nLineHeight /= 3;
8062cdf0e10cSrcweir         if ( nLineHeight < 2 )
8063cdf0e10cSrcweir         {
8064cdf0e10cSrcweir             if ( nOrgLineHeight > 1 )
8065cdf0e10cSrcweir                 nLineHeight = 2;
8066cdf0e10cSrcweir             else
8067cdf0e10cSrcweir                 nLineHeight = 1;
8068cdf0e10cSrcweir         }
8069cdf0e10cSrcweir         long nLineDY = nOrgLineHeight-(nLineHeight*2);
8070cdf0e10cSrcweir         if ( nLineDY < nLineWidth )
8071cdf0e10cSrcweir             nLineDY = nLineWidth;
8072cdf0e10cSrcweir         long nLineDY2 = nLineDY/2;
8073cdf0e10cSrcweir         if ( !nLineDY2 )
8074cdf0e10cSrcweir             nLineDY2 = 1;
8075cdf0e10cSrcweir 
8076cdf0e10cSrcweir         nLinePos -= nLineWidth-nLineDY2;
8077cdf0e10cSrcweir 
8078cdf0e10cSrcweir         m_aPages.back().appendWaveLine( nWidth, -nLinePos, 2*nLineHeight, aLine );
8079cdf0e10cSrcweir 
8080cdf0e10cSrcweir         nLinePos += nLineWidth+nLineDY;
8081cdf0e10cSrcweir         m_aPages.back().appendWaveLine( nWidth, -nLinePos, 2*nLineHeight, aLine );
8082cdf0e10cSrcweir     }
8083cdf0e10cSrcweir     else
8084cdf0e10cSrcweir     {
8085cdf0e10cSrcweir         if ( eTextLine != UNDERLINE_BOLDWAVE )
8086cdf0e10cSrcweir             nLinePos -= nLineWidth/2;
8087cdf0e10cSrcweir         m_aPages.back().appendWaveLine( nWidth, -nLinePos, nLineHeight, aLine );
8088cdf0e10cSrcweir     }
8089cdf0e10cSrcweir }
8090cdf0e10cSrcweir 
drawStraightTextLine(OStringBuffer & aLine,long nWidth,FontUnderline eTextLine,Color aColor,bool bIsAbove)8091cdf0e10cSrcweir void PDFWriterImpl::drawStraightTextLine( OStringBuffer& aLine, long nWidth, FontUnderline eTextLine, Color aColor, bool bIsAbove )
8092cdf0e10cSrcweir {
8093cdf0e10cSrcweir     // note: units in pFontEntry are ref device pixel
8094cdf0e10cSrcweir     ImplFontEntry*  pFontEntry = m_pReferenceDevice->mpFontEntry;
8095cdf0e10cSrcweir     long            nLineHeight = 0;
8096cdf0e10cSrcweir     long            nLinePos  = 0;
8097cdf0e10cSrcweir     long            nLinePos2 = 0;
8098cdf0e10cSrcweir 
8099cdf0e10cSrcweir     if ( eTextLine > UNDERLINE_BOLDWAVE )
8100cdf0e10cSrcweir         eTextLine = UNDERLINE_SINGLE;
8101cdf0e10cSrcweir 
8102cdf0e10cSrcweir     switch ( eTextLine )
8103cdf0e10cSrcweir     {
8104cdf0e10cSrcweir         case UNDERLINE_SINGLE:
8105cdf0e10cSrcweir         case UNDERLINE_DOTTED:
8106cdf0e10cSrcweir         case UNDERLINE_DASH:
8107cdf0e10cSrcweir         case UNDERLINE_LONGDASH:
8108cdf0e10cSrcweir         case UNDERLINE_DASHDOT:
8109cdf0e10cSrcweir         case UNDERLINE_DASHDOTDOT:
8110cdf0e10cSrcweir             if ( bIsAbove )
8111cdf0e10cSrcweir             {
8112cdf0e10cSrcweir                 if ( !pFontEntry->maMetric.mnAboveUnderlineSize )
8113cdf0e10cSrcweir                     m_pReferenceDevice->ImplInitAboveTextLineSize();
8114cdf0e10cSrcweir                 nLineHeight = HCONV( pFontEntry->maMetric.mnAboveUnderlineSize );
8115cdf0e10cSrcweir                 nLinePos    = HCONV( pFontEntry->maMetric.mnAboveUnderlineOffset );
8116cdf0e10cSrcweir             }
8117cdf0e10cSrcweir             else
8118cdf0e10cSrcweir             {
8119cdf0e10cSrcweir                 if ( !pFontEntry->maMetric.mnUnderlineSize )
8120cdf0e10cSrcweir                     m_pReferenceDevice->ImplInitTextLineSize();
8121cdf0e10cSrcweir                 nLineHeight = HCONV( pFontEntry->maMetric.mnUnderlineSize );
8122cdf0e10cSrcweir                 nLinePos    = HCONV( pFontEntry->maMetric.mnUnderlineOffset );
8123cdf0e10cSrcweir             }
8124cdf0e10cSrcweir             break;
8125cdf0e10cSrcweir         case UNDERLINE_BOLD:
8126cdf0e10cSrcweir         case UNDERLINE_BOLDDOTTED:
8127cdf0e10cSrcweir         case UNDERLINE_BOLDDASH:
8128cdf0e10cSrcweir         case UNDERLINE_BOLDLONGDASH:
8129cdf0e10cSrcweir         case UNDERLINE_BOLDDASHDOT:
8130cdf0e10cSrcweir         case UNDERLINE_BOLDDASHDOTDOT:
8131cdf0e10cSrcweir             if ( bIsAbove )
8132cdf0e10cSrcweir             {
8133cdf0e10cSrcweir                 if ( !pFontEntry->maMetric.mnAboveBUnderlineSize )
8134cdf0e10cSrcweir                     m_pReferenceDevice->ImplInitAboveTextLineSize();
8135cdf0e10cSrcweir                 nLineHeight = HCONV( pFontEntry->maMetric.mnAboveBUnderlineSize );
8136cdf0e10cSrcweir                 nLinePos    = HCONV( pFontEntry->maMetric.mnAboveBUnderlineOffset );
8137cdf0e10cSrcweir             }
8138cdf0e10cSrcweir             else
8139cdf0e10cSrcweir             {
8140cdf0e10cSrcweir                 if ( !pFontEntry->maMetric.mnBUnderlineSize )
8141cdf0e10cSrcweir                     m_pReferenceDevice->ImplInitTextLineSize();
8142cdf0e10cSrcweir                 nLineHeight = HCONV( pFontEntry->maMetric.mnBUnderlineSize );
8143cdf0e10cSrcweir                 nLinePos    = HCONV( pFontEntry->maMetric.mnBUnderlineOffset );
8144cdf0e10cSrcweir                 nLinePos += nLineHeight/2;
8145cdf0e10cSrcweir             }
8146cdf0e10cSrcweir             break;
8147cdf0e10cSrcweir         case UNDERLINE_DOUBLE:
8148cdf0e10cSrcweir             if ( bIsAbove )
8149cdf0e10cSrcweir             {
8150cdf0e10cSrcweir                 if ( !pFontEntry->maMetric.mnAboveDUnderlineSize )
8151cdf0e10cSrcweir                     m_pReferenceDevice->ImplInitAboveTextLineSize();
8152cdf0e10cSrcweir                 nLineHeight = HCONV( pFontEntry->maMetric.mnAboveDUnderlineSize );
8153cdf0e10cSrcweir                 nLinePos    = HCONV( pFontEntry->maMetric.mnAboveDUnderlineOffset1 );
8154cdf0e10cSrcweir                 nLinePos2   = HCONV( pFontEntry->maMetric.mnAboveDUnderlineOffset2 );
8155cdf0e10cSrcweir             }
8156cdf0e10cSrcweir             else
8157cdf0e10cSrcweir             {
8158cdf0e10cSrcweir                 if ( !pFontEntry->maMetric.mnDUnderlineSize )
8159cdf0e10cSrcweir                     m_pReferenceDevice->ImplInitTextLineSize();
8160cdf0e10cSrcweir                 nLineHeight = HCONV( pFontEntry->maMetric.mnDUnderlineSize );
8161cdf0e10cSrcweir                 nLinePos    = HCONV( pFontEntry->maMetric.mnDUnderlineOffset1 );
8162cdf0e10cSrcweir                 nLinePos2   = HCONV( pFontEntry->maMetric.mnDUnderlineOffset2 );
8163cdf0e10cSrcweir             }
8164cdf0e10cSrcweir         default:
8165cdf0e10cSrcweir             break;
8166cdf0e10cSrcweir     }
8167cdf0e10cSrcweir 
8168cdf0e10cSrcweir     if ( nLineHeight )
8169cdf0e10cSrcweir     {
8170cdf0e10cSrcweir         m_aPages.back().appendMappedLength( (sal_Int32)nLineHeight, aLine, true );
8171cdf0e10cSrcweir         aLine.append( " w " );
8172cdf0e10cSrcweir         appendStrokingColor( aColor, aLine );
8173cdf0e10cSrcweir         aLine.append( "\n" );
8174cdf0e10cSrcweir 
8175cdf0e10cSrcweir         switch ( eTextLine )
8176cdf0e10cSrcweir         {
8177cdf0e10cSrcweir             case UNDERLINE_DOTTED:
8178cdf0e10cSrcweir             case UNDERLINE_BOLDDOTTED:
8179cdf0e10cSrcweir                 aLine.append( "[ " );
8180cdf0e10cSrcweir                 m_aPages.back().appendMappedLength( (sal_Int32)nLineHeight, aLine, false );
8181cdf0e10cSrcweir                 aLine.append( " ] 0 d\n" );
8182cdf0e10cSrcweir                 break;
8183cdf0e10cSrcweir             case UNDERLINE_DASH:
8184cdf0e10cSrcweir             case UNDERLINE_LONGDASH:
8185cdf0e10cSrcweir             case UNDERLINE_BOLDDASH:
8186cdf0e10cSrcweir             case UNDERLINE_BOLDLONGDASH:
8187cdf0e10cSrcweir                 {
8188cdf0e10cSrcweir                     sal_Int32 nDashLength = 4*nLineHeight;
8189cdf0e10cSrcweir                     sal_Int32 nVoidLength = 2*nLineHeight;
8190cdf0e10cSrcweir                     if ( ( eTextLine == UNDERLINE_LONGDASH ) || ( eTextLine == UNDERLINE_BOLDLONGDASH ) )
8191cdf0e10cSrcweir                         nDashLength = 8*nLineHeight;
8192cdf0e10cSrcweir 
8193cdf0e10cSrcweir                     aLine.append( "[ " );
8194cdf0e10cSrcweir                     m_aPages.back().appendMappedLength( nDashLength, aLine, false );
8195cdf0e10cSrcweir                     aLine.append( ' ' );
8196cdf0e10cSrcweir                     m_aPages.back().appendMappedLength( nVoidLength, aLine, false );
8197cdf0e10cSrcweir                     aLine.append( " ] 0 d\n" );
8198cdf0e10cSrcweir                 }
8199cdf0e10cSrcweir                 break;
8200cdf0e10cSrcweir             case UNDERLINE_DASHDOT:
8201cdf0e10cSrcweir             case UNDERLINE_BOLDDASHDOT:
8202cdf0e10cSrcweir                 {
8203cdf0e10cSrcweir                     sal_Int32 nDashLength = 4*nLineHeight;
8204cdf0e10cSrcweir                     sal_Int32 nVoidLength = 2*nLineHeight;
8205cdf0e10cSrcweir                     aLine.append( "[ " );
8206cdf0e10cSrcweir                     m_aPages.back().appendMappedLength( nDashLength, aLine, false );
8207cdf0e10cSrcweir                     aLine.append( ' ' );
8208cdf0e10cSrcweir                     m_aPages.back().appendMappedLength( nVoidLength, aLine, false );
8209cdf0e10cSrcweir                     aLine.append( ' ' );
8210cdf0e10cSrcweir                     m_aPages.back().appendMappedLength( (sal_Int32)nLineHeight, aLine, false );
8211cdf0e10cSrcweir                     aLine.append( ' ' );
8212cdf0e10cSrcweir                     m_aPages.back().appendMappedLength( nVoidLength, aLine, false );
8213cdf0e10cSrcweir                     aLine.append( " ] 0 d\n" );
8214cdf0e10cSrcweir                 }
8215cdf0e10cSrcweir                 break;
8216cdf0e10cSrcweir             case UNDERLINE_DASHDOTDOT:
8217cdf0e10cSrcweir             case UNDERLINE_BOLDDASHDOTDOT:
8218cdf0e10cSrcweir                 {
8219cdf0e10cSrcweir                     sal_Int32 nDashLength = 4*nLineHeight;
8220cdf0e10cSrcweir                     sal_Int32 nVoidLength = 2*nLineHeight;
8221cdf0e10cSrcweir                     aLine.append( "[ " );
8222cdf0e10cSrcweir                     m_aPages.back().appendMappedLength( nDashLength, aLine, false );
8223cdf0e10cSrcweir                     aLine.append( ' ' );
8224cdf0e10cSrcweir                     m_aPages.back().appendMappedLength( nVoidLength, aLine, false );
8225cdf0e10cSrcweir                     aLine.append( ' ' );
8226cdf0e10cSrcweir                     m_aPages.back().appendMappedLength( (sal_Int32)nLineHeight, aLine, false );
8227cdf0e10cSrcweir                     aLine.append( ' ' );
8228cdf0e10cSrcweir                     m_aPages.back().appendMappedLength( nVoidLength, aLine, false );
8229cdf0e10cSrcweir                     aLine.append( ' ' );
8230cdf0e10cSrcweir                     m_aPages.back().appendMappedLength( (sal_Int32)nLineHeight, aLine, false );
8231cdf0e10cSrcweir                     aLine.append( ' ' );
8232cdf0e10cSrcweir                     m_aPages.back().appendMappedLength( nVoidLength, aLine, false );
8233cdf0e10cSrcweir                     aLine.append( " ] 0 d\n" );
8234cdf0e10cSrcweir                 }
8235cdf0e10cSrcweir                 break;
8236cdf0e10cSrcweir             default:
8237cdf0e10cSrcweir                 break;
8238cdf0e10cSrcweir         }
8239cdf0e10cSrcweir 
8240cdf0e10cSrcweir         aLine.append( "0 " );
8241cdf0e10cSrcweir         m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos), aLine, true );
8242cdf0e10cSrcweir         aLine.append( " m " );
8243cdf0e10cSrcweir         m_aPages.back().appendMappedLength( (sal_Int32)nWidth, aLine, false );
8244cdf0e10cSrcweir         aLine.append( ' ' );
8245cdf0e10cSrcweir         m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos), aLine, true );
8246cdf0e10cSrcweir         aLine.append( " l S\n" );
8247cdf0e10cSrcweir         if ( eTextLine == UNDERLINE_DOUBLE )
8248cdf0e10cSrcweir         {
8249cdf0e10cSrcweir             aLine.append( "0 " );
8250cdf0e10cSrcweir             m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos2-nLineHeight), aLine, true );
8251cdf0e10cSrcweir             aLine.append( " m " );
8252cdf0e10cSrcweir             m_aPages.back().appendMappedLength( (sal_Int32)nWidth, aLine, false );
8253cdf0e10cSrcweir             aLine.append( ' ' );
8254cdf0e10cSrcweir             m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos2-nLineHeight), aLine, true );
8255cdf0e10cSrcweir             aLine.append( " l S\n" );
8256cdf0e10cSrcweir         }
8257cdf0e10cSrcweir     }
8258cdf0e10cSrcweir }
8259cdf0e10cSrcweir 
drawStrikeoutLine(OStringBuffer & aLine,long nWidth,FontStrikeout eStrikeout,Color aColor)8260cdf0e10cSrcweir void PDFWriterImpl::drawStrikeoutLine( OStringBuffer& aLine, long nWidth, FontStrikeout eStrikeout, Color aColor )
8261cdf0e10cSrcweir {
8262cdf0e10cSrcweir     // note: units in pFontEntry are ref device pixel
8263cdf0e10cSrcweir     ImplFontEntry*  pFontEntry = m_pReferenceDevice->mpFontEntry;
8264cdf0e10cSrcweir     long            nLineHeight = 0;
8265cdf0e10cSrcweir     long            nLinePos  = 0;
8266cdf0e10cSrcweir     long            nLinePos2 = 0;
8267cdf0e10cSrcweir 
8268cdf0e10cSrcweir     if ( eStrikeout > STRIKEOUT_X )
8269cdf0e10cSrcweir         eStrikeout = STRIKEOUT_SINGLE;
8270cdf0e10cSrcweir 
8271cdf0e10cSrcweir     switch ( eStrikeout )
8272cdf0e10cSrcweir     {
8273cdf0e10cSrcweir         case STRIKEOUT_SINGLE:
8274cdf0e10cSrcweir             if ( !pFontEntry->maMetric.mnStrikeoutSize )
8275cdf0e10cSrcweir                 m_pReferenceDevice->ImplInitTextLineSize();
8276cdf0e10cSrcweir             nLineHeight = HCONV( pFontEntry->maMetric.mnStrikeoutSize );
8277cdf0e10cSrcweir             nLinePos    = HCONV( pFontEntry->maMetric.mnStrikeoutOffset );
8278cdf0e10cSrcweir             break;
8279cdf0e10cSrcweir         case STRIKEOUT_BOLD:
8280cdf0e10cSrcweir             if ( !pFontEntry->maMetric.mnBStrikeoutSize )
8281cdf0e10cSrcweir                 m_pReferenceDevice->ImplInitTextLineSize();
8282cdf0e10cSrcweir             nLineHeight = HCONV( pFontEntry->maMetric.mnBStrikeoutSize );
8283cdf0e10cSrcweir             nLinePos    = HCONV( pFontEntry->maMetric.mnBStrikeoutOffset );
8284cdf0e10cSrcweir             break;
8285cdf0e10cSrcweir         case STRIKEOUT_DOUBLE:
8286cdf0e10cSrcweir             if ( !pFontEntry->maMetric.mnDStrikeoutSize )
8287cdf0e10cSrcweir                 m_pReferenceDevice->ImplInitTextLineSize();
8288cdf0e10cSrcweir             nLineHeight = HCONV( pFontEntry->maMetric.mnDStrikeoutSize );
8289cdf0e10cSrcweir             nLinePos    = HCONV( pFontEntry->maMetric.mnDStrikeoutOffset1 );
8290cdf0e10cSrcweir             nLinePos2   = HCONV( pFontEntry->maMetric.mnDStrikeoutOffset2 );
8291cdf0e10cSrcweir             break;
8292cdf0e10cSrcweir         default:
8293cdf0e10cSrcweir             break;
8294cdf0e10cSrcweir     }
8295cdf0e10cSrcweir 
8296cdf0e10cSrcweir     if ( nLineHeight )
8297cdf0e10cSrcweir     {
8298cdf0e10cSrcweir         m_aPages.back().appendMappedLength( (sal_Int32)nLineHeight, aLine, true );
8299cdf0e10cSrcweir         aLine.append( " w " );
8300cdf0e10cSrcweir         appendStrokingColor( aColor, aLine );
8301cdf0e10cSrcweir         aLine.append( "\n" );
8302cdf0e10cSrcweir 
8303cdf0e10cSrcweir         aLine.append( "0 " );
8304cdf0e10cSrcweir         m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos), aLine, true );
8305cdf0e10cSrcweir         aLine.append( " m " );
8306cdf0e10cSrcweir         m_aPages.back().appendMappedLength( (sal_Int32)nWidth, aLine, true );
8307cdf0e10cSrcweir         aLine.append( ' ' );
8308cdf0e10cSrcweir         m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos), aLine, true );
8309cdf0e10cSrcweir         aLine.append( " l S\n" );
8310cdf0e10cSrcweir 
8311cdf0e10cSrcweir         if ( eStrikeout == STRIKEOUT_DOUBLE )
8312cdf0e10cSrcweir         {
8313cdf0e10cSrcweir             aLine.append( "0 " );
8314cdf0e10cSrcweir             m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos2-nLineHeight), aLine, true );
8315cdf0e10cSrcweir             aLine.append( " m " );
8316cdf0e10cSrcweir             m_aPages.back().appendMappedLength( (sal_Int32)nWidth, aLine, true );
8317cdf0e10cSrcweir             aLine.append( ' ' );
8318cdf0e10cSrcweir             m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos2-nLineHeight), aLine, true );
8319cdf0e10cSrcweir             aLine.append( " l S\n" );
8320cdf0e10cSrcweir         }
8321cdf0e10cSrcweir     }
8322cdf0e10cSrcweir }
8323cdf0e10cSrcweir 
drawStrikeoutChar(const Point & rPos,long nWidth,FontStrikeout eStrikeout)8324cdf0e10cSrcweir void PDFWriterImpl::drawStrikeoutChar( const Point& rPos, long nWidth, FontStrikeout eStrikeout )
8325cdf0e10cSrcweir {
8326cdf0e10cSrcweir     String aStrikeoutChar = String::CreateFromAscii( eStrikeout == STRIKEOUT_SLASH ? "/" : "X" );
8327cdf0e10cSrcweir     String aStrikeout = aStrikeoutChar;
8328cdf0e10cSrcweir     while( m_pReferenceDevice->GetTextWidth( aStrikeout ) < nWidth )
8329cdf0e10cSrcweir         aStrikeout.Append( aStrikeout );
8330cdf0e10cSrcweir 
8331cdf0e10cSrcweir     // do not get broader than nWidth modulo 1 character
8332cdf0e10cSrcweir     while( m_pReferenceDevice->GetTextWidth( aStrikeout ) >= nWidth )
8333cdf0e10cSrcweir         aStrikeout.Erase( 0, 1 );
8334cdf0e10cSrcweir     aStrikeout.Append( aStrikeoutChar );
8335cdf0e10cSrcweir     sal_Bool bShadow = m_aCurrentPDFState.m_aFont.IsShadow();
8336cdf0e10cSrcweir     if ( bShadow )
8337cdf0e10cSrcweir     {
8338cdf0e10cSrcweir         Font aFont = m_aCurrentPDFState.m_aFont;
8339cdf0e10cSrcweir         aFont.SetShadow( sal_False );
8340cdf0e10cSrcweir         setFont( aFont );
8341cdf0e10cSrcweir         updateGraphicsState();
8342cdf0e10cSrcweir     }
8343cdf0e10cSrcweir 
8344cdf0e10cSrcweir     // strikeout string is left aligned non-CTL text
8345cdf0e10cSrcweir     sal_uLong nOrigTLM = m_pReferenceDevice->GetLayoutMode();
8346cdf0e10cSrcweir     m_pReferenceDevice->SetLayoutMode( TEXT_LAYOUT_BIDI_STRONG|TEXT_LAYOUT_COMPLEX_DISABLED );
8347cdf0e10cSrcweir     drawText( rPos, aStrikeout, 0, aStrikeout.Len(), false );
8348cdf0e10cSrcweir     m_pReferenceDevice->SetLayoutMode( nOrigTLM );
8349cdf0e10cSrcweir 
8350cdf0e10cSrcweir     if ( bShadow )
8351cdf0e10cSrcweir     {
8352cdf0e10cSrcweir         Font aFont = m_aCurrentPDFState.m_aFont;
8353cdf0e10cSrcweir         aFont.SetShadow( sal_True );
8354cdf0e10cSrcweir         setFont( aFont );
8355cdf0e10cSrcweir         updateGraphicsState();
8356cdf0e10cSrcweir     }
8357cdf0e10cSrcweir }
8358cdf0e10cSrcweir 
drawTextLine(const Point & rPos,long nWidth,FontStrikeout eStrikeout,FontUnderline eUnderline,FontUnderline eOverline,bool bUnderlineAbove)8359cdf0e10cSrcweir void PDFWriterImpl::drawTextLine( const Point& rPos, long nWidth, FontStrikeout eStrikeout, FontUnderline eUnderline, FontUnderline eOverline, bool bUnderlineAbove )
8360cdf0e10cSrcweir {
8361cdf0e10cSrcweir     if ( !nWidth ||
8362cdf0e10cSrcweir          ( ((eStrikeout == STRIKEOUT_NONE)||(eStrikeout == STRIKEOUT_DONTKNOW)) &&
8363cdf0e10cSrcweir            ((eUnderline == UNDERLINE_NONE)||(eUnderline == UNDERLINE_DONTKNOW)) &&
8364cdf0e10cSrcweir            ((eOverline  == UNDERLINE_NONE)||(eOverline  == UNDERLINE_DONTKNOW)) ) )
8365cdf0e10cSrcweir         return;
8366cdf0e10cSrcweir 
8367cdf0e10cSrcweir     MARK( "drawTextLine" );
8368cdf0e10cSrcweir     updateGraphicsState();
8369cdf0e10cSrcweir 
8370cdf0e10cSrcweir     // note: units in pFontEntry are ref device pixel
8371cdf0e10cSrcweir     ImplFontEntry*  pFontEntry = m_pReferenceDevice->mpFontEntry;
8372cdf0e10cSrcweir     Color           aUnderlineColor = m_aCurrentPDFState.m_aTextLineColor;
8373cdf0e10cSrcweir     Color           aOverlineColor  = m_aCurrentPDFState.m_aOverlineColor;
8374cdf0e10cSrcweir     Color           aStrikeoutColor = m_aCurrentPDFState.m_aFont.GetColor();
8375cdf0e10cSrcweir     bool            bStrikeoutDone = false;
8376cdf0e10cSrcweir     bool            bUnderlineDone = false;
8377cdf0e10cSrcweir     bool            bOverlineDone  = false;
8378cdf0e10cSrcweir 
8379cdf0e10cSrcweir     if ( (eStrikeout == STRIKEOUT_SLASH) || (eStrikeout == STRIKEOUT_X) )
8380cdf0e10cSrcweir     {
8381cdf0e10cSrcweir         drawStrikeoutChar( rPos, nWidth, eStrikeout );
8382cdf0e10cSrcweir         bStrikeoutDone = true;
8383cdf0e10cSrcweir     }
8384cdf0e10cSrcweir 
8385cdf0e10cSrcweir     Point aPos( rPos );
8386cdf0e10cSrcweir     TextAlign eAlign = m_aCurrentPDFState.m_aFont.GetAlign();
8387cdf0e10cSrcweir     if( eAlign == ALIGN_TOP )
8388cdf0e10cSrcweir         aPos.Y() += HCONV( pFontEntry->maMetric.mnAscent );
8389cdf0e10cSrcweir     else if( eAlign == ALIGN_BOTTOM )
8390cdf0e10cSrcweir         aPos.Y() -= HCONV( pFontEntry->maMetric.mnDescent );
8391cdf0e10cSrcweir 
8392cdf0e10cSrcweir     OStringBuffer aLine( 512 );
8393cdf0e10cSrcweir     // save GS
8394cdf0e10cSrcweir     aLine.append( "q " );
8395cdf0e10cSrcweir 
8396cdf0e10cSrcweir     // rotate and translate matrix
8397cdf0e10cSrcweir     double fAngle = (double)m_aCurrentPDFState.m_aFont.GetOrientation() * M_PI / 1800.0;
8398cdf0e10cSrcweir     Matrix3 aMat;
8399cdf0e10cSrcweir     aMat.rotate( fAngle );
8400cdf0e10cSrcweir     aMat.translate( aPos.X(), aPos.Y() );
8401cdf0e10cSrcweir     aMat.append( m_aPages.back(), aLine );
8402cdf0e10cSrcweir     aLine.append( " cm\n" );
8403cdf0e10cSrcweir 
8404cdf0e10cSrcweir     if ( aUnderlineColor.GetTransparency() != 0 )
8405cdf0e10cSrcweir         aUnderlineColor = aStrikeoutColor;
8406cdf0e10cSrcweir 
8407cdf0e10cSrcweir     if ( (eUnderline == UNDERLINE_SMALLWAVE) ||
8408cdf0e10cSrcweir          (eUnderline == UNDERLINE_WAVE) ||
8409cdf0e10cSrcweir          (eUnderline == UNDERLINE_DOUBLEWAVE) ||
8410cdf0e10cSrcweir          (eUnderline == UNDERLINE_BOLDWAVE) )
8411cdf0e10cSrcweir     {
8412cdf0e10cSrcweir         drawWaveTextLine( aLine, nWidth, eUnderline, aUnderlineColor, bUnderlineAbove );
8413cdf0e10cSrcweir         bUnderlineDone = true;
8414cdf0e10cSrcweir     }
8415cdf0e10cSrcweir 
8416cdf0e10cSrcweir     if ( (eOverline == UNDERLINE_SMALLWAVE) ||
8417cdf0e10cSrcweir          (eOverline == UNDERLINE_WAVE) ||
8418cdf0e10cSrcweir          (eOverline == UNDERLINE_DOUBLEWAVE) ||
8419cdf0e10cSrcweir          (eOverline == UNDERLINE_BOLDWAVE) )
8420cdf0e10cSrcweir     {
8421cdf0e10cSrcweir         drawWaveTextLine( aLine, nWidth, eOverline, aOverlineColor, true );
8422cdf0e10cSrcweir         bOverlineDone = true;
8423cdf0e10cSrcweir     }
8424cdf0e10cSrcweir 
8425cdf0e10cSrcweir     if ( !bUnderlineDone )
8426cdf0e10cSrcweir     {
8427cdf0e10cSrcweir         drawStraightTextLine( aLine, nWidth, eUnderline, aUnderlineColor, bUnderlineAbove );
8428cdf0e10cSrcweir     }
8429cdf0e10cSrcweir 
8430cdf0e10cSrcweir     if ( !bOverlineDone )
8431cdf0e10cSrcweir     {
8432cdf0e10cSrcweir         drawStraightTextLine( aLine, nWidth, eOverline, aOverlineColor, true );
8433cdf0e10cSrcweir     }
8434cdf0e10cSrcweir 
8435cdf0e10cSrcweir     if ( !bStrikeoutDone )
8436cdf0e10cSrcweir     {
8437cdf0e10cSrcweir         drawStrikeoutLine( aLine, nWidth, eStrikeout, aStrikeoutColor );
8438cdf0e10cSrcweir     }
8439cdf0e10cSrcweir 
8440cdf0e10cSrcweir     aLine.append( "Q\n" );
8441cdf0e10cSrcweir     writeBuffer( aLine.getStr(), aLine.getLength() );
8442cdf0e10cSrcweir }
8443cdf0e10cSrcweir 
drawPolygon(const Polygon & rPoly)8444cdf0e10cSrcweir void PDFWriterImpl::drawPolygon( const Polygon& rPoly )
8445cdf0e10cSrcweir {
8446cdf0e10cSrcweir     MARK( "drawPolygon" );
8447cdf0e10cSrcweir 
8448cdf0e10cSrcweir     updateGraphicsState();
8449cdf0e10cSrcweir 
8450cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) &&
8451cdf0e10cSrcweir         m_aGraphicsStack.front().m_aFillColor == Color( COL_TRANSPARENT ) )
8452cdf0e10cSrcweir         return;
8453cdf0e10cSrcweir 
8454cdf0e10cSrcweir     int nPoints = rPoly.GetSize();
8455cdf0e10cSrcweir     OStringBuffer aLine( 20 * nPoints );
8456cdf0e10cSrcweir     m_aPages.back().appendPolygon( rPoly, aLine );
8457cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) &&
8458cdf0e10cSrcweir         m_aGraphicsStack.front().m_aFillColor != Color( COL_TRANSPARENT ) )
8459cdf0e10cSrcweir         aLine.append( "B*\n" );
8460cdf0e10cSrcweir     else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
8461cdf0e10cSrcweir         aLine.append( "S\n" );
8462cdf0e10cSrcweir     else
8463cdf0e10cSrcweir         aLine.append( "f*\n" );
8464cdf0e10cSrcweir 
8465cdf0e10cSrcweir     writeBuffer( aLine.getStr(), aLine.getLength() );
8466cdf0e10cSrcweir }
8467cdf0e10cSrcweir 
drawPolyPolygon(const PolyPolygon & rPolyPoly)8468cdf0e10cSrcweir void PDFWriterImpl::drawPolyPolygon( const PolyPolygon& rPolyPoly )
8469cdf0e10cSrcweir {
8470cdf0e10cSrcweir     MARK( "drawPolyPolygon" );
8471cdf0e10cSrcweir 
8472cdf0e10cSrcweir     updateGraphicsState();
8473cdf0e10cSrcweir 
8474cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) &&
8475cdf0e10cSrcweir         m_aGraphicsStack.front().m_aFillColor == Color( COL_TRANSPARENT ) )
8476cdf0e10cSrcweir         return;
8477cdf0e10cSrcweir 
8478cdf0e10cSrcweir     int nPolygons = rPolyPoly.Count();
8479cdf0e10cSrcweir 
8480cdf0e10cSrcweir     OStringBuffer aLine( 40 * nPolygons );
8481cdf0e10cSrcweir     m_aPages.back().appendPolyPolygon( rPolyPoly, aLine );
8482cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) &&
8483cdf0e10cSrcweir         m_aGraphicsStack.front().m_aFillColor != Color( COL_TRANSPARENT ) )
8484cdf0e10cSrcweir         aLine.append( "B*\n" );
8485cdf0e10cSrcweir     else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
8486cdf0e10cSrcweir         aLine.append( "S\n" );
8487cdf0e10cSrcweir     else
8488cdf0e10cSrcweir         aLine.append( "f*\n" );
8489cdf0e10cSrcweir 
8490cdf0e10cSrcweir     writeBuffer( aLine.getStr(), aLine.getLength() );
8491cdf0e10cSrcweir }
8492cdf0e10cSrcweir 
drawTransparent(const PolyPolygon & rPolyPoly,sal_uInt32 nTransparentPercent)8493cdf0e10cSrcweir void PDFWriterImpl::drawTransparent( const PolyPolygon& rPolyPoly, sal_uInt32 nTransparentPercent )
8494cdf0e10cSrcweir {
8495cdf0e10cSrcweir     DBG_ASSERT( nTransparentPercent <= 100, "invalid alpha value" );
8496cdf0e10cSrcweir     nTransparentPercent = nTransparentPercent % 100;
8497cdf0e10cSrcweir 
8498cdf0e10cSrcweir     MARK( "drawTransparent" );
8499cdf0e10cSrcweir 
8500cdf0e10cSrcweir     updateGraphicsState();
8501cdf0e10cSrcweir 
8502cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) &&
8503cdf0e10cSrcweir         m_aGraphicsStack.front().m_aFillColor == Color( COL_TRANSPARENT ) )
8504cdf0e10cSrcweir         return;
8505cdf0e10cSrcweir 
8506cdf0e10cSrcweir     if( m_bIsPDF_A1 || m_aContext.Version < PDFWriter::PDF_1_4 )
8507cdf0e10cSrcweir     {
8508cdf0e10cSrcweir         m_aErrors.insert( m_bIsPDF_A1 ?
8509cdf0e10cSrcweir                           PDFWriter::Warning_Transparency_Omitted_PDFA :
8510cdf0e10cSrcweir                           PDFWriter::Warning_Transparency_Omitted_PDF13 );
8511cdf0e10cSrcweir 
8512cdf0e10cSrcweir         drawPolyPolygon( rPolyPoly );
8513cdf0e10cSrcweir         return;
8514cdf0e10cSrcweir     }
8515cdf0e10cSrcweir 
8516cdf0e10cSrcweir     // create XObject
8517cdf0e10cSrcweir     m_aTransparentObjects.push_back( TransparencyEmit() );
8518cdf0e10cSrcweir     // FIXME: polygons with beziers may yield incorrect bound rect
8519cdf0e10cSrcweir     m_aTransparentObjects.back().m_aBoundRect     = rPolyPoly.GetBoundRect();
8520cdf0e10cSrcweir     // convert rectangle to default user space
8521cdf0e10cSrcweir     m_aPages.back().convertRect( m_aTransparentObjects.back().m_aBoundRect );
8522cdf0e10cSrcweir     m_aTransparentObjects.back().m_nObject          = createObject();
8523cdf0e10cSrcweir     m_aTransparentObjects.back().m_nExtGStateObject = createObject();
8524cdf0e10cSrcweir     m_aTransparentObjects.back().m_fAlpha           = (double)(100-nTransparentPercent) / 100.0;
8525cdf0e10cSrcweir     m_aTransparentObjects.back().m_pContentStream   = new SvMemoryStream( 256, 256 );
8526cdf0e10cSrcweir     // create XObject's content stream
8527cdf0e10cSrcweir     OStringBuffer aContent( 256 );
8528cdf0e10cSrcweir     m_aPages.back().appendPolyPolygon( rPolyPoly, aContent );
8529cdf0e10cSrcweir     if( m_aCurrentPDFState.m_aLineColor != Color( COL_TRANSPARENT ) &&
8530cdf0e10cSrcweir         m_aCurrentPDFState.m_aFillColor != Color( COL_TRANSPARENT ) )
8531cdf0e10cSrcweir         aContent.append( " B*\n" );
8532cdf0e10cSrcweir     else if( m_aCurrentPDFState.m_aLineColor != Color( COL_TRANSPARENT ) )
8533cdf0e10cSrcweir         aContent.append( " S\n" );
8534cdf0e10cSrcweir     else
8535cdf0e10cSrcweir         aContent.append( " f*\n" );
8536cdf0e10cSrcweir     m_aTransparentObjects.back().m_pContentStream->Write( aContent.getStr(), aContent.getLength() );
8537cdf0e10cSrcweir 
8538cdf0e10cSrcweir     OStringBuffer aObjName( 16 );
8539cdf0e10cSrcweir     aObjName.append( "Tr" );
8540cdf0e10cSrcweir     aObjName.append( m_aTransparentObjects.back().m_nObject );
8541cdf0e10cSrcweir     OString aTrName( aObjName.makeStringAndClear() );
8542cdf0e10cSrcweir     aObjName.append( "EGS" );
8543cdf0e10cSrcweir     aObjName.append( m_aTransparentObjects.back().m_nExtGStateObject );
8544cdf0e10cSrcweir     OString aExtName( aObjName.makeStringAndClear() );
8545cdf0e10cSrcweir 
8546cdf0e10cSrcweir     OStringBuffer aLine( 80 );
8547cdf0e10cSrcweir     // insert XObject
8548cdf0e10cSrcweir     aLine.append( "q /" );
8549cdf0e10cSrcweir     aLine.append( aExtName );
8550cdf0e10cSrcweir     aLine.append( " gs /" );
8551cdf0e10cSrcweir     aLine.append( aTrName );
8552cdf0e10cSrcweir     aLine.append( " Do Q\n" );
8553cdf0e10cSrcweir     writeBuffer( aLine.getStr(), aLine.getLength() );
8554cdf0e10cSrcweir 
8555cdf0e10cSrcweir     pushResource( ResXObject, aTrName, m_aTransparentObjects.back().m_nObject );
8556cdf0e10cSrcweir     pushResource( ResExtGState, aExtName, m_aTransparentObjects.back().m_nExtGStateObject );
8557cdf0e10cSrcweir }
8558cdf0e10cSrcweir 
pushResource(ResourceKind eKind,const OString & rResource,sal_Int32 nObject)8559cdf0e10cSrcweir void PDFWriterImpl::pushResource( ResourceKind eKind, const OString& rResource, sal_Int32 nObject )
8560cdf0e10cSrcweir {
8561cdf0e10cSrcweir     if( nObject >= 0 )
8562cdf0e10cSrcweir     {
8563cdf0e10cSrcweir         switch( eKind )
8564cdf0e10cSrcweir         {
8565cdf0e10cSrcweir             case ResXObject:
8566cdf0e10cSrcweir                 m_aGlobalResourceDict.m_aXObjects[ rResource ] = nObject;
8567cdf0e10cSrcweir                 if( ! m_aOutputStreams.empty() )
8568cdf0e10cSrcweir                     m_aOutputStreams.front().m_aResourceDict.m_aXObjects[ rResource ] = nObject;
8569cdf0e10cSrcweir                 break;
8570cdf0e10cSrcweir             case ResExtGState:
8571cdf0e10cSrcweir                 m_aGlobalResourceDict.m_aExtGStates[ rResource ] = nObject;
8572cdf0e10cSrcweir                 if( ! m_aOutputStreams.empty() )
8573cdf0e10cSrcweir                     m_aOutputStreams.front().m_aResourceDict.m_aExtGStates[ rResource ] = nObject;
8574cdf0e10cSrcweir                 break;
8575cdf0e10cSrcweir             case ResShading:
8576cdf0e10cSrcweir                 m_aGlobalResourceDict.m_aShadings[ rResource ] = nObject;
8577cdf0e10cSrcweir                 if( ! m_aOutputStreams.empty() )
8578cdf0e10cSrcweir                     m_aOutputStreams.front().m_aResourceDict.m_aShadings[ rResource ] = nObject;
8579cdf0e10cSrcweir                 break;
8580cdf0e10cSrcweir             case ResPattern:
8581cdf0e10cSrcweir                 m_aGlobalResourceDict.m_aPatterns[ rResource ] = nObject;
8582cdf0e10cSrcweir                 if( ! m_aOutputStreams.empty() )
8583cdf0e10cSrcweir                     m_aOutputStreams.front().m_aResourceDict.m_aPatterns[ rResource ] = nObject;
8584cdf0e10cSrcweir                 break;
8585cdf0e10cSrcweir         }
8586cdf0e10cSrcweir     }
8587cdf0e10cSrcweir }
8588cdf0e10cSrcweir 
beginRedirect(SvStream * pStream,const Rectangle & rTargetRect)8589cdf0e10cSrcweir void PDFWriterImpl::beginRedirect( SvStream* pStream, const Rectangle& rTargetRect )
8590cdf0e10cSrcweir {
8591cdf0e10cSrcweir     push( PUSH_ALL );
8592cdf0e10cSrcweir 
8593cdf0e10cSrcweir     // force reemitting clip region
8594cdf0e10cSrcweir     clearClipRegion();
8595cdf0e10cSrcweir     updateGraphicsState();
8596cdf0e10cSrcweir 
8597cdf0e10cSrcweir     m_aOutputStreams.push_front( StreamRedirect() );
8598cdf0e10cSrcweir     m_aOutputStreams.front().m_pStream = pStream;
8599cdf0e10cSrcweir     m_aOutputStreams.front().m_aMapMode = m_aMapMode;
8600cdf0e10cSrcweir 
8601cdf0e10cSrcweir     if( !rTargetRect.IsEmpty() )
8602cdf0e10cSrcweir     {
8603cdf0e10cSrcweir         m_aOutputStreams.front().m_aTargetRect =
8604cdf0e10cSrcweir             lcl_convert( m_aGraphicsStack.front().m_aMapMode,
8605cdf0e10cSrcweir                          m_aMapMode,
8606cdf0e10cSrcweir                          getReferenceDevice(),
8607cdf0e10cSrcweir                          rTargetRect );
8608cdf0e10cSrcweir         Point aDelta = m_aOutputStreams.front().m_aTargetRect.BottomLeft();
8609cdf0e10cSrcweir         long nPageHeight = pointToPixel(m_aPages[m_nCurrentPage].getHeight());
8610cdf0e10cSrcweir         aDelta.Y() = -(nPageHeight - m_aOutputStreams.front().m_aTargetRect.Bottom());
8611cdf0e10cSrcweir         m_aMapMode.SetOrigin( m_aMapMode.GetOrigin() + aDelta );
8612cdf0e10cSrcweir     }
8613cdf0e10cSrcweir 
8614cdf0e10cSrcweir     // setup graphics state for independent object stream
8615cdf0e10cSrcweir 
8616cdf0e10cSrcweir     // force reemitting colors
8617cdf0e10cSrcweir     m_aCurrentPDFState.m_aLineColor = Color( COL_TRANSPARENT );
8618cdf0e10cSrcweir     m_aCurrentPDFState.m_aFillColor = Color( COL_TRANSPARENT );
8619cdf0e10cSrcweir }
8620cdf0e10cSrcweir 
getRedirectTargetRect() const8621cdf0e10cSrcweir Rectangle PDFWriterImpl::getRedirectTargetRect() const
8622cdf0e10cSrcweir {
8623cdf0e10cSrcweir     return m_aOutputStreams.empty() ? Rectangle() : m_aOutputStreams.front().m_aTargetRect;
8624cdf0e10cSrcweir }
8625cdf0e10cSrcweir 
endRedirect()8626cdf0e10cSrcweir SvStream* PDFWriterImpl::endRedirect()
8627cdf0e10cSrcweir {
8628cdf0e10cSrcweir     SvStream* pStream = NULL;
8629cdf0e10cSrcweir     if( ! m_aOutputStreams.empty() )
8630cdf0e10cSrcweir     {
8631cdf0e10cSrcweir         pStream     = m_aOutputStreams.front().m_pStream;
8632cdf0e10cSrcweir         m_aMapMode  = m_aOutputStreams.front().m_aMapMode;
8633cdf0e10cSrcweir         m_aOutputStreams.pop_front();
8634cdf0e10cSrcweir     }
8635cdf0e10cSrcweir 
8636cdf0e10cSrcweir     pop();
8637cdf0e10cSrcweir     // force reemitting colors and clip region
8638cdf0e10cSrcweir     clearClipRegion();
8639cdf0e10cSrcweir     m_aCurrentPDFState.m_bClipRegion = m_aGraphicsStack.front().m_bClipRegion;
8640cdf0e10cSrcweir     m_aCurrentPDFState.m_aClipRegion = m_aGraphicsStack.front().m_aClipRegion;
8641cdf0e10cSrcweir     m_aCurrentPDFState.m_aLineColor = Color( COL_TRANSPARENT );
8642cdf0e10cSrcweir     m_aCurrentPDFState.m_aFillColor = Color( COL_TRANSPARENT );
8643cdf0e10cSrcweir 
8644cdf0e10cSrcweir     updateGraphicsState();
8645cdf0e10cSrcweir 
8646cdf0e10cSrcweir     return pStream;
8647cdf0e10cSrcweir }
8648cdf0e10cSrcweir 
beginTransparencyGroup()8649cdf0e10cSrcweir void PDFWriterImpl::beginTransparencyGroup()
8650cdf0e10cSrcweir {
8651cdf0e10cSrcweir     updateGraphicsState();
8652cdf0e10cSrcweir     if( m_aContext.Version >= PDFWriter::PDF_1_4 )
8653cdf0e10cSrcweir         beginRedirect( new SvMemoryStream( 1024, 1024 ), Rectangle() );
8654cdf0e10cSrcweir }
8655cdf0e10cSrcweir 
endTransparencyGroup(const Rectangle & rBoundingBox,sal_uInt32 nTransparentPercent)8656cdf0e10cSrcweir void PDFWriterImpl::endTransparencyGroup( const Rectangle& rBoundingBox, sal_uInt32 nTransparentPercent )
8657cdf0e10cSrcweir {
8658cdf0e10cSrcweir     DBG_ASSERT( nTransparentPercent <= 100, "invalid alpha value" );
8659cdf0e10cSrcweir     nTransparentPercent = nTransparentPercent % 100;
8660cdf0e10cSrcweir 
8661cdf0e10cSrcweir     if( m_aContext.Version >= PDFWriter::PDF_1_4 )
8662cdf0e10cSrcweir     {
8663cdf0e10cSrcweir         // create XObject
8664cdf0e10cSrcweir         m_aTransparentObjects.push_back( TransparencyEmit() );
8665cdf0e10cSrcweir         m_aTransparentObjects.back().m_aBoundRect   = rBoundingBox;
8666cdf0e10cSrcweir         // convert rectangle to default user space
8667cdf0e10cSrcweir         m_aPages.back().convertRect( m_aTransparentObjects.back().m_aBoundRect );
8668cdf0e10cSrcweir         m_aTransparentObjects.back().m_nObject      = createObject();
8669cdf0e10cSrcweir         m_aTransparentObjects.back().m_fAlpha       = (double)(100-nTransparentPercent) / 100.0;
8670cdf0e10cSrcweir         // get XObject's content stream
8671cdf0e10cSrcweir         m_aTransparentObjects.back().m_pContentStream = static_cast<SvMemoryStream*>(endRedirect());
8672cdf0e10cSrcweir         m_aTransparentObjects.back().m_nExtGStateObject = createObject();
8673cdf0e10cSrcweir 
8674cdf0e10cSrcweir         OStringBuffer aObjName( 16 );
8675cdf0e10cSrcweir         aObjName.append( "Tr" );
8676cdf0e10cSrcweir         aObjName.append( m_aTransparentObjects.back().m_nObject );
8677cdf0e10cSrcweir         OString aTrName( aObjName.makeStringAndClear() );
8678cdf0e10cSrcweir         aObjName.append( "EGS" );
8679cdf0e10cSrcweir         aObjName.append( m_aTransparentObjects.back().m_nExtGStateObject );
8680cdf0e10cSrcweir         OString aExtName( aObjName.makeStringAndClear() );
8681cdf0e10cSrcweir 
8682cdf0e10cSrcweir         OStringBuffer aLine( 80 );
8683cdf0e10cSrcweir         // insert XObject
8684cdf0e10cSrcweir         aLine.append( "q /" );
8685cdf0e10cSrcweir         aLine.append( aExtName );
8686cdf0e10cSrcweir         aLine.append( " gs /" );
8687cdf0e10cSrcweir         aLine.append( aTrName );
8688cdf0e10cSrcweir         aLine.append( " Do Q\n" );
8689cdf0e10cSrcweir         writeBuffer( aLine.getStr(), aLine.getLength() );
8690cdf0e10cSrcweir 
8691cdf0e10cSrcweir         pushResource( ResXObject, aTrName, m_aTransparentObjects.back().m_nObject );
8692cdf0e10cSrcweir         pushResource( ResExtGState, aExtName, m_aTransparentObjects.back().m_nExtGStateObject );
8693cdf0e10cSrcweir     }
8694cdf0e10cSrcweir }
8695cdf0e10cSrcweir 
endTransparencyGroup(const Rectangle & rBoundingBox,const Bitmap & rAlphaMask)8696cdf0e10cSrcweir void PDFWriterImpl::endTransparencyGroup( const Rectangle& rBoundingBox, const Bitmap& rAlphaMask )
8697cdf0e10cSrcweir {
8698cdf0e10cSrcweir     if( m_aContext.Version >= PDFWriter::PDF_1_4 )
8699cdf0e10cSrcweir     {
8700cdf0e10cSrcweir         // create XObject
8701cdf0e10cSrcweir         m_aTransparentObjects.push_back( TransparencyEmit() );
8702cdf0e10cSrcweir         m_aTransparentObjects.back().m_aBoundRect   = rBoundingBox;
8703cdf0e10cSrcweir         // convert rectangle to default user space
8704cdf0e10cSrcweir         m_aPages.back().convertRect( m_aTransparentObjects.back().m_aBoundRect );
8705cdf0e10cSrcweir         m_aTransparentObjects.back().m_nObject      = createObject();
8706cdf0e10cSrcweir         m_aTransparentObjects.back().m_fAlpha       = 0.0;
8707cdf0e10cSrcweir         // get XObject's content stream
8708cdf0e10cSrcweir         m_aTransparentObjects.back().m_pContentStream = static_cast<SvMemoryStream*>(endRedirect());
8709cdf0e10cSrcweir         m_aTransparentObjects.back().m_nExtGStateObject = createObject();
8710cdf0e10cSrcweir 
8711cdf0e10cSrcweir         // draw soft mask
8712cdf0e10cSrcweir         beginRedirect( new SvMemoryStream( 1024, 1024 ), Rectangle() );
8713cdf0e10cSrcweir         drawBitmap( rBoundingBox.TopLeft(), rBoundingBox.GetSize(), rAlphaMask );
8714cdf0e10cSrcweir         m_aTransparentObjects.back().m_pSoftMaskStream = static_cast<SvMemoryStream*>(endRedirect());
8715cdf0e10cSrcweir 
8716cdf0e10cSrcweir         OStringBuffer aObjName( 16 );
8717cdf0e10cSrcweir         aObjName.append( "Tr" );
8718cdf0e10cSrcweir         aObjName.append( m_aTransparentObjects.back().m_nObject );
8719cdf0e10cSrcweir         OString aTrName( aObjName.makeStringAndClear() );
8720cdf0e10cSrcweir         aObjName.append( "EGS" );
8721cdf0e10cSrcweir         aObjName.append( m_aTransparentObjects.back().m_nExtGStateObject );
8722cdf0e10cSrcweir         OString aExtName( aObjName.makeStringAndClear() );
8723cdf0e10cSrcweir 
8724cdf0e10cSrcweir         OStringBuffer aLine( 80 );
8725cdf0e10cSrcweir         // insert XObject
8726cdf0e10cSrcweir         aLine.append( "q /" );
8727cdf0e10cSrcweir         aLine.append( aExtName );
8728cdf0e10cSrcweir         aLine.append( " gs /" );
8729cdf0e10cSrcweir         aLine.append( aTrName );
8730cdf0e10cSrcweir         aLine.append( " Do Q\n" );
8731cdf0e10cSrcweir         writeBuffer( aLine.getStr(), aLine.getLength() );
8732cdf0e10cSrcweir 
8733cdf0e10cSrcweir         pushResource( ResXObject, aTrName, m_aTransparentObjects.back().m_nObject );
8734cdf0e10cSrcweir         pushResource( ResExtGState, aExtName, m_aTransparentObjects.back().m_nExtGStateObject );
8735cdf0e10cSrcweir     }
8736cdf0e10cSrcweir }
8737cdf0e10cSrcweir 
drawRectangle(const Rectangle & rRect)8738cdf0e10cSrcweir void PDFWriterImpl::drawRectangle( const Rectangle& rRect )
8739cdf0e10cSrcweir {
8740cdf0e10cSrcweir     MARK( "drawRectangle" );
8741cdf0e10cSrcweir 
8742cdf0e10cSrcweir     updateGraphicsState();
8743cdf0e10cSrcweir 
8744cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) &&
8745cdf0e10cSrcweir         m_aGraphicsStack.front().m_aFillColor == Color( COL_TRANSPARENT ) )
8746cdf0e10cSrcweir         return;
8747cdf0e10cSrcweir 
8748cdf0e10cSrcweir     OStringBuffer aLine( 40 );
8749cdf0e10cSrcweir     m_aPages.back().appendRect( rRect, aLine );
8750cdf0e10cSrcweir 
8751cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) &&
8752cdf0e10cSrcweir         m_aGraphicsStack.front().m_aFillColor != Color( COL_TRANSPARENT ) )
8753cdf0e10cSrcweir         aLine.append( " B*\n" );
8754cdf0e10cSrcweir     else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
8755cdf0e10cSrcweir         aLine.append( " S\n" );
8756cdf0e10cSrcweir     else
8757cdf0e10cSrcweir         aLine.append( " f*\n" );
8758cdf0e10cSrcweir 
8759cdf0e10cSrcweir     writeBuffer( aLine.getStr(), aLine.getLength() );
8760cdf0e10cSrcweir }
8761cdf0e10cSrcweir 
drawRectangle(const Rectangle & rRect,sal_uInt32 nHorzRound,sal_uInt32 nVertRound)8762cdf0e10cSrcweir void PDFWriterImpl::drawRectangle( const Rectangle& rRect, sal_uInt32 nHorzRound, sal_uInt32 nVertRound )
8763cdf0e10cSrcweir {
8764cdf0e10cSrcweir     MARK( "drawRectangle with rounded edges" );
8765cdf0e10cSrcweir 
8766cdf0e10cSrcweir     if( !nHorzRound && !nVertRound )
8767cdf0e10cSrcweir         drawRectangle( rRect );
8768cdf0e10cSrcweir 
8769cdf0e10cSrcweir     updateGraphicsState();
8770cdf0e10cSrcweir 
8771cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) &&
8772cdf0e10cSrcweir         m_aGraphicsStack.front().m_aFillColor == Color( COL_TRANSPARENT ) )
8773cdf0e10cSrcweir         return;
8774cdf0e10cSrcweir 
8775cdf0e10cSrcweir     if( nHorzRound > (sal_uInt32)rRect.GetWidth()/2 )
8776cdf0e10cSrcweir         nHorzRound = rRect.GetWidth()/2;
8777cdf0e10cSrcweir     if( nVertRound > (sal_uInt32)rRect.GetHeight()/2 )
8778cdf0e10cSrcweir         nVertRound = rRect.GetHeight()/2;
8779cdf0e10cSrcweir 
8780cdf0e10cSrcweir     Point aPoints[16];
8781cdf0e10cSrcweir     const double kappa = 0.5522847498;
8782cdf0e10cSrcweir     const sal_uInt32 kx = (sal_uInt32)((kappa*(double)nHorzRound)+0.5);
8783cdf0e10cSrcweir     const sal_uInt32 ky = (sal_uInt32)((kappa*(double)nVertRound)+0.5);
8784cdf0e10cSrcweir 
8785cdf0e10cSrcweir     aPoints[1]  = Point( rRect.TopLeft().X() + nHorzRound, rRect.TopLeft().Y() );
8786cdf0e10cSrcweir     aPoints[0]  = Point( aPoints[1].X() - kx, aPoints[1].Y() );
8787cdf0e10cSrcweir     aPoints[2]  = Point( rRect.TopRight().X()+1 - nHorzRound, aPoints[1].Y() );
8788cdf0e10cSrcweir     aPoints[3]  = Point( aPoints[2].X()+kx, aPoints[2].Y() );
8789cdf0e10cSrcweir 
8790cdf0e10cSrcweir     aPoints[5]  = Point( rRect.TopRight().X()+1, rRect.TopRight().Y()+nVertRound );
8791cdf0e10cSrcweir     aPoints[4]  = Point( aPoints[5].X(), aPoints[5].Y()-ky );
8792cdf0e10cSrcweir     aPoints[6]  = Point( aPoints[5].X(), rRect.BottomRight().Y()+1 - nVertRound );
8793cdf0e10cSrcweir     aPoints[7]  = Point( aPoints[6].X(), aPoints[6].Y()+ky );
8794cdf0e10cSrcweir 
8795cdf0e10cSrcweir     aPoints[9]  = Point( rRect.BottomRight().X()+1-nHorzRound, rRect.BottomRight().Y()+1 );
8796cdf0e10cSrcweir     aPoints[8]  = Point( aPoints[9].X()+kx, aPoints[9].Y() );
8797cdf0e10cSrcweir     aPoints[10] = Point( rRect.BottomLeft().X() + nHorzRound, aPoints[9].Y() );
8798cdf0e10cSrcweir     aPoints[11] = Point( aPoints[10].X()-kx, aPoints[10].Y() );
8799cdf0e10cSrcweir 
8800cdf0e10cSrcweir     aPoints[13] = Point( rRect.BottomLeft().X(), rRect.BottomLeft().Y()+1-nVertRound );
8801cdf0e10cSrcweir     aPoints[12] = Point( aPoints[13].X(), aPoints[13].Y()+ky );
8802cdf0e10cSrcweir     aPoints[14] = Point( rRect.TopLeft().X(), rRect.TopLeft().Y()+nVertRound );
8803cdf0e10cSrcweir     aPoints[15] = Point( aPoints[14].X(), aPoints[14].Y()-ky );
8804cdf0e10cSrcweir 
8805cdf0e10cSrcweir 
8806cdf0e10cSrcweir     OStringBuffer aLine( 80 );
8807cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[1], aLine );
8808cdf0e10cSrcweir     aLine.append( " m " );
8809cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[2], aLine );
8810cdf0e10cSrcweir     aLine.append( " l " );
8811cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[3], aLine );
8812cdf0e10cSrcweir     aLine.append( ' ' );
8813cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[4], aLine );
8814cdf0e10cSrcweir     aLine.append( ' ' );
8815cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[5], aLine );
8816cdf0e10cSrcweir     aLine.append( " c\n" );
8817cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[6], aLine );
8818cdf0e10cSrcweir     aLine.append( " l " );
8819cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[7], aLine );
8820cdf0e10cSrcweir     aLine.append( ' ' );
8821cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[8], aLine );
8822cdf0e10cSrcweir     aLine.append( ' ' );
8823cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[9], aLine );
8824cdf0e10cSrcweir     aLine.append( " c\n" );
8825cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[10], aLine );
8826cdf0e10cSrcweir     aLine.append( " l " );
8827cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[11], aLine );
8828cdf0e10cSrcweir     aLine.append( ' ' );
8829cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[12], aLine );
8830cdf0e10cSrcweir     aLine.append( ' ' );
8831cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[13], aLine );
8832cdf0e10cSrcweir     aLine.append( " c\n" );
8833cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[14], aLine );
8834cdf0e10cSrcweir     aLine.append( " l " );
8835cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[15], aLine );
8836cdf0e10cSrcweir     aLine.append( ' ' );
8837cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[0], aLine );
8838cdf0e10cSrcweir     aLine.append( ' ' );
8839cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[1], aLine );
8840cdf0e10cSrcweir     aLine.append( " c " );
8841cdf0e10cSrcweir 
8842cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) &&
8843cdf0e10cSrcweir         m_aGraphicsStack.front().m_aFillColor != Color( COL_TRANSPARENT ) )
8844cdf0e10cSrcweir         aLine.append( "b*\n" );
8845cdf0e10cSrcweir     else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
8846cdf0e10cSrcweir         aLine.append( "s\n" );
8847cdf0e10cSrcweir     else
8848cdf0e10cSrcweir         aLine.append( "f*\n" );
8849cdf0e10cSrcweir 
8850cdf0e10cSrcweir     writeBuffer( aLine.getStr(), aLine.getLength() );
8851cdf0e10cSrcweir }
8852cdf0e10cSrcweir 
drawEllipse(const Rectangle & rRect)8853cdf0e10cSrcweir void PDFWriterImpl::drawEllipse( const Rectangle& rRect )
8854cdf0e10cSrcweir {
8855cdf0e10cSrcweir     MARK( "drawEllipse" );
8856cdf0e10cSrcweir 
8857cdf0e10cSrcweir     updateGraphicsState();
8858cdf0e10cSrcweir 
8859cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) &&
8860cdf0e10cSrcweir         m_aGraphicsStack.front().m_aFillColor == Color( COL_TRANSPARENT ) )
8861cdf0e10cSrcweir         return;
8862cdf0e10cSrcweir 
8863cdf0e10cSrcweir     Point aPoints[12];
8864cdf0e10cSrcweir     const double kappa = 0.5522847498;
8865cdf0e10cSrcweir     const sal_uInt32 kx = (sal_uInt32)((kappa*(double)rRect.GetWidth()/2.0)+0.5);
8866cdf0e10cSrcweir     const sal_uInt32 ky = (sal_uInt32)((kappa*(double)rRect.GetHeight()/2.0)+0.5);
8867cdf0e10cSrcweir 
8868cdf0e10cSrcweir     aPoints[1]  = Point( rRect.TopLeft().X() + rRect.GetWidth()/2, rRect.TopLeft().Y() );
8869cdf0e10cSrcweir     aPoints[0]  = Point( aPoints[1].X() - kx, aPoints[1].Y() );
8870cdf0e10cSrcweir     aPoints[2]  = Point( aPoints[1].X() + kx, aPoints[1].Y() );
8871cdf0e10cSrcweir 
8872cdf0e10cSrcweir     aPoints[4]  = Point( rRect.TopRight().X()+1, rRect.TopRight().Y() + rRect.GetHeight()/2 );
8873cdf0e10cSrcweir     aPoints[3]  = Point( aPoints[4].X(), aPoints[4].Y() - ky );
8874cdf0e10cSrcweir     aPoints[5]  = Point( aPoints[4].X(), aPoints[4].Y() + ky );
8875cdf0e10cSrcweir 
8876cdf0e10cSrcweir     aPoints[7]  = Point( rRect.BottomLeft().X() + rRect.GetWidth()/2, rRect.BottomLeft().Y()+1 );
8877cdf0e10cSrcweir     aPoints[6]  = Point( aPoints[7].X() + kx, aPoints[7].Y() );
8878cdf0e10cSrcweir     aPoints[8]  = Point( aPoints[7].X() - kx, aPoints[7].Y() );
8879cdf0e10cSrcweir 
8880cdf0e10cSrcweir     aPoints[10] = Point( rRect.TopLeft().X(), rRect.TopLeft().Y() + rRect.GetHeight()/2 );
8881cdf0e10cSrcweir     aPoints[9]  = Point( aPoints[10].X(), aPoints[10].Y() + ky );
8882cdf0e10cSrcweir     aPoints[11] = Point( aPoints[10].X(), aPoints[10].Y() - ky );
8883cdf0e10cSrcweir 
8884cdf0e10cSrcweir     OStringBuffer aLine( 80 );
8885cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[1], aLine );
8886cdf0e10cSrcweir     aLine.append( " m " );
8887cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[2], aLine );
8888cdf0e10cSrcweir     aLine.append( ' ' );
8889cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[3], aLine );
8890cdf0e10cSrcweir     aLine.append( ' ' );
8891cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[4], aLine );
8892cdf0e10cSrcweir     aLine.append( " c\n" );
8893cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[5], aLine );
8894cdf0e10cSrcweir     aLine.append( ' ' );
8895cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[6], aLine );
8896cdf0e10cSrcweir     aLine.append( ' ' );
8897cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[7], aLine );
8898cdf0e10cSrcweir     aLine.append( " c\n" );
8899cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[8], aLine );
8900cdf0e10cSrcweir     aLine.append( ' ' );
8901cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[9], aLine );
8902cdf0e10cSrcweir     aLine.append( ' ' );
8903cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[10], aLine );
8904cdf0e10cSrcweir     aLine.append( " c\n" );
8905cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[11], aLine );
8906cdf0e10cSrcweir     aLine.append( ' ' );
8907cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[0], aLine );
8908cdf0e10cSrcweir     aLine.append( ' ' );
8909cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoints[1], aLine );
8910cdf0e10cSrcweir     aLine.append( " c " );
8911cdf0e10cSrcweir 
8912cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) &&
8913cdf0e10cSrcweir         m_aGraphicsStack.front().m_aFillColor != Color( COL_TRANSPARENT ) )
8914cdf0e10cSrcweir         aLine.append( "b*\n" );
8915cdf0e10cSrcweir     else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
8916cdf0e10cSrcweir         aLine.append( "s\n" );
8917cdf0e10cSrcweir     else
8918cdf0e10cSrcweir         aLine.append( "f*\n" );
8919cdf0e10cSrcweir 
8920cdf0e10cSrcweir     writeBuffer( aLine.getStr(), aLine.getLength() );
8921cdf0e10cSrcweir }
8922cdf0e10cSrcweir 
calcAngle(const Rectangle & rRect,const Point & rPoint)8923cdf0e10cSrcweir static double calcAngle( const Rectangle& rRect, const Point& rPoint )
8924cdf0e10cSrcweir {
8925cdf0e10cSrcweir     Point aOrigin((rRect.Left()+rRect.Right()+1)/2,
8926cdf0e10cSrcweir                   (rRect.Top()+rRect.Bottom()+1)/2);
8927cdf0e10cSrcweir     Point aPoint = rPoint - aOrigin;
8928cdf0e10cSrcweir 
8929cdf0e10cSrcweir     double fX = (double)aPoint.X();
8930cdf0e10cSrcweir     double fY = (double)-aPoint.Y();
8931cdf0e10cSrcweir 
8932487b2be3SPedro Giffuni     if((rRect.GetWidth() > rRect.GetHeight()) && (rRect.GetHeight() != 0 ))
8933cdf0e10cSrcweir         fY = fY*((double)rRect.GetWidth()/(double)rRect.GetHeight());
8934487b2be3SPedro Giffuni     else if((rRect.GetHeight() > rRect.GetWidth()) && (rRect.GetWidth() != 0))
8935cdf0e10cSrcweir         fX = fX*((double)rRect.GetHeight()/(double)rRect.GetWidth());
8936cdf0e10cSrcweir     return atan2( fY, fX );
8937cdf0e10cSrcweir }
8938cdf0e10cSrcweir 
drawArc(const Rectangle & rRect,const Point & rStart,const Point & rStop,bool bWithPie,bool bWithChord)8939cdf0e10cSrcweir void PDFWriterImpl::drawArc( const Rectangle& rRect, const Point& rStart, const Point& rStop, bool bWithPie, bool bWithChord )
8940cdf0e10cSrcweir {
8941cdf0e10cSrcweir     MARK( "drawArc" );
8942cdf0e10cSrcweir 
8943cdf0e10cSrcweir     updateGraphicsState();
8944cdf0e10cSrcweir 
8945cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) &&
8946cdf0e10cSrcweir         m_aGraphicsStack.front().m_aFillColor == Color( COL_TRANSPARENT ) )
8947cdf0e10cSrcweir         return;
8948cdf0e10cSrcweir 
8949cdf0e10cSrcweir     // calculate start and stop angles
8950cdf0e10cSrcweir     const double fStartAngle = calcAngle( rRect, rStart );
8951cdf0e10cSrcweir     double fStopAngle  = calcAngle( rRect, rStop );
8952cdf0e10cSrcweir     while( fStopAngle < fStartAngle )
8953cdf0e10cSrcweir         fStopAngle += 2.0*M_PI;
8954cdf0e10cSrcweir     const int nFragments = (int)((fStopAngle-fStartAngle)/(M_PI/2.0))+1;
8955cdf0e10cSrcweir     const double fFragmentDelta = (fStopAngle-fStartAngle)/(double)nFragments;
8956cdf0e10cSrcweir     const double kappa = fabs( 4.0 * (1.0-cos(fFragmentDelta/2.0))/sin(fFragmentDelta/2.0) / 3.0);
8957cdf0e10cSrcweir     const double halfWidth = (double)rRect.GetWidth()/2.0;
8958cdf0e10cSrcweir     const double halfHeight = (double)rRect.GetHeight()/2.0;
8959cdf0e10cSrcweir 
8960cdf0e10cSrcweir     const Point aCenter( (rRect.Left()+rRect.Right()+1)/2,
8961cdf0e10cSrcweir                          (rRect.Top()+rRect.Bottom()+1)/2 );
8962cdf0e10cSrcweir 
8963cdf0e10cSrcweir     OStringBuffer aLine( 30*nFragments );
8964cdf0e10cSrcweir     Point aPoint( (int)(halfWidth * cos(fStartAngle) ),
8965cdf0e10cSrcweir                   -(int)(halfHeight * sin(fStartAngle) ) );
8966cdf0e10cSrcweir     aPoint += aCenter;
8967cdf0e10cSrcweir     m_aPages.back().appendPoint( aPoint, aLine );
8968cdf0e10cSrcweir     aLine.append( " m " );
8969cdf0e10cSrcweir     if( !basegfx::fTools::equal(fStartAngle, fStopAngle) )
8970cdf0e10cSrcweir     {
8971cdf0e10cSrcweir         for( int i = 0; i < nFragments; i++ )
8972cdf0e10cSrcweir         {
8973cdf0e10cSrcweir             const double fStartFragment = fStartAngle + (double)i*fFragmentDelta;
8974cdf0e10cSrcweir             const double fStopFragment = fStartFragment + fFragmentDelta;
8975cdf0e10cSrcweir             aPoint = Point( (int)(halfWidth * (cos(fStartFragment) - kappa*sin(fStartFragment) ) ),
8976cdf0e10cSrcweir                             -(int)(halfHeight * (sin(fStartFragment) + kappa*cos(fStartFragment) ) ) );
8977cdf0e10cSrcweir             aPoint += aCenter;
8978cdf0e10cSrcweir             m_aPages.back().appendPoint( aPoint, aLine );
8979cdf0e10cSrcweir             aLine.append( ' ' );
8980cdf0e10cSrcweir 
8981cdf0e10cSrcweir             aPoint = Point( (int)(halfWidth * (cos(fStopFragment) + kappa*sin(fStopFragment) ) ),
8982cdf0e10cSrcweir                             -(int)(halfHeight * (sin(fStopFragment) - kappa*cos(fStopFragment) ) ) );
8983cdf0e10cSrcweir             aPoint += aCenter;
8984cdf0e10cSrcweir             m_aPages.back().appendPoint( aPoint, aLine );
8985cdf0e10cSrcweir             aLine.append( ' ' );
8986cdf0e10cSrcweir 
8987cdf0e10cSrcweir             aPoint = Point( (int)(halfWidth * cos(fStopFragment) ),
8988cdf0e10cSrcweir                             -(int)(halfHeight * sin(fStopFragment) ) );
8989cdf0e10cSrcweir             aPoint += aCenter;
8990cdf0e10cSrcweir             m_aPages.back().appendPoint( aPoint, aLine );
8991cdf0e10cSrcweir             aLine.append( " c\n" );
8992cdf0e10cSrcweir         }
8993cdf0e10cSrcweir     }
8994cdf0e10cSrcweir     if( bWithChord || bWithPie )
8995cdf0e10cSrcweir     {
8996cdf0e10cSrcweir         if( bWithPie )
8997cdf0e10cSrcweir         {
8998cdf0e10cSrcweir             m_aPages.back().appendPoint( aCenter, aLine );
8999cdf0e10cSrcweir             aLine.append( " l " );
9000cdf0e10cSrcweir         }
9001cdf0e10cSrcweir         aLine.append( "h " );
9002cdf0e10cSrcweir     }
9003cdf0e10cSrcweir     if( ! bWithChord && ! bWithPie )
9004cdf0e10cSrcweir         aLine.append( "S\n" );
9005cdf0e10cSrcweir     else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) &&
9006cdf0e10cSrcweir         m_aGraphicsStack.front().m_aFillColor != Color( COL_TRANSPARENT ) )
9007cdf0e10cSrcweir         aLine.append( "B*\n" );
9008cdf0e10cSrcweir     else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
9009cdf0e10cSrcweir         aLine.append( "S\n" );
9010cdf0e10cSrcweir     else
9011cdf0e10cSrcweir         aLine.append( "f*\n" );
9012cdf0e10cSrcweir 
9013cdf0e10cSrcweir     writeBuffer( aLine.getStr(), aLine.getLength() );
9014cdf0e10cSrcweir }
9015cdf0e10cSrcweir 
drawPolyLine(const Polygon & rPoly)9016cdf0e10cSrcweir void PDFWriterImpl::drawPolyLine( const Polygon& rPoly )
9017cdf0e10cSrcweir {
9018cdf0e10cSrcweir     MARK( "drawPolyLine" );
9019cdf0e10cSrcweir 
9020cdf0e10cSrcweir     sal_uInt16 nPoints = rPoly.GetSize();
9021cdf0e10cSrcweir     if( nPoints < 2 )
9022cdf0e10cSrcweir         return;
9023cdf0e10cSrcweir 
9024cdf0e10cSrcweir     updateGraphicsState();
9025cdf0e10cSrcweir 
9026cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) )
9027cdf0e10cSrcweir         return;
9028cdf0e10cSrcweir 
9029cdf0e10cSrcweir     OStringBuffer aLine( 20 * nPoints );
9030cdf0e10cSrcweir     m_aPages.back().appendPolygon( rPoly, aLine, rPoly[0] == rPoly[nPoints-1] );
9031cdf0e10cSrcweir     aLine.append( "S\n" );
9032cdf0e10cSrcweir 
9033cdf0e10cSrcweir     writeBuffer( aLine.getStr(), aLine.getLength() );
9034cdf0e10cSrcweir }
9035cdf0e10cSrcweir 
drawPolyLine(const Polygon & rPoly,const LineInfo & rInfo)9036cdf0e10cSrcweir void PDFWriterImpl::drawPolyLine( const Polygon& rPoly, const LineInfo& rInfo )
9037cdf0e10cSrcweir {
9038cdf0e10cSrcweir     MARK( "drawPolyLine with LineInfo" );
9039cdf0e10cSrcweir 
9040cdf0e10cSrcweir     updateGraphicsState();
9041cdf0e10cSrcweir 
9042cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) )
9043cdf0e10cSrcweir         return;
9044cdf0e10cSrcweir 
9045cdf0e10cSrcweir     OStringBuffer aLine;
9046cdf0e10cSrcweir     aLine.append( "q " );
9047cdf0e10cSrcweir     if( m_aPages.back().appendLineInfo( rInfo, aLine ) )
9048cdf0e10cSrcweir     {
9049cdf0e10cSrcweir         writeBuffer( aLine.getStr(), aLine.getLength() );
9050cdf0e10cSrcweir         drawPolyLine( rPoly );
9051cdf0e10cSrcweir         writeBuffer( "Q\n", 2 );
9052cdf0e10cSrcweir     }
9053cdf0e10cSrcweir     else
9054cdf0e10cSrcweir     {
9055cdf0e10cSrcweir         PDFWriter::ExtLineInfo aInfo;
9056cdf0e10cSrcweir         convertLineInfoToExtLineInfo( rInfo, aInfo );
9057cdf0e10cSrcweir         drawPolyLine( rPoly, aInfo );
9058cdf0e10cSrcweir     }
9059cdf0e10cSrcweir }
9060cdf0e10cSrcweir 
convertLineInfoToExtLineInfo(const LineInfo & rIn,PDFWriter::ExtLineInfo & rOut)9061cdf0e10cSrcweir void PDFWriterImpl::convertLineInfoToExtLineInfo( const LineInfo& rIn, PDFWriter::ExtLineInfo& rOut )
9062cdf0e10cSrcweir {
9063cdf0e10cSrcweir     DBG_ASSERT( rIn.GetStyle() == LINE_DASH, "invalid conversion" );
9064cdf0e10cSrcweir     rOut.m_fLineWidth           = rIn.GetWidth();
9065cdf0e10cSrcweir     rOut.m_fTransparency        = 0.0;
9066cdf0e10cSrcweir     rOut.m_eCap                 = PDFWriter::capButt;
9067cdf0e10cSrcweir     rOut.m_eJoin                = PDFWriter::joinMiter;
9068cdf0e10cSrcweir     rOut.m_fMiterLimit          = 10;
9069cdf0e10cSrcweir     rOut.m_aDashArray.clear();
9070cdf0e10cSrcweir 
90715aaf853bSArmin Le Grand     // add DashDot to DashArray
90725aaf853bSArmin Le Grand     const int nDashes     = rIn.GetDashCount();
90735aaf853bSArmin Le Grand     const int nDashLen    = rIn.GetDashLen();
90745aaf853bSArmin Le Grand     const int nDistance   = rIn.GetDistance();
90755aaf853bSArmin Le Grand 
9076cdf0e10cSrcweir     for( int n  = 0; n < nDashes; n++ )
9077cdf0e10cSrcweir     {
9078cdf0e10cSrcweir         rOut.m_aDashArray.push_back( nDashLen );
9079cdf0e10cSrcweir         rOut.m_aDashArray.push_back( nDistance );
9080cdf0e10cSrcweir     }
90815aaf853bSArmin Le Grand 
90825aaf853bSArmin Le Grand     const int nDots       = rIn.GetDotCount();
90835aaf853bSArmin Le Grand     const int nDotLen     = rIn.GetDotLen();
90845aaf853bSArmin Le Grand 
9085cdf0e10cSrcweir     for( int n  = 0; n < nDots; n++ )
9086cdf0e10cSrcweir     {
9087cdf0e10cSrcweir         rOut.m_aDashArray.push_back( nDotLen );
9088cdf0e10cSrcweir         rOut.m_aDashArray.push_back( nDistance );
9089cdf0e10cSrcweir     }
90905aaf853bSArmin Le Grand 
90915aaf853bSArmin Le Grand     // add LineJoin
90925aaf853bSArmin Le Grand     switch(rIn.GetLineJoin())
90935aaf853bSArmin Le Grand     {
90945aaf853bSArmin Le Grand         case basegfx::B2DLINEJOIN_BEVEL :
90955aaf853bSArmin Le Grand         {
90965aaf853bSArmin Le Grand             rOut.m_eJoin = PDFWriter::joinBevel;
90975aaf853bSArmin Le Grand             break;
90985aaf853bSArmin Le Grand         }
90995aaf853bSArmin Le Grand         default : // basegfx::B2DLINEJOIN_NONE :
91005aaf853bSArmin Le Grand         // Pdf has no 'none' lineJoin, default is miter
91015aaf853bSArmin Le Grand         case basegfx::B2DLINEJOIN_MIDDLE :
91025aaf853bSArmin Le Grand         case basegfx::B2DLINEJOIN_MITER :
91035aaf853bSArmin Le Grand         {
91045aaf853bSArmin Le Grand             rOut.m_eJoin = PDFWriter::joinMiter;
91055aaf853bSArmin Le Grand             break;
91065aaf853bSArmin Le Grand         }
91075aaf853bSArmin Le Grand         case basegfx::B2DLINEJOIN_ROUND :
91085aaf853bSArmin Le Grand         {
91095aaf853bSArmin Le Grand             rOut.m_eJoin = PDFWriter::joinRound;
91105aaf853bSArmin Le Grand             break;
91115aaf853bSArmin Le Grand         }
91125aaf853bSArmin Le Grand     }
91135aaf853bSArmin Le Grand 
91145aaf853bSArmin Le Grand     // add LineCap
91155aaf853bSArmin Le Grand     switch(rIn.GetLineCap())
91165aaf853bSArmin Le Grand     {
91175aaf853bSArmin Le Grand         default: /* com::sun::star::drawing::LineCap_BUTT */
91185aaf853bSArmin Le Grand         {
91195aaf853bSArmin Le Grand             rOut.m_eCap = PDFWriter::capButt;
91205aaf853bSArmin Le Grand             break;
91215aaf853bSArmin Le Grand         }
91225aaf853bSArmin Le Grand         case com::sun::star::drawing::LineCap_ROUND:
91235aaf853bSArmin Le Grand         {
91245aaf853bSArmin Le Grand             rOut.m_eCap = PDFWriter::capRound;
91255aaf853bSArmin Le Grand             break;
91265aaf853bSArmin Le Grand         }
91275aaf853bSArmin Le Grand         case com::sun::star::drawing::LineCap_SQUARE:
91285aaf853bSArmin Le Grand         {
91295aaf853bSArmin Le Grand             rOut.m_eCap = PDFWriter::capSquare;
91305aaf853bSArmin Le Grand             break;
91315aaf853bSArmin Le Grand         }
91325aaf853bSArmin Le Grand     }
9133cdf0e10cSrcweir }
9134cdf0e10cSrcweir 
drawPolyLine(const Polygon & rPoly,const PDFWriter::ExtLineInfo & rInfo)9135cdf0e10cSrcweir void PDFWriterImpl::drawPolyLine( const Polygon& rPoly, const PDFWriter::ExtLineInfo& rInfo )
9136cdf0e10cSrcweir {
9137cdf0e10cSrcweir     MARK( "drawPolyLine with ExtLineInfo" );
9138cdf0e10cSrcweir 
9139cdf0e10cSrcweir     updateGraphicsState();
9140cdf0e10cSrcweir 
9141cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) )
9142cdf0e10cSrcweir         return;
9143cdf0e10cSrcweir 
9144cdf0e10cSrcweir     if( rInfo.m_fTransparency >= 1.0 )
9145cdf0e10cSrcweir         return;
9146cdf0e10cSrcweir 
9147cdf0e10cSrcweir     if( rInfo.m_fTransparency != 0.0 )
9148cdf0e10cSrcweir         beginTransparencyGroup();
9149cdf0e10cSrcweir 
9150cdf0e10cSrcweir     OStringBuffer aLine;
9151cdf0e10cSrcweir     aLine.append( "q " );
9152cdf0e10cSrcweir     m_aPages.back().appendMappedLength( rInfo.m_fLineWidth, aLine );
9153cdf0e10cSrcweir     aLine.append( " w" );
9154cc0d486eSmseidel     if( rInfo.m_aDashArray.size() < 10 ) // implementation limit of acrobat reader
9155cdf0e10cSrcweir     {
9156cdf0e10cSrcweir         switch( rInfo.m_eCap )
9157cdf0e10cSrcweir         {
9158cdf0e10cSrcweir             default:
9159cdf0e10cSrcweir             case PDFWriter::capButt:   aLine.append( " 0 J" );break;
9160cdf0e10cSrcweir             case PDFWriter::capRound:  aLine.append( " 1 J" );break;
9161cdf0e10cSrcweir             case PDFWriter::capSquare: aLine.append( " 2 J" );break;
9162cdf0e10cSrcweir         }
9163cdf0e10cSrcweir         switch( rInfo.m_eJoin )
9164cdf0e10cSrcweir         {
9165cdf0e10cSrcweir             default:
9166cdf0e10cSrcweir             case PDFWriter::joinMiter:
9167cdf0e10cSrcweir             {
9168cdf0e10cSrcweir                 double fLimit = rInfo.m_fMiterLimit;
9169cdf0e10cSrcweir                 if( rInfo.m_fLineWidth < rInfo.m_fMiterLimit )
9170cdf0e10cSrcweir                     fLimit = fLimit / rInfo.m_fLineWidth;
9171cdf0e10cSrcweir                 if( fLimit < 1.0 )
9172cdf0e10cSrcweir                     fLimit = 1.0;
9173cdf0e10cSrcweir                 aLine.append( " 0 j " );
9174cdf0e10cSrcweir                 appendDouble( fLimit, aLine );
9175cdf0e10cSrcweir                 aLine.append( " M" );
9176cdf0e10cSrcweir             }
9177cdf0e10cSrcweir             break;
9178cdf0e10cSrcweir             case PDFWriter::joinRound:  aLine.append( " 1 j" );break;
9179cdf0e10cSrcweir             case PDFWriter::joinBevel:  aLine.append( " 2 j" );break;
9180cdf0e10cSrcweir         }
9181cdf0e10cSrcweir         if( rInfo.m_aDashArray.size() > 0 )
9182cdf0e10cSrcweir         {
9183cdf0e10cSrcweir             aLine.append( " [ " );
9184cdf0e10cSrcweir             for( std::vector<double>::const_iterator it = rInfo.m_aDashArray.begin();
9185cdf0e10cSrcweir                  it != rInfo.m_aDashArray.end(); ++it )
9186cdf0e10cSrcweir             {
9187cdf0e10cSrcweir                 m_aPages.back().appendMappedLength( *it, aLine );
9188cdf0e10cSrcweir                 aLine.append( ' ' );
9189cdf0e10cSrcweir             }
9190cdf0e10cSrcweir             aLine.append( "] 0 d" );
9191cdf0e10cSrcweir         }
9192cdf0e10cSrcweir         aLine.append( "\n" );
9193cdf0e10cSrcweir         writeBuffer( aLine.getStr(), aLine.getLength() );
9194cdf0e10cSrcweir         drawPolyLine( rPoly );
9195cdf0e10cSrcweir     }
9196cdf0e10cSrcweir     else
9197cdf0e10cSrcweir     {
9198cdf0e10cSrcweir         basegfx::B2DPolygon aPoly(rPoly.getB2DPolygon());
9199cdf0e10cSrcweir         basegfx::B2DPolyPolygon aPolyPoly;
9200cdf0e10cSrcweir 
9201cdf0e10cSrcweir         basegfx::tools::applyLineDashing(aPoly, rInfo.m_aDashArray, &aPolyPoly);
9202cdf0e10cSrcweir 
9203cdf0e10cSrcweir         // Old applyLineDashing subdivided the polygon. New one will create bezier curve segments.
9204cdf0e10cSrcweir         // To mimic old behaviour, apply subdivide here. If beziers shall be written (better quality)
9205cdf0e10cSrcweir         // this line needs to be removed and the loop below adapted accordingly
9206cdf0e10cSrcweir         aPolyPoly = basegfx::tools::adaptiveSubdivideByAngle(aPolyPoly);
9207cdf0e10cSrcweir 
9208cdf0e10cSrcweir         const sal_uInt32 nPolygonCount(aPolyPoly.count());
9209cdf0e10cSrcweir 
9210cdf0e10cSrcweir         for( sal_uInt32 nPoly = 0; nPoly < nPolygonCount; nPoly++ )
9211cdf0e10cSrcweir         {
9212cdf0e10cSrcweir             aLine.append( (nPoly != 0 && (nPoly & 7) == 0) ? "\n" : " " );
9213cdf0e10cSrcweir             aPoly = aPolyPoly.getB2DPolygon( nPoly );
9214cdf0e10cSrcweir             const sal_uInt32 nPointCount(aPoly.count());
9215cdf0e10cSrcweir 
9216cdf0e10cSrcweir             if(nPointCount)
9217cdf0e10cSrcweir             {
9218cdf0e10cSrcweir                 const sal_uInt32 nEdgeCount(aPoly.isClosed() ? nPointCount : nPointCount - 1);
9219cdf0e10cSrcweir                 basegfx::B2DPoint aCurrent(aPoly.getB2DPoint(0));
9220cdf0e10cSrcweir 
9221cdf0e10cSrcweir                 for(sal_uInt32 a(0); a < nEdgeCount; a++)
9222cdf0e10cSrcweir                 {
9223cdf0e10cSrcweir                     if( a > 0 )
9224cdf0e10cSrcweir                         aLine.append( " " );
9225cdf0e10cSrcweir                     const sal_uInt32 nNextIndex((a + 1) % nPointCount);
9226cdf0e10cSrcweir                     const basegfx::B2DPoint aNext(aPoly.getB2DPoint(nNextIndex));
9227cdf0e10cSrcweir 
9228cdf0e10cSrcweir                     m_aPages.back().appendPoint( Point( FRound(aCurrent.getX()),
9229cdf0e10cSrcweir                                                         FRound(aCurrent.getY()) ),
9230cdf0e10cSrcweir                                                  aLine );
9231cdf0e10cSrcweir                     aLine.append( " m " );
9232cdf0e10cSrcweir                     m_aPages.back().appendPoint( Point( FRound(aNext.getX()),
9233cdf0e10cSrcweir                                                         FRound(aNext.getY()) ),
9234cdf0e10cSrcweir                                                  aLine );
9235cdf0e10cSrcweir                     aLine.append( " l" );
9236cdf0e10cSrcweir 
9237cdf0e10cSrcweir                     // prepare next edge
9238cdf0e10cSrcweir                     aCurrent = aNext;
9239cdf0e10cSrcweir                 }
9240cdf0e10cSrcweir             }
9241cdf0e10cSrcweir         }
9242cdf0e10cSrcweir         aLine.append( " S " );
9243cdf0e10cSrcweir         writeBuffer( aLine.getStr(), aLine.getLength() );
9244cdf0e10cSrcweir     }
9245cdf0e10cSrcweir     writeBuffer( "Q\n", 2 );
9246cdf0e10cSrcweir 
9247cdf0e10cSrcweir     if( rInfo.m_fTransparency != 0.0 )
9248cdf0e10cSrcweir     {
9249cdf0e10cSrcweir         // FIXME: actually this may be incorrect with bezier polygons
9250cdf0e10cSrcweir         Rectangle aBoundRect( rPoly.GetBoundRect() );
9251cdf0e10cSrcweir         // avoid clipping with thick lines
9252cdf0e10cSrcweir         if( rInfo.m_fLineWidth > 0.0 )
9253cdf0e10cSrcweir         {
9254cdf0e10cSrcweir             sal_Int32 nLW = sal_Int32(rInfo.m_fLineWidth);
9255cdf0e10cSrcweir             aBoundRect.Top()    -= nLW;
9256cdf0e10cSrcweir             aBoundRect.Left()   -= nLW;
9257cdf0e10cSrcweir             aBoundRect.Right()  += nLW;
9258cdf0e10cSrcweir             aBoundRect.Bottom() += nLW;
9259cdf0e10cSrcweir         }
9260cdf0e10cSrcweir         endTransparencyGroup( aBoundRect, (sal_uInt16)(100.0*rInfo.m_fTransparency) );
9261cdf0e10cSrcweir     }
9262cdf0e10cSrcweir }
9263cdf0e10cSrcweir 
drawPixel(const Point & rPoint,const Color & rColor)9264cdf0e10cSrcweir void PDFWriterImpl::drawPixel( const Point& rPoint, const Color& rColor )
9265cdf0e10cSrcweir {
9266cdf0e10cSrcweir     MARK( "drawPixel" );
9267cdf0e10cSrcweir 
9268cdf0e10cSrcweir     Color aColor = ( rColor == Color( COL_TRANSPARENT ) ? m_aGraphicsStack.front().m_aLineColor : rColor );
9269cdf0e10cSrcweir 
9270cdf0e10cSrcweir     if( aColor == Color( COL_TRANSPARENT ) )
9271cdf0e10cSrcweir         return;
9272cdf0e10cSrcweir 
9273cdf0e10cSrcweir     // pixels are drawn in line color, so have to set
9274cdf0e10cSrcweir     // the nonstroking color to line color
9275cdf0e10cSrcweir     Color aOldFillColor = m_aGraphicsStack.front().m_aFillColor;
9276cdf0e10cSrcweir     setFillColor( aColor );
9277cdf0e10cSrcweir 
9278cdf0e10cSrcweir     updateGraphicsState();
9279cdf0e10cSrcweir 
9280cdf0e10cSrcweir     OStringBuffer aLine( 20 );
9281cdf0e10cSrcweir     m_aPages.back().appendPoint( rPoint, aLine );
9282cdf0e10cSrcweir     aLine.append( ' ' );
9283cdf0e10cSrcweir     appendDouble( 1.0/double(getReferenceDevice()->ImplGetDPIX()), aLine );
9284cdf0e10cSrcweir     aLine.append( ' ' );
9285cdf0e10cSrcweir     appendDouble( 1.0/double(getReferenceDevice()->ImplGetDPIY()), aLine );
9286cdf0e10cSrcweir     aLine.append( " re f\n" );
9287cdf0e10cSrcweir     writeBuffer( aLine.getStr(), aLine.getLength() );
9288cdf0e10cSrcweir 
9289cdf0e10cSrcweir     setFillColor( aOldFillColor );
9290cdf0e10cSrcweir }
9291cdf0e10cSrcweir 
drawPixel(const Polygon & rPoints,const Color * pColors)9292cdf0e10cSrcweir void PDFWriterImpl::drawPixel( const Polygon& rPoints, const Color* pColors )
9293cdf0e10cSrcweir {
9294cdf0e10cSrcweir     MARK( "drawPixel with Polygon" );
9295cdf0e10cSrcweir 
9296cdf0e10cSrcweir     updateGraphicsState();
9297cdf0e10cSrcweir 
9298cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) && ! pColors )
9299cdf0e10cSrcweir         return;
9300cdf0e10cSrcweir 
9301cdf0e10cSrcweir     sal_uInt16 nPoints = rPoints.GetSize();
9302cdf0e10cSrcweir     OStringBuffer aLine( nPoints*40 );
9303cdf0e10cSrcweir     aLine.append( "q " );
9304cdf0e10cSrcweir     if( ! pColors )
9305cdf0e10cSrcweir     {
9306cdf0e10cSrcweir         appendNonStrokingColor( m_aGraphicsStack.front().m_aLineColor, aLine );
9307cdf0e10cSrcweir         aLine.append( ' ' );
9308cdf0e10cSrcweir     }
9309cdf0e10cSrcweir 
9310cdf0e10cSrcweir     OStringBuffer aPixel(32);
9311cdf0e10cSrcweir     aPixel.append( ' ' );
9312cdf0e10cSrcweir     appendDouble( 1.0/double(getReferenceDevice()->ImplGetDPIX()), aPixel );
9313cdf0e10cSrcweir     aPixel.append( ' ' );
9314cdf0e10cSrcweir     appendDouble( 1.0/double(getReferenceDevice()->ImplGetDPIY()), aPixel );
9315cdf0e10cSrcweir     OString aPixelStr = aPixel.makeStringAndClear();
9316cdf0e10cSrcweir     for( sal_uInt16 i = 0; i < nPoints; i++ )
9317cdf0e10cSrcweir     {
9318cdf0e10cSrcweir         if( pColors )
9319cdf0e10cSrcweir         {
9320cdf0e10cSrcweir             if( pColors[i] == Color( COL_TRANSPARENT ) )
9321cdf0e10cSrcweir                 continue;
9322cdf0e10cSrcweir 
9323cdf0e10cSrcweir             appendNonStrokingColor( pColors[i], aLine );
9324cdf0e10cSrcweir             aLine.append( ' ' );
9325cdf0e10cSrcweir         }
9326cdf0e10cSrcweir         m_aPages.back().appendPoint( rPoints[i], aLine );
9327cdf0e10cSrcweir         aLine.append( aPixelStr );
9328cdf0e10cSrcweir         aLine.append( " re f\n" );
9329cdf0e10cSrcweir     }
9330cdf0e10cSrcweir     aLine.append( "Q\n" );
9331cdf0e10cSrcweir     writeBuffer( aLine.getStr(), aLine.getLength() );
9332cdf0e10cSrcweir }
9333cdf0e10cSrcweir 
9334cdf0e10cSrcweir class AccessReleaser
9335cdf0e10cSrcweir {
9336cdf0e10cSrcweir     BitmapReadAccess* m_pAccess;
9337cdf0e10cSrcweir public:
AccessReleaser(BitmapReadAccess * pAccess)9338cdf0e10cSrcweir     AccessReleaser( BitmapReadAccess* pAccess ) : m_pAccess( pAccess ){}
~AccessReleaser()9339cdf0e10cSrcweir     ~AccessReleaser() { delete m_pAccess; }
9340cdf0e10cSrcweir };
9341cdf0e10cSrcweir 
writeTransparentObject(TransparencyEmit & rObject)9342cdf0e10cSrcweir bool PDFWriterImpl::writeTransparentObject( TransparencyEmit& rObject )
9343cdf0e10cSrcweir {
9344cdf0e10cSrcweir     CHECK_RETURN( updateObject( rObject.m_nObject ) );
9345cdf0e10cSrcweir 
9346cdf0e10cSrcweir     bool bFlateFilter = compressStream( rObject.m_pContentStream );
9347cdf0e10cSrcweir     rObject.m_pContentStream->Seek( STREAM_SEEK_TO_END );
9348cdf0e10cSrcweir     sal_uLong nSize = rObject.m_pContentStream->Tell();
9349cdf0e10cSrcweir     rObject.m_pContentStream->Seek( STREAM_SEEK_TO_BEGIN );
9350cdf0e10cSrcweir     #if OSL_DEBUG_LEVEL > 1
9351cdf0e10cSrcweir     emitComment( "PDFWriterImpl::writeTransparentObject" );
9352cdf0e10cSrcweir     #endif
9353cdf0e10cSrcweir     OStringBuffer aLine( 512 );
9354cdf0e10cSrcweir     CHECK_RETURN( updateObject( rObject.m_nObject ) );
9355cdf0e10cSrcweir     aLine.append( rObject.m_nObject );
9356cdf0e10cSrcweir     aLine.append( " 0 obj\n"
9357cdf0e10cSrcweir                   "<</Type/XObject\n"
9358cdf0e10cSrcweir                   "/Subtype/Form\n"
9359cdf0e10cSrcweir                   "/BBox[ " );
9360cdf0e10cSrcweir     appendFixedInt( rObject.m_aBoundRect.Left(), aLine );
9361cdf0e10cSrcweir     aLine.append( ' ' );
9362cdf0e10cSrcweir     appendFixedInt( rObject.m_aBoundRect.Top(), aLine );
9363cdf0e10cSrcweir     aLine.append( ' ' );
9364cdf0e10cSrcweir     appendFixedInt( rObject.m_aBoundRect.Right(), aLine );
9365cdf0e10cSrcweir     aLine.append( ' ' );
9366cdf0e10cSrcweir     appendFixedInt( rObject.m_aBoundRect.Bottom()+1, aLine );
9367cdf0e10cSrcweir     aLine.append( " ]\n" );
9368cdf0e10cSrcweir     if( ! rObject.m_pSoftMaskStream )
9369cdf0e10cSrcweir     {
9370cdf0e10cSrcweir         if( ! m_bIsPDF_A1 )
9371cdf0e10cSrcweir         {
9372cdf0e10cSrcweir             aLine.append( "/Group<</S/Transparency/CS/DeviceRGB/K true>>\n" );
9373cdf0e10cSrcweir         }
9374cdf0e10cSrcweir     }
9375cdf0e10cSrcweir     /* #i42884# the PDF reference recommends that each Form XObject
9376cdf0e10cSrcweir     *  should have a resource dict; alas if that is the same object
9377cdf0e10cSrcweir     *  as the one of the page it triggers an endless recursion in
9378cdf0e10cSrcweir     *  acroread 5 (6 and up have that fixed). Since we have only one
9379cdf0e10cSrcweir     *  resource dict anyway, let's use the one from the page by NOT
9380cdf0e10cSrcweir     *  emitting a Resources entry.
9381cdf0e10cSrcweir     */
9382cdf0e10cSrcweir     #if 0
9383cdf0e10cSrcweir     aLine.append( "   /Resources " );
9384cdf0e10cSrcweir     aLine.append( getResourceDictObj() );
9385cdf0e10cSrcweir     aLine.append( " 0 R\n" );
9386cdf0e10cSrcweir     #endif
9387cdf0e10cSrcweir 
9388cdf0e10cSrcweir     aLine.append( "/Length " );
9389cdf0e10cSrcweir     aLine.append( (sal_Int32)(nSize) );
9390cdf0e10cSrcweir     aLine.append( "\n" );
9391cdf0e10cSrcweir     if( bFlateFilter )
9392cdf0e10cSrcweir         aLine.append( "/Filter/FlateDecode\n" );
9393cdf0e10cSrcweir     aLine.append( ">>\n"
9394cdf0e10cSrcweir                   "stream\n" );
9395cdf0e10cSrcweir     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
9396cdf0e10cSrcweir     checkAndEnableStreamEncryption( rObject.m_nObject );
9397cdf0e10cSrcweir     CHECK_RETURN( writeBuffer( rObject.m_pContentStream->GetData(), nSize ) );
9398cdf0e10cSrcweir     disableStreamEncryption();
9399cdf0e10cSrcweir     aLine.setLength( 0 );
9400cdf0e10cSrcweir     aLine.append( "\n"
9401cdf0e10cSrcweir                   "endstream\n"
9402cdf0e10cSrcweir                   "endobj\n\n" );
9403cdf0e10cSrcweir     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
9404cdf0e10cSrcweir 
9405cdf0e10cSrcweir     // write ExtGState dict for this XObject
9406cdf0e10cSrcweir     aLine.setLength( 0 );
9407cdf0e10cSrcweir     aLine.append( rObject.m_nExtGStateObject );
9408cdf0e10cSrcweir     aLine.append( " 0 obj\n"
9409cdf0e10cSrcweir                   "<<" );
9410cdf0e10cSrcweir     if( ! rObject.m_pSoftMaskStream )
9411cdf0e10cSrcweir     {
9412cdf0e10cSrcweir //i59651
9413cdf0e10cSrcweir         if( m_bIsPDF_A1 )
9414cdf0e10cSrcweir         {
9415cdf0e10cSrcweir             aLine.append( "/CA 1.0/ca 1.0" );
9416cdf0e10cSrcweir             m_aErrors.insert( PDFWriter::Warning_Transparency_Omitted_PDFA );
9417cdf0e10cSrcweir         }
9418cdf0e10cSrcweir         else
9419cdf0e10cSrcweir         {
9420cdf0e10cSrcweir             aLine.append(  "/CA " );
9421cdf0e10cSrcweir             appendDouble( rObject.m_fAlpha, aLine );
9422cdf0e10cSrcweir             aLine.append( "\n"
9423cdf0e10cSrcweir                           "   /ca " );
9424cdf0e10cSrcweir             appendDouble( rObject.m_fAlpha, aLine );
9425cdf0e10cSrcweir         }
9426cdf0e10cSrcweir         aLine.append( "\n" );
9427cdf0e10cSrcweir     }
9428cdf0e10cSrcweir     else
9429cdf0e10cSrcweir     {
9430cdf0e10cSrcweir         if( m_bIsPDF_A1 )
9431cdf0e10cSrcweir         {
9432cdf0e10cSrcweir             aLine.append( "/SMask/None" );
9433cdf0e10cSrcweir             m_aErrors.insert( PDFWriter::Warning_Transparency_Omitted_PDFA );
9434cdf0e10cSrcweir         }
9435cdf0e10cSrcweir         else
9436cdf0e10cSrcweir         {
9437cdf0e10cSrcweir             rObject.m_pSoftMaskStream->Seek( STREAM_SEEK_TO_END );
9438cdf0e10cSrcweir             sal_Int32 nMaskSize = (sal_Int32)rObject.m_pSoftMaskStream->Tell();
9439cdf0e10cSrcweir             rObject.m_pSoftMaskStream->Seek( STREAM_SEEK_TO_BEGIN );
9440cdf0e10cSrcweir             sal_Int32 nMaskObject = createObject();
9441cdf0e10cSrcweir             aLine.append( "/SMask<</Type/Mask/S/Luminosity/G " );
9442cdf0e10cSrcweir             aLine.append( nMaskObject );
9443cdf0e10cSrcweir             aLine.append( " 0 R>>\n" );
9444cdf0e10cSrcweir 
9445cdf0e10cSrcweir             OStringBuffer aMask;
9446cdf0e10cSrcweir             aMask.append( nMaskObject );
9447cdf0e10cSrcweir             aMask.append( " 0 obj\n"
9448cdf0e10cSrcweir                           "<</Type/XObject\n"
9449cdf0e10cSrcweir                           "/Subtype/Form\n"
9450cdf0e10cSrcweir                           "/BBox[" );
9451cdf0e10cSrcweir             appendFixedInt( rObject.m_aBoundRect.Left(), aMask );
9452cdf0e10cSrcweir             aMask.append( ' ' );
9453cdf0e10cSrcweir             appendFixedInt( rObject.m_aBoundRect.Top(), aMask );
9454cdf0e10cSrcweir             aMask.append( ' ' );
9455cdf0e10cSrcweir             appendFixedInt( rObject.m_aBoundRect.Right(), aMask );
9456cdf0e10cSrcweir             aMask.append( ' ' );
9457cdf0e10cSrcweir             appendFixedInt( rObject.m_aBoundRect.Bottom()+1, aMask );
9458cdf0e10cSrcweir             aMask.append( "]\n" );
9459cdf0e10cSrcweir 
9460cdf0e10cSrcweir             /* #i42884# see above */
9461cdf0e10cSrcweir #if 0
9462cdf0e10cSrcweir             aLine.append( "/Resources " );
9463cdf0e10cSrcweir             aMask.append( getResourceDictObj() );
9464cdf0e10cSrcweir             aMask.append( " 0 R\n" );
9465cdf0e10cSrcweir #endif
9466cdf0e10cSrcweir 
9467cdf0e10cSrcweir             aMask.append( "/Group<</S/Transparency/CS/DeviceRGB>>\n" );
9468cdf0e10cSrcweir             aMask.append( "/Length " );
9469cdf0e10cSrcweir             aMask.append( nMaskSize );
9470cdf0e10cSrcweir             aMask.append( ">>\n"
9471cdf0e10cSrcweir                           "stream\n" );
9472cdf0e10cSrcweir             CHECK_RETURN( updateObject( nMaskObject ) );
9473cdf0e10cSrcweir             checkAndEnableStreamEncryption(  nMaskObject );
9474cdf0e10cSrcweir             CHECK_RETURN( writeBuffer( aMask.getStr(), aMask.getLength() ) );
9475cdf0e10cSrcweir             CHECK_RETURN( writeBuffer( rObject.m_pSoftMaskStream->GetData(), nMaskSize ) );
9476cdf0e10cSrcweir             disableStreamEncryption();
9477cdf0e10cSrcweir             aMask.setLength( 0 );
9478cdf0e10cSrcweir             aMask.append( "\nendstream\n"
9479cdf0e10cSrcweir                           "endobj\n\n" );
9480cdf0e10cSrcweir             CHECK_RETURN( writeBuffer( aMask.getStr(), aMask.getLength() ) );
9481cdf0e10cSrcweir         }
9482cdf0e10cSrcweir     }
9483cdf0e10cSrcweir     aLine.append( ">>\n"
9484cdf0e10cSrcweir                   "endobj\n\n" );
9485cdf0e10cSrcweir     CHECK_RETURN( updateObject( rObject.m_nExtGStateObject ) );
9486cdf0e10cSrcweir     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
9487cdf0e10cSrcweir 
9488cdf0e10cSrcweir     return true;
9489cdf0e10cSrcweir }
9490cdf0e10cSrcweir 
writeGradientFunction(GradientEmit & rObject)9491cdf0e10cSrcweir bool PDFWriterImpl::writeGradientFunction( GradientEmit& rObject )
9492cdf0e10cSrcweir {
9493cdf0e10cSrcweir     sal_Int32 nFunctionObject = createObject();
9494cdf0e10cSrcweir     CHECK_RETURN( updateObject( nFunctionObject ) );
9495cdf0e10cSrcweir 
9496cdf0e10cSrcweir     VirtualDevice aDev;
9497cdf0e10cSrcweir     aDev.SetOutputSizePixel( rObject.m_aSize );
9498cdf0e10cSrcweir     aDev.SetMapMode( MapMode( MAP_PIXEL ) );
9499cdf0e10cSrcweir     if( m_aContext.ColorMode == PDFWriter::DrawGreyscale )
9500cdf0e10cSrcweir         aDev.SetDrawMode( aDev.GetDrawMode() |
9501cdf0e10cSrcweir                           ( DRAWMODE_GRAYLINE | DRAWMODE_GRAYFILL | DRAWMODE_GRAYTEXT |
9502cdf0e10cSrcweir                             DRAWMODE_GRAYBITMAP | DRAWMODE_GRAYGRADIENT ) );
9503cdf0e10cSrcweir     aDev.DrawGradient( Rectangle( Point( 0, 0 ), rObject.m_aSize ), rObject.m_aGradient );
9504cdf0e10cSrcweir 
9505cdf0e10cSrcweir     Bitmap aSample = aDev.GetBitmap( Point( 0, 0 ), rObject.m_aSize );
9506cdf0e10cSrcweir     BitmapReadAccess* pAccess = aSample.AcquireReadAccess();
9507cdf0e10cSrcweir     AccessReleaser aReleaser( pAccess );
9508cdf0e10cSrcweir 
9509cdf0e10cSrcweir     Size aSize = aSample.GetSizePixel();
9510cdf0e10cSrcweir 
9511cdf0e10cSrcweir     sal_Int32 nStreamLengthObject = createObject();
9512cdf0e10cSrcweir     #if OSL_DEBUG_LEVEL > 1
9513cdf0e10cSrcweir     emitComment( "PDFWriterImpl::writeGradientFunction" );
9514cdf0e10cSrcweir     #endif
9515cdf0e10cSrcweir     OStringBuffer aLine( 120 );
9516cdf0e10cSrcweir     aLine.append( nFunctionObject );
9517cdf0e10cSrcweir     aLine.append( " 0 obj\n"
9518cdf0e10cSrcweir                   "<</FunctionType 0\n"
9519cdf0e10cSrcweir                   "/Domain[ 0 1 0 1 ]\n"
9520cdf0e10cSrcweir                   "/Size[ " );
9521cdf0e10cSrcweir     aLine.append( (sal_Int32)aSize.Width() );
9522cdf0e10cSrcweir     aLine.append( ' ' );
9523cdf0e10cSrcweir     aLine.append( (sal_Int32)aSize.Height() );
9524cdf0e10cSrcweir     aLine.append( " ]\n"
9525cdf0e10cSrcweir                   "/BitsPerSample 8\n"
9526cdf0e10cSrcweir                   "/Range[ 0 1 0 1 0 1 ]\n"
9527cdf0e10cSrcweir                   "/Order 3\n"
9528cdf0e10cSrcweir                   "/Length " );
9529cdf0e10cSrcweir     aLine.append( nStreamLengthObject );
9530cdf0e10cSrcweir     aLine.append( " 0 R\n"
9531cdf0e10cSrcweir #ifndef DEBUG_DISABLE_PDFCOMPRESSION
9532cdf0e10cSrcweir                   "/Filter/FlateDecode"
9533cdf0e10cSrcweir #endif
9534cdf0e10cSrcweir                   ">>\n"
9535cdf0e10cSrcweir                   "stream\n" );
9536cdf0e10cSrcweir     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
9537cdf0e10cSrcweir 
9538cdf0e10cSrcweir     sal_uInt64 nStartStreamPos = 0;
9539cdf0e10cSrcweir     CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nStartStreamPos )) );
9540cdf0e10cSrcweir 
9541cdf0e10cSrcweir     checkAndEnableStreamEncryption( nFunctionObject );
9542cdf0e10cSrcweir     beginCompression();
9543cdf0e10cSrcweir     for( int y = aSize.Height()-1; y >= 0; y-- )
9544cdf0e10cSrcweir     {
9545cdf0e10cSrcweir         for( int x = 0; x < aSize.Width(); x++ )
9546cdf0e10cSrcweir         {
9547cdf0e10cSrcweir             sal_uInt8 aCol[3];
9548cdf0e10cSrcweir             BitmapColor aColor = pAccess->GetColor( y, x );
9549cdf0e10cSrcweir             aCol[0] = aColor.GetRed();
9550cdf0e10cSrcweir             aCol[1] = aColor.GetGreen();
9551cdf0e10cSrcweir             aCol[2] = aColor.GetBlue();
9552cdf0e10cSrcweir             CHECK_RETURN( writeBuffer( aCol, 3 ) );
9553cdf0e10cSrcweir         }
9554cdf0e10cSrcweir     }
9555cdf0e10cSrcweir     endCompression();
9556cdf0e10cSrcweir     disableStreamEncryption();
9557cdf0e10cSrcweir 
9558cdf0e10cSrcweir     sal_uInt64 nEndStreamPos = 0;
9559cdf0e10cSrcweir     CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nEndStreamPos )) );
9560cdf0e10cSrcweir 
9561cdf0e10cSrcweir     aLine.setLength( 0 );
9562cdf0e10cSrcweir     aLine.append( "\nendstream\nendobj\n\n" );
9563cdf0e10cSrcweir     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
9564cdf0e10cSrcweir 
9565cdf0e10cSrcweir     // write stream length
9566cdf0e10cSrcweir     CHECK_RETURN( updateObject( nStreamLengthObject ) );
9567cdf0e10cSrcweir     aLine.setLength( 0 );
9568cdf0e10cSrcweir     aLine.append( nStreamLengthObject );
9569cdf0e10cSrcweir     aLine.append( " 0 obj\n" );
9570cdf0e10cSrcweir     aLine.append( (sal_Int64)(nEndStreamPos-nStartStreamPos) );
9571cdf0e10cSrcweir     aLine.append( "\nendobj\n\n" );
9572cdf0e10cSrcweir     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
9573cdf0e10cSrcweir 
9574cdf0e10cSrcweir     CHECK_RETURN( updateObject( rObject.m_nObject ) );
9575cdf0e10cSrcweir     aLine.setLength( 0 );
9576cdf0e10cSrcweir     aLine.append( rObject.m_nObject );
9577cdf0e10cSrcweir     aLine.append( " 0 obj\n"
9578cdf0e10cSrcweir                   "<</ShadingType 1\n"
9579cdf0e10cSrcweir                   "/ColorSpace/DeviceRGB\n"
9580cdf0e10cSrcweir                   "/AntiAlias true\n"
9581cdf0e10cSrcweir                   "/Domain[ 0 1 0 1 ]\n"
9582cdf0e10cSrcweir                   "/Matrix[ " );
9583cdf0e10cSrcweir     aLine.append( (sal_Int32)aSize.Width() );
9584cdf0e10cSrcweir     aLine.append( " 0 0 " );
9585cdf0e10cSrcweir     aLine.append( (sal_Int32)aSize.Height() );
9586cdf0e10cSrcweir     aLine.append( " 0 0 ]\n"
9587cdf0e10cSrcweir                   "/Function " );
9588cdf0e10cSrcweir     aLine.append( nFunctionObject );
9589cdf0e10cSrcweir     aLine.append( " 0 R\n"
9590cdf0e10cSrcweir                   ">>\n"
9591cdf0e10cSrcweir                   "endobj\n\n" );
9592cdf0e10cSrcweir     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
9593cdf0e10cSrcweir 
9594cdf0e10cSrcweir     return true;
9595cdf0e10cSrcweir }
9596cdf0e10cSrcweir 
writeJPG(JPGEmit & rObject)9597cdf0e10cSrcweir bool PDFWriterImpl::writeJPG( JPGEmit& rObject )
9598cdf0e10cSrcweir {
9599cdf0e10cSrcweir     CHECK_RETURN( rObject.m_pStream );
9600cdf0e10cSrcweir     CHECK_RETURN( updateObject( rObject.m_nObject ) );
9601cdf0e10cSrcweir 
9602cdf0e10cSrcweir     sal_Int32 nLength = 0;
9603cdf0e10cSrcweir     rObject.m_pStream->Seek( STREAM_SEEK_TO_END );
9604cdf0e10cSrcweir     nLength = rObject.m_pStream->Tell();
9605cdf0e10cSrcweir     rObject.m_pStream->Seek( STREAM_SEEK_TO_BEGIN );
9606cdf0e10cSrcweir 
9607cdf0e10cSrcweir     sal_Int32 nMaskObject = 0;
9608cdf0e10cSrcweir     if( !!rObject.m_aMask )
9609cdf0e10cSrcweir     {
9610cdf0e10cSrcweir         if( rObject.m_aMask.GetBitCount() == 1 ||
9611cdf0e10cSrcweir             ( rObject.m_aMask.GetBitCount() == 8 && m_aContext.Version >= PDFWriter::PDF_1_4 && !m_bIsPDF_A1 )//i59651
9612cdf0e10cSrcweir             )
9613cdf0e10cSrcweir         {
9614cdf0e10cSrcweir             nMaskObject = createObject();
9615cdf0e10cSrcweir         }
9616cdf0e10cSrcweir         else if( m_bIsPDF_A1 )
9617cdf0e10cSrcweir             m_aErrors.insert( PDFWriter::Warning_Transparency_Omitted_PDFA );
9618cdf0e10cSrcweir         else if( m_aContext.Version < PDFWriter::PDF_1_4 )
9619cdf0e10cSrcweir             m_aErrors.insert( PDFWriter::Warning_Transparency_Omitted_PDF13 );
9620cdf0e10cSrcweir 
9621cdf0e10cSrcweir     }
9622cdf0e10cSrcweir     #if OSL_DEBUG_LEVEL > 1
9623cdf0e10cSrcweir     emitComment( "PDFWriterImpl::writeJPG" );
9624cdf0e10cSrcweir     #endif
9625cdf0e10cSrcweir 
9626cdf0e10cSrcweir     OStringBuffer aLine(200);
9627cdf0e10cSrcweir     aLine.append( rObject.m_nObject );
9628cdf0e10cSrcweir     aLine.append( " 0 obj\n"
9629cdf0e10cSrcweir                   "<</Type/XObject/Subtype/Image/Width " );
9630cdf0e10cSrcweir     aLine.append( (sal_Int32)rObject.m_aID.m_aPixelSize.Width() );
9631cdf0e10cSrcweir     aLine.append( " /Height " );
9632cdf0e10cSrcweir     aLine.append( (sal_Int32)rObject.m_aID.m_aPixelSize.Height() );
9633cdf0e10cSrcweir     aLine.append( " /BitsPerComponent 8 " );
9634cdf0e10cSrcweir     if( rObject.m_bTrueColor )
9635cdf0e10cSrcweir         aLine.append( "/ColorSpace/DeviceRGB" );
9636cdf0e10cSrcweir     else
9637cdf0e10cSrcweir         aLine.append( "/ColorSpace/DeviceGray" );
9638cdf0e10cSrcweir     aLine.append( "/Filter/DCTDecode/Length " );
9639cdf0e10cSrcweir     aLine.append( nLength );
9640cdf0e10cSrcweir     if( nMaskObject )
9641cdf0e10cSrcweir     {
9642cdf0e10cSrcweir         aLine.append( rObject.m_aMask.GetBitCount() == 1 ? " /Mask " : " /SMask " );
9643cdf0e10cSrcweir         aLine.append( nMaskObject );
9644cdf0e10cSrcweir         aLine.append( " 0 R " );
9645cdf0e10cSrcweir     }
9646cdf0e10cSrcweir     aLine.append( ">>\nstream\n" );
9647cdf0e10cSrcweir     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
9648cdf0e10cSrcweir 
9649cdf0e10cSrcweir     checkAndEnableStreamEncryption( rObject.m_nObject );
9650cdf0e10cSrcweir     CHECK_RETURN( writeBuffer( rObject.m_pStream->GetData(), nLength ) );
9651cdf0e10cSrcweir     disableStreamEncryption();
9652cdf0e10cSrcweir 
9653cdf0e10cSrcweir     aLine.setLength( 0 );
9654cdf0e10cSrcweir     aLine.append( "\nendstream\nendobj\n\n" );
9655cdf0e10cSrcweir     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
9656cdf0e10cSrcweir 
9657cdf0e10cSrcweir     if( nMaskObject )
9658cdf0e10cSrcweir     {
9659cdf0e10cSrcweir         BitmapEmit aEmit;
9660cdf0e10cSrcweir         aEmit.m_nObject = nMaskObject;
9661cdf0e10cSrcweir         if( rObject.m_aMask.GetBitCount() == 1 )
9662cdf0e10cSrcweir             aEmit.m_aBitmap = BitmapEx( rObject.m_aMask, rObject.m_aMask );
9663cdf0e10cSrcweir         else if( rObject.m_aMask.GetBitCount() == 8 )
9664cdf0e10cSrcweir             aEmit.m_aBitmap = BitmapEx( rObject.m_aMask, AlphaMask( rObject.m_aMask ) );
9665cdf0e10cSrcweir         writeBitmapObject( aEmit, true );
9666cdf0e10cSrcweir     }
9667cdf0e10cSrcweir 
9668cdf0e10cSrcweir     return true;
9669cdf0e10cSrcweir }
9670cdf0e10cSrcweir 
writeBitmapObject(BitmapEmit & rObject,bool bMask)9671cdf0e10cSrcweir bool PDFWriterImpl::writeBitmapObject( BitmapEmit& rObject, bool bMask )
9672cdf0e10cSrcweir {
9673cdf0e10cSrcweir     CHECK_RETURN( updateObject( rObject.m_nObject ) );
9674cdf0e10cSrcweir 
9675cdf0e10cSrcweir     Bitmap  aBitmap;
9676cdf0e10cSrcweir     Color   aTransparentColor( COL_TRANSPARENT );
9677cdf0e10cSrcweir     bool    bWriteMask = false;
9678cdf0e10cSrcweir     if( ! bMask )
9679cdf0e10cSrcweir     {
9680cdf0e10cSrcweir         aBitmap = rObject.m_aBitmap.GetBitmap();
9681cdf0e10cSrcweir         if( rObject.m_aBitmap.IsAlpha() )
9682cdf0e10cSrcweir         {
9683cdf0e10cSrcweir             if( m_aContext.Version >= PDFWriter::PDF_1_4 )
9684cdf0e10cSrcweir                 bWriteMask = true;
9685cdf0e10cSrcweir             // else draw without alpha channel
9686cdf0e10cSrcweir         }
9687cdf0e10cSrcweir         else
9688cdf0e10cSrcweir         {
9689cdf0e10cSrcweir             switch( rObject.m_aBitmap.GetTransparentType() )
9690cdf0e10cSrcweir             {
9691cdf0e10cSrcweir                 case TRANSPARENT_NONE:
9692cdf0e10cSrcweir                     // comes from drawMask function
9693cdf0e10cSrcweir                     if( aBitmap.GetBitCount() == 1 && rObject.m_bDrawMask )
9694cdf0e10cSrcweir                         bMask = true;
9695cdf0e10cSrcweir                     break;
9696cdf0e10cSrcweir                 case TRANSPARENT_COLOR:
9697cdf0e10cSrcweir                     aTransparentColor = rObject.m_aBitmap.GetTransparentColor();
9698cdf0e10cSrcweir                     break;
9699cdf0e10cSrcweir                 case TRANSPARENT_BITMAP:
9700cdf0e10cSrcweir                     bWriteMask = true;
9701cdf0e10cSrcweir                     break;
9702cdf0e10cSrcweir             }
9703cdf0e10cSrcweir         }
9704cdf0e10cSrcweir     }
9705cdf0e10cSrcweir     else
9706cdf0e10cSrcweir     {
9707cdf0e10cSrcweir         if( m_aContext.Version < PDFWriter::PDF_1_4 || ! rObject.m_aBitmap.IsAlpha() )
9708cdf0e10cSrcweir         {
9709cdf0e10cSrcweir             aBitmap = rObject.m_aBitmap.GetMask();
9710cdf0e10cSrcweir             aBitmap.Convert( BMP_CONVERSION_1BIT_THRESHOLD );
9711cdf0e10cSrcweir             DBG_ASSERT( aBitmap.GetBitCount() == 1, "mask conversion failed" );
9712cdf0e10cSrcweir         }
9713cdf0e10cSrcweir         else if( aBitmap.GetBitCount() != 8 )
9714cdf0e10cSrcweir         {
9715cdf0e10cSrcweir             aBitmap = rObject.m_aBitmap.GetAlpha().GetBitmap();
9716cdf0e10cSrcweir             aBitmap.Convert( BMP_CONVERSION_8BIT_GREYS );
9717cdf0e10cSrcweir             DBG_ASSERT( aBitmap.GetBitCount() == 8, "alpha mask conversion failed" );
9718cdf0e10cSrcweir         }
9719cdf0e10cSrcweir     }
9720cdf0e10cSrcweir 
9721cdf0e10cSrcweir     BitmapReadAccess* pAccess = aBitmap.AcquireReadAccess();
9722cdf0e10cSrcweir     AccessReleaser aReleaser( pAccess );
9723cdf0e10cSrcweir 
9724cdf0e10cSrcweir     bool bTrueColor;
9725cdf0e10cSrcweir     sal_Int32 nBitsPerComponent;
9726cdf0e10cSrcweir     switch( aBitmap.GetBitCount() )
9727cdf0e10cSrcweir     {
9728cdf0e10cSrcweir         case 1:
9729cdf0e10cSrcweir         case 2:
9730cdf0e10cSrcweir         case 4:
9731cdf0e10cSrcweir         case 8:
9732cdf0e10cSrcweir             bTrueColor = false;
9733cdf0e10cSrcweir             nBitsPerComponent = aBitmap.GetBitCount();
9734cdf0e10cSrcweir             break;
9735cdf0e10cSrcweir         default:
9736cdf0e10cSrcweir             bTrueColor = true;
9737cdf0e10cSrcweir             nBitsPerComponent = 8;
9738cdf0e10cSrcweir             break;
9739cdf0e10cSrcweir     }
9740cdf0e10cSrcweir 
9741cdf0e10cSrcweir     sal_Int32 nStreamLengthObject   = createObject();
9742cdf0e10cSrcweir     sal_Int32 nMaskObject           = 0;
9743cdf0e10cSrcweir 
9744cdf0e10cSrcweir     #if OSL_DEBUG_LEVEL > 1
9745cdf0e10cSrcweir     emitComment( "PDFWriterImpl::writeBitmapObject" );
9746cdf0e10cSrcweir     #endif
9747cdf0e10cSrcweir     OStringBuffer aLine(1024);
9748cdf0e10cSrcweir     aLine.append( rObject.m_nObject );
9749cdf0e10cSrcweir     aLine.append( " 0 obj\n"
9750cdf0e10cSrcweir                   "<</Type/XObject/Subtype/Image/Width " );
9751cdf0e10cSrcweir     aLine.append( (sal_Int32)aBitmap.GetSizePixel().Width() );
9752cdf0e10cSrcweir     aLine.append( "/Height " );
9753cdf0e10cSrcweir     aLine.append( (sal_Int32)aBitmap.GetSizePixel().Height() );
9754cdf0e10cSrcweir     aLine.append( "/BitsPerComponent " );
9755cdf0e10cSrcweir     aLine.append( nBitsPerComponent );
9756cdf0e10cSrcweir     aLine.append( "/Length " );
9757cdf0e10cSrcweir     aLine.append( nStreamLengthObject );
9758cdf0e10cSrcweir     aLine.append( " 0 R\n" );
9759cdf0e10cSrcweir #ifndef DEBUG_DISABLE_PDFCOMPRESSION
9760cdf0e10cSrcweir     if( nBitsPerComponent != 1 )
9761cdf0e10cSrcweir     {
9762cdf0e10cSrcweir         aLine.append( "/Filter/FlateDecode" );
9763cdf0e10cSrcweir     }
9764cdf0e10cSrcweir     else
9765cdf0e10cSrcweir     {
9766cdf0e10cSrcweir         aLine.append( "/Filter/CCITTFaxDecode/DecodeParms<</K -1/BlackIs1 true/Columns " );
9767cdf0e10cSrcweir         aLine.append( (sal_Int32)aBitmap.GetSizePixel().Width() );
9768cdf0e10cSrcweir         aLine.append( ">>\n" );
9769cdf0e10cSrcweir     }
9770cdf0e10cSrcweir #endif
9771cdf0e10cSrcweir     if( ! bMask )
9772cdf0e10cSrcweir     {
9773cdf0e10cSrcweir         aLine.append( "/ColorSpace" );
9774cdf0e10cSrcweir         if( bTrueColor )
9775cdf0e10cSrcweir             aLine.append( "/DeviceRGB\n" );
9776cdf0e10cSrcweir         else if( aBitmap.HasGreyPalette() )
9777cdf0e10cSrcweir         {
9778cdf0e10cSrcweir             aLine.append( "/DeviceGray\n" );
9779cdf0e10cSrcweir             if( aBitmap.GetBitCount() == 1 )
9780cdf0e10cSrcweir             {
9781cdf0e10cSrcweir                 // #i47395# 1 bit bitmaps occasionally have an inverted grey palette
9782cdf0e10cSrcweir                 sal_Int32 nBlackIndex = pAccess->GetBestPaletteIndex( BitmapColor( Color( COL_BLACK ) ) );
9783cdf0e10cSrcweir                 DBG_ASSERT( nBlackIndex == 0 || nBlackIndex == 1, "wrong black index" );
9784cdf0e10cSrcweir                 if( nBlackIndex == 1 )
9785cdf0e10cSrcweir                     aLine.append( "/Decode[1 0]\n" );
9786cdf0e10cSrcweir             }
9787cdf0e10cSrcweir         }
9788cdf0e10cSrcweir         else
9789cdf0e10cSrcweir         {
9790cdf0e10cSrcweir             aLine.append( "[ /Indexed/DeviceRGB " );
9791cdf0e10cSrcweir             aLine.append( (sal_Int32)(pAccess->GetPaletteEntryCount()-1) );
9792cdf0e10cSrcweir             aLine.append( "\n<" );
9793cdf0e10cSrcweir             if( m_aContext.Encryption.Encrypt() )
9794cdf0e10cSrcweir             {
9795cdf0e10cSrcweir                 enableStringEncryption( rObject.m_nObject );
9796cdf0e10cSrcweir                 //check encryption buffer size
9797cdf0e10cSrcweir                 if( checkEncryptionBufferSize( pAccess->GetPaletteEntryCount()*3 ) )
9798cdf0e10cSrcweir                 {
9799cdf0e10cSrcweir                     int nChar = 0;
9800cdf0e10cSrcweir                     //fill the encryption buffer
9801cdf0e10cSrcweir                     for( sal_uInt16 i = 0; i < pAccess->GetPaletteEntryCount(); i++ )
9802cdf0e10cSrcweir                     {
9803cdf0e10cSrcweir                         const BitmapColor& rColor = pAccess->GetPaletteColor( i );
9804cdf0e10cSrcweir                         m_pEncryptionBuffer[nChar++] = rColor.GetRed();
9805cdf0e10cSrcweir                         m_pEncryptionBuffer[nChar++] = rColor.GetGreen();
9806cdf0e10cSrcweir                         m_pEncryptionBuffer[nChar++] = rColor.GetBlue();
9807cdf0e10cSrcweir                     }
9808cdf0e10cSrcweir                     //encrypt the colorspace lookup table
9809cdf0e10cSrcweir                     rtl_cipher_encodeARCFOUR( m_aCipher, m_pEncryptionBuffer, nChar, m_pEncryptionBuffer, nChar );
9810cdf0e10cSrcweir                     //now queue the data for output
9811cdf0e10cSrcweir                     nChar = 0;
9812cdf0e10cSrcweir                     for( sal_uInt16 i = 0; i < pAccess->GetPaletteEntryCount(); i++ )
9813cdf0e10cSrcweir                     {
9814cdf0e10cSrcweir                         appendHex(m_pEncryptionBuffer[nChar++], aLine );
9815cdf0e10cSrcweir                         appendHex(m_pEncryptionBuffer[nChar++], aLine );
9816cdf0e10cSrcweir                         appendHex(m_pEncryptionBuffer[nChar++], aLine );
9817cdf0e10cSrcweir                     }
9818cdf0e10cSrcweir                 }
9819cdf0e10cSrcweir             }
9820cdf0e10cSrcweir             else //no encryption requested (PDF/A-1a program flow drops here)
9821cdf0e10cSrcweir             {
9822cdf0e10cSrcweir                 for( sal_uInt16 i = 0; i < pAccess->GetPaletteEntryCount(); i++ )
9823cdf0e10cSrcweir                 {
9824cdf0e10cSrcweir                     const BitmapColor& rColor = pAccess->GetPaletteColor( i );
9825cdf0e10cSrcweir                     appendHex( rColor.GetRed(), aLine );
9826cdf0e10cSrcweir                     appendHex( rColor.GetGreen(), aLine );
9827cdf0e10cSrcweir                     appendHex( rColor.GetBlue(), aLine );
9828cdf0e10cSrcweir                 }
9829cdf0e10cSrcweir             }
9830cdf0e10cSrcweir             aLine.append( ">\n]\n" );
9831cdf0e10cSrcweir         }
9832cdf0e10cSrcweir     }
9833cdf0e10cSrcweir     else
9834cdf0e10cSrcweir     {
9835cdf0e10cSrcweir         if( aBitmap.GetBitCount() == 1 )
9836cdf0e10cSrcweir         {
9837cdf0e10cSrcweir             aLine.append( "/ImageMask true\n" );
9838cdf0e10cSrcweir             sal_Int32 nBlackIndex = pAccess->GetBestPaletteIndex( BitmapColor( Color( COL_BLACK ) ) );
9839cdf0e10cSrcweir             DBG_ASSERT( nBlackIndex == 0 || nBlackIndex == 1, "wrong black index" );
9840cdf0e10cSrcweir             if( nBlackIndex )
9841cdf0e10cSrcweir                 aLine.append( "/Decode[ 1 0 ]\n" );
9842cdf0e10cSrcweir             else
9843cdf0e10cSrcweir                 aLine.append( "/Decode[ 0 1 ]\n" );
9844cdf0e10cSrcweir         }
9845cdf0e10cSrcweir         else if( aBitmap.GetBitCount() == 8 )
9846cdf0e10cSrcweir         {
9847cdf0e10cSrcweir             aLine.append( "/ColorSpace/DeviceGray\n"
9848cdf0e10cSrcweir                           "/Decode [ 1 0 ]\n" );
9849cdf0e10cSrcweir         }
9850cdf0e10cSrcweir     }
9851cdf0e10cSrcweir 
9852cdf0e10cSrcweir     if( ! bMask && m_aContext.Version > PDFWriter::PDF_1_2 && !m_bIsPDF_A1 )//i59651
9853cdf0e10cSrcweir     {
9854cdf0e10cSrcweir         if( bWriteMask )
9855cdf0e10cSrcweir         {
9856cdf0e10cSrcweir             nMaskObject = createObject();
9857cdf0e10cSrcweir             if( rObject.m_aBitmap.IsAlpha() && m_aContext.Version > PDFWriter::PDF_1_3 )
9858cdf0e10cSrcweir                 aLine.append( "/SMask " );
9859cdf0e10cSrcweir             else
9860cdf0e10cSrcweir                 aLine.append( "/Mask " );
9861cdf0e10cSrcweir             aLine.append( nMaskObject );
9862cdf0e10cSrcweir             aLine.append( " 0 R\n" );
9863cdf0e10cSrcweir         }
9864cdf0e10cSrcweir         else if( aTransparentColor != Color( COL_TRANSPARENT ) )
9865cdf0e10cSrcweir         {
9866cdf0e10cSrcweir             aLine.append( "/Mask[ " );
9867cdf0e10cSrcweir             if( bTrueColor )
9868cdf0e10cSrcweir             {
9869cdf0e10cSrcweir                 aLine.append( (sal_Int32)aTransparentColor.GetRed() );
9870cdf0e10cSrcweir                 aLine.append( ' ' );
9871cdf0e10cSrcweir                 aLine.append( (sal_Int32)aTransparentColor.GetRed() );
9872cdf0e10cSrcweir                 aLine.append( ' ' );
9873cdf0e10cSrcweir                 aLine.append( (sal_Int32)aTransparentColor.GetGreen() );
9874cdf0e10cSrcweir                 aLine.append( ' ' );
9875cdf0e10cSrcweir                 aLine.append( (sal_Int32)aTransparentColor.GetGreen() );
9876cdf0e10cSrcweir                 aLine.append( ' ' );
9877cdf0e10cSrcweir                 aLine.append( (sal_Int32)aTransparentColor.GetBlue() );
9878cdf0e10cSrcweir                 aLine.append( ' ' );
9879cdf0e10cSrcweir                 aLine.append( (sal_Int32)aTransparentColor.GetBlue() );
9880cdf0e10cSrcweir             }
9881cdf0e10cSrcweir             else
9882cdf0e10cSrcweir             {
9883cdf0e10cSrcweir                 sal_Int32 nIndex = pAccess->GetBestPaletteIndex( BitmapColor( aTransparentColor ) );
9884cdf0e10cSrcweir                 aLine.append( nIndex );
9885cdf0e10cSrcweir             }
9886cdf0e10cSrcweir             aLine.append( " ]\n" );
9887cdf0e10cSrcweir         }
9888cdf0e10cSrcweir     }
9889cdf0e10cSrcweir     else if( m_bIsPDF_A1 && (bWriteMask || aTransparentColor != Color( COL_TRANSPARENT )) )
9890cdf0e10cSrcweir         m_aErrors.insert( PDFWriter::Warning_Transparency_Omitted_PDFA );
9891cdf0e10cSrcweir 
9892cdf0e10cSrcweir     aLine.append( ">>\n"
9893cdf0e10cSrcweir                   "stream\n" );
9894cdf0e10cSrcweir     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
9895cdf0e10cSrcweir     sal_uInt64 nStartPos = 0;
9896cdf0e10cSrcweir     CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nStartPos )) );
9897cdf0e10cSrcweir 
9898cdf0e10cSrcweir     checkAndEnableStreamEncryption( rObject.m_nObject );
9899cdf0e10cSrcweir #ifndef DEBUG_DISABLE_PDFCOMPRESSION
9900cdf0e10cSrcweir     if( nBitsPerComponent == 1 )
9901cdf0e10cSrcweir     {
9902cdf0e10cSrcweir         writeG4Stream( pAccess );
9903cdf0e10cSrcweir     }
9904cdf0e10cSrcweir     else
9905cdf0e10cSrcweir #endif
9906cdf0e10cSrcweir     {
9907cdf0e10cSrcweir         beginCompression();
9908cdf0e10cSrcweir         if( ! bTrueColor || pAccess->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB )
9909cdf0e10cSrcweir         {
9910cdf0e10cSrcweir             const int nScanLineBytes = 1 + ( pAccess->GetBitCount() * ( pAccess->Width() - 1 ) / 8U );
9911cdf0e10cSrcweir 
9912cdf0e10cSrcweir             for( int i = 0; i < pAccess->Height(); i++ )
9913cdf0e10cSrcweir             {
9914cdf0e10cSrcweir                 CHECK_RETURN( writeBuffer( pAccess->GetScanline( i ), nScanLineBytes ) );
9915cdf0e10cSrcweir             }
9916cdf0e10cSrcweir         }
9917cdf0e10cSrcweir         else
9918cdf0e10cSrcweir         {
9919cdf0e10cSrcweir             const int nScanLineBytes = pAccess->Width()*3;
9920cdf0e10cSrcweir             boost::shared_array<sal_uInt8> pCol( new sal_uInt8[ nScanLineBytes ] );
9921cdf0e10cSrcweir             for( int y = 0; y < pAccess->Height(); y++ )
9922cdf0e10cSrcweir             {
9923cdf0e10cSrcweir                 for( int x = 0; x < pAccess->Width(); x++ )
9924cdf0e10cSrcweir                 {
9925cdf0e10cSrcweir                     BitmapColor aColor = pAccess->GetColor( y, x );
9926cdf0e10cSrcweir                     pCol[3*x+0] = aColor.GetRed();
9927cdf0e10cSrcweir                     pCol[3*x+1] = aColor.GetGreen();
9928cdf0e10cSrcweir                     pCol[3*x+2] = aColor.GetBlue();
9929cdf0e10cSrcweir                 }
9930cdf0e10cSrcweir                 CHECK_RETURN( writeBuffer( pCol.get(), nScanLineBytes ) );
9931cdf0e10cSrcweir             }
9932cdf0e10cSrcweir         }
9933cdf0e10cSrcweir         endCompression();
9934cdf0e10cSrcweir     }
9935cdf0e10cSrcweir     disableStreamEncryption();
9936cdf0e10cSrcweir 
9937cdf0e10cSrcweir     sal_uInt64 nEndPos = 0;
9938cdf0e10cSrcweir     CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nEndPos )) );
9939cdf0e10cSrcweir     aLine.setLength( 0 );
9940cdf0e10cSrcweir     aLine.append( "\nendstream\nendobj\n\n" );
9941cdf0e10cSrcweir     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
9942cdf0e10cSrcweir     CHECK_RETURN( updateObject( nStreamLengthObject ) );
9943cdf0e10cSrcweir     aLine.setLength( 0 );
9944cdf0e10cSrcweir     aLine.append( nStreamLengthObject );
9945cdf0e10cSrcweir     aLine.append( " 0 obj\n" );
9946cdf0e10cSrcweir     aLine.append( (sal_Int64)(nEndPos-nStartPos) );
9947cdf0e10cSrcweir     aLine.append( "\nendobj\n\n" );
9948cdf0e10cSrcweir     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
9949cdf0e10cSrcweir 
9950cdf0e10cSrcweir     if( nMaskObject )
9951cdf0e10cSrcweir     {
9952cdf0e10cSrcweir         BitmapEmit aEmit;
9953cdf0e10cSrcweir         aEmit.m_nObject             = nMaskObject;
9954cdf0e10cSrcweir         aEmit.m_aBitmap             = rObject.m_aBitmap;
9955cdf0e10cSrcweir         return writeBitmapObject( aEmit, true );
9956cdf0e10cSrcweir     }
9957cdf0e10cSrcweir 
9958cdf0e10cSrcweir     return true;
9959cdf0e10cSrcweir }
9960cdf0e10cSrcweir 
drawJPGBitmap(SvStream & rDCTData,bool bIsTrueColor,const Size & rSizePixel,const Rectangle & rTargetArea,const Bitmap & rMask)9961cdf0e10cSrcweir void PDFWriterImpl::drawJPGBitmap( SvStream& rDCTData, bool bIsTrueColor, const Size& rSizePixel, const Rectangle& rTargetArea, const Bitmap& rMask )
9962cdf0e10cSrcweir {
9963cdf0e10cSrcweir     MARK( "drawJPGBitmap" );
9964cdf0e10cSrcweir 
9965cdf0e10cSrcweir     OStringBuffer aLine( 80 );
9966cdf0e10cSrcweir     updateGraphicsState();
9967cdf0e10cSrcweir 
9968cdf0e10cSrcweir     // #i40055# sanity check
9969cdf0e10cSrcweir     if( ! (rTargetArea.GetWidth() && rTargetArea.GetHeight() ) )
9970cdf0e10cSrcweir         return;
9971cdf0e10cSrcweir     if( ! (rSizePixel.Width() && rSizePixel.Height()) )
9972cdf0e10cSrcweir         return;
9973cdf0e10cSrcweir 
9974cdf0e10cSrcweir     rDCTData.Seek( 0 );
9975cdf0e10cSrcweir     if( bIsTrueColor && m_aContext.ColorMode == PDFWriter::DrawGreyscale )
9976cdf0e10cSrcweir     {
9977cdf0e10cSrcweir         // need to convert to grayscale;
9978cdf0e10cSrcweir         // load stream to bitmap and draw the bitmap instead
9979cdf0e10cSrcweir         Graphic aGraphic;
9980cdf0e10cSrcweir         GraphicConverter::Import( rDCTData, aGraphic, CVT_JPG );
9981cdf0e10cSrcweir         Bitmap aBmp( aGraphic.GetBitmap() );
9982cdf0e10cSrcweir         if( !!rMask && rMask.GetSizePixel() == aBmp.GetSizePixel() )
9983cdf0e10cSrcweir         {
9984cdf0e10cSrcweir             BitmapEx aBmpEx( aBmp, rMask );
9985cdf0e10cSrcweir             drawBitmap( rTargetArea.TopLeft(), rTargetArea.GetSize(), aBmpEx );
9986cdf0e10cSrcweir         }
9987cdf0e10cSrcweir         else
9988cdf0e10cSrcweir             drawBitmap( rTargetArea.TopLeft(), rTargetArea.GetSize(), aBmp );
9989cdf0e10cSrcweir         return;
9990cdf0e10cSrcweir     }
9991cdf0e10cSrcweir 
9992cdf0e10cSrcweir     SvMemoryStream* pStream = new SvMemoryStream;
9993cdf0e10cSrcweir     *pStream << rDCTData;
9994cdf0e10cSrcweir     pStream->Seek( STREAM_SEEK_TO_END );
9995cdf0e10cSrcweir 
9996cdf0e10cSrcweir     BitmapID aID;
9997cdf0e10cSrcweir     aID.m_aPixelSize    = rSizePixel;
9998cdf0e10cSrcweir     aID.m_nSize         = pStream->Tell();
9999cdf0e10cSrcweir     pStream->Seek( STREAM_SEEK_TO_BEGIN );
10000cdf0e10cSrcweir     aID.m_nChecksum     = rtl_crc32( 0, pStream->GetData(), aID.m_nSize );
10001cdf0e10cSrcweir     if( ! rMask.IsEmpty() )
10002cdf0e10cSrcweir         aID.m_nMaskChecksum = rMask.GetChecksum();
10003cdf0e10cSrcweir 
10004cdf0e10cSrcweir     std::list< JPGEmit >::const_iterator it;
10005cdf0e10cSrcweir     for( it = m_aJPGs.begin(); it != m_aJPGs.end() && ! (aID == it->m_aID); ++it )
10006cdf0e10cSrcweir         ;
10007cdf0e10cSrcweir     if( it == m_aJPGs.end() )
10008cdf0e10cSrcweir     {
10009cdf0e10cSrcweir         m_aJPGs.push_front( JPGEmit() );
10010cdf0e10cSrcweir         JPGEmit& rEmit = m_aJPGs.front();
10011cdf0e10cSrcweir         rEmit.m_nObject     = createObject();
10012cdf0e10cSrcweir         rEmit.m_aID         = aID;
10013cdf0e10cSrcweir         rEmit.m_pStream     = pStream;
10014cdf0e10cSrcweir         rEmit.m_bTrueColor  = bIsTrueColor;
10015cdf0e10cSrcweir         if( !! rMask && rMask.GetSizePixel() == rSizePixel )
10016cdf0e10cSrcweir             rEmit.m_aMask   = rMask;
10017cdf0e10cSrcweir 
10018cdf0e10cSrcweir         it = m_aJPGs.begin();
10019cdf0e10cSrcweir     }
10020cdf0e10cSrcweir     else
10021cdf0e10cSrcweir         delete pStream;
10022cdf0e10cSrcweir 
10023cdf0e10cSrcweir     aLine.append( "q " );
10024cdf0e10cSrcweir     sal_Int32 nCheckWidth = 0;
10025cdf0e10cSrcweir     m_aPages.back().appendMappedLength( (sal_Int32)rTargetArea.GetWidth(), aLine, false, &nCheckWidth );
10026cdf0e10cSrcweir     aLine.append( " 0 0 " );
10027cdf0e10cSrcweir     sal_Int32 nCheckHeight = 0;
10028cdf0e10cSrcweir     m_aPages.back().appendMappedLength( (sal_Int32)rTargetArea.GetHeight(), aLine, true, &nCheckHeight );
10029cdf0e10cSrcweir     aLine.append( ' ' );
10030cdf0e10cSrcweir     m_aPages.back().appendPoint( rTargetArea.BottomLeft(), aLine );
10031cdf0e10cSrcweir     aLine.append( " cm\n/Im" );
10032cdf0e10cSrcweir     aLine.append( it->m_nObject );
10033cdf0e10cSrcweir     aLine.append( " Do Q\n" );
10034cdf0e10cSrcweir     if( nCheckWidth == 0 || nCheckHeight == 0 )
10035cdf0e10cSrcweir     {
10036cdf0e10cSrcweir         // #i97512# avoid invalid current matrix
10037cdf0e10cSrcweir         aLine.setLength( 0 );
10038cdf0e10cSrcweir         aLine.append( "\n%jpeg image /Im" );
10039cdf0e10cSrcweir         aLine.append( it->m_nObject );
10040cdf0e10cSrcweir         aLine.append( " scaled to zero size, omitted\n" );
10041cdf0e10cSrcweir     }
10042cdf0e10cSrcweir     writeBuffer( aLine.getStr(), aLine.getLength() );
10043cdf0e10cSrcweir 
10044cdf0e10cSrcweir     OStringBuffer aObjName( 16 );
10045cdf0e10cSrcweir     aObjName.append( "Im" );
10046cdf0e10cSrcweir     aObjName.append( it->m_nObject );
10047cdf0e10cSrcweir     pushResource( ResXObject, aObjName.makeStringAndClear(), it->m_nObject );
10048cdf0e10cSrcweir 
10049cdf0e10cSrcweir }
10050cdf0e10cSrcweir 
drawBitmap(const Point & rDestPoint,const Size & rDestSize,const BitmapEmit & rBitmap,const Color & rFillColor)10051cdf0e10cSrcweir void PDFWriterImpl::drawBitmap( const Point& rDestPoint, const Size& rDestSize, const BitmapEmit& rBitmap, const Color& rFillColor )
10052cdf0e10cSrcweir {
10053cdf0e10cSrcweir     OStringBuffer aLine( 80 );
10054cdf0e10cSrcweir     updateGraphicsState();
10055cdf0e10cSrcweir 
10056cdf0e10cSrcweir     aLine.append( "q " );
10057cdf0e10cSrcweir     if( rFillColor != Color( COL_TRANSPARENT ) )
10058cdf0e10cSrcweir     {
10059cdf0e10cSrcweir         appendNonStrokingColor( rFillColor, aLine );
10060cdf0e10cSrcweir         aLine.append( ' ' );
10061cdf0e10cSrcweir     }
10062cdf0e10cSrcweir     sal_Int32 nCheckWidth = 0;
10063cdf0e10cSrcweir     m_aPages.back().appendMappedLength( (sal_Int32)rDestSize.Width(), aLine, false, &nCheckWidth );
10064cdf0e10cSrcweir     aLine.append( " 0 0 " );
10065cdf0e10cSrcweir     sal_Int32 nCheckHeight = 0;
10066cdf0e10cSrcweir     m_aPages.back().appendMappedLength( (sal_Int32)rDestSize.Height(), aLine, true, &nCheckHeight );
10067cdf0e10cSrcweir     aLine.append( ' ' );
10068cdf0e10cSrcweir     m_aPages.back().appendPoint( rDestPoint + Point( 0, rDestSize.Height()-1 ), aLine );
10069cdf0e10cSrcweir     aLine.append( " cm\n/Im" );
10070cdf0e10cSrcweir     aLine.append( rBitmap.m_nObject );
10071cdf0e10cSrcweir     aLine.append( " Do Q\n" );
10072cdf0e10cSrcweir     if( nCheckWidth == 0 || nCheckHeight == 0 )
10073cdf0e10cSrcweir     {
10074cdf0e10cSrcweir         // #i97512# avoid invalid current matrix
10075cdf0e10cSrcweir         aLine.setLength( 0 );
10076cdf0e10cSrcweir         aLine.append( "\n%bitmap image /Im" );
10077cdf0e10cSrcweir         aLine.append( rBitmap.m_nObject );
10078cdf0e10cSrcweir         aLine.append( " scaled to zero size, omitted\n" );
10079cdf0e10cSrcweir     }
10080cdf0e10cSrcweir     writeBuffer( aLine.getStr(), aLine.getLength() );
10081cdf0e10cSrcweir }
10082cdf0e10cSrcweir 
createBitmapEmit(const BitmapEx & i_rBitmap,bool bDrawMask)10083cdf0e10cSrcweir const PDFWriterImpl::BitmapEmit& PDFWriterImpl::createBitmapEmit( const BitmapEx& i_rBitmap, bool bDrawMask )
10084cdf0e10cSrcweir {
10085cdf0e10cSrcweir     BitmapEx aBitmap( i_rBitmap );
10086cdf0e10cSrcweir     if( m_aContext.ColorMode == PDFWriter::DrawGreyscale )
10087cdf0e10cSrcweir     {
10088cdf0e10cSrcweir         BmpConversion eConv = BMP_CONVERSION_8BIT_GREYS;
10089cdf0e10cSrcweir         int nDepth = aBitmap.GetBitmap().GetBitCount();
10090cdf0e10cSrcweir         if( nDepth <= 4 )
10091cdf0e10cSrcweir             eConv = BMP_CONVERSION_4BIT_GREYS;
10092cdf0e10cSrcweir         if( nDepth > 1 )
10093cdf0e10cSrcweir             aBitmap.Convert( eConv );
10094cdf0e10cSrcweir     }
10095cdf0e10cSrcweir     BitmapID aID;
10096cdf0e10cSrcweir     aID.m_aPixelSize        = aBitmap.GetSizePixel();
10097cdf0e10cSrcweir     aID.m_nSize             = aBitmap.GetBitCount();
10098cdf0e10cSrcweir     aID.m_nChecksum         = aBitmap.GetBitmap().GetChecksum();
10099cdf0e10cSrcweir     aID.m_nMaskChecksum     = 0;
10100cdf0e10cSrcweir     if( aBitmap.IsAlpha() )
10101cdf0e10cSrcweir         aID.m_nMaskChecksum = aBitmap.GetAlpha().GetChecksum();
10102cdf0e10cSrcweir     else
10103cdf0e10cSrcweir     {
10104cdf0e10cSrcweir         Bitmap aMask = aBitmap.GetMask();
10105cdf0e10cSrcweir         if( ! aMask.IsEmpty() )
10106cdf0e10cSrcweir             aID.m_nMaskChecksum = aMask.GetChecksum();
10107cdf0e10cSrcweir     }
10108cdf0e10cSrcweir     std::list< BitmapEmit >::const_iterator it;
10109cdf0e10cSrcweir     for( it = m_aBitmaps.begin(); it != m_aBitmaps.end(); ++it )
10110cdf0e10cSrcweir     {
10111cdf0e10cSrcweir         if( aID == it->m_aID )
10112cdf0e10cSrcweir             break;
10113cdf0e10cSrcweir     }
10114cdf0e10cSrcweir     if( it == m_aBitmaps.end() )
10115cdf0e10cSrcweir     {
10116cdf0e10cSrcweir         m_aBitmaps.push_front( BitmapEmit() );
10117cdf0e10cSrcweir         m_aBitmaps.front().m_aID        = aID;
10118cdf0e10cSrcweir         m_aBitmaps.front().m_aBitmap    = aBitmap;
10119cdf0e10cSrcweir         m_aBitmaps.front().m_nObject    = createObject();
10120cdf0e10cSrcweir         m_aBitmaps.front().m_bDrawMask  = bDrawMask;
10121cdf0e10cSrcweir         it = m_aBitmaps.begin();
10122cdf0e10cSrcweir     }
10123cdf0e10cSrcweir 
10124cdf0e10cSrcweir     OStringBuffer aObjName( 16 );
10125cdf0e10cSrcweir     aObjName.append( "Im" );
10126cdf0e10cSrcweir     aObjName.append( it->m_nObject );
10127cdf0e10cSrcweir     pushResource( ResXObject, aObjName.makeStringAndClear(), it->m_nObject );
10128cdf0e10cSrcweir 
10129cdf0e10cSrcweir     return *it;
10130cdf0e10cSrcweir }
10131cdf0e10cSrcweir 
drawBitmap(const Point & rDestPoint,const Size & rDestSize,const Bitmap & rBitmap)10132cdf0e10cSrcweir void PDFWriterImpl::drawBitmap( const Point& rDestPoint, const Size& rDestSize, const Bitmap& rBitmap )
10133cdf0e10cSrcweir {
10134cdf0e10cSrcweir     MARK( "drawBitmap (Bitmap)" );
10135cdf0e10cSrcweir 
10136cdf0e10cSrcweir     // #i40055# sanity check
10137cdf0e10cSrcweir     if( ! (rDestSize.Width() && rDestSize.Height()) )
10138cdf0e10cSrcweir         return;
10139cdf0e10cSrcweir 
10140cdf0e10cSrcweir     const BitmapEmit& rEmit = createBitmapEmit( BitmapEx( rBitmap ) );
10141cdf0e10cSrcweir     drawBitmap( rDestPoint, rDestSize, rEmit, Color( COL_TRANSPARENT ) );
10142cdf0e10cSrcweir }
10143cdf0e10cSrcweir 
drawBitmap(const Point & rDestPoint,const Size & rDestSize,const BitmapEx & rBitmap)10144cdf0e10cSrcweir void PDFWriterImpl::drawBitmap( const Point& rDestPoint, const Size& rDestSize, const BitmapEx& rBitmap )
10145cdf0e10cSrcweir {
10146cdf0e10cSrcweir     MARK( "drawBitmap (BitmapEx)" );
10147cdf0e10cSrcweir 
10148cdf0e10cSrcweir     // #i40055# sanity check
10149cdf0e10cSrcweir     if( ! (rDestSize.Width() && rDestSize.Height()) )
10150cdf0e10cSrcweir         return;
10151cdf0e10cSrcweir 
10152cdf0e10cSrcweir     const BitmapEmit& rEmit = createBitmapEmit( rBitmap );
10153cdf0e10cSrcweir     drawBitmap( rDestPoint, rDestSize, rEmit, Color( COL_TRANSPARENT ) );
10154cdf0e10cSrcweir }
10155cdf0e10cSrcweir 
drawMask(const Point & rDestPoint,const Size & rDestSize,const Bitmap & rBitmap,const Color & rFillColor)10156cdf0e10cSrcweir void PDFWriterImpl::drawMask( const Point& rDestPoint, const Size& rDestSize, const Bitmap& rBitmap, const Color& rFillColor )
10157cdf0e10cSrcweir {
10158cdf0e10cSrcweir     MARK( "drawMask" );
10159cdf0e10cSrcweir 
10160cdf0e10cSrcweir     // #i40055# sanity check
10161cdf0e10cSrcweir     if( ! (rDestSize.Width() && rDestSize.Height()) )
10162cdf0e10cSrcweir         return;
10163cdf0e10cSrcweir 
10164cdf0e10cSrcweir     Bitmap aBitmap( rBitmap );
10165cdf0e10cSrcweir     if( aBitmap.GetBitCount() > 1 )
10166cdf0e10cSrcweir         aBitmap.Convert( BMP_CONVERSION_1BIT_THRESHOLD );
10167cdf0e10cSrcweir     DBG_ASSERT( aBitmap.GetBitCount() == 1, "mask conversion failed" );
10168cdf0e10cSrcweir 
10169cdf0e10cSrcweir     const BitmapEmit& rEmit = createBitmapEmit( BitmapEx( aBitmap ), true );
10170cdf0e10cSrcweir     drawBitmap( rDestPoint, rDestSize, rEmit, rFillColor );
10171cdf0e10cSrcweir }
10172cdf0e10cSrcweir 
createGradient(const Gradient & rGradient,const Size & rSize)10173cdf0e10cSrcweir sal_Int32 PDFWriterImpl::createGradient( const Gradient& rGradient, const Size& rSize )
10174cdf0e10cSrcweir {
10175cdf0e10cSrcweir     Size aPtSize( lcl_convert( m_aGraphicsStack.front().m_aMapMode,
10176cdf0e10cSrcweir                                MapMode( MAP_POINT ),
10177cdf0e10cSrcweir                                getReferenceDevice(),
10178cdf0e10cSrcweir                                rSize ) );
10179cdf0e10cSrcweir     // check if we already have this gradient
10180cdf0e10cSrcweir     std::list<GradientEmit>::iterator it;
10181cdf0e10cSrcweir     // rounding to point will generally lose some pixels
10182cdf0e10cSrcweir     // round up to point boundary
10183cdf0e10cSrcweir     aPtSize.Width()++;
10184cdf0e10cSrcweir     aPtSize.Height()++;
10185cdf0e10cSrcweir     for( it = m_aGradients.begin(); it != m_aGradients.end(); ++it )
10186cdf0e10cSrcweir     {
10187cdf0e10cSrcweir         if( it->m_aGradient == rGradient )
10188cdf0e10cSrcweir         {
10189cdf0e10cSrcweir             if( it->m_aSize == aPtSize )
10190cdf0e10cSrcweir                 break;
10191cdf0e10cSrcweir         }
10192cdf0e10cSrcweir     }
10193cdf0e10cSrcweir     if( it == m_aGradients.end() )
10194cdf0e10cSrcweir     {
10195cdf0e10cSrcweir         m_aGradients.push_front( GradientEmit() );
10196cdf0e10cSrcweir         m_aGradients.front().m_aGradient    = rGradient;
10197cdf0e10cSrcweir         m_aGradients.front().m_nObject      = createObject();
10198cdf0e10cSrcweir         m_aGradients.front().m_aSize        = aPtSize;
10199cdf0e10cSrcweir         it = m_aGradients.begin();
10200cdf0e10cSrcweir     }
10201cdf0e10cSrcweir 
10202cdf0e10cSrcweir     OStringBuffer aObjName( 16 );
10203cdf0e10cSrcweir     aObjName.append( 'P' );
10204cdf0e10cSrcweir     aObjName.append( it->m_nObject );
10205cdf0e10cSrcweir     pushResource( ResShading, aObjName.makeStringAndClear(), it->m_nObject );
10206cdf0e10cSrcweir 
10207cdf0e10cSrcweir     return it->m_nObject;
10208cdf0e10cSrcweir }
10209cdf0e10cSrcweir 
drawGradient(const Rectangle & rRect,const Gradient & rGradient)10210cdf0e10cSrcweir void PDFWriterImpl::drawGradient( const Rectangle& rRect, const Gradient& rGradient )
10211cdf0e10cSrcweir {
10212cdf0e10cSrcweir     MARK( "drawGradient (Rectangle)" );
10213cdf0e10cSrcweir 
10214cdf0e10cSrcweir     if( m_aContext.Version == PDFWriter::PDF_1_2 )
10215cdf0e10cSrcweir     {
10216cdf0e10cSrcweir         drawRectangle( rRect );
10217cdf0e10cSrcweir         return;
10218cdf0e10cSrcweir     }
10219cdf0e10cSrcweir 
10220cdf0e10cSrcweir     sal_Int32 nGradient = createGradient( rGradient, rRect.GetSize() );
10221cdf0e10cSrcweir 
10222cdf0e10cSrcweir     Point aTranslate( rRect.BottomLeft() );
10223cdf0e10cSrcweir     aTranslate += Point( 0, 1 );
10224cdf0e10cSrcweir 
10225cdf0e10cSrcweir     updateGraphicsState();
10226cdf0e10cSrcweir 
10227cdf0e10cSrcweir     OStringBuffer aLine( 80 );
10228cdf0e10cSrcweir     aLine.append( "q 1 0 0 1 " );
10229cdf0e10cSrcweir     m_aPages.back().appendPoint( aTranslate, aLine );
10230cdf0e10cSrcweir     aLine.append( " cm " );
10231cdf0e10cSrcweir     // if a stroke is appended reset the clip region before stroke
10232cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
10233cdf0e10cSrcweir         aLine.append( "q " );
10234cdf0e10cSrcweir     aLine.append( "0 0 " );
10235cdf0e10cSrcweir     m_aPages.back().appendMappedLength( (sal_Int32)rRect.GetWidth(), aLine, false );
10236cdf0e10cSrcweir     aLine.append( ' ' );
10237cdf0e10cSrcweir     m_aPages.back().appendMappedLength( (sal_Int32)rRect.GetHeight(), aLine, true );
10238cdf0e10cSrcweir     aLine.append( " re W n\n" );
10239cdf0e10cSrcweir 
10240cdf0e10cSrcweir     aLine.append( "/P" );
10241cdf0e10cSrcweir     aLine.append( nGradient );
10242cdf0e10cSrcweir     aLine.append( " sh " );
10243cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
10244cdf0e10cSrcweir     {
10245cdf0e10cSrcweir         aLine.append( "Q 0 0 " );
10246cdf0e10cSrcweir         m_aPages.back().appendMappedLength( (sal_Int32)rRect.GetWidth(), aLine, false );
10247cdf0e10cSrcweir         aLine.append( ' ' );
10248cdf0e10cSrcweir         m_aPages.back().appendMappedLength( (sal_Int32)rRect.GetHeight(), aLine, true );
10249cdf0e10cSrcweir         aLine.append( " re S " );
10250cdf0e10cSrcweir     }
10251cdf0e10cSrcweir     aLine.append( "Q\n" );
10252cdf0e10cSrcweir     writeBuffer( aLine.getStr(), aLine.getLength() );
10253cdf0e10cSrcweir }
10254cdf0e10cSrcweir 
drawGradient(const PolyPolygon & rPolyPoly,const Gradient & rGradient)10255cdf0e10cSrcweir void PDFWriterImpl::drawGradient( const PolyPolygon& rPolyPoly, const Gradient& rGradient )
10256cdf0e10cSrcweir {
10257cdf0e10cSrcweir     MARK( "drawGradient (PolyPolygon)" );
10258cdf0e10cSrcweir 
10259cdf0e10cSrcweir     if( m_aContext.Version == PDFWriter::PDF_1_2 )
10260cdf0e10cSrcweir     {
10261cdf0e10cSrcweir         drawPolyPolygon( rPolyPoly );
10262cdf0e10cSrcweir         return;
10263cdf0e10cSrcweir     }
10264cdf0e10cSrcweir 
10265cdf0e10cSrcweir     Rectangle aBoundRect = rPolyPoly.GetBoundRect();
10266cdf0e10cSrcweir     sal_Int32 nGradient = createGradient( rGradient, aBoundRect.GetSize() );
10267cdf0e10cSrcweir 
10268cdf0e10cSrcweir     updateGraphicsState();
10269cdf0e10cSrcweir 
10270cdf0e10cSrcweir     Point aTranslate = aBoundRect.BottomLeft();
10271cdf0e10cSrcweir     int nPolygons = rPolyPoly.Count();
10272cdf0e10cSrcweir 
10273cdf0e10cSrcweir     OStringBuffer aLine( 80*nPolygons );
10274cdf0e10cSrcweir     aLine.append( "q " );
10275cdf0e10cSrcweir     // set PolyPolygon as clip path
10276cdf0e10cSrcweir     m_aPages.back().appendPolyPolygon( rPolyPoly, aLine );
10277cdf0e10cSrcweir     aLine.append( "W* n\n" );
10278cdf0e10cSrcweir     aLine.append( "1 0 0 1 " );
10279cdf0e10cSrcweir     m_aPages.back().appendPoint( aTranslate, aLine );
10280cdf0e10cSrcweir     aLine.append( " cm\n" );
10281cdf0e10cSrcweir     aLine.append( "/P" );
10282cdf0e10cSrcweir     aLine.append( nGradient );
10283cdf0e10cSrcweir     aLine.append( " sh Q\n" );
10284cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
10285cdf0e10cSrcweir     {
10286cdf0e10cSrcweir         // and draw the surrounding path
10287cdf0e10cSrcweir         m_aPages.back().appendPolyPolygon( rPolyPoly, aLine );
10288cdf0e10cSrcweir         aLine.append( "S\n" );
10289cdf0e10cSrcweir     }
10290cdf0e10cSrcweir     writeBuffer( aLine.getStr(), aLine.getLength() );
10291cdf0e10cSrcweir }
10292cdf0e10cSrcweir 
drawHatch(const PolyPolygon & rPolyPoly,const Hatch & rHatch)10293cdf0e10cSrcweir void PDFWriterImpl::drawHatch( const PolyPolygon& rPolyPoly, const Hatch& rHatch )
10294cdf0e10cSrcweir {
10295cdf0e10cSrcweir     MARK( "drawHatch" );
10296cdf0e10cSrcweir 
10297cdf0e10cSrcweir     updateGraphicsState();
10298cdf0e10cSrcweir 
10299cdf0e10cSrcweir     if( rPolyPoly.Count() )
10300cdf0e10cSrcweir     {
10301cdf0e10cSrcweir         PolyPolygon     aPolyPoly( rPolyPoly );
10302cdf0e10cSrcweir 
10303cdf0e10cSrcweir         aPolyPoly.Optimize( POLY_OPTIMIZE_NO_SAME );
10304cdf0e10cSrcweir         push( PUSH_LINECOLOR );
10305cdf0e10cSrcweir         setLineColor( rHatch.GetColor() );
10306cdf0e10cSrcweir         getReferenceDevice()->ImplDrawHatch( aPolyPoly, rHatch, sal_False );
10307cdf0e10cSrcweir         pop();
10308cdf0e10cSrcweir     }
10309cdf0e10cSrcweir }
10310cdf0e10cSrcweir 
drawWallpaper(const Rectangle & rRect,const Wallpaper & rWall)10311cdf0e10cSrcweir void PDFWriterImpl::drawWallpaper( const Rectangle& rRect, const Wallpaper& rWall )
10312cdf0e10cSrcweir {
10313cdf0e10cSrcweir     MARK( "drawWallpaper" );
10314cdf0e10cSrcweir 
10315cdf0e10cSrcweir     bool bDrawColor         = false;
10316cdf0e10cSrcweir     bool bDrawGradient      = false;
10317cdf0e10cSrcweir     bool bDrawBitmap        = false;
10318cdf0e10cSrcweir 
10319cdf0e10cSrcweir     BitmapEx aBitmap;
10320cdf0e10cSrcweir     Point aBmpPos = rRect.TopLeft();
10321cdf0e10cSrcweir     Size aBmpSize;
10322cdf0e10cSrcweir     if( rWall.IsBitmap() )
10323cdf0e10cSrcweir     {
10324cdf0e10cSrcweir         aBitmap = rWall.GetBitmap();
10325cdf0e10cSrcweir         aBmpSize = lcl_convert( aBitmap.GetPrefMapMode(),
10326cdf0e10cSrcweir                                 getMapMode(),
10327cdf0e10cSrcweir                                 getReferenceDevice(),
10328cdf0e10cSrcweir                                 aBitmap.GetPrefSize() );
10329cdf0e10cSrcweir         Rectangle aRect( rRect );
10330cdf0e10cSrcweir         if( rWall.IsRect() )
10331cdf0e10cSrcweir         {
10332cdf0e10cSrcweir             aRect = rWall.GetRect();
10333cdf0e10cSrcweir             aBmpPos = aRect.TopLeft();
10334cdf0e10cSrcweir             aBmpSize = aRect.GetSize();
10335cdf0e10cSrcweir         }
10336cdf0e10cSrcweir         if( rWall.GetStyle() != WALLPAPER_SCALE )
10337cdf0e10cSrcweir         {
10338cdf0e10cSrcweir             if( rWall.GetStyle() != WALLPAPER_TILE )
10339cdf0e10cSrcweir             {
10340cdf0e10cSrcweir                 bDrawBitmap     = true;
10341cdf0e10cSrcweir                 if( rWall.IsGradient() )
10342cdf0e10cSrcweir                     bDrawGradient = true;
10343cdf0e10cSrcweir                 else
10344cdf0e10cSrcweir                     bDrawColor = true;
10345cdf0e10cSrcweir                 switch( rWall.GetStyle() )
10346cdf0e10cSrcweir                 {
10347cdf0e10cSrcweir                     case WALLPAPER_TOPLEFT:
10348cdf0e10cSrcweir                         break;
10349cdf0e10cSrcweir                     case WALLPAPER_TOP:
10350cdf0e10cSrcweir                         aBmpPos.X() += (aRect.GetWidth()-aBmpSize.Width())/2;
10351cdf0e10cSrcweir                         break;
10352cdf0e10cSrcweir                     case WALLPAPER_LEFT:
10353cdf0e10cSrcweir                         aBmpPos.Y() += (aRect.GetHeight()-aBmpSize.Height())/2;
10354cdf0e10cSrcweir                         break;
10355cdf0e10cSrcweir                     case WALLPAPER_TOPRIGHT:
10356cdf0e10cSrcweir                         aBmpPos.X() += aRect.GetWidth()-aBmpSize.Width();
10357cdf0e10cSrcweir                         break;
10358cdf0e10cSrcweir                     case WALLPAPER_CENTER:
10359cdf0e10cSrcweir                         aBmpPos.X() += (aRect.GetWidth()-aBmpSize.Width())/2;
10360cdf0e10cSrcweir                         aBmpPos.Y() += (aRect.GetHeight()-aBmpSize.Height())/2;
10361cdf0e10cSrcweir                         break;
10362cdf0e10cSrcweir                     case WALLPAPER_RIGHT:
10363cdf0e10cSrcweir                         aBmpPos.X() += aRect.GetWidth()-aBmpSize.Width();
10364cdf0e10cSrcweir                         aBmpPos.Y() += (aRect.GetHeight()-aBmpSize.Height())/2;
10365cdf0e10cSrcweir                         break;
10366cdf0e10cSrcweir                     case WALLPAPER_BOTTOMLEFT:
10367cdf0e10cSrcweir                         aBmpPos.Y() += aRect.GetHeight()-aBmpSize.Height();
10368cdf0e10cSrcweir                         break;
10369cdf0e10cSrcweir                     case WALLPAPER_BOTTOM:
10370cdf0e10cSrcweir                         aBmpPos.X() += (aRect.GetWidth()-aBmpSize.Width())/2;
10371cdf0e10cSrcweir                         aBmpPos.Y() += aRect.GetHeight()-aBmpSize.Height();
10372cdf0e10cSrcweir                         break;
10373cdf0e10cSrcweir                     case WALLPAPER_BOTTOMRIGHT:
10374cdf0e10cSrcweir                         aBmpPos.X() += aRect.GetWidth()-aBmpSize.Width();
10375cdf0e10cSrcweir                         aBmpPos.Y() += aRect.GetHeight()-aBmpSize.Height();
10376cdf0e10cSrcweir                         break;
10377cdf0e10cSrcweir                     default: ;
10378cdf0e10cSrcweir                 }
10379cdf0e10cSrcweir             }
10380cdf0e10cSrcweir             else
10381cdf0e10cSrcweir             {
10382cdf0e10cSrcweir                 // push the bitmap
10383cdf0e10cSrcweir                 const BitmapEmit& rEmit = createBitmapEmit( BitmapEx( aBitmap ) );
10384cdf0e10cSrcweir 
10385cdf0e10cSrcweir                 // convert to page coordinates; this needs to be done here
10386cdf0e10cSrcweir                 // since the emit does not know the page anymore
10387cdf0e10cSrcweir                 Rectangle aConvertRect( aBmpPos, aBmpSize );
10388cdf0e10cSrcweir                 m_aPages.back().convertRect( aConvertRect );
10389cdf0e10cSrcweir 
10390cdf0e10cSrcweir                 OStringBuffer aNameBuf(16);
10391cdf0e10cSrcweir                 aNameBuf.append( "Im" );
10392cdf0e10cSrcweir                 aNameBuf.append( rEmit.m_nObject );
10393cdf0e10cSrcweir                 OString aImageName( aNameBuf.makeStringAndClear() );
10394cdf0e10cSrcweir 
10395cdf0e10cSrcweir                 // push the pattern
10396cdf0e10cSrcweir                 OStringBuffer aTilingStream( 32 );
10397cdf0e10cSrcweir                 appendFixedInt( aConvertRect.GetWidth(), aTilingStream );
10398cdf0e10cSrcweir                 aTilingStream.append( " 0 0 " );
10399cdf0e10cSrcweir                 appendFixedInt( aConvertRect.GetHeight(), aTilingStream );
10400cdf0e10cSrcweir                 aTilingStream.append( " 0 0 cm\n/" );
10401cdf0e10cSrcweir                 aTilingStream.append( aImageName );
10402cdf0e10cSrcweir                 aTilingStream.append( " Do\n" );
10403cdf0e10cSrcweir 
10404cdf0e10cSrcweir                 m_aTilings.push_back( TilingEmit() );
10405cdf0e10cSrcweir                 m_aTilings.back().m_nObject         = createObject();
10406cdf0e10cSrcweir                 m_aTilings.back().m_aRectangle      = Rectangle( Point( 0, 0 ), aConvertRect.GetSize() );
10407cdf0e10cSrcweir                 m_aTilings.back().m_pTilingStream   = new SvMemoryStream();
10408cdf0e10cSrcweir                 m_aTilings.back().m_pTilingStream->Write( aTilingStream.getStr(), aTilingStream.getLength() );
10409cdf0e10cSrcweir                 // phase the tiling so wallpaper begins on upper left
10410cdf0e10cSrcweir                 m_aTilings.back().m_aTransform.matrix[2] = double(aConvertRect.Left() % aConvertRect.GetWidth()) / fDivisor;
10411cdf0e10cSrcweir                 m_aTilings.back().m_aTransform.matrix[5] = double(aConvertRect.Top() % aConvertRect.GetHeight()) / fDivisor;
10412cdf0e10cSrcweir                 m_aTilings.back().m_aResources.m_aXObjects[aImageName] = rEmit.m_nObject;
10413cdf0e10cSrcweir 
10414cdf0e10cSrcweir                 updateGraphicsState();
10415cdf0e10cSrcweir 
10416cdf0e10cSrcweir                 OStringBuffer aObjName( 16 );
10417cdf0e10cSrcweir                 aObjName.append( 'P' );
10418cdf0e10cSrcweir                 aObjName.append( m_aTilings.back().m_nObject );
10419cdf0e10cSrcweir                 OString aPatternName( aObjName.makeStringAndClear() );
10420cdf0e10cSrcweir                 pushResource( ResPattern, aPatternName, m_aTilings.back().m_nObject );
10421cdf0e10cSrcweir 
10422cdf0e10cSrcweir                 // fill a rRect with the pattern
10423cdf0e10cSrcweir                 OStringBuffer aLine( 100 );
10424cdf0e10cSrcweir                 aLine.append( "q /Pattern cs /" );
10425cdf0e10cSrcweir                 aLine.append( aPatternName );
10426cdf0e10cSrcweir                 aLine.append( " scn " );
10427cdf0e10cSrcweir                 m_aPages.back().appendRect( rRect, aLine );
10428cdf0e10cSrcweir                 aLine.append( " f Q\n" );
10429cdf0e10cSrcweir                 writeBuffer( aLine.getStr(), aLine.getLength() );
10430cdf0e10cSrcweir             }
10431cdf0e10cSrcweir         }
10432cdf0e10cSrcweir         else
10433cdf0e10cSrcweir         {
10434cdf0e10cSrcweir             aBmpPos     = aRect.TopLeft();
10435cdf0e10cSrcweir             aBmpSize    = aRect.GetSize();
10436cdf0e10cSrcweir             bDrawBitmap = true;
10437cdf0e10cSrcweir         }
10438cdf0e10cSrcweir 
10439cdf0e10cSrcweir         if( aBitmap.IsTransparent() )
10440cdf0e10cSrcweir         {
10441cdf0e10cSrcweir             if( rWall.IsGradient() )
10442cdf0e10cSrcweir                 bDrawGradient = true;
10443cdf0e10cSrcweir             else
10444cdf0e10cSrcweir                 bDrawColor = true;
10445cdf0e10cSrcweir         }
10446cdf0e10cSrcweir     }
10447cdf0e10cSrcweir     else if( rWall.IsGradient() )
10448cdf0e10cSrcweir         bDrawGradient = true;
10449cdf0e10cSrcweir     else
10450cdf0e10cSrcweir         bDrawColor = true;
10451cdf0e10cSrcweir 
10452cdf0e10cSrcweir     if( bDrawGradient )
10453cdf0e10cSrcweir     {
10454cdf0e10cSrcweir         drawGradient( rRect, rWall.GetGradient() );
10455cdf0e10cSrcweir     }
10456cdf0e10cSrcweir     if( bDrawColor )
10457cdf0e10cSrcweir     {
10458cdf0e10cSrcweir         Color aOldLineColor = m_aGraphicsStack.front().m_aLineColor;
10459cdf0e10cSrcweir         Color aOldFillColor = m_aGraphicsStack.front().m_aFillColor;
10460cdf0e10cSrcweir         setLineColor( Color( COL_TRANSPARENT ) );
10461cdf0e10cSrcweir         setFillColor( rWall.GetColor() );
10462cdf0e10cSrcweir         drawRectangle( rRect );
10463cdf0e10cSrcweir         setLineColor( aOldLineColor );
10464cdf0e10cSrcweir         setFillColor( aOldFillColor );
10465cdf0e10cSrcweir     }
10466cdf0e10cSrcweir     if( bDrawBitmap )
10467cdf0e10cSrcweir     {
10468cdf0e10cSrcweir         // set temporary clip region since aBmpPos and aBmpSize
10469cdf0e10cSrcweir         // may be outside rRect
10470cdf0e10cSrcweir         OStringBuffer aLine( 20 );
10471cdf0e10cSrcweir         aLine.append( "q " );
10472cdf0e10cSrcweir         m_aPages.back().appendRect( rRect, aLine );
10473cdf0e10cSrcweir         aLine.append( " W n\n" );
10474cdf0e10cSrcweir         writeBuffer( aLine.getStr(), aLine.getLength() );
10475cdf0e10cSrcweir         drawBitmap( aBmpPos, aBmpSize, aBitmap );
10476cdf0e10cSrcweir         writeBuffer( "Q\n", 2 );
10477cdf0e10cSrcweir     }
10478cdf0e10cSrcweir }
10479cdf0e10cSrcweir 
beginPattern(const Rectangle & rCellRect)10480cdf0e10cSrcweir void PDFWriterImpl::beginPattern( const Rectangle& rCellRect )
10481cdf0e10cSrcweir {
10482cdf0e10cSrcweir     beginRedirect( new SvMemoryStream(), rCellRect );
10483cdf0e10cSrcweir }
10484cdf0e10cSrcweir 
endPattern(const SvtGraphicFill::Transform & rTransform)10485cdf0e10cSrcweir sal_Int32 PDFWriterImpl::endPattern( const SvtGraphicFill::Transform& rTransform )
10486cdf0e10cSrcweir {
10487cdf0e10cSrcweir     Rectangle aConvertRect( getRedirectTargetRect() );
10488cdf0e10cSrcweir     DBG_ASSERT( aConvertRect.GetWidth() != 0 && aConvertRect.GetHeight() != 0, "empty cell rectangle in pattern" );
10489cdf0e10cSrcweir 
10490cdf0e10cSrcweir     // get scaling between current mapmode and PDF output
10491cdf0e10cSrcweir     Size aScaling( lcl_convert( m_aGraphicsStack.front().m_aMapMode, m_aMapMode, getReferenceDevice(), Size( 10000, 10000 ) ) );
10492cdf0e10cSrcweir     double fSX = (double(aScaling.Width()) / 10000.0);
10493cdf0e10cSrcweir     double fSY = (double(aScaling.Height()) / 10000.0);
10494cdf0e10cSrcweir 
10495cdf0e10cSrcweir     // transform translation part of matrix
10496cdf0e10cSrcweir     Size aTranslation( (long)rTransform.matrix[2], (long)rTransform.matrix[5] );
10497cdf0e10cSrcweir     aTranslation = lcl_convert( m_aGraphicsStack.front().m_aMapMode, m_aMapMode, getReferenceDevice(), aTranslation );
10498cdf0e10cSrcweir 
10499cdf0e10cSrcweir     sal_Int32 nTilingId = m_aTilings.size();
10500cdf0e10cSrcweir     m_aTilings.push_back( TilingEmit() );
10501cdf0e10cSrcweir     TilingEmit& rTile = m_aTilings.back();
10502cdf0e10cSrcweir     rTile.m_nObject         = createObject();
10503cdf0e10cSrcweir     rTile.m_aResources      = m_aOutputStreams.front().m_aResourceDict;
10504cdf0e10cSrcweir     rTile.m_aTransform.matrix[0] = rTransform.matrix[0] * fSX;
10505cdf0e10cSrcweir     rTile.m_aTransform.matrix[1] = rTransform.matrix[1] * fSY;
10506cdf0e10cSrcweir     rTile.m_aTransform.matrix[2] = aTranslation.Width();
10507cdf0e10cSrcweir     rTile.m_aTransform.matrix[3] = rTransform.matrix[3] * fSX;
10508cdf0e10cSrcweir     rTile.m_aTransform.matrix[4] = rTransform.matrix[4] * fSY;
10509cdf0e10cSrcweir     rTile.m_aTransform.matrix[5] = -aTranslation.Height();
10510cdf0e10cSrcweir     // caution: endRedirect pops the stream, so do this last
10511cdf0e10cSrcweir     rTile.m_pTilingStream   = dynamic_cast<SvMemoryStream*>(endRedirect());
10512cdf0e10cSrcweir     // FIXME: bound rect will not work with rotated matrix
10513cdf0e10cSrcweir     rTile.m_aRectangle      = Rectangle( Point(0,0), aConvertRect.GetSize() );
10514cdf0e10cSrcweir     rTile.m_aCellSize       = aConvertRect.GetSize();
10515cdf0e10cSrcweir 
10516cdf0e10cSrcweir     OStringBuffer aObjName( 16 );
10517cdf0e10cSrcweir     aObjName.append( 'P' );
10518cdf0e10cSrcweir     aObjName.append( rTile.m_nObject );
10519cdf0e10cSrcweir     pushResource( ResPattern, aObjName.makeStringAndClear(), rTile.m_nObject );
10520cdf0e10cSrcweir     return nTilingId;
10521cdf0e10cSrcweir }
10522cdf0e10cSrcweir 
drawPolyPolygon(const PolyPolygon & rPolyPoly,sal_Int32 nPattern,bool bEOFill)10523cdf0e10cSrcweir void PDFWriterImpl::drawPolyPolygon( const PolyPolygon& rPolyPoly, sal_Int32 nPattern, bool bEOFill )
10524cdf0e10cSrcweir {
10525cdf0e10cSrcweir     if( nPattern < 0 || nPattern >= (sal_Int32)m_aTilings.size() )
10526cdf0e10cSrcweir         return;
10527cdf0e10cSrcweir 
10528cdf0e10cSrcweir     m_aPages.back().endStream();
10529cdf0e10cSrcweir     sal_Int32 nXObject = createObject();
10530cdf0e10cSrcweir     OStringBuffer aNameBuf( 16 );
10531cdf0e10cSrcweir     aNameBuf.append( "Pol" );
10532cdf0e10cSrcweir     aNameBuf.append( nXObject );
10533cdf0e10cSrcweir     OString aObjName( aNameBuf.makeStringAndClear() );
10534cdf0e10cSrcweir     Rectangle aObjRect;
10535cdf0e10cSrcweir     if( updateObject( nXObject ) )
10536cdf0e10cSrcweir     {
10537cdf0e10cSrcweir         // get bounding rect of object
10538cdf0e10cSrcweir         PolyPolygon aSubDiv;
10539cdf0e10cSrcweir         rPolyPoly.AdaptiveSubdivide( aSubDiv );
10540cdf0e10cSrcweir         aObjRect = aSubDiv.GetBoundRect();
10541cdf0e10cSrcweir         Rectangle aConvObjRect( aObjRect );
10542cdf0e10cSrcweir         m_aPages.back().convertRect( aConvObjRect );
10543cdf0e10cSrcweir 
10544cdf0e10cSrcweir         // move polypolygon to bottom left of page
10545cdf0e10cSrcweir         PolyPolygon aLocalPath( rPolyPoly );
10546cdf0e10cSrcweir         sal_Int32 nPgWd = getReferenceDevice()->ImplGetDPIX() * m_aPages.back().getWidth() / 72;
10547cdf0e10cSrcweir         sal_Int32 nPgHt = getReferenceDevice()->ImplGetDPIY() * m_aPages.back().getHeight() / 72;
10548cdf0e10cSrcweir         Size aLogicPgSz = getReferenceDevice()->PixelToLogic( Size( nPgWd, nPgHt ), m_aGraphicsStack.front().m_aMapMode );
10549cdf0e10cSrcweir         sal_Int32 nXOff = aObjRect.Left();
10550cdf0e10cSrcweir         sal_Int32 nYOff = aLogicPgSz.Height() - aObjRect.Bottom();
10551cdf0e10cSrcweir         aLocalPath.Move( -nXOff, nYOff );
10552cdf0e10cSrcweir 
10553cdf0e10cSrcweir         // prepare XObject's content stream
10554cdf0e10cSrcweir         OStringBuffer aStream( 512 );
10555cdf0e10cSrcweir         aStream.append( "/Pattern cs /P" );
10556cdf0e10cSrcweir         aStream.append( m_aTilings[ nPattern ].m_nObject );
10557cdf0e10cSrcweir         aStream.append( " scn\n" );
10558cdf0e10cSrcweir         m_aPages.back().appendPolyPolygon( aLocalPath, aStream );
10559cdf0e10cSrcweir         aStream.append( bEOFill ? "f*" : "f" );
10560cdf0e10cSrcweir         SvMemoryStream aMemStream( aStream.getLength() );
10561cdf0e10cSrcweir         aMemStream.Write( aStream.getStr(), aStream.getLength() );
10562cdf0e10cSrcweir         bool bDeflate = compressStream( &aMemStream );
10563cdf0e10cSrcweir         aMemStream.Seek( STREAM_SEEK_TO_END );
10564cdf0e10cSrcweir         sal_Int32 nStreamLen = (sal_Int32)aMemStream.Tell();
10565cdf0e10cSrcweir         aMemStream.Seek( STREAM_SEEK_TO_BEGIN );
10566cdf0e10cSrcweir 
10567cdf0e10cSrcweir         // add new XObject to global resource dict
10568cdf0e10cSrcweir         m_aGlobalResourceDict.m_aXObjects[ aObjName ] = nXObject;
10569cdf0e10cSrcweir 
10570cdf0e10cSrcweir         // write XObject
10571cdf0e10cSrcweir         OStringBuffer aLine( 512 );
10572cdf0e10cSrcweir         aLine.append( nXObject );
10573cdf0e10cSrcweir         aLine.append( " 0 obj\n"
10574cdf0e10cSrcweir                       "<</Type/XObject/Subtype/Form/BBox[0 0 " );
10575cdf0e10cSrcweir         appendFixedInt( aConvObjRect.GetWidth(), aLine );
10576cdf0e10cSrcweir         aLine.append( ' ' );
10577cdf0e10cSrcweir         appendFixedInt( aConvObjRect.GetHeight(), aLine );
10578cdf0e10cSrcweir         aLine.append( "]/Length " );
10579cdf0e10cSrcweir         aLine.append( nStreamLen );
10580cdf0e10cSrcweir         if( bDeflate )
10581cdf0e10cSrcweir             aLine.append( "/Filter/FlateDecode" );
10582cdf0e10cSrcweir         aLine.append( ">>\n"
10583cdf0e10cSrcweir                       "stream\n" );
10584cdf0e10cSrcweir         writeBuffer( aLine.getStr(), aLine.getLength() );
10585cdf0e10cSrcweir         checkAndEnableStreamEncryption( nXObject );
10586cdf0e10cSrcweir         writeBuffer( aMemStream.GetData(), nStreamLen );
10587cdf0e10cSrcweir         disableStreamEncryption();
10588cdf0e10cSrcweir         writeBuffer( "\nendstream\nendobj\n\n", 19 );
10589cdf0e10cSrcweir     }
10590cdf0e10cSrcweir     m_aPages.back().beginStream();
10591cdf0e10cSrcweir     OStringBuffer aLine( 80 );
10592cdf0e10cSrcweir     aLine.append( "q 1 0 0 1 " );
10593cdf0e10cSrcweir     m_aPages.back().appendPoint( aObjRect.BottomLeft(), aLine );
10594cdf0e10cSrcweir     aLine.append( " cm/" );
10595cdf0e10cSrcweir     aLine.append( aObjName );
10596cdf0e10cSrcweir     aLine.append( " Do Q\n" );
10597cdf0e10cSrcweir     writeBuffer( aLine.getStr(), aLine.getLength() );
10598cdf0e10cSrcweir }
10599cdf0e10cSrcweir 
updateGraphicsState()10600cdf0e10cSrcweir void PDFWriterImpl::updateGraphicsState()
10601cdf0e10cSrcweir {
10602cdf0e10cSrcweir     OStringBuffer aLine( 256 );
10603cdf0e10cSrcweir     GraphicsState& rNewState = m_aGraphicsStack.front();
10604cdf0e10cSrcweir     // first set clip region since it might invalidate everything else
10605cdf0e10cSrcweir 
10606cdf0e10cSrcweir     if( (rNewState.m_nUpdateFlags & GraphicsState::updateClipRegion) )
10607cdf0e10cSrcweir     {
10608cdf0e10cSrcweir         rNewState.m_nUpdateFlags &= ~GraphicsState::updateClipRegion;
10609cdf0e10cSrcweir 
10610cdf0e10cSrcweir         if( m_aCurrentPDFState.m_bClipRegion != rNewState.m_bClipRegion ||
10611cdf0e10cSrcweir             ( rNewState.m_bClipRegion && m_aCurrentPDFState.m_aClipRegion != rNewState.m_aClipRegion ) )
10612cdf0e10cSrcweir         {
10613cdf0e10cSrcweir             if( m_aCurrentPDFState.m_bClipRegion && m_aCurrentPDFState.m_aClipRegion.count() )
10614cdf0e10cSrcweir             {
10615cdf0e10cSrcweir                 aLine.append( "Q " );
10616cdf0e10cSrcweir                 // invalidate everything but the clip region
10617cdf0e10cSrcweir                 m_aCurrentPDFState = GraphicsState();
10618cdf0e10cSrcweir                 rNewState.m_nUpdateFlags = sal::static_int_cast<sal_uInt16>(~GraphicsState::updateClipRegion);
10619cdf0e10cSrcweir             }
10620cdf0e10cSrcweir             if( rNewState.m_bClipRegion && rNewState.m_aClipRegion.count() )
10621cdf0e10cSrcweir             {
10622cdf0e10cSrcweir                 // clip region is always stored in private PDF mapmode
10623cdf0e10cSrcweir                 MapMode aNewMapMode = rNewState.m_aMapMode;
10624cdf0e10cSrcweir                 rNewState.m_aMapMode = m_aMapMode;
10625cdf0e10cSrcweir                 getReferenceDevice()->SetMapMode( rNewState.m_aMapMode );
10626cdf0e10cSrcweir                 m_aCurrentPDFState.m_aMapMode = rNewState.m_aMapMode;
10627cdf0e10cSrcweir 
10628cdf0e10cSrcweir                 aLine.append( "q " );
10629cdf0e10cSrcweir                 m_aPages.back().appendPolyPolygon( rNewState.m_aClipRegion, aLine );
10630cdf0e10cSrcweir                 aLine.append( "W* n\n" );
10631cdf0e10cSrcweir                 rNewState.m_aMapMode = aNewMapMode;
10632cdf0e10cSrcweir                 getReferenceDevice()->SetMapMode( rNewState.m_aMapMode );
10633cdf0e10cSrcweir                 m_aCurrentPDFState.m_aMapMode = rNewState.m_aMapMode;
10634cdf0e10cSrcweir             }
10635cdf0e10cSrcweir         }
10636cdf0e10cSrcweir     }
10637cdf0e10cSrcweir 
10638cdf0e10cSrcweir     if( (rNewState.m_nUpdateFlags & GraphicsState::updateMapMode) )
10639cdf0e10cSrcweir     {
10640cdf0e10cSrcweir         rNewState.m_nUpdateFlags &= ~GraphicsState::updateMapMode;
10641cdf0e10cSrcweir         getReferenceDevice()->SetMapMode( rNewState.m_aMapMode );
10642cdf0e10cSrcweir     }
10643cdf0e10cSrcweir 
10644cdf0e10cSrcweir     if( (rNewState.m_nUpdateFlags & GraphicsState::updateFont) )
10645cdf0e10cSrcweir     {
10646cdf0e10cSrcweir         rNewState.m_nUpdateFlags &= ~GraphicsState::updateFont;
10647cdf0e10cSrcweir         getReferenceDevice()->SetFont( rNewState.m_aFont );
10648cdf0e10cSrcweir         getReferenceDevice()->ImplNewFont();
10649cdf0e10cSrcweir     }
10650cdf0e10cSrcweir 
10651cdf0e10cSrcweir     if( (rNewState.m_nUpdateFlags & GraphicsState::updateLayoutMode) )
10652cdf0e10cSrcweir     {
10653cdf0e10cSrcweir         rNewState.m_nUpdateFlags &= ~GraphicsState::updateLayoutMode;
10654cdf0e10cSrcweir         getReferenceDevice()->SetLayoutMode( rNewState.m_nLayoutMode );
10655cdf0e10cSrcweir     }
10656cdf0e10cSrcweir 
10657cdf0e10cSrcweir     if( (rNewState.m_nUpdateFlags & GraphicsState::updateDigitLanguage) )
10658cdf0e10cSrcweir     {
10659cdf0e10cSrcweir         rNewState.m_nUpdateFlags &= ~GraphicsState::updateDigitLanguage;
10660cdf0e10cSrcweir         getReferenceDevice()->SetDigitLanguage( rNewState.m_aDigitLanguage );
10661cdf0e10cSrcweir     }
10662cdf0e10cSrcweir 
10663cdf0e10cSrcweir     if( (rNewState.m_nUpdateFlags & GraphicsState::updateLineColor) )
10664cdf0e10cSrcweir     {
10665cdf0e10cSrcweir         rNewState.m_nUpdateFlags &= ~GraphicsState::updateLineColor;
10666cdf0e10cSrcweir         if( m_aCurrentPDFState.m_aLineColor != rNewState.m_aLineColor &&
10667cdf0e10cSrcweir             rNewState.m_aLineColor != Color( COL_TRANSPARENT ) )
10668cdf0e10cSrcweir         {
10669cdf0e10cSrcweir             appendStrokingColor( rNewState.m_aLineColor, aLine );
10670cdf0e10cSrcweir             aLine.append( "\n" );
10671cdf0e10cSrcweir         }
10672cdf0e10cSrcweir     }
10673cdf0e10cSrcweir 
10674cdf0e10cSrcweir     if( (rNewState.m_nUpdateFlags & GraphicsState::updateFillColor) )
10675cdf0e10cSrcweir     {
10676cdf0e10cSrcweir         rNewState.m_nUpdateFlags &= ~GraphicsState::updateFillColor;
10677cdf0e10cSrcweir         if( m_aCurrentPDFState.m_aFillColor != rNewState.m_aFillColor &&
10678cdf0e10cSrcweir             rNewState.m_aFillColor != Color( COL_TRANSPARENT ) )
10679cdf0e10cSrcweir         {
10680cdf0e10cSrcweir             appendNonStrokingColor( rNewState.m_aFillColor, aLine );
10681cdf0e10cSrcweir             aLine.append( "\n" );
10682cdf0e10cSrcweir         }
10683cdf0e10cSrcweir     }
10684cdf0e10cSrcweir 
10685cdf0e10cSrcweir     if( (rNewState.m_nUpdateFlags & GraphicsState::updateTransparentPercent) )
10686cdf0e10cSrcweir     {
10687cdf0e10cSrcweir         rNewState.m_nUpdateFlags &= ~GraphicsState::updateTransparentPercent;
10688cdf0e10cSrcweir         if( m_aContext.Version >= PDFWriter::PDF_1_4 && m_aCurrentPDFState.m_nTransparentPercent != rNewState.m_nTransparentPercent )
10689cdf0e10cSrcweir         {
10690cdf0e10cSrcweir             // TODO: switch extended graphicsstate
10691cdf0e10cSrcweir         }
10692cdf0e10cSrcweir     }
10693cdf0e10cSrcweir 
10694cdf0e10cSrcweir     // everything is up to date now
10695cdf0e10cSrcweir     m_aCurrentPDFState = m_aGraphicsStack.front();
10696cdf0e10cSrcweir     if( aLine.getLength() )
10697cdf0e10cSrcweir         writeBuffer( aLine.getStr(), aLine.getLength() );
10698cdf0e10cSrcweir }
10699cdf0e10cSrcweir 
10700cdf0e10cSrcweir /* #i47544# imitate OutputDevice behaviour:
10701cdf0e10cSrcweir *  if a font with a nontransparent color is set, it overwrites the current
10702cdf0e10cSrcweir *  text color. OTOH setting the text color will overwrite the color of the font.
10703cdf0e10cSrcweir */
setFont(const Font & rFont)10704cdf0e10cSrcweir void PDFWriterImpl::setFont( const Font& rFont )
10705cdf0e10cSrcweir {
10706cdf0e10cSrcweir     Color aColor = rFont.GetColor();
10707cdf0e10cSrcweir     if( aColor == Color( COL_TRANSPARENT ) )
10708cdf0e10cSrcweir         aColor = m_aGraphicsStack.front().m_aFont.GetColor();
10709cdf0e10cSrcweir     m_aGraphicsStack.front().m_aFont = rFont;
10710cdf0e10cSrcweir     m_aGraphicsStack.front().m_aFont.SetColor( aColor );
10711cdf0e10cSrcweir     m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsState::updateFont;
10712cdf0e10cSrcweir }
10713cdf0e10cSrcweir 
push(sal_uInt16 nFlags)10714cdf0e10cSrcweir void PDFWriterImpl::push( sal_uInt16 nFlags )
10715cdf0e10cSrcweir {
10716cdf0e10cSrcweir     OSL_ENSURE( m_aGraphicsStack.size() > 0, "invalid graphics stack" );
10717cdf0e10cSrcweir     m_aGraphicsStack.push_front( m_aGraphicsStack.front() );
10718cdf0e10cSrcweir     m_aGraphicsStack.front().m_nFlags = nFlags;
10719cdf0e10cSrcweir }
10720cdf0e10cSrcweir 
pop()10721cdf0e10cSrcweir void PDFWriterImpl::pop()
10722cdf0e10cSrcweir {
10723cdf0e10cSrcweir     OSL_ENSURE( m_aGraphicsStack.size() > 1, "pop without push" );
10724cdf0e10cSrcweir     if( m_aGraphicsStack.size() < 2 )
10725cdf0e10cSrcweir         return;
10726cdf0e10cSrcweir 
10727cdf0e10cSrcweir     GraphicsState aState = m_aGraphicsStack.front();
10728cdf0e10cSrcweir     m_aGraphicsStack.pop_front();
10729cdf0e10cSrcweir     GraphicsState& rOld = m_aGraphicsStack.front();
10730cdf0e10cSrcweir 
10731cdf0e10cSrcweir     // move those parameters back that were not pushed
10732cdf0e10cSrcweir     // in the first place
10733cdf0e10cSrcweir     if( ! (aState.m_nFlags & PUSH_LINECOLOR) )
10734cdf0e10cSrcweir         setLineColor( aState.m_aLineColor );
10735cdf0e10cSrcweir     if( ! (aState.m_nFlags & PUSH_FILLCOLOR) )
10736cdf0e10cSrcweir         setFillColor( aState.m_aFillColor );
10737cdf0e10cSrcweir     if( ! (aState.m_nFlags & PUSH_FONT) )
10738cdf0e10cSrcweir         setFont( aState.m_aFont );
10739cdf0e10cSrcweir     if( ! (aState.m_nFlags & PUSH_TEXTCOLOR) )
10740cdf0e10cSrcweir         setTextColor( aState.m_aFont.GetColor() );
10741cdf0e10cSrcweir     if( ! (aState.m_nFlags & PUSH_MAPMODE) )
10742cdf0e10cSrcweir         setMapMode( aState.m_aMapMode );
10743cdf0e10cSrcweir     if( ! (aState.m_nFlags & PUSH_CLIPREGION) )
10744cdf0e10cSrcweir     {
10745cdf0e10cSrcweir         // do not use setClipRegion here
10746cdf0e10cSrcweir         // it would convert again assuming the current mapmode
10747cdf0e10cSrcweir         rOld.m_aClipRegion = aState.m_aClipRegion;
10748cdf0e10cSrcweir         rOld.m_bClipRegion = aState.m_bClipRegion;
10749cdf0e10cSrcweir     }
10750cdf0e10cSrcweir     if( ! (aState.m_nFlags & PUSH_TEXTLINECOLOR ) )
10751cdf0e10cSrcweir         setTextLineColor( aState.m_aTextLineColor );
10752cdf0e10cSrcweir     if( ! (aState.m_nFlags & PUSH_OVERLINECOLOR ) )
10753cdf0e10cSrcweir         setOverlineColor( aState.m_aOverlineColor );
10754cdf0e10cSrcweir     if( ! (aState.m_nFlags & PUSH_TEXTALIGN ) )
10755cdf0e10cSrcweir         setTextAlign( aState.m_aFont.GetAlign() );
10756cdf0e10cSrcweir     if( ! (aState.m_nFlags & PUSH_TEXTFILLCOLOR) )
10757cdf0e10cSrcweir         setTextFillColor( aState.m_aFont.GetFillColor() );
10758cdf0e10cSrcweir     if( ! (aState.m_nFlags & PUSH_REFPOINT) )
10759cdf0e10cSrcweir     {
10760cdf0e10cSrcweir         // what ?
10761cdf0e10cSrcweir     }
10762cdf0e10cSrcweir     // invalidate graphics state
10763cdf0e10cSrcweir     m_aGraphicsStack.front().m_nUpdateFlags = sal::static_int_cast<sal_uInt16>(~0U);
10764cdf0e10cSrcweir }
10765cdf0e10cSrcweir 
setMapMode(const MapMode & rMapMode)10766cdf0e10cSrcweir void PDFWriterImpl::setMapMode( const MapMode& rMapMode )
10767cdf0e10cSrcweir {
10768cdf0e10cSrcweir     m_aGraphicsStack.front().m_aMapMode = rMapMode;
10769cdf0e10cSrcweir     getReferenceDevice()->SetMapMode( rMapMode );
10770cdf0e10cSrcweir     m_aCurrentPDFState.m_aMapMode = rMapMode;
10771cdf0e10cSrcweir }
10772cdf0e10cSrcweir 
setClipRegion(const basegfx::B2DPolyPolygon & rRegion)10773cdf0e10cSrcweir void PDFWriterImpl::setClipRegion( const basegfx::B2DPolyPolygon& rRegion )
10774cdf0e10cSrcweir {
10775cdf0e10cSrcweir     basegfx::B2DPolyPolygon aRegion = getReferenceDevice()->LogicToPixel( rRegion, m_aGraphicsStack.front().m_aMapMode );
10776cdf0e10cSrcweir     aRegion = getReferenceDevice()->PixelToLogic( aRegion, m_aMapMode );
10777cdf0e10cSrcweir     m_aGraphicsStack.front().m_aClipRegion = aRegion;
10778cdf0e10cSrcweir     m_aGraphicsStack.front().m_bClipRegion = true;
10779cdf0e10cSrcweir     m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsState::updateClipRegion;
10780cdf0e10cSrcweir }
10781cdf0e10cSrcweir 
moveClipRegion(sal_Int32 nX,sal_Int32 nY)10782cdf0e10cSrcweir void PDFWriterImpl::moveClipRegion( sal_Int32 nX, sal_Int32 nY )
10783cdf0e10cSrcweir {
10784cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_bClipRegion && m_aGraphicsStack.front().m_aClipRegion.count() )
10785cdf0e10cSrcweir     {
10786cdf0e10cSrcweir         Point aPoint( lcl_convert( m_aGraphicsStack.front().m_aMapMode,
10787cdf0e10cSrcweir                                    m_aMapMode,
10788cdf0e10cSrcweir                                    getReferenceDevice(),
10789cdf0e10cSrcweir                                    Point( nX, nY ) ) );
10790cdf0e10cSrcweir         aPoint -= lcl_convert( m_aGraphicsStack.front().m_aMapMode,
10791cdf0e10cSrcweir                                m_aMapMode,
10792cdf0e10cSrcweir                                getReferenceDevice(),
10793cdf0e10cSrcweir                                Point() );
10794cdf0e10cSrcweir         basegfx::B2DHomMatrix aMat;
10795cdf0e10cSrcweir         aMat.translate( aPoint.X(), aPoint.Y() );
10796cdf0e10cSrcweir         m_aGraphicsStack.front().m_aClipRegion.transform( aMat );
10797cdf0e10cSrcweir         m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsState::updateClipRegion;
10798cdf0e10cSrcweir     }
10799cdf0e10cSrcweir }
10800cdf0e10cSrcweir 
intersectClipRegion(const Rectangle & rRect)10801cdf0e10cSrcweir bool PDFWriterImpl::intersectClipRegion( const Rectangle& rRect )
10802cdf0e10cSrcweir {
10803cdf0e10cSrcweir     basegfx::B2DPolyPolygon aRect( basegfx::tools::createPolygonFromRect(
10804cdf0e10cSrcweir         basegfx::B2DRectangle( rRect.Left(), rRect.Top(), rRect.Right(), rRect.Bottom() ) ) );
10805cdf0e10cSrcweir     return intersectClipRegion( aRect );
10806cdf0e10cSrcweir }
10807cdf0e10cSrcweir 
10808cdf0e10cSrcweir 
intersectClipRegion(const basegfx::B2DPolyPolygon & rRegion)10809cdf0e10cSrcweir bool PDFWriterImpl::intersectClipRegion( const basegfx::B2DPolyPolygon& rRegion )
10810cdf0e10cSrcweir {
10811cdf0e10cSrcweir     basegfx::B2DPolyPolygon aRegion( getReferenceDevice()->LogicToPixel( rRegion, m_aGraphicsStack.front().m_aMapMode ) );
10812cdf0e10cSrcweir     aRegion = getReferenceDevice()->PixelToLogic( aRegion, m_aMapMode );
10813cdf0e10cSrcweir     m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsState::updateClipRegion;
10814cdf0e10cSrcweir     if( m_aGraphicsStack.front().m_bClipRegion )
10815cdf0e10cSrcweir     {
10816cdf0e10cSrcweir         basegfx::B2DPolyPolygon aOld( basegfx::tools::prepareForPolygonOperation( m_aGraphicsStack.front().m_aClipRegion ) );
10817cdf0e10cSrcweir         aRegion = basegfx::tools::prepareForPolygonOperation( aRegion );
10818cdf0e10cSrcweir         m_aGraphicsStack.front().m_aClipRegion = basegfx::tools::solvePolygonOperationAnd( aOld, aRegion );
10819cdf0e10cSrcweir     }
10820cdf0e10cSrcweir     else
10821cdf0e10cSrcweir     {
10822cdf0e10cSrcweir         m_aGraphicsStack.front().m_aClipRegion = aRegion;
10823cdf0e10cSrcweir         m_aGraphicsStack.front().m_bClipRegion = true;
10824cdf0e10cSrcweir     }
10825cdf0e10cSrcweir     return true;
10826cdf0e10cSrcweir }
10827cdf0e10cSrcweir 
createNote(const Rectangle & rRect,const PDFNote & rNote,sal_Int32 nPageNr)10828cdf0e10cSrcweir void PDFWriterImpl::createNote( const Rectangle& rRect, const PDFNote& rNote, sal_Int32 nPageNr )
10829cdf0e10cSrcweir {
10830cdf0e10cSrcweir     if( nPageNr < 0 )
10831cdf0e10cSrcweir         nPageNr = m_nCurrentPage;
10832cdf0e10cSrcweir 
10833cdf0e10cSrcweir     if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() )
10834cdf0e10cSrcweir         return;
10835cdf0e10cSrcweir 
10836cdf0e10cSrcweir     m_aNotes.push_back( PDFNoteEntry() );
10837cdf0e10cSrcweir     m_aNotes.back().m_nObject       = createObject();
10838cdf0e10cSrcweir     m_aNotes.back().m_aContents     = rNote;
10839cdf0e10cSrcweir     m_aNotes.back().m_aRect         = rRect;
10840cdf0e10cSrcweir     // convert to default user space now, since the mapmode may change
10841cdf0e10cSrcweir     m_aPages[nPageNr].convertRect( m_aNotes.back().m_aRect );
10842cdf0e10cSrcweir 
10843cdf0e10cSrcweir     // insert note to page's annotation list
10844cdf0e10cSrcweir     m_aPages[ nPageNr ].m_aAnnotations.push_back( m_aNotes.back().m_nObject );
10845cdf0e10cSrcweir }
10846cdf0e10cSrcweir 
createLink(const Rectangle & rRect,sal_Int32 nPageNr)10847cdf0e10cSrcweir sal_Int32 PDFWriterImpl::createLink( const Rectangle& rRect, sal_Int32 nPageNr )
10848cdf0e10cSrcweir {
10849cdf0e10cSrcweir     if( nPageNr < 0 )
10850cdf0e10cSrcweir         nPageNr = m_nCurrentPage;
10851cdf0e10cSrcweir 
10852cdf0e10cSrcweir     if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() )
10853cdf0e10cSrcweir         return -1;
10854cdf0e10cSrcweir 
10855cdf0e10cSrcweir     sal_Int32 nRet = m_aLinks.size();
10856cdf0e10cSrcweir 
10857cdf0e10cSrcweir     m_aLinks.push_back( PDFLink() );
10858cdf0e10cSrcweir     m_aLinks.back().m_nObject   = createObject();
10859cdf0e10cSrcweir     m_aLinks.back().m_nPage     = nPageNr;
10860cdf0e10cSrcweir     m_aLinks.back().m_aRect     = rRect;
10861cdf0e10cSrcweir     // convert to default user space now, since the mapmode may change
10862cdf0e10cSrcweir     m_aPages[nPageNr].convertRect( m_aLinks.back().m_aRect );
10863cdf0e10cSrcweir 
10864cdf0e10cSrcweir     // insert link to page's annotation list
10865cdf0e10cSrcweir     m_aPages[ nPageNr ].m_aAnnotations.push_back( m_aLinks.back().m_nObject );
10866cdf0e10cSrcweir 
10867cdf0e10cSrcweir     return nRet;
10868cdf0e10cSrcweir }
10869cdf0e10cSrcweir 
10870cdf0e10cSrcweir //--->i56629
createNamedDest(const rtl::OUString & sDestName,const Rectangle & rRect,sal_Int32 nPageNr,PDFWriter::DestAreaType eType)10871cdf0e10cSrcweir sal_Int32 PDFWriterImpl::createNamedDest( const rtl::OUString& sDestName, const Rectangle& rRect, sal_Int32 nPageNr, PDFWriter::DestAreaType eType )
10872cdf0e10cSrcweir {
10873cdf0e10cSrcweir     if( nPageNr < 0 )
10874cdf0e10cSrcweir         nPageNr = m_nCurrentPage;
10875cdf0e10cSrcweir 
10876cdf0e10cSrcweir     if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() )
10877cdf0e10cSrcweir         return -1;
10878cdf0e10cSrcweir 
10879cdf0e10cSrcweir     sal_Int32 nRet = m_aNamedDests.size();
10880cdf0e10cSrcweir 
10881cdf0e10cSrcweir     m_aNamedDests.push_back( PDFNamedDest() );
10882cdf0e10cSrcweir     m_aNamedDests.back().m_aDestName = sDestName;
10883cdf0e10cSrcweir     m_aNamedDests.back().m_nPage = nPageNr;
10884cdf0e10cSrcweir     m_aNamedDests.back().m_eType = eType;
10885cdf0e10cSrcweir     m_aNamedDests.back().m_aRect = rRect;
10886cdf0e10cSrcweir     // convert to default user space now, since the mapmode may change
10887cdf0e10cSrcweir     m_aPages[nPageNr].convertRect( m_aNamedDests.back().m_aRect );
10888cdf0e10cSrcweir 
10889cdf0e10cSrcweir     return nRet;
10890cdf0e10cSrcweir }
10891cdf0e10cSrcweir //<---i56629
10892cdf0e10cSrcweir 
createDest(const Rectangle & rRect,sal_Int32 nPageNr,PDFWriter::DestAreaType eType)10893cdf0e10cSrcweir sal_Int32 PDFWriterImpl::createDest( const Rectangle& rRect, sal_Int32 nPageNr, PDFWriter::DestAreaType eType )
10894cdf0e10cSrcweir {
10895cdf0e10cSrcweir     if( nPageNr < 0 )
10896cdf0e10cSrcweir         nPageNr = m_nCurrentPage;
10897cdf0e10cSrcweir 
10898cdf0e10cSrcweir     if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() )
10899cdf0e10cSrcweir         return -1;
10900cdf0e10cSrcweir 
10901cdf0e10cSrcweir     sal_Int32 nRet = m_aDests.size();
10902cdf0e10cSrcweir 
10903cdf0e10cSrcweir     m_aDests.push_back( PDFDest() );
10904cdf0e10cSrcweir     m_aDests.back().m_nPage = nPageNr;
10905cdf0e10cSrcweir     m_aDests.back().m_eType = eType;
10906cdf0e10cSrcweir     m_aDests.back().m_aRect = rRect;
10907cdf0e10cSrcweir     // convert to default user space now, since the mapmode may change
10908cdf0e10cSrcweir     m_aPages[nPageNr].convertRect( m_aDests.back().m_aRect );
10909cdf0e10cSrcweir 
10910cdf0e10cSrcweir     return nRet;
10911cdf0e10cSrcweir }
10912cdf0e10cSrcweir 
registerDestReference(sal_Int32 nDestId,const Rectangle & rRect,sal_Int32 nPageNr,PDFWriter::DestAreaType eType)10913cdf0e10cSrcweir sal_Int32 PDFWriterImpl::registerDestReference( sal_Int32 nDestId, const Rectangle& rRect, sal_Int32 nPageNr, PDFWriter::DestAreaType eType )
10914cdf0e10cSrcweir {
10915cdf0e10cSrcweir     return m_aDestinationIdTranslation[ nDestId ] = createDest( rRect, nPageNr, eType );
10916cdf0e10cSrcweir }
10917cdf0e10cSrcweir 
setLinkDest(sal_Int32 nLinkId,sal_Int32 nDestId)10918cdf0e10cSrcweir sal_Int32 PDFWriterImpl::setLinkDest( sal_Int32 nLinkId, sal_Int32 nDestId )
10919cdf0e10cSrcweir {
10920cdf0e10cSrcweir     if( nLinkId < 0 || nLinkId >= (sal_Int32)m_aLinks.size() )
10921cdf0e10cSrcweir         return -1;
10922cdf0e10cSrcweir     if( nDestId < 0 || nDestId >= (sal_Int32)m_aDests.size() )
10923cdf0e10cSrcweir         return -2;
10924cdf0e10cSrcweir 
10925cdf0e10cSrcweir     m_aLinks[ nLinkId ].m_nDest = nDestId;
10926cdf0e10cSrcweir 
10927cdf0e10cSrcweir     return 0;
10928cdf0e10cSrcweir }
10929cdf0e10cSrcweir 
setLinkURL(sal_Int32 nLinkId,const OUString & rURL)10930cdf0e10cSrcweir sal_Int32 PDFWriterImpl::setLinkURL( sal_Int32 nLinkId, const OUString& rURL )
10931cdf0e10cSrcweir {
10932cdf0e10cSrcweir     if( nLinkId < 0 || nLinkId >= (sal_Int32)m_aLinks.size() )
10933cdf0e10cSrcweir         return -1;
10934cdf0e10cSrcweir 
10935cdf0e10cSrcweir     m_aLinks[ nLinkId ].m_nDest = -1;
10936cdf0e10cSrcweir 
10937cdf0e10cSrcweir     using namespace ::com::sun::star;
10938cdf0e10cSrcweir 
10939cdf0e10cSrcweir     if (!m_xTrans.is())
10940cdf0e10cSrcweir     {
10941cdf0e10cSrcweir         uno::Reference< lang::XMultiServiceFactory > xFact( comphelper::getProcessServiceFactory() );
10942cdf0e10cSrcweir         if( xFact.is() )
10943cdf0e10cSrcweir         {
10944cdf0e10cSrcweir             m_xTrans = uno::Reference < util::XURLTransformer >(
10945cdf0e10cSrcweir                 xFact->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.util.URLTransformer" ) ) ), uno::UNO_QUERY );
10946cdf0e10cSrcweir         }
10947cdf0e10cSrcweir     }
10948cdf0e10cSrcweir 
10949cdf0e10cSrcweir     util::URL aURL;
10950cdf0e10cSrcweir     aURL.Complete = rURL;
10951cdf0e10cSrcweir 
10952cdf0e10cSrcweir     if (m_xTrans.is())
10953cdf0e10cSrcweir         m_xTrans->parseStrict( aURL );
10954cdf0e10cSrcweir 
10955cdf0e10cSrcweir     m_aLinks[ nLinkId ].m_aURL  = aURL.Complete;
10956cdf0e10cSrcweir 
10957cdf0e10cSrcweir     return 0;
10958cdf0e10cSrcweir }
10959cdf0e10cSrcweir 
setLinkPropertyId(sal_Int32 nLinkId,sal_Int32 nPropertyId)10960cdf0e10cSrcweir void PDFWriterImpl::setLinkPropertyId( sal_Int32 nLinkId, sal_Int32 nPropertyId )
10961cdf0e10cSrcweir {
10962cdf0e10cSrcweir     m_aLinkPropertyMap[ nPropertyId ] = nLinkId;
10963cdf0e10cSrcweir }
10964cdf0e10cSrcweir 
createOutlineItem(sal_Int32 nParent,const OUString & rText,sal_Int32 nDestID)10965cdf0e10cSrcweir sal_Int32 PDFWriterImpl::createOutlineItem( sal_Int32 nParent, const OUString& rText, sal_Int32 nDestID )
10966cdf0e10cSrcweir {
10967cdf0e10cSrcweir     // create new item
10968cdf0e10cSrcweir     sal_Int32 nNewItem = m_aOutline.size();
10969cdf0e10cSrcweir     m_aOutline.push_back( PDFOutlineEntry() );
10970cdf0e10cSrcweir 
10971cdf0e10cSrcweir     // set item attributes
10972cdf0e10cSrcweir     setOutlineItemParent( nNewItem, nParent );
10973cdf0e10cSrcweir     setOutlineItemText( nNewItem, rText );
10974cdf0e10cSrcweir     setOutlineItemDest( nNewItem, nDestID );
10975cdf0e10cSrcweir 
10976cdf0e10cSrcweir     return nNewItem;
10977cdf0e10cSrcweir }
10978cdf0e10cSrcweir 
setOutlineItemParent(sal_Int32 nItem,sal_Int32 nNewParent)10979cdf0e10cSrcweir sal_Int32 PDFWriterImpl::setOutlineItemParent( sal_Int32 nItem, sal_Int32 nNewParent )
10980cdf0e10cSrcweir {
10981cdf0e10cSrcweir     if( nItem < 1 || nItem >= (sal_Int32)m_aOutline.size() )
10982cdf0e10cSrcweir         return -1;
10983cdf0e10cSrcweir 
10984cdf0e10cSrcweir     int nRet = 0;
10985cdf0e10cSrcweir 
10986cdf0e10cSrcweir     if( nNewParent < 0 || nNewParent >= (sal_Int32)m_aOutline.size() || nNewParent == nItem )
10987cdf0e10cSrcweir     {
10988cdf0e10cSrcweir         nNewParent = 0;
10989cdf0e10cSrcweir         nRet = -2;
10990cdf0e10cSrcweir     }
10991cdf0e10cSrcweir     // remove item from previous parent
10992cdf0e10cSrcweir     sal_Int32 nParentID = m_aOutline[ nItem ].m_nParentID;
10993cdf0e10cSrcweir     if( nParentID >= 0 && nParentID < (sal_Int32)m_aOutline.size() )
10994cdf0e10cSrcweir     {
10995cdf0e10cSrcweir         PDFOutlineEntry& rParent = m_aOutline[ nParentID ];
10996cdf0e10cSrcweir 
10997cdf0e10cSrcweir         for( std::vector<sal_Int32>::iterator it = rParent.m_aChildren.begin();
10998cdf0e10cSrcweir              it != rParent.m_aChildren.end(); ++it )
10999cdf0e10cSrcweir         {
11000cdf0e10cSrcweir             if( *it == nItem )
11001cdf0e10cSrcweir             {
11002cdf0e10cSrcweir                 rParent.m_aChildren.erase( it );
11003cdf0e10cSrcweir                 break;
11004cdf0e10cSrcweir             }
11005cdf0e10cSrcweir         }
11006cdf0e10cSrcweir     }
11007cdf0e10cSrcweir 
11008cdf0e10cSrcweir     // insert item to new parent's list of children
11009cdf0e10cSrcweir     m_aOutline[ nNewParent ].m_aChildren.push_back( nItem );
11010cdf0e10cSrcweir 
11011cdf0e10cSrcweir     return nRet;
11012cdf0e10cSrcweir }
11013cdf0e10cSrcweir 
setOutlineItemText(sal_Int32 nItem,const OUString & rText)11014cdf0e10cSrcweir sal_Int32 PDFWriterImpl::setOutlineItemText( sal_Int32 nItem, const OUString& rText )
11015cdf0e10cSrcweir {
11016cdf0e10cSrcweir     if( nItem < 1 || nItem >= (sal_Int32)m_aOutline.size() )
11017cdf0e10cSrcweir         return -1;
11018cdf0e10cSrcweir 
11019cdf0e10cSrcweir     m_aOutline[ nItem ].m_aTitle = psp::WhitespaceToSpace( rText );
11020cdf0e10cSrcweir     return 0;
11021cdf0e10cSrcweir }
11022cdf0e10cSrcweir 
setOutlineItemDest(sal_Int32 nItem,sal_Int32 nDestID)11023cdf0e10cSrcweir sal_Int32 PDFWriterImpl::setOutlineItemDest( sal_Int32 nItem, sal_Int32 nDestID )
11024cdf0e10cSrcweir {
11025cdf0e10cSrcweir     if( nItem < 1 || nItem >= (sal_Int32)m_aOutline.size() ) // item does not exist
11026cdf0e10cSrcweir         return -1;
11027cdf0e10cSrcweir     if( nDestID < 0 || nDestID >= (sal_Int32)m_aDests.size() ) // dest does not exist
11028cdf0e10cSrcweir         return -2;
11029cdf0e10cSrcweir     m_aOutline[nItem].m_nDestID = nDestID;
11030cdf0e10cSrcweir     return 0;
11031cdf0e10cSrcweir }
11032cdf0e10cSrcweir 
getStructureTag(PDFWriter::StructElement eType)11033cdf0e10cSrcweir const sal_Char* PDFWriterImpl::getStructureTag( PDFWriter::StructElement eType )
11034cdf0e10cSrcweir {
11035cdf0e10cSrcweir     static std::map< PDFWriter::StructElement, const char* > aTagStrings;
11036cdf0e10cSrcweir     if( aTagStrings.empty() )
11037cdf0e10cSrcweir     {
11038cdf0e10cSrcweir         aTagStrings[ PDFWriter::NonStructElement] = "NonStruct";
11039cdf0e10cSrcweir         aTagStrings[ PDFWriter::Document ]      = "Document";
11040cdf0e10cSrcweir         aTagStrings[ PDFWriter::Part ]          = "Part";
11041cdf0e10cSrcweir         aTagStrings[ PDFWriter::Article ]       = "Art";
11042cdf0e10cSrcweir         aTagStrings[ PDFWriter::Section ]       = "Sect";
11043cdf0e10cSrcweir         aTagStrings[ PDFWriter::Division ]      = "Div";
11044cdf0e10cSrcweir         aTagStrings[ PDFWriter::BlockQuote ]    = "BlockQuote";
11045cdf0e10cSrcweir         aTagStrings[ PDFWriter::Caption ]       = "Caption";
11046cdf0e10cSrcweir         aTagStrings[ PDFWriter::TOC ]           = "TOC";
11047cdf0e10cSrcweir         aTagStrings[ PDFWriter::TOCI ]          = "TOCI";
11048cdf0e10cSrcweir         aTagStrings[ PDFWriter::Index ]         = "Index";
11049cdf0e10cSrcweir         aTagStrings[ PDFWriter::Paragraph ]     = "P";
11050cdf0e10cSrcweir         aTagStrings[ PDFWriter::Heading ]       = "H";
11051cdf0e10cSrcweir         aTagStrings[ PDFWriter::H1 ]            = "H1";
11052cdf0e10cSrcweir         aTagStrings[ PDFWriter::H2 ]            = "H2";
11053cdf0e10cSrcweir         aTagStrings[ PDFWriter::H3 ]            = "H3";
11054cdf0e10cSrcweir         aTagStrings[ PDFWriter::H4 ]            = "H4";
11055cdf0e10cSrcweir         aTagStrings[ PDFWriter::H5 ]            = "H5";
11056cdf0e10cSrcweir         aTagStrings[ PDFWriter::H6 ]            = "H6";
11057cdf0e10cSrcweir         aTagStrings[ PDFWriter::List ]          = "L";
11058cdf0e10cSrcweir         aTagStrings[ PDFWriter::ListItem ]      = "LI";
11059cdf0e10cSrcweir         aTagStrings[ PDFWriter::LILabel ]       = "Lbl";
11060cdf0e10cSrcweir         aTagStrings[ PDFWriter::LIBody ]        = "LBody";
11061cdf0e10cSrcweir         aTagStrings[ PDFWriter::Table ]         = "Table";
11062cdf0e10cSrcweir         aTagStrings[ PDFWriter::TableRow ]      = "TR";
11063cdf0e10cSrcweir         aTagStrings[ PDFWriter::TableHeader ]   = "TH";
11064cdf0e10cSrcweir         aTagStrings[ PDFWriter::TableData ]     = "TD";
11065cdf0e10cSrcweir         aTagStrings[ PDFWriter::Span ]          = "Span";
11066cdf0e10cSrcweir         aTagStrings[ PDFWriter::Quote ]         = "Quote";
11067cdf0e10cSrcweir         aTagStrings[ PDFWriter::Note ]          = "Note";
11068cdf0e10cSrcweir         aTagStrings[ PDFWriter::Reference ]     = "Reference";
11069cdf0e10cSrcweir         aTagStrings[ PDFWriter::BibEntry ]      = "BibEntry";
11070cdf0e10cSrcweir         aTagStrings[ PDFWriter::Code ]          = "Code";
11071cdf0e10cSrcweir         aTagStrings[ PDFWriter::Link ]          = "Link";
11072cdf0e10cSrcweir         aTagStrings[ PDFWriter::Figure ]        = "Figure";
11073cdf0e10cSrcweir         aTagStrings[ PDFWriter::Formula ]       = "Formula";
11074cdf0e10cSrcweir         aTagStrings[ PDFWriter::Form ]          = "Form";
11075cdf0e10cSrcweir     }
11076cdf0e10cSrcweir 
11077cdf0e10cSrcweir     std::map< PDFWriter::StructElement, const char* >::const_iterator it = aTagStrings.find( eType );
11078cdf0e10cSrcweir 
11079cdf0e10cSrcweir     return it != aTagStrings.end() ? it->second : "Div";
11080cdf0e10cSrcweir }
11081cdf0e10cSrcweir 
beginStructureElementMCSeq()11082cdf0e10cSrcweir void PDFWriterImpl::beginStructureElementMCSeq()
11083cdf0e10cSrcweir {
11084cdf0e10cSrcweir     if( m_bEmitStructure &&
11085cdf0e10cSrcweir         m_nCurrentStructElement > 0 && // StructTreeRoot
11086cdf0e10cSrcweir         ! m_aStructure[ m_nCurrentStructElement ].m_bOpenMCSeq // already opened sequence
11087cdf0e10cSrcweir         )
11088cdf0e10cSrcweir     {
11089cdf0e10cSrcweir         PDFStructureElement& rEle = m_aStructure[ m_nCurrentStructElement ];
11090cdf0e10cSrcweir         OStringBuffer aLine( 128 );
11091cdf0e10cSrcweir         sal_Int32 nMCID = m_aPages[ m_nCurrentPage ].m_aMCIDParents.size();
11092cdf0e10cSrcweir         aLine.append( "/" );
11093cdf0e10cSrcweir         if( rEle.m_aAlias.getLength() > 0 )
11094cdf0e10cSrcweir             aLine.append( rEle.m_aAlias );
11095cdf0e10cSrcweir         else
11096cdf0e10cSrcweir             aLine.append( getStructureTag( rEle.m_eType ) );
11097cdf0e10cSrcweir         aLine.append( "<</MCID " );
11098cdf0e10cSrcweir         aLine.append( nMCID );
11099cdf0e10cSrcweir         aLine.append( ">>BDC\n" );
11100cdf0e10cSrcweir         writeBuffer( aLine.getStr(), aLine.getLength() );
11101cdf0e10cSrcweir 
11102cdf0e10cSrcweir         // update the element's content list
11103cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
11104cdf0e10cSrcweir         fprintf( stderr, "beginning marked content id %" SAL_PRIdINT32 " on page object %" SAL_PRIdINT32 ", structure first page = %" SAL_PRIdINT32 "\n",
11105cdf0e10cSrcweir                  nMCID,
11106cdf0e10cSrcweir                  m_aPages[ m_nCurrentPage ].m_nPageObject,
11107cdf0e10cSrcweir                  rEle.m_nFirstPageObject );
11108cdf0e10cSrcweir #endif
11109cdf0e10cSrcweir         rEle.m_aKids.push_back( PDFStructureElementKid( nMCID, m_aPages[m_nCurrentPage].m_nPageObject ) );
11110cdf0e10cSrcweir         // update the page's mcid parent list
11111cdf0e10cSrcweir         m_aPages[ m_nCurrentPage ].m_aMCIDParents.push_back( rEle.m_nObject );
11112cdf0e10cSrcweir         // mark element MC sequence as open
11113cdf0e10cSrcweir         rEle.m_bOpenMCSeq = true;
11114cdf0e10cSrcweir     }
11115cdf0e10cSrcweir     // handle artifacts
11116cdf0e10cSrcweir     else if( ! m_bEmitStructure && m_aContext.Tagged &&
11117cdf0e10cSrcweir                m_nCurrentStructElement > 0 &&
11118cdf0e10cSrcweir                m_aStructure[ m_nCurrentStructElement ].m_eType == PDFWriter::NonStructElement &&
11119cdf0e10cSrcweir              ! m_aStructure[ m_nCurrentStructElement ].m_bOpenMCSeq // already opened sequence
11120cdf0e10cSrcweir              )
11121cdf0e10cSrcweir     {
11122cdf0e10cSrcweir         OStringBuffer aLine( 128 );
11123cdf0e10cSrcweir         aLine.append( "/Artifact BMC\n" );
11124cdf0e10cSrcweir         writeBuffer( aLine.getStr(), aLine.getLength() );
11125cdf0e10cSrcweir         // mark element MC sequence as open
11126cdf0e10cSrcweir         m_aStructure[ m_nCurrentStructElement ].m_bOpenMCSeq = true;
11127cdf0e10cSrcweir     }
11128cdf0e10cSrcweir }
11129cdf0e10cSrcweir 
endStructureElementMCSeq()11130cdf0e10cSrcweir void PDFWriterImpl::endStructureElementMCSeq()
11131cdf0e10cSrcweir {
11132cdf0e10cSrcweir     if( m_nCurrentStructElement > 0 && // StructTreeRoot
11133cdf0e10cSrcweir         ( m_bEmitStructure || m_aStructure[ m_nCurrentStructElement ].m_eType == PDFWriter::NonStructElement ) &&
11134cdf0e10cSrcweir         m_aStructure[ m_nCurrentStructElement ].m_bOpenMCSeq // must have an opened MC sequence
11135cdf0e10cSrcweir         )
11136cdf0e10cSrcweir     {
11137cdf0e10cSrcweir         writeBuffer( "EMC\n", 4 );
11138cdf0e10cSrcweir         m_aStructure[ m_nCurrentStructElement ].m_bOpenMCSeq = false;
11139cdf0e10cSrcweir     }
11140cdf0e10cSrcweir }
11141cdf0e10cSrcweir 
checkEmitStructure()11142cdf0e10cSrcweir bool PDFWriterImpl::checkEmitStructure()
11143cdf0e10cSrcweir {
11144cdf0e10cSrcweir     bool bEmit = false;
11145cdf0e10cSrcweir     if( m_aContext.Tagged )
11146cdf0e10cSrcweir     {
11147cdf0e10cSrcweir         bEmit = true;
11148cdf0e10cSrcweir         sal_Int32 nEle = m_nCurrentStructElement;
11149cdf0e10cSrcweir         while( nEle > 0 && nEle < sal_Int32(m_aStructure.size()) )
11150cdf0e10cSrcweir         {
11151cdf0e10cSrcweir             if( m_aStructure[ nEle ].m_eType == PDFWriter::NonStructElement )
11152cdf0e10cSrcweir             {
11153cdf0e10cSrcweir                 bEmit = false;
11154cdf0e10cSrcweir                 break;
11155cdf0e10cSrcweir             }
11156cdf0e10cSrcweir             nEle = m_aStructure[ nEle ].m_nParentElement;
11157cdf0e10cSrcweir         }
11158cdf0e10cSrcweir     }
11159cdf0e10cSrcweir     return bEmit;
11160cdf0e10cSrcweir }
11161cdf0e10cSrcweir 
beginStructureElement(PDFWriter::StructElement eType,const rtl::OUString & rAlias)11162cdf0e10cSrcweir sal_Int32 PDFWriterImpl::beginStructureElement( PDFWriter::StructElement eType, const rtl::OUString& rAlias )
11163cdf0e10cSrcweir {
11164cdf0e10cSrcweir     if( m_nCurrentPage < 0 )
11165cdf0e10cSrcweir         return -1;
11166cdf0e10cSrcweir 
11167cdf0e10cSrcweir     if( ! m_aContext.Tagged )
11168cdf0e10cSrcweir         return -1;
11169cdf0e10cSrcweir 
11170cdf0e10cSrcweir     // close eventual current MC sequence
11171cdf0e10cSrcweir     endStructureElementMCSeq();
11172cdf0e10cSrcweir 
11173cdf0e10cSrcweir     if( m_nCurrentStructElement == 0 &&
11174cdf0e10cSrcweir         eType != PDFWriter::Document && eType != PDFWriter::NonStructElement )
11175cdf0e10cSrcweir     {
11176cdf0e10cSrcweir         // struct tree root hit, but not beginning document
11177cdf0e10cSrcweir         // this might happen with setCurrentStructureElement
11178cdf0e10cSrcweir         // silently insert structure into document again if one properly exists
11179cdf0e10cSrcweir         if( ! m_aStructure[ 0 ].m_aChildren.empty() )
11180cdf0e10cSrcweir         {
11181cdf0e10cSrcweir             PDFWriter::StructElement childType = PDFWriter::NonStructElement;
11182cdf0e10cSrcweir             sal_Int32 nNewCurElement = 0;
11183cdf0e10cSrcweir             const std::list< sal_Int32 >& rRootChildren = m_aStructure[0].m_aChildren;
11184cdf0e10cSrcweir             for( std::list< sal_Int32 >::const_iterator it = rRootChildren.begin();
11185cdf0e10cSrcweir                  childType != PDFWriter::Document && it != rRootChildren.end(); ++it )
11186cdf0e10cSrcweir             {
11187cdf0e10cSrcweir                 nNewCurElement = *it;
11188cdf0e10cSrcweir                 childType = m_aStructure[ nNewCurElement ].m_eType;
11189cdf0e10cSrcweir             }
11190cdf0e10cSrcweir             if( childType == PDFWriter::Document )
11191cdf0e10cSrcweir             {
11192cdf0e10cSrcweir                 m_nCurrentStructElement = nNewCurElement;
11193cdf0e10cSrcweir                 DBG_ASSERT( 0, "Structure element inserted to StructTreeRoot that is not a document" );
11194cdf0e10cSrcweir             }
11195cdf0e10cSrcweir             else {
11196cdf0e10cSrcweir                 DBG_ERROR( "document structure in disorder !" );
11197cdf0e10cSrcweir             }
11198cdf0e10cSrcweir         }
11199cdf0e10cSrcweir         else {
11200cdf0e10cSrcweir             DBG_ERROR( "PDF document structure MUST be contained in a Document element" );
11201cdf0e10cSrcweir         }
11202cdf0e10cSrcweir     }
11203cdf0e10cSrcweir 
11204cdf0e10cSrcweir     sal_Int32 nNewId = sal_Int32(m_aStructure.size());
11205cdf0e10cSrcweir     m_aStructure.push_back( PDFStructureElement() );
11206cdf0e10cSrcweir     PDFStructureElement& rEle = m_aStructure.back();
11207cdf0e10cSrcweir     rEle.m_eType            = eType;
11208cdf0e10cSrcweir     rEle.m_nOwnElement      = nNewId;
11209cdf0e10cSrcweir     rEle.m_nParentElement   = m_nCurrentStructElement;
11210cdf0e10cSrcweir     rEle.m_nFirstPageObject = m_aPages[ m_nCurrentPage ].m_nPageObject;
11211cdf0e10cSrcweir     m_aStructure[ m_nCurrentStructElement ].m_aChildren.push_back( nNewId );
11212cdf0e10cSrcweir     m_nCurrentStructElement = nNewId;
11213cdf0e10cSrcweir 
11214cdf0e10cSrcweir     // handle alias names
11215cdf0e10cSrcweir     if( rAlias.getLength() && eType != PDFWriter::NonStructElement )
11216cdf0e10cSrcweir     {
11217cdf0e10cSrcweir         OStringBuffer aNameBuf( rAlias.getLength() );
11218cdf0e10cSrcweir         appendName( rAlias, aNameBuf );
11219cdf0e10cSrcweir         OString aAliasName( aNameBuf.makeStringAndClear() );
11220cdf0e10cSrcweir         rEle.m_aAlias = aAliasName;
11221cdf0e10cSrcweir         m_aRoleMap[ aAliasName ] = getStructureTag( eType );
11222cdf0e10cSrcweir     }
11223cdf0e10cSrcweir 
11224cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
11225cdf0e10cSrcweir     OStringBuffer aLine( "beginStructureElement " );
11226cdf0e10cSrcweir     aLine.append( m_nCurrentStructElement );
11227cdf0e10cSrcweir     aLine.append( ": " );
11228cdf0e10cSrcweir     aLine.append( getStructureTag( eType ) );
11229cdf0e10cSrcweir     if( rEle.m_aAlias.getLength() )
11230cdf0e10cSrcweir     {
11231cdf0e10cSrcweir         aLine.append( " aliased as \"" );
11232cdf0e10cSrcweir         aLine.append( rEle.m_aAlias );
11233cdf0e10cSrcweir         aLine.append( '\"' );
11234cdf0e10cSrcweir     }
11235cdf0e10cSrcweir     emitComment( aLine.getStr() );
11236cdf0e10cSrcweir #endif
11237cdf0e10cSrcweir 
11238cdf0e10cSrcweir     // check whether to emit structure henceforth
11239cdf0e10cSrcweir     m_bEmitStructure = checkEmitStructure();
11240cdf0e10cSrcweir 
11241cdf0e10cSrcweir     if( m_bEmitStructure ) // don't create nonexistant objects
11242cdf0e10cSrcweir     {
11243cdf0e10cSrcweir         rEle.m_nObject      = createObject();
11244cdf0e10cSrcweir         // update parent's kids list
11245cdf0e10cSrcweir         m_aStructure[ rEle.m_nParentElement ].m_aKids.push_back( rEle.m_nObject );
11246cdf0e10cSrcweir     }
11247cdf0e10cSrcweir     return nNewId;
11248cdf0e10cSrcweir }
11249cdf0e10cSrcweir 
endStructureElement()11250cdf0e10cSrcweir void PDFWriterImpl::endStructureElement()
11251cdf0e10cSrcweir {
11252cdf0e10cSrcweir     if( m_nCurrentPage < 0 )
11253cdf0e10cSrcweir         return;
11254cdf0e10cSrcweir 
11255cdf0e10cSrcweir     if( ! m_aContext.Tagged )
11256cdf0e10cSrcweir         return;
11257cdf0e10cSrcweir 
11258cdf0e10cSrcweir     if( m_nCurrentStructElement == 0 )
11259cdf0e10cSrcweir     {
11260cdf0e10cSrcweir         // hit the struct tree root, that means there is an endStructureElement
11261cdf0e10cSrcweir         // without corresponding beginStructureElement
11262cdf0e10cSrcweir         return;
11263cdf0e10cSrcweir     }
11264cdf0e10cSrcweir 
11265cdf0e10cSrcweir     // end the marked content sequence
11266cdf0e10cSrcweir     endStructureElementMCSeq();
11267cdf0e10cSrcweir 
11268cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
11269cdf0e10cSrcweir     OStringBuffer aLine( "endStructureElement " );
11270cdf0e10cSrcweir     aLine.append( m_nCurrentStructElement );
11271cdf0e10cSrcweir     aLine.append( ": " );
11272cdf0e10cSrcweir     aLine.append( getStructureTag( m_aStructure[ m_nCurrentStructElement ].m_eType ) );
11273cdf0e10cSrcweir     if( m_aStructure[ m_nCurrentStructElement ].m_aAlias.getLength() )
11274cdf0e10cSrcweir     {
11275cdf0e10cSrcweir         aLine.append( " aliased as \"" );
11276cdf0e10cSrcweir         aLine.append( m_aStructure[ m_nCurrentStructElement ].m_aAlias );
11277cdf0e10cSrcweir         aLine.append( '\"' );
11278cdf0e10cSrcweir     }
11279cdf0e10cSrcweir #endif
11280cdf0e10cSrcweir 
11281cdf0e10cSrcweir     // "end" the structure element, the parent becomes current element
11282cdf0e10cSrcweir     m_nCurrentStructElement = m_aStructure[ m_nCurrentStructElement ].m_nParentElement;
11283cdf0e10cSrcweir 
11284cdf0e10cSrcweir     // check whether to emit structure henceforth
11285cdf0e10cSrcweir     m_bEmitStructure = checkEmitStructure();
11286cdf0e10cSrcweir 
11287cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
11288cdf0e10cSrcweir     if( m_bEmitStructure )
11289cdf0e10cSrcweir         emitComment( aLine.getStr() );
11290cdf0e10cSrcweir #endif
11291cdf0e10cSrcweir }
11292cdf0e10cSrcweir 
11293cdf0e10cSrcweir //---> i94258
11294cdf0e10cSrcweir /*
11295cdf0e10cSrcweir  * This function adds an internal structure list container to overcome the 8191 elements array limitation
11296cdf0e10cSrcweir  * in kids element emission.
11297cdf0e10cSrcweir  * Recursive function
11298cdf0e10cSrcweir  *
11299cdf0e10cSrcweir  */
addInternalStructureContainer(PDFStructureElement & rEle)11300cdf0e10cSrcweir void PDFWriterImpl::addInternalStructureContainer( PDFStructureElement& rEle )
11301cdf0e10cSrcweir {
11302cdf0e10cSrcweir     if( rEle.m_eType == PDFWriter::NonStructElement &&
11303cdf0e10cSrcweir         rEle.m_nOwnElement != rEle.m_nParentElement )
11304cdf0e10cSrcweir         return;
11305cdf0e10cSrcweir 
11306cdf0e10cSrcweir     for( std::list< sal_Int32 >::const_iterator it = rEle.m_aChildren.begin(); it != rEle.m_aChildren.end(); ++it )
11307cdf0e10cSrcweir     {
11308cdf0e10cSrcweir         if( *it > 0 && *it < sal_Int32(m_aStructure.size()) )
11309cdf0e10cSrcweir         {
11310cdf0e10cSrcweir             PDFStructureElement& rChild = m_aStructure[ *it ];
11311cdf0e10cSrcweir             if( rChild.m_eType != PDFWriter::NonStructElement )
11312cdf0e10cSrcweir             {
11313cdf0e10cSrcweir                 //triggered when a child of the rEle element is found
11314cdf0e10cSrcweir                 if( rChild.m_nParentElement == rEle.m_nOwnElement )
11315cdf0e10cSrcweir                     addInternalStructureContainer( rChild );//examine the child
11316cdf0e10cSrcweir                 else
11317cdf0e10cSrcweir                 {
11318cdf0e10cSrcweir                     DBG_ERROR( "PDFWriterImpl::addInternalStructureContainer: invalid child structure element" );
11319cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
11320cdf0e10cSrcweir                     fprintf( stderr, "PDFWriterImpl::addInternalStructureContainer: invalid child structure elemnt with id %" SAL_PRIdINT32 "\n", *it );
11321cdf0e10cSrcweir #endif
11322cdf0e10cSrcweir                 }
11323cdf0e10cSrcweir             }
11324cdf0e10cSrcweir         }
11325cdf0e10cSrcweir         else
11326cdf0e10cSrcweir         {
11327cdf0e10cSrcweir             DBG_ERROR( "PDFWriterImpl::emitStructure: invalid child structure id" );
11328cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
11329cdf0e10cSrcweir             fprintf( stderr, "PDFWriterImpl::addInternalStructureContainer: invalid child structure id %" SAL_PRIdINT32 "\n", *it );
11330cdf0e10cSrcweir #endif
11331cdf0e10cSrcweir         }
11332cdf0e10cSrcweir     }
11333cdf0e10cSrcweir 
11334cdf0e10cSrcweir     if( rEle.m_nOwnElement != rEle.m_nParentElement )
11335cdf0e10cSrcweir     {
11336cdf0e10cSrcweir         if( !rEle.m_aKids.empty() )
11337cdf0e10cSrcweir         {
11338cdf0e10cSrcweir             if( rEle.m_aKids.size() > ncMaxPDFArraySize ) {
11339cdf0e10cSrcweir                 //then we need to add the containers for the kids elements
11340cdf0e10cSrcweir                 // a list to be used for the new kid element
11341cdf0e10cSrcweir                 std::list< PDFStructureElementKid > aNewKids;
11342cdf0e10cSrcweir                 std::list< sal_Int32 > aNewChildren;
11343cdf0e10cSrcweir 
11344cdf0e10cSrcweir                 // add Div in RoleMap, in case no one else did (TODO: is it needed? Is it dangerous?)
11345cdf0e10cSrcweir                 OStringBuffer aNameBuf( "Div" );
11346cdf0e10cSrcweir                 OString aAliasName( aNameBuf.makeStringAndClear() );
11347cdf0e10cSrcweir                 m_aRoleMap[ aAliasName ] = getStructureTag( PDFWriter::Division );
11348cdf0e10cSrcweir 
11349cdf0e10cSrcweir                 while( rEle.m_aKids.size() > ncMaxPDFArraySize )
11350cdf0e10cSrcweir                 {
11351cdf0e10cSrcweir                     sal_Int32 nCurrentStructElement = rEle.m_nOwnElement;
11352cdf0e10cSrcweir                     sal_Int32 nNewId = sal_Int32(m_aStructure.size());
11353cdf0e10cSrcweir                     m_aStructure.push_back( PDFStructureElement() );
11354cdf0e10cSrcweir                     PDFStructureElement& rEleNew = m_aStructure.back();
11355cdf0e10cSrcweir                     rEleNew.m_aAlias            = aAliasName;
11356cdf0e10cSrcweir                     rEleNew.m_eType             = PDFWriter::Division; // a new Div type container
11357cdf0e10cSrcweir                     rEleNew.m_nOwnElement       = nNewId;
11358cdf0e10cSrcweir                     rEleNew.m_nParentElement    = nCurrentStructElement;
11359cdf0e10cSrcweir                     //inherit the same page as the first child to be reparented
11360cdf0e10cSrcweir                     rEleNew.m_nFirstPageObject  = m_aStructure[ rEle.m_aChildren.front() ].m_nFirstPageObject;
11361cdf0e10cSrcweir                     rEleNew.m_nObject           = createObject();//assign a PDF object number
11362cdf0e10cSrcweir                     //add the object to the kid list of the parent
11363cdf0e10cSrcweir                     aNewKids.push_back( PDFStructureElementKid( rEleNew.m_nObject ) );
11364cdf0e10cSrcweir                     aNewChildren.push_back( nNewId );
11365cdf0e10cSrcweir 
11366cdf0e10cSrcweir                     std::list< sal_Int32 >::iterator aChildEndIt( rEle.m_aChildren.begin() );
11367cdf0e10cSrcweir                     std::list< PDFStructureElementKid >::iterator aKidEndIt( rEle.m_aKids.begin() );
11368cdf0e10cSrcweir                     advance( aChildEndIt, ncMaxPDFArraySize );
11369cdf0e10cSrcweir                     advance( aKidEndIt, ncMaxPDFArraySize );
11370cdf0e10cSrcweir 
11371cdf0e10cSrcweir                     rEleNew.m_aKids.splice( rEleNew.m_aKids.begin(),
11372cdf0e10cSrcweir                                             rEle.m_aKids,
11373cdf0e10cSrcweir                                             rEle.m_aKids.begin(),
11374cdf0e10cSrcweir                                             aKidEndIt );
11375cdf0e10cSrcweir                     rEleNew.m_aChildren.splice( rEleNew.m_aChildren.begin(),
11376cdf0e10cSrcweir                                                 rEle.m_aChildren,
11377cdf0e10cSrcweir                                                 rEle.m_aChildren.begin(),
11378cdf0e10cSrcweir                                                 aChildEndIt );
11379cdf0e10cSrcweir                     // set the kid's new parent
11380cdf0e10cSrcweir                     for( std::list< sal_Int32 >::const_iterator it = rEleNew.m_aChildren.begin();
11381cdf0e10cSrcweir                          it != rEleNew.m_aChildren.end(); ++it )
11382cdf0e10cSrcweir                     {
11383cdf0e10cSrcweir                         m_aStructure[ *it ].m_nParentElement = nNewId;
11384cdf0e10cSrcweir                     }
11385cdf0e10cSrcweir                 }
11386cdf0e10cSrcweir                 //finally add the new kids resulting from the container added
11387cdf0e10cSrcweir                 rEle.m_aKids.insert( rEle.m_aKids.begin(), aNewKids.begin(), aNewKids.end() );
11388cdf0e10cSrcweir                 rEle.m_aChildren.insert( rEle.m_aChildren.begin(), aNewChildren.begin(), aNewChildren.end() );
11389cdf0e10cSrcweir             }
11390cdf0e10cSrcweir         }
11391cdf0e10cSrcweir     }
11392cdf0e10cSrcweir }
11393cdf0e10cSrcweir //<--- i94258
11394cdf0e10cSrcweir 
setCurrentStructureElement(sal_Int32 nEle)11395cdf0e10cSrcweir bool PDFWriterImpl::setCurrentStructureElement( sal_Int32 nEle )
11396cdf0e10cSrcweir {
11397cdf0e10cSrcweir     bool bSuccess = false;
11398cdf0e10cSrcweir 
11399cdf0e10cSrcweir     if( m_aContext.Tagged && nEle >= 0 && nEle < sal_Int32(m_aStructure.size()) )
11400cdf0e10cSrcweir     {
11401cdf0e10cSrcweir         // end eventual previous marked content sequence
11402cdf0e10cSrcweir         endStructureElementMCSeq();
11403cdf0e10cSrcweir 
11404cdf0e10cSrcweir         m_nCurrentStructElement = nEle;
11405cdf0e10cSrcweir         m_bEmitStructure = checkEmitStructure();
11406cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
11407cdf0e10cSrcweir         OStringBuffer aLine( "setCurrentStructureElement " );
11408cdf0e10cSrcweir         aLine.append( m_nCurrentStructElement );
11409cdf0e10cSrcweir         aLine.append( ": " );
11410cdf0e10cSrcweir         aLine.append( getStructureTag( m_aStructure[ m_nCurrentStructElement ].m_eType ) );
11411cdf0e10cSrcweir         if( m_aStructure[ m_nCurrentStructElement ].m_aAlias.getLength() )
11412cdf0e10cSrcweir         {
11413cdf0e10cSrcweir             aLine.append( " aliased as \"" );
11414cdf0e10cSrcweir             aLine.append( m_aStructure[ m_nCurrentStructElement ].m_aAlias );
11415cdf0e10cSrcweir             aLine.append( '\"' );
11416cdf0e10cSrcweir         }
11417cdf0e10cSrcweir         if( ! m_bEmitStructure )
11418cdf0e10cSrcweir             aLine.append( " (inside NonStruct)" );
11419cdf0e10cSrcweir         emitComment( aLine.getStr() );
11420cdf0e10cSrcweir #endif
11421cdf0e10cSrcweir         bSuccess = true;
11422cdf0e10cSrcweir     }
11423cdf0e10cSrcweir 
11424cdf0e10cSrcweir     return bSuccess;
11425cdf0e10cSrcweir }
11426cdf0e10cSrcweir 
getCurrentStructureElement()11427cdf0e10cSrcweir sal_Int32 PDFWriterImpl::getCurrentStructureElement()
11428cdf0e10cSrcweir {
11429cdf0e10cSrcweir     return m_nCurrentStructElement;
11430cdf0e10cSrcweir }
11431cdf0e10cSrcweir 
setStructureAttribute(enum PDFWriter::StructAttribute eAttr,enum PDFWriter::StructAttributeValue eVal)11432cdf0e10cSrcweir bool PDFWriterImpl::setStructureAttribute( enum PDFWriter::StructAttribute eAttr, enum PDFWriter::StructAttributeValue eVal )
11433cdf0e10cSrcweir {
11434cdf0e10cSrcweir     if( !m_aContext.Tagged )
11435cdf0e10cSrcweir         return false;
11436cdf0e10cSrcweir 
11437cdf0e10cSrcweir     bool bInsert = false;
11438cdf0e10cSrcweir     if( m_nCurrentStructElement > 0 && m_bEmitStructure )
11439cdf0e10cSrcweir     {
11440cdf0e10cSrcweir         PDFWriter::StructElement eType = m_aStructure[ m_nCurrentStructElement ].m_eType;
11441cdf0e10cSrcweir         switch( eAttr )
11442cdf0e10cSrcweir         {
11443cdf0e10cSrcweir             case PDFWriter::Placement:
11444cdf0e10cSrcweir                 if( eVal == PDFWriter::Block        ||
11445cdf0e10cSrcweir                     eVal == PDFWriter::Inline       ||
11446cdf0e10cSrcweir                     eVal == PDFWriter::Before       ||
11447cdf0e10cSrcweir                     eVal == PDFWriter::Start        ||
11448cdf0e10cSrcweir                     eVal == PDFWriter::End )
11449cdf0e10cSrcweir                     bInsert = true;
11450cdf0e10cSrcweir                 break;
11451cdf0e10cSrcweir             case PDFWriter::WritingMode:
11452cdf0e10cSrcweir                 if( eVal == PDFWriter::LrTb         ||
11453cdf0e10cSrcweir                     eVal == PDFWriter::RlTb         ||
11454cdf0e10cSrcweir                     eVal == PDFWriter::TbRl )
11455cdf0e10cSrcweir                 {
11456cdf0e10cSrcweir                     bInsert = true;
11457cdf0e10cSrcweir                 }
11458cdf0e10cSrcweir                 break;
11459cdf0e10cSrcweir             case PDFWriter::TextAlign:
11460cdf0e10cSrcweir                 if( eVal == PDFWriter::Start        ||
11461cdf0e10cSrcweir                     eVal == PDFWriter::Center       ||
11462cdf0e10cSrcweir                     eVal == PDFWriter::End          ||
11463cdf0e10cSrcweir                     eVal == PDFWriter::Justify )
11464cdf0e10cSrcweir                 {
11465cdf0e10cSrcweir                     if( eType == PDFWriter::Paragraph   ||
11466cdf0e10cSrcweir                         eType == PDFWriter::Heading     ||
11467cdf0e10cSrcweir                         eType == PDFWriter::H1          ||
11468cdf0e10cSrcweir                         eType == PDFWriter::H2          ||
11469cdf0e10cSrcweir                         eType == PDFWriter::H3          ||
11470cdf0e10cSrcweir                         eType == PDFWriter::H4          ||
11471cdf0e10cSrcweir                         eType == PDFWriter::H5          ||
11472cdf0e10cSrcweir                         eType == PDFWriter::H6          ||
11473cdf0e10cSrcweir                         eType == PDFWriter::List        ||
11474cdf0e10cSrcweir                         eType == PDFWriter::ListItem    ||
11475cdf0e10cSrcweir                         eType == PDFWriter::LILabel     ||
11476cdf0e10cSrcweir                         eType == PDFWriter::LIBody      ||
11477cdf0e10cSrcweir                         eType == PDFWriter::Table       ||
11478cdf0e10cSrcweir                         eType == PDFWriter::TableRow    ||
11479cdf0e10cSrcweir                         eType == PDFWriter::TableHeader ||
11480cdf0e10cSrcweir                         eType == PDFWriter::TableData )
11481cdf0e10cSrcweir                     {
11482cdf0e10cSrcweir                         bInsert = true;
11483cdf0e10cSrcweir                     }
11484cdf0e10cSrcweir                 }
11485cdf0e10cSrcweir                 break;
11486cdf0e10cSrcweir             case PDFWriter::Width:
11487cdf0e10cSrcweir             case PDFWriter::Height:
11488cdf0e10cSrcweir                 if( eVal == PDFWriter::Auto )
11489cdf0e10cSrcweir                 {
11490cdf0e10cSrcweir                     if( eType == PDFWriter::Figure      ||
11491cdf0e10cSrcweir                         eType == PDFWriter::Formula     ||
11492cdf0e10cSrcweir                         eType == PDFWriter::Form        ||
11493cdf0e10cSrcweir                         eType == PDFWriter::Table       ||
11494cdf0e10cSrcweir                         eType == PDFWriter::TableHeader ||
11495cdf0e10cSrcweir                         eType == PDFWriter::TableData )
11496cdf0e10cSrcweir                     {
11497cdf0e10cSrcweir                         bInsert = true;
11498cdf0e10cSrcweir                     }
11499cdf0e10cSrcweir                 }
11500cdf0e10cSrcweir                 break;
11501cdf0e10cSrcweir             case PDFWriter::BlockAlign:
11502cdf0e10cSrcweir                 if( eVal == PDFWriter::Before       ||
11503cdf0e10cSrcweir                     eVal == PDFWriter::Middle       ||
11504cdf0e10cSrcweir                     eVal == PDFWriter::After        ||
11505cdf0e10cSrcweir                     eVal == PDFWriter::Justify )
11506cdf0e10cSrcweir                 {
11507cdf0e10cSrcweir                     if( eType == PDFWriter::TableHeader ||
11508cdf0e10cSrcweir                         eType == PDFWriter::TableData )
11509cdf0e10cSrcweir                     {
11510cdf0e10cSrcweir                         bInsert = true;
11511cdf0e10cSrcweir                     }
11512cdf0e10cSrcweir                 }
11513cdf0e10cSrcweir                 break;
11514cdf0e10cSrcweir             case PDFWriter::InlineAlign:
11515cdf0e10cSrcweir                 if( eVal == PDFWriter::Start        ||
11516cdf0e10cSrcweir                     eVal == PDFWriter::Center       ||
11517cdf0e10cSrcweir                     eVal == PDFWriter::End )
11518cdf0e10cSrcweir                 {
11519cdf0e10cSrcweir                     if( eType == PDFWriter::TableHeader ||
11520cdf0e10cSrcweir                         eType == PDFWriter::TableData )
11521cdf0e10cSrcweir                     {
11522cdf0e10cSrcweir                         bInsert = true;
11523cdf0e10cSrcweir                     }
11524cdf0e10cSrcweir                 }
11525cdf0e10cSrcweir                 break;
11526cdf0e10cSrcweir             case PDFWriter::LineHeight:
11527cdf0e10cSrcweir                 if( eVal == PDFWriter::Normal       ||
11528cdf0e10cSrcweir                     eVal == PDFWriter::Auto )
11529cdf0e10cSrcweir                 {
11530cdf0e10cSrcweir                     // only for ILSE and BLSE
11531cdf0e10cSrcweir                     if( eType == PDFWriter::Paragraph   ||
11532cdf0e10cSrcweir                         eType == PDFWriter::Heading     ||
11533cdf0e10cSrcweir                         eType == PDFWriter::H1          ||
11534cdf0e10cSrcweir                         eType == PDFWriter::H2          ||
11535cdf0e10cSrcweir                         eType == PDFWriter::H3          ||
11536cdf0e10cSrcweir                         eType == PDFWriter::H4          ||
11537cdf0e10cSrcweir                         eType == PDFWriter::H5          ||
11538cdf0e10cSrcweir                         eType == PDFWriter::H6          ||
11539cdf0e10cSrcweir                         eType == PDFWriter::List        ||
11540cdf0e10cSrcweir                         eType == PDFWriter::ListItem    ||
11541cdf0e10cSrcweir                         eType == PDFWriter::LILabel     ||
11542cdf0e10cSrcweir                         eType == PDFWriter::LIBody      ||
11543cdf0e10cSrcweir                         eType == PDFWriter::Table       ||
11544cdf0e10cSrcweir                         eType == PDFWriter::TableRow    ||
11545cdf0e10cSrcweir                         eType == PDFWriter::TableHeader ||
11546cdf0e10cSrcweir                         eType == PDFWriter::TableData   ||
11547cdf0e10cSrcweir                         eType == PDFWriter::Span        ||
11548cdf0e10cSrcweir                         eType == PDFWriter::Quote       ||
11549cdf0e10cSrcweir                         eType == PDFWriter::Note        ||
11550cdf0e10cSrcweir                         eType == PDFWriter::Reference   ||
11551cdf0e10cSrcweir                         eType == PDFWriter::BibEntry    ||
11552cdf0e10cSrcweir                         eType == PDFWriter::Code        ||
11553cdf0e10cSrcweir                         eType == PDFWriter::Link )
11554cdf0e10cSrcweir                     {
11555cdf0e10cSrcweir                         bInsert = true;
11556cdf0e10cSrcweir                     }
11557cdf0e10cSrcweir                 }
11558cdf0e10cSrcweir                 break;
11559cdf0e10cSrcweir             case PDFWriter::TextDecorationType:
11560cdf0e10cSrcweir                 if( eVal == PDFWriter::NONE         ||
11561cdf0e10cSrcweir                     eVal == PDFWriter::Underline    ||
11562cdf0e10cSrcweir                     eVal == PDFWriter::Overline     ||
11563cdf0e10cSrcweir                     eVal == PDFWriter::LineThrough )
11564cdf0e10cSrcweir                 {
11565cdf0e10cSrcweir                     // only for ILSE and BLSE
11566cdf0e10cSrcweir                     if( eType == PDFWriter::Paragraph   ||
11567cdf0e10cSrcweir                         eType == PDFWriter::Heading     ||
11568cdf0e10cSrcweir                         eType == PDFWriter::H1          ||
11569cdf0e10cSrcweir                         eType == PDFWriter::H2          ||
11570cdf0e10cSrcweir                         eType == PDFWriter::H3          ||
11571cdf0e10cSrcweir                         eType == PDFWriter::H4          ||
11572cdf0e10cSrcweir                         eType == PDFWriter::H5          ||
11573cdf0e10cSrcweir                         eType == PDFWriter::H6          ||
11574cdf0e10cSrcweir                         eType == PDFWriter::List        ||
11575cdf0e10cSrcweir                         eType == PDFWriter::ListItem    ||
11576cdf0e10cSrcweir                         eType == PDFWriter::LILabel     ||
11577cdf0e10cSrcweir                         eType == PDFWriter::LIBody      ||
11578cdf0e10cSrcweir                         eType == PDFWriter::Table       ||
11579cdf0e10cSrcweir                         eType == PDFWriter::TableRow    ||
11580cdf0e10cSrcweir                         eType == PDFWriter::TableHeader ||
11581cdf0e10cSrcweir                         eType == PDFWriter::TableData   ||
11582cdf0e10cSrcweir                         eType == PDFWriter::Span        ||
11583cdf0e10cSrcweir                         eType == PDFWriter::Quote       ||
11584cdf0e10cSrcweir                         eType == PDFWriter::Note        ||
11585cdf0e10cSrcweir                         eType == PDFWriter::Reference   ||
11586cdf0e10cSrcweir                         eType == PDFWriter::BibEntry    ||
11587cdf0e10cSrcweir                         eType == PDFWriter::Code        ||
11588cdf0e10cSrcweir                         eType == PDFWriter::Link )
11589cdf0e10cSrcweir                     {
11590cdf0e10cSrcweir                         bInsert = true;
11591cdf0e10cSrcweir                     }
11592cdf0e10cSrcweir                 }
11593cdf0e10cSrcweir                 break;
11594cdf0e10cSrcweir             case PDFWriter::ListNumbering:
11595cdf0e10cSrcweir                 if( eVal == PDFWriter::NONE         ||
11596cdf0e10cSrcweir                     eVal == PDFWriter::Disc         ||
11597cdf0e10cSrcweir                     eVal == PDFWriter::Circle       ||
11598cdf0e10cSrcweir                     eVal == PDFWriter::Square       ||
11599cdf0e10cSrcweir                     eVal == PDFWriter::Decimal      ||
11600cdf0e10cSrcweir                     eVal == PDFWriter::UpperRoman   ||
11601cdf0e10cSrcweir                     eVal == PDFWriter::LowerRoman   ||
11602cdf0e10cSrcweir                     eVal == PDFWriter::UpperAlpha   ||
11603cdf0e10cSrcweir                     eVal == PDFWriter::LowerAlpha )
11604cdf0e10cSrcweir                 {
11605cdf0e10cSrcweir                     if( eType == PDFWriter::List )
11606cdf0e10cSrcweir                         bInsert = true;
11607cdf0e10cSrcweir                 }
11608cdf0e10cSrcweir                 break;
11609cdf0e10cSrcweir             default: break;
11610cdf0e10cSrcweir         }
11611cdf0e10cSrcweir     }
11612cdf0e10cSrcweir 
11613cdf0e10cSrcweir     if( bInsert )
11614cdf0e10cSrcweir         m_aStructure[ m_nCurrentStructElement ].m_aAttributes[ eAttr ] = PDFStructureAttribute( eVal );
11615cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
11616cdf0e10cSrcweir     else if( m_nCurrentStructElement > 0 && m_bEmitStructure )
11617cdf0e10cSrcweir         fprintf( stderr, "rejecting setStructureAttribute( %s, %s ) on %s (%s) element\n",
11618cdf0e10cSrcweir                  getAttributeTag( eAttr ),
11619cdf0e10cSrcweir                  getAttributeValueTag( eVal ),
11620cdf0e10cSrcweir                  getStructureTag( m_aStructure[ m_nCurrentStructElement ].m_eType ),
11621cdf0e10cSrcweir                  m_aStructure[ m_nCurrentStructElement ].m_aAlias.getStr()
11622cdf0e10cSrcweir                  );
11623cdf0e10cSrcweir #endif
11624cdf0e10cSrcweir 
11625cdf0e10cSrcweir     return bInsert;
11626cdf0e10cSrcweir }
11627cdf0e10cSrcweir 
setStructureAttributeNumerical(enum PDFWriter::StructAttribute eAttr,sal_Int32 nValue)11628cdf0e10cSrcweir bool PDFWriterImpl::setStructureAttributeNumerical( enum PDFWriter::StructAttribute eAttr, sal_Int32 nValue )
11629cdf0e10cSrcweir {
11630cdf0e10cSrcweir     if( ! m_aContext.Tagged )
11631cdf0e10cSrcweir         return false;
11632cdf0e10cSrcweir 
11633cdf0e10cSrcweir     bool bInsert = false;
11634cdf0e10cSrcweir     if( m_nCurrentStructElement > 0 && m_bEmitStructure )
11635cdf0e10cSrcweir     {
11636cdf0e10cSrcweir         if( eAttr == PDFWriter::Language )
11637cdf0e10cSrcweir         {
11638cdf0e10cSrcweir             m_aStructure[ m_nCurrentStructElement ].m_aLocale = MsLangId::convertLanguageToLocale( (LanguageType)nValue );
11639cdf0e10cSrcweir             return true;
11640cdf0e10cSrcweir         }
11641cdf0e10cSrcweir 
11642cdf0e10cSrcweir         PDFWriter::StructElement eType = m_aStructure[ m_nCurrentStructElement ].m_eType;
11643cdf0e10cSrcweir         switch( eAttr )
11644cdf0e10cSrcweir         {
11645cdf0e10cSrcweir             case PDFWriter::SpaceBefore:
11646cdf0e10cSrcweir             case PDFWriter::SpaceAfter:
11647cdf0e10cSrcweir             case PDFWriter::StartIndent:
11648cdf0e10cSrcweir             case PDFWriter::EndIndent:
11649cdf0e10cSrcweir                 // just for BLSE
11650cdf0e10cSrcweir                 if( eType == PDFWriter::Paragraph   ||
11651cdf0e10cSrcweir                     eType == PDFWriter::Heading     ||
11652cdf0e10cSrcweir                     eType == PDFWriter::H1          ||
11653cdf0e10cSrcweir                     eType == PDFWriter::H2          ||
11654cdf0e10cSrcweir                     eType == PDFWriter::H3          ||
11655cdf0e10cSrcweir                     eType == PDFWriter::H4          ||
11656cdf0e10cSrcweir                     eType == PDFWriter::H5          ||
11657cdf0e10cSrcweir                     eType == PDFWriter::H6          ||
11658cdf0e10cSrcweir                     eType == PDFWriter::List        ||
11659cdf0e10cSrcweir                     eType == PDFWriter::ListItem    ||
11660cdf0e10cSrcweir                     eType == PDFWriter::LILabel     ||
11661cdf0e10cSrcweir                     eType == PDFWriter::LIBody      ||
11662cdf0e10cSrcweir                     eType == PDFWriter::Table       ||
11663cdf0e10cSrcweir                     eType == PDFWriter::TableRow    ||
11664cdf0e10cSrcweir                     eType == PDFWriter::TableHeader ||
11665cdf0e10cSrcweir                     eType == PDFWriter::TableData )
11666cdf0e10cSrcweir                 {
11667cdf0e10cSrcweir                     bInsert = true;
11668cdf0e10cSrcweir                 }
11669cdf0e10cSrcweir                 break;
11670cdf0e10cSrcweir             case PDFWriter::TextIndent:
11671cdf0e10cSrcweir                 // paragraph like BLSE and additional elements
11672cdf0e10cSrcweir                 if( eType == PDFWriter::Paragraph   ||
11673cdf0e10cSrcweir                     eType == PDFWriter::Heading     ||
11674cdf0e10cSrcweir                     eType == PDFWriter::H1          ||
11675cdf0e10cSrcweir                     eType == PDFWriter::H2          ||
11676cdf0e10cSrcweir                     eType == PDFWriter::H3          ||
11677cdf0e10cSrcweir                     eType == PDFWriter::H4          ||
11678cdf0e10cSrcweir                     eType == PDFWriter::H5          ||
11679cdf0e10cSrcweir                     eType == PDFWriter::H6          ||
11680cdf0e10cSrcweir                     eType == PDFWriter::LILabel     ||
11681cdf0e10cSrcweir                     eType == PDFWriter::LIBody      ||
11682cdf0e10cSrcweir                     eType == PDFWriter::TableHeader ||
11683cdf0e10cSrcweir                     eType == PDFWriter::TableData )
11684cdf0e10cSrcweir                 {
11685cdf0e10cSrcweir                     bInsert = true;
11686cdf0e10cSrcweir                 }
11687cdf0e10cSrcweir                 break;
11688cdf0e10cSrcweir             case PDFWriter::Width:
11689cdf0e10cSrcweir             case PDFWriter::Height:
11690cdf0e10cSrcweir                 if( eType == PDFWriter::Figure      ||
11691cdf0e10cSrcweir                     eType == PDFWriter::Formula     ||
11692cdf0e10cSrcweir                     eType == PDFWriter::Form        ||
11693cdf0e10cSrcweir                     eType == PDFWriter::Table       ||
11694cdf0e10cSrcweir                     eType == PDFWriter::TableHeader ||
11695cdf0e10cSrcweir                     eType == PDFWriter::TableData )
11696cdf0e10cSrcweir                 {
11697cdf0e10cSrcweir                     bInsert = true;
11698cdf0e10cSrcweir                 }
11699cdf0e10cSrcweir                 break;
11700cdf0e10cSrcweir             case PDFWriter::LineHeight:
11701cdf0e10cSrcweir             case PDFWriter::BaselineShift:
11702cdf0e10cSrcweir                 // only for ILSE and BLSE
11703cdf0e10cSrcweir                 if( eType == PDFWriter::Paragraph   ||
11704cdf0e10cSrcweir                     eType == PDFWriter::Heading     ||
11705cdf0e10cSrcweir                     eType == PDFWriter::H1          ||
11706cdf0e10cSrcweir                     eType == PDFWriter::H2          ||
11707cdf0e10cSrcweir                     eType == PDFWriter::H3          ||
11708cdf0e10cSrcweir                     eType == PDFWriter::H4          ||
11709cdf0e10cSrcweir                     eType == PDFWriter::H5          ||
11710cdf0e10cSrcweir                     eType == PDFWriter::H6          ||
11711cdf0e10cSrcweir                     eType == PDFWriter::List        ||
11712cdf0e10cSrcweir                     eType == PDFWriter::ListItem    ||
11713cdf0e10cSrcweir                     eType == PDFWriter::LILabel     ||
11714cdf0e10cSrcweir                     eType == PDFWriter::LIBody      ||
11715cdf0e10cSrcweir                     eType == PDFWriter::Table       ||
11716cdf0e10cSrcweir                     eType == PDFWriter::TableRow    ||
11717cdf0e10cSrcweir                     eType == PDFWriter::TableHeader ||
11718cdf0e10cSrcweir                     eType == PDFWriter::TableData   ||
11719cdf0e10cSrcweir                     eType == PDFWriter::Span        ||
11720cdf0e10cSrcweir                     eType == PDFWriter::Quote       ||
11721cdf0e10cSrcweir                     eType == PDFWriter::Note        ||
11722cdf0e10cSrcweir                     eType == PDFWriter::Reference   ||
11723cdf0e10cSrcweir                     eType == PDFWriter::BibEntry    ||
11724cdf0e10cSrcweir                     eType == PDFWriter::Code        ||
11725cdf0e10cSrcweir                     eType == PDFWriter::Link )
11726cdf0e10cSrcweir                 {
11727cdf0e10cSrcweir                         bInsert = true;
11728cdf0e10cSrcweir                 }
11729cdf0e10cSrcweir                 break;
11730cdf0e10cSrcweir             case PDFWriter::RowSpan:
11731cdf0e10cSrcweir             case PDFWriter::ColSpan:
11732cdf0e10cSrcweir                 // only for table cells
11733cdf0e10cSrcweir                 if( eType == PDFWriter::TableHeader ||
11734cdf0e10cSrcweir                     eType == PDFWriter::TableData )
11735cdf0e10cSrcweir                 {
11736cdf0e10cSrcweir                     bInsert = true;
11737cdf0e10cSrcweir                 }
11738cdf0e10cSrcweir                 break;
11739cdf0e10cSrcweir             case PDFWriter::LinkAnnotation:
11740cdf0e10cSrcweir                 if( eType == PDFWriter::Link )
11741cdf0e10cSrcweir                     bInsert = true;
11742cdf0e10cSrcweir                 break;
11743cdf0e10cSrcweir             default: break;
11744cdf0e10cSrcweir         }
11745cdf0e10cSrcweir     }
11746cdf0e10cSrcweir 
11747cdf0e10cSrcweir     if( bInsert )
11748cdf0e10cSrcweir         m_aStructure[ m_nCurrentStructElement ].m_aAttributes[ eAttr ] = PDFStructureAttribute( nValue );
11749cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
11750cdf0e10cSrcweir     else if( m_nCurrentStructElement > 0 && m_bEmitStructure )
11751cdf0e10cSrcweir         fprintf( stderr, "rejecting setStructureAttributeNumerical( %s, %d ) on %s (%s) element\n",
11752cdf0e10cSrcweir                  getAttributeTag( eAttr ),
11753cdf0e10cSrcweir                  (int)nValue,
11754cdf0e10cSrcweir                  getStructureTag( m_aStructure[ m_nCurrentStructElement ].m_eType ),
11755cdf0e10cSrcweir                  m_aStructure[ m_nCurrentStructElement ].m_aAlias.getStr() );
11756cdf0e10cSrcweir #endif
11757cdf0e10cSrcweir 
11758cdf0e10cSrcweir     return bInsert;
11759cdf0e10cSrcweir }
11760cdf0e10cSrcweir 
setStructureBoundingBox(const Rectangle & rRect)11761cdf0e10cSrcweir void PDFWriterImpl::setStructureBoundingBox( const Rectangle& rRect )
11762cdf0e10cSrcweir {
11763cdf0e10cSrcweir     sal_Int32 nPageNr = m_nCurrentPage;
11764cdf0e10cSrcweir     if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() || !m_aContext.Tagged )
11765cdf0e10cSrcweir         return;
11766cdf0e10cSrcweir 
11767cdf0e10cSrcweir 
11768cdf0e10cSrcweir     if( m_nCurrentStructElement > 0 && m_bEmitStructure )
11769cdf0e10cSrcweir     {
11770cdf0e10cSrcweir         PDFWriter::StructElement eType = m_aStructure[ m_nCurrentStructElement ].m_eType;
11771cdf0e10cSrcweir         if( eType == PDFWriter::Figure      ||
11772cdf0e10cSrcweir             eType == PDFWriter::Formula     ||
11773cdf0e10cSrcweir             eType == PDFWriter::Form        ||
11774cdf0e10cSrcweir             eType == PDFWriter::Table )
11775cdf0e10cSrcweir         {
11776cdf0e10cSrcweir             m_aStructure[ m_nCurrentStructElement ].m_aBBox = rRect;
11777cdf0e10cSrcweir             // convert to default user space now, since the mapmode may change
11778cdf0e10cSrcweir             m_aPages[nPageNr].convertRect( m_aStructure[ m_nCurrentStructElement ].m_aBBox );
11779cdf0e10cSrcweir         }
11780cdf0e10cSrcweir     }
11781cdf0e10cSrcweir }
11782cdf0e10cSrcweir 
setActualText(const String & rText)11783cdf0e10cSrcweir void PDFWriterImpl::setActualText( const String& rText )
11784cdf0e10cSrcweir {
11785cdf0e10cSrcweir     if( m_aContext.Tagged && m_nCurrentStructElement > 0 && m_bEmitStructure )
11786cdf0e10cSrcweir     {
11787cdf0e10cSrcweir         m_aStructure[ m_nCurrentStructElement ].m_aActualText = rText;
11788cdf0e10cSrcweir     }
11789cdf0e10cSrcweir }
11790cdf0e10cSrcweir 
setAlternateText(const String & rText)11791cdf0e10cSrcweir void PDFWriterImpl::setAlternateText( const String& rText )
11792cdf0e10cSrcweir {
11793cdf0e10cSrcweir     if( m_aContext.Tagged && m_nCurrentStructElement > 0 && m_bEmitStructure )
11794cdf0e10cSrcweir     {
11795cdf0e10cSrcweir         m_aStructure[ m_nCurrentStructElement ].m_aAltText = rText;
11796cdf0e10cSrcweir     }
11797cdf0e10cSrcweir }
11798cdf0e10cSrcweir 
setAutoAdvanceTime(sal_uInt32 nSeconds,sal_Int32 nPageNr)11799cdf0e10cSrcweir void PDFWriterImpl::setAutoAdvanceTime( sal_uInt32 nSeconds, sal_Int32 nPageNr )
11800cdf0e10cSrcweir {
11801cdf0e10cSrcweir     if( nPageNr < 0 )
11802cdf0e10cSrcweir         nPageNr = m_nCurrentPage;
11803cdf0e10cSrcweir 
11804cdf0e10cSrcweir     if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() )
11805cdf0e10cSrcweir         return;
11806cdf0e10cSrcweir 
11807cdf0e10cSrcweir     m_aPages[ nPageNr ].m_nDuration = nSeconds;
11808cdf0e10cSrcweir }
11809cdf0e10cSrcweir 
setPageTransition(PDFWriter::PageTransition eType,sal_uInt32 nMilliSec,sal_Int32 nPageNr)11810cdf0e10cSrcweir void PDFWriterImpl::setPageTransition( PDFWriter::PageTransition eType, sal_uInt32 nMilliSec, sal_Int32 nPageNr )
11811cdf0e10cSrcweir {
11812cdf0e10cSrcweir     if( nPageNr < 0 )
11813cdf0e10cSrcweir         nPageNr = m_nCurrentPage;
11814cdf0e10cSrcweir 
11815cdf0e10cSrcweir     if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() )
11816cdf0e10cSrcweir         return;
11817cdf0e10cSrcweir 
11818cdf0e10cSrcweir     m_aPages[ nPageNr ].m_eTransition   = eType;
11819cdf0e10cSrcweir     m_aPages[ nPageNr ].m_nTransTime    = nMilliSec;
11820cdf0e10cSrcweir }
11821cdf0e10cSrcweir 
ensureUniqueRadioOnValues()11822cdf0e10cSrcweir void PDFWriterImpl::ensureUniqueRadioOnValues()
11823cdf0e10cSrcweir {
11824cdf0e10cSrcweir     // loop over radio groups
11825cdf0e10cSrcweir     for( std::map<sal_Int32,sal_Int32>::const_iterator group = m_aRadioGroupWidgets.begin();
11826cdf0e10cSrcweir          group != m_aRadioGroupWidgets.end(); ++group )
11827cdf0e10cSrcweir     {
11828cdf0e10cSrcweir         PDFWidget& rGroupWidget = m_aWidgets[ group->second ];
11829cdf0e10cSrcweir         // check whether all kids have a unique OnValue
11830cdf0e10cSrcweir         std::hash_map< OUString, sal_Int32, OUStringHash > aOnValues;
11831cdf0e10cSrcweir         int nChildren = rGroupWidget.m_aKidsIndex.size();
11832cdf0e10cSrcweir         bool bIsUnique = true;
11833cdf0e10cSrcweir         for( int nKid = 0; nKid < nChildren && bIsUnique; nKid++ )
11834cdf0e10cSrcweir         {
11835cdf0e10cSrcweir             int nKidIndex = rGroupWidget.m_aKidsIndex[nKid];
11836cdf0e10cSrcweir             const OUString& rVal = m_aWidgets[nKidIndex].m_aOnValue;
11837cdf0e10cSrcweir             #if OSL_DEBUG_LEVEL > 1
11838cdf0e10cSrcweir             fprintf( stderr, "OnValue: %s\n", OUStringToOString( rVal, RTL_TEXTENCODING_UTF8 ).getStr() );
11839cdf0e10cSrcweir             #endif
11840cdf0e10cSrcweir             if( aOnValues.find( rVal ) == aOnValues.end() )
11841cdf0e10cSrcweir             {
11842cdf0e10cSrcweir                 aOnValues[ rVal ] = 1;
11843cdf0e10cSrcweir             }
11844cdf0e10cSrcweir             else
11845cdf0e10cSrcweir             {
11846cdf0e10cSrcweir                 bIsUnique = false;
11847cdf0e10cSrcweir             }
11848cdf0e10cSrcweir         }
11849cdf0e10cSrcweir         if( ! bIsUnique )
11850cdf0e10cSrcweir         {
11851cdf0e10cSrcweir             #if OSL_DEBUG_LEVEL > 1
11852cdf0e10cSrcweir             fprintf( stderr, "enforcing unique OnValues\n" );
11853cdf0e10cSrcweir             #endif
11854cdf0e10cSrcweir             // make unique by using ascending OnValues
11855cdf0e10cSrcweir             for( int nKid = 0; nKid < nChildren; nKid++ )
11856cdf0e10cSrcweir             {
11857cdf0e10cSrcweir                 int nKidIndex = rGroupWidget.m_aKidsIndex[nKid];
11858cdf0e10cSrcweir                 PDFWidget& rKid = m_aWidgets[nKidIndex];
11859cdf0e10cSrcweir                 rKid.m_aOnValue = OUString::valueOf( sal_Int32(nKid+1) );
11860cdf0e10cSrcweir                 if( ! rKid.m_aValue.equalsAscii( "Off" ) )
11861cdf0e10cSrcweir                     rKid.m_aValue = rKid.m_aOnValue;
11862cdf0e10cSrcweir             }
11863cdf0e10cSrcweir         }
11864cdf0e10cSrcweir         // finally move the "Yes" appearance to the OnValue appearance
11865cdf0e10cSrcweir         for( int nKid = 0; nKid < nChildren; nKid++ )
11866cdf0e10cSrcweir         {
11867cdf0e10cSrcweir             int nKidIndex = rGroupWidget.m_aKidsIndex[nKid];
11868cdf0e10cSrcweir             PDFWidget& rKid = m_aWidgets[nKidIndex];
11869cdf0e10cSrcweir             PDFAppearanceMap::iterator app_it = rKid.m_aAppearances.find( "N" );
11870cdf0e10cSrcweir             if( app_it != rKid.m_aAppearances.end() )
11871cdf0e10cSrcweir             {
11872cdf0e10cSrcweir                 PDFAppearanceStreams::iterator stream_it = app_it->second.find( "Yes" );
11873cdf0e10cSrcweir                 if( stream_it != app_it->second.end() )
11874cdf0e10cSrcweir                 {
11875cdf0e10cSrcweir                     SvMemoryStream* pStream = stream_it->second;
11876cdf0e10cSrcweir                     app_it->second.erase( stream_it );
11877cdf0e10cSrcweir                     OStringBuffer aBuf( rKid.m_aOnValue.getLength()*2 );
11878cdf0e10cSrcweir                     appendName( rKid.m_aOnValue, aBuf );
11879cdf0e10cSrcweir                     (app_it->second)[ aBuf.makeStringAndClear() ] = pStream;
11880cdf0e10cSrcweir                 }
11881cdf0e10cSrcweir                 #if OSL_DEBUG_LEVEL > 1
11882cdf0e10cSrcweir                 else
11883cdf0e10cSrcweir                     fprintf( stderr, "error: RadioButton without \"Yes\" stream\n" );
11884cdf0e10cSrcweir                 #endif
11885cdf0e10cSrcweir             }
11886cdf0e10cSrcweir             // update selected radio button
11887cdf0e10cSrcweir             if( ! rKid.m_aValue.equalsAscii( "Off" ) )
11888cdf0e10cSrcweir             {
11889cdf0e10cSrcweir                 rGroupWidget.m_aValue = rKid.m_aValue;
11890cdf0e10cSrcweir             }
11891cdf0e10cSrcweir         }
11892cdf0e10cSrcweir     }
11893cdf0e10cSrcweir }
11894cdf0e10cSrcweir 
findRadioGroupWidget(const PDFWriter::RadioButtonWidget & rBtn)11895cdf0e10cSrcweir sal_Int32 PDFWriterImpl::findRadioGroupWidget( const PDFWriter::RadioButtonWidget& rBtn )
11896cdf0e10cSrcweir {
11897cdf0e10cSrcweir     sal_Int32 nRadioGroupWidget = -1;
11898cdf0e10cSrcweir 
11899cdf0e10cSrcweir     std::map< sal_Int32, sal_Int32 >::const_iterator it = m_aRadioGroupWidgets.find( rBtn.RadioGroup );
11900cdf0e10cSrcweir 
11901cdf0e10cSrcweir     if( it == m_aRadioGroupWidgets.end() )
11902cdf0e10cSrcweir     {
11903cdf0e10cSrcweir         m_aRadioGroupWidgets[ rBtn.RadioGroup ] = nRadioGroupWidget =
11904cdf0e10cSrcweir             sal_Int32(m_aWidgets.size());
11905cdf0e10cSrcweir 
11906cdf0e10cSrcweir         // new group, insert the radiobutton
11907cdf0e10cSrcweir         m_aWidgets.push_back( PDFWidget() );
11908cdf0e10cSrcweir         m_aWidgets.back().m_nObject     = createObject();
11909cdf0e10cSrcweir         m_aWidgets.back().m_nPage       = m_nCurrentPage;
11910cdf0e10cSrcweir         m_aWidgets.back().m_eType       = PDFWriter::RadioButton;
11911cdf0e10cSrcweir         m_aWidgets.back().m_nRadioGroup = rBtn.RadioGroup;
11912cdf0e10cSrcweir         m_aWidgets.back().m_nFlags |= 0x0000C000;   // NoToggleToOff and Radio bits
11913cdf0e10cSrcweir 
11914cdf0e10cSrcweir         createWidgetFieldName( sal_Int32(m_aWidgets.size()-1), rBtn );
11915cdf0e10cSrcweir     }
11916cdf0e10cSrcweir     else
11917cdf0e10cSrcweir         nRadioGroupWidget = it->second;
11918cdf0e10cSrcweir 
11919cdf0e10cSrcweir     return nRadioGroupWidget;
11920cdf0e10cSrcweir }
11921cdf0e10cSrcweir 
createControl(const PDFWriter::AnyWidget & rControl,sal_Int32 nPageNr)11922cdf0e10cSrcweir sal_Int32 PDFWriterImpl::createControl( const PDFWriter::AnyWidget& rControl, sal_Int32 nPageNr )
11923cdf0e10cSrcweir {
11924cdf0e10cSrcweir     if( nPageNr < 0 )
11925cdf0e10cSrcweir         nPageNr = m_nCurrentPage;
11926cdf0e10cSrcweir 
11927cdf0e10cSrcweir     if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() )
11928cdf0e10cSrcweir         return -1;
11929cdf0e10cSrcweir 
11930cdf0e10cSrcweir     sal_Int32 nNewWidget = m_aWidgets.size();
11931cdf0e10cSrcweir     m_aWidgets.push_back( PDFWidget() );
11932cdf0e10cSrcweir 
11933cdf0e10cSrcweir     m_aWidgets.back().m_nObject         = createObject();
11934cdf0e10cSrcweir     m_aWidgets.back().m_aRect               = rControl.Location;
11935cdf0e10cSrcweir     m_aWidgets.back().m_nPage               = nPageNr;
11936cdf0e10cSrcweir     m_aWidgets.back().m_eType               = rControl.getType();
11937cdf0e10cSrcweir 
11938cdf0e10cSrcweir     sal_Int32 nRadioGroupWidget = -1;
11939cdf0e10cSrcweir     // for unknown reasons the radio buttons of a radio group must not have a
11940cdf0e10cSrcweir     // field name, else the buttons are in fact check boxes -
11941cdf0e10cSrcweir     // that is multiple buttons of the radio group can be selected
11942cdf0e10cSrcweir     if( rControl.getType() == PDFWriter::RadioButton )
11943cdf0e10cSrcweir         nRadioGroupWidget = findRadioGroupWidget( static_cast<const PDFWriter::RadioButtonWidget&>(rControl) );
11944cdf0e10cSrcweir     else
11945cdf0e10cSrcweir     {
11946cdf0e10cSrcweir         createWidgetFieldName( nNewWidget, rControl );
11947cdf0e10cSrcweir     }
11948cdf0e10cSrcweir 
11949cdf0e10cSrcweir     // caution: m_aWidgets must not be changed after here or rNewWidget may be invalid
11950cdf0e10cSrcweir     PDFWidget& rNewWidget           = m_aWidgets[nNewWidget];
11951cdf0e10cSrcweir     rNewWidget.m_aDescription       = rControl.Description;
11952cdf0e10cSrcweir     rNewWidget.m_aText              = rControl.Text;
11953cdf0e10cSrcweir     rNewWidget.m_nTextStyle         = rControl.TextStyle &
11954cdf0e10cSrcweir         (  TEXT_DRAW_LEFT | TEXT_DRAW_CENTER | TEXT_DRAW_RIGHT | TEXT_DRAW_TOP |
11955cdf0e10cSrcweir            TEXT_DRAW_VCENTER | TEXT_DRAW_BOTTOM |
11956cdf0e10cSrcweir            TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK  );
11957cdf0e10cSrcweir     rNewWidget.m_nTabOrder          = rControl.TabOrder;
11958cdf0e10cSrcweir 
11959cdf0e10cSrcweir     // various properties are set via the flags (/Ff) property of the field dict
11960cdf0e10cSrcweir     if( rControl.ReadOnly )
11961cdf0e10cSrcweir         rNewWidget.m_nFlags |= 1;
11962cdf0e10cSrcweir     if( rControl.getType() == PDFWriter::PushButton )
11963cdf0e10cSrcweir     {
11964cdf0e10cSrcweir         const PDFWriter::PushButtonWidget& rBtn = static_cast<const PDFWriter::PushButtonWidget&>(rControl);
11965cdf0e10cSrcweir         if( rNewWidget.m_nTextStyle == 0 )
11966cdf0e10cSrcweir             rNewWidget.m_nTextStyle =
11967cdf0e10cSrcweir                 TEXT_DRAW_CENTER | TEXT_DRAW_VCENTER |
11968cdf0e10cSrcweir                 TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK;
11969cdf0e10cSrcweir 
11970cdf0e10cSrcweir         rNewWidget.m_nFlags |= 0x00010000;
11971cdf0e10cSrcweir         if( rBtn.URL.getLength() )
11972cdf0e10cSrcweir             rNewWidget.m_aListEntries.push_back( rBtn.URL );
11973cdf0e10cSrcweir         rNewWidget.m_bSubmit    = rBtn.Submit;
11974cdf0e10cSrcweir         rNewWidget.m_bSubmitGet = rBtn.SubmitGet;
11975cdf0e10cSrcweir         rNewWidget.m_nDest      = rBtn.Dest;
11976cdf0e10cSrcweir         createDefaultPushButtonAppearance( rNewWidget, rBtn );
11977cdf0e10cSrcweir     }
11978cdf0e10cSrcweir     else if( rControl.getType() == PDFWriter::RadioButton )
11979cdf0e10cSrcweir     {
11980cdf0e10cSrcweir         const PDFWriter::RadioButtonWidget& rBtn = static_cast<const PDFWriter::RadioButtonWidget&>(rControl);
11981cdf0e10cSrcweir         if( rNewWidget.m_nTextStyle == 0 )
11982cdf0e10cSrcweir             rNewWidget.m_nTextStyle =
11983cdf0e10cSrcweir                 TEXT_DRAW_VCENTER | TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK;
11984cdf0e10cSrcweir         /*  PDF sees a RadioButton group as one radio button with
11985cdf0e10cSrcweir          *  children which are in turn check boxes
11986cdf0e10cSrcweir          *
11987cdf0e10cSrcweir          *  so we need to create a radio button on demand for a new group
11988cdf0e10cSrcweir          *  and insert a checkbox for each RadioButtonWidget as its child
11989cdf0e10cSrcweir          */
11990cdf0e10cSrcweir         rNewWidget.m_eType          = PDFWriter::CheckBox;
11991cdf0e10cSrcweir         rNewWidget.m_nRadioGroup    = rBtn.RadioGroup;
11992cdf0e10cSrcweir 
11993cdf0e10cSrcweir         DBG_ASSERT( nRadioGroupWidget >= 0 && nRadioGroupWidget < (sal_Int32)m_aWidgets.size(), "no radio group parent" );
11994cdf0e10cSrcweir 
11995cdf0e10cSrcweir         PDFWidget& rRadioButton = m_aWidgets[nRadioGroupWidget];
11996cdf0e10cSrcweir         rRadioButton.m_aKids.push_back( rNewWidget.m_nObject );
11997cdf0e10cSrcweir         rRadioButton.m_aKidsIndex.push_back( nNewWidget );
11998cdf0e10cSrcweir         rNewWidget.m_nParent = rRadioButton.m_nObject;
11999cdf0e10cSrcweir 
12000cdf0e10cSrcweir         rNewWidget.m_aValue     = OUString( RTL_CONSTASCII_USTRINGPARAM( "Off" ) );
12001cdf0e10cSrcweir         rNewWidget.m_aOnValue   = rBtn.OnValue;
12002cdf0e10cSrcweir         if( ! rRadioButton.m_aValue.getLength() && rBtn.Selected )
12003cdf0e10cSrcweir         {
12004cdf0e10cSrcweir             rNewWidget.m_aValue     = rNewWidget.m_aOnValue;
12005cdf0e10cSrcweir             rRadioButton.m_aValue   = rNewWidget.m_aOnValue;
12006cdf0e10cSrcweir         }
12007cdf0e10cSrcweir         createDefaultRadioButtonAppearance( rNewWidget, rBtn );
12008cdf0e10cSrcweir 
12009cdf0e10cSrcweir         // union rect of radio group
12010cdf0e10cSrcweir         Rectangle aRect = rNewWidget.m_aRect;
12011cdf0e10cSrcweir         m_aPages[ nPageNr ].convertRect( aRect );
12012cdf0e10cSrcweir         rRadioButton.m_aRect.Union( aRect );
12013cdf0e10cSrcweir     }
12014cdf0e10cSrcweir     else if( rControl.getType() == PDFWriter::CheckBox )
12015cdf0e10cSrcweir     {
12016cdf0e10cSrcweir         const PDFWriter::CheckBoxWidget& rBox = static_cast<const PDFWriter::CheckBoxWidget&>(rControl);
12017cdf0e10cSrcweir         if( rNewWidget.m_nTextStyle == 0 )
12018cdf0e10cSrcweir             rNewWidget.m_nTextStyle =
12019cdf0e10cSrcweir                 TEXT_DRAW_VCENTER | TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK;
12020cdf0e10cSrcweir 
12021cdf0e10cSrcweir         rNewWidget.m_aValue = OUString::createFromAscii( rBox.Checked ? "Yes" : "Off" );
12022cdf0e10cSrcweir         // create default appearance before m_aRect gets transformed
12023cdf0e10cSrcweir         createDefaultCheckBoxAppearance( rNewWidget, rBox );
12024cdf0e10cSrcweir     }
12025cdf0e10cSrcweir     else if( rControl.getType() == PDFWriter::ListBox )
12026cdf0e10cSrcweir     {
12027cdf0e10cSrcweir         if( rNewWidget.m_nTextStyle == 0 )
12028cdf0e10cSrcweir             rNewWidget.m_nTextStyle = TEXT_DRAW_VCENTER;
12029cdf0e10cSrcweir 
12030cdf0e10cSrcweir         const PDFWriter::ListBoxWidget& rLstBox = static_cast<const PDFWriter::ListBoxWidget&>(rControl);
12031cdf0e10cSrcweir         rNewWidget.m_aListEntries     = rLstBox.Entries;
12032cdf0e10cSrcweir         rNewWidget.m_aSelectedEntries = rLstBox.SelectedEntries;
12033cdf0e10cSrcweir         rNewWidget.m_aValue           = rLstBox.Text;
12034cdf0e10cSrcweir         if( rLstBox.DropDown )
12035cdf0e10cSrcweir             rNewWidget.m_nFlags |= 0x00020000;
12036cdf0e10cSrcweir         if( rLstBox.Sort )
12037cdf0e10cSrcweir             rNewWidget.m_nFlags |= 0x00080000;
12038cdf0e10cSrcweir         if( rLstBox.MultiSelect && !rLstBox.DropDown && (int)m_aContext.Version > (int)PDFWriter::PDF_1_3 )
12039cdf0e10cSrcweir             rNewWidget.m_nFlags |= 0x00200000;
12040cdf0e10cSrcweir 
12041cdf0e10cSrcweir         createDefaultListBoxAppearance( rNewWidget, rLstBox );
12042cdf0e10cSrcweir     }
12043cdf0e10cSrcweir     else if( rControl.getType() == PDFWriter::ComboBox )
12044cdf0e10cSrcweir     {
12045cdf0e10cSrcweir         if( rNewWidget.m_nTextStyle == 0 )
12046cdf0e10cSrcweir             rNewWidget.m_nTextStyle = TEXT_DRAW_VCENTER;
12047cdf0e10cSrcweir 
12048cdf0e10cSrcweir         const PDFWriter::ComboBoxWidget& rBox = static_cast<const PDFWriter::ComboBoxWidget&>(rControl);
12049cdf0e10cSrcweir         rNewWidget.m_aValue         = rBox.Text;
12050cdf0e10cSrcweir         rNewWidget.m_aListEntries   = rBox.Entries;
12051cdf0e10cSrcweir         rNewWidget.m_nFlags |= 0x00060000; // combo and edit flag
12052cdf0e10cSrcweir         if( rBox.Sort )
12053cdf0e10cSrcweir             rNewWidget.m_nFlags |= 0x00080000;
12054cdf0e10cSrcweir 
12055cdf0e10cSrcweir         PDFWriter::ListBoxWidget aLBox;
12056cdf0e10cSrcweir         aLBox.Name              = rBox.Name;
12057cdf0e10cSrcweir         aLBox.Description       = rBox.Description;
12058cdf0e10cSrcweir         aLBox.Text              = rBox.Text;
12059cdf0e10cSrcweir         aLBox.TextStyle         = rBox.TextStyle;
12060cdf0e10cSrcweir         aLBox.ReadOnly          = rBox.ReadOnly;
12061cdf0e10cSrcweir         aLBox.Border            = rBox.Border;
12062cdf0e10cSrcweir         aLBox.BorderColor       = rBox.BorderColor;
12063cdf0e10cSrcweir         aLBox.Background        = rBox.Background;
12064cdf0e10cSrcweir         aLBox.BackgroundColor   = rBox.BackgroundColor;
12065cdf0e10cSrcweir         aLBox.TextFont          = rBox.TextFont;
12066cdf0e10cSrcweir         aLBox.TextColor         = rBox.TextColor;
12067cdf0e10cSrcweir         aLBox.DropDown          = true;
12068cdf0e10cSrcweir         aLBox.Sort              = rBox.Sort;
12069cdf0e10cSrcweir         aLBox.MultiSelect       = false;
12070cdf0e10cSrcweir         aLBox.Entries           = rBox.Entries;
12071cdf0e10cSrcweir 
12072cdf0e10cSrcweir         createDefaultListBoxAppearance( rNewWidget, aLBox );
12073cdf0e10cSrcweir     }
12074cdf0e10cSrcweir     else if( rControl.getType() == PDFWriter::Edit )
12075cdf0e10cSrcweir     {
12076cdf0e10cSrcweir         if( rNewWidget.m_nTextStyle == 0 )
12077cdf0e10cSrcweir             rNewWidget.m_nTextStyle = TEXT_DRAW_LEFT | TEXT_DRAW_VCENTER;
12078cdf0e10cSrcweir 
12079cdf0e10cSrcweir         const PDFWriter::EditWidget& rEdit = static_cast<const  PDFWriter::EditWidget&>(rControl);
12080cdf0e10cSrcweir         if( rEdit.MultiLine )
12081cdf0e10cSrcweir         {
12082cdf0e10cSrcweir             rNewWidget.m_nFlags |= 0x00001000;
12083cdf0e10cSrcweir             rNewWidget.m_nTextStyle |= TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK;
12084cdf0e10cSrcweir         }
12085cdf0e10cSrcweir         if( rEdit.Password )
12086cdf0e10cSrcweir             rNewWidget.m_nFlags |= 0x00002000;
12087cdf0e10cSrcweir         if( rEdit.FileSelect && m_aContext.Version > PDFWriter::PDF_1_3 )
12088cdf0e10cSrcweir             rNewWidget.m_nFlags |= 0x00100000;
12089cdf0e10cSrcweir         rNewWidget.m_nMaxLen = rEdit.MaxLen;
12090cdf0e10cSrcweir         rNewWidget.m_aValue = rEdit.Text;
12091cdf0e10cSrcweir 
12092cdf0e10cSrcweir         createDefaultEditAppearance( rNewWidget, rEdit );
12093cdf0e10cSrcweir     }
12094cdf0e10cSrcweir 
12095cdf0e10cSrcweir     // convert to default user space now, since the mapmode may change
12096cdf0e10cSrcweir     // note: create default appearances before m_aRect gets transformed
12097cdf0e10cSrcweir     m_aPages[ nPageNr ].convertRect( rNewWidget.m_aRect );
12098cdf0e10cSrcweir 
12099cdf0e10cSrcweir     // insert widget to page's annotation list
12100cdf0e10cSrcweir     m_aPages[ nPageNr ].m_aAnnotations.push_back( rNewWidget.m_nObject );
12101cdf0e10cSrcweir 
12102cdf0e10cSrcweir     // mark page as having widgets
12103cdf0e10cSrcweir     m_aPages[ nPageNr ].m_bHasWidgets = true;
12104cdf0e10cSrcweir 
12105cdf0e10cSrcweir     return nNewWidget;
12106cdf0e10cSrcweir }
12107cdf0e10cSrcweir 
beginControlAppearance(sal_Int32 nControl)12108cdf0e10cSrcweir void PDFWriterImpl::beginControlAppearance( sal_Int32 nControl )
12109cdf0e10cSrcweir {
12110cdf0e10cSrcweir     if( nControl < 0 || nControl >= (sal_Int32)m_aWidgets.size() )
12111cdf0e10cSrcweir         return;
12112cdf0e10cSrcweir 
12113cdf0e10cSrcweir     PDFWidget& rWidget = m_aWidgets[ nControl ];
12114cdf0e10cSrcweir     m_nCurrentControl = nControl;
12115cdf0e10cSrcweir 
12116cdf0e10cSrcweir     SvMemoryStream* pControlStream = new SvMemoryStream( 1024, 1024 );
12117cdf0e10cSrcweir     // back conversion of control rect to current MapMode; necessary because
12118cdf0e10cSrcweir     // MapMode between createControl and beginControlAppearance
12119cdf0e10cSrcweir     // could have changed; therefore the widget rectangle is
12120cdf0e10cSrcweir     // already converted
12121cdf0e10cSrcweir     Rectangle aBack( Point( rWidget.m_aRect.Left(), pointToPixel(m_aPages[m_nCurrentPage].getHeight()) - rWidget.m_aRect.Top() - rWidget.m_aRect.GetHeight() ),
12122cdf0e10cSrcweir                      rWidget.m_aRect.GetSize() );
12123cdf0e10cSrcweir     aBack = lcl_convert( m_aMapMode,
12124cdf0e10cSrcweir                          m_aGraphicsStack.front().m_aMapMode,
12125cdf0e10cSrcweir                          getReferenceDevice(),
12126cdf0e10cSrcweir                          aBack );
12127cdf0e10cSrcweir     beginRedirect( pControlStream, aBack );
12128cdf0e10cSrcweir     writeBuffer( "/Tx BMC\n", 8 );
12129cdf0e10cSrcweir }
12130cdf0e10cSrcweir 
endControlAppearance(PDFWriter::WidgetState eState)12131cdf0e10cSrcweir bool PDFWriterImpl::endControlAppearance( PDFWriter::WidgetState eState )
12132cdf0e10cSrcweir {
12133cdf0e10cSrcweir     bool bRet = false;
12134cdf0e10cSrcweir     if( ! m_aOutputStreams.empty() )
12135cdf0e10cSrcweir         writeBuffer( "\nEMC\n", 5 );
12136cdf0e10cSrcweir     SvMemoryStream* pAppearance = static_cast<SvMemoryStream*>(endRedirect());
12137cdf0e10cSrcweir     if( pAppearance && m_nCurrentControl >= 0 && m_nCurrentControl < (sal_Int32)m_aWidgets.size() )
12138cdf0e10cSrcweir     {
12139cdf0e10cSrcweir         PDFWidget& rWidget = m_aWidgets[ m_nCurrentControl ];
12140cdf0e10cSrcweir         OString aState, aStyle;
12141cdf0e10cSrcweir         switch( rWidget.m_eType )
12142cdf0e10cSrcweir         {
12143cdf0e10cSrcweir             case PDFWriter::PushButton:
12144cdf0e10cSrcweir                 if( eState == PDFWriter::Up || eState == PDFWriter::Down )
12145cdf0e10cSrcweir                 {
12146cdf0e10cSrcweir                     aState = (eState == PDFWriter::Up) ? "N" : "D";
12147cdf0e10cSrcweir                     aStyle = "Standard";
12148cdf0e10cSrcweir                 }
12149cdf0e10cSrcweir                 break;
12150cdf0e10cSrcweir             case PDFWriter::CheckBox:
12151cdf0e10cSrcweir                 if( eState == PDFWriter::Up || eState == PDFWriter::Down )
12152cdf0e10cSrcweir                 {
12153cdf0e10cSrcweir                     aState = "N";
12154cdf0e10cSrcweir                     aStyle = (eState == PDFWriter::Up) ? "Off" : "Yes";
12155cdf0e10cSrcweir                     /* cf PDFReference 3rd ed. V1.4 p539:
12156cdf0e10cSrcweir                        recommended name for on state is "Yes",
12157cdf0e10cSrcweir                        recommended name for off state is "Off"
12158cdf0e10cSrcweir                      */
12159cdf0e10cSrcweir                 }
12160cdf0e10cSrcweir                 break;
12161cdf0e10cSrcweir             case PDFWriter::RadioButton:
12162cdf0e10cSrcweir                 if( eState == PDFWriter::Up || eState == PDFWriter::Down )
12163cdf0e10cSrcweir                 {
12164cdf0e10cSrcweir                     aState = "N";
12165cdf0e10cSrcweir                     if( eState == PDFWriter::Up )
12166cdf0e10cSrcweir                         aStyle = "Off";
12167cdf0e10cSrcweir                     else
12168cdf0e10cSrcweir                     {
12169cdf0e10cSrcweir                         OStringBuffer aBuf( rWidget.m_aOnValue.getLength()*2 );
12170cdf0e10cSrcweir                         appendName( rWidget.m_aOnValue, aBuf );
12171cdf0e10cSrcweir                         aStyle = aBuf.makeStringAndClear();
12172cdf0e10cSrcweir                     }
12173cdf0e10cSrcweir                 }
12174cdf0e10cSrcweir                 break;
12175cdf0e10cSrcweir             case PDFWriter::Edit:
12176cdf0e10cSrcweir                 aState = "N";
12177cdf0e10cSrcweir                 aStyle = "Standard";
12178cdf0e10cSrcweir                 break;
12179cdf0e10cSrcweir             case PDFWriter::ListBox:
12180cdf0e10cSrcweir             case PDFWriter::ComboBox:
12181cdf0e10cSrcweir             case PDFWriter::Hierarchy:
12182cdf0e10cSrcweir                 break;
12183cdf0e10cSrcweir         }
12184cdf0e10cSrcweir         if( aState.getLength() && aStyle.getLength() )
12185cdf0e10cSrcweir         {
12186cdf0e10cSrcweir             // delete eventual existing stream
12187cdf0e10cSrcweir             PDFAppearanceStreams::iterator it =
12188cdf0e10cSrcweir                 rWidget.m_aAppearances[ aState ].find( aStyle );
12189cdf0e10cSrcweir             if( it != rWidget.m_aAppearances[ aState ].end() )
12190cdf0e10cSrcweir                 delete it->second;
12191cdf0e10cSrcweir             rWidget.m_aAppearances[ aState ][ aStyle ] = pAppearance;
12192cdf0e10cSrcweir             bRet = true;
12193cdf0e10cSrcweir         }
12194cdf0e10cSrcweir     }
12195cdf0e10cSrcweir 
12196cdf0e10cSrcweir     if( ! bRet )
12197cdf0e10cSrcweir         delete pAppearance;
12198cdf0e10cSrcweir 
12199cdf0e10cSrcweir     m_nCurrentControl = -1;
12200cdf0e10cSrcweir 
12201cdf0e10cSrcweir     return bRet;
12202cdf0e10cSrcweir }
12203cdf0e10cSrcweir 
addStream(const String & rMimeType,PDFOutputStream * pStream,bool bCompress)12204cdf0e10cSrcweir void PDFWriterImpl::addStream( const String& rMimeType, PDFOutputStream* pStream, bool bCompress )
12205cdf0e10cSrcweir {
12206cdf0e10cSrcweir     if( pStream )
12207cdf0e10cSrcweir     {
12208cdf0e10cSrcweir         m_aAdditionalStreams.push_back( PDFAddStream() );
12209cdf0e10cSrcweir         PDFAddStream& rStream = m_aAdditionalStreams.back();
12210cdf0e10cSrcweir         rStream.m_aMimeType = rMimeType.Len()
12211cdf0e10cSrcweir                               ? OUString( rMimeType )
12212cdf0e10cSrcweir                               : OUString( RTL_CONSTASCII_USTRINGPARAM( "application/octet-stream" ) );
12213cdf0e10cSrcweir         rStream.m_pStream = pStream;
12214cdf0e10cSrcweir         rStream.m_bCompress = bCompress;
12215cdf0e10cSrcweir     }
12216cdf0e10cSrcweir }
12217