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( "&" ) );
6302cdf0e10cSrcweir break;
6303cdf0e10cSrcweir case sal_Unicode('<'):
6304cdf0e10cSrcweir rValue += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "<" ) );
6305cdf0e10cSrcweir break;
6306cdf0e10cSrcweir case sal_Unicode('>'):
6307cdf0e10cSrcweir rValue += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( ">" ) );
6308cdf0e10cSrcweir break;
6309cdf0e10cSrcweir case sal_Unicode('\''):
6310cdf0e10cSrcweir rValue += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "'" ) );
6311cdf0e10cSrcweir break;
6312cdf0e10cSrcweir case sal_Unicode('"'):
6313cdf0e10cSrcweir rValue += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( """ ) );
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