Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : :
30 : : #define _USE_MATH_DEFINES
31 : : #include <math.h>
32 : : #include <algorithm>
33 : :
34 : : #include <tools/urlobj.hxx>
35 : :
36 : : #include <pdfwriter_impl.hxx>
37 : :
38 : : #include <basegfx/polygon/b2dpolygon.hxx>
39 : : #include <basegfx/polygon/b2dpolypolygon.hxx>
40 : : #include <basegfx/polygon/b2dpolygontools.hxx>
41 : : #include <basegfx/polygon/b2dpolypolygontools.hxx>
42 : : #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
43 : : #include <basegfx/matrix/b2dhommatrix.hxx>
44 : :
45 : : #include <osl/thread.h>
46 : : #include <osl/file.h>
47 : :
48 : : #include <rtl/crc.h>
49 : : #include <rtl/digest.h>
50 : : #include <rtl/ustrbuf.hxx>
51 : :
52 : : #include <tools/debug.hxx>
53 : : #include <tools/zcodec.hxx>
54 : : #include <tools/stream.hxx>
55 : :
56 : : #include <i18npool/mslangid.hxx>
57 : :
58 : : #include <vcl/virdev.hxx>
59 : : #include <vcl/bmpacc.hxx>
60 : : #include <vcl/bitmapex.hxx>
61 : : #include <vcl/image.hxx>
62 : : #include <vcl/metric.hxx>
63 : : #include <vcl/svapp.hxx>
64 : : #include <vcl/lineinfo.hxx>
65 : : #include "vcl/cvtgrf.hxx"
66 : : #include "vcl/strhelper.hxx"
67 : :
68 : : #include <fontsubset.hxx>
69 : : #include <outdev.h>
70 : : #include <sallayout.hxx>
71 : : #include <textlayout.hxx>
72 : : #include <salgdi.hxx>
73 : :
74 : : #include <lcms2.h>
75 : :
76 : : #include <comphelper/processfactory.hxx>
77 : : #include <comphelper/string.hxx>
78 : :
79 : : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
80 : : #include <com/sun/star/util/URLTransformer.hpp>
81 : : #include <com/sun/star/util/URL.hpp>
82 : :
83 : : #include "cppuhelper/implbase1.hxx"
84 : :
85 : : #if !defined(ANDROID) && !defined(IOS)
86 : : // NSS header files for PDF signing support
87 : : #include "nss.h"
88 : : #include "cert.h"
89 : : #include "hasht.h"
90 : : #include "sechash.h"
91 : : #include "cms.h"
92 : : #include "cmst.h"
93 : : #endif
94 : :
95 : : using namespace vcl;
96 : :
97 : : using ::rtl::OUString;
98 : : using ::rtl::OUStringToOString;
99 : : using ::rtl::OString;
100 : : using ::rtl::OStringHash;
101 : : using ::rtl::OUStringHash;
102 : : using ::rtl::OStringBuffer;
103 : : using ::rtl::OUStringBuffer;
104 : :
105 : : #if (OSL_DEBUG_LEVEL < 3)
106 : : #define COMPRESS_PAGES
107 : : #else
108 : : #define DEBUG_DISABLE_PDFCOMPRESSION // also do not compress streams
109 : : #endif
110 : :
111 : : #define MAX_SIGNATURE_CONTENT_LENGTH 0x4000
112 : :
113 : : #ifdef DO_TEST_PDF
114 : : class PDFTestOutputStream : public PDFOutputStream
115 : : {
116 : : public:
117 : : virtual ~PDFTestOutputStream();
118 : : virtual void write( const com::sun::star::uno::Reference< com::sun::star::io::XOutputStream >& xStream );
119 : : };
120 : :
121 : : PDFTestOutputStream::~PDFTestOutputStream()
122 : : {
123 : : }
124 : :
125 : : void PDFTestOutputStream::write( const com::sun::star::uno::Reference< com::sun::star::io::XOutputStream >& xStream )
126 : : {
127 : : OString aStr( "lalala\ntest\ntest\ntest" );
128 : : com::sun::star::uno::Sequence< sal_Int8 > aData( aStr.getLength() );
129 : : memcpy( aData.getArray(), aStr.getStr(), aStr.getLength() );
130 : : xStream->writeBytes( aData );
131 : : }
132 : :
133 : : // this test code cannot be used to test PDF/A-1 because it forces
134 : : // control item (widgets) to bypass the structure controlling
135 : : // the embedding of such elements in actual run
136 : : void doTestCode()
137 : : {
138 : : static const char* pHome = getenv( "HOME" );
139 : : rtl::OUString aTestFile( "file://" );
140 : : aTestFile += rtl::OUString( pHome, strlen( pHome ), RTL_TEXTENCODING_MS_1252 );
141 : : aTestFile += rtl::OUString( "/pdf_export_test.pdf" );
142 : :
143 : : PDFWriter::PDFWriterContext aContext;
144 : : aContext.URL = aTestFile;
145 : : aContext.Version = PDFWriter::PDF_1_4;
146 : : aContext.Tagged = true;
147 : : aContext.InitialPage = 2;
148 : : aContext.DocumentInfo.Title = OUString( "PDF export test document" );
149 : : aContext.DocumentInfo.Producer = OUString( "VCL" );
150 : :
151 : : aContext.SignPDF = true;
152 : : aContext.SignLocation = OUString( "Burdur" );
153 : : aContext.SignReason = OUString( "Some valid reason to sign" );
154 : : aContext.SignContact = OUString( "signer@example.com" );
155 : :
156 : : com::sun::star::uno::Reference< com::sun::star::beans::XMaterialHolder > xEnc;
157 : : PDFWriter aWriter( aContext, xEnc );
158 : : aWriter.NewPage( 595, 842 );
159 : : aWriter.BeginStructureElement( PDFWriter::Document );
160 : : // set duration of 3 sec for first page
161 : : aWriter.SetAutoAdvanceTime( 3 );
162 : : aWriter.SetMapMode( MapMode( MAP_100TH_MM ) );
163 : :
164 : : aWriter.SetFillColor( Color( COL_LIGHTRED ) );
165 : : aWriter.SetLineColor( Color( COL_LIGHTGREEN ) );
166 : : aWriter.DrawRect( Rectangle( Point( 2000, 200 ), Size( 8000, 3000 ) ), 5000, 2000 );
167 : :
168 : : aWriter.SetFont( Font( String( RTL_CONSTASCII_USTRINGPARAM( "Times" ) ), Size( 0, 500 ) ) );
169 : : aWriter.SetTextColor( Color( COL_BLACK ) );
170 : : aWriter.SetLineColor( Color( COL_BLACK ) );
171 : : aWriter.SetFillColor( Color( COL_LIGHTBLUE ) );
172 : :
173 : : Rectangle aRect( Point( 5000, 5000 ), Size( 6000, 3000 ) );
174 : : aWriter.DrawRect( aRect );
175 : : aWriter.DrawText( aRect, String( RTL_CONSTASCII_USTRINGPARAM( "Link annot 1" ) ) );
176 : : sal_Int32 nFirstLink = aWriter.CreateLink( aRect );
177 : : PDFNote aNote;
178 : : aNote.Title = String( RTL_CONSTASCII_USTRINGPARAM( "A small test note" ) );
179 : : aNote.Contents = String( RTL_CONSTASCII_USTRINGPARAM( "There is no business like show business like no business i know. Everything about it is appealing." ) );
180 : : aWriter.CreateNote( Rectangle( Point( aRect.Right(), aRect.Top() ), Size( 6000, 3000 ) ), aNote );
181 : :
182 : : Rectangle aTargetRect( Point( 3000, 23000 ), Size( 12000, 6000 ) );
183 : : aWriter.SetFillColor( Color( COL_LIGHTGREEN ) );
184 : : aWriter.DrawRect( aTargetRect );
185 : : aWriter.DrawText( aTargetRect, String( RTL_CONSTASCII_USTRINGPARAM( "Dest second link" ) ) );
186 : : sal_Int32 nSecondDest = aWriter.CreateDest( aTargetRect );
187 : :
188 : : aWriter.BeginStructureElement( PDFWriter::Section );
189 : : aWriter.BeginStructureElement( PDFWriter::Heading );
190 : : aWriter.DrawText( Point(4500, 9000), String( RTL_CONSTASCII_USTRINGPARAM( "A small structure test" ) ) );
191 : : aWriter.EndStructureElement();
192 : : aWriter.BeginStructureElement( PDFWriter::Paragraph );
193 : : aWriter.SetStructureAttribute( PDFWriter::WritingMode, PDFWriter::LrTb );
194 : : aWriter.SetStructureAttribute( PDFWriter::TextDecorationType, PDFWriter::Underline );
195 : : aWriter.DrawText( Rectangle( Point( 4500, 10000 ), Size( 12000, 6000 ) ),
196 : : 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." ) ),
197 : : TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK
198 : : );
199 : : 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." ) ) );
200 : : aWriter.SetAlternateText( String( RTL_CONSTASCII_USTRINGPARAM( "This paragraph contains some lengthy nonsense to test structural element emission of PDFWriter." ) ) );
201 : : aWriter.EndStructureElement();
202 : : aWriter.BeginStructureElement( PDFWriter::Paragraph );
203 : : aWriter.SetStructureAttribute( PDFWriter::WritingMode, PDFWriter::LrTb );
204 : : aWriter.DrawText( Rectangle( Point( 4500, 19000 ), Size( 12000, 1000 ) ),
205 : : String( RTL_CONSTASCII_USTRINGPARAM( "This paragraph is nothing special either but ends on the next page structurewise" ) ),
206 : : TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK
207 : : );
208 : :
209 : : aWriter.NewPage( 595, 842 );
210 : : // test AddStream interface
211 : : aWriter.AddStream( String( RTL_CONSTASCII_USTRINGPARAM( "text/plain" ) ), new PDFTestOutputStream(), true );
212 : : // set transitional mode
213 : : aWriter.SetPageTransition( PDFWriter::WipeRightToLeft, 1500 );
214 : : aWriter.SetMapMode( MapMode( MAP_100TH_MM ) );
215 : : aWriter.SetTextColor( Color( COL_BLACK ) );
216 : : aWriter.SetFont( Font( String( RTL_CONSTASCII_USTRINGPARAM( "Times" ) ), Size( 0, 500 ) ) );
217 : : aWriter.DrawText( Rectangle( Point( 4500, 1500 ), Size( 12000, 3000 ) ),
218 : : String( RTL_CONSTASCII_USTRINGPARAM( "Here's where all things come to an end ... well at least the paragaph from the last page." ) ),
219 : : TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK
220 : : );
221 : : aWriter.EndStructureElement();
222 : :
223 : : aWriter.SetFillColor( Color( COL_LIGHTBLUE ) );
224 : : // disable structure
225 : : aWriter.BeginStructureElement( PDFWriter::NonStructElement );
226 : : aWriter.DrawRect( aRect );
227 : : aWriter.BeginStructureElement( PDFWriter::Paragraph );
228 : : aWriter.DrawText( aRect, String( RTL_CONSTASCII_USTRINGPARAM( "Link annot 2" ) ) );
229 : : sal_Int32 nSecondLink = aWriter.CreateLink( aRect );
230 : :
231 : : aWriter.SetFillColor( Color( COL_LIGHTGREEN ) );
232 : : aWriter.BeginStructureElement( PDFWriter::ListItem );
233 : : aWriter.DrawRect( aTargetRect );
234 : : aWriter.DrawText( aTargetRect, String( RTL_CONSTASCII_USTRINGPARAM( "Dest first link" ) ) );
235 : : sal_Int32 nFirstDest = aWriter.CreateDest( aTargetRect );
236 : : // enable structure
237 : : aWriter.EndStructureElement();
238 : :
239 : : // add something to the long paragraph as an afterthought
240 : : /* PDFWriter::aWriter.GetCurrentStructureElement removed as an unusedcode.easy item:
241 : : http://cgit.freedesktop.org/libreoffice/core/commit/?id=09279fe3dad24ab58121e4f0a9564d252b64d81a
242 : :
243 : : sal_Int32 nSaveStruct = aWriter.GetCurrentStructureElement();
244 : : aWriter.SetCurrentStructureElement( nLongPara );
245 : : aWriter.DrawText( Rectangle( Point( 4500,4500 ), Size( 12000, 1000 ) ),
246 : : String( RTL_CONSTASCII_USTRINGPARAM( "Add something to the longish paragraph above." ) ),
247 : : TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK );
248 : : aWriter.SetCurrentStructureElement( nSaveStruct );
249 : : */
250 : :
251 : : aWriter.EndStructureElement();
252 : : aWriter.EndStructureElement();
253 : : aWriter.BeginStructureElement( PDFWriter::Figure );
254 : : aWriter.BeginStructureElement( PDFWriter::Caption );
255 : : aWriter.DrawText( Point( 4500, 9000 ), String( RTL_CONSTASCII_USTRINGPARAM( "Some drawing stuff inside the structure" ) ) );
256 : : aWriter.EndStructureElement();
257 : :
258 : : // test clipping
259 : : basegfx::B2DPolyPolygon aClip;
260 : : basegfx::B2DPolygon aClipPoly;
261 : : aClipPoly.append( basegfx::B2DPoint( 8250, 9600 ) );
262 : : aClipPoly.append( basegfx::B2DPoint( 16500, 11100 ) );
263 : : aClipPoly.append( basegfx::B2DPoint( 8250, 12600 ) );
264 : : aClipPoly.append( basegfx::B2DPoint( 4500, 11100 ) );
265 : : aClipPoly.setClosed( true );
266 : : //aClipPoly.flip();
267 : : aClip.append( aClipPoly );
268 : :
269 : : aWriter.Push( PUSH_CLIPREGION | PUSH_FILLCOLOR );
270 : : aWriter.SetClipRegion( aClip );
271 : : aWriter.DrawEllipse( Rectangle( Point( 4500, 9600 ), Size( 12000, 3000 ) ) );
272 : : aWriter.MoveClipRegion( 1000, 500 );
273 : : aWriter.SetFillColor( Color( COL_RED ) );
274 : : aWriter.DrawEllipse( Rectangle( Point( 4500, 9600 ), Size( 12000, 3000 ) ) );
275 : : aWriter.Pop();
276 : : // test transparency
277 : : // draw background
278 : : Rectangle aTranspRect( Point( 7500, 13500 ), Size( 9000, 6000 ) );
279 : : aWriter.SetFillColor( Color( COL_LIGHTRED ) );
280 : : aWriter.DrawRect( aTranspRect );
281 : : aWriter.BeginTransparencyGroup();
282 : :
283 : : aWriter.SetFillColor( Color( COL_LIGHTGREEN ) );
284 : : aWriter.DrawEllipse( aTranspRect );
285 : : aWriter.SetTextColor( Color( COL_LIGHTBLUE ) );
286 : : aWriter.DrawText( aTranspRect,
287 : : String( RTL_CONSTASCII_USTRINGPARAM( "Some transparent text" ) ),
288 : : TEXT_DRAW_CENTER | TEXT_DRAW_VCENTER | TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK );
289 : :
290 : : aWriter.EndTransparencyGroup( aTranspRect, 50 );
291 : :
292 : : // prepare an alpha mask
293 : : Bitmap aTransMask( Size( 256, 256 ), 8, &Bitmap::GetGreyPalette( 256 ) );
294 : : BitmapWriteAccess* pAcc = aTransMask.AcquireWriteAccess();
295 : : for( int nX = 0; nX < 256; nX++ )
296 : : for( int nY = 0; nY < 256; nY++ )
297 : : pAcc->SetPixel( nX, nY, BitmapColor( (sal_uInt8)((nX+nY)/2) ) );
298 : : aTransMask.ReleaseAccess( pAcc );
299 : : aTransMask.SetPrefMapMode( MAP_MM );
300 : : aTransMask.SetPrefSize( Size( 10, 10 ) );
301 : :
302 : : aWriter.DrawBitmap( Point( 600, 13500 ), Size( 3000, 3000 ), aTransMask );
303 : :
304 : : aTranspRect = Rectangle( Point( 4200, 13500 ), Size( 3000, 3000 ) );
305 : : aWriter.SetFillColor( Color( COL_LIGHTRED ) );
306 : : aWriter.DrawRect( aTranspRect );
307 : : aWriter.SetFillColor( Color( COL_LIGHTGREEN ) );
308 : : aWriter.DrawEllipse( aTranspRect );
309 : : aWriter.SetTextColor( Color( COL_LIGHTBLUE ) );
310 : : aWriter.DrawText( aTranspRect,
311 : : String( RTL_CONSTASCII_USTRINGPARAM( "Some transparent text" ) ),
312 : : TEXT_DRAW_CENTER | TEXT_DRAW_VCENTER | TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK );
313 : : aTranspRect = Rectangle( Point( 1500, 16500 ), Size( 4800, 3000 ) );
314 : : aWriter.SetFillColor( Color( COL_LIGHTRED ) );
315 : : aWriter.DrawRect( aTranspRect );
316 : :
317 : : /*
318 : : EndTransparencyGroup( const Rectangle& rBoundRect, const Bitmap& rAlphaMask ) is removed as an unusedcode.easy item:
319 : : http://cgit.freedesktop.org/libreoffice/core/commit/?id=581e7d7057afa87036d84e42c0e0a8a7368e20c7
320 : :
321 : : aWriter.BeginTransparencyGroup();
322 : : aWriter.SetFillColor( Color( COL_LIGHTGREEN ) );
323 : : aWriter.DrawEllipse( aTranspRect );
324 : : aWriter.SetTextColor( Color( COL_LIGHTBLUE ) );
325 : : aWriter.DrawText( aTranspRect,
326 : : String( RTL_CONSTASCII_USTRINGPARAM( "Some transparent text" ) ),
327 : : TEXT_DRAW_CENTER | TEXT_DRAW_VCENTER | TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK );
328 : : aWriter.EndTransparencyGroup( aTranspRect, aTransMask );
329 : : */
330 : :
331 : : Bitmap aImageBmp( Size( 256, 256 ), 24 );
332 : : pAcc = aImageBmp.AcquireWriteAccess();
333 : : pAcc->SetFillColor( Color( 0xff, 0, 0xff ) );
334 : : pAcc->FillRect( Rectangle( Point( 0, 0 ), Size( 256, 256 ) ) );
335 : : aImageBmp.ReleaseAccess( pAcc );
336 : : BitmapEx aBmpEx( aImageBmp, AlphaMask( aTransMask ) );
337 : : aWriter.DrawBitmapEx( Point( 1500, 19500 ), Size( 4800, 3000 ), aBmpEx );
338 : :
339 : :
340 : : aWriter.EndStructureElement();
341 : : aWriter.EndStructureElement();
342 : :
343 : : LineInfo aLI( LINE_DASH, 3 );
344 : : aLI.SetDashCount( 2 );
345 : : aLI.SetDashLen( 50 );
346 : : aLI.SetDotCount( 2 );
347 : : aLI.SetDotLen( 25 );
348 : : aLI.SetDistance( 15 );
349 : : Point aLIPoints[] = { Point( 4000, 10000 ),
350 : : Point( 8000, 12000 ),
351 : : Point( 3000, 19000 ) };
352 : : Polygon aLIPoly( 3, aLIPoints );
353 : : aWriter.SetLineColor( Color( COL_BLUE ) );
354 : : aWriter.SetFillColor();
355 : : aWriter.DrawPolyLine( aLIPoly, aLI );
356 : :
357 : : aLI.SetDashCount( 4 );
358 : : aLIPoly.Move( 1000, 1000 );
359 : : aWriter.DrawPolyLine( aLIPoly, aLI );
360 : :
361 : : aWriter.NewPage( 595, 842 );
362 : : aWriter.SetMapMode( MapMode( MAP_100TH_MM ) );
363 : : Wallpaper aWall( aTransMask );
364 : : aWall.SetStyle( WALLPAPER_TILE );
365 : : aWriter.DrawWallpaper( Rectangle( Point( 4400, 4200 ), Size( 10200, 6300 ) ), aWall );
366 : :
367 : : /*
368 : : BeginPattern/EndPattern is removed as an unusedcode.easy item:
369 : : http://cgit.freedesktop.org/libreoffice/core/commit/?id=581e7d7057afa87036d84e42c0e0a8a7368e20c7
370 : :
371 : : aWriter.Push( PUSH_ALL );
372 : : aWriter.BeginPattern(Rectangle(Point(0,0),Size(2000,1000)));
373 : : aWriter.SetFillColor( Color( COL_RED ) );
374 : : aWriter.SetLineColor( Color( COL_LIGHTBLUE ) );
375 : : Point aFillPoints[] = { Point( 1000, 0 ),
376 : : Point( 0, 1000 ),
377 : : Point( 2000, 1000 ) };
378 : : aWriter.DrawPolygon( Polygon( 3, aFillPoints ) );
379 : : aWriter.DrawBitmap( Point( 200, 200 ), Size( 1600, 600 ), aTransMask );
380 : : aWriter.DrawText( Rectangle( Point( 200, 200 ), Size( 1600, 600 ) ), String( RTL_CONSTASCII_USTRINGPARAM( "Pattern" ) ) );
381 : : sal_Int32 nPattern = aWriter.EndPattern( SvtGraphicFill::Transform() );
382 : : aWriter.Pop();
383 : : Rectangle aPolyRect( Point( 3800, 11200 ), Size( 10200, 6300 ) );
384 : : aWriter.DrawPolyPolygon( PolyPolygon( Polygon( aPolyRect ) ), nPattern, true );
385 : : aWriter.SetFillColor();
386 : : aWriter.SetLineColor( Color( COL_LIGHTBLUE ) );
387 : : aWriter.DrawRect( aPolyRect );
388 : : */
389 : :
390 : : aWriter.NewPage( 595, 842 );
391 : : aWriter.SetMapMode( MapMode( MAP_100TH_MM ) );
392 : : aWriter.SetFont( Font( String( RTL_CONSTASCII_USTRINGPARAM( "Times" ) ), Size( 0, 500 ) ) );
393 : : aWriter.SetTextColor( Color( COL_BLACK ) );
394 : : aRect = Rectangle( Point( 4500, 6000 ), Size( 6000, 1500 ) );
395 : : aWriter.DrawRect( aRect );
396 : : aWriter.DrawText( aRect, String( RTL_CONSTASCII_USTRINGPARAM( "www.heise.de" ) ) );
397 : : sal_Int32 nURILink = aWriter.CreateLink( aRect );
398 : : aWriter.SetLinkURL( nURILink, OUString( "http://www.heise.de" ) );
399 : :
400 : : aWriter.SetLinkDest( nFirstLink, nFirstDest );
401 : : aWriter.SetLinkDest( nSecondLink, nSecondDest );
402 : :
403 : : // include a button
404 : : PDFWriter::PushButtonWidget aBtn;
405 : : aBtn.Name = OUString( "testButton" );
406 : : aBtn.Description = OUString( "A test button" );
407 : : aBtn.Text = OUString( "hit me" );
408 : : aBtn.Location = Rectangle( Point( 4500, 9000 ), Size( 4500, 3000 ) );
409 : : aBtn.Border = aBtn.Background = true;
410 : : aWriter.CreateControl( aBtn );
411 : :
412 : : // include a uri button
413 : : PDFWriter::PushButtonWidget aUriBtn;
414 : : aUriBtn.Name = OUString( "wwwButton" );
415 : : aUriBtn.Description = OUString( "A URI button" );
416 : : aUriBtn.Text = OUString( "to www" );
417 : : aUriBtn.Location = Rectangle( Point( 9500, 9000 ), Size( 4500, 3000 ) );
418 : : aUriBtn.Border = aUriBtn.Background = true;
419 : : aUriBtn.URL = OUString( "http://www.heise.de" );
420 : : aWriter.CreateControl( aUriBtn );
421 : :
422 : : // include a dest button
423 : : PDFWriter::PushButtonWidget aDstBtn;
424 : : aDstBtn.Name = OUString( "destButton" );
425 : : aDstBtn.Description = OUString( "A Dest button" );
426 : : aDstBtn.Text = OUString( "to paragraph" );
427 : : aDstBtn.Location = Rectangle( Point( 14500, 9000 ), Size( 4500, 3000 ) );
428 : : aDstBtn.Border = aDstBtn.Background = true;
429 : : aDstBtn.Dest = nFirstDest;
430 : : aWriter.CreateControl( aDstBtn );
431 : :
432 : : PDFWriter::CheckBoxWidget aCBox;
433 : : aCBox.Name = OUString( "textCheckBox" );
434 : : aCBox.Description = OUString( "A test check box" );
435 : : aCBox.Text = OUString( "check me" );
436 : : aCBox.Location = Rectangle( Point( 4500, 13500 ), Size( 3000, 750 ) );
437 : : aCBox.Checked = true;
438 : : aCBox.Border = aCBox.Background = false;
439 : : aWriter.CreateControl( aCBox );
440 : :
441 : : PDFWriter::CheckBoxWidget aCBox2;
442 : : aCBox2.Name = OUString( "textCheckBox2" );
443 : : aCBox2.Description = OUString( "Another test check box" );
444 : : aCBox2.Text = OUString( "check me right" );
445 : : aCBox2.Location = Rectangle( Point( 4500, 14250 ), Size( 3000, 750 ) );
446 : : aCBox2.Checked = true;
447 : : aCBox2.Border = aCBox2.Background = false;
448 : : aCBox2.ButtonIsLeft = false;
449 : : aWriter.CreateControl( aCBox2 );
450 : :
451 : : PDFWriter::RadioButtonWidget aRB1;
452 : : aRB1.Name = OUString( "rb1_1" );
453 : : aRB1.Description = OUString( "radio 1 button 1" );
454 : : aRB1.Text = OUString( "Despair" );
455 : : aRB1.Location = Rectangle( Point( 4500, 15000 ), Size( 6000, 1000 ) );
456 : : aRB1.Selected = true;
457 : : aRB1.RadioGroup = 1;
458 : : aRB1.Border = aRB1.Background = true;
459 : : aRB1.ButtonIsLeft = false;
460 : : aRB1.BorderColor = Color( COL_LIGHTGREEN );
461 : : aRB1.BackgroundColor = Color( COL_LIGHTBLUE );
462 : : aRB1.TextColor = Color( COL_LIGHTRED );
463 : : aRB1.TextFont = Font( String( RTL_CONSTASCII_USTRINGPARAM( "Courier" ) ), Size( 0, 800 ) );
464 : : aWriter.CreateControl( aRB1 );
465 : :
466 : : PDFWriter::RadioButtonWidget aRB2;
467 : : aRB2.Name = OUString( "rb2_1" );
468 : : aRB2.Description = OUString( "radio 2 button 1" );
469 : : aRB2.Text = OUString( "Joy" );
470 : : aRB2.Location = Rectangle( Point( 10500, 15000 ), Size( 3000, 1000 ) );
471 : : aRB2.Selected = true;
472 : : aRB2.RadioGroup = 2;
473 : : aWriter.CreateControl( aRB2 );
474 : :
475 : : PDFWriter::RadioButtonWidget aRB3;
476 : : aRB3.Name = OUString( "rb1_2" );
477 : : aRB3.Description = OUString( "radio 1 button 2" );
478 : : aRB3.Text = OUString( "Desperation" );
479 : : aRB3.Location = Rectangle( Point( 4500, 16000 ), Size( 3000, 1000 ) );
480 : : aRB3.Selected = true;
481 : : aRB3.RadioGroup = 1;
482 : : aWriter.CreateControl( aRB3 );
483 : :
484 : : PDFWriter::EditWidget aEditBox;
485 : : aEditBox.Name = OUString( "testEdit" );
486 : : aEditBox.Description = OUString( "A test edit field" );
487 : : aEditBox.Text = OUString( "A little test text" );
488 : : aEditBox.TextStyle = TEXT_DRAW_LEFT | TEXT_DRAW_VCENTER;
489 : : aEditBox.Location = Rectangle( Point( 10000, 18000 ), Size( 5000, 1500 ) );
490 : : aEditBox.MaxLen = 100;
491 : : aEditBox.Border = aEditBox.Background = true;
492 : : aEditBox.BorderColor = Color( COL_BLACK );
493 : : aWriter.CreateControl( aEditBox );
494 : :
495 : : // normal list box
496 : : PDFWriter::ListBoxWidget aLstBox;
497 : : aLstBox.Name = OUString( "testListBox" );
498 : : aLstBox.Text = OUString( "One" );
499 : : aLstBox.Description = OUString( "select me" );
500 : : aLstBox.Location = Rectangle( Point( 4500, 18000 ), Size( 3000, 1500 ) );
501 : : aLstBox.Sort = true;
502 : : aLstBox.MultiSelect = true;
503 : : aLstBox.Border = aLstBox.Background = true;
504 : : aLstBox.BorderColor = Color( COL_BLACK );
505 : : aLstBox.Entries.push_back( OUString( "One" ) );
506 : : aLstBox.Entries.push_back( OUString( "Two" ) );
507 : : aLstBox.Entries.push_back( OUString( "Three" ) );
508 : : aLstBox.Entries.push_back( OUString( "Four" ) );
509 : : aLstBox.SelectedEntries.push_back( 1 );
510 : : aLstBox.SelectedEntries.push_back( 2 );
511 : : aWriter.CreateControl( aLstBox );
512 : :
513 : : // dropdown list box
514 : : aLstBox.Name = OUString( "testDropDownListBox" );
515 : : aLstBox.DropDown = true;
516 : : aLstBox.Location = Rectangle( Point( 4500, 19500 ), Size( 3000, 500 ) );
517 : : aWriter.CreateControl( aLstBox );
518 : :
519 : : // combo box
520 : : PDFWriter::ComboBoxWidget aComboBox;
521 : : aComboBox.Name = OUString( "testComboBox" );
522 : : aComboBox.Text = OUString( "test a combobox" );
523 : : aComboBox.Entries.push_back( OUString( "Larry" ) );
524 : : aComboBox.Entries.push_back( OUString( "Curly" ) );
525 : : aComboBox.Entries.push_back( OUString( "Moe" ) );
526 : : aComboBox.Location = Rectangle( Point( 4500, 20000 ), Size( 3000, 500 ) );
527 : : aWriter.CreateControl( aComboBox );
528 : :
529 : : // test outlines
530 : : sal_Int32 nPage1OL = aWriter.CreateOutlineItem();
531 : : aWriter.SetOutlineItemText( nPage1OL, OUString( "Page 1" ) );
532 : : aWriter.SetOutlineItemDest( nPage1OL, nSecondDest );
533 : : aWriter.CreateOutlineItem( nPage1OL, OUString( "Dest 2" ), nSecondDest );
534 : : aWriter.CreateOutlineItem( nPage1OL, OUString( "Dest 2 revisited" ), nSecondDest );
535 : : aWriter.CreateOutlineItem( nPage1OL, OUString( "Dest 2 again" ), nSecondDest );
536 : : sal_Int32 nPage2OL = aWriter.CreateOutlineItem();
537 : : aWriter.SetOutlineItemText( nPage2OL, OUString( "Page 2" ) );
538 : : aWriter.CreateOutlineItem( nPage2OL, OUString( "Dest 1" ), nFirstDest );
539 : :
540 : : aWriter.EndStructureElement(); // close document
541 : :
542 : : aWriter.Emit();
543 : : }
544 : : #endif
545 : :
546 : : static const sal_Int32 nLog10Divisor = 1;
547 : : static const double fDivisor = 10.0;
548 : :
549 : : static inline double pixelToPoint( sal_Int32 px ) { return double(px)/fDivisor; }
550 : 0 : static inline double pixelToPoint( double px ) { return px/fDivisor; }
551 : 0 : static inline sal_Int32 pointToPixel( double pt ) { return sal_Int32(pt*fDivisor); }
552 : :
553 : : const sal_uInt8 PDFWriterImpl::s_nPadString[32] =
554 : : {
555 : : 0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08,
556 : : 0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80, 0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A
557 : : };
558 : :
559 : 0 : static void appendHex( sal_Int8 nInt, OStringBuffer& rBuffer )
560 : : {
561 : : static const sal_Char pHexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7',
562 : : '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
563 : 0 : rBuffer.append( pHexDigits[ (nInt >> 4) & 15 ] );
564 : 0 : rBuffer.append( pHexDigits[ nInt & 15 ] );
565 : 0 : }
566 : :
567 : 0 : static void appendName( const OUString& rStr, OStringBuffer& rBuffer )
568 : : {
569 : : // FIXME i59651 add a check for max length of 127 chars? Per PDF spec 1.4, appendix C.1
570 : : // I guess than when reading the #xx sequence it will count for a single character.
571 [ # # ]: 0 : OString aStr( OUStringToOString( rStr, RTL_TEXTENCODING_UTF8 ) );
572 : 0 : const sal_Char* pStr = aStr.getStr();
573 : 0 : int nLen = aStr.getLength();
574 [ # # ]: 0 : for( int i = 0; i < nLen; i++ )
575 : : {
576 : : /* #i16920# PDF recommendation: output UTF8, any byte
577 : : * outside the interval [33(=ASCII'!');126(=ASCII'~')]
578 : : * should be escaped hexadecimal
579 : : * for the sake of ghostscript which also reads PDF
580 : : * but has a narrower acceptance rate we only pass
581 : : * alphanumerics and '-' literally.
582 : : */
583 [ # # ][ # # ]: 0 : if( (pStr[i] >= 'A' && pStr[i] <= 'Z' ) ||
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
584 : 0 : (pStr[i] >= 'a' && pStr[i] <= 'z' ) ||
585 : 0 : (pStr[i] >= '0' && pStr[i] <= '9' ) ||
586 : 0 : pStr[i] == '-' )
587 : : {
588 [ # # ]: 0 : rBuffer.append( pStr[i] );
589 : : }
590 : : else
591 : : {
592 [ # # ]: 0 : rBuffer.append( '#' );
593 [ # # ]: 0 : appendHex( (sal_Int8)pStr[i], rBuffer );
594 : : }
595 : 0 : }
596 : 0 : }
597 : :
598 : 0 : static void appendName( const sal_Char* pStr, OStringBuffer& rBuffer )
599 : : {
600 : : //FIXME i59651 see above
601 [ # # ][ # # ]: 0 : while( pStr && *pStr )
[ # # ]
602 : : {
603 [ # # ][ # # ]: 0 : if( (*pStr >= 'A' && *pStr <= 'Z' ) ||
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
604 : : (*pStr >= 'a' && *pStr <= 'z' ) ||
605 : : (*pStr >= '0' && *pStr <= '9' ) ||
606 : : *pStr == '-' )
607 : : {
608 : 0 : rBuffer.append( *pStr );
609 : : }
610 : : else
611 : : {
612 : 0 : rBuffer.append( '#' );
613 : 0 : appendHex( (sal_Int8)*pStr, rBuffer );
614 : : }
615 : 0 : pStr++;
616 : : }
617 : 0 : }
618 : :
619 : : //used only to emit encoded passwords
620 : 0 : static void appendLiteralString( const sal_Char* pStr, sal_Int32 nLength, OStringBuffer& rBuffer )
621 : : {
622 [ # # ]: 0 : while( nLength )
623 : : {
624 [ # # # # : 0 : switch( *pStr )
# # # ]
625 : : {
626 : : case '\n' :
627 : 0 : rBuffer.append( "\\n" );
628 : 0 : break;
629 : : case '\r' :
630 : 0 : rBuffer.append( "\\r" );
631 : 0 : break;
632 : : case '\t' :
633 : 0 : rBuffer.append( "\\t" );
634 : 0 : break;
635 : : case '\b' :
636 : 0 : rBuffer.append( "\\b" );
637 : 0 : break;
638 : : case '\f' :
639 : 0 : rBuffer.append( "\\f" );
640 : 0 : break;
641 : : case '(' :
642 : : case ')' :
643 : : case '\\' :
644 : 0 : rBuffer.append( "\\" );
645 : 0 : rBuffer.append( (sal_Char) *pStr );
646 : 0 : break;
647 : : default:
648 : 0 : rBuffer.append( (sal_Char) *pStr );
649 : 0 : break;
650 : : }
651 : 0 : pStr++;
652 : 0 : nLength--;
653 : : }
654 : 0 : }
655 : :
656 : : /**--->i56629
657 : : * Convert a string before using it.
658 : : *
659 : : * This string conversion function is needed because the destination name
660 : : * in a PDF file seen through an Internet browser should be
661 : : * specially crafted, in order to be used directly by the browser.
662 : : * In this way the fragment part of a hyperlink to a PDF file (e.g. something
663 : : * as 'test1/test2/a-file.pdf#thefragment) will be (hopefully) interpreted by the
664 : : * PDF reader (currently only Adobe Reader plug-in seems to be working that way) called
665 : : * from inside the Internet browser as: 'open the file test1/test2/a-file.pdf
666 : : * and go to named destination thefragment using default zoom'.
667 : : * The conversion is needed because in case of a fragment in the form: Slide%201
668 : : * (meaning Slide 1) as it is converted obeying the Inet rules, it will become Slide25201
669 : : * using this conversion, in both the generated named destinations, fragment and GoToR
670 : : * destination.
671 : : *
672 : : * The names for destinations are name objects and so they don't need to be encrypted
673 : : * even though they expose the content of PDF file (e.g. guessing the PDF content from the
674 : : * destination name).
675 : : *
676 : : * Fhurter limitation: it is advisable to use standard ASCII characters for
677 : : * OOo bookmarks.
678 : : */
679 : 0 : static void appendDestinationName( const rtl::OUString& rString, OStringBuffer& rBuffer )
680 : : {
681 : 0 : const sal_Unicode* pStr = rString.getStr();
682 : 0 : sal_Int32 nLen = rString.getLength();
683 [ # # ]: 0 : for( int i = 0; i < nLen; i++ )
684 : : {
685 : 0 : sal_Unicode aChar = pStr[i];
686 [ # # ][ # # ]: 0 : if( (aChar >= '0' && aChar <= '9' ) ||
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
687 : : (aChar >= 'a' && aChar <= 'z' ) ||
688 : : (aChar >= 'A' && aChar <= 'Z' ) ||
689 : : aChar == '-' )
690 : : {
691 : 0 : rBuffer.append((sal_Char)aChar);
692 : : }
693 : : else
694 : : {
695 : 0 : sal_Int8 aValueHigh = sal_Int8(aChar >> 8);
696 [ # # ]: 0 : if(aValueHigh > 0)
697 : 0 : appendHex( aValueHigh, rBuffer );
698 : 0 : appendHex( (sal_Int8)(aChar & 255 ), rBuffer );
699 : : }
700 : : }
701 : 0 : }
702 : : //<--- i56629
703 : :
704 : 0 : static void appendUnicodeTextString( const rtl::OUString& rString, OStringBuffer& rBuffer )
705 : : {
706 : 0 : rBuffer.append( "FEFF" );
707 : 0 : const sal_Unicode* pStr = rString.getStr();
708 : 0 : sal_Int32 nLen = rString.getLength();
709 [ # # ]: 0 : for( int i = 0; i < nLen; i++ )
710 : : {
711 : 0 : sal_Unicode aChar = pStr[i];
712 : 0 : appendHex( (sal_Int8)(aChar >> 8), rBuffer );
713 : 0 : appendHex( (sal_Int8)(aChar & 255 ), rBuffer );
714 : : }
715 : 0 : }
716 : :
717 : 0 : void PDFWriterImpl::createWidgetFieldName( sal_Int32 i_nWidgetIndex, const PDFWriter::AnyWidget& i_rControl )
718 : : {
719 : : /* #i80258# previously we use appendName here
720 : : however we need a slightly different coding scheme than the normal
721 : : name encoding for field names
722 : : */
723 [ # # ]: 0 : const OUString& rName = (m_aContext.Version > PDFWriter::PDF_1_2) ? i_rControl.Name : i_rControl.Text;
724 [ # # ]: 0 : OString aStr( OUStringToOString( rName, RTL_TEXTENCODING_UTF8 ) );
725 : 0 : const sal_Char* pStr = aStr.getStr();
726 : 0 : int nLen = aStr.getLength();
727 : :
728 : 0 : OStringBuffer aBuffer( rName.getLength()+64 );
729 [ # # ]: 0 : for( int i = 0; i < nLen; i++ )
730 : : {
731 : : /* #i16920# PDF recommendation: output UTF8, any byte
732 : : * outside the interval [32(=ASCII' ');126(=ASCII'~')]
733 : : * should be escaped hexadecimal
734 : : */
735 [ # # ][ # # ]: 0 : if( (pStr[i] >= 32 && pStr[i] <= 126 ) )
736 [ # # ]: 0 : aBuffer.append( pStr[i] );
737 : : else
738 : : {
739 [ # # ]: 0 : aBuffer.append( '#' );
740 [ # # ]: 0 : appendHex( (sal_Int8)pStr[i], aBuffer );
741 : : }
742 : : }
743 : :
744 : 0 : OString aFullName( aBuffer.makeStringAndClear() );
745 : :
746 : : /* #i82785# create hierarchical fields down to the for each dot in i_rName */
747 : 0 : sal_Int32 nTokenIndex = 0, nLastTokenIndex = 0;
748 : 0 : OString aPartialName;
749 : 0 : OString aDomain;
750 [ # # ]: 0 : do
751 : : {
752 : 0 : nLastTokenIndex = nTokenIndex;
753 : 0 : aPartialName = aFullName.getToken( 0, '.', nTokenIndex );
754 [ # # ]: 0 : if( nTokenIndex != -1 )
755 : : {
756 : : // find or create a hierarchical field
757 : : // first find the fully qualified name up to this field
758 : 0 : aDomain = aFullName.copy( 0, nTokenIndex-1 );
759 [ # # ]: 0 : boost::unordered_map< rtl::OString, sal_Int32, rtl::OStringHash >::const_iterator it = m_aFieldNameMap.find( aDomain );
760 [ # # ][ # # ]: 0 : if( it == m_aFieldNameMap.end() )
761 : : {
762 : : // create new hierarchy field
763 : 0 : sal_Int32 nNewWidget = m_aWidgets.size();
764 [ # # ][ # # ]: 0 : m_aWidgets.push_back( PDFWidget() );
[ # # ]
765 [ # # ]: 0 : m_aWidgets[nNewWidget].m_nObject = createObject();
766 : 0 : m_aWidgets[nNewWidget].m_eType = PDFWriter::Hierarchy;
767 : 0 : m_aWidgets[nNewWidget].m_aName = aPartialName;
768 : 0 : m_aWidgets[i_nWidgetIndex].m_nParent = m_aWidgets[nNewWidget].m_nObject;
769 [ # # ]: 0 : m_aFieldNameMap[aDomain] = nNewWidget;
770 : 0 : m_aWidgets[i_nWidgetIndex].m_nParent = m_aWidgets[nNewWidget].m_nObject;
771 [ # # ]: 0 : if( nLastTokenIndex > 0 )
772 : : {
773 : : // this field is not a root field and
774 : : // needs to be inserted to its parent
775 : 0 : OString aParentDomain( aDomain.copy( 0, nLastTokenIndex-1 ) );
776 [ # # ]: 0 : it = m_aFieldNameMap.find( aParentDomain );
777 : : OSL_ENSURE( it != m_aFieldNameMap.end(), "field name not found" );
778 [ # # ][ # # ]: 0 : if( it != m_aFieldNameMap.end() )
779 : : {
780 : : OSL_ENSURE( it->second < sal_Int32(m_aWidgets.size()), "invalid field number entry" );
781 [ # # ][ # # ]: 0 : if( it->second < sal_Int32(m_aWidgets.size()) )
782 : : {
783 [ # # ]: 0 : PDFWidget& rParentField( m_aWidgets[it->second] );
784 [ # # ]: 0 : rParentField.m_aKids.push_back( m_aWidgets[nNewWidget].m_nObject );
785 [ # # ]: 0 : rParentField.m_aKidsIndex.push_back( nNewWidget );
786 : 0 : m_aWidgets[nNewWidget].m_nParent = rParentField.m_nObject;
787 : : }
788 : 0 : }
789 : : }
790 : : }
791 [ # # ][ # # ]: 0 : else if( m_aWidgets[it->second].m_eType != PDFWriter::Hierarchy )
792 : : {
793 : : // this is invalid, someone tries to have a terminal field as parent
794 : : // example: a button with the name foo.bar exists and
795 : : // another button is named foo.bar.no
796 : : // workaround: put the second terminal field as much up in the hierarchy as
797 : : // necessary to have a non-terminal field as parent (or none at all)
798 : : // since it->second already is terminal, we just need to use its parent
799 : 0 : aDomain = OString();
800 : 0 : aPartialName = aFullName.copy( aFullName.lastIndexOf( '.' )+1 );
801 [ # # ]: 0 : if( nLastTokenIndex > 0 )
802 : : {
803 : 0 : aDomain = aFullName.copy( 0, nLastTokenIndex-1 );
804 : 0 : OStringBuffer aBuf( aDomain.getLength() + 1 + aPartialName.getLength() );
805 [ # # ]: 0 : aBuf.append( aDomain );
806 [ # # ]: 0 : aBuf.append( '.' );
807 [ # # ]: 0 : aBuf.append( aPartialName );
808 : 0 : aFullName = aBuf.makeStringAndClear();
809 : : }
810 : : else
811 : 0 : aFullName = aPartialName;
812 : : break;
813 : : }
814 : : }
815 : : } while( nTokenIndex != -1 );
816 : :
817 : : // insert widget into its hierarchy field
818 [ # # ]: 0 : if( !aDomain.isEmpty() )
819 : : {
820 [ # # ]: 0 : boost::unordered_map< rtl::OString, sal_Int32, rtl::OStringHash >::const_iterator it = m_aFieldNameMap.find( aDomain );
821 [ # # ][ # # ]: 0 : if( it != m_aFieldNameMap.end() )
822 : : {
823 : : OSL_ENSURE( it->second >= 0 && it->second < sal_Int32( m_aWidgets.size() ), "invalid field index" );
824 [ # # ][ # # ]: 0 : if( it->second >= 0 && it->second < sal_Int32(m_aWidgets.size()) )
[ # # ][ # # ]
[ # # ]
825 : : {
826 [ # # ]: 0 : m_aWidgets[i_nWidgetIndex].m_nParent = m_aWidgets[it->second].m_nObject;
827 [ # # ][ # # ]: 0 : m_aWidgets[it->second].m_aKids.push_back( m_aWidgets[i_nWidgetIndex].m_nObject);
828 [ # # ][ # # ]: 0 : m_aWidgets[it->second].m_aKidsIndex.push_back( i_nWidgetIndex );
829 : : }
830 : : }
831 : : }
832 : :
833 [ # # ]: 0 : if( aPartialName.isEmpty() )
834 : : {
835 : : // how funny, an empty field name
836 [ # # ]: 0 : if( i_rControl.getType() == PDFWriter::RadioButton )
837 : : {
838 : 0 : aPartialName = "RadioGroup";
839 : 0 : aPartialName += OString::valueOf( static_cast<const PDFWriter::RadioButtonWidget&>(i_rControl).RadioGroup );
840 : : }
841 : : else
842 : 0 : aPartialName = OString( "Widget" );
843 : : }
844 : :
845 [ # # ]: 0 : if( ! m_aContext.AllowDuplicateFieldNames )
846 : : {
847 [ # # ]: 0 : boost::unordered_map<OString, sal_Int32, OStringHash>::iterator it = m_aFieldNameMap.find( aFullName );
848 : :
849 [ # # ][ # # ]: 0 : if( it != m_aFieldNameMap.end() ) // not unique
850 : : {
851 : 0 : boost::unordered_map< OString, sal_Int32, OStringHash >::const_iterator check_it;
852 : 0 : OString aTry;
853 : 0 : sal_Int32 nTry = 2;
854 [ # # ]: 0 : do
855 : : {
856 : 0 : OStringBuffer aUnique( aFullName.getLength() + 16 );
857 [ # # ]: 0 : aUnique.append( aFullName );
858 [ # # ]: 0 : aUnique.append( '_' );
859 [ # # ]: 0 : aUnique.append( nTry++ );
860 : 0 : aTry = aUnique.makeStringAndClear();
861 [ # # ]: 0 : check_it = m_aFieldNameMap.find( aTry );
862 [ # # ]: 0 : } while( check_it != m_aFieldNameMap.end() );
863 : 0 : aFullName = aTry;
864 [ # # ]: 0 : m_aFieldNameMap[ aFullName ] = i_nWidgetIndex;
865 : 0 : aPartialName = aFullName.copy( aFullName.lastIndexOf( '.' )+1 );
866 : : }
867 : : else
868 [ # # ]: 0 : m_aFieldNameMap[ aFullName ] = i_nWidgetIndex;
869 : : }
870 : :
871 : : // finally
872 : 0 : m_aWidgets[i_nWidgetIndex].m_aName = aPartialName;
873 : 0 : }
874 : :
875 : 0 : static void appendFixedInt( sal_Int32 nValue, OStringBuffer& rBuffer, sal_Int32 nPrecision = nLog10Divisor )
876 : : {
877 [ # # ]: 0 : if( nValue < 0 )
878 : : {
879 : 0 : rBuffer.append( '-' );
880 : 0 : nValue = -nValue;
881 : : }
882 : 0 : sal_Int32 nFactor = 1, nDiv = nPrecision;
883 [ # # ]: 0 : while( nDiv-- )
884 : 0 : nFactor *= 10;
885 : :
886 : 0 : sal_Int32 nInt = nValue / nFactor;
887 : 0 : rBuffer.append( nInt );
888 [ # # ]: 0 : if( nFactor > 1 )
889 : : {
890 : 0 : sal_Int32 nDecimal = nValue % nFactor;
891 [ # # ]: 0 : if( nDecimal )
892 : : {
893 : 0 : rBuffer.append( '.' );
894 : : // omit trailing zeros
895 [ # # ]: 0 : while( (nDecimal % 10) == 0 )
896 : 0 : nDecimal /= 10;
897 : 0 : rBuffer.append( nDecimal );
898 : : }
899 : : }
900 : 0 : }
901 : :
902 : :
903 : : // appends a double. PDF does not accept exponential format, only fixed point
904 : 0 : static void appendDouble( double fValue, OStringBuffer& rBuffer, sal_Int32 nPrecision = 5 )
905 : : {
906 : 0 : bool bNeg = false;
907 [ # # ]: 0 : if( fValue < 0.0 )
908 : : {
909 : 0 : bNeg = true;
910 : 0 : fValue=-fValue;
911 : : }
912 : :
913 : 0 : sal_Int64 nInt = (sal_Int64)fValue;
914 : 0 : fValue -= (double)nInt;
915 : : // optimizing hardware may lead to a value of 1.0 after the subtraction
916 [ # # ][ # # ]: 0 : if( fValue == 1.0 || log10( 1.0-fValue ) <= -nPrecision )
[ # # ]
917 : : {
918 : 0 : nInt++;
919 : 0 : fValue = 0.0;
920 : : }
921 : 0 : sal_Int64 nFrac = 0;
922 [ # # ]: 0 : if( fValue )
923 : : {
924 : 0 : fValue *= pow( 10.0, (double)nPrecision );
925 : 0 : nFrac = (sal_Int64)fValue;
926 : : }
927 [ # # ][ # # ]: 0 : if( bNeg && ( nInt || nFrac ) )
[ # # ]
928 : 0 : rBuffer.append( '-' );
929 : 0 : rBuffer.append( nInt );
930 [ # # ]: 0 : if( nFrac )
931 : : {
932 : : int i;
933 : 0 : rBuffer.append( '.' );
934 : 0 : sal_Int64 nBound = (sal_Int64)(pow( 10.0, nPrecision - 1.0 )+0.5);
935 [ # # ][ # # ]: 0 : for ( i = 0; ( i < nPrecision ) && nFrac; i++ )
[ # # ]
936 : : {
937 : 0 : sal_Int64 nNumb = nFrac / nBound;
938 : 0 : nFrac -= nNumb * nBound;
939 : 0 : rBuffer.append( nNumb );
940 : 0 : nBound /= 10;
941 : : }
942 : : }
943 : 0 : }
944 : :
945 : :
946 : 0 : static void appendColor( const Color& rColor, OStringBuffer& rBuffer, bool bConvertToGrey = false )
947 : : {
948 : :
949 [ # # ]: 0 : if( rColor != Color( COL_TRANSPARENT ) )
950 : : {
951 [ # # ]: 0 : if( bConvertToGrey )
952 : : {
953 : 0 : sal_uInt8 cByte = rColor.GetLuminance();
954 : 0 : appendDouble( (double)cByte / 255.0, rBuffer );
955 : : }
956 : : else
957 : : {
958 : 0 : appendDouble( (double)rColor.GetRed() / 255.0, rBuffer );
959 : 0 : rBuffer.append( ' ' );
960 : 0 : appendDouble( (double)rColor.GetGreen() / 255.0, rBuffer );
961 : 0 : rBuffer.append( ' ' );
962 : 0 : appendDouble( (double)rColor.GetBlue() / 255.0, rBuffer );
963 : : }
964 : : }
965 : 0 : }
966 : :
967 : 0 : void PDFWriterImpl::appendStrokingColor( const Color& rColor, OStringBuffer& rBuffer )
968 : : {
969 [ # # ]: 0 : if( rColor != Color( COL_TRANSPARENT ) )
970 : : {
971 : 0 : bool bGrey = m_aContext.ColorMode == PDFWriter::DrawGreyscale;
972 : 0 : appendColor( rColor, rBuffer, bGrey );
973 [ # # ][ # # ]: 0 : rBuffer.append( bGrey ? " G" : " RG" );
974 : : }
975 : 0 : }
976 : :
977 : 0 : void PDFWriterImpl::appendNonStrokingColor( const Color& rColor, OStringBuffer& rBuffer )
978 : : {
979 [ # # ]: 0 : if( rColor != Color( COL_TRANSPARENT ) )
980 : : {
981 : 0 : bool bGrey = m_aContext.ColorMode == PDFWriter::DrawGreyscale;
982 : 0 : appendColor( rColor, rBuffer, bGrey );
983 [ # # ][ # # ]: 0 : rBuffer.append( bGrey ? " g" : " rg" );
984 : : }
985 : 0 : }
986 : :
987 : : // matrix helper class
988 : : // TODO: use basegfx matrix class instead or derive from it
989 : : namespace vcl // TODO: use anonymous namespace to keep this class local
990 : : {
991 : : /* for sparse matrices of the form (2D linear transformations)
992 : : * f[0] f[1] 0
993 : : * f[2] f[3] 0
994 : : * f[4] f[5] 1
995 : : */
996 : : class Matrix3
997 : : {
998 : : double f[6];
999 : :
1000 [ # # ]: 0 : void set( double *pn ) { for( int i = 0 ; i < 6; i++ ) f[i] = pn[i]; }
1001 : : public:
1002 : : Matrix3();
1003 : 0 : ~Matrix3() {}
1004 : :
1005 : : void skew( double alpha, double beta );
1006 : : void scale( double sx, double sy );
1007 : : void rotate( double angle );
1008 : : void translate( double tx, double ty );
1009 : : bool invert();
1010 : :
1011 : : void append( PDFWriterImpl::PDFPage& rPage, OStringBuffer& rBuffer, Point* pBack = NULL );
1012 : :
1013 : : Point transform( const Point& rPoint ) const;
1014 : : };
1015 : : }
1016 : :
1017 : 0 : Matrix3::Matrix3()
1018 : : {
1019 : : // initialize to unity
1020 : 0 : f[0] = 1.0;
1021 : 0 : f[1] = 0.0;
1022 : 0 : f[2] = 0.0;
1023 : 0 : f[3] = 1.0;
1024 : 0 : f[4] = 0.0;
1025 : 0 : f[5] = 0.0;
1026 : 0 : }
1027 : :
1028 : 0 : Point Matrix3::transform( const Point& rOrig ) const
1029 : : {
1030 : 0 : double x = (double)rOrig.X(), y = (double)rOrig.Y();
1031 : 0 : return Point( (int)(x*f[0] + y*f[2] + f[4]), (int)(x*f[1] + y*f[3] + f[5]) );
1032 : : }
1033 : :
1034 : 0 : void Matrix3::skew( double alpha, double beta )
1035 : : {
1036 : : double fn[6];
1037 : 0 : double tb = tan( beta );
1038 : 0 : fn[0] = f[0] + f[2]*tb;
1039 : 0 : fn[1] = f[1];
1040 : 0 : fn[2] = f[2] + f[3]*tb;
1041 : 0 : fn[3] = f[3];
1042 : 0 : fn[4] = f[4] + f[5]*tb;
1043 : 0 : fn[5] = f[5];
1044 [ # # ]: 0 : if( alpha != 0.0 )
1045 : : {
1046 : 0 : double ta = tan( alpha );
1047 : 0 : fn[1] += f[0]*ta;
1048 : 0 : fn[3] += f[2]*ta;
1049 : 0 : fn[5] += f[4]*ta;
1050 : : }
1051 : 0 : set( fn );
1052 : 0 : }
1053 : :
1054 : 0 : void Matrix3::scale( double sx, double sy )
1055 : : {
1056 : : double fn[6];
1057 : 0 : fn[0] = sx*f[0];
1058 : 0 : fn[1] = sy*f[1];
1059 : 0 : fn[2] = sx*f[2];
1060 : 0 : fn[3] = sy*f[3];
1061 : 0 : fn[4] = sx*f[4];
1062 : 0 : fn[5] = sy*f[5];
1063 : 0 : set( fn );
1064 : 0 : }
1065 : :
1066 : 0 : void Matrix3::rotate( double angle )
1067 : : {
1068 : : double fn[6];
1069 : 0 : double fSin = sin(angle);
1070 : 0 : double fCos = cos(angle);
1071 : 0 : fn[0] = f[0]*fCos - f[1]*fSin;
1072 : 0 : fn[1] = f[0]*fSin + f[1]*fCos;
1073 : 0 : fn[2] = f[2]*fCos - f[3]*fSin;
1074 : 0 : fn[3] = f[2]*fSin + f[3]*fCos;
1075 : 0 : fn[4] = f[4]*fCos - f[5]*fSin;
1076 : 0 : fn[5] = f[4]*fSin + f[5]*fCos;
1077 : 0 : set( fn );
1078 : 0 : }
1079 : :
1080 : 0 : void Matrix3::translate( double tx, double ty )
1081 : : {
1082 : 0 : f[4] += tx;
1083 : 0 : f[5] += ty;
1084 : 0 : }
1085 : :
1086 : 0 : bool Matrix3::invert()
1087 : : {
1088 : : // short circuit trivial cases
1089 [ # # ][ # # ]: 0 : if( f[1]==f[2] && f[1]==0.0 && f[0]==f[3] && f[0]==1.0 )
[ # # ][ # # ]
1090 : : {
1091 : 0 : f[4] = -f[4];
1092 : 0 : f[5] = -f[5];
1093 : 0 : return true;
1094 : : }
1095 : :
1096 : : // check determinant
1097 : 0 : const double fDet = f[0]*f[3]-f[1]*f[2];
1098 [ # # ]: 0 : if( fDet == 0.0 )
1099 : 0 : return false;
1100 : :
1101 : : // invert the matrix
1102 : : double fn[6];
1103 : 0 : fn[0] = +f[3] / fDet;
1104 : 0 : fn[1] = -f[1] / fDet;
1105 : 0 : fn[2] = -f[2] / fDet;
1106 : 0 : fn[3] = +f[0] / fDet;
1107 : :
1108 : : // apply inversion to translation
1109 : 0 : fn[4] = -(f[4]*fn[0] + f[5]*fn[2]);
1110 : 0 : fn[5] = -(f[4]*fn[1] + f[5]*fn[3]);
1111 : :
1112 : 0 : set( fn );
1113 : 0 : return true;
1114 : : }
1115 : :
1116 : 0 : void Matrix3::append( PDFWriterImpl::PDFPage& rPage, OStringBuffer& rBuffer, Point* pBack )
1117 : : {
1118 : 0 : appendDouble( f[0], rBuffer );
1119 : 0 : rBuffer.append( ' ' );
1120 : 0 : appendDouble( f[1], rBuffer );
1121 : 0 : rBuffer.append( ' ' );
1122 : 0 : appendDouble( f[2], rBuffer );
1123 : 0 : rBuffer.append( ' ' );
1124 : 0 : appendDouble( f[3], rBuffer );
1125 : 0 : rBuffer.append( ' ' );
1126 [ # # ]: 0 : rPage.appendPoint( Point( (long)f[4], (long)f[5] ), rBuffer, false, pBack );
1127 : 0 : }
1128 : :
1129 : 0 : static void appendResourceMap( OStringBuffer& rBuf, const char* pPrefix, const PDFWriterImpl::ResourceMap& rList )
1130 : : {
1131 [ # # ]: 0 : if( rList.empty() )
1132 : 0 : return;
1133 : 0 : rBuf.append( '/' );
1134 : 0 : rBuf.append( pPrefix );
1135 : 0 : rBuf.append( "<<" );
1136 : 0 : int ni = 0;
1137 [ # # ]: 0 : for( PDFWriterImpl::ResourceMap::const_iterator it = rList.begin(); it != rList.end(); ++it )
1138 : : {
1139 [ # # ][ # # ]: 0 : if( !it->first.isEmpty() && it->second > 0 )
[ # # ]
1140 : : {
1141 [ # # ]: 0 : rBuf.append( '/' );
1142 [ # # ]: 0 : rBuf.append( it->first );
1143 [ # # ]: 0 : rBuf.append( ' ' );
1144 [ # # ]: 0 : rBuf.append( it->second );
1145 [ # # ]: 0 : rBuf.append( " 0 R" );
1146 [ # # ]: 0 : if( ((++ni) & 7) == 0 )
1147 [ # # ]: 0 : rBuf.append( '\n' );
1148 : : }
1149 : : }
1150 : 0 : rBuf.append( ">>\n" );
1151 : : }
1152 : :
1153 : 0 : void PDFWriterImpl::ResourceDict::append( OStringBuffer& rBuf, sal_Int32 nFontDictObject )
1154 : : {
1155 : 0 : rBuf.append( "<</Font " );
1156 : 0 : rBuf.append( nFontDictObject );
1157 : 0 : rBuf.append( " 0 R\n" );
1158 : 0 : appendResourceMap( rBuf, "XObject", m_aXObjects );
1159 : 0 : appendResourceMap( rBuf, "ExtGState", m_aExtGStates );
1160 : 0 : appendResourceMap( rBuf, "Shading", m_aShadings );
1161 : 0 : appendResourceMap( rBuf, "Pattern", m_aPatterns );
1162 : 0 : rBuf.append( "/ProcSet[/PDF/Text" );
1163 [ # # ]: 0 : if( !m_aXObjects.empty() )
1164 : 0 : rBuf.append( "/ImageC/ImageI/ImageB" );
1165 : 0 : rBuf.append( "]\n>>\n" );
1166 : 0 : };
1167 : :
1168 : 0 : PDFWriterImpl::PDFPage::PDFPage( PDFWriterImpl* pWriter, sal_Int32 nPageWidth, sal_Int32 nPageHeight, PDFWriter::Orientation eOrientation )
1169 : : :
1170 : : m_pWriter( pWriter ),
1171 : : m_nPageWidth( nPageWidth ),
1172 : : m_nPageHeight( nPageHeight ),
1173 : : m_eOrientation( eOrientation ),
1174 : : m_nPageObject( 0 ), // invalid object number
1175 : : m_nPageIndex( -1 ), // invalid index
1176 : : m_nStreamLengthObject( 0 ),
1177 : : m_nBeginStreamPos( 0 ),
1178 : : m_eTransition( PDFWriter::Regular ),
1179 : : m_nTransTime( 0 ),
1180 : : m_nDuration( 0 ),
1181 [ # # ][ # # ]: 0 : m_bHasWidgets( false )
1182 : : {
1183 : : // object ref must be only ever updated in emit()
1184 [ # # ]: 0 : m_nPageObject = m_pWriter->createObject();
1185 : 0 : }
1186 : :
1187 : 0 : PDFWriterImpl::PDFPage::~PDFPage()
1188 : : {
1189 : 0 : }
1190 : :
1191 : 0 : void PDFWriterImpl::PDFPage::beginStream()
1192 : : {
1193 : : #if OSL_DEBUG_LEVEL > 1
1194 : : {
1195 : : OStringBuffer aLine( "PDFWriterImpl::PDFPage::beginStream, +" );
1196 : : m_pWriter->emitComment( aLine.getStr() );
1197 : : }
1198 : : #endif
1199 [ # # ][ # # ]: 0 : m_aStreamObjects.push_back(m_pWriter->createObject());
1200 [ # # ][ # # ]: 0 : if( ! m_pWriter->updateObject( m_aStreamObjects.back() ) )
[ # # ]
1201 : : return;
1202 : :
1203 [ # # ]: 0 : m_nStreamLengthObject = m_pWriter->createObject();
1204 : : // write content stream header
1205 : 0 : OStringBuffer aLine;
1206 [ # # ][ # # ]: 0 : aLine.append( m_aStreamObjects.back() );
1207 [ # # ]: 0 : aLine.append( " 0 obj\n<</Length " );
1208 [ # # ]: 0 : aLine.append( m_nStreamLengthObject );
1209 [ # # ]: 0 : aLine.append( " 0 R" );
1210 : : #if defined ( COMPRESS_PAGES ) && !defined ( DEBUG_DISABLE_PDFCOMPRESSION )
1211 [ # # ]: 0 : aLine.append( "/Filter/FlateDecode" );
1212 : : #endif
1213 [ # # ]: 0 : aLine.append( ">>\nstream\n" );
1214 [ # # ][ # # ]: 0 : if( ! m_pWriter->writeBuffer( aLine.getStr(), aLine.getLength() ) )
1215 : : return;
1216 [ # # ][ # # ]: 0 : if( osl_File_E_None != osl_getFilePos( m_pWriter->m_aFile, &m_nBeginStreamPos ) )
1217 : : {
1218 [ # # ]: 0 : osl_closeFile( m_pWriter->m_aFile );
1219 : 0 : m_pWriter->m_bOpen = false;
1220 : : }
1221 : : #if defined ( COMPRESS_PAGES ) && !defined ( DEBUG_DISABLE_PDFCOMPRESSION )
1222 [ # # ]: 0 : m_pWriter->beginCompression();
1223 : : #endif
1224 [ # # ][ # # ]: 0 : m_pWriter->checkAndEnableStreamEncryption( m_aStreamObjects.back() );
[ # # ]
1225 : : }
1226 : :
1227 : 0 : void PDFWriterImpl::PDFPage::endStream()
1228 : : {
1229 : : #if defined ( COMPRESS_PAGES ) && !defined ( DEBUG_DISABLE_PDFCOMPRESSION )
1230 [ # # ]: 0 : m_pWriter->endCompression();
1231 : : #endif
1232 : : sal_uInt64 nEndStreamPos;
1233 [ # # ][ # # ]: 0 : if( osl_File_E_None != osl_getFilePos( m_pWriter->m_aFile, &nEndStreamPos ) )
1234 : : {
1235 [ # # ]: 0 : osl_closeFile( m_pWriter->m_aFile );
1236 : 0 : m_pWriter->m_bOpen = false;
1237 : : return;
1238 : : }
1239 : 0 : m_pWriter->disableStreamEncryption();
1240 [ # # ][ # # ]: 0 : if( ! m_pWriter->writeBuffer( "\nendstream\nendobj\n\n", 19 ) )
1241 : : return;
1242 : : // emit stream length object
1243 [ # # ][ # # ]: 0 : if( ! m_pWriter->updateObject( m_nStreamLengthObject ) )
1244 : : return;
1245 : 0 : OStringBuffer aLine;
1246 [ # # ]: 0 : aLine.append( m_nStreamLengthObject );
1247 [ # # ]: 0 : aLine.append( " 0 obj\n" );
1248 [ # # ]: 0 : aLine.append( (sal_Int64)(nEndStreamPos-m_nBeginStreamPos) );
1249 [ # # ]: 0 : aLine.append( "\nendobj\n\n" );
1250 [ # # ]: 0 : m_pWriter->writeBuffer( aLine.getStr(), aLine.getLength() );
1251 : : }
1252 : :
1253 : 0 : bool PDFWriterImpl::PDFPage::emit(sal_Int32 nParentObject )
1254 : : {
1255 : : // emit page object
1256 [ # # ][ # # ]: 0 : if( ! m_pWriter->updateObject( m_nPageObject ) )
1257 : 0 : return false;
1258 : 0 : OStringBuffer aLine;
1259 : :
1260 [ # # ]: 0 : aLine.append( m_nPageObject );
1261 : : aLine.append( " 0 obj\n"
1262 [ # # ]: 0 : "<</Type/Page/Parent " );
1263 [ # # ]: 0 : aLine.append( nParentObject );
1264 [ # # ]: 0 : aLine.append( " 0 R" );
1265 [ # # ]: 0 : aLine.append( "/Resources " );
1266 [ # # ][ # # ]: 0 : aLine.append( m_pWriter->getResourceDictObj() );
1267 [ # # ]: 0 : aLine.append( " 0 R" );
1268 [ # # ][ # # ]: 0 : if( m_nPageWidth && m_nPageHeight )
1269 : : {
1270 [ # # ]: 0 : aLine.append( "/MediaBox[0 0 " );
1271 [ # # ]: 0 : aLine.append( m_nPageWidth );
1272 [ # # ]: 0 : aLine.append( ' ' );
1273 [ # # ]: 0 : aLine.append( m_nPageHeight );
1274 [ # # ]: 0 : aLine.append( "]" );
1275 : : }
1276 [ # # # # ]: 0 : switch( m_eOrientation )
1277 : : {
1278 [ # # ]: 0 : case PDFWriter::Landscape: aLine.append( "/Rotate 90\n" );break;
1279 [ # # ]: 0 : case PDFWriter::Seascape: aLine.append( "/Rotate -90\n" );break;
1280 [ # # ]: 0 : case PDFWriter::Portrait: aLine.append( "/Rotate 0\n" );break;
1281 : :
1282 : : case PDFWriter::Inherit:
1283 : : default:
1284 : 0 : break;
1285 : : }
1286 : 0 : int nAnnots = m_aAnnotations.size();
1287 [ # # ]: 0 : if( nAnnots > 0 )
1288 : : {
1289 [ # # ]: 0 : aLine.append( "/Annots[\n" );
1290 [ # # ]: 0 : for( int i = 0; i < nAnnots; i++ )
1291 : : {
1292 [ # # ][ # # ]: 0 : aLine.append( m_aAnnotations[i] );
1293 [ # # ]: 0 : aLine.append( " 0 R" );
1294 [ # # ][ # # ]: 0 : aLine.append( ((i+1)%15) ? " " : "\n" );
1295 : : }
1296 [ # # ]: 0 : aLine.append( "]\n" );
1297 : : }
1298 [ # # ]: 0 : if( m_aMCIDParents.size() > 0 )
1299 : : {
1300 : 0 : OStringBuffer aStructParents( 1024 );
1301 [ # # ]: 0 : aStructParents.append( "[ " );
1302 : 0 : int nParents = m_aMCIDParents.size();
1303 [ # # ]: 0 : for( int i = 0; i < nParents; i++ )
1304 : : {
1305 [ # # ][ # # ]: 0 : aStructParents.append( m_aMCIDParents[i] );
1306 [ # # ]: 0 : aStructParents.append( " 0 R" );
1307 [ # # ][ # # ]: 0 : aStructParents.append( ((i%10) == 9) ? "\n" : " " );
1308 : : }
1309 [ # # ]: 0 : aStructParents.append( "]" );
1310 [ # # ]: 0 : m_pWriter->m_aStructParentTree.push_back( aStructParents.makeStringAndClear() );
1311 : :
1312 [ # # ]: 0 : aLine.append( "/StructParents " );
1313 [ # # ]: 0 : aLine.append( sal_Int32(m_pWriter->m_aStructParentTree.size()-1) );
1314 [ # # ]: 0 : aLine.append( "\n" );
1315 : : }
1316 [ # # ]: 0 : if( m_nDuration > 0 )
1317 : : {
1318 [ # # ]: 0 : aLine.append( "/Dur " );
1319 [ # # ]: 0 : aLine.append( (sal_Int32)m_nDuration );
1320 [ # # ]: 0 : aLine.append( "\n" );
1321 : : }
1322 [ # # ][ # # ]: 0 : if( m_eTransition != PDFWriter::Regular && m_nTransTime > 0 )
1323 : : {
1324 : : // transition duration
1325 [ # # ]: 0 : aLine.append( "/Trans<</D " );
1326 [ # # ]: 0 : appendDouble( (double)m_nTransTime/1000.0, aLine, 3 );
1327 [ # # ]: 0 : aLine.append( "\n" );
1328 : 0 : const char *pStyle = NULL, *pDm = NULL, *pM = NULL, *pDi = NULL;
1329 [ # # # # : 0 : switch( m_eTransition )
# # # # #
# # # # #
# # # # ]
1330 : : {
1331 : : case PDFWriter::SplitHorizontalInward:
1332 : 0 : pStyle = "Split"; pDm = "H"; pM = "I"; break;
1333 : : case PDFWriter::SplitHorizontalOutward:
1334 : 0 : pStyle = "Split"; pDm = "H"; pM = "O"; break;
1335 : : case PDFWriter::SplitVerticalInward:
1336 : 0 : pStyle = "Split"; pDm = "V"; pM = "I"; break;
1337 : : case PDFWriter::SplitVerticalOutward:
1338 : 0 : pStyle = "Split"; pDm = "V"; pM = "O"; break;
1339 : : case PDFWriter::BlindsHorizontal:
1340 : 0 : pStyle = "Blinds"; pDm = "H"; break;
1341 : : case PDFWriter::BlindsVertical:
1342 : 0 : pStyle = "Blinds"; pDm = "V"; break;
1343 : : case PDFWriter::BoxInward:
1344 : 0 : pStyle = "Box"; pM = "I"; break;
1345 : : case PDFWriter::BoxOutward:
1346 : 0 : pStyle = "Box"; pM = "O"; break;
1347 : : case PDFWriter::WipeLeftToRight:
1348 : 0 : pStyle = "Wipe"; pDi = "0"; break;
1349 : : case PDFWriter::WipeBottomToTop:
1350 : 0 : pStyle = "Wipe"; pDi = "90"; break;
1351 : : case PDFWriter::WipeRightToLeft:
1352 : 0 : pStyle = "Wipe"; pDi = "180"; break;
1353 : : case PDFWriter::WipeTopToBottom:
1354 : 0 : pStyle = "Wipe"; pDi = "270"; break;
1355 : : case PDFWriter::Dissolve:
1356 : 0 : pStyle = "Dissolve"; break;
1357 : : case PDFWriter::GlitterLeftToRight:
1358 : 0 : pStyle = "Glitter"; pDi = "0"; break;
1359 : : case PDFWriter::GlitterTopToBottom:
1360 : 0 : pStyle = "Glitter"; pDi = "270"; break;
1361 : : case PDFWriter::GlitterTopLeftToBottomRight:
1362 : 0 : pStyle = "Glitter"; pDi = "315"; break;
1363 : : case PDFWriter::Regular:
1364 : 0 : break;
1365 : : }
1366 : : // transition style
1367 [ # # ]: 0 : if( pStyle )
1368 : : {
1369 [ # # ]: 0 : aLine.append( "/S/" );
1370 [ # # ]: 0 : aLine.append( pStyle );
1371 [ # # ]: 0 : aLine.append( "\n" );
1372 : : }
1373 [ # # ]: 0 : if( pDm )
1374 : : {
1375 [ # # ]: 0 : aLine.append( "/Dm/" );
1376 [ # # ]: 0 : aLine.append( pDm );
1377 [ # # ]: 0 : aLine.append( "\n" );
1378 : : }
1379 [ # # ]: 0 : if( pM )
1380 : : {
1381 [ # # ]: 0 : aLine.append( "/M/" );
1382 [ # # ]: 0 : aLine.append( pM );
1383 [ # # ]: 0 : aLine.append( "\n" );
1384 : : }
1385 [ # # ]: 0 : if( pDi )
1386 : : {
1387 [ # # ]: 0 : aLine.append( "/Di " );
1388 [ # # ]: 0 : aLine.append( pDi );
1389 [ # # ]: 0 : aLine.append( "\n" );
1390 : : }
1391 [ # # ]: 0 : aLine.append( ">>\n" );
1392 : : }
1393 [ # # ][ # # ]: 0 : if( m_pWriter->getVersion() > PDFWriter::PDF_1_3 && ! m_pWriter->m_bIsPDF_A1 )
[ # # ]
1394 : : {
1395 [ # # ]: 0 : aLine.append( "/Group<</S/Transparency/CS/DeviceRGB/I true>>" );
1396 : : }
1397 [ # # ]: 0 : aLine.append( "/Contents" );
1398 : 0 : unsigned int nStreamObjects = m_aStreamObjects.size();
1399 [ # # ]: 0 : if( nStreamObjects > 1 )
1400 [ # # ]: 0 : aLine.append( '[' );
1401 [ # # ]: 0 : for( unsigned int i = 0; i < m_aStreamObjects.size(); i++ )
1402 : : {
1403 [ # # ]: 0 : aLine.append( ' ' );
1404 [ # # ][ # # ]: 0 : aLine.append( m_aStreamObjects[i] );
1405 [ # # ]: 0 : aLine.append( " 0 R" );
1406 : : }
1407 [ # # ]: 0 : if( nStreamObjects > 1 )
1408 [ # # ]: 0 : aLine.append( ']' );
1409 [ # # ]: 0 : aLine.append( ">>\nendobj\n\n" );
1410 [ # # ]: 0 : return m_pWriter->writeBuffer( aLine.getStr(), aLine.getLength() );
1411 : : }
1412 : :
1413 : : namespace vcl
1414 : : {
1415 : : template < class GEOMETRY >
1416 : 0 : GEOMETRY lcl_convert( const MapMode& _rSource, const MapMode& _rDest, OutputDevice* _pPixelConversion, const GEOMETRY& _rObject )
1417 : : {
1418 : 0 : GEOMETRY aPoint;
1419 [ # # # # : 0 : if ( MAP_PIXEL == _rSource.GetMapUnit() )
# # # # ]
1420 : : {
1421 [ # # ][ # # ]: 0 : aPoint = _pPixelConversion->PixelToLogic( _rObject, _rDest );
[ # # ]
1422 : : }
1423 : : else
1424 : : {
1425 [ # # ][ # # ]: 0 : aPoint = OutputDevice::LogicToLogic( _rObject, _rSource, _rDest );
[ # # ]
1426 : : }
1427 : 0 : return aPoint;
1428 : : }
1429 : : }
1430 : :
1431 : 0 : void PDFWriterImpl::PDFPage::appendPoint( const Point& rPoint, OStringBuffer& rBuffer, bool bNeg, Point* pOutPoint ) const
1432 : : {
1433 [ # # ]: 0 : if( pOutPoint )
1434 : : {
1435 [ # # ]: 0 : Point aPoint( lcl_convert( m_pWriter->m_aGraphicsStack.front().m_aMapMode,
1436 : : m_pWriter->m_aMapMode,
1437 : : m_pWriter->getReferenceDevice(),
1438 [ # # ][ # # ]: 0 : rPoint ) );
1439 : 0 : *pOutPoint = aPoint;
1440 : : }
1441 : :
1442 [ # # ]: 0 : Point aPoint( lcl_convert( m_pWriter->m_aGraphicsStack.front().m_aMapMode,
1443 : : m_pWriter->m_aMapMode,
1444 : : m_pWriter->getReferenceDevice(),
1445 [ # # ][ # # ]: 0 : rPoint ) );
1446 : :
1447 : 0 : sal_Int32 nValue = aPoint.X();
1448 [ # # ]: 0 : if( bNeg )
1449 : 0 : nValue = -nValue;
1450 : :
1451 [ # # ]: 0 : appendFixedInt( nValue, rBuffer );
1452 : :
1453 [ # # ]: 0 : rBuffer.append( ' ' );
1454 : :
1455 : 0 : nValue = pointToPixel(getHeight()) - aPoint.Y();
1456 [ # # ]: 0 : if( bNeg )
1457 : 0 : nValue = -nValue;
1458 : :
1459 [ # # ]: 0 : appendFixedInt( nValue, rBuffer );
1460 : 0 : }
1461 : :
1462 : 0 : void PDFWriterImpl::PDFPage::appendPixelPoint( const basegfx::B2DPoint& rPoint, OStringBuffer& rBuffer ) const
1463 : : {
1464 : 0 : double fValue = pixelToPoint(rPoint.getX());
1465 : :
1466 : 0 : appendDouble( fValue, rBuffer, nLog10Divisor );
1467 : :
1468 : 0 : rBuffer.append( ' ' );
1469 : :
1470 : 0 : fValue = double(getHeight()) - pixelToPoint(rPoint.getY());
1471 : :
1472 : 0 : appendDouble( fValue, rBuffer, nLog10Divisor );
1473 : 0 : }
1474 : :
1475 : 0 : void PDFWriterImpl::PDFPage::appendRect( const Rectangle& rRect, OStringBuffer& rBuffer ) const
1476 : : {
1477 [ # # ][ # # ]: 0 : appendPoint( rRect.BottomLeft() + Point( 0, 1 ), rBuffer );
1478 : 0 : rBuffer.append( ' ' );
1479 : 0 : appendMappedLength( (sal_Int32)rRect.GetWidth(), rBuffer, false );
1480 : 0 : rBuffer.append( ' ' );
1481 : 0 : appendMappedLength( (sal_Int32)rRect.GetHeight(), rBuffer, true );
1482 : 0 : rBuffer.append( " re" );
1483 : 0 : }
1484 : :
1485 : 0 : void PDFWriterImpl::PDFPage::convertRect( Rectangle& rRect ) const
1486 : : {
1487 [ # # ]: 0 : Point aLL = lcl_convert( m_pWriter->m_aGraphicsStack.front().m_aMapMode,
1488 : : m_pWriter->m_aMapMode,
1489 : : m_pWriter->getReferenceDevice(),
1490 [ # # ]: 0 : rRect.BottomLeft() + Point( 0, 1 )
1491 [ # # ][ # # ]: 0 : );
1492 [ # # ]: 0 : Size aSize = lcl_convert( m_pWriter->m_aGraphicsStack.front().m_aMapMode,
1493 : : m_pWriter->m_aMapMode,
1494 : : m_pWriter->getReferenceDevice(),
1495 [ # # ][ # # ]: 0 : rRect.GetSize() );
[ # # ]
1496 : 0 : rRect.Left() = aLL.X();
1497 : 0 : rRect.Right() = aLL.X() + aSize.Width();
1498 : 0 : rRect.Top() = pointToPixel(getHeight()) - aLL.Y();
1499 : 0 : rRect.Bottom() = rRect.Top() + aSize.Height();
1500 : 0 : }
1501 : :
1502 : 0 : void PDFWriterImpl::PDFPage::appendPolygon( const Polygon& rPoly, OStringBuffer& rBuffer, bool bClose ) const
1503 : : {
1504 : 0 : sal_uInt16 nPoints = rPoly.GetSize();
1505 : : /*
1506 : : * #108582# applications do weird things
1507 : : */
1508 : 0 : sal_uInt32 nBufLen = rBuffer.getLength();
1509 [ # # ]: 0 : if( nPoints > 0 )
1510 : : {
1511 : 0 : const sal_uInt8* pFlagArray = rPoly.GetConstFlagAry();
1512 : 0 : appendPoint( rPoly[0], rBuffer );
1513 : 0 : rBuffer.append( " m\n" );
1514 [ # # ]: 0 : for( sal_uInt16 i = 1; i < nPoints; i++ )
1515 : : {
1516 [ # # ][ # # ]: 0 : if( pFlagArray && pFlagArray[i] == POLY_CONTROL && nPoints-i > 2 )
[ # # ]
1517 : : {
1518 : : // bezier
1519 : : DBG_ASSERT( pFlagArray[i+1] == POLY_CONTROL && pFlagArray[i+2] != POLY_CONTROL, "unexpected sequence of control points" );
1520 : 0 : appendPoint( rPoly[i], rBuffer );
1521 : 0 : rBuffer.append( " " );
1522 : 0 : appendPoint( rPoly[i+1], rBuffer );
1523 : 0 : rBuffer.append( " " );
1524 : 0 : appendPoint( rPoly[i+2], rBuffer );
1525 : 0 : rBuffer.append( " c" );
1526 : 0 : i += 2; // add additionally consumed points
1527 : : }
1528 : : else
1529 : : {
1530 : : // line
1531 : 0 : appendPoint( rPoly[i], rBuffer );
1532 : 0 : rBuffer.append( " l" );
1533 : : }
1534 [ # # ]: 0 : if( (rBuffer.getLength() - nBufLen) > 65 )
1535 : : {
1536 : 0 : rBuffer.append( "\n" );
1537 : 0 : nBufLen = rBuffer.getLength();
1538 : : }
1539 : : else
1540 : 0 : rBuffer.append( " " );
1541 : : }
1542 [ # # ]: 0 : if( bClose )
1543 : 0 : rBuffer.append( "h\n" );
1544 : : }
1545 : 0 : }
1546 : :
1547 : 0 : void PDFWriterImpl::PDFPage::appendPolygon( const basegfx::B2DPolygon& rPoly, OStringBuffer& rBuffer, bool bClose ) const
1548 : : {
1549 [ # # ]: 0 : basegfx::B2DPolygon aPoly( lcl_convert( m_pWriter->m_aGraphicsStack.front().m_aMapMode,
1550 : : m_pWriter->m_aMapMode,
1551 : : m_pWriter->getReferenceDevice(),
1552 [ # # ][ # # ]: 0 : rPoly ) );
1553 : :
1554 [ # # ][ # # ]: 0 : if( basegfx::tools::isRectangle( aPoly ) )
1555 : : {
1556 [ # # ]: 0 : basegfx::B2DRange aRange( aPoly.getB2DRange() );
1557 [ # # ][ # # ]: 0 : basegfx::B2DPoint aBL( aRange.getMinX(), aRange.getMaxY() );
1558 [ # # ]: 0 : appendPixelPoint( aBL, rBuffer );
1559 [ # # ]: 0 : rBuffer.append( ' ' );
1560 [ # # ][ # # ]: 0 : appendMappedLength( aRange.getWidth(), rBuffer, false, NULL, nLog10Divisor );
1561 [ # # ]: 0 : rBuffer.append( ' ' );
1562 [ # # ][ # # ]: 0 : appendMappedLength( aRange.getHeight(), rBuffer, true, NULL, nLog10Divisor );
1563 [ # # ]: 0 : rBuffer.append( " re\n" );
1564 : 0 : return;
1565 : : }
1566 [ # # ]: 0 : sal_uInt32 nPoints = aPoly.count();
1567 [ # # ]: 0 : if( nPoints > 0 )
1568 : : {
1569 : 0 : sal_uInt32 nBufLen = rBuffer.getLength();
1570 [ # # ]: 0 : basegfx::B2DPoint aLastPoint( aPoly.getB2DPoint( 0 ) );
1571 [ # # ]: 0 : appendPixelPoint( aLastPoint, rBuffer );
1572 [ # # ]: 0 : rBuffer.append( " m\n" );
1573 [ # # ]: 0 : for( sal_uInt32 i = 1; i <= nPoints; i++ )
1574 : : {
1575 [ # # ][ # # ]: 0 : if( i != nPoints || aPoly.isClosed() )
[ # # ][ # # ]
1576 : : {
1577 : 0 : sal_uInt32 nCurPoint = i % nPoints;
1578 : 0 : sal_uInt32 nLastPoint = i-1;
1579 [ # # ]: 0 : basegfx::B2DPoint aPoint( aPoly.getB2DPoint( nCurPoint ) );
1580 [ # # ][ # # ]: 0 : if( aPoly.isNextControlPointUsed( nLastPoint ) &&
[ # # ][ # # ]
1581 [ # # ]: 0 : aPoly.isPrevControlPointUsed( nCurPoint ) )
1582 : : {
1583 [ # # ][ # # ]: 0 : appendPixelPoint( aPoly.getNextControlPoint( nLastPoint ), rBuffer );
1584 [ # # ]: 0 : rBuffer.append( ' ' );
1585 [ # # ][ # # ]: 0 : appendPixelPoint( aPoly.getPrevControlPoint( nCurPoint ), rBuffer );
1586 [ # # ]: 0 : rBuffer.append( ' ' );
1587 [ # # ]: 0 : appendPixelPoint( aPoint, rBuffer );
1588 [ # # ]: 0 : rBuffer.append( " c" );
1589 : : }
1590 [ # # ][ # # ]: 0 : else if( aPoly.isNextControlPointUsed( nLastPoint ) )
1591 : : {
1592 [ # # ][ # # ]: 0 : appendPixelPoint( aPoly.getNextControlPoint( nLastPoint ), rBuffer );
1593 [ # # ]: 0 : rBuffer.append( ' ' );
1594 [ # # ]: 0 : appendPixelPoint( aPoint, rBuffer );
1595 [ # # ]: 0 : rBuffer.append( " y" );
1596 : : }
1597 [ # # ][ # # ]: 0 : else if( aPoly.isPrevControlPointUsed( nCurPoint ) )
1598 : : {
1599 [ # # ][ # # ]: 0 : appendPixelPoint( aPoly.getPrevControlPoint( nCurPoint ), rBuffer );
1600 [ # # ]: 0 : rBuffer.append( ' ' );
1601 [ # # ]: 0 : appendPixelPoint( aPoint, rBuffer );
1602 [ # # ]: 0 : rBuffer.append( " v" );
1603 : : }
1604 : : else
1605 : : {
1606 [ # # ]: 0 : appendPixelPoint( aPoint, rBuffer );
1607 [ # # ]: 0 : rBuffer.append( " l" );
1608 : : }
1609 [ # # ]: 0 : if( (rBuffer.getLength() - nBufLen) > 65 )
1610 : : {
1611 [ # # ]: 0 : rBuffer.append( "\n" );
1612 : 0 : nBufLen = rBuffer.getLength();
1613 : : }
1614 : : else
1615 [ # # ]: 0 : rBuffer.append( " " );
1616 : : }
1617 : : }
1618 [ # # ]: 0 : if( bClose )
1619 [ # # ]: 0 : rBuffer.append( "h\n" );
1620 [ # # ][ # # ]: 0 : }
1621 : : }
1622 : :
1623 : 0 : void PDFWriterImpl::PDFPage::appendPolyPolygon( const PolyPolygon& rPolyPoly, OStringBuffer& rBuffer, bool bClose ) const
1624 : : {
1625 : 0 : sal_uInt16 nPolygons = rPolyPoly.Count();
1626 [ # # ]: 0 : for( sal_uInt16 n = 0; n < nPolygons; n++ )
1627 : 0 : appendPolygon( rPolyPoly[n], rBuffer, bClose );
1628 : 0 : }
1629 : :
1630 : 0 : void PDFWriterImpl::PDFPage::appendPolyPolygon( const basegfx::B2DPolyPolygon& rPolyPoly, OStringBuffer& rBuffer, bool bClose ) const
1631 : : {
1632 : 0 : sal_uInt32 nPolygons = rPolyPoly.count();
1633 [ # # ]: 0 : for( sal_uInt32 n = 0; n < nPolygons; n++ )
1634 [ # # ]: 0 : appendPolygon( rPolyPoly.getB2DPolygon( n ), rBuffer, bClose );
1635 : 0 : }
1636 : :
1637 : 0 : void PDFWriterImpl::PDFPage::appendMappedLength( sal_Int32 nLength, OStringBuffer& rBuffer, bool bVertical, sal_Int32* pOutLength ) const
1638 : : {
1639 : 0 : sal_Int32 nValue = nLength;
1640 [ # # ]: 0 : if ( nLength < 0 )
1641 : : {
1642 [ # # ]: 0 : rBuffer.append( '-' );
1643 : 0 : nValue = -nLength;
1644 : : }
1645 [ # # ]: 0 : Size aSize( lcl_convert( m_pWriter->m_aGraphicsStack.front().m_aMapMode,
1646 : : m_pWriter->m_aMapMode,
1647 : : m_pWriter->getReferenceDevice(),
1648 [ # # ][ # # ]: 0 : Size( nValue, nValue ) ) );
1649 [ # # ]: 0 : nValue = bVertical ? aSize.Height() : aSize.Width();
1650 [ # # ]: 0 : if( pOutLength )
1651 [ # # ]: 0 : *pOutLength = ((nLength < 0 ) ? -nValue : nValue);
1652 : :
1653 [ # # ]: 0 : appendFixedInt( nValue, rBuffer, 1 );
1654 : 0 : }
1655 : :
1656 : 0 : void PDFWriterImpl::PDFPage::appendMappedLength( double fLength, OStringBuffer& rBuffer, bool bVertical, sal_Int32* pOutLength, sal_Int32 nPrecision ) const
1657 : : {
1658 [ # # ]: 0 : Size aSize( lcl_convert( m_pWriter->m_aGraphicsStack.front().m_aMapMode,
1659 : : m_pWriter->m_aMapMode,
1660 : : m_pWriter->getReferenceDevice(),
1661 [ # # ][ # # ]: 0 : Size( 1000, 1000 ) ) );
1662 [ # # ]: 0 : if( pOutLength )
1663 [ # # ]: 0 : *pOutLength = (sal_Int32)(fLength*(double)(bVertical ? aSize.Height() : aSize.Width())/1000.0);
1664 [ # # ]: 0 : fLength *= pixelToPoint((double)(bVertical ? aSize.Height() : aSize.Width()) / 1000.0);
1665 [ # # ]: 0 : appendDouble( fLength, rBuffer, nPrecision );
1666 : 0 : }
1667 : :
1668 : 0 : bool PDFWriterImpl::PDFPage::appendLineInfo( const LineInfo& rInfo, OStringBuffer& rBuffer ) const
1669 : : {
1670 : 0 : bool bRet = true;
1671 [ # # ]: 0 : if( rInfo.GetStyle() == LINE_DASH )
1672 : : {
1673 : 0 : rBuffer.append( "[ " );
1674 [ # # ]: 0 : if( rInfo.GetDashLen() == rInfo.GetDotLen() ) // degraded case
1675 : : {
1676 : 0 : appendMappedLength( (sal_Int32)rInfo.GetDashLen(), rBuffer );
1677 : 0 : rBuffer.append( ' ' );
1678 : 0 : appendMappedLength( (sal_Int32)rInfo.GetDistance(), rBuffer );
1679 : 0 : rBuffer.append( ' ' );
1680 : : }
1681 : : else
1682 : : {
1683 : : // check for implementation limits of dash array
1684 : : // in PDF reader apps (e.g. acroread)
1685 [ # # ]: 0 : if( 2*(rInfo.GetDashCount() + rInfo.GetDotCount()) > 10 )
1686 : 0 : bRet = false;
1687 [ # # ]: 0 : for( int n = 0; n < rInfo.GetDashCount(); n++ )
1688 : : {
1689 : 0 : appendMappedLength( (sal_Int32)rInfo.GetDashLen(), rBuffer );
1690 : 0 : rBuffer.append( ' ' );
1691 : 0 : appendMappedLength( (sal_Int32)rInfo.GetDistance(), rBuffer );
1692 : 0 : rBuffer.append( ' ' );
1693 : : }
1694 [ # # ]: 0 : for( int m = 0; m < rInfo.GetDotCount(); m++ )
1695 : : {
1696 : 0 : appendMappedLength( (sal_Int32)rInfo.GetDotLen(), rBuffer );
1697 : 0 : rBuffer.append( ' ' );
1698 : 0 : appendMappedLength( (sal_Int32)rInfo.GetDistance(), rBuffer );
1699 : 0 : rBuffer.append( ' ' );
1700 : : }
1701 : : }
1702 : 0 : rBuffer.append( "] 0 d\n" );
1703 : : }
1704 [ # # ]: 0 : if( rInfo.GetWidth() > 1 )
1705 : : {
1706 : 0 : appendMappedLength( (sal_Int32)rInfo.GetWidth(), rBuffer );
1707 : 0 : rBuffer.append( " w\n" );
1708 : : }
1709 [ # # ]: 0 : else if( rInfo.GetWidth() == 0 )
1710 : : {
1711 : : // "pixel" line
1712 : 0 : appendDouble( 72.0/double(m_pWriter->getReferenceDevice()->ImplGetDPIX()), rBuffer );
1713 : 0 : rBuffer.append( " w\n" );
1714 : : }
1715 : 0 : return bRet;
1716 : : }
1717 : :
1718 : 0 : void PDFWriterImpl::PDFPage::appendWaveLine( sal_Int32 nWidth, sal_Int32 nY, sal_Int32 nDelta, OStringBuffer& rBuffer ) const
1719 : : {
1720 [ # # ]: 0 : if( nWidth <= 0 )
1721 : 0 : return;
1722 [ # # ]: 0 : if( nDelta < 1 )
1723 : 0 : nDelta = 1;
1724 : :
1725 : 0 : rBuffer.append( "0 " );
1726 : 0 : appendMappedLength( nY, rBuffer, true );
1727 : 0 : rBuffer.append( " m\n" );
1728 [ # # ]: 0 : for( sal_Int32 n = 0; n < nWidth; )
1729 : : {
1730 : 0 : n += nDelta;
1731 : 0 : appendMappedLength( n, rBuffer, false );
1732 : 0 : rBuffer.append( ' ' );
1733 : 0 : appendMappedLength( nDelta+nY, rBuffer, true );
1734 : 0 : rBuffer.append( ' ' );
1735 : 0 : n += nDelta;
1736 : 0 : appendMappedLength( n, rBuffer, false );
1737 : 0 : rBuffer.append( ' ' );
1738 : 0 : appendMappedLength( nY, rBuffer, true );
1739 : 0 : rBuffer.append( " v " );
1740 [ # # ]: 0 : if( n < nWidth )
1741 : : {
1742 : 0 : n += nDelta;
1743 : 0 : appendMappedLength( n, rBuffer, false );
1744 : 0 : rBuffer.append( ' ' );
1745 : 0 : appendMappedLength( nY-nDelta, rBuffer, true );
1746 : 0 : rBuffer.append( ' ' );
1747 : 0 : n += nDelta;
1748 : 0 : appendMappedLength( n, rBuffer, false );
1749 : 0 : rBuffer.append( ' ' );
1750 : 0 : appendMappedLength( nY, rBuffer, true );
1751 : 0 : rBuffer.append( " v\n" );
1752 : : }
1753 : : }
1754 : 0 : rBuffer.append( "S\n" );
1755 : : }
1756 : :
1757 : : /*
1758 : : * class PDFWriterImpl
1759 : : */
1760 : :
1761 : 0 : PDFWriterImpl::PDFWriterImpl( const PDFWriter::PDFWriterContext& rContext,
1762 : : const com::sun::star::uno::Reference< com::sun::star::beans::XMaterialHolder >& xEnc,
1763 : : PDFWriter& i_rOuterFace)
1764 : : :
1765 : : m_pReferenceDevice( NULL ),
1766 : : m_aMapMode( MAP_POINT, Point(), Fraction( 1L, pointToPixel(1) ), Fraction( 1L, pointToPixel(1) ) ),
1767 : : m_nCurrentStructElement( 0 ),
1768 : : m_bEmitStructure( true ),
1769 : : m_bNewMCID( false ),
1770 : : m_bEmbedStandardFonts( false ),
1771 : : m_nNextFID( 1 ),
1772 : : m_nInheritedPageWidth( 595 ), // default A4
1773 : : m_nInheritedPageHeight( 842 ), // default A4
1774 : : m_eInheritedOrientation( PDFWriter::Portrait ),
1775 : : m_nCurrentPage( -1 ),
1776 : : m_nSignatureObject( -1 ),
1777 : : m_nSignatureContentOffset( 0 ),
1778 : : m_nSignatureLastByteRangeNoOffset( 0 ),
1779 : : m_nResourceDict( -1 ),
1780 : : m_nFontDictObject( -1 ),
1781 : : m_pCodec( NULL ),
1782 : 0 : m_aDocDigest( rtl_digest_createMD5() ),
1783 : : m_aCipher( (rtlCipher)NULL ),
1784 : : m_aDigest( NULL ),
1785 : : m_bEncryptThisStream( false ),
1786 : : m_pEncryptionBuffer( NULL ),
1787 : : m_nEncryptionBufferSize( 0 ),
1788 : : m_bIsPDF_A1( false ),
1789 [ # # ][ # # ]: 0 : m_rOuterFace( i_rOuterFace )
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
1790 : : {
1791 : : #ifdef DO_TEST_PDF
1792 : : static bool bOnce = true;
1793 : : if( bOnce )
1794 : : {
1795 : : bOnce = false;
1796 : : doTestCode();
1797 : : }
1798 : : #endif
1799 [ # # ]: 0 : m_aContext = rContext;
1800 [ # # ][ # # ]: 0 : m_aStructure.push_back( PDFStructureElement() );
1801 : 0 : m_aStructure[0].m_nOwnElement = 0;
1802 : 0 : m_aStructure[0].m_nParentElement = 0;
1803 : :
1804 [ # # ]: 0 : Font aFont;
1805 [ # # ][ # # ]: 0 : aFont.SetName( String( RTL_CONSTASCII_USTRINGPARAM( "Times" ) ) );
[ # # ][ # # ]
1806 [ # # ]: 0 : aFont.SetSize( Size( 0, 12 ) );
1807 : :
1808 [ # # ]: 0 : GraphicsState aState;
1809 [ # # ]: 0 : aState.m_aMapMode = m_aMapMode;
1810 [ # # ]: 0 : aState.m_aFont = aFont;
1811 [ # # ]: 0 : m_aGraphicsStack.push_front( aState );
1812 : :
1813 [ # # ]: 0 : oslFileError aError = osl_openFile( m_aContext.URL.pData, &m_aFile, osl_File_OpenFlag_Write | osl_File_OpenFlag_Create );
1814 [ # # ]: 0 : if( aError != osl_File_E_None )
1815 : : {
1816 [ # # ]: 0 : if( aError == osl_File_E_EXIST )
1817 : : {
1818 [ # # ]: 0 : aError = osl_openFile( m_aContext.URL.pData, &m_aFile, osl_File_OpenFlag_Write );
1819 [ # # ]: 0 : if( aError == osl_File_E_None )
1820 [ # # ]: 0 : aError = osl_setFileSize( m_aFile, 0 );
1821 : : }
1822 : : }
1823 [ # # ]: 0 : if( aError != osl_File_E_None )
1824 : : return;
1825 : :
1826 : 0 : m_bOpen = true;
1827 : :
1828 : : // setup DocInfo
1829 [ # # ]: 0 : setupDocInfo();
1830 : :
1831 : : /* prepare the cypher engine, can be done in CTOR, free in DTOR */
1832 : 0 : m_aCipher = rtl_cipher_createARCFOUR( rtl_Cipher_ModeStream );
1833 : 0 : m_aDigest = rtl_digest_createMD5();
1834 : :
1835 : : /* the size of the Codec default maximum */
1836 [ # # ]: 0 : checkEncryptionBufferSize( 0x4000 );
1837 : :
1838 [ # # ]: 0 : if( xEnc.is() )
1839 [ # # ]: 0 : prepareEncryption( xEnc );
1840 : :
1841 [ # # ]: 0 : if( m_aContext.Encryption.Encrypt() )
1842 : : {
1843 : : // sanity check
1844 [ # # # # : 0 : if( m_aContext.Encryption.OValue.size() != ENCRYPTED_PWD_SIZE ||
# # ][ # # ]
1845 : 0 : m_aContext.Encryption.UValue.size() != ENCRYPTED_PWD_SIZE ||
1846 : 0 : m_aContext.Encryption.EncryptionKey.size() != MAXIMUM_RC4_KEY_LENGTH
1847 : : )
1848 : : {
1849 : : // the field lengths are invalid ? This was not setup by initEncryption.
1850 : : // do not encrypt after all
1851 : 0 : m_aContext.Encryption.OValue.clear();
1852 : 0 : m_aContext.Encryption.UValue.clear();
1853 : : OSL_ENSURE( 0, "encryption data failed sanity check, encryption disabled" );
1854 : : }
1855 : : else // setup key lengths
1856 [ # # ]: 0 : m_nAccessPermissions = computeAccessPermissions( m_aContext.Encryption, m_nKeyLength, m_nRC4KeyLength );
1857 : : }
1858 : :
1859 : : // write header
1860 : 0 : OStringBuffer aBuffer( 20 );
1861 [ # # ]: 0 : aBuffer.append( "%PDF-" );
1862 [ # # # # ]: 0 : switch( m_aContext.Version )
1863 : : {
1864 [ # # ]: 0 : case PDFWriter::PDF_1_2: aBuffer.append( "1.2" );break;
1865 [ # # ]: 0 : case PDFWriter::PDF_1_3: aBuffer.append( "1.3" );break;
1866 : : case PDFWriter::PDF_A_1:
1867 : : default:
1868 [ # # ]: 0 : case PDFWriter::PDF_1_4: aBuffer.append( "1.4" );break;
1869 [ # # ]: 0 : case PDFWriter::PDF_1_5: aBuffer.append( "1.5" );break;
1870 : : }
1871 : : // append something binary as comment (suggested in PDF Reference)
1872 [ # # ]: 0 : aBuffer.append( "\n%äüöß\n" );
1873 [ # # ][ # # ]: 0 : if( !writeBuffer( aBuffer.getStr(), aBuffer.getLength() ) )
1874 : : {
1875 [ # # ]: 0 : osl_closeFile( m_aFile );
1876 : 0 : m_bOpen = false;
1877 : : return;
1878 : : }
1879 : :
1880 : : // insert outline root
1881 [ # # ][ # # ]: 0 : m_aOutline.push_back( PDFOutlineEntry() );
1882 : :
1883 : 0 : m_bIsPDF_A1 = (m_aContext.Version == PDFWriter::PDF_A_1);
1884 [ # # ]: 0 : if( m_bIsPDF_A1 )
1885 : 0 : m_aContext.Version = PDFWriter::PDF_1_4; //meaning we need PDF 1.4, PDF/A flavour
1886 : :
1887 [ # # ][ # # ]: 0 : m_bEmbedStandardFonts = m_aContext.EmbedStandardFonts;
[ # # ][ # # ]
[ # # ]
1888 : : }
1889 : :
1890 [ # # ][ # # ]: 0 : PDFWriterImpl::~PDFWriterImpl()
[ # # ][ # # ]
1891 : : {
1892 [ # # ]: 0 : if( m_aDocDigest )
1893 : 0 : rtl_digest_destroyMD5( m_aDocDigest );
1894 [ # # ][ # # ]: 0 : delete static_cast<VirtualDevice*>(m_pReferenceDevice);
1895 : :
1896 [ # # ]: 0 : if( m_aCipher )
1897 : 0 : rtl_cipher_destroyARCFOUR( m_aCipher );
1898 [ # # ]: 0 : if( m_aDigest )
1899 : 0 : rtl_digest_destroyMD5( m_aDigest );
1900 : :
1901 : 0 : rtl_freeMemory( m_pEncryptionBuffer );
1902 : 0 : }
1903 : :
1904 : 0 : void PDFWriterImpl::setupDocInfo()
1905 : : {
1906 [ # # ]: 0 : std::vector< sal_uInt8 > aId;
1907 [ # # ]: 0 : computeDocumentIdentifier( aId, m_aContext.DocumentInfo, m_aCreationDateString, m_aCreationMetaDateString );
1908 [ # # ]: 0 : if( m_aContext.Encryption.DocumentIdentifier.empty() )
1909 [ # # ]: 0 : m_aContext.Encryption.DocumentIdentifier = aId;
1910 : 0 : }
1911 : :
1912 : 0 : void PDFWriterImpl::computeDocumentIdentifier( std::vector< sal_uInt8 >& o_rIdentifier,
1913 : : const vcl::PDFWriter::PDFDocInfo& i_rDocInfo,
1914 : : rtl::OString& o_rCString1,
1915 : : rtl::OString& o_rCString2
1916 : : )
1917 : : {
1918 : 0 : o_rIdentifier.clear();
1919 : :
1920 : : //build the document id
1921 : 0 : rtl::OString aInfoValuesOut;
1922 : 0 : OStringBuffer aID( 1024 );
1923 [ # # ]: 0 : if( i_rDocInfo.Title.Len() )
1924 [ # # ][ # # ]: 0 : appendUnicodeTextString( i_rDocInfo.Title, aID );
1925 [ # # ]: 0 : if( i_rDocInfo.Author.Len() )
1926 [ # # ][ # # ]: 0 : appendUnicodeTextString( i_rDocInfo.Author, aID );
1927 [ # # ]: 0 : if( i_rDocInfo.Subject.Len() )
1928 [ # # ][ # # ]: 0 : appendUnicodeTextString( i_rDocInfo.Subject, aID );
1929 [ # # ]: 0 : if( i_rDocInfo.Keywords.Len() )
1930 [ # # ][ # # ]: 0 : appendUnicodeTextString( i_rDocInfo.Keywords, aID );
1931 [ # # ]: 0 : if( i_rDocInfo.Creator.Len() )
1932 [ # # ][ # # ]: 0 : appendUnicodeTextString( i_rDocInfo.Creator, aID );
1933 [ # # ]: 0 : if( i_rDocInfo.Producer.Len() )
1934 [ # # ][ # # ]: 0 : appendUnicodeTextString( i_rDocInfo.Producer, aID );
1935 : :
1936 : : TimeValue aTVal, aGMT;
1937 : : oslDateTime aDT;
1938 [ # # ]: 0 : osl_getSystemTime( &aGMT );
1939 [ # # ]: 0 : osl_getLocalTimeFromSystemTime( &aGMT, &aTVal );
1940 [ # # ]: 0 : osl_getDateTimeFromTimeValue( &aTVal, &aDT );
1941 : 0 : rtl::OStringBuffer aCreationDateString(64), aCreationMetaDateString(64);
1942 [ # # ]: 0 : aCreationDateString.append( "D:" );
1943 [ # # ]: 0 : aCreationDateString.append( (sal_Char)('0' + ((aDT.Year/1000)%10)) );
1944 [ # # ]: 0 : aCreationDateString.append( (sal_Char)('0' + ((aDT.Year/100)%10)) );
1945 [ # # ]: 0 : aCreationDateString.append( (sal_Char)('0' + ((aDT.Year/10)%10)) );
1946 [ # # ]: 0 : aCreationDateString.append( (sal_Char)('0' + ((aDT.Year)%10)) );
1947 [ # # ]: 0 : aCreationDateString.append( (sal_Char)('0' + ((aDT.Month/10)%10)) );
1948 [ # # ]: 0 : aCreationDateString.append( (sal_Char)('0' + ((aDT.Month)%10)) );
1949 [ # # ]: 0 : aCreationDateString.append( (sal_Char)('0' + ((aDT.Day/10)%10)) );
1950 [ # # ]: 0 : aCreationDateString.append( (sal_Char)('0' + ((aDT.Day)%10)) );
1951 [ # # ]: 0 : aCreationDateString.append( (sal_Char)('0' + ((aDT.Hours/10)%10)) );
1952 [ # # ]: 0 : aCreationDateString.append( (sal_Char)('0' + ((aDT.Hours)%10)) );
1953 [ # # ]: 0 : aCreationDateString.append( (sal_Char)('0' + ((aDT.Minutes/10)%10)) );
1954 [ # # ]: 0 : aCreationDateString.append( (sal_Char)('0' + ((aDT.Minutes)%10)) );
1955 [ # # ]: 0 : aCreationDateString.append( (sal_Char)('0' + ((aDT.Seconds/10)%10)) );
1956 [ # # ]: 0 : aCreationDateString.append( (sal_Char)('0' + ((aDT.Seconds)%10)) );
1957 : :
1958 : : //--> i59651, we fill the Metadata date string as well, if PDF/A is requested
1959 : : // according to ISO 19005-1:2005 6.7.3 the date is corrected for
1960 : : // local time zone offset UTC only, whereas Acrobat 8 seems
1961 : : // to use the localtime notation only
1962 : : // according to a raccomandation in XMP Specification (Jan 2004, page 75)
1963 : : // the Acrobat way seems the right approach
1964 [ # # ]: 0 : aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Year/1000)%10)) );
1965 [ # # ]: 0 : aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Year/100)%10)) );
1966 [ # # ]: 0 : aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Year/10)%10)) );
1967 [ # # ]: 0 : aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Year)%10)) );
1968 [ # # ]: 0 : aCreationMetaDateString.append( "-" );
1969 [ # # ]: 0 : aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Month/10)%10)) );
1970 [ # # ]: 0 : aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Month)%10)) );
1971 [ # # ]: 0 : aCreationMetaDateString.append( "-" );
1972 [ # # ]: 0 : aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Day/10)%10)) );
1973 [ # # ]: 0 : aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Day)%10)) );
1974 [ # # ]: 0 : aCreationMetaDateString.append( "T" );
1975 [ # # ]: 0 : aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Hours/10)%10)) );
1976 [ # # ]: 0 : aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Hours)%10)) );
1977 [ # # ]: 0 : aCreationMetaDateString.append( ":" );
1978 [ # # ]: 0 : aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Minutes/10)%10)) );
1979 [ # # ]: 0 : aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Minutes)%10)) );
1980 [ # # ]: 0 : aCreationMetaDateString.append( ":" );
1981 [ # # ]: 0 : aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Seconds/10)%10)) );
1982 [ # # ]: 0 : aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Seconds)%10)) );
1983 : :
1984 : 0 : sal_uInt32 nDelta = 0;
1985 [ # # ]: 0 : if( aGMT.Seconds > aTVal.Seconds )
1986 : : {
1987 [ # # ]: 0 : aCreationDateString.append( "-" );
1988 : 0 : nDelta = aGMT.Seconds-aTVal.Seconds;
1989 [ # # ]: 0 : aCreationMetaDateString.append( "-" );
1990 : : }
1991 [ # # ]: 0 : else if( aGMT.Seconds < aTVal.Seconds )
1992 : : {
1993 [ # # ]: 0 : aCreationDateString.append( "+" );
1994 : 0 : nDelta = aTVal.Seconds-aGMT.Seconds;
1995 [ # # ]: 0 : aCreationMetaDateString.append( "+" );
1996 : : }
1997 : : else
1998 : : {
1999 [ # # ]: 0 : aCreationDateString.append( "Z" );
2000 [ # # ]: 0 : aCreationMetaDateString.append( "Z" );
2001 : :
2002 : : }
2003 [ # # ]: 0 : if( nDelta )
2004 : : {
2005 [ # # ]: 0 : aCreationDateString.append( (sal_Char)('0' + ((nDelta/36000)%10)) );
2006 [ # # ]: 0 : aCreationDateString.append( (sal_Char)('0' + ((nDelta/3600)%10)) );
2007 [ # # ]: 0 : aCreationDateString.append( "'" );
2008 [ # # ]: 0 : aCreationDateString.append( (sal_Char)('0' + ((nDelta/600)%6)) );
2009 [ # # ]: 0 : aCreationDateString.append( (sal_Char)('0' + ((nDelta/60)%10)) );
2010 : :
2011 [ # # ]: 0 : aCreationMetaDateString.append( (sal_Char)('0' + ((nDelta/36000)%10)) );
2012 [ # # ]: 0 : aCreationMetaDateString.append( (sal_Char)('0' + ((nDelta/3600)%10)) );
2013 [ # # ]: 0 : aCreationMetaDateString.append( ":" );
2014 [ # # ]: 0 : aCreationMetaDateString.append( (sal_Char)('0' + ((nDelta/600)%6)) );
2015 [ # # ]: 0 : aCreationMetaDateString.append( (sal_Char)('0' + ((nDelta/60)%10)) );
2016 : : }
2017 [ # # ]: 0 : aCreationDateString.append( "'" );
2018 [ # # ]: 0 : aID.append( aCreationDateString.getStr(), aCreationDateString.getLength() );
2019 : :
2020 : 0 : aInfoValuesOut = aID.makeStringAndClear();
2021 : 0 : o_rCString1 = aCreationDateString.makeStringAndClear();
2022 : 0 : o_rCString2 = aCreationMetaDateString.makeStringAndClear();
2023 : :
2024 : 0 : rtlDigest aDigest = rtl_digest_createMD5();
2025 : : OSL_ENSURE( aDigest != NULL, "PDFWriterImpl::computeDocumentIdentifier: cannot obtain a digest object !" );
2026 [ # # ]: 0 : if( aDigest )
2027 : : {
2028 : 0 : rtlDigestError nError = rtl_digest_updateMD5( aDigest, &aGMT, sizeof( aGMT ) );
2029 [ # # ]: 0 : if( nError == rtl_Digest_E_None )
2030 : 0 : nError = rtl_digest_updateMD5( aDigest, aInfoValuesOut.getStr(), aInfoValuesOut.getLength() );
2031 [ # # ]: 0 : if( nError == rtl_Digest_E_None )
2032 : : {
2033 [ # # ]: 0 : o_rIdentifier = std::vector< sal_uInt8 >( 16, 0 );
2034 : : //the binary form of the doc id is needed for encryption stuff
2035 [ # # ]: 0 : rtl_digest_getMD5( aDigest, &o_rIdentifier[0], 16 );
2036 : : }
2037 : 0 : }
2038 : 0 : }
2039 : :
2040 : : /* i12626 methods */
2041 : : /*
2042 : : check if the Unicode string must be encrypted or not, perform the requested task,
2043 : : append the string as unicode hex, encrypted if needed
2044 : : */
2045 : 0 : inline void PDFWriterImpl::appendUnicodeTextStringEncrypt( const rtl::OUString& rInString, const sal_Int32 nInObjectNumber, OStringBuffer& rOutBuffer )
2046 : : {
2047 : 0 : rOutBuffer.append( "<" );
2048 [ # # ]: 0 : if( m_aContext.Encryption.Encrypt() )
2049 : : {
2050 : 0 : const sal_Unicode* pStr = rInString.getStr();
2051 : 0 : sal_Int32 nLen = rInString.getLength();
2052 : : //prepare a unicode string, encrypt it
2053 [ # # ]: 0 : if( checkEncryptionBufferSize( nLen*2 ) )
2054 : : {
2055 : 0 : enableStringEncryption( nInObjectNumber );
2056 : 0 : register sal_uInt8 *pCopy = m_pEncryptionBuffer;
2057 : 0 : sal_Int32 nChars = 2;
2058 : 0 : *pCopy++ = 0xFE;
2059 : 0 : *pCopy++ = 0xFF;
2060 : : // we need to prepare a byte stream from the unicode string buffer
2061 [ # # ]: 0 : for( register int i = 0; i < nLen; i++ )
2062 : : {
2063 : 0 : register sal_Unicode aUnChar = pStr[i];
2064 : 0 : *pCopy++ = (sal_uInt8)( aUnChar >> 8 );
2065 : 0 : *pCopy++ = (sal_uInt8)( aUnChar & 255 );
2066 : 0 : nChars += 2;
2067 : : }
2068 : : //encrypt in place
2069 : 0 : rtl_cipher_encodeARCFOUR( m_aCipher, m_pEncryptionBuffer, nChars, m_pEncryptionBuffer, nChars );
2070 : : //now append, hexadecimal (appendHex), the encrypted result
2071 [ # # ]: 0 : for(register int i = 0; i < nChars; i++)
2072 : 0 : appendHex( m_pEncryptionBuffer[i], rOutBuffer );
2073 : : }
2074 : : }
2075 : : else
2076 : 0 : appendUnicodeTextString( rInString, rOutBuffer );
2077 : 0 : rOutBuffer.append( ">" );
2078 : 0 : }
2079 : :
2080 : 0 : inline void PDFWriterImpl::appendLiteralStringEncrypt( rtl::OStringBuffer& rInString, const sal_Int32 nInObjectNumber, rtl::OStringBuffer& rOutBuffer )
2081 : : {
2082 : 0 : rOutBuffer.append( "(" );
2083 : 0 : sal_Int32 nChars = rInString.getLength();
2084 : : //check for encryption, if ok, encrypt the string, then convert with appndLiteralString
2085 [ # # ][ # # ]: 0 : if( m_aContext.Encryption.Encrypt() && checkEncryptionBufferSize( nChars ) )
[ # # ]
2086 : : {
2087 : : //encrypt the string in a buffer, then append it
2088 : 0 : enableStringEncryption( nInObjectNumber );
2089 : 0 : rtl_cipher_encodeARCFOUR( m_aCipher, rInString.getStr(), nChars, m_pEncryptionBuffer, nChars );
2090 : 0 : appendLiteralString( (const sal_Char*)m_pEncryptionBuffer, nChars, rOutBuffer );
2091 : : }
2092 : : else
2093 : 0 : appendLiteralString( rInString.getStr(), nChars , rOutBuffer );
2094 : 0 : rOutBuffer.append( ")" );
2095 : 0 : }
2096 : :
2097 : 0 : inline void PDFWriterImpl::appendLiteralStringEncrypt( const rtl::OString& rInString, const sal_Int32 nInObjectNumber, rtl::OStringBuffer& rOutBuffer )
2098 : : {
2099 [ # # ]: 0 : rtl::OStringBuffer aBufferString( rInString );
2100 [ # # ]: 0 : appendLiteralStringEncrypt( aBufferString, nInObjectNumber, rOutBuffer);
2101 : 0 : }
2102 : :
2103 : 0 : void PDFWriterImpl::appendLiteralStringEncrypt( const rtl::OUString& rInString, const sal_Int32 nInObjectNumber, rtl::OStringBuffer& rOutBuffer, rtl_TextEncoding nEnc )
2104 : : {
2105 [ # # ]: 0 : rtl::OString aBufferString( rtl::OUStringToOString( rInString, nEnc ) );
2106 : 0 : sal_Int32 nLen = aBufferString.getLength();
2107 : 0 : rtl::OStringBuffer aBuf( nLen );
2108 : 0 : const sal_Char* pT = aBufferString.getStr();
2109 : :
2110 [ # # ]: 0 : for( sal_Int32 i = 0; i < nLen; i++, pT++ )
2111 : : {
2112 [ # # ]: 0 : if( (*pT & 0x80) == 0 )
2113 [ # # ]: 0 : aBuf.append( *pT );
2114 : : else
2115 : : {
2116 [ # # ]: 0 : aBuf.append( '<' );
2117 [ # # ]: 0 : appendHex( *pT, aBuf );
2118 [ # # ]: 0 : aBuf.append( '>' );
2119 : : }
2120 : : }
2121 : 0 : aBufferString = aBuf.makeStringAndClear();
2122 [ # # ]: 0 : appendLiteralStringEncrypt( aBufferString, nInObjectNumber, rOutBuffer);
2123 : 0 : }
2124 : :
2125 : : /* end i12626 methods */
2126 : :
2127 : 0 : void PDFWriterImpl::emitComment( const char* pComment )
2128 : : {
2129 : 0 : OStringBuffer aLine( 64 );
2130 [ # # ]: 0 : aLine.append( "% " );
2131 [ # # ]: 0 : aLine.append( (const sal_Char*)pComment );
2132 [ # # ]: 0 : aLine.append( "\n" );
2133 [ # # ]: 0 : writeBuffer( aLine.getStr(), aLine.getLength() );
2134 : 0 : }
2135 : :
2136 : 0 : bool PDFWriterImpl::compressStream( SvMemoryStream* pStream )
2137 : : {
2138 : : #ifndef DEBUG_DISABLE_PDFCOMPRESSION
2139 [ # # ]: 0 : pStream->Seek( STREAM_SEEK_TO_END );
2140 : 0 : sal_uLong nEndPos = pStream->Tell();
2141 [ # # ]: 0 : pStream->Seek( STREAM_SEEK_TO_BEGIN );
2142 [ # # ][ # # ]: 0 : ZCodec* pCodec = new ZCodec( 0x4000, 0x4000 );
2143 [ # # ]: 0 : SvMemoryStream aStream;
2144 [ # # ]: 0 : pCodec->BeginCompression();
2145 [ # # ][ # # ]: 0 : pCodec->Write( aStream, (const sal_uInt8*)pStream->GetData(), nEndPos );
2146 [ # # ]: 0 : pCodec->EndCompression();
2147 [ # # ][ # # ]: 0 : delete pCodec;
2148 : 0 : nEndPos = aStream.Tell();
2149 [ # # ]: 0 : pStream->Seek( STREAM_SEEK_TO_BEGIN );
2150 [ # # ]: 0 : aStream.Seek( STREAM_SEEK_TO_BEGIN );
2151 [ # # ]: 0 : pStream->SetStreamSize( nEndPos );
2152 [ # # ][ # # ]: 0 : pStream->Write( aStream.GetData(), nEndPos );
2153 [ # # ]: 0 : return true;
2154 : : #else
2155 : : (void)pStream;
2156 : : return false;
2157 : : #endif
2158 : : }
2159 : :
2160 : 0 : void PDFWriterImpl::beginCompression()
2161 : : {
2162 : : #ifndef DEBUG_DISABLE_PDFCOMPRESSION
2163 [ # # ]: 0 : m_pCodec = new ZCodec( 0x4000, 0x4000 );
2164 [ # # ]: 0 : m_pMemStream = new SvMemoryStream();
2165 : 0 : m_pCodec->BeginCompression();
2166 : : #endif
2167 : 0 : }
2168 : :
2169 : 0 : void PDFWriterImpl::endCompression()
2170 : : {
2171 : : #ifndef DEBUG_DISABLE_PDFCOMPRESSION
2172 [ # # ]: 0 : if( m_pCodec )
2173 : : {
2174 : 0 : m_pCodec->EndCompression();
2175 [ # # ]: 0 : delete m_pCodec;
2176 : 0 : m_pCodec = NULL;
2177 : 0 : sal_uInt64 nLen = m_pMemStream->Tell();
2178 : 0 : m_pMemStream->Seek( 0 );
2179 : 0 : writeBuffer( m_pMemStream->GetData(), nLen );
2180 [ # # ]: 0 : delete m_pMemStream;
2181 : 0 : m_pMemStream = NULL;
2182 : : }
2183 : : #endif
2184 : 0 : }
2185 : :
2186 : 0 : bool PDFWriterImpl::writeBuffer( const void* pBuffer, sal_uInt64 nBytes )
2187 : : {
2188 [ # # ]: 0 : if( ! m_bOpen ) // we are already down the drain
2189 : 0 : return false;
2190 : :
2191 [ # # ]: 0 : if( ! nBytes ) // huh ?
2192 : 0 : return true;
2193 : :
2194 [ # # ]: 0 : if( m_aOutputStreams.begin() != m_aOutputStreams.end() )
2195 : : {
2196 [ # # ][ # # ]: 0 : m_aOutputStreams.front().m_pStream->Seek( STREAM_SEEK_TO_END );
2197 [ # # ][ # # ]: 0 : m_aOutputStreams.front().m_pStream->Write( pBuffer, sal::static_int_cast<sal_Size>(nBytes) );
2198 : 0 : return true;
2199 : : }
2200 : :
2201 : : sal_uInt64 nWritten;
2202 [ # # ]: 0 : if( m_pCodec )
2203 : : {
2204 [ # # ]: 0 : m_pCodec->Write( *m_pMemStream, static_cast<const sal_uInt8*>(pBuffer), (sal_uLong)nBytes );
2205 : 0 : nWritten = nBytes;
2206 : : }
2207 : : else
2208 : : {
2209 : 0 : sal_Bool buffOK = sal_True;
2210 [ # # ]: 0 : if( m_bEncryptThisStream )
2211 : : {
2212 : : /* implement the encryption part of the PDF spec encryption algorithm 3.1 */
2213 [ # # ][ # # ]: 0 : if( ( buffOK = checkEncryptionBufferSize( static_cast<sal_Int32>(nBytes) ) ) != sal_False )
2214 : : rtl_cipher_encodeARCFOUR( m_aCipher,
2215 : : (sal_uInt8*)pBuffer, static_cast<sal_Size>(nBytes),
2216 : 0 : m_pEncryptionBuffer, static_cast<sal_Size>(nBytes) );
2217 : : }
2218 : :
2219 [ # # ][ # # ]: 0 : const void* pWriteBuffer = ( m_bEncryptThisStream && buffOK ) ? m_pEncryptionBuffer : pBuffer;
2220 [ # # ]: 0 : if( m_aDocDigest )
2221 : 0 : rtl_digest_updateMD5( m_aDocDigest, pWriteBuffer, static_cast<sal_uInt32>(nBytes) );
2222 : :
2223 [ # # ]: 0 : if( osl_writeFile( m_aFile,
2224 : : pWriteBuffer,
2225 [ # # ]: 0 : nBytes, &nWritten ) != osl_File_E_None )
2226 : 0 : nWritten = 0;
2227 : :
2228 [ # # ]: 0 : if( nWritten != nBytes )
2229 : : {
2230 [ # # ]: 0 : osl_closeFile( m_aFile );
2231 : 0 : m_bOpen = false;
2232 : : }
2233 : : }
2234 : :
2235 : 0 : return nWritten == nBytes;
2236 : : }
2237 : :
2238 : 0 : OutputDevice* PDFWriterImpl::getReferenceDevice()
2239 : : {
2240 [ # # ]: 0 : if( ! m_pReferenceDevice )
2241 : : {
2242 [ # # ]: 0 : VirtualDevice* pVDev = new VirtualDevice( 0 );
2243 : :
2244 : 0 : m_pReferenceDevice = pVDev;
2245 : :
2246 [ # # ][ # # ]: 0 : if( m_aContext.DPIx == 0 || m_aContext.DPIy == 0 )
2247 : 0 : pVDev->SetReferenceDevice( VirtualDevice::REFDEV_MODE_PDF1 );
2248 : : else
2249 : 0 : pVDev->SetReferenceDevice( m_aContext.DPIx, m_aContext.DPIy );
2250 : :
2251 [ # # ]: 0 : pVDev->SetOutputSizePixel( Size( 640, 480 ) );
2252 [ # # ]: 0 : pVDev->SetMapMode( MAP_MM );
2253 : :
2254 : 0 : m_pReferenceDevice->mpPDFWriter = this;
2255 : 0 : m_pReferenceDevice->ImplUpdateFontData( sal_True );
2256 : : }
2257 : 0 : return m_pReferenceDevice;
2258 : : }
2259 : :
2260 [ # # ]: 0 : class ImplPdfBuiltinFontData : public PhysicalFontFace
2261 : : {
2262 : : private:
2263 : : const PDFWriterImpl::BuiltinFont& mrBuiltin;
2264 : :
2265 : : public:
2266 : : enum {PDF_FONT_MAGIC = 0xBDFF0A1C };
2267 : : ImplPdfBuiltinFontData( const PDFWriterImpl::BuiltinFont& );
2268 : 0 : const PDFWriterImpl::BuiltinFont* GetBuiltinFont() const { return &mrBuiltin; }
2269 : :
2270 [ # # ]: 0 : virtual PhysicalFontFace* Clone() const { return new ImplPdfBuiltinFontData(*this); }
2271 : : virtual ImplFontEntry* CreateFontInstance( FontSelectPattern& ) const;
2272 : 0 : virtual sal_IntPtr GetFontId() const { return reinterpret_cast<sal_IntPtr>(&mrBuiltin); }
2273 : : };
2274 : :
2275 : 0 : inline const ImplPdfBuiltinFontData* GetPdfFontData( const PhysicalFontFace* pFontData )
2276 : : {
2277 : 0 : const ImplPdfBuiltinFontData* pFD = NULL;
2278 [ # # ][ # # ]: 0 : if( pFontData && pFontData->CheckMagic( ImplPdfBuiltinFontData::PDF_FONT_MAGIC ) )
[ # # ]
2279 : 0 : pFD = static_cast<const ImplPdfBuiltinFontData*>( pFontData );
2280 : 0 : return pFD;
2281 : : }
2282 : :
2283 : 0 : static ImplDevFontAttributes GetDevFontAttributes( const PDFWriterImpl::BuiltinFont& rBuiltin )
2284 : : {
2285 : 0 : ImplDevFontAttributes aDFA;
2286 [ # # ]: 0 : aDFA.maName = rtl::OUString::createFromAscii( rBuiltin.m_pName );
2287 [ # # ]: 0 : aDFA.maStyleName = rtl::OUString::createFromAscii( rBuiltin.m_pStyleName );
2288 : 0 : aDFA.meFamily = rBuiltin.m_eFamily;
2289 : 0 : aDFA.mbSymbolFlag = (rBuiltin.m_eCharSet != RTL_TEXTENCODING_MS_1252 );
2290 : 0 : aDFA.mePitch = rBuiltin.m_ePitch;
2291 : 0 : aDFA.meWeight = rBuiltin.m_eWeight;
2292 : 0 : aDFA.meItalic = rBuiltin.m_eItalic;
2293 : 0 : aDFA.meWidthType = rBuiltin.m_eWidthType;
2294 : :
2295 : 0 : aDFA.mbOrientation = true;
2296 : 0 : aDFA.mbDevice = true;
2297 : 0 : aDFA.mnQuality = 50000;
2298 : 0 : aDFA.mbSubsettable = false;
2299 : 0 : aDFA.mbEmbeddable = false;
2300 : 0 : return aDFA;
2301 : : }
2302 : :
2303 : 0 : ImplPdfBuiltinFontData::ImplPdfBuiltinFontData( const PDFWriterImpl::BuiltinFont& rBuiltin )
2304 : : : PhysicalFontFace( GetDevFontAttributes(rBuiltin), PDF_FONT_MAGIC ),
2305 [ # # ]: 0 : mrBuiltin( rBuiltin )
2306 : 0 : {}
2307 : :
2308 : 0 : ImplFontEntry* ImplPdfBuiltinFontData::CreateFontInstance( FontSelectPattern& rFSD ) const
2309 : : {
2310 [ # # ]: 0 : ImplFontEntry* pEntry = new ImplFontEntry( rFSD );
2311 : 0 : return pEntry;
2312 : : }
2313 : :
2314 : 0 : ImplDevFontList* PDFWriterImpl::filterDevFontList( ImplDevFontList* pFontList )
2315 : : {
2316 : : DBG_ASSERT( m_aSubsets.empty(), "Fonts changing during PDF generation, document will be invalid" );
2317 : 0 : ImplDevFontList* pFiltered = pFontList->Clone( true, true );
2318 : :
2319 : : // append the PDF builtin fonts
2320 [ # # ][ # # ]: 0 : if( !m_bIsPDF_A1 && !m_bEmbedStandardFonts)
2321 [ # # ]: 0 : for( unsigned int i = 0; i < SAL_N_ELEMENTS(m_aBuiltinFonts); i++ )
2322 : : {
2323 [ # # ]: 0 : PhysicalFontFace* pNewData = new ImplPdfBuiltinFontData( m_aBuiltinFonts[i] );
2324 : 0 : pFiltered->Add( pNewData );
2325 : : }
2326 : 0 : return pFiltered;
2327 : : }
2328 : :
2329 : 0 : bool PDFWriterImpl::isBuiltinFont( const PhysicalFontFace* pFont ) const
2330 : : {
2331 : 0 : const ImplPdfBuiltinFontData* pFD = GetPdfFontData( pFont );
2332 : 0 : return (pFD != NULL);
2333 : : }
2334 : :
2335 : 0 : void PDFWriterImpl::getFontMetric( FontSelectPattern* pSelect, ImplFontMetricData* pMetric ) const
2336 : : {
2337 : 0 : const ImplPdfBuiltinFontData* pFD = GetPdfFontData( pSelect->mpFontData );
2338 [ # # ]: 0 : if( !pFD )
2339 : 0 : return;
2340 : 0 : const BuiltinFont* pBuiltinFont = pFD->GetBuiltinFont();
2341 : :
2342 : 0 : pMetric->mnOrientation = sal::static_int_cast<short>(pSelect->mnOrientation);
2343 : 0 : pMetric->meFamily = pBuiltinFont->m_eFamily;
2344 : 0 : pMetric->mePitch = pBuiltinFont->m_ePitch;
2345 : 0 : pMetric->meWeight = pBuiltinFont->m_eWeight;
2346 : 0 : pMetric->meItalic = pBuiltinFont->m_eItalic;
2347 : 0 : pMetric->mbSymbolFlag = pFD->IsSymbolFont();
2348 : 0 : pMetric->mnWidth = pSelect->mnHeight;
2349 : 0 : pMetric->mnAscent = ( pSelect->mnHeight * +pBuiltinFont->m_nAscent + 500 ) / 1000;
2350 : 0 : pMetric->mnDescent = ( pSelect->mnHeight * -pBuiltinFont->m_nDescent + 500 ) / 1000;
2351 : 0 : pMetric->mnIntLeading = 0;
2352 : 0 : pMetric->mnExtLeading = 0;
2353 : 0 : pMetric->mnSlant = 0;
2354 : 0 : pMetric->mbScalableFont = true;
2355 : 0 : pMetric->mbDevice = true;
2356 : : }
2357 : :
2358 : : // -----------------------------------------------------------------------
2359 : :
2360 : : namespace vcl {
2361 : :
2362 [ # # ][ # # ]: 0 : class PDFSalLayout : public GenericSalLayout
2363 : : {
2364 : : PDFWriterImpl& mrPDFWriterImpl;
2365 : : const PDFWriterImpl::BuiltinFont& mrBuiltinFont;
2366 : : bool mbIsSymbolFont;
2367 : : long mnPixelPerEM;
2368 : : String maOrigText;
2369 : :
2370 : : public:
2371 : : PDFSalLayout( PDFWriterImpl&,
2372 : : const PDFWriterImpl::BuiltinFont&,
2373 : : long nPixelPerEM, int nOrientation );
2374 : :
2375 : 0 : void SetText( const rtl::OUString& rText ) { maOrigText = rText; }
2376 : : virtual bool LayoutText( ImplLayoutArgs& );
2377 : : virtual void InitFont() const;
2378 : : virtual void DrawText( SalGraphics& ) const;
2379 : : };
2380 : :
2381 : : }
2382 : :
2383 : : // -----------------------------------------------------------------------
2384 : :
2385 : 0 : PDFSalLayout::PDFSalLayout( PDFWriterImpl& rPDFWriterImpl,
2386 : : const PDFWriterImpl::BuiltinFont& rBuiltinFont,
2387 : : long nPixelPerEM, int nOrientation )
2388 : : : mrPDFWriterImpl( rPDFWriterImpl ),
2389 : : mrBuiltinFont( rBuiltinFont ),
2390 [ # # ]: 0 : mnPixelPerEM( nPixelPerEM )
2391 : : {
2392 : 0 : mbIsSymbolFont = (rBuiltinFont.m_eCharSet != RTL_TEXTENCODING_MS_1252);
2393 : 0 : SetOrientation( nOrientation );
2394 : 0 : }
2395 : :
2396 : : // -----------------------------------------------------------------------
2397 : :
2398 : 0 : bool PDFSalLayout::LayoutText( ImplLayoutArgs& rArgs )
2399 : : {
2400 : 0 : const rtl::OUString aText(rArgs.mpStr+rArgs.mnMinCharPos, rArgs.mnEndCharPos-rArgs.mnMinCharPos);
2401 [ # # ]: 0 : SetText( aText );
2402 : 0 : SetUnitsPerPixel( 1000 );
2403 : :
2404 [ # # ]: 0 : rtl_UnicodeToTextConverter aConv = rtl_createTextToUnicodeConverter( mrBuiltinFont.m_eCharSet );
2405 : :
2406 : 0 : Point aNewPos( 0, 0 );
2407 : : bool bRightToLeft;
2408 [ # # ]: 0 : Reserve(rArgs.mnLength);
2409 [ # # ][ # # ]: 0 : for( int nCharPos = -1; rArgs.GetNextPos( &nCharPos, &bRightToLeft ); )
2410 : : {
2411 : : // TODO: handle unicode surrogates
2412 : : // on the other hand the PDF builtin fonts don't support them anyway
2413 : 0 : sal_Unicode cChar = rArgs.mpStr[ nCharPos ];
2414 [ # # ]: 0 : if( bRightToLeft )
2415 [ # # ]: 0 : cChar = static_cast<sal_Unicode>(GetMirroredChar( cChar ));
2416 : :
2417 : : sal_Char aBuf[4];
2418 : : sal_uInt32 nInfo;
2419 : : sal_Size nSrcCvtChars;
2420 : :
2421 : : sal_Size nConv = rtl_convertUnicodeToText( aConv,
2422 : : NULL,
2423 : : &cChar, 1,
2424 : : aBuf, sizeof(aBuf)/sizeof(*aBuf),
2425 : : RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR,
2426 [ # # ]: 0 : &nInfo, &nSrcCvtChars );
2427 : : // check whether conversion was possible
2428 : : // else fallback font is needed as the standard fonts
2429 : : // are handled via WinAnsi encoding
2430 [ # # ]: 0 : if( nConv > 0 )
2431 : 0 : cChar = ((sal_Unicode)aBuf[0]) & 0x00ff;
2432 : :
2433 [ # # ]: 0 : if( cChar & 0xff00 )
2434 : : {
2435 : 0 : cChar = 0; // NotDef glyph
2436 [ # # ]: 0 : rArgs.NeedFallback( nCharPos, bRightToLeft );
2437 : : }
2438 : :
2439 : 0 : long nGlyphWidth = (long)mrBuiltinFont.m_aWidths[cChar] * mnPixelPerEM;
2440 : 0 : long nGlyphFlags = 0; // builtin fonts don't have diacritic glyphs
2441 [ # # ]: 0 : if( bRightToLeft )
2442 : 0 : nGlyphFlags |= GlyphItem::IS_RTL_GLYPH;
2443 : : // TODO: get kerning from builtin fonts
2444 : 0 : GlyphItem aGI( nCharPos, cChar, aNewPos, nGlyphFlags, nGlyphWidth );
2445 [ # # ]: 0 : AppendGlyph( aGI );
2446 : :
2447 : 0 : aNewPos.X() += nGlyphWidth;
2448 : : }
2449 : :
2450 [ # # ]: 0 : rtl_destroyUnicodeToTextConverter( aConv );
2451 : :
2452 : 0 : return true;
2453 : : }
2454 : :
2455 : : // -----------------------------------------------------------------------
2456 : :
2457 : 0 : void PDFSalLayout::InitFont() const
2458 : : {
2459 : : // TODO: recreate font with all its attributes
2460 : 0 : }
2461 : :
2462 : : // -----------------------------------------------------------------------
2463 : :
2464 : 0 : void PDFSalLayout::DrawText( SalGraphics& ) const
2465 : : {
2466 : 0 : mrPDFWriterImpl.drawLayout( *const_cast<PDFSalLayout*>(this), maOrigText, true );
2467 : 0 : }
2468 : :
2469 : : // -----------------------------------------------------------------------
2470 : :
2471 : 0 : SalLayout* PDFWriterImpl::GetTextLayout( ImplLayoutArgs& rArgs, FontSelectPattern* pSelect )
2472 : : {
2473 : : DBG_ASSERT( (pSelect->mpFontData != NULL),
2474 : : "PDFWriterImpl::GetTextLayout mpFontData is NULL" );
2475 : :
2476 : 0 : const ImplPdfBuiltinFontData* pFD = GetPdfFontData( pSelect->mpFontData );
2477 [ # # ]: 0 : if( !pFD )
2478 : 0 : return NULL;
2479 : 0 : const BuiltinFont* pBuiltinFont = pFD->GetBuiltinFont();
2480 : :
2481 [ # # ]: 0 : long nPixelPerEM = pSelect->mnWidth ? pSelect->mnWidth : pSelect->mnHeight;
2482 : 0 : int nOrientation = pSelect->mnOrientation;
2483 [ # # ]: 0 : PDFSalLayout* pLayout = new PDFSalLayout( *this, *pBuiltinFont, nPixelPerEM, nOrientation );
2484 [ # # ]: 0 : pLayout->SetText( rArgs.mpStr );
2485 : 0 : return pLayout;
2486 : : }
2487 : :
2488 : 0 : sal_Int32 PDFWriterImpl::newPage( sal_Int32 nPageWidth, sal_Int32 nPageHeight, PDFWriter::Orientation eOrientation )
2489 : : {
2490 [ # # ]: 0 : endPage();
2491 : 0 : m_nCurrentPage = m_aPages.size();
2492 [ # # ][ # # ]: 0 : m_aPages.push_back( PDFPage(this, nPageWidth, nPageHeight, eOrientation ) );
2493 [ # # ]: 0 : m_aPages.back().m_nPageIndex = m_nCurrentPage;
2494 [ # # ][ # # ]: 0 : m_aPages.back().beginStream();
2495 : :
2496 : : // setup global graphics state
2497 : : // linewidth is "1 pixel" by default
2498 : 0 : OStringBuffer aBuf( 16 );
2499 [ # # ][ # # ]: 0 : appendDouble( 72.0/double(getReferenceDevice()->ImplGetDPIX()), aBuf );
2500 [ # # ]: 0 : aBuf.append( " w\n" );
2501 [ # # ]: 0 : writeBuffer( aBuf.getStr(), aBuf.getLength() );
2502 : :
2503 : 0 : return m_nCurrentPage;
2504 : : }
2505 : :
2506 : 0 : void PDFWriterImpl::endPage()
2507 : : {
2508 [ # # ][ # # ]: 0 : if( m_aPages.begin() != m_aPages.end() )
2509 : : {
2510 : : // close eventual MC sequence
2511 [ # # ]: 0 : endStructureElementMCSeq();
2512 : :
2513 : : // sanity check
2514 [ # # ]: 0 : if( m_aOutputStreams.begin() != m_aOutputStreams.end() )
2515 : : {
2516 : : OSL_FAIL( "redirection across pages !!!" );
2517 : 0 : m_aOutputStreams.clear(); // leak !
2518 [ # # ]: 0 : m_aMapMode.SetOrigin( Point() );
2519 : : }
2520 : :
2521 : 0 : m_aGraphicsStack.clear();
2522 [ # # ][ # # ]: 0 : m_aGraphicsStack.push_back( GraphicsState() );
[ # # ]
2523 : :
2524 : : // this should pop the PDF graphics stack if necessary
2525 [ # # ]: 0 : updateGraphicsState();
2526 : :
2527 [ # # ][ # # ]: 0 : m_aPages.back().endStream();
2528 : :
2529 : : // reset the default font
2530 [ # # ]: 0 : Font aFont;
2531 [ # # ][ # # ]: 0 : aFont.SetName( String( RTL_CONSTASCII_USTRINGPARAM( "Times" ) ) );
[ # # ][ # # ]
2532 [ # # ]: 0 : aFont.SetSize( Size( 0, 12 ) );
2533 : :
2534 [ # # ][ # # ]: 0 : m_aCurrentPDFState = m_aGraphicsStack.front();
2535 [ # # ][ # # ]: 0 : m_aGraphicsStack.front().m_aFont = aFont;
2536 : :
2537 [ # # ]: 0 : for( std::list<BitmapEmit>::iterator it = m_aBitmaps.begin();
2538 : 0 : it != m_aBitmaps.end(); ++it )
2539 : : {
2540 [ # # ][ # # ]: 0 : if( ! it->m_aBitmap.IsEmpty() )
2541 : : {
2542 [ # # ]: 0 : writeBitmapObject( *it );
2543 [ # # ][ # # ]: 0 : it->m_aBitmap = BitmapEx();
[ # # ]
2544 : : }
2545 : : }
2546 [ # # ]: 0 : for( std::list<JPGEmit>::iterator jpeg = m_aJPGs.begin(); jpeg != m_aJPGs.end(); ++jpeg )
2547 : : {
2548 [ # # ]: 0 : if( jpeg->m_pStream )
2549 : : {
2550 [ # # ]: 0 : writeJPG( *jpeg );
2551 [ # # ][ # # ]: 0 : delete jpeg->m_pStream;
2552 : 0 : jpeg->m_pStream = NULL;
2553 [ # # ][ # # ]: 0 : jpeg->m_aMask = Bitmap();
[ # # ]
2554 : : }
2555 : : }
2556 [ # # ]: 0 : for( std::list<TransparencyEmit>::iterator t = m_aTransparentObjects.begin();
2557 : 0 : t != m_aTransparentObjects.end(); ++t )
2558 : : {
2559 [ # # ]: 0 : if( t->m_pContentStream )
2560 : : {
2561 [ # # ]: 0 : writeTransparentObject( *t );
2562 [ # # ][ # # ]: 0 : delete t->m_pContentStream;
2563 : 0 : t->m_pContentStream = NULL;
2564 : : }
2565 [ # # ]: 0 : }
2566 : : }
2567 : 0 : }
2568 : :
2569 : 0 : sal_Int32 PDFWriterImpl::createObject()
2570 : : {
2571 [ # # ]: 0 : m_aObjects.push_back( ~0U );
2572 : 0 : return m_aObjects.size();
2573 : : }
2574 : :
2575 : 0 : bool PDFWriterImpl::updateObject( sal_Int32 n )
2576 : : {
2577 [ # # ]: 0 : if( ! m_bOpen )
2578 : 0 : return false;
2579 : :
2580 : 0 : sal_uInt64 nOffset = ~0U;
2581 [ # # ]: 0 : oslFileError aError = osl_getFilePos( m_aFile, &nOffset );
2582 : : DBG_ASSERT( aError == osl_File_E_None, "could not register object" );
2583 [ # # ]: 0 : if( aError != osl_File_E_None )
2584 : : {
2585 [ # # ]: 0 : osl_closeFile( m_aFile );
2586 : 0 : m_bOpen = false;
2587 : : }
2588 [ # # ]: 0 : m_aObjects[ n-1 ] = nOffset;
2589 : 0 : return aError == osl_File_E_None;
2590 : : }
2591 : :
2592 : : #define CHECK_RETURN( x ) if( !(x) ) return 0
2593 : :
2594 : 0 : sal_Int32 PDFWriterImpl::emitStructParentTree( sal_Int32 nObject )
2595 : : {
2596 [ # # ]: 0 : if( nObject > 0 )
2597 : : {
2598 : 0 : OStringBuffer aLine( 1024 );
2599 : :
2600 [ # # ]: 0 : aLine.append( nObject );
2601 : : aLine.append( " 0 obj\n"
2602 [ # # ]: 0 : "<</Nums[\n" );
2603 : 0 : sal_Int32 nTreeItems = m_aStructParentTree.size();
2604 [ # # ]: 0 : for( sal_Int32 n = 0; n < nTreeItems; n++ )
2605 : : {
2606 [ # # ]: 0 : aLine.append( n );
2607 [ # # ]: 0 : aLine.append( ' ' );
2608 [ # # ]: 0 : aLine.append( m_aStructParentTree[n] );
2609 [ # # ]: 0 : aLine.append( "\n" );
2610 : : }
2611 [ # # ]: 0 : aLine.append( "]>>\nendobj\n\n" );
2612 [ # # ][ # # ]: 0 : CHECK_RETURN( updateObject( nObject ) );
2613 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
[ # # ]
2614 : : }
2615 : 0 : return nObject;
2616 : : }
2617 : :
2618 : 0 : const sal_Char* PDFWriterImpl::getAttributeTag( PDFWriter::StructAttribute eAttr )
2619 : : {
2620 [ # # ][ # # ]: 0 : static std::map< PDFWriter::StructAttribute, const char* > aAttributeStrings;
[ # # ][ # # ]
2621 : : // fill maps once
2622 [ # # ]: 0 : if( aAttributeStrings.empty() )
2623 : : {
2624 [ # # ]: 0 : aAttributeStrings[ PDFWriter::Placement ] = "Placement";
2625 [ # # ]: 0 : aAttributeStrings[ PDFWriter::WritingMode ] = "WritingMode";
2626 [ # # ]: 0 : aAttributeStrings[ PDFWriter::SpaceBefore ] = "SpaceBefore";
2627 [ # # ]: 0 : aAttributeStrings[ PDFWriter::SpaceAfter ] = "SpaceAfter";
2628 [ # # ]: 0 : aAttributeStrings[ PDFWriter::StartIndent ] = "StartIndent";
2629 [ # # ]: 0 : aAttributeStrings[ PDFWriter::EndIndent ] = "EndIndent";
2630 [ # # ]: 0 : aAttributeStrings[ PDFWriter::TextIndent ] = "TextIndent";
2631 [ # # ]: 0 : aAttributeStrings[ PDFWriter::TextAlign ] = "TextAlign";
2632 [ # # ]: 0 : aAttributeStrings[ PDFWriter::Width ] = "Width";
2633 [ # # ]: 0 : aAttributeStrings[ PDFWriter::Height ] = "Height";
2634 [ # # ]: 0 : aAttributeStrings[ PDFWriter::BlockAlign ] = "BlockAlign";
2635 [ # # ]: 0 : aAttributeStrings[ PDFWriter::InlineAlign ] = "InlineAlign";
2636 [ # # ]: 0 : aAttributeStrings[ PDFWriter::LineHeight ] = "LineHeight";
2637 [ # # ]: 0 : aAttributeStrings[ PDFWriter::BaselineShift ] = "BaselineShift";
2638 [ # # ]: 0 : aAttributeStrings[ PDFWriter::TextDecorationType ] = "TextDecorationType";
2639 [ # # ]: 0 : aAttributeStrings[ PDFWriter::ListNumbering ] = "ListNumbering";
2640 [ # # ]: 0 : aAttributeStrings[ PDFWriter::RowSpan ] = "RowSpan";
2641 [ # # ]: 0 : aAttributeStrings[ PDFWriter::ColSpan ] = "ColSpan";
2642 [ # # ]: 0 : aAttributeStrings[ PDFWriter::LinkAnnotation ] = "LinkAnnotation";
2643 : : }
2644 : :
2645 : : std::map< PDFWriter::StructAttribute, const char* >::const_iterator it =
2646 [ # # ][ # # ]: 0 : aAttributeStrings.find( eAttr );
2647 : :
2648 : : #if OSL_DEBUG_LEVEL > 1
2649 : : if( it == aAttributeStrings.end() )
2650 : : fprintf( stderr, "invalid PDFWriter::StructAttribute %d\n", eAttr );
2651 : : #endif
2652 : :
2653 [ # # ][ # # ]: 0 : return it != aAttributeStrings.end() ? it->second : "";
[ # # ][ # # ]
2654 : : }
2655 : :
2656 : 0 : const sal_Char* PDFWriterImpl::getAttributeValueTag( PDFWriter::StructAttributeValue eVal )
2657 : : {
2658 [ # # ][ # # ]: 0 : static std::map< PDFWriter::StructAttributeValue, const char* > aValueStrings;
[ # # ][ # # ]
2659 : :
2660 [ # # ]: 0 : if( aValueStrings.empty() )
2661 : : {
2662 [ # # ]: 0 : aValueStrings[ PDFWriter::NONE ] = "None";
2663 [ # # ]: 0 : aValueStrings[ PDFWriter::Block ] = "Block";
2664 [ # # ]: 0 : aValueStrings[ PDFWriter::Inline ] = "Inline";
2665 [ # # ]: 0 : aValueStrings[ PDFWriter::Before ] = "Before";
2666 [ # # ]: 0 : aValueStrings[ PDFWriter::After ] = "After";
2667 [ # # ]: 0 : aValueStrings[ PDFWriter::Start ] = "Start";
2668 [ # # ]: 0 : aValueStrings[ PDFWriter::End ] = "End";
2669 [ # # ]: 0 : aValueStrings[ PDFWriter::LrTb ] = "LrTb";
2670 [ # # ]: 0 : aValueStrings[ PDFWriter::RlTb ] = "RlTb";
2671 [ # # ]: 0 : aValueStrings[ PDFWriter::TbRl ] = "TbRl";
2672 [ # # ]: 0 : aValueStrings[ PDFWriter::Center ] = "Center";
2673 [ # # ]: 0 : aValueStrings[ PDFWriter::Justify ] = "Justify";
2674 [ # # ]: 0 : aValueStrings[ PDFWriter::Auto ] = "Auto";
2675 [ # # ]: 0 : aValueStrings[ PDFWriter::Middle ] = "Middle";
2676 [ # # ]: 0 : aValueStrings[ PDFWriter::Normal ] = "Normal";
2677 [ # # ]: 0 : aValueStrings[ PDFWriter::Underline ] = "Underline";
2678 [ # # ]: 0 : aValueStrings[ PDFWriter::Overline ] = "Overline";
2679 [ # # ]: 0 : aValueStrings[ PDFWriter::LineThrough ] = "LineThrough";
2680 [ # # ]: 0 : aValueStrings[ PDFWriter::Disc ] = "Disc";
2681 [ # # ]: 0 : aValueStrings[ PDFWriter::Circle ] = "Circle";
2682 [ # # ]: 0 : aValueStrings[ PDFWriter::Square ] = "Square";
2683 [ # # ]: 0 : aValueStrings[ PDFWriter::Decimal ] = "Decimal";
2684 [ # # ]: 0 : aValueStrings[ PDFWriter::UpperRoman ] = "UpperRoman";
2685 [ # # ]: 0 : aValueStrings[ PDFWriter::LowerRoman ] = "LowerRoman";
2686 [ # # ]: 0 : aValueStrings[ PDFWriter::UpperAlpha ] = "UpperAlpha";
2687 [ # # ]: 0 : aValueStrings[ PDFWriter::LowerAlpha ] = "LowerAlpha";
2688 : : }
2689 : :
2690 : : std::map< PDFWriter::StructAttributeValue, const char* >::const_iterator it =
2691 [ # # ][ # # ]: 0 : aValueStrings.find( eVal );
2692 : :
2693 : : #if OSL_DEBUG_LEVEL > 1
2694 : : if( it == aValueStrings.end() )
2695 : : fprintf( stderr, "invalid PDFWriter::StructAttributeValue %d\n", eVal );
2696 : : #endif
2697 : :
2698 [ # # ][ # # ]: 0 : return it != aValueStrings.end() ? it->second : "";
[ # # ][ # # ]
2699 : : }
2700 : :
2701 : 0 : static void appendStructureAttributeLine( PDFWriter::StructAttribute i_eAttr, const PDFWriterImpl::PDFStructureAttribute& i_rVal, OStringBuffer& o_rLine, bool i_bIsFixedInt )
2702 : : {
2703 : 0 : o_rLine.append( "/" );
2704 [ # # ]: 0 : o_rLine.append( PDFWriterImpl::getAttributeTag( i_eAttr ) );
2705 : :
2706 [ # # ]: 0 : if( i_rVal.eValue != PDFWriter::Invalid )
2707 : : {
2708 : 0 : o_rLine.append( "/" );
2709 [ # # ]: 0 : o_rLine.append( PDFWriterImpl::getAttributeValueTag( i_rVal.eValue ) );
2710 : : }
2711 : : else
2712 : : {
2713 : : // numerical value
2714 : 0 : o_rLine.append( " " );
2715 [ # # ]: 0 : if( i_bIsFixedInt )
2716 : 0 : appendFixedInt( i_rVal.nValue, o_rLine );
2717 : : else
2718 : 0 : o_rLine.append( i_rVal.nValue );
2719 : : }
2720 : 0 : o_rLine.append( "\n" );
2721 : 0 : }
2722 : :
2723 : 0 : OString PDFWriterImpl::emitStructureAttributes( PDFStructureElement& i_rEle )
2724 : : {
2725 : : // create layout, list and table attribute sets
2726 : 0 : OStringBuffer aLayout(256), aList(64), aTable(64);
2727 [ # # ]: 0 : for( PDFStructAttributes::const_iterator it = i_rEle.m_aAttributes.begin();
2728 : 0 : it != i_rEle.m_aAttributes.end(); ++it )
2729 : : {
2730 [ # # ]: 0 : if( it->first == PDFWriter::ListNumbering )
2731 [ # # ]: 0 : appendStructureAttributeLine( it->first, it->second, aList, true );
2732 [ # # # # ]: 0 : else if( it->first == PDFWriter::RowSpan ||
[ # # ]
2733 : 0 : it->first == PDFWriter::ColSpan )
2734 [ # # ]: 0 : appendStructureAttributeLine( it->first, it->second, aTable, false );
2735 [ # # ]: 0 : else if( it->first == PDFWriter::LinkAnnotation )
2736 : : {
2737 : 0 : sal_Int32 nLink = it->second.nValue;
2738 : : std::map< sal_Int32, sal_Int32 >::const_iterator link_it =
2739 [ # # ][ # # ]: 0 : m_aLinkPropertyMap.find( nLink );
2740 [ # # ][ # # ]: 0 : if( link_it != m_aLinkPropertyMap.end() )
[ # # ]
2741 [ # # ]: 0 : nLink = link_it->second;
2742 [ # # ][ # # ]: 0 : if( nLink >= 0 && nLink < (sal_Int32)m_aLinks.size() )
[ # # ]
2743 : : {
2744 : : // update struct parent of link
2745 : 0 : OStringBuffer aStructParentEntry( 32 );
2746 [ # # ]: 0 : aStructParentEntry.append( i_rEle.m_nObject );
2747 [ # # ]: 0 : aStructParentEntry.append( " 0 R" );
2748 [ # # ]: 0 : m_aStructParentTree.push_back( aStructParentEntry.makeStringAndClear() );
2749 : 0 : m_aLinks[ nLink ].m_nStructParent = m_aStructParentTree.size()-1;
2750 : :
2751 [ # # ]: 0 : sal_Int32 nRefObject = createObject();
2752 : 0 : OStringBuffer aRef( 256 );
2753 [ # # ]: 0 : aRef.append( nRefObject );
2754 : : aRef.append( " 0 obj\n"
2755 [ # # ]: 0 : "<</Type/OBJR/Obj " );
2756 [ # # ]: 0 : aRef.append( m_aLinks[ nLink ].m_nObject );
2757 : : aRef.append( " 0 R>>\n"
2758 : : "endobj\n\n"
2759 [ # # ]: 0 : );
2760 [ # # ]: 0 : updateObject( nRefObject );
2761 [ # # ]: 0 : writeBuffer( aRef.getStr(), aRef.getLength() );
2762 : :
2763 [ # # ]: 0 : i_rEle.m_aKids.push_back( PDFStructureElementKid( nRefObject ) );
2764 : : }
2765 : : else
2766 : : {
2767 : : OSL_FAIL( "unresolved link id for Link structure" );
2768 : : #if OSL_DEBUG_LEVEL > 1
2769 : : fprintf( stderr, "unresolved link id %" SAL_PRIdINT32 " for Link structure\n", nLink );
2770 : : {
2771 : : OStringBuffer aLine( "unresolved link id " );
2772 : : aLine.append( nLink );
2773 : : aLine.append( " for Link structure" );
2774 : : emitComment( aLine.getStr() );
2775 : : }
2776 : : #endif
2777 : : }
2778 : : }
2779 : : else
2780 [ # # ]: 0 : appendStructureAttributeLine( it->first, it->second, aLayout, true );
2781 : : }
2782 [ # # ][ # # ]: 0 : if( ! i_rEle.m_aBBox.IsEmpty() )
2783 : : {
2784 [ # # ]: 0 : aLayout.append( "/BBox[" );
2785 [ # # ]: 0 : appendFixedInt( i_rEle.m_aBBox.Left(), aLayout );
2786 [ # # ]: 0 : aLayout.append( " " );
2787 [ # # ]: 0 : appendFixedInt( i_rEle.m_aBBox.Top(), aLayout );
2788 [ # # ]: 0 : aLayout.append( " " );
2789 [ # # ]: 0 : appendFixedInt( i_rEle.m_aBBox.Right(), aLayout );
2790 [ # # ]: 0 : aLayout.append( " " );
2791 [ # # ]: 0 : appendFixedInt( i_rEle.m_aBBox.Bottom(), aLayout );
2792 [ # # ]: 0 : aLayout.append( "]\n" );
2793 : : }
2794 : :
2795 [ # # ]: 0 : std::vector< sal_Int32 > aAttribObjects;
2796 [ # # ]: 0 : if( aLayout.getLength() )
2797 : : {
2798 [ # # ][ # # ]: 0 : aAttribObjects.push_back( createObject() );
2799 [ # # ][ # # ]: 0 : updateObject( aAttribObjects.back() );
2800 : 0 : OStringBuffer aObj( 64 );
2801 [ # # ][ # # ]: 0 : aObj.append( aAttribObjects.back() );
2802 : : aObj.append( " 0 obj\n"
2803 [ # # ]: 0 : "<</O/Layout\n" );
2804 [ # # ]: 0 : aLayout.append( ">>\nendobj\n\n" );
2805 [ # # ]: 0 : writeBuffer( aObj.getStr(), aObj.getLength() );
2806 [ # # ]: 0 : writeBuffer( aLayout.getStr(), aLayout.getLength() );
2807 : : }
2808 [ # # ]: 0 : if( aList.getLength() )
2809 : : {
2810 [ # # ][ # # ]: 0 : aAttribObjects.push_back( createObject() );
2811 [ # # ][ # # ]: 0 : updateObject( aAttribObjects.back() );
2812 : 0 : OStringBuffer aObj( 64 );
2813 [ # # ][ # # ]: 0 : aObj.append( aAttribObjects.back() );
2814 : : aObj.append( " 0 obj\n"
2815 [ # # ]: 0 : "<</O/List\n" );
2816 [ # # ]: 0 : aList.append( ">>\nendobj\n\n" );
2817 [ # # ]: 0 : writeBuffer( aObj.getStr(), aObj.getLength() );
2818 [ # # ]: 0 : writeBuffer( aList.getStr(), aList.getLength() );
2819 : : }
2820 [ # # ]: 0 : if( aTable.getLength() )
2821 : : {
2822 [ # # ][ # # ]: 0 : aAttribObjects.push_back( createObject() );
2823 [ # # ][ # # ]: 0 : updateObject( aAttribObjects.back() );
2824 : 0 : OStringBuffer aObj( 64 );
2825 [ # # ][ # # ]: 0 : aObj.append( aAttribObjects.back() );
2826 : : aObj.append( " 0 obj\n"
2827 [ # # ]: 0 : "<</O/Table\n" );
2828 [ # # ]: 0 : aTable.append( ">>\nendobj\n\n" );
2829 [ # # ]: 0 : writeBuffer( aObj.getStr(), aObj.getLength() );
2830 [ # # ]: 0 : writeBuffer( aTable.getStr(), aTable.getLength() );
2831 : : }
2832 : :
2833 : 0 : OStringBuffer aRet( 64 );
2834 [ # # ]: 0 : if( aAttribObjects.size() > 1 )
2835 [ # # ]: 0 : aRet.append( " [" );
2836 [ # # ]: 0 : for( std::vector< sal_Int32 >::const_iterator at_it = aAttribObjects.begin();
[ # # # # ]
[ # # ]
2837 : 0 : at_it != aAttribObjects.end(); ++at_it )
2838 : : {
2839 [ # # ]: 0 : aRet.append( " " );
2840 [ # # ][ # # ]: 0 : aRet.append( *at_it );
2841 [ # # ]: 0 : aRet.append( " 0 R" );
2842 : : }
2843 [ # # ]: 0 : if( aAttribObjects.size() > 1 )
2844 [ # # ]: 0 : aRet.append( " ]" );
2845 : 0 : return aRet.makeStringAndClear();
2846 : : }
2847 : :
2848 : 0 : sal_Int32 PDFWriterImpl::emitStructure( PDFStructureElement& rEle )
2849 : : {
2850 [ # # ][ # # ]: 0 : if(
2851 : : // do not emit NonStruct and its children
2852 : : rEle.m_eType == PDFWriter::NonStructElement &&
2853 : : rEle.m_nOwnElement != rEle.m_nParentElement // but of course emit the struct tree root
2854 : : )
2855 : 0 : return 0;
2856 : :
2857 [ # # ][ # # ]: 0 : for( std::list< sal_Int32 >::const_iterator it = rEle.m_aChildren.begin(); it != rEle.m_aChildren.end(); ++it )
[ # # ][ # # ]
[ # # ]
2858 : : {
2859 [ # # ][ # # ]: 0 : if( *it > 0 && *it < sal_Int32(m_aStructure.size()) )
[ # # ][ # # ]
[ # # ]
2860 : : {
2861 [ # # ]: 0 : PDFStructureElement& rChild = m_aStructure[ *it ];
2862 [ # # ]: 0 : if( rChild.m_eType != PDFWriter::NonStructElement )
2863 : : {
2864 [ # # ]: 0 : if( rChild.m_nParentElement == rEle.m_nOwnElement )
2865 [ # # ]: 0 : emitStructure( rChild );
2866 : : else
2867 : : {
2868 : : OSL_FAIL( "PDFWriterImpl::emitStructure: invalid child structure element" );
2869 : : #if OSL_DEBUG_LEVEL > 1
2870 : : fprintf( stderr, "PDFWriterImpl::emitStructure: invalid child structure elemnt with id %" SAL_PRIdINT32 "\n", *it );
2871 : : #endif
2872 : : }
2873 : : }
2874 : : }
2875 : : else
2876 : : {
2877 : : OSL_FAIL( "PDFWriterImpl::emitStructure: invalid child structure id" );
2878 : : #if OSL_DEBUG_LEVEL > 1
2879 : : fprintf( stderr, "PDFWriterImpl::emitStructure: invalid child structure id %" SAL_PRIdINT32 "\n", *it );
2880 : : #endif
2881 : : }
2882 : : }
2883 : :
2884 : 0 : OStringBuffer aLine( 512 );
2885 [ # # ]: 0 : aLine.append( rEle.m_nObject );
2886 : : aLine.append( " 0 obj\n"
2887 [ # # ]: 0 : "<</Type" );
2888 : 0 : sal_Int32 nParentTree = -1;
2889 [ # # ]: 0 : if( rEle.m_nOwnElement == rEle.m_nParentElement )
2890 : : {
2891 [ # # ]: 0 : nParentTree = createObject();
2892 [ # # ]: 0 : CHECK_RETURN( nParentTree );
2893 [ # # ]: 0 : aLine.append( "/StructTreeRoot\n" );
2894 [ # # ]: 0 : aLine.append( "/ParentTree " );
2895 [ # # ]: 0 : aLine.append( nParentTree );
2896 [ # # ]: 0 : aLine.append( " 0 R\n" );
2897 [ # # ]: 0 : if( ! m_aRoleMap.empty() )
2898 : : {
2899 [ # # ]: 0 : aLine.append( "/RoleMap<<" );
2900 [ # # ]: 0 : for( boost::unordered_map<OString,OString,OStringHash>::const_iterator
2901 [ # # ][ # # ]: 0 : it = m_aRoleMap.begin(); it != m_aRoleMap.end(); ++it )
2902 : : {
2903 [ # # ]: 0 : aLine.append( '/' );
2904 [ # # ][ # # ]: 0 : aLine.append(it->first);
2905 [ # # ]: 0 : aLine.append( '/' );
2906 [ # # ][ # # ]: 0 : aLine.append( it->second );
2907 [ # # ]: 0 : aLine.append( '\n' );
2908 : : }
2909 [ # # ]: 0 : aLine.append( ">>\n" );
2910 : : }
2911 : : }
2912 : : else
2913 : : {
2914 : : aLine.append( "/StructElem\n"
2915 [ # # ]: 0 : "/S/" );
2916 [ # # ]: 0 : if( !rEle.m_aAlias.isEmpty() )
2917 [ # # ]: 0 : aLine.append( rEle.m_aAlias );
2918 : : else
2919 [ # # ][ # # ]: 0 : aLine.append( getStructureTag( rEle.m_eType ) );
2920 : : aLine.append( "\n"
2921 [ # # ]: 0 : "/P " );
2922 [ # # ]: 0 : aLine.append( m_aStructure[ rEle.m_nParentElement ].m_nObject );
2923 : : aLine.append( " 0 R\n"
2924 [ # # ]: 0 : "/Pg " );
2925 [ # # ]: 0 : aLine.append( rEle.m_nFirstPageObject );
2926 [ # # ]: 0 : aLine.append( " 0 R\n" );
2927 [ # # ]: 0 : if( !rEle.m_aActualText.isEmpty() )
2928 : : {
2929 [ # # ]: 0 : aLine.append( "/ActualText" );
2930 [ # # ]: 0 : appendUnicodeTextStringEncrypt( rEle.m_aActualText, rEle.m_nObject, aLine );
2931 [ # # ]: 0 : aLine.append( "\n" );
2932 : : }
2933 [ # # ]: 0 : if( !rEle.m_aAltText.isEmpty() )
2934 : : {
2935 [ # # ]: 0 : aLine.append( "/Alt" );
2936 [ # # ]: 0 : appendUnicodeTextStringEncrypt( rEle.m_aAltText, rEle.m_nObject, aLine );
2937 [ # # ]: 0 : aLine.append( "\n" );
2938 : : }
2939 : : }
2940 [ # # ][ # # ]: 0 : if( ! rEle.m_aBBox.IsEmpty() || rEle.m_aAttributes.size() )
[ # # ][ # # ]
2941 : : {
2942 [ # # ]: 0 : OString aAttribs = emitStructureAttributes( rEle );
2943 [ # # ]: 0 : if( !aAttribs.isEmpty() )
2944 : : {
2945 [ # # ]: 0 : aLine.append( "/A" );
2946 [ # # ]: 0 : aLine.append( aAttribs );
2947 [ # # ]: 0 : aLine.append( "\n" );
2948 : 0 : }
2949 : : }
2950 [ # # ]: 0 : if( !rEle.m_aLocale.Language.isEmpty() )
2951 : : {
2952 : 0 : OUStringBuffer aLocBuf( 16 );
2953 [ # # ]: 0 : aLocBuf.append( rEle.m_aLocale.Language.toAsciiLowerCase() );
2954 [ # # ]: 0 : if( !rEle.m_aLocale.Country.isEmpty() )
2955 : : {
2956 [ # # ]: 0 : aLocBuf.append( sal_Unicode('-') );
2957 [ # # ]: 0 : aLocBuf.append( rEle.m_aLocale.Country );
2958 : : }
2959 [ # # ]: 0 : aLine.append( "/Lang" );
2960 [ # # ][ # # ]: 0 : appendLiteralStringEncrypt( aLocBuf.makeStringAndClear(), rEle.m_nObject, aLine );
2961 [ # # ]: 0 : aLine.append( "\n" );
2962 : : }
2963 [ # # ]: 0 : if( ! rEle.m_aKids.empty() )
2964 : : {
2965 : 0 : unsigned int i = 0;
2966 [ # # ]: 0 : aLine.append( "/K[" );
2967 [ # # ]: 0 : for( std::list< PDFStructureElementKid >::const_iterator it =
2968 : 0 : rEle.m_aKids.begin(); it != rEle.m_aKids.end(); ++it, i++ )
2969 : : {
2970 [ # # ]: 0 : if( it->nMCID == -1 )
2971 : : {
2972 [ # # ]: 0 : aLine.append( it->nObject );
2973 [ # # ]: 0 : aLine.append( " 0 R" );
2974 [ # # ][ # # ]: 0 : aLine.append( ( (i & 15) == 15 ) ? "\n" : " " );
2975 : : }
2976 : : else
2977 : : {
2978 [ # # ]: 0 : if( it->nObject == rEle.m_nFirstPageObject )
2979 : : {
2980 [ # # ]: 0 : aLine.append( it->nMCID );
2981 [ # # ]: 0 : aLine.append( " " );
2982 : : }
2983 : : else
2984 : : {
2985 [ # # ]: 0 : aLine.append( "<</Type/MCR/Pg " );
2986 [ # # ]: 0 : aLine.append( it->nObject );
2987 [ # # ]: 0 : aLine.append( " 0 R /MCID " );
2988 [ # # ]: 0 : aLine.append( it->nMCID );
2989 [ # # ]: 0 : aLine.append( ">>\n" );
2990 : : }
2991 : : }
2992 : : }
2993 [ # # ]: 0 : aLine.append( "]\n" );
2994 : : }
2995 [ # # ]: 0 : aLine.append( ">>\nendobj\n\n" );
2996 : :
2997 [ # # ][ # # ]: 0 : CHECK_RETURN( updateObject( rEle.m_nObject ) );
2998 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
2999 : :
3000 [ # # ][ # # ]: 0 : CHECK_RETURN( emitStructParentTree( nParentTree ) );
3001 : :
3002 : 0 : return rEle.m_nObject;
3003 : : }
3004 : :
3005 : 0 : bool PDFWriterImpl::emitGradients()
3006 : : {
3007 [ # # ]: 0 : for( std::list<GradientEmit>::iterator it = m_aGradients.begin();
3008 : 0 : it != m_aGradients.end(); ++it )
3009 : : {
3010 [ # # ][ # # ]: 0 : CHECK_RETURN( writeGradientFunction( *it ) );
3011 : : }
3012 : 0 : return true;
3013 : : }
3014 : :
3015 : 0 : bool PDFWriterImpl::emitTilings()
3016 : : {
3017 : 0 : OStringBuffer aTilingObj( 1024 );
3018 : :
3019 [ # # ][ # # ]: 0 : for( std::vector<TilingEmit>::iterator it = m_aTilings.begin(); it != m_aTilings.end(); ++it )
3020 : : {
3021 : : DBG_ASSERT( it->m_pTilingStream, "tiling without stream" );
3022 [ # # ]: 0 : if( ! it->m_pTilingStream )
3023 : 0 : continue;
3024 : :
3025 [ # # ]: 0 : aTilingObj.setLength( 0 );
3026 : :
3027 : : #if OSL_DEBUG_LEVEL > 1
3028 : : emitComment( "PDFWriterImpl::emitTilings" );
3029 : : #endif
3030 : :
3031 : 0 : sal_Int32 nX = (sal_Int32)it->m_aRectangle.Left();
3032 : 0 : sal_Int32 nY = (sal_Int32)it->m_aRectangle.Top();
3033 [ # # ]: 0 : sal_Int32 nW = (sal_Int32)it->m_aRectangle.GetWidth();
3034 [ # # ]: 0 : sal_Int32 nH = (sal_Int32)it->m_aRectangle.GetHeight();
3035 [ # # ]: 0 : if( it->m_aCellSize.Width() == 0 )
3036 : 0 : it->m_aCellSize.Width() = nW;
3037 [ # # ]: 0 : if( it->m_aCellSize.Height() == 0 )
3038 : 0 : it->m_aCellSize.Height() = nH;
3039 : :
3040 [ # # ]: 0 : bool bDeflate = compressStream( it->m_pTilingStream );
3041 [ # # ]: 0 : it->m_pTilingStream->Seek( STREAM_SEEK_TO_END );
3042 : 0 : sal_Size nTilingStreamSize = it->m_pTilingStream->Tell();
3043 [ # # ]: 0 : it->m_pTilingStream->Seek( STREAM_SEEK_TO_BEGIN );
3044 : :
3045 : : // write pattern object
3046 [ # # ]: 0 : aTilingObj.append( it->m_nObject );
3047 [ # # ]: 0 : aTilingObj.append( " 0 obj\n" );
3048 : : aTilingObj.append( "<</Type/Pattern/PatternType 1\n"
3049 : : "/PaintType 1\n"
3050 : : "/TilingType 2\n"
3051 [ # # ]: 0 : "/BBox[" );
3052 [ # # ]: 0 : appendFixedInt( nX, aTilingObj );
3053 [ # # ]: 0 : aTilingObj.append( ' ' );
3054 [ # # ]: 0 : appendFixedInt( nY, aTilingObj );
3055 [ # # ]: 0 : aTilingObj.append( ' ' );
3056 [ # # ]: 0 : appendFixedInt( nX+nW, aTilingObj );
3057 [ # # ]: 0 : aTilingObj.append( ' ' );
3058 [ # # ]: 0 : appendFixedInt( nY+nH, aTilingObj );
3059 : : aTilingObj.append( "]\n"
3060 [ # # ]: 0 : "/XStep " );
3061 [ # # ]: 0 : appendFixedInt( it->m_aCellSize.Width(), aTilingObj );
3062 : : aTilingObj.append( "\n"
3063 [ # # ]: 0 : "/YStep " );
3064 [ # # ]: 0 : appendFixedInt( it->m_aCellSize.Height(), aTilingObj );
3065 [ # # ]: 0 : aTilingObj.append( "\n" );
3066 [ # # # # : 0 : if( it->m_aTransform.matrix[0] != 1.0 ||
# # # # #
# # # ]
[ # # ]
3067 : 0 : it->m_aTransform.matrix[1] != 0.0 ||
3068 : 0 : it->m_aTransform.matrix[3] != 0.0 ||
3069 : 0 : it->m_aTransform.matrix[4] != 1.0 ||
3070 : 0 : it->m_aTransform.matrix[2] != 0.0 ||
3071 : 0 : it->m_aTransform.matrix[5] != 0.0 )
3072 : : {
3073 [ # # ]: 0 : aTilingObj.append( "/Matrix [" );
3074 : : // TODO: scaling, mirroring on y, etc
3075 [ # # ]: 0 : appendDouble( it->m_aTransform.matrix[0], aTilingObj );
3076 [ # # ]: 0 : aTilingObj.append( ' ' );
3077 [ # # ]: 0 : appendDouble( it->m_aTransform.matrix[1], aTilingObj );
3078 [ # # ]: 0 : aTilingObj.append( ' ' );
3079 [ # # ]: 0 : appendDouble( it->m_aTransform.matrix[3], aTilingObj );
3080 [ # # ]: 0 : aTilingObj.append( ' ' );
3081 [ # # ]: 0 : appendDouble( it->m_aTransform.matrix[4], aTilingObj );
3082 [ # # ]: 0 : aTilingObj.append( ' ' );
3083 [ # # ]: 0 : appendDouble( it->m_aTransform.matrix[2], aTilingObj );
3084 [ # # ]: 0 : aTilingObj.append( ' ' );
3085 [ # # ]: 0 : appendDouble( it->m_aTransform.matrix[5], aTilingObj );
3086 [ # # ]: 0 : aTilingObj.append( "]\n" );
3087 : : }
3088 [ # # ]: 0 : aTilingObj.append( "/Resources" );
3089 [ # # ][ # # ]: 0 : it->m_aResources.append( aTilingObj, getFontDictObject() );
3090 [ # # ]: 0 : if( bDeflate )
3091 [ # # ]: 0 : aTilingObj.append( "/Filter/FlateDecode" );
3092 [ # # ]: 0 : aTilingObj.append( "/Length " );
3093 [ # # ]: 0 : aTilingObj.append( (sal_Int32)nTilingStreamSize );
3094 [ # # ]: 0 : aTilingObj.append( ">>\nstream\n" );
3095 [ # # ][ # # ]: 0 : CHECK_RETURN( updateObject( it->m_nObject ) );
3096 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aTilingObj.getStr(), aTilingObj.getLength() ) );
3097 [ # # ]: 0 : checkAndEnableStreamEncryption( it->m_nObject );
3098 [ # # ][ # # ]: 0 : nTilingStreamSize = writeBuffer( it->m_pTilingStream->GetData(), nTilingStreamSize );
3099 [ # # ][ # # ]: 0 : delete it->m_pTilingStream;
3100 : 0 : it->m_pTilingStream = NULL;
3101 [ # # ]: 0 : if( nTilingStreamSize == 0 )
3102 : 0 : return false;
3103 : 0 : disableStreamEncryption();
3104 [ # # ]: 0 : aTilingObj.setLength( 0 );
3105 [ # # ]: 0 : aTilingObj.append( "\nendstream\nendobj\n\n" );
3106 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aTilingObj.getStr(), aTilingObj.getLength() ) );
3107 : : }
3108 : 0 : return true;
3109 : : }
3110 : :
3111 : 0 : sal_Int32 PDFWriterImpl::emitBuiltinFont( const PhysicalFontFace* pFont, sal_Int32 nFontObject )
3112 : : {
3113 : 0 : const ImplPdfBuiltinFontData* pFD = GetPdfFontData( pFont );
3114 [ # # ]: 0 : if( !pFD )
3115 : 0 : return 0;
3116 : 0 : const BuiltinFont* pBuiltinFont = pFD->GetBuiltinFont();
3117 : :
3118 : 0 : OStringBuffer aLine( 1024 );
3119 : :
3120 [ # # ]: 0 : if( nFontObject <= 0 )
3121 [ # # ]: 0 : nFontObject = createObject();
3122 [ # # ][ # # ]: 0 : CHECK_RETURN( updateObject( nFontObject ) );
3123 [ # # ]: 0 : aLine.append( nFontObject );
3124 : : aLine.append( " 0 obj\n"
3125 [ # # ]: 0 : "<</Type/Font/Subtype/Type1/BaseFont/" );
3126 [ # # ]: 0 : appendName( pBuiltinFont->m_pPSName, aLine );
3127 [ # # ]: 0 : aLine.append( "\n" );
3128 [ # # ]: 0 : if( pBuiltinFont->m_eCharSet == RTL_TEXTENCODING_MS_1252 )
3129 [ # # ]: 0 : aLine.append( "/Encoding/WinAnsiEncoding\n" );
3130 [ # # ]: 0 : aLine.append( ">>\nendobj\n\n" );
3131 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
3132 : 0 : return nFontObject;
3133 : : }
3134 : :
3135 : 0 : std::map< sal_Int32, sal_Int32 > PDFWriterImpl::emitSystemFont( const PhysicalFontFace* pFont, EmbedFont& rEmbed )
3136 : : {
3137 [ # # ]: 0 : std::map< sal_Int32, sal_Int32 > aRet;
3138 [ # # ]: 0 : if( isBuiltinFont( pFont ) )
3139 : : {
3140 [ # # ][ # # ]: 0 : aRet[ rEmbed.m_nNormalFontID ] = emitBuiltinFont( pFont );
3141 : : return aRet;
3142 : : }
3143 : :
3144 : 0 : sal_Int32 nFontDescriptor = 0;
3145 : 0 : rtl::OString aSubType( "/Type1" );
3146 [ # # ]: 0 : FontSubsetInfo aInfo;
3147 : : // fill in dummy values
3148 : 0 : aInfo.m_nAscent = 1000;
3149 : 0 : aInfo.m_nDescent = 200;
3150 : 0 : aInfo.m_nCapHeight = 1000;
3151 [ # # ]: 0 : aInfo.m_aFontBBox = Rectangle( Point( -200, -200 ), Size( 1700, 1700 ) );
3152 [ # # ]: 0 : aInfo.m_aPSName = pFont->maName;
3153 : : sal_Int32 pWidths[256];
3154 : 0 : memset( pWidths, 0, sizeof(pWidths) );
3155 [ # # ]: 0 : if( pFont->IsEmbeddable() )
3156 : : {
3157 : 0 : const unsigned char* pFontData = NULL;
3158 : 0 : long nFontLen = 0;
3159 : : sal_Ucs nEncodedCodes[256];
3160 : : sal_Int32 pEncWidths[256];
3161 [ # # ][ # # ]: 0 : if( (pFontData = (const unsigned char*)m_pReferenceDevice->mpGraphics->GetEmbedFontData( pFont, nEncodedCodes, pEncWidths, aInfo, &nFontLen )) != NULL )
3162 : : {
3163 [ # # ]: 0 : m_pReferenceDevice->mpGraphics->FreeEmbedFontData( pFontData, nFontLen );
3164 [ # # ]: 0 : for( int i = 0; i < 256; i++ )
3165 : : {
3166 [ # # ][ # # ]: 0 : if( nEncodedCodes[i] >= 32 && nEncodedCodes[i] < 256 )
3167 : : {
3168 : 0 : pWidths[i] = pEncWidths[ i ];
3169 : : }
3170 : : }
3171 : : }
3172 : : }
3173 [ # # ]: 0 : else if( pFont->mbSubsettable )
3174 : : {
3175 : 0 : aSubType = rtl::OString( "/TrueType" );
3176 [ # # ]: 0 : Int32Vector aGlyphWidths;
3177 [ # # ]: 0 : Ucs2UIntMap aUnicodeMap;
3178 [ # # ]: 0 : m_pReferenceDevice->mpGraphics->GetGlyphWidths( pFont, false, aGlyphWidths, aUnicodeMap );
3179 : :
3180 : 0 : OUString aTmpName;
3181 [ # # ]: 0 : osl_createTempFile( NULL, NULL, &aTmpName.pData );
3182 : : sal_Int32 pGlyphIDs[ 256 ];
3183 : : sal_uInt8 pEncoding[ 256 ];
3184 : : sal_Ucs pUnicodes[ 256 ];
3185 : : sal_Int32 pDuWidths[ 256 ];
3186 : :
3187 : 0 : memset( pGlyphIDs, 0, sizeof( pGlyphIDs ) );
3188 : 0 : memset( pEncoding, 0, sizeof( pEncoding ) );
3189 : 0 : memset( pUnicodes, 0, sizeof( pUnicodes ) );
3190 : 0 : memset( pDuWidths, 0, sizeof( pDuWidths ) );
3191 : :
3192 [ # # ]: 0 : for( sal_Ucs c = 32; c < 256; c++ )
3193 : : {
3194 : 0 : pUnicodes[c] = c;
3195 : 0 : pEncoding[c] = c;
3196 : 0 : pGlyphIDs[c] = 0;
3197 [ # # ][ # # ]: 0 : if( aUnicodeMap.find( c ) != aUnicodeMap.end() )
[ # # ]
3198 [ # # ][ # # ]: 0 : pWidths[ c ] = aGlyphWidths[ aUnicodeMap[ c ] ];
3199 : : }
3200 : :
3201 [ # # ]: 0 : m_pReferenceDevice->mpGraphics->CreateFontSubset( aTmpName, pFont, pGlyphIDs, pEncoding, pDuWidths, 256, aInfo );
3202 [ # # ]: 0 : osl_removeFile( aTmpName.pData );
3203 : : }
3204 : : else
3205 : : {
3206 : : OSL_FAIL( "system font neither embeddable nor subsettable" );
3207 : : }
3208 : :
3209 : : // write font descriptor
3210 [ # # ]: 0 : nFontDescriptor = emitFontDescriptor( pFont, aInfo, 0, 0 );
3211 [ # # ]: 0 : if( nFontDescriptor )
3212 : : {
3213 : : // write font object
3214 [ # # ]: 0 : sal_Int32 nObject = createObject();
3215 [ # # ][ # # ]: 0 : if( updateObject( nObject ) )
3216 : : {
3217 : 0 : OStringBuffer aLine( 1024 );
3218 [ # # ]: 0 : aLine.append( nObject );
3219 : : aLine.append( " 0 obj\n"
3220 [ # # ]: 0 : "<</Type/Font/Subtype" );
3221 [ # # ]: 0 : aLine.append( aSubType );
3222 [ # # ]: 0 : aLine.append( "/BaseFont/" );
3223 [ # # ][ # # ]: 0 : appendName( aInfo.m_aPSName, aLine );
3224 [ # # ]: 0 : aLine.append( "\n" );
3225 [ # # ]: 0 : if( !pFont->mbSymbolFlag )
3226 [ # # ]: 0 : aLine.append( "/Encoding/WinAnsiEncoding\n" );
3227 : : aLine.append( "/FirstChar 32 /LastChar 255\n"
3228 [ # # ]: 0 : "/Widths[" );
3229 [ # # ]: 0 : for( int i = 32; i < 256; i++ )
3230 : : {
3231 [ # # ]: 0 : aLine.append( pWidths[i] );
3232 [ # # ][ # # ]: 0 : aLine.append( ((i&15) == 15) ? "\n" : " " );
3233 : : }
3234 : : aLine.append( "]\n"
3235 [ # # ]: 0 : "/FontDescriptor " );
3236 [ # # ]: 0 : aLine.append( nFontDescriptor );
3237 : : aLine.append( " 0 R>>\n"
3238 [ # # ]: 0 : "endobj\n\n" );
3239 [ # # ]: 0 : writeBuffer( aLine.getStr(), aLine.getLength() );
3240 : :
3241 [ # # ]: 0 : aRet[ rEmbed.m_nNormalFontID ] = nObject;
3242 : : }
3243 : : }
3244 : :
3245 [ # # ]: 0 : return aRet;
3246 : : }
3247 : :
3248 : : typedef int ThreeInts[3];
3249 : 0 : static bool getPfbSegmentLengths( const unsigned char* pFontBytes, int nByteLen,
3250 : : ThreeInts& rSegmentLengths )
3251 : : {
3252 [ # # ][ # # ]: 0 : if( !pFontBytes || (nByteLen < 0) )
3253 : 0 : return false;
3254 : 0 : const unsigned char* pPtr = pFontBytes;
3255 : 0 : const unsigned char* pEnd = pFontBytes + nByteLen;
3256 : :
3257 [ # # ]: 0 : for( int i = 0; i < 3; ++i) {
3258 : : // read segment1 header
3259 [ # # ]: 0 : if( pPtr+6 >= pEnd )
3260 : 0 : return false;
3261 [ # # ][ # # ]: 0 : if( (pPtr[0] != 0x80) || (pPtr[1] >= 0x03) )
3262 : 0 : return false;
3263 : 0 : const int nLen = (pPtr[5]<<24) + (pPtr[4]<<16) + (pPtr[3]<<8) + pPtr[2];
3264 [ # # ]: 0 : if( nLen <= 0)
3265 : 0 : return false;
3266 : 0 : rSegmentLengths[i] = nLen;
3267 : 0 : pPtr += nLen + 6;
3268 : : }
3269 : :
3270 : : // read segment-end header
3271 [ # # ]: 0 : if( pPtr+2 >= pEnd )
3272 : 0 : return false;
3273 [ # # ][ # # ]: 0 : if( (pPtr[0] != 0x80) || (pPtr[1] != 0x03) )
3274 : 0 : return false;
3275 : :
3276 : 0 : return true;
3277 : : }
3278 : :
3279 [ # # ]: 0 : struct FontException : public std::exception
3280 : : {
3281 : : };
3282 : :
3283 : : // TODO: always subset instead of embedding the full font => this method becomes obsolete then
3284 : 0 : std::map< sal_Int32, sal_Int32 > PDFWriterImpl::emitEmbeddedFont( const PhysicalFontFace* pFont, EmbedFont& rEmbed )
3285 : : {
3286 [ # # ]: 0 : std::map< sal_Int32, sal_Int32 > aRet;
3287 [ # # ]: 0 : if( isBuiltinFont( pFont ) )
3288 : : {
3289 [ # # ][ # # ]: 0 : aRet[ rEmbed.m_nNormalFontID ] = emitBuiltinFont( pFont );
3290 : : return aRet;
3291 : : }
3292 : :
3293 : 0 : sal_Int32 nStreamObject = 0;
3294 : 0 : sal_Int32 nFontDescriptor = 0;
3295 : :
3296 : : // prepare font encoding
3297 [ # # ]: 0 : const Ucs2SIntMap* pEncoding = m_pReferenceDevice->mpGraphics->GetFontEncodingVector( pFont, NULL );
3298 : 0 : sal_Int32 nToUnicodeStream = 0;
3299 : : sal_uInt8 nEncoding[256];
3300 : : sal_Ucs nEncodedCodes[256];
3301 [ # # ]: 0 : std::vector<sal_Ucs> aUnicodes;
3302 [ # # ]: 0 : aUnicodes.reserve( 256 );
3303 : : sal_Int32 pUnicodesPerGlyph[256];
3304 : : sal_Int32 pEncToUnicodeIndex[256];
3305 [ # # ]: 0 : if( pEncoding )
3306 : : {
3307 : 0 : memset( nEncoding, 0, sizeof(nEncoding) );
3308 : 0 : memset( nEncodedCodes, 0, sizeof(nEncodedCodes) );
3309 : 0 : memset( pUnicodesPerGlyph, 0, sizeof(pUnicodesPerGlyph) );
3310 : 0 : memset( pEncToUnicodeIndex, 0, sizeof(pEncToUnicodeIndex) );
3311 [ # # ][ # # ]: 0 : for( Ucs2SIntMap::const_iterator it = pEncoding->begin(); it != pEncoding->end(); ++it )
[ # # ]
3312 : : {
3313 [ # # ][ # # ]: 0 : if( it->second != -1 )
3314 : : {
3315 [ # # ]: 0 : sal_Int32 nCode = (sal_Int32)(it->second & 0x000000ff);
3316 : 0 : nEncoding[ nCode ] = static_cast<sal_uInt8>( nCode );
3317 [ # # ]: 0 : nEncodedCodes[ nCode ] = it->first;
3318 : 0 : pEncToUnicodeIndex[ nCode ] = static_cast<sal_Int32>(aUnicodes.size());
3319 [ # # ][ # # ]: 0 : aUnicodes.push_back( it->first );
3320 : 0 : pUnicodesPerGlyph[ nCode ] = 1;
3321 : : }
3322 : : }
3323 : : }
3324 : :
3325 [ # # ]: 0 : FontSubsetInfo aInfo;
3326 : : sal_Int32 pWidths[256];
3327 : 0 : const unsigned char* pFontData = NULL;
3328 : 0 : long nFontLen = 0;
3329 : : sal_Int32 nLength1, nLength2;
3330 : : try
3331 : : {
3332 [ # # ][ # # ]: 0 : if( (pFontData = (const unsigned char*)m_pReferenceDevice->mpGraphics->GetEmbedFontData( pFont, nEncodedCodes, pWidths, aInfo, &nFontLen )) != NULL )
3333 : : {
3334 [ # # ]: 0 : if( (aInfo.m_nFontType & FontSubsetInfo::ANY_TYPE1) == 0 )
3335 : 0 : throw FontException();
3336 : : // see whether it is pfb or pfa; if it is a pfb, fill ranges
3337 : : // of 6 bytes that are not part of the font program
3338 [ # # ]: 0 : std::list< int > aSections;
3339 [ # # ]: 0 : std::list< int >::const_iterator it;
3340 : 0 : int nIndex = 0;
3341 [ # # ][ # # ]: 0 : while( (nIndex < nFontLen-1) && pFontData[nIndex] == 0x80 )
[ # # ]
3342 : : {
3343 [ # # ]: 0 : aSections.push_back( nIndex );
3344 [ # # ]: 0 : if( pFontData[nIndex+1] == 0x03 )
3345 : 0 : break;
3346 : : sal_Int32 nBytes =
3347 : 0 : ((sal_Int32)pFontData[nIndex+2]) |
3348 : 0 : ((sal_Int32)pFontData[nIndex+3]) << 8 |
3349 : 0 : ((sal_Int32)pFontData[nIndex+4]) << 16 |
3350 : 0 : ((sal_Int32)pFontData[nIndex+5]) << 24;
3351 : 0 : nIndex += nBytes+6;
3352 : : }
3353 : :
3354 : : // search for eexec
3355 : : // TODO: use getPfbSegmentLengths() if possible to skip the search thingies below
3356 : 0 : nIndex = 0;
3357 : : int nEndAsciiIndex;
3358 : : int nBeginBinaryIndex;
3359 : : int nEndBinaryIndex;
3360 [ # # ][ # # ]: 0 : do
[ # # ]
3361 : : {
3362 [ # # ][ # # ]: 0 : while( nIndex < nFontLen-4 &&
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
3363 : 0 : ( pFontData[nIndex] != 'e' ||
3364 : 0 : pFontData[nIndex+1] != 'e' ||
3365 : 0 : pFontData[nIndex+2] != 'x' ||
3366 : 0 : pFontData[nIndex+3] != 'e' ||
3367 : 0 : pFontData[nIndex+4] != 'c'
3368 : : )
3369 : : )
3370 : 0 : nIndex++;
3371 : : // check whether we are in a excluded section
3372 [ # # ][ # # ]: 0 : for( it = aSections.begin(); it != aSections.end() && (nIndex < *it || nIndex > ((*it) + 5) ); ++it )
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # #
# # # # ]
3373 : : ;
3374 [ # # ][ # # ]: 0 : } while( it != aSections.end() && nIndex < nFontLen-4 );
[ # # ][ # # ]
[ # # # # ]
3375 : : // this should end the ascii part
3376 [ # # ]: 0 : if( nIndex > nFontLen-5 )
3377 : 0 : throw FontException();
3378 : :
3379 : 0 : nEndAsciiIndex = nIndex+4;
3380 : : // now count backwards until we can account for 512 '0'
3381 : : // which is the endmarker of the (hopefully) binary data
3382 : : // do not count the pfb header sections
3383 : 0 : int nFound = 0;
3384 : 0 : nIndex = nFontLen-1;
3385 [ # # ][ # # ]: 0 : while( nIndex > 0 && nFound < 512 )
[ # # ]
3386 : : {
3387 [ # # ][ # # ]: 0 : for( it = aSections.begin(); it != aSections.end() && (nIndex < *it || nIndex > ((*it) + 5) ); ++it )
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # #
# # # # ]
3388 : : ;
3389 [ # # ][ # # ]: 0 : if( it == aSections.end() )
[ # # ]
3390 : : {
3391 : : // inside the 512 '0' block there may only be whitespace
3392 : : // according to T1 spec; probably it would be to simple
3393 : : // if all fonts complied
3394 [ # # ]: 0 : if( pFontData[nIndex] == '0' )
3395 : 0 : nFound++;
3396 [ # # ][ # # ]: 0 : else if( nFound > 0 &&
[ # # ][ # # ]
[ # # ]
3397 : 0 : pFontData[nIndex] != '\r' &&
3398 : 0 : pFontData[nIndex] != '\t' &&
3399 : 0 : pFontData[nIndex] != '\n' &&
3400 : 0 : pFontData[nIndex] != ' ' )
3401 : 0 : break;
3402 : : }
3403 : 0 : nIndex--;
3404 : : }
3405 : :
3406 [ # # ][ # # ]: 0 : if( nIndex < 1 || nIndex <= nEndAsciiIndex )
3407 : 0 : throw FontException();
3408 : :
3409 : : // nLength3 is the rest of the file - excluding any section headers
3410 : : // nIndex now points before the first of the 512 '0' characters marking the
3411 : : // fixed content portion
3412 : 0 : sal_Int32 nLength3 = nFontLen - nIndex - 1;
3413 [ # # ][ # # ]: 0 : for( it = aSections.begin(); it != aSections.end(); ++it )
[ # # ][ # # ]
[ # # ]
3414 : : {
3415 [ # # ][ # # ]: 0 : if( *it >= nIndex )
3416 : : {
3417 : : // special case: nIndex inside a section marker
3418 [ # # ][ # # ]: 0 : if( nIndex >= (*it) && (*it)+5 > nIndex )
[ # # ][ # # ]
[ # # ]
3419 [ # # ]: 0 : nLength3 -= (*it)+5 - nIndex;
3420 : : else
3421 : : {
3422 [ # # ][ # # ]: 0 : if( *it < nFontLen - 6 )
3423 : 0 : nLength3 -= 6;
3424 : : else // the last section 0x8003 is only 2 bytes after all
3425 [ # # ]: 0 : nLength3 -= (nFontLen - *it);
3426 : : }
3427 : : }
3428 : : }
3429 : :
3430 : : // there may be whitespace to ignore before the 512 '0'
3431 [ # # ][ # # ]: 0 : while( pFontData[nIndex] == '\r' || pFontData[nIndex] == '\n' )
[ # # ]
3432 : : {
3433 : 0 : nIndex--;
3434 [ # # ][ # # ]: 0 : for( it = aSections.begin(); it != aSections.end() && (nIndex < *it || nIndex > ((*it) + 5) ); ++it )
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # #
# # # # ]
3435 : : ;
3436 [ # # ][ # # ]: 0 : if( it != aSections.end() )
[ # # ]
3437 : : {
3438 [ # # ]: 0 : nIndex = (*it)-1;
3439 : 0 : break; // this is surely a binary boundary, in ascii case it wouldn't matter
3440 : : }
3441 : : }
3442 : 0 : nEndBinaryIndex = nIndex;
3443 : :
3444 : : // search for beginning of binary section
3445 : 0 : nBeginBinaryIndex = nEndAsciiIndex;
3446 [ # # ][ # # ]: 0 : do
[ # # ][ # # ]
[ # # ]
3447 : : {
3448 : 0 : nBeginBinaryIndex++;
3449 [ # # ][ # # ]: 0 : for( it = aSections.begin(); it != aSections.end() && (nBeginBinaryIndex < *it || nBeginBinaryIndex > ((*it) + 5) ); ++it )
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # #
# # # # ]
3450 : : ;
3451 : : } while( nBeginBinaryIndex < nEndBinaryIndex &&
3452 : 0 : ( pFontData[nBeginBinaryIndex] == '\r' ||
3453 : 0 : pFontData[nBeginBinaryIndex] == '\n' ||
3454 [ # # ][ # # ]: 0 : it != aSections.end() ) );
[ # # ][ # # ]
[ # # # # ]
3455 : :
3456 : : // it seems to be vital to copy the exact whitespace between binary data
3457 : : // and eexec, else a invalid font results. so make nEndAsciiIndex
3458 : : // always immediate in front of nBeginBinaryIndex
3459 : 0 : nEndAsciiIndex = nBeginBinaryIndex-1;
3460 [ # # ][ # # ]: 0 : for( it = aSections.begin(); it != aSections.end() && (nEndAsciiIndex < *it || nEndAsciiIndex > ((*it)+5)); ++it )
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # #
# # # # ]
3461 : : ;
3462 [ # # ][ # # ]: 0 : if( it != aSections.end() )
[ # # ]
3463 [ # # ]: 0 : nEndAsciiIndex = (*it)-1;
3464 : :
3465 : 0 : nLength1 = nEndAsciiIndex+1; // including the last character
3466 [ # # ][ # # ]: 0 : for( it = aSections.begin(); it != aSections.end() && *it < nEndAsciiIndex; ++it )
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # #
# # # # ]
3467 : 0 : nLength1 -= 6; // decrease by pfb section size
3468 : :
3469 : : // if the first four bytes are all ascii hex characters, then binary data
3470 : : // has to be converted to real binary data
3471 [ # # ][ # # ]: 0 : for( nIndex = 0; nIndex < 4 &&
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
3472 : 0 : ( ( pFontData[ nBeginBinaryIndex+nIndex ] >= '0' && pFontData[ nBeginBinaryIndex+nIndex ] <= '9' ) ||
3473 : 0 : ( pFontData[ nBeginBinaryIndex+nIndex ] >= 'a' && pFontData[ nBeginBinaryIndex+nIndex ] <= 'f' ) ||
3474 : 0 : ( pFontData[ nBeginBinaryIndex+nIndex ] >= 'A' && pFontData[ nBeginBinaryIndex+nIndex ] <= 'F' )
3475 : : ); ++nIndex )
3476 : : ;
3477 : 0 : bool bConvertHexData = true;
3478 [ # # ]: 0 : if( nIndex < 4 )
3479 : : {
3480 : 0 : bConvertHexData = false;
3481 : 0 : nLength2 = nEndBinaryIndex - nBeginBinaryIndex + 1; // include the last byte
3482 [ # # ][ # # ]: 0 : for( it = aSections.begin(); it != aSections.end(); ++it )
[ # # ][ # # ]
[ # # ]
3483 [ # # ][ # # ]: 0 : if( *it > nBeginBinaryIndex && *it < nEndBinaryIndex )
[ # # ][ # # ]
[ # # ]
3484 : 0 : nLength2 -= 6;
3485 : : }
3486 : : else
3487 : : {
3488 : : // count the hex ascii characters to get nLength2
3489 : 0 : nLength2 = 0;
3490 : 0 : int nNextSectionIndex = 0;
3491 [ # # ][ # # ]: 0 : for( it = aSections.begin(); it != aSections.end() && *it < nBeginBinaryIndex; ++it )
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # #
# # # # ]
3492 : : ;
3493 [ # # ][ # # ]: 0 : if( it != aSections.end() )
[ # # ]
3494 [ # # ]: 0 : nNextSectionIndex = *it;
3495 [ # # ]: 0 : for( nIndex = nBeginBinaryIndex; nIndex <= nEndBinaryIndex; nIndex++ )
3496 : : {
3497 [ # # ]: 0 : if( nIndex == nNextSectionIndex )
3498 : : {
3499 : 0 : nIndex += 6;
3500 [ # # ]: 0 : ++it;
3501 [ # # ][ # # ]: 0 : nNextSectionIndex = (it == aSections.end() ? 0 : *it );
[ # # ][ # # ]
3502 : : }
3503 [ # # ][ # # ]: 0 : if( ( pFontData[ nIndex ] >= '0' && pFontData[ nIndex ] <= '9' ) ||
[ # # ][ # # ]
[ # # ][ # # ]
3504 : 0 : ( pFontData[ nIndex ] >= 'a' && pFontData[ nIndex ] <= 'f' ) ||
3505 : 0 : ( pFontData[ nIndex ] >= 'A' && pFontData[ nIndex ] <= 'F' ) )
3506 : 0 : nLength2++;
3507 : : }
3508 : : DBG_ASSERT( !(nLength2 & 1), "uneven number of hex chars in binary pfa section" );
3509 : 0 : nLength2 /= 2;
3510 : : }
3511 : :
3512 : : // now we can actually write the font stream !
3513 : : #if OSL_DEBUG_LEVEL > 1
3514 : : emitComment( " PDFWriterImpl::emitEmbeddedFont" );
3515 : : #endif
3516 : 0 : OStringBuffer aLine( 512 );
3517 [ # # ]: 0 : nStreamObject = createObject();
3518 [ # # ][ # # ]: 0 : if( !updateObject(nStreamObject))
3519 : 0 : throw FontException();
3520 [ # # ]: 0 : sal_Int32 nStreamLengthObject = createObject();
3521 [ # # ]: 0 : aLine.append( nStreamObject );
3522 : : aLine.append( " 0 obj\n"
3523 [ # # ]: 0 : "<</Length " );
3524 [ # # ]: 0 : aLine.append( nStreamLengthObject );
3525 : : aLine.append( " 0 R"
3526 : : #ifndef DEBUG_DISABLE_PDFCOMPRESSION
3527 : : "/Filter/FlateDecode"
3528 : : #endif
3529 [ # # ]: 0 : "/Length1 " );
3530 [ # # ]: 0 : aLine.append( nLength1 );
3531 [ # # ]: 0 : aLine.append( " /Length2 " );
3532 [ # # ]: 0 : aLine.append( nLength2 );
3533 [ # # ]: 0 : aLine.append( " /Length3 ");
3534 [ # # ]: 0 : aLine.append( nLength3 );
3535 : : aLine.append( ">>\n"
3536 [ # # ]: 0 : "stream\n" );
3537 [ # # ][ # # ]: 0 : if( !writeBuffer( aLine.getStr(), aLine.getLength() ) )
3538 : 0 : throw FontException();
3539 : :
3540 : 0 : sal_uInt64 nBeginStreamPos = 0;
3541 [ # # ]: 0 : osl_getFilePos( m_aFile, &nBeginStreamPos );
3542 : :
3543 [ # # ]: 0 : beginCompression();
3544 [ # # ]: 0 : checkAndEnableStreamEncryption( nStreamObject );
3545 : :
3546 : : // write ascii section
3547 [ # # ][ # # ]: 0 : if( aSections.begin() == aSections.end() )
3548 : : {
3549 [ # # ][ # # ]: 0 : if( ! writeBuffer( pFontData, nEndAsciiIndex+1 ) )
3550 : 0 : throw FontException();
3551 : : }
3552 : : else
3553 : : {
3554 : : // first section always starts at 0
3555 [ # # ]: 0 : it = aSections.begin();
3556 [ # # ]: 0 : nIndex = (*it)+6;
3557 [ # # ]: 0 : ++it;
3558 [ # # ][ # # ]: 0 : while( *it < nEndAsciiIndex )
3559 : : {
3560 [ # # ][ # # ]: 0 : if( ! writeBuffer( pFontData+nIndex, (*it)-nIndex ) )
[ # # ]
3561 : 0 : throw FontException();
3562 [ # # ]: 0 : nIndex = (*it)+6;
3563 [ # # ]: 0 : ++it;
3564 : : }
3565 : : // write partial last section
3566 [ # # ][ # # ]: 0 : if( ! writeBuffer( pFontData+nIndex, nEndAsciiIndex-nIndex+1 ) )
3567 : 0 : throw FontException();
3568 : : }
3569 : :
3570 : : // write binary section
3571 [ # # ]: 0 : if( ! bConvertHexData )
3572 : : {
3573 [ # # ][ # # ]: 0 : if( aSections.begin() == aSections.end() )
3574 : : {
3575 [ # # ][ # # ]: 0 : if( ! writeBuffer( pFontData+nBeginBinaryIndex, nFontLen-nBeginBinaryIndex ) )
3576 : 0 : throw FontException();
3577 : : }
3578 : : else
3579 : : {
3580 [ # # ][ # # ]: 0 : for( it = aSections.begin(); *it < nBeginBinaryIndex; ++it )
[ # # ][ # # ]
3581 : : ;
3582 : : // write first partial section
3583 [ # # ][ # # ]: 0 : if( ! writeBuffer( pFontData+nBeginBinaryIndex, (*it) - nBeginBinaryIndex ) )
[ # # ]
3584 : 0 : throw FontException();
3585 : : // write following sections
3586 [ # # ][ # # ]: 0 : while( it != aSections.end() )
[ # # ]
3587 : : {
3588 [ # # ]: 0 : nIndex = (*it)+6;
3589 [ # # ]: 0 : ++it;
3590 [ # # ]: 0 : if( nIndex < nFontLen ) // last section marker is usually the EOF which has only 2 bytes
3591 : : {
3592 [ # # ][ # # ]: 0 : sal_Int32 nSectionLen = (it == aSections.end()) ? nFontLen - nIndex : (*it) - nIndex;
[ # # ][ # # ]
3593 [ # # ][ # # ]: 0 : if( ! writeBuffer( pFontData+nIndex, nSectionLen ) )
3594 : 0 : throw FontException();
3595 : : }
3596 : : }
3597 : : }
3598 : : }
3599 : : else
3600 : : {
3601 [ # # ][ # # ]: 0 : boost::shared_array<unsigned char> pWriteBuffer( new unsigned char[ nLength2 ] );
3602 : 0 : memset( pWriteBuffer.get(), 0, nLength2 );
3603 : 0 : int nWriteIndex = 0;
3604 : :
3605 : 0 : int nNextSectionIndex = 0;
3606 [ # # ][ # # ]: 0 : for( it = aSections.begin(); it != aSections.end() && *it < nBeginBinaryIndex; ++it )
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # # #
# # ][ # # ]
3607 : : ;
3608 [ # # ][ # # ]: 0 : if( it != aSections.end() )
[ # # ]
3609 [ # # ]: 0 : nNextSectionIndex = *it;
3610 [ # # ]: 0 : for( nIndex = nBeginBinaryIndex; nIndex <= nEndBinaryIndex; nIndex++ )
3611 : : {
3612 [ # # ]: 0 : if( nIndex == nNextSectionIndex )
3613 : : {
3614 : 0 : nIndex += 6;
3615 [ # # ]: 0 : ++it;
3616 [ # # ][ # # ]: 0 : nNextSectionIndex = (it == aSections.end() ? nFontLen : *it );
[ # # ][ # # ]
3617 : : }
3618 : 0 : unsigned char cNibble = 0x80;
3619 [ # # ][ # # ]: 0 : if( pFontData[ nIndex ] >= '0' && pFontData[ nIndex ] <= '9' )
3620 : 0 : cNibble = pFontData[nIndex] - '0';
3621 [ # # ][ # # ]: 0 : else if( pFontData[ nIndex ] >= 'a' && pFontData[ nIndex ] <= 'f' )
3622 : 0 : cNibble = pFontData[nIndex] - 'a' + 10;
3623 [ # # ][ # # ]: 0 : else if( pFontData[ nIndex ] >= 'A' && pFontData[ nIndex ] <= 'F' )
3624 : 0 : cNibble = pFontData[nIndex] - 'A' + 10;
3625 [ # # ]: 0 : if( cNibble != 0x80 )
3626 : : {
3627 [ # # ]: 0 : if( !(nWriteIndex & 1 ) )
3628 : 0 : cNibble <<= 4;
3629 : 0 : pWriteBuffer.get()[ nWriteIndex/2 ] |= cNibble;
3630 : 0 : nWriteIndex++;
3631 : : }
3632 : : }
3633 [ # # ][ # # ]: 0 : if( ! writeBuffer( pWriteBuffer.get(), nLength2 ) )
3634 : 0 : throw FontException();
3635 [ # # ]: 0 : if( aSections.empty() )
3636 : : {
3637 [ # # ][ # # ]: 0 : if( ! writeBuffer( pFontData+nIndex, nFontLen-nIndex ) )
3638 : 0 : throw FontException();
3639 : : }
3640 : : else
3641 : : {
3642 : : // write rest of this section
3643 [ # # ]: 0 : if( nIndex < nNextSectionIndex )
3644 : : {
3645 [ # # ][ # # ]: 0 : if( ! writeBuffer( pFontData+nIndex, nNextSectionIndex - nIndex ) )
3646 : 0 : throw FontException();
3647 : : }
3648 : : // write following sections
3649 [ # # ][ # # ]: 0 : while( it != aSections.end() )
[ # # ]
3650 : : {
3651 [ # # ]: 0 : nIndex = (*it)+6;
3652 [ # # ]: 0 : ++it;
3653 [ # # ]: 0 : if( nIndex < nFontLen ) // last section marker is usually the EOF which has only 2 bytes
3654 : : {
3655 [ # # ][ # # ]: 0 : sal_Int32 nSectionLen = (it == aSections.end()) ? nFontLen - nIndex : (*it) - nIndex;
[ # # ][ # # ]
3656 [ # # ][ # # ]: 0 : if( ! writeBuffer( pFontData+nIndex, nSectionLen ) )
3657 : 0 : throw FontException();
3658 : : }
3659 : : }
3660 [ # # ]: 0 : }
3661 : : }
3662 [ # # ]: 0 : endCompression();
3663 : 0 : disableStreamEncryption();
3664 : :
3665 : :
3666 : 0 : sal_uInt64 nEndStreamPos = 0;
3667 [ # # ]: 0 : osl_getFilePos( m_aFile, &nEndStreamPos );
3668 : :
3669 : : // and finally close the stream
3670 [ # # ]: 0 : aLine.setLength( 0 );
3671 [ # # ]: 0 : aLine.append( "\nendstream\nendobj\n\n" );
3672 [ # # ][ # # ]: 0 : if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) )
3673 : 0 : throw FontException();
3674 : :
3675 : : // write stream length object
3676 [ # # ]: 0 : aLine.setLength( 0 );
3677 [ # # ][ # # ]: 0 : if( ! updateObject( nStreamLengthObject ) )
3678 : 0 : throw FontException();
3679 [ # # ]: 0 : aLine.append( nStreamLengthObject );
3680 [ # # ]: 0 : aLine.append( " 0 obj\n" );
3681 [ # # ]: 0 : aLine.append( (sal_Int64)(nEndStreamPos-nBeginStreamPos ) );
3682 [ # # ]: 0 : aLine.append( "\nendobj\n\n" );
3683 [ # # ][ # # ]: 0 : if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) )
3684 : 0 : throw FontException();
3685 : : }
3686 : : else
3687 : : {
3688 : 0 : rtl::OStringBuffer aErrorComment( 256 );
3689 [ # # ]: 0 : aErrorComment.append( "GetEmbedFontData failed for font \"" );
3690 [ # # ][ # # ]: 0 : aErrorComment.append( OUStringToOString( pFont->GetFamilyName(), RTL_TEXTENCODING_UTF8 ) );
[ # # ]
3691 [ # # ]: 0 : aErrorComment.append( '\"' );
3692 [ # # ]: 0 : if( pFont->GetSlant() == ITALIC_NORMAL )
3693 [ # # ]: 0 : aErrorComment.append( " italic" );
3694 [ # # ]: 0 : else if( pFont->GetSlant() == ITALIC_OBLIQUE )
3695 [ # # ]: 0 : aErrorComment.append( " oblique" );
3696 [ # # ]: 0 : aErrorComment.append( " weight=" );
3697 [ # # ]: 0 : aErrorComment.append( sal_Int32(pFont->GetWeight()) );
3698 [ # # ]: 0 : emitComment( aErrorComment.getStr() );
3699 : : }
3700 : :
3701 [ # # ]: 0 : if( nStreamObject )
3702 : : // write font descriptor
3703 [ # # ]: 0 : nFontDescriptor = emitFontDescriptor( pFont, aInfo, 0, nStreamObject );
3704 : :
3705 [ # # ]: 0 : if( nFontDescriptor )
3706 : : {
3707 [ # # ]: 0 : if( pEncoding )
3708 [ # # ][ # # ]: 0 : nToUnicodeStream = createToUnicodeCMap( nEncoding, &aUnicodes[0], pUnicodesPerGlyph, pEncToUnicodeIndex, SAL_N_ELEMENTS(nEncoding) );
3709 : :
3710 : : // write font object
3711 [ # # ]: 0 : sal_Int32 nObject = createObject();
3712 [ # # ][ # # ]: 0 : if( ! updateObject( nObject ) )
3713 : 0 : throw FontException();
3714 : :
3715 : 0 : OStringBuffer aLine( 1024 );
3716 [ # # ]: 0 : aLine.append( nObject );
3717 : : aLine.append( " 0 obj\n"
3718 [ # # ]: 0 : "<</Type/Font/Subtype/Type1/BaseFont/" );
3719 [ # # ][ # # ]: 0 : appendName( aInfo.m_aPSName, aLine );
3720 [ # # ]: 0 : aLine.append( "\n" );
3721 [ # # ][ # # ]: 0 : if( !pFont->mbSymbolFlag && pEncoding == 0 )
3722 [ # # ]: 0 : aLine.append( "/Encoding/WinAnsiEncoding\n" );
3723 [ # # ]: 0 : if( nToUnicodeStream )
3724 : : {
3725 [ # # ]: 0 : aLine.append( "/ToUnicode " );
3726 [ # # ]: 0 : aLine.append( nToUnicodeStream );
3727 [ # # ]: 0 : aLine.append( " 0 R\n" );
3728 : : }
3729 : : aLine.append( "/FirstChar 0 /LastChar 255\n"
3730 [ # # ]: 0 : "/Widths[" );
3731 [ # # ]: 0 : for( int i = 0; i < 256; i++ )
3732 : : {
3733 [ # # ]: 0 : aLine.append( pWidths[i] );
3734 [ # # ][ # # ]: 0 : aLine.append( ((i&15) == 15) ? "\n" : " " );
3735 : : }
3736 : : aLine.append( "]\n"
3737 [ # # ]: 0 : "/FontDescriptor " );
3738 [ # # ]: 0 : aLine.append( nFontDescriptor );
3739 : : aLine.append( " 0 R>>\n"
3740 [ # # ]: 0 : "endobj\n\n" );
3741 [ # # ][ # # ]: 0 : if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) )
3742 : 0 : throw FontException();
3743 : :
3744 [ # # ]: 0 : aRet[ rEmbed.m_nNormalFontID ] = nObject;
3745 : :
3746 : : // write additional encodings
3747 [ # # ]: 0 : for( std::list< EmbedEncoding >::iterator enc_it = rEmbed.m_aExtendedEncodings.begin(); enc_it != rEmbed.m_aExtendedEncodings.end(); ++enc_it )
3748 : : {
3749 : : sal_Int32 aEncWidths[ 256 ];
3750 : : // emit encoding dict
3751 [ # # ]: 0 : sal_Int32 nEncObject = createObject();
3752 [ # # ][ # # ]: 0 : if( ! updateObject( nEncObject ) )
3753 : 0 : throw FontException();
3754 : :
3755 [ # # ]: 0 : OutputDevice* pRef = getReferenceDevice();
3756 [ # # ]: 0 : pRef->Push( PUSH_FONT | PUSH_MAPMODE );
3757 [ # # ][ # # ]: 0 : pRef->SetMapMode( MapMode( MAP_PIXEL ) );
[ # # ]
3758 [ # # ]: 0 : Font aFont( pFont->GetFamilyName(), pFont->GetStyleName(), Size( 0, 1000 ) );
3759 [ # # ]: 0 : aFont.SetWeight( pFont->GetWeight() );
3760 [ # # ]: 0 : aFont.SetItalic( pFont->GetSlant() );
3761 [ # # ]: 0 : aFont.SetPitch( pFont->GetPitch() );
3762 [ # # ]: 0 : pRef->SetFont( aFont );
3763 [ # # ]: 0 : pRef->ImplNewFont();
3764 : :
3765 [ # # ]: 0 : aLine.setLength( 0 );
3766 [ # # ]: 0 : aLine.append( nEncObject );
3767 : : aLine.append( " 0 obj\n"
3768 [ # # ]: 0 : "<</Type/Encoding/Differences[ 0\n" );
3769 : 0 : int nEncoded = 0;
3770 : 0 : aUnicodes.clear();
3771 [ # # ][ # # ]: 0 : for( std::vector< EmbedCode >::iterator str_it = enc_it->m_aEncVector.begin(); str_it != enc_it->m_aEncVector.end(); ++str_it )
3772 : : {
3773 : 0 : rtl::OUString aStr( str_it->m_aUnicode );
3774 [ # # ][ # # ]: 0 : aEncWidths[nEncoded] = pRef->GetTextWidth( aStr );
[ # # ]
3775 : 0 : nEncodedCodes[nEncoded] = str_it->m_aUnicode;
3776 : 0 : nEncoding[nEncoded] = sal::static_int_cast<sal_uInt8>(nEncoded);
3777 : 0 : pEncToUnicodeIndex[nEncoded] = static_cast<sal_Int32>(aUnicodes.size());
3778 [ # # ]: 0 : aUnicodes.push_back( nEncodedCodes[nEncoded] );
3779 : 0 : pUnicodesPerGlyph[nEncoded] = 1;
3780 : :
3781 [ # # ]: 0 : aLine.append( " /" );
3782 [ # # ]: 0 : aLine.append( str_it->m_aName );
3783 [ # # ]: 0 : if( !((++nEncoded) & 15) )
3784 [ # # ]: 0 : aLine.append( "\n" );
3785 : 0 : }
3786 : : aLine.append( "]>>\n"
3787 [ # # ]: 0 : "endobj\n\n" );
3788 : :
3789 [ # # ]: 0 : pRef->Pop();
3790 : :
3791 [ # # ][ # # ]: 0 : if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) )
3792 : 0 : throw FontException();
3793 : :
3794 [ # # ][ # # ]: 0 : nToUnicodeStream = createToUnicodeCMap( nEncoding, &aUnicodes[0], pUnicodesPerGlyph, pEncToUnicodeIndex, nEncoded );
3795 : :
3796 [ # # ]: 0 : nObject = createObject();
3797 [ # # ][ # # ]: 0 : if( ! updateObject( nObject ) )
3798 : 0 : throw FontException();
3799 : :
3800 [ # # ]: 0 : aLine.setLength( 0 );
3801 [ # # ]: 0 : aLine.append( nObject );
3802 : : aLine.append( " 0 obj\n"
3803 [ # # ]: 0 : "<</Type/Font/Subtype/Type1/BaseFont/" );
3804 [ # # ][ # # ]: 0 : appendName( aInfo.m_aPSName, aLine );
3805 [ # # ]: 0 : aLine.append( "\n" );
3806 [ # # ]: 0 : aLine.append( "/Encoding " );
3807 [ # # ]: 0 : aLine.append( nEncObject );
3808 [ # # ]: 0 : aLine.append( " 0 R\n" );
3809 [ # # ]: 0 : if( nToUnicodeStream )
3810 : : {
3811 [ # # ]: 0 : aLine.append( "/ToUnicode " );
3812 [ # # ]: 0 : aLine.append( nToUnicodeStream );
3813 [ # # ]: 0 : aLine.append( " 0 R\n" );
3814 : : }
3815 : : aLine.append( "/FirstChar 0\n"
3816 [ # # ]: 0 : "/LastChar " );
3817 [ # # ]: 0 : aLine.append( (sal_Int32)(nEncoded-1) );
3818 : : aLine.append( "\n"
3819 [ # # ]: 0 : "/Widths[" );
3820 [ # # ]: 0 : for( int i = 0; i < nEncoded; i++ )
3821 : : {
3822 [ # # ]: 0 : aLine.append( aEncWidths[i] );
3823 [ # # ][ # # ]: 0 : aLine.append( ((i&15) == 15) ? "\n" : " " );
3824 : : }
3825 : : aLine.append( " ]\n"
3826 [ # # ]: 0 : "/FontDescriptor " );
3827 [ # # ]: 0 : aLine.append( nFontDescriptor );
3828 : : aLine.append( " 0 R>>\n"
3829 [ # # ]: 0 : "endobj\n\n" );
3830 [ # # ][ # # ]: 0 : if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) )
3831 : 0 : throw FontException();
3832 : :
3833 [ # # ]: 0 : aRet[ enc_it->m_nFontID ] = nObject;
3834 [ # # ]: 0 : }
3835 : : }
3836 : : }
3837 [ # # # # ]: 0 : catch( FontException& )
3838 : : {
3839 : : // these do nothing in case there was no compression or encryption ongoing
3840 [ # # ]: 0 : endCompression();
3841 : 0 : disableStreamEncryption();
3842 : : }
3843 : :
3844 [ # # ]: 0 : if( pFontData )
3845 [ # # ]: 0 : m_pReferenceDevice->mpGraphics->FreeEmbedFontData( pFontData, nFontLen );
3846 : :
3847 [ # # ]: 0 : return aRet;
3848 : : }
3849 : :
3850 : 0 : static void appendSubsetName( int nSubsetID, const OUString& rPSName, OStringBuffer& rBuffer )
3851 : : {
3852 [ # # ]: 0 : if( nSubsetID )
3853 : : {
3854 [ # # ]: 0 : for( int i = 0; i < 6; i++ )
3855 : : {
3856 : 0 : int nOffset = (nSubsetID % 26);
3857 : 0 : nSubsetID /= 26;
3858 : 0 : rBuffer.append( (sal_Char)('A'+nOffset) );
3859 : : }
3860 : 0 : rBuffer.append( '+' );
3861 : : }
3862 : 0 : appendName( rPSName, rBuffer );
3863 : 0 : }
3864 : :
3865 : 0 : sal_Int32 PDFWriterImpl::createToUnicodeCMap( sal_uInt8* pEncoding,
3866 : : sal_Ucs* pUnicodes,
3867 : : sal_Int32* pUnicodesPerGlyph,
3868 : : sal_Int32* pEncToUnicodeIndex,
3869 : : int nGlyphs )
3870 : : {
3871 : 0 : int nMapped = 0, n = 0;
3872 [ # # ]: 0 : for( n = 0; n < nGlyphs; n++ )
3873 [ # # ][ # # ]: 0 : if( pUnicodes[pEncToUnicodeIndex[n]] && pUnicodesPerGlyph[n] )
3874 : 0 : nMapped++;
3875 : :
3876 [ # # ]: 0 : if( nMapped == 0 )
3877 : 0 : return 0;
3878 : :
3879 [ # # ]: 0 : sal_Int32 nStream = createObject();
3880 [ # # ][ # # ]: 0 : CHECK_RETURN( updateObject( nStream ) );
3881 : :
3882 : 0 : OStringBuffer aContents( 1024 );
3883 : : aContents.append(
3884 : : "/CIDInit/ProcSet findresource begin\n"
3885 : : "12 dict begin\n"
3886 : : "begincmap\n"
3887 : : "/CIDSystemInfo<<\n"
3888 : : "/Registry (Adobe)\n"
3889 : : "/Ordering (UCS)\n"
3890 : : "/Supplement 0\n"
3891 : : ">> def\n"
3892 : : "/CMapName/Adobe-Identity-UCS def\n"
3893 : : "/CMapType 2 def\n"
3894 : : "1 begincodespacerange\n"
3895 : : "<00> <FF>\n"
3896 : : "endcodespacerange\n"
3897 [ # # ]: 0 : );
3898 : 0 : int nCount = 0;
3899 [ # # ]: 0 : for( n = 0; n < nGlyphs; n++ )
3900 : : {
3901 [ # # ][ # # ]: 0 : if( pUnicodes[pEncToUnicodeIndex[n]] && pUnicodesPerGlyph[n] )
3902 : : {
3903 [ # # ]: 0 : if( (nCount % 100) == 0 )
3904 : : {
3905 [ # # ]: 0 : if( nCount )
3906 [ # # ]: 0 : aContents.append( "endbfchar\n" );
3907 [ # # ]: 0 : aContents.append( (sal_Int32)((nMapped-nCount > 100) ? 100 : nMapped-nCount ) );
3908 [ # # ]: 0 : aContents.append( " beginbfchar\n" );
3909 : : }
3910 [ # # ]: 0 : aContents.append( '<' );
3911 [ # # ]: 0 : appendHex( (sal_Int8)pEncoding[n], aContents );
3912 [ # # ]: 0 : aContents.append( "> <" );
3913 : : // TODO: handle unicodes>U+FFFF
3914 : 0 : sal_Int32 nIndex = pEncToUnicodeIndex[n];
3915 [ # # ]: 0 : for( sal_Int32 j = 0; j < pUnicodesPerGlyph[n]; j++ )
3916 : : {
3917 [ # # ]: 0 : appendHex( (sal_Int8)(pUnicodes[nIndex + j] / 256), aContents );
3918 [ # # ]: 0 : appendHex( (sal_Int8)(pUnicodes[nIndex + j] & 255), aContents );
3919 : : }
3920 [ # # ]: 0 : aContents.append( ">\n" );
3921 : 0 : nCount++;
3922 : : }
3923 : : }
3924 : : aContents.append( "endbfchar\n"
3925 : : "endcmap\n"
3926 : : "CMapName currentdict /CMap defineresource pop\n"
3927 : : "end\n"
3928 [ # # ]: 0 : "end\n" );
3929 : : #ifndef DEBUG_DISABLE_PDFCOMPRESSION
3930 [ # # ][ # # ]: 0 : ZCodec* pCodec = new ZCodec( 0x4000, 0x4000 );
3931 [ # # ]: 0 : SvMemoryStream aStream;
3932 [ # # ]: 0 : pCodec->BeginCompression();
3933 [ # # ]: 0 : pCodec->Write( aStream, (const sal_uInt8*)aContents.getStr(), aContents.getLength() );
3934 [ # # ]: 0 : pCodec->EndCompression();
3935 [ # # ][ # # ]: 0 : delete pCodec;
3936 : : #endif
3937 : :
3938 : : #if OSL_DEBUG_LEVEL > 1
3939 : : emitComment( "PDFWriterImpl::createToUnicodeCMap" );
3940 : : #endif
3941 : 0 : OStringBuffer aLine( 40 );
3942 : :
3943 [ # # ]: 0 : aLine.append( nStream );
3944 [ # # ]: 0 : aLine.append( " 0 obj\n<</Length " );
3945 : : #ifndef DEBUG_DISABLE_PDFCOMPRESSION
3946 : 0 : sal_Int32 nLen = (sal_Int32)aStream.Tell();
3947 [ # # ]: 0 : aStream.Seek( 0 );
3948 [ # # ]: 0 : aLine.append( nLen );
3949 [ # # ]: 0 : aLine.append( "/Filter/FlateDecode" );
3950 : : #else
3951 : : aLine.append( aContents.getLength() );
3952 : : #endif
3953 [ # # ]: 0 : aLine.append( ">>\nstream\n" );
3954 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
3955 [ # # ]: 0 : checkAndEnableStreamEncryption( nStream );
3956 : : #ifndef DEBUG_DISABLE_PDFCOMPRESSION
3957 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aStream.GetData(), nLen ) );
[ # # ]
3958 : : #else
3959 : : CHECK_RETURN( writeBuffer( aContents.getStr(), aContents.getLength() ) );
3960 : : #endif
3961 : 0 : disableStreamEncryption();
3962 [ # # ]: 0 : aLine.setLength( 0 );
3963 : : aLine.append( "\nendstream\n"
3964 [ # # ]: 0 : "endobj\n\n" );
3965 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
3966 [ # # ]: 0 : return nStream;
3967 : : }
3968 : :
3969 : 0 : sal_Int32 PDFWriterImpl::emitFontDescriptor( const PhysicalFontFace* pFont, FontSubsetInfo& rInfo, sal_Int32 nSubsetID, sal_Int32 nFontStream )
3970 : : {
3971 : 0 : OStringBuffer aLine( 1024 );
3972 : : // get font flags, see PDF reference 1.4 p. 358
3973 : : // possibly characters outside Adobe standard encoding
3974 : : // so set Symbolic flag
3975 : 0 : sal_Int32 nFontFlags = (1<<2);
3976 [ # # ][ # # ]: 0 : if( pFont->GetSlant() == ITALIC_NORMAL || pFont->GetSlant() == ITALIC_OBLIQUE )
[ # # ]
3977 : 0 : nFontFlags |= (1 << 6);
3978 [ # # ]: 0 : if( pFont->GetPitch() == PITCH_FIXED )
3979 : 0 : nFontFlags |= 1;
3980 [ # # ]: 0 : if( pFont->GetFamilyType() == FAMILY_SCRIPT )
3981 : 0 : nFontFlags |= (1 << 3);
3982 [ # # ]: 0 : else if( pFont->GetFamilyType() == FAMILY_ROMAN )
3983 : 0 : nFontFlags |= (1 << 1);
3984 : :
3985 [ # # ]: 0 : sal_Int32 nFontDescriptor = createObject();
3986 [ # # ][ # # ]: 0 : CHECK_RETURN( updateObject( nFontDescriptor ) );
3987 [ # # ]: 0 : aLine.setLength( 0 );
3988 [ # # ]: 0 : aLine.append( nFontDescriptor );
3989 : : aLine.append( " 0 obj\n"
3990 [ # # ]: 0 : "<</Type/FontDescriptor/FontName/" );
3991 [ # # ][ # # ]: 0 : appendSubsetName( nSubsetID, rInfo.m_aPSName, aLine );
3992 : : aLine.append( "\n"
3993 [ # # ]: 0 : "/Flags " );
3994 [ # # ]: 0 : aLine.append( nFontFlags );
3995 : : aLine.append( "\n"
3996 [ # # ]: 0 : "/FontBBox[" );
3997 : : // note: Top and Bottom are reversed in VCL and PDF rectangles
3998 [ # # ]: 0 : aLine.append( (sal_Int32)rInfo.m_aFontBBox.TopLeft().X() );
3999 [ # # ]: 0 : aLine.append( ' ' );
4000 [ # # ]: 0 : aLine.append( (sal_Int32)rInfo.m_aFontBBox.TopLeft().Y() );
4001 [ # # ]: 0 : aLine.append( ' ' );
4002 [ # # ][ # # ]: 0 : aLine.append( (sal_Int32)rInfo.m_aFontBBox.BottomRight().X() );
4003 [ # # ]: 0 : aLine.append( ' ' );
4004 [ # # ][ # # ]: 0 : aLine.append( (sal_Int32)(rInfo.m_aFontBBox.BottomRight().Y()+1) );
4005 [ # # ]: 0 : aLine.append( "]/ItalicAngle " );
4006 [ # # ][ # # ]: 0 : if( pFont->GetSlant() == ITALIC_OBLIQUE || pFont->GetSlant() == ITALIC_NORMAL )
[ # # ]
4007 [ # # ]: 0 : aLine.append( "-30" );
4008 : : else
4009 [ # # ]: 0 : aLine.append( "0" );
4010 : : aLine.append( "\n"
4011 [ # # ]: 0 : "/Ascent " );
4012 [ # # ]: 0 : aLine.append( (sal_Int32)rInfo.m_nAscent );
4013 : : aLine.append( "\n"
4014 [ # # ]: 0 : "/Descent " );
4015 [ # # ]: 0 : aLine.append( (sal_Int32)-rInfo.m_nDescent );
4016 : : aLine.append( "\n"
4017 [ # # ]: 0 : "/CapHeight " );
4018 [ # # ]: 0 : aLine.append( (sal_Int32)rInfo.m_nCapHeight );
4019 : : // According to PDF reference 1.4 StemV is required
4020 : : // seems a tad strange to me, but well ...
4021 : : aLine.append( "\n"
4022 [ # # ]: 0 : "/StemV 80\n" );
4023 [ # # ]: 0 : if( nFontStream )
4024 : : {
4025 [ # # ]: 0 : aLine.append( "/FontFile" );
4026 [ # # # ]: 0 : switch( rInfo.m_nFontType )
4027 : : {
4028 : : case FontSubsetInfo::SFNT_TTF:
4029 [ # # ]: 0 : aLine.append( '2' );
4030 : 0 : break;
4031 : : case FontSubsetInfo::TYPE1_PFA:
4032 : : case FontSubsetInfo::TYPE1_PFB:
4033 : : case FontSubsetInfo::ANY_TYPE1:
4034 : 0 : break;
4035 : : default:
4036 : : OSL_FAIL( "unknown fonttype in PDF font descriptor" );
4037 : 0 : return 0;
4038 : : }
4039 [ # # ]: 0 : aLine.append( ' ' );
4040 [ # # ]: 0 : aLine.append( nFontStream );
4041 [ # # ]: 0 : aLine.append( " 0 R\n" );
4042 : : }
4043 : : aLine.append( ">>\n"
4044 [ # # ]: 0 : "endobj\n\n" );
4045 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
4046 : :
4047 : 0 : return nFontDescriptor;
4048 : : }
4049 : :
4050 : 0 : void PDFWriterImpl::appendBuiltinFontsToDict( OStringBuffer& rDict ) const
4051 : : {
4052 [ # # # # ]: 0 : for( std::map< sal_Int32, sal_Int32 >::const_iterator it =
[ # # ]
4053 : 0 : m_aBuiltinFontToObjectMap.begin(); it != m_aBuiltinFontToObjectMap.end(); ++it )
4054 : : {
4055 [ # # ][ # # ]: 0 : rDict.append( m_aBuiltinFonts[it->first].getNameObject() );
[ # # ]
4056 [ # # ]: 0 : rDict.append( ' ' );
4057 [ # # ][ # # ]: 0 : rDict.append( it->second );
4058 [ # # ]: 0 : rDict.append( " 0 R" );
4059 : : }
4060 : 0 : }
4061 : :
4062 : 0 : bool PDFWriterImpl::emitFonts()
4063 : : {
4064 [ # # ][ # # ]: 0 : if( ! m_pReferenceDevice->ImplGetGraphics() )
4065 : 0 : return false;
4066 : :
4067 : 0 : OStringBuffer aLine( 1024 );
4068 : :
4069 [ # # ]: 0 : std::map< sal_Int32, sal_Int32 > aFontIDToObject;
4070 : :
4071 : 0 : OUString aTmpName;
4072 [ # # ]: 0 : osl_createTempFile( NULL, NULL, &aTmpName.pData );
4073 [ # # ]: 0 : for( FontSubsetData::iterator it = m_aSubsets.begin(); it != m_aSubsets.end(); ++it )
4074 : : {
4075 [ # # ]: 0 : for( FontEmitList::iterator lit = it->second.m_aSubsets.begin(); lit != it->second.m_aSubsets.end(); ++lit )
4076 : : {
4077 : : sal_Int32 pGlyphIDs[ 256 ];
4078 : : sal_Int32 pWidths[ 256 ];
4079 : : sal_uInt8 pEncoding[ 256 ];
4080 : : sal_Int32 pEncToUnicodeIndex[ 256 ];
4081 : : sal_Int32 pUnicodesPerGlyph[ 256 ];
4082 [ # # ]: 0 : std::vector<sal_Ucs> aUnicodes;
4083 [ # # ]: 0 : aUnicodes.reserve( 256 );
4084 : 0 : int nGlyphs = 1;
4085 : : // fill arrays and prepare encoding index map
4086 : 0 : sal_Int32 nToUnicodeStream = 0;
4087 : :
4088 : 0 : memset( pGlyphIDs, 0, sizeof( pGlyphIDs ) );
4089 : 0 : memset( pEncoding, 0, sizeof( pEncoding ) );
4090 : 0 : memset( pUnicodesPerGlyph, 0, sizeof( pUnicodesPerGlyph ) );
4091 : 0 : memset( pEncToUnicodeIndex, 0, sizeof( pEncToUnicodeIndex ) );
4092 [ # # ]: 0 : for( FontEmitMapping::iterator fit = lit->m_aMapping.begin(); fit != lit->m_aMapping.end();++fit )
4093 : : {
4094 : 0 : sal_uInt8 nEnc = fit->second.getGlyphId();
4095 : :
4096 : : DBG_ASSERT( pGlyphIDs[nEnc] == 0 && pEncoding[nEnc] == 0, "duplicate glyph" );
4097 : : DBG_ASSERT( nEnc <= lit->m_aMapping.size(), "invalid glyph encoding" );
4098 : :
4099 : 0 : pGlyphIDs[ nEnc ] = fit->first;
4100 : 0 : pEncoding[ nEnc ] = nEnc;
4101 : 0 : pEncToUnicodeIndex[ nEnc ] = static_cast<sal_Int32>(aUnicodes.size());
4102 : 0 : pUnicodesPerGlyph[ nEnc ] = fit->second.countCodes();
4103 [ # # ]: 0 : for( sal_Int32 n = 0; n < pUnicodesPerGlyph[ nEnc ]; n++ )
4104 [ # # ][ # # ]: 0 : aUnicodes.push_back( fit->second.getCode( n ) );
4105 [ # # ][ # # ]: 0 : if( fit->second.getCode(0) )
4106 : 0 : nToUnicodeStream = 1;
4107 [ # # ]: 0 : if( nGlyphs < 256 )
4108 : 0 : nGlyphs++;
4109 : : else
4110 : : {
4111 : : OSL_FAIL( "too many glyphs for subset" );
4112 : : }
4113 : : }
4114 [ # # ]: 0 : FontSubsetInfo aSubsetInfo;
4115 [ # # ][ # # ]: 0 : if( m_pReferenceDevice->mpGraphics->CreateFontSubset( aTmpName, it->first, pGlyphIDs, pEncoding, pWidths, nGlyphs, aSubsetInfo ) )
4116 : : {
4117 : : // create font stream
4118 : : oslFileHandle aFontFile;
4119 [ # # ][ # # ]: 0 : CHECK_RETURN( (osl_File_E_None == osl_openFile( aTmpName.pData, &aFontFile, osl_File_OpenFlag_Read ) ) );
4120 : : // get file size
4121 : : sal_uInt64 nLength1;
4122 [ # # ][ # # ]: 0 : CHECK_RETURN( (osl_File_E_None == osl_setFilePos( aFontFile, osl_Pos_End, 0 ) ) );
4123 [ # # ][ # # ]: 0 : CHECK_RETURN( (osl_File_E_None == osl_getFilePos( aFontFile, &nLength1 ) ) );
4124 [ # # ][ # # ]: 0 : CHECK_RETURN( (osl_File_E_None == osl_setFilePos( aFontFile, osl_Pos_Absolut, 0 ) ) );
4125 : :
4126 : : #if OSL_DEBUG_LEVEL > 1
4127 : : emitComment( "PDFWriterImpl::emitFonts" );
4128 : : #endif
4129 [ # # ]: 0 : sal_Int32 nFontStream = createObject();
4130 [ # # ]: 0 : sal_Int32 nStreamLengthObject = createObject();
4131 [ # # ][ # # ]: 0 : CHECK_RETURN( updateObject( nFontStream ) );
4132 [ # # ]: 0 : aLine.setLength( 0 );
4133 [ # # ]: 0 : aLine.append( nFontStream );
4134 : : aLine.append( " 0 obj\n"
4135 [ # # ]: 0 : "<</Length " );
4136 [ # # ]: 0 : aLine.append( (sal_Int32)nStreamLengthObject );
4137 : : aLine.append( " 0 R"
4138 : : #ifndef DEBUG_DISABLE_PDFCOMPRESSION
4139 : : "/Filter/FlateDecode"
4140 : : #endif
4141 [ # # ]: 0 : "/Length1 " );
4142 : :
4143 : 0 : sal_uInt64 nStartPos = 0;
4144 [ # # ]: 0 : if( aSubsetInfo.m_nFontType == FontSubsetInfo::SFNT_TTF )
4145 : : {
4146 [ # # ]: 0 : aLine.append( (sal_Int32)nLength1 );
4147 : :
4148 : : aLine.append( ">>\n"
4149 [ # # ]: 0 : "stream\n" );
4150 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
4151 [ # # ][ # # ]: 0 : CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nStartPos ) ) );
4152 : :
4153 : : // copy font file
4154 [ # # ]: 0 : beginCompression();
4155 [ # # ]: 0 : checkAndEnableStreamEncryption( nFontStream );
4156 : 0 : sal_Bool bEOF = sal_False;
4157 [ # # ]: 0 : do
4158 : : {
4159 : : char buf[8192];
4160 : : sal_uInt64 nRead;
4161 [ # # ][ # # ]: 0 : CHECK_RETURN( (osl_File_E_None == osl_readFile( aFontFile, buf, sizeof( buf ), &nRead ) ) );
4162 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( buf, nRead ) );
4163 [ # # ][ # # ]: 0 : CHECK_RETURN( (osl_File_E_None == osl_isEndOfFile( aFontFile, &bEOF ) ) );
4164 : 0 : } while( ! bEOF );
4165 : : }
4166 [ # # ]: 0 : else if( (aSubsetInfo.m_nFontType & FontSubsetInfo::CFF_FONT) != 0 )
4167 : : {
4168 : : // TODO: implement
4169 : : OSL_FAIL( "PDFWriterImpl does not support CFF-font subsets yet!" );
4170 : : }
4171 [ # # ]: 0 : else if( (aSubsetInfo.m_nFontType & FontSubsetInfo::TYPE1_PFB) != 0 ) // TODO: also support PFA?
4172 : : {
4173 [ # # ][ # # ]: 0 : boost::shared_array<unsigned char> pBuffer( new unsigned char[ nLength1 ] );
4174 : :
4175 : 0 : sal_uInt64 nBytesRead = 0;
4176 [ # # ][ # # ]: 0 : CHECK_RETURN( (osl_File_E_None == osl_readFile( aFontFile, pBuffer.get(), nLength1, &nBytesRead ) ) );
4177 : : DBG_ASSERT( nBytesRead==nLength1, "PDF-FontSubset read incomplete!" );
4178 [ # # ][ # # ]: 0 : CHECK_RETURN( (osl_File_E_None == osl_setFilePos( aFontFile, osl_Pos_Absolut, 0 ) ) );
4179 : : // get the PFB-segment lengths
4180 : 0 : ThreeInts aSegmentLengths = {0,0,0};
4181 : 0 : getPfbSegmentLengths( pBuffer.get(), (int)nBytesRead, aSegmentLengths );
4182 : : // the lengths below are mandatory for PDF-exported Type1 fonts
4183 : : // because the PFB segment headers get stripped! WhyOhWhy.
4184 [ # # ]: 0 : aLine.append( (sal_Int32)aSegmentLengths[0] );
4185 [ # # ]: 0 : aLine.append( "/Length2 " );
4186 [ # # ]: 0 : aLine.append( (sal_Int32)aSegmentLengths[1] );
4187 [ # # ]: 0 : aLine.append( "/Length3 " );
4188 [ # # ]: 0 : aLine.append( (sal_Int32)aSegmentLengths[2] );
4189 : :
4190 : : aLine.append( ">>\n"
4191 [ # # ]: 0 : "stream\n" );
4192 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
4193 [ # # ][ # # ]: 0 : CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nStartPos ) ) );
4194 : :
4195 : : // emit PFB-sections without section headers
4196 [ # # ]: 0 : beginCompression();
4197 [ # # ]: 0 : checkAndEnableStreamEncryption( nFontStream );
4198 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( &pBuffer[6], aSegmentLengths[0] ) );
4199 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( &pBuffer[12] + aSegmentLengths[0], aSegmentLengths[1] ) );
4200 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( &pBuffer[18] + aSegmentLengths[0] + aSegmentLengths[1], aSegmentLengths[2] ) );
[ # # ][ # # ]
4201 : : }
4202 : : else
4203 : : {
4204 [ # # ]: 0 : fprintf( stderr, "PDF: CreateFontSubset result in not yet supported format=%d\n",aSubsetInfo.m_nFontType);
4205 [ # # ]: 0 : aLine.append( "0 >>\nstream\n" );
4206 : : }
4207 : :
4208 [ # # ]: 0 : endCompression();
4209 : 0 : disableStreamEncryption();
4210 : : // close the file
4211 [ # # ]: 0 : osl_closeFile( aFontFile );
4212 : :
4213 : 0 : sal_uInt64 nEndPos = 0;
4214 [ # # ][ # # ]: 0 : CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nEndPos ) ) );
4215 : : // end the stream
4216 [ # # ]: 0 : aLine.setLength( 0 );
4217 [ # # ]: 0 : aLine.append( "\nendstream\nendobj\n\n" );
4218 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
4219 : :
4220 : : // emit stream length object
4221 [ # # ][ # # ]: 0 : CHECK_RETURN( updateObject( nStreamLengthObject ) );
4222 [ # # ]: 0 : aLine.setLength( 0 );
4223 [ # # ]: 0 : aLine.append( nStreamLengthObject );
4224 [ # # ]: 0 : aLine.append( " 0 obj\n" );
4225 [ # # ]: 0 : aLine.append( (sal_Int64)(nEndPos-nStartPos) );
4226 [ # # ]: 0 : aLine.append( "\nendobj\n\n" );
4227 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
4228 : :
4229 : : // write font descriptor
4230 [ # # ]: 0 : sal_Int32 nFontDescriptor = emitFontDescriptor( it->first, aSubsetInfo, lit->m_nFontID, nFontStream );
4231 : :
4232 [ # # ]: 0 : if( nToUnicodeStream )
4233 [ # # ][ # # ]: 0 : nToUnicodeStream = createToUnicodeCMap( pEncoding, &aUnicodes[0], pUnicodesPerGlyph, pEncToUnicodeIndex, nGlyphs );
4234 : :
4235 [ # # ]: 0 : sal_Int32 nFontObject = createObject();
4236 [ # # ][ # # ]: 0 : CHECK_RETURN( updateObject( nFontObject ) );
4237 [ # # ]: 0 : aLine.setLength( 0 );
4238 [ # # ]: 0 : aLine.append( nFontObject );
4239 : :
4240 [ # # ]: 0 : aLine.append( " 0 obj\n" );
4241 : : aLine.append( ((aSubsetInfo.m_nFontType & FontSubsetInfo::ANY_TYPE1) != 0) ?
4242 : : "<</Type/Font/Subtype/Type1/BaseFont/" :
4243 [ # # ][ # # ]: 0 : "<</Type/Font/Subtype/TrueType/BaseFont/" );
4244 [ # # ][ # # ]: 0 : appendSubsetName( lit->m_nFontID, aSubsetInfo.m_aPSName, aLine );
4245 : : aLine.append( "\n"
4246 : : "/FirstChar 0\n"
4247 [ # # ]: 0 : "/LastChar " );
4248 [ # # ]: 0 : aLine.append( (sal_Int32)(nGlyphs-1) );
4249 : : aLine.append( "\n"
4250 [ # # ]: 0 : "/Widths[" );
4251 [ # # ]: 0 : for( int i = 0; i < nGlyphs; i++ )
4252 : : {
4253 [ # # ]: 0 : aLine.append( pWidths[ i ] );
4254 [ # # ][ # # ]: 0 : aLine.append( ((i & 15) == 15) ? "\n" : " " );
4255 : : }
4256 : : aLine.append( "]\n"
4257 [ # # ]: 0 : "/FontDescriptor " );
4258 [ # # ]: 0 : aLine.append( nFontDescriptor );
4259 [ # # ]: 0 : aLine.append( " 0 R\n" );
4260 [ # # ]: 0 : if( nToUnicodeStream )
4261 : : {
4262 [ # # ]: 0 : aLine.append( "/ToUnicode " );
4263 [ # # ]: 0 : aLine.append( nToUnicodeStream );
4264 [ # # ]: 0 : aLine.append( " 0 R\n" );
4265 : : }
4266 : : aLine.append( ">>\n"
4267 [ # # ]: 0 : "endobj\n\n" );
4268 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
4269 : :
4270 [ # # ]: 0 : aFontIDToObject[ lit->m_nFontID ] = nFontObject;
4271 : : }
4272 : : else
4273 : : {
4274 : 0 : const PhysicalFontFace* pFont = it->first;
4275 : 0 : rtl::OStringBuffer aErrorComment( 256 );
4276 [ # # ]: 0 : aErrorComment.append( "CreateFontSubset failed for font \"" );
4277 [ # # ][ # # ]: 0 : aErrorComment.append( OUStringToOString( pFont->GetFamilyName(), RTL_TEXTENCODING_UTF8 ) );
[ # # ]
4278 [ # # ]: 0 : aErrorComment.append( '\"' );
4279 [ # # ]: 0 : if( pFont->GetSlant() == ITALIC_NORMAL )
4280 [ # # ]: 0 : aErrorComment.append( " italic" );
4281 [ # # ]: 0 : else if( pFont->GetSlant() == ITALIC_OBLIQUE )
4282 [ # # ]: 0 : aErrorComment.append( " oblique" );
4283 [ # # ]: 0 : aErrorComment.append( " weight=" );
4284 [ # # ]: 0 : aErrorComment.append( sal_Int32(pFont->GetWeight()) );
4285 [ # # ]: 0 : emitComment( aErrorComment.getStr() );
4286 : : }
4287 [ # # ][ # # ]: 0 : }
[ # # ]
4288 : : }
4289 [ # # ]: 0 : osl_removeFile( aTmpName.pData );
4290 : :
4291 : : // emit embedded fonts
4292 [ # # ]: 0 : for( FontEmbedData::iterator eit = m_aEmbeddedFonts.begin(); eit != m_aEmbeddedFonts.end(); ++eit )
4293 : : {
4294 [ # # ]: 0 : std::map< sal_Int32, sal_Int32 > aObjects = emitEmbeddedFont( eit->first, eit->second );
4295 [ # # ][ # # ]: 0 : for( std::map< sal_Int32, sal_Int32 >::iterator fit = aObjects.begin(); fit != aObjects.end(); ++fit )
[ # # ]
4296 : : {
4297 [ # # ][ # # ]: 0 : CHECK_RETURN( fit->second );
4298 [ # # ][ # # ]: 0 : aFontIDToObject[ fit->first ] = fit->second;
[ # # ]
4299 : : }
4300 [ # # ]: 0 : }
4301 : :
4302 : : // emit system fonts
4303 [ # # ]: 0 : for( FontEmbedData::iterator sit = m_aSystemFonts.begin(); sit != m_aSystemFonts.end(); ++sit )
4304 : : {
4305 [ # # ]: 0 : std::map< sal_Int32, sal_Int32 > aObjects = emitSystemFont( sit->first, sit->second );
4306 [ # # ][ # # ]: 0 : for( std::map< sal_Int32, sal_Int32 >::iterator fit = aObjects.begin(); fit != aObjects.end(); ++fit )
[ # # ]
4307 : : {
4308 [ # # ][ # # ]: 0 : CHECK_RETURN( fit->second );
4309 [ # # ][ # # ]: 0 : aFontIDToObject[ fit->first ] = fit->second;
[ # # ]
4310 : : }
4311 [ # # ]: 0 : }
4312 : :
4313 : 0 : OStringBuffer aFontDict( 1024 );
4314 [ # # ][ # # ]: 0 : aFontDict.append( getFontDictObject() );
4315 : : aFontDict.append( " 0 obj\n"
4316 [ # # ]: 0 : "<<" );
4317 : 0 : int ni = 0;
4318 [ # # ][ # # ]: 0 : for( std::map< sal_Int32, sal_Int32 >::iterator mit = aFontIDToObject.begin(); mit != aFontIDToObject.end(); ++mit )
[ # # ]
4319 : : {
4320 [ # # ]: 0 : aFontDict.append( "/F" );
4321 [ # # ][ # # ]: 0 : aFontDict.append( mit->first );
4322 [ # # ]: 0 : aFontDict.append( ' ' );
4323 [ # # ][ # # ]: 0 : aFontDict.append( mit->second );
4324 [ # # ]: 0 : aFontDict.append( " 0 R" );
4325 [ # # ]: 0 : if( ((++ni) & 7) == 0 )
4326 [ # # ]: 0 : aFontDict.append( '\n' );
4327 : : }
4328 : : // emit builtin font for widget apperances / variable text
4329 [ # # # # ]: 0 : for( std::map< sal_Int32, sal_Int32 >::iterator it = m_aBuiltinFontToObjectMap.begin();
[ # # ]
4330 : 0 : it != m_aBuiltinFontToObjectMap.end(); ++it )
4331 : : {
4332 [ # # ][ # # ]: 0 : ImplPdfBuiltinFontData aData(m_aBuiltinFonts[it->first]);
4333 [ # # ][ # # ]: 0 : it->second = emitBuiltinFont( &aData, it->second );
[ # # ]
4334 [ # # ]: 0 : }
4335 [ # # ]: 0 : appendBuiltinFontsToDict( aFontDict );
4336 [ # # ]: 0 : aFontDict.append( "\n>>\nendobj\n\n" );
4337 : :
4338 [ # # ][ # # ]: 0 : CHECK_RETURN( updateObject( getFontDictObject() ) );
[ # # ]
4339 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aFontDict.getStr(), aFontDict.getLength() ) );
4340 : 0 : return true;
4341 : : }
4342 : :
4343 : 0 : sal_Int32 PDFWriterImpl::emitResources()
4344 : : {
4345 : : // emit shadings
4346 [ # # ]: 0 : if( ! m_aGradients.empty() )
4347 [ # # ][ # # ]: 0 : CHECK_RETURN( emitGradients() );
4348 : : // emit tilings
4349 [ # # ]: 0 : if( ! m_aTilings.empty() )
4350 [ # # ][ # # ]: 0 : CHECK_RETURN( emitTilings() );
4351 : :
4352 : : // emit font dict
4353 [ # # ][ # # ]: 0 : CHECK_RETURN( emitFonts() );
4354 : :
4355 : : // emit Resource dict
4356 : 0 : OStringBuffer aLine( 512 );
4357 [ # # ]: 0 : sal_Int32 nResourceDict = getResourceDictObj();
4358 [ # # ][ # # ]: 0 : CHECK_RETURN( updateObject( nResourceDict ) );
4359 [ # # ]: 0 : aLine.setLength( 0 );
4360 [ # # ]: 0 : aLine.append( nResourceDict );
4361 [ # # ]: 0 : aLine.append( " 0 obj\n" );
4362 [ # # ][ # # ]: 0 : m_aGlobalResourceDict.append( aLine, getFontDictObject() );
4363 [ # # ]: 0 : aLine.append( "endobj\n\n" );
4364 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
4365 : 0 : return nResourceDict;
4366 : : }
4367 : :
4368 : 0 : sal_Int32 PDFWriterImpl::updateOutlineItemCount( std::vector< sal_Int32 >& rCounts,
4369 : : sal_Int32 nItemLevel,
4370 : : sal_Int32 nCurrentItemId )
4371 : : {
4372 : : /* The /Count number of an item is
4373 : : positive: the number of visible subitems
4374 : : negative: the negative number of subitems that will become visible if
4375 : : the item gets opened
4376 : : see PDF ref 1.4 p 478
4377 : : */
4378 : :
4379 : 0 : sal_Int32 nCount = 0;
4380 : :
4381 [ # # ][ # # ]: 0 : if( m_aContext.OpenBookmarkLevels < 0 || // all levels arevisible
4382 : : m_aContext.OpenBookmarkLevels >= nItemLevel // this level is visible
4383 : : )
4384 : : {
4385 : 0 : PDFOutlineEntry& rItem = m_aOutline[ nCurrentItemId ];
4386 : 0 : sal_Int32 nChildren = rItem.m_aChildren.size();
4387 [ # # ]: 0 : for( sal_Int32 i = 0; i < nChildren; i++ )
4388 : 0 : nCount += updateOutlineItemCount( rCounts, nItemLevel+1, rItem.m_aChildren[i] );
4389 : 0 : rCounts[nCurrentItemId] = nCount;
4390 : : // return 1 (this item) + visible sub items
4391 [ # # ]: 0 : if( nCount < 0 )
4392 : 0 : nCount = 0;
4393 : 0 : nCount++;
4394 : : }
4395 : : else
4396 : : {
4397 : : // this bookmark level is invisible
4398 : 0 : PDFOutlineEntry& rItem = m_aOutline[ nCurrentItemId ];
4399 : 0 : sal_Int32 nChildren = rItem.m_aChildren.size();
4400 : 0 : rCounts[ nCurrentItemId ] = -sal_Int32(rItem.m_aChildren.size());
4401 [ # # ]: 0 : for( sal_Int32 i = 0; i < nChildren; i++ )
4402 : 0 : updateOutlineItemCount( rCounts, nItemLevel+1, rItem.m_aChildren[i] );
4403 : 0 : nCount = -1;
4404 : : }
4405 : :
4406 : 0 : return nCount;
4407 : : }
4408 : :
4409 : 0 : sal_Int32 PDFWriterImpl::emitOutline()
4410 : : {
4411 : 0 : int i, nItems = m_aOutline.size();
4412 : :
4413 : : // do we have an outline at all ?
4414 [ # # ]: 0 : if( nItems < 2 )
4415 : 0 : return 0;
4416 : :
4417 : : // reserve object numbers for all outline items
4418 [ # # ]: 0 : for( i = 0; i < nItems; ++i )
4419 [ # # ]: 0 : m_aOutline[i].m_nObject = createObject();
4420 : :
4421 : : // update all parent, next and prev object ids
4422 [ # # ]: 0 : for( i = 0; i < nItems; ++i )
4423 : : {
4424 : 0 : PDFOutlineEntry& rItem = m_aOutline[i];
4425 : 0 : int nChildren = rItem.m_aChildren.size();
4426 : :
4427 [ # # ]: 0 : if( nChildren )
4428 : : {
4429 [ # # ]: 0 : for( int n = 0; n < nChildren; ++n )
4430 : : {
4431 [ # # ]: 0 : PDFOutlineEntry& rChild = m_aOutline[ rItem.m_aChildren[n] ];
4432 : :
4433 : 0 : rChild.m_nParentObject = rItem.m_nObject;
4434 [ # # ][ # # ]: 0 : rChild.m_nPrevObject = (n > 0) ? m_aOutline[ rItem.m_aChildren[n-1] ].m_nObject : 0;
4435 [ # # ][ # # ]: 0 : rChild.m_nNextObject = (n < nChildren-1) ? m_aOutline[ rItem.m_aChildren[n+1] ].m_nObject : 0;
4436 : : }
4437 : :
4438 : : }
4439 : : }
4440 : :
4441 : : // calculate Count entries for all items
4442 [ # # ]: 0 : std::vector< sal_Int32 > aCounts( nItems );
4443 [ # # ]: 0 : updateOutlineItemCount( aCounts, 0, 0 );
4444 : :
4445 : : // emit hierarchy
4446 [ # # ]: 0 : for( i = 0; i < nItems; ++i )
4447 : : {
4448 : 0 : PDFOutlineEntry& rItem = m_aOutline[i];
4449 : 0 : OStringBuffer aLine( 1024 );
4450 : :
4451 [ # # ][ # # ]: 0 : CHECK_RETURN( updateObject( rItem.m_nObject ) );
4452 [ # # ]: 0 : aLine.append( rItem.m_nObject );
4453 [ # # ]: 0 : aLine.append( " 0 obj\n" );
4454 [ # # ]: 0 : aLine.append( "<<" );
4455 : : // number of visible children (all levels)
4456 [ # # ][ # # ]: 0 : if( i > 0 || aCounts[0] > 0 )
[ # # ][ # # ]
4457 : : {
4458 [ # # ]: 0 : aLine.append( "/Count " );
4459 [ # # ][ # # ]: 0 : aLine.append( aCounts[i] );
4460 : : }
4461 [ # # ]: 0 : if( ! rItem.m_aChildren.empty() )
4462 : : {
4463 : : // children list: First, Last
4464 [ # # ]: 0 : aLine.append( "/First " );
4465 [ # # ][ # # ]: 0 : aLine.append( m_aOutline[rItem.m_aChildren.front()].m_nObject );
4466 [ # # ]: 0 : aLine.append( " 0 R/Last " );
4467 [ # # ][ # # ]: 0 : aLine.append( m_aOutline[rItem.m_aChildren.back()].m_nObject );
4468 [ # # ]: 0 : aLine.append( " 0 R\n" );
4469 : : }
4470 [ # # ]: 0 : if( i > 0 )
4471 : : {
4472 : : // Title, Dest, Parent, Prev, Next
4473 [ # # ]: 0 : aLine.append( "/Title" );
4474 [ # # ]: 0 : appendUnicodeTextStringEncrypt( rItem.m_aTitle, rItem.m_nObject, aLine );
4475 [ # # ]: 0 : aLine.append( "\n" );
4476 : : // Dest is not required
4477 [ # # ][ # # ]: 0 : if( rItem.m_nDestID >= 0 && rItem.m_nDestID < (sal_Int32)m_aDests.size() )
[ # # ]
4478 : : {
4479 [ # # ]: 0 : aLine.append( "/Dest" );
4480 [ # # ]: 0 : appendDest( rItem.m_nDestID, aLine );
4481 : : }
4482 [ # # ]: 0 : aLine.append( "/Parent " );
4483 [ # # ]: 0 : aLine.append( rItem.m_nParentObject );
4484 [ # # ]: 0 : aLine.append( " 0 R" );
4485 [ # # ]: 0 : if( rItem.m_nPrevObject )
4486 : : {
4487 [ # # ]: 0 : aLine.append( "/Prev " );
4488 [ # # ]: 0 : aLine.append( rItem.m_nPrevObject );
4489 [ # # ]: 0 : aLine.append( " 0 R" );
4490 : : }
4491 [ # # ]: 0 : if( rItem.m_nNextObject )
4492 : : {
4493 [ # # ]: 0 : aLine.append( "/Next " );
4494 [ # # ]: 0 : aLine.append( rItem.m_nNextObject );
4495 [ # # ]: 0 : aLine.append( " 0 R" );
4496 : : }
4497 : : }
4498 [ # # ]: 0 : aLine.append( ">>\nendobj\n\n" );
4499 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
4500 [ # # ]: 0 : }
4501 : :
4502 : 0 : return m_aOutline[0].m_nObject;
4503 : : }
4504 : :
4505 : : #undef CHECK_RETURN
4506 : : #define CHECK_RETURN( x ) if( !x ) return false
4507 : :
4508 : 0 : bool PDFWriterImpl::appendDest( sal_Int32 nDestID, OStringBuffer& rBuffer )
4509 : : {
4510 [ # # ][ # # ]: 0 : if( nDestID < 0 || nDestID >= (sal_Int32)m_aDests.size() )
[ # # ]
4511 : : {
4512 : : #if OSL_DEBUG_LEVEL > 1
4513 : : fprintf( stderr, "ERROR: invalid dest %d requested\n", (int)nDestID );
4514 : : #endif
4515 : 0 : return false;
4516 : : }
4517 : :
4518 : :
4519 : 0 : const PDFDest& rDest = m_aDests[ nDestID ];
4520 : 0 : const PDFPage& rDestPage = m_aPages[ rDest.m_nPage ];
4521 : :
4522 : 0 : rBuffer.append( '[' );
4523 : 0 : rBuffer.append( rDestPage.m_nPageObject );
4524 : 0 : rBuffer.append( " 0 R" );
4525 : :
4526 [ # # # # : 0 : switch( rDest.m_eType )
# # # # ]
4527 : : {
4528 : : case PDFWriter::XYZ:
4529 : : default:
4530 : 0 : rBuffer.append( "/XYZ " );
4531 : 0 : appendFixedInt( rDest.m_aRect.Left(), rBuffer );
4532 : 0 : rBuffer.append( ' ' );
4533 : 0 : appendFixedInt( rDest.m_aRect.Bottom(), rBuffer );
4534 : 0 : rBuffer.append( " 0" );
4535 : 0 : break;
4536 : : case PDFWriter::Fit:
4537 : 0 : rBuffer.append( "/Fit" );
4538 : 0 : break;
4539 : : case PDFWriter::FitRectangle:
4540 : 0 : rBuffer.append( "/FitR " );
4541 : 0 : appendFixedInt( rDest.m_aRect.Left(), rBuffer );
4542 : 0 : rBuffer.append( ' ' );
4543 : 0 : appendFixedInt( rDest.m_aRect.Top(), rBuffer );
4544 : 0 : rBuffer.append( ' ' );
4545 : 0 : appendFixedInt( rDest.m_aRect.Right(), rBuffer );
4546 : 0 : rBuffer.append( ' ' );
4547 : 0 : appendFixedInt( rDest.m_aRect.Bottom(), rBuffer );
4548 : 0 : break;
4549 : : case PDFWriter::FitHorizontal:
4550 : 0 : rBuffer.append( "/FitH " );
4551 : 0 : appendFixedInt( rDest.m_aRect.Bottom(), rBuffer );
4552 : 0 : break;
4553 : : case PDFWriter::FitVertical:
4554 : 0 : rBuffer.append( "/FitV " );
4555 : 0 : appendFixedInt( rDest.m_aRect.Left(), rBuffer );
4556 : 0 : break;
4557 : : case PDFWriter::FitPageBoundingBox:
4558 : 0 : rBuffer.append( "/FitB" );
4559 : 0 : break;
4560 : : case PDFWriter::FitPageBoundingBoxHorizontal:
4561 : 0 : rBuffer.append( "/FitBH " );
4562 : 0 : appendFixedInt( rDest.m_aRect.Bottom(), rBuffer );
4563 : 0 : break;
4564 : : case PDFWriter::FitPageBoundingBoxVertical:
4565 : 0 : rBuffer.append( "/FitBV " );
4566 : 0 : appendFixedInt( rDest.m_aRect.Left(), rBuffer );
4567 : 0 : break;
4568 : : }
4569 : 0 : rBuffer.append( ']' );
4570 : :
4571 : 0 : return true;
4572 : : }
4573 : :
4574 : 0 : bool PDFWriterImpl::emitLinkAnnotations()
4575 : : {
4576 : 0 : int nAnnots = m_aLinks.size();
4577 [ # # ]: 0 : for( int i = 0; i < nAnnots; i++ )
4578 : : {
4579 : 0 : const PDFLink& rLink = m_aLinks[i];
4580 [ # # ][ # # ]: 0 : if( ! updateObject( rLink.m_nObject ) )
4581 : 0 : continue;
4582 : :
4583 : 0 : OStringBuffer aLine( 1024 );
4584 [ # # ]: 0 : aLine.append( rLink.m_nObject );
4585 [ # # ]: 0 : aLine.append( " 0 obj\n" );
4586 : : //i59651 key /F set bits Print to 1 rest to 0. We don't set NoZoom NoRotate to 1, since it's a 'should'
4587 : : // see PDF 8.4.2 and ISO 19005-1:2005 6.5.3
4588 [ # # ]: 0 : aLine.append( "<</Type/Annot" );
4589 [ # # ]: 0 : if( m_bIsPDF_A1 )
4590 [ # # ]: 0 : aLine.append( "/F 4" );
4591 [ # # ]: 0 : aLine.append( "/Subtype/Link/Border[0 0 0]/Rect[" );
4592 : :
4593 [ # # ]: 0 : appendFixedInt( rLink.m_aRect.Left()-7, aLine );//the +7 to have a better shape of the border rectangle
4594 [ # # ]: 0 : aLine.append( ' ' );
4595 [ # # ]: 0 : appendFixedInt( rLink.m_aRect.Top(), aLine );
4596 [ # # ]: 0 : aLine.append( ' ' );
4597 [ # # ]: 0 : appendFixedInt( rLink.m_aRect.Right()+7, aLine );//the +7 to have a better shape of the border rectangle
4598 [ # # ]: 0 : aLine.append( ' ' );
4599 [ # # ]: 0 : appendFixedInt( rLink.m_aRect.Bottom(), aLine );
4600 [ # # ]: 0 : aLine.append( "]" );
4601 [ # # ]: 0 : if( rLink.m_nDest >= 0 )
4602 : : {
4603 [ # # ]: 0 : aLine.append( "/Dest" );
4604 [ # # ]: 0 : appendDest( rLink.m_nDest, aLine );
4605 : : }
4606 : : else
4607 : : {
4608 : : /*--->i56629
4609 : : destination is external to the document, so
4610 : : we check in the following sequence:
4611 : :
4612 : : if target type is neither .pdf, nor .od[tpgs], then
4613 : : check if relative or absolute and act accordingly (use URI or 'launch application' as requested)
4614 : : end processing
4615 : : else if target is .od[tpgs]: then
4616 : : if conversion of type from od[tpgs] to pdf is requested, convert it and this becomes the new target file
4617 : : processing continue
4618 : :
4619 : : if (new)target is .pdf : then
4620 : : if GotToR is requested, then
4621 : : convert the target in GoToR where the fragment of the URI is
4622 : : considered the named destination in the target file, set relative or absolute as requested
4623 : : else strip the fragment from URL and then set URI or 'launch application' as requested
4624 : : */
4625 : : //
4626 : : // FIXME: check if the decode mechanisms for URL processing throughout this implementation
4627 : : // are the correct one!!
4628 : : //
4629 : : // extract target file type
4630 [ # # ]: 0 : INetURLObject aDocumentURL( m_aContext.BaseURL );
4631 [ # # ]: 0 : INetURLObject aTargetURL( rLink.m_aURL );
4632 : 0 : sal_Int32 nSetGoToRMode = 0;
4633 : 0 : sal_Bool bTargetHasPDFExtension = sal_False;
4634 : 0 : INetProtocol eTargetProtocol = aTargetURL.GetProtocol();
4635 : 0 : sal_Bool bIsUNCPath = sal_False;
4636 : : // check if the protocol is a known one, or if there is no protocol at all (on target only)
4637 : : // if there is no protocol, make the target relative to the current document directory
4638 : : // getting the needed URL information from the current document path
4639 [ # # ]: 0 : if( eTargetProtocol == INET_PROT_NOT_VALID )
4640 : : {
4641 [ # # ][ # # ]: 0 : if( rLink.m_aURL.getLength() > 4 && rLink.m_aURL.compareToAscii( "\\\\\\\\", 4 ) == 0)
[ # # ]
4642 : : {
4643 : 0 : bIsUNCPath = sal_True;
4644 : : }
4645 : : else
4646 : : {
4647 [ # # ]: 0 : INetURLObject aNewBase( aDocumentURL );//duplicate document URL
4648 [ # # ]: 0 : aNewBase.removeSegment(); //remove last segment from it, obtaining the base URL of the
4649 : : //target document
4650 [ # # ]: 0 : aNewBase.insertName( rLink.m_aURL );
4651 [ # # ]: 0 : aTargetURL = aNewBase;//reassign the new target URL
4652 : : //recompute the target protocol, with the new URL
4653 : : //normal URL processing resumes
4654 [ # # ]: 0 : eTargetProtocol = aTargetURL.GetProtocol();
4655 : : }
4656 : : }
4657 : :
4658 [ # # ]: 0 : rtl::OUString aFileExtension = aTargetURL.GetFileExtension();
4659 : :
4660 : : // Check if the URL ends in '/': if yes it's a directory,
4661 : : // it will be forced to a URI link.
4662 : : // possibly a malformed URI, leave it as it is, force as URI
4663 [ # # ][ # # ]: 0 : if( aTargetURL.hasFinalSlash() )
4664 : 0 : m_aContext.DefaultLinkAction = PDFWriter::URIAction;
4665 : :
4666 [ # # ]: 0 : if( !aFileExtension.isEmpty() )
4667 : : {
4668 [ # # ]: 0 : if( m_aContext.ConvertOOoTargetToPDFTarget )
4669 : : {
4670 : 0 : sal_Int32 bChangeFileExtensionToPDF = false;
4671 : : //examine the file type (.odm .odt. .odp, odg, ods)
4672 [ # # ]: 0 : if( aFileExtension.equalsIgnoreAsciiCase(rtl::OUString( "odm" ) ) )
4673 : 0 : bChangeFileExtensionToPDF = true;
4674 [ # # ]: 0 : if( aFileExtension.equalsIgnoreAsciiCase(rtl::OUString( "odt" ) ) )
4675 : 0 : bChangeFileExtensionToPDF = true;
4676 [ # # ]: 0 : else if( aFileExtension.equalsIgnoreAsciiCase(rtl::OUString( "odp" ) ) )
4677 : 0 : bChangeFileExtensionToPDF = true;
4678 [ # # ]: 0 : else if( aFileExtension.equalsIgnoreAsciiCase(rtl::OUString( "odg" ) ) )
4679 : 0 : bChangeFileExtensionToPDF = true;
4680 [ # # ]: 0 : else if( aFileExtension.equalsIgnoreAsciiCase(rtl::OUString( "ods" ) ) )
4681 : 0 : bChangeFileExtensionToPDF = true;
4682 [ # # ]: 0 : if( bChangeFileExtensionToPDF )
4683 [ # # ]: 0 : aTargetURL.setExtension(rtl::OUString( "pdf" ) );
4684 : : }
4685 : : //check if extension is pdf, see if GoToR should be forced
4686 [ # # ]: 0 : bTargetHasPDFExtension = aTargetURL.GetFileExtension().equalsIgnoreAsciiCase(rtl::OUString( "pdf" ) );
4687 [ # # ][ # # ]: 0 : if( m_aContext.ForcePDFAction && bTargetHasPDFExtension )
4688 : 0 : nSetGoToRMode++;
4689 : : }
4690 : : //prepare the URL, if relative or not
4691 : 0 : INetProtocol eBaseProtocol = aDocumentURL.GetProtocol();
4692 : : //queue the string common to all types of actions
4693 [ # # ]: 0 : aLine.append( "/A<</Type/Action/S");
4694 [ # # ]: 0 : if( bIsUNCPath ) // handle Win UNC paths
4695 : : {
4696 [ # # ]: 0 : aLine.append( "/Launch/Win<</F" );
4697 : : // INetURLObject is not good with UNC paths, use original path
4698 [ # # ][ # # ]: 0 : appendLiteralStringEncrypt( rLink.m_aURL, rLink.m_nObject, aLine, osl_getThreadTextEncoding() );
4699 [ # # ]: 0 : aLine.append( ">>" );
4700 : : }
4701 : : else
4702 : : {
4703 : 0 : bool bSetRelative = false;
4704 : 0 : bool bFileSpec = false;
4705 : : //check if relative file link is requested and if the protocol is 'file://'
4706 [ # # ][ # # ]: 0 : if( m_aContext.RelFsys && eBaseProtocol == eTargetProtocol && eTargetProtocol == INET_PROT_FILE )
[ # # ]
4707 : 0 : bSetRelative = true;
4708 : :
4709 [ # # ]: 0 : rtl::OUString aFragment = aTargetURL.GetMark( INetURLObject::NO_DECODE /*DECODE_WITH_CHARSET*/ ); //fragment as is,
4710 [ # # ]: 0 : if( nSetGoToRMode == 0 )
4711 : : {
4712 [ # # ]: 0 : switch( m_aContext.DefaultLinkAction )
4713 : : {
4714 : : default:
4715 : : case PDFWriter::URIAction :
4716 : : case PDFWriter::URIActionDestination :
4717 [ # # ]: 0 : aLine.append( "/URI/URI" );
4718 : 0 : break;
4719 : : case PDFWriter::LaunchAction:
4720 : : // now:
4721 : : // if a launch action is requested and the hyperlink target has a fragment
4722 : : // and the target file does not have a pdf extension, or it's not a 'file:://' protocol
4723 : : // then force the uri action on it
4724 : : // This code will permit the correct opening of application on web pages, the one that
4725 : : // normally have fragments (but I may be wrong...)
4726 : : // and will force the use of URI when the protocol is not file://
4727 [ # # ][ # # ]: 0 : if( (!aFragment.isEmpty() && !bTargetHasPDFExtension) ||
[ # # ][ # # ]
4728 : : eTargetProtocol != INET_PROT_FILE )
4729 : : {
4730 [ # # ]: 0 : aLine.append( "/URI/URI" );
4731 : : }
4732 : : else
4733 : : {
4734 [ # # ]: 0 : aLine.append( "/Launch/F" );
4735 : 0 : bFileSpec = true;
4736 : : }
4737 : 0 : break;
4738 : : }
4739 : : }
4740 : : //fragment are encoded in the same way as in the named destination processing
4741 [ # # ]: 0 : if( nSetGoToRMode )
4742 : : {
4743 : : //add the fragment
4744 [ # # ]: 0 : rtl::OUString aURLNoMark = aTargetURL.GetURLNoMark( INetURLObject::DECODE_WITH_CHARSET );
4745 [ # # ]: 0 : aLine.append("/GoToR");
4746 [ # # ]: 0 : aLine.append("/F");
4747 : 0 : bFileSpec = true;
4748 : : appendLiteralStringEncrypt( bSetRelative ? INetURLObject::GetRelURL( m_aContext.BaseURL, aURLNoMark,
4749 : : INetURLObject::WAS_ENCODED,
4750 : : INetURLObject::DECODE_WITH_CHARSET ) :
4751 [ # # ][ # # ]: 0 : aURLNoMark, rLink.m_nObject, aLine, osl_getThreadTextEncoding() );
[ # # ][ # # ]
4752 [ # # ]: 0 : if( !aFragment.isEmpty() )
4753 : : {
4754 [ # # ]: 0 : aLine.append("/D/");
4755 [ # # ]: 0 : appendDestinationName( aFragment , aLine );
4756 : 0 : }
4757 : : }
4758 : : else
4759 : : {
4760 : : // change the fragment to accomodate the bookmark (only if the file extension is PDF and
4761 : : // the requested action is of the correct type)
4762 [ # # ]: 0 : if(m_aContext.DefaultLinkAction == PDFWriter::URIActionDestination &&
[ # # # # ]
[ # # ]
4763 : 0 : bTargetHasPDFExtension && !aFragment.isEmpty() )
4764 : : {
4765 : 0 : OStringBuffer aLineLoc( 1024 );
4766 [ # # ]: 0 : appendDestinationName( aFragment , aLineLoc );
4767 : : //substitute the fragment
4768 [ # # ]: 0 : aTargetURL.SetMark( aLineLoc.getStr() );
4769 : : }
4770 [ # # ][ # # ]: 0 : rtl::OUString aURL = aTargetURL.GetMainURL( bFileSpec ? INetURLObject::DECODE_WITH_CHARSET : INetURLObject::NO_DECODE );
4771 : : appendLiteralStringEncrypt(bSetRelative ? INetURLObject::GetRelURL( m_aContext.BaseURL, aURL,
4772 : : INetURLObject::WAS_ENCODED,
4773 : : bFileSpec ? INetURLObject::DECODE_WITH_CHARSET : INetURLObject::NO_DECODE
4774 : : ) :
4775 [ # # ][ # # ]: 0 : aURL , rLink.m_nObject, aLine, osl_getThreadTextEncoding() );
[ # # ][ # # ]
[ # # ]
4776 : 0 : }
4777 : : //<--- i56629
4778 : : }
4779 [ # # ][ # # ]: 0 : aLine.append( ">>\n" );
[ # # ]
4780 : : }
4781 [ # # ]: 0 : if( rLink.m_nStructParent > 0 )
4782 : : {
4783 [ # # ]: 0 : aLine.append( "/StructParent " );
4784 [ # # ]: 0 : aLine.append( rLink.m_nStructParent );
4785 : : }
4786 [ # # ]: 0 : aLine.append( ">>\nendobj\n\n" );
4787 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
4788 [ # # ]: 0 : }
4789 : :
4790 : 0 : return true;
4791 : : }
4792 : :
4793 : 0 : bool PDFWriterImpl::emitNoteAnnotations()
4794 : : {
4795 : : // emit note annotations
4796 : 0 : int nAnnots = m_aNotes.size();
4797 [ # # ]: 0 : for( int i = 0; i < nAnnots; i++ )
4798 : : {
4799 : 0 : const PDFNoteEntry& rNote = m_aNotes[i];
4800 [ # # ][ # # ]: 0 : if( ! updateObject( rNote.m_nObject ) )
4801 : 0 : return false;
4802 : :
4803 : 0 : OStringBuffer aLine( 1024 );
4804 [ # # ]: 0 : aLine.append( rNote.m_nObject );
4805 [ # # ]: 0 : aLine.append( " 0 obj\n" );
4806 : : //i59651 key /F set bits Print to 1 rest to 0. We don't set NoZoom NoRotate to 1, since it's a 'should'
4807 : : // see PDF 8.4.2 and ISO 19005-1:2005 6.5.3
4808 [ # # ]: 0 : aLine.append( "<</Type/Annot" );
4809 [ # # ]: 0 : if( m_bIsPDF_A1 )
4810 [ # # ]: 0 : aLine.append( "/F 4" );
4811 [ # # ]: 0 : aLine.append( "/Subtype/Text/Rect[" );
4812 : :
4813 [ # # ]: 0 : appendFixedInt( rNote.m_aRect.Left(), aLine );
4814 [ # # ]: 0 : aLine.append( ' ' );
4815 [ # # ]: 0 : appendFixedInt( rNote.m_aRect.Top(), aLine );
4816 [ # # ]: 0 : aLine.append( ' ' );
4817 [ # # ]: 0 : appendFixedInt( rNote.m_aRect.Right(), aLine );
4818 [ # # ]: 0 : aLine.append( ' ' );
4819 [ # # ]: 0 : appendFixedInt( rNote.m_aRect.Bottom(), aLine );
4820 [ # # ]: 0 : aLine.append( "]" );
4821 : :
4822 : : // contents of the note (type text string)
4823 [ # # ]: 0 : aLine.append( "/Contents\n" );
4824 [ # # ][ # # ]: 0 : appendUnicodeTextStringEncrypt( rNote.m_aContents.Contents, rNote.m_nObject, aLine );
4825 [ # # ]: 0 : aLine.append( "\n" );
4826 : :
4827 : : // optional title
4828 [ # # ]: 0 : if( rNote.m_aContents.Title.Len() )
4829 : : {
4830 [ # # ]: 0 : aLine.append( "/T" );
4831 [ # # ][ # # ]: 0 : appendUnicodeTextStringEncrypt( rNote.m_aContents.Title, rNote.m_nObject, aLine );
4832 [ # # ]: 0 : aLine.append( "\n" );
4833 : : }
4834 : :
4835 [ # # ]: 0 : aLine.append( ">>\nendobj\n\n" );
4836 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
4837 [ # # ]: 0 : }
4838 : 0 : return true;
4839 : : }
4840 : :
4841 : 0 : Font PDFWriterImpl::replaceFont( const Font& rControlFont, const Font& rAppSetFont )
4842 : : {
4843 : 0 : bool bAdjustSize = false;
4844 : :
4845 : 0 : Font aFont( rControlFont );
4846 [ # # ][ # # ]: 0 : if( ! aFont.GetName().Len() )
4847 : : {
4848 [ # # ]: 0 : aFont = rAppSetFont;
4849 [ # # ][ # # ]: 0 : if( rControlFont.GetHeight() )
4850 [ # # ][ # # ]: 0 : aFont.SetSize( Size( 0, rControlFont.GetHeight() ) );
4851 : : else
4852 : 0 : bAdjustSize = true;
4853 [ # # ][ # # ]: 0 : if( rControlFont.GetItalic() != ITALIC_DONTKNOW )
4854 [ # # ][ # # ]: 0 : aFont.SetItalic( rControlFont.GetItalic() );
4855 [ # # ][ # # ]: 0 : if( rControlFont.GetWeight() != WEIGHT_DONTKNOW )
4856 [ # # ][ # # ]: 0 : aFont.SetWeight( rControlFont.GetWeight() );
4857 : : }
4858 [ # # ][ # # ]: 0 : else if( ! aFont.GetHeight() )
4859 : : {
4860 [ # # ][ # # ]: 0 : aFont.SetSize( rAppSetFont.GetSize() );
4861 : 0 : bAdjustSize = true;
4862 : : }
4863 [ # # ]: 0 : if( bAdjustSize )
4864 : : {
4865 [ # # ]: 0 : Size aFontSize = aFont.GetSize();
4866 [ # # ]: 0 : OutputDevice* pDefDev = Application::GetDefaultDevice();
4867 [ # # ][ # # ]: 0 : aFontSize = OutputDevice::LogicToLogic( aFontSize, pDefDev->GetMapMode(), getMapMode() );
4868 [ # # ]: 0 : aFont.SetSize( aFontSize );
4869 : : }
4870 : 0 : return aFont;
4871 : : }
4872 : :
4873 : 0 : sal_Int32 PDFWriterImpl::getBestBuiltinFont( const Font& rFont )
4874 : : {
4875 : 0 : sal_Int32 nBest = 4; // default to Helvetica
4876 [ # # ][ # # ]: 0 : OUString aFontName( rFont.GetName() );
4877 : 0 : aFontName = aFontName.toAsciiLowerCase();
4878 : :
4879 [ # # ]: 0 : if( aFontName.indexOf( "times" ) != -1 )
4880 : 0 : nBest = 8;
4881 [ # # ]: 0 : else if( aFontName.indexOf( "courier" ) != -1 )
4882 : 0 : nBest = 0;
4883 [ # # ]: 0 : else if( aFontName.indexOf( "dingbats" ) != -1 )
4884 : 0 : nBest = 13;
4885 [ # # ]: 0 : else if( aFontName.indexOf( "symbol" ) != -1 )
4886 : 0 : nBest = 12;
4887 [ # # ]: 0 : if( nBest < 12 )
4888 : : {
4889 [ # # ][ # # ]: 0 : if( rFont.GetItalic() == ITALIC_OBLIQUE || rFont.GetItalic() == ITALIC_NORMAL )
[ # # ][ # # ]
[ # # ]
4890 : 0 : nBest += 1;
4891 [ # # ][ # # ]: 0 : if( rFont.GetWeight() > WEIGHT_MEDIUM )
4892 : 0 : nBest += 2;
4893 : : }
4894 : :
4895 [ # # ][ # # ]: 0 : if( m_aBuiltinFontToObjectMap.find( nBest ) == m_aBuiltinFontToObjectMap.end() )
[ # # ]
4896 [ # # ][ # # ]: 0 : m_aBuiltinFontToObjectMap[ nBest ] = createObject();
4897 : :
4898 : 0 : return nBest;
4899 : : }
4900 : :
4901 : 0 : static inline const Color& replaceColor( const Color& rCol1, const Color& rCol2 )
4902 : : {
4903 [ # # ]: 0 : return (rCol1 == Color( COL_TRANSPARENT )) ? rCol2 : rCol1;
4904 : : }
4905 : :
4906 : 0 : void PDFWriterImpl::createDefaultPushButtonAppearance( PDFWidget& rButton, const PDFWriter::PushButtonWidget& rWidget )
4907 : : {
4908 [ # # ]: 0 : const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
4909 : :
4910 : : // save graphics state
4911 [ # # ]: 0 : push( sal::static_int_cast<sal_uInt16>(~0U) );
4912 : :
4913 : : // transform relative to control's coordinates since an
4914 : : // appearance stream is a form XObject
4915 : : // this relies on the m_aRect member of rButton NOT already being transformed
4916 : : // to default user space
4917 [ # # ][ # # ]: 0 : if( rWidget.Background || rWidget.Border )
4918 : : {
4919 [ # # ][ # # ]: 0 : setLineColor( rWidget.Border ? replaceColor( rWidget.BorderColor, rSettings.GetLightColor() ) : Color( COL_TRANSPARENT ) );
4920 [ # # ][ # # ]: 0 : setFillColor( rWidget.Background ? replaceColor( rWidget.BackgroundColor, rSettings.GetDialogColor() ) : Color( COL_TRANSPARENT ) );
4921 [ # # ]: 0 : drawRectangle( rWidget.Location );
4922 : : }
4923 : : // prepare font to use
4924 [ # # ]: 0 : Font aFont = replaceFont( rWidget.TextFont, rSettings.GetPushButtonFont() );
4925 [ # # ]: 0 : setFont( aFont );
4926 [ # # ]: 0 : setTextColor( replaceColor( rWidget.TextColor, rSettings.GetButtonTextColor() ) );
4927 : :
4928 [ # # ][ # # ]: 0 : drawText( rButton.m_aRect, rButton.m_aText, rButton.m_nTextStyle );
[ # # ]
4929 : :
4930 : : // create DA string while local mapmode is still in place
4931 : : // (that is before endRedirect())
4932 : 0 : OStringBuffer aDA( 256 );
4933 [ # # ]: 0 : appendNonStrokingColor( replaceColor( rWidget.TextColor, rSettings.GetButtonTextColor() ), aDA );
4934 [ # # ][ # # ]: 0 : Font aDummyFont( String( RTL_CONSTASCII_USTRINGPARAM( "Helvetica" ) ), aFont.GetSize() );
[ # # ][ # # ]
4935 [ # # ]: 0 : sal_Int32 nDummyBuiltin = getBestBuiltinFont( aDummyFont );
4936 [ # # ]: 0 : aDA.append( ' ' );
4937 [ # # ][ # # ]: 0 : aDA.append( m_aBuiltinFonts[nDummyBuiltin].getNameObject() );
4938 [ # # ]: 0 : aDA.append( ' ' );
4939 [ # # ][ # # ]: 0 : m_aPages[m_nCurrentPage].appendMappedLength( sal_Int32( aFont.GetHeight() ), aDA );
4940 [ # # ]: 0 : aDA.append( " Tf" );
4941 : 0 : rButton.m_aDAString = aDA.makeStringAndClear();
4942 : :
4943 [ # # ]: 0 : pop();
4944 : :
4945 [ # # ][ # # ]: 0 : rButton.m_aAppearances[ "N" ][ "Standard" ] = new SvMemoryStream();
[ # # ][ # # ]
4946 : :
4947 : : /* seems like a bad hack but at least works in both AR5 and 6:
4948 : : we draw the button ourselves and tell AR
4949 : : the button would be totally transparent with no text
4950 : :
4951 : : One would expect that simply setting a normal appearance
4952 : : should suffice, but no, as soon as the user actually presses
4953 : : the button and an action is tied to it (gasp! a button that
4954 : : does something) the appearance gets replaced by some crap that AR
4955 : : creates on the fly even if no DA or MK is given. On AR6 at least
4956 : : the DA and MK work as expected, but on AR5 this creates a region
4957 : : filled with the background color but nor text. Urgh.
4958 : : */
4959 : 0 : rButton.m_aMKDict = "/BC [] /BG [] /CA";
4960 [ # # ][ # # ]: 0 : rButton.m_aMKDictCAString = "";
4961 : 0 : }
4962 : :
4963 : 0 : Font PDFWriterImpl::drawFieldBorder( PDFWidget& rIntern,
4964 : : const PDFWriter::AnyWidget& rWidget,
4965 : : const StyleSettings& rSettings )
4966 : : {
4967 : 0 : Font aFont = replaceFont( rWidget.TextFont, rSettings.GetFieldFont() );
4968 : :
4969 [ # # ][ # # ]: 0 : if( rWidget.Background || rWidget.Border )
4970 : : {
4971 [ # # ][ # # ]: 0 : if( rWidget.Border && rWidget.BorderColor == Color( COL_TRANSPARENT ) )
[ # # ][ # # ]
4972 : : {
4973 [ # # ]: 0 : sal_Int32 nDelta = getReferenceDevice()->ImplGetDPIX() / 500;
4974 [ # # ]: 0 : if( nDelta < 1 )
4975 : 0 : nDelta = 1;
4976 [ # # ]: 0 : setLineColor( Color( COL_TRANSPARENT ) );
4977 : 0 : Rectangle aRect = rIntern.m_aRect;
4978 [ # # ]: 0 : setFillColor( rSettings.GetLightBorderColor() );
4979 [ # # ]: 0 : drawRectangle( aRect );
4980 : 0 : aRect.Left() += nDelta; aRect.Top() += nDelta;
4981 : 0 : aRect.Right() -= nDelta; aRect.Bottom() -= nDelta;
4982 [ # # ]: 0 : setFillColor( rSettings.GetFieldColor() );
4983 [ # # ]: 0 : drawRectangle( aRect );
4984 [ # # ]: 0 : setFillColor( rSettings.GetLightColor() );
4985 [ # # ][ # # ]: 0 : drawRectangle( Rectangle( Point( aRect.Left(), aRect.Bottom()-nDelta ), aRect.BottomRight() ) );
[ # # ]
4986 [ # # ][ # # ]: 0 : drawRectangle( Rectangle( Point( aRect.Right()-nDelta, aRect.Top() ), aRect.BottomRight() ) );
[ # # ]
4987 [ # # ]: 0 : setFillColor( rSettings.GetDarkShadowColor() );
4988 [ # # ][ # # ]: 0 : drawRectangle( Rectangle( aRect.TopLeft(), Point( aRect.Left()+nDelta, aRect.Bottom() ) ) );
4989 [ # # ][ # # ]: 0 : drawRectangle( Rectangle( aRect.TopLeft(), Point( aRect.Right(), aRect.Top()+nDelta ) ) );
4990 : : }
4991 : : else
4992 : : {
4993 [ # # ][ # # ]: 0 : setLineColor( rWidget.Border ? replaceColor( rWidget.BorderColor, rSettings.GetShadowColor() ) : Color( COL_TRANSPARENT ) );
4994 [ # # ][ # # ]: 0 : setFillColor( rWidget.Background ? replaceColor( rWidget.BackgroundColor, rSettings.GetFieldColor() ) : Color( COL_TRANSPARENT ) );
4995 [ # # ]: 0 : drawRectangle( rIntern.m_aRect );
4996 : : }
4997 : :
4998 [ # # ]: 0 : if( rWidget.Border )
4999 : : {
5000 : : // adjust edit area accounting for border
5001 [ # # ]: 0 : sal_Int32 nDelta = aFont.GetHeight()/4;
5002 [ # # ]: 0 : if( nDelta < 1 )
5003 : 0 : nDelta = 1;
5004 : 0 : rIntern.m_aRect.Left() += nDelta;
5005 : 0 : rIntern.m_aRect.Top() += nDelta;
5006 : 0 : rIntern.m_aRect.Right() -= nDelta;
5007 : 0 : rIntern.m_aRect.Bottom()-= nDelta;
5008 : : }
5009 : : }
5010 : 0 : return aFont;
5011 : : }
5012 : :
5013 : 0 : void PDFWriterImpl::createDefaultEditAppearance( PDFWidget& rEdit, const PDFWriter::EditWidget& rWidget )
5014 : : {
5015 [ # # ]: 0 : const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
5016 [ # # ][ # # ]: 0 : SvMemoryStream* pEditStream = new SvMemoryStream( 1024, 1024 );
5017 : :
5018 [ # # ]: 0 : push( sal::static_int_cast<sal_uInt16>(~0U) );
5019 : :
5020 : : // prepare font to use, draw field border
5021 [ # # ]: 0 : Font aFont = drawFieldBorder( rEdit, rWidget, rSettings );
5022 [ # # ][ # # ]: 0 : sal_Int32 nBest = m_aContext.FieldsUseSystemFonts ? getSystemFont( aFont ): getBestBuiltinFont( aFont );
[ # # ]
5023 : :
5024 : : // prepare DA string
5025 : 0 : OStringBuffer aDA( 32 );
5026 [ # # ]: 0 : appendNonStrokingColor( replaceColor( rWidget.TextColor, rSettings.GetFieldTextColor() ), aDA );
5027 [ # # ]: 0 : aDA.append( ' ' );
5028 [ # # ]: 0 : if( m_aContext.FieldsUseSystemFonts )
5029 : : {
5030 [ # # ]: 0 : aDA.append( "/F" );
5031 [ # # ]: 0 : aDA.append( nBest );
5032 : :
5033 : 0 : OStringBuffer aDR( 32 );
5034 [ # # ]: 0 : aDR.append( "/Font " );
5035 [ # # ][ # # ]: 0 : aDR.append( getFontDictObject() );
5036 [ # # ]: 0 : aDR.append( " 0 R" );
5037 : 0 : rEdit.m_aDRDict = aDR.makeStringAndClear();
5038 : : }
5039 : : else
5040 [ # # ][ # # ]: 0 : aDA.append( m_aBuiltinFonts[nBest].getNameObject() );
5041 [ # # ]: 0 : aDA.append( ' ' );
5042 [ # # ][ # # ]: 0 : m_aPages[ m_nCurrentPage ].appendMappedLength( sal_Int32( aFont.GetHeight() ), aDA );
5043 [ # # ]: 0 : aDA.append( " Tf" );
5044 : :
5045 : : /* create an empty appearance stream, let the viewer create
5046 : : the appearance at runtime. This is because AR5 seems to
5047 : : paint the widget appearance always, and a dynamically created
5048 : : appearance on top of it. AR6 is well behaved in that regard, so
5049 : : that behaviour seems to be a bug. Anyway this empty appearance
5050 : : relies on /NeedAppearances in the AcroForm dictionary set to "true"
5051 : : */
5052 [ # # ]: 0 : beginRedirect( pEditStream, rEdit.m_aRect );
5053 : 0 : OStringBuffer aAppearance( 32 );
5054 [ # # ]: 0 : aAppearance.append( "/Tx BMC\nEMC\n" );
5055 [ # # ]: 0 : writeBuffer( aAppearance.getStr(), aAppearance.getLength() );
5056 : :
5057 [ # # ]: 0 : endRedirect();
5058 [ # # ]: 0 : pop();
5059 : :
5060 [ # # ][ # # ]: 0 : rEdit.m_aAppearances[ "N" ][ "Standard" ] = pEditStream;
5061 : :
5062 [ # # ]: 0 : rEdit.m_aDAString = aDA.makeStringAndClear();
5063 : 0 : }
5064 : :
5065 : 0 : void PDFWriterImpl::createDefaultListBoxAppearance( PDFWidget& rBox, const PDFWriter::ListBoxWidget& rWidget )
5066 : : {
5067 [ # # ]: 0 : const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
5068 [ # # ][ # # ]: 0 : SvMemoryStream* pListBoxStream = new SvMemoryStream( 1024, 1024 );
5069 : :
5070 [ # # ]: 0 : push( sal::static_int_cast<sal_uInt16>(~0U) );
5071 : :
5072 : : // prepare font to use, draw field border
5073 [ # # ]: 0 : Font aFont = drawFieldBorder( rBox, rWidget, rSettings );
5074 [ # # ][ # # ]: 0 : sal_Int32 nBest = m_aContext.FieldsUseSystemFonts ? getSystemFont( aFont ): getBestBuiltinFont( aFont );
[ # # ]
5075 : :
5076 [ # # ]: 0 : beginRedirect( pListBoxStream, rBox.m_aRect );
5077 : 0 : OStringBuffer aAppearance( 64 );
5078 : :
5079 [ # # ]: 0 : setLineColor( Color( COL_TRANSPARENT ) );
5080 [ # # ]: 0 : setFillColor( replaceColor( rWidget.BackgroundColor, rSettings.GetFieldColor() ) );
5081 [ # # ]: 0 : drawRectangle( rBox.m_aRect );
5082 : :
5083 : : // empty appearance, see createDefaultEditAppearance for reference
5084 [ # # ]: 0 : aAppearance.append( "/Tx BMC\nEMC\n" );
5085 [ # # ]: 0 : writeBuffer( aAppearance.getStr(), aAppearance.getLength() );
5086 : :
5087 [ # # ]: 0 : endRedirect();
5088 [ # # ]: 0 : pop();
5089 : :
5090 [ # # ][ # # ]: 0 : rBox.m_aAppearances[ "N" ][ "Standard" ] = pListBoxStream;
5091 : :
5092 : : // prepare DA string
5093 : 0 : OStringBuffer aDA( 256 );
5094 : : // prepare DA string
5095 [ # # ]: 0 : appendNonStrokingColor( replaceColor( rWidget.TextColor, rSettings.GetFieldTextColor() ), aDA );
5096 [ # # ]: 0 : aDA.append( ' ' );
5097 [ # # ]: 0 : if( m_aContext.FieldsUseSystemFonts )
5098 : : {
5099 [ # # ]: 0 : aDA.append( "/F" );
5100 [ # # ]: 0 : aDA.append( nBest );
5101 : :
5102 : 0 : OStringBuffer aDR( 32 );
5103 [ # # ]: 0 : aDR.append( "/Font " );
5104 [ # # ][ # # ]: 0 : aDR.append( getFontDictObject() );
5105 [ # # ]: 0 : aDR.append( " 0 R" );
5106 : 0 : rBox.m_aDRDict = aDR.makeStringAndClear();
5107 : : }
5108 : : else
5109 [ # # ][ # # ]: 0 : aDA.append( m_aBuiltinFonts[nBest].getNameObject() );
5110 [ # # ]: 0 : aDA.append( ' ' );
5111 [ # # ][ # # ]: 0 : m_aPages[ m_nCurrentPage ].appendMappedLength( sal_Int32( aFont.GetHeight() ), aDA );
5112 [ # # ]: 0 : aDA.append( " Tf" );
5113 [ # # ]: 0 : rBox.m_aDAString = aDA.makeStringAndClear();
5114 : 0 : }
5115 : :
5116 : 0 : void PDFWriterImpl::createDefaultCheckBoxAppearance( PDFWidget& rBox, const PDFWriter::CheckBoxWidget& rWidget )
5117 : : {
5118 [ # # ]: 0 : const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
5119 : :
5120 : : // save graphics state
5121 [ # # ]: 0 : push( sal::static_int_cast<sal_uInt16>(~0U) );
5122 : :
5123 [ # # ][ # # ]: 0 : if( rWidget.Background || rWidget.Border )
5124 : : {
5125 [ # # ][ # # ]: 0 : setLineColor( rWidget.Border ? replaceColor( rWidget.BorderColor, rSettings.GetCheckedColor() ) : Color( COL_TRANSPARENT ) );
5126 [ # # ][ # # ]: 0 : setFillColor( rWidget.Background ? replaceColor( rWidget.BackgroundColor, rSettings.GetFieldColor() ) : Color( COL_TRANSPARENT ) );
5127 [ # # ]: 0 : drawRectangle( rBox.m_aRect );
5128 : : }
5129 : :
5130 [ # # ]: 0 : Font aFont = replaceFont( rWidget.TextFont, rSettings.GetRadioCheckFont() );
5131 [ # # ]: 0 : setFont( aFont );
5132 [ # # ]: 0 : Size aFontSize = aFont.GetSize();
5133 [ # # ][ # # ]: 0 : if( aFontSize.Height() > rBox.m_aRect.GetHeight() )
5134 [ # # ]: 0 : aFontSize.Height() = rBox.m_aRect.GetHeight();
5135 : 0 : sal_Int32 nDelta = aFontSize.Height()/10;
5136 [ # # ]: 0 : if( nDelta < 1 )
5137 : 0 : nDelta = 1;
5138 : :
5139 [ # # ][ # # ]: 0 : Rectangle aCheckRect, aTextRect;
5140 [ # # ]: 0 : if( rWidget.ButtonIsLeft )
5141 : : {
5142 : 0 : aCheckRect.Left() = rBox.m_aRect.Left() + nDelta;
5143 [ # # ]: 0 : aCheckRect.Top() = rBox.m_aRect.Top() + (rBox.m_aRect.GetHeight()-aFontSize.Height())/2;
5144 : 0 : aCheckRect.Right() = aCheckRect.Left() + aFontSize.Height();
5145 : 0 : aCheckRect.Bottom() = aCheckRect.Top() + aFontSize.Height();
5146 : :
5147 : : // #i74206# handle small controls without text area
5148 [ # # ][ # # ]: 0 : while( aCheckRect.GetWidth() > rBox.m_aRect.GetWidth() && aCheckRect.GetWidth() > nDelta )
[ # # ][ # # ]
[ # # ][ # # ]
5149 : : {
5150 : 0 : aCheckRect.Right() -= nDelta;
5151 : 0 : aCheckRect.Top() += nDelta/2;
5152 : 0 : aCheckRect.Bottom() -= nDelta - (nDelta/2);
5153 : : }
5154 : :
5155 [ # # ]: 0 : aTextRect.Left() = rBox.m_aRect.Left() + aCheckRect.GetWidth()+5*nDelta;
5156 : 0 : aTextRect.Top() = rBox.m_aRect.Top();
5157 [ # # ][ # # ]: 0 : aTextRect.Right() = aTextRect.Left() + rBox.m_aRect.GetWidth() - aCheckRect.GetWidth()-6*nDelta;
5158 : 0 : aTextRect.Bottom() = rBox.m_aRect.Bottom();
5159 : : }
5160 : : else
5161 : : {
5162 : 0 : aCheckRect.Left() = rBox.m_aRect.Right() - nDelta - aFontSize.Height();
5163 [ # # ]: 0 : aCheckRect.Top() = rBox.m_aRect.Top() + (rBox.m_aRect.GetHeight()-aFontSize.Height())/2;
5164 : 0 : aCheckRect.Right() = aCheckRect.Left() + aFontSize.Height();
5165 : 0 : aCheckRect.Bottom() = aCheckRect.Top() + aFontSize.Height();
5166 : :
5167 : : // #i74206# handle small controls without text area
5168 [ # # ][ # # ]: 0 : while( aCheckRect.GetWidth() > rBox.m_aRect.GetWidth() && aCheckRect.GetWidth() > nDelta )
[ # # ][ # # ]
[ # # ][ # # ]
5169 : : {
5170 : 0 : aCheckRect.Left() += nDelta;
5171 : 0 : aCheckRect.Top() += nDelta/2;
5172 : 0 : aCheckRect.Bottom() -= nDelta - (nDelta/2);
5173 : : }
5174 : :
5175 : 0 : aTextRect.Left() = rBox.m_aRect.Left();
5176 : 0 : aTextRect.Top() = rBox.m_aRect.Top();
5177 [ # # ][ # # ]: 0 : aTextRect.Right() = aTextRect.Left() + rBox.m_aRect.GetWidth() - aCheckRect.GetWidth()-6*nDelta;
5178 : 0 : aTextRect.Bottom() = rBox.m_aRect.Bottom();
5179 : : }
5180 [ # # ]: 0 : setLineColor( Color( COL_BLACK ) );
5181 [ # # ]: 0 : setFillColor( Color( COL_TRANSPARENT ) );
5182 : 0 : OStringBuffer aLW( 32 );
5183 [ # # ]: 0 : aLW.append( "q " );
5184 [ # # ]: 0 : m_aPages[m_nCurrentPage].appendMappedLength( nDelta, aLW );
5185 [ # # ]: 0 : aLW.append( " w " );
5186 [ # # ]: 0 : writeBuffer( aLW.getStr(), aLW.getLength() );
5187 [ # # ]: 0 : drawRectangle( aCheckRect );
5188 [ # # ]: 0 : writeBuffer( " Q\n", 3 );
5189 [ # # ]: 0 : setTextColor( replaceColor( rWidget.TextColor, rSettings.GetRadioCheckTextColor() ) );
5190 [ # # ][ # # ]: 0 : drawText( aTextRect, rBox.m_aText, rBox.m_nTextStyle );
[ # # ]
5191 : :
5192 [ # # ]: 0 : pop();
5193 : :
5194 : 0 : OStringBuffer aDA( 256 );
5195 [ # # ]: 0 : appendNonStrokingColor( replaceColor( rWidget.TextColor, rSettings.GetRadioCheckTextColor() ), aDA );
5196 [ # # ][ # # ]: 0 : sal_Int32 nBest = getBestBuiltinFont( Font( String( RTL_CONSTASCII_USTRINGPARAM( "ZapfDingbats" ) ), aFont.GetSize() ) );
[ # # ][ # # ]
[ # # ][ # # ]
5197 [ # # ]: 0 : aDA.append( ' ' );
5198 [ # # ][ # # ]: 0 : aDA.append( m_aBuiltinFonts[nBest].getNameObject() );
5199 [ # # ]: 0 : aDA.append( " 0 Tf" );
5200 : 0 : rBox.m_aDAString = aDA.makeStringAndClear();
5201 : 0 : rBox.m_aMKDict = "/CA";
5202 : 0 : rBox.m_aMKDictCAString = "8";
5203 : 0 : rBox.m_aRect = aCheckRect;
5204 : :
5205 : : // create appearance streams
5206 : 0 : sal_Char cMark = '8';
5207 : 0 : sal_Int32 nCharXOffset = 1000-m_aBuiltinFonts[13].m_aWidths[sal_Int32(cMark)];
5208 [ # # ]: 0 : nCharXOffset *= aCheckRect.GetHeight();
5209 : 0 : nCharXOffset /= 2000;
5210 : : sal_Int32 nCharYOffset = 1000-
5211 : 0 : (m_aBuiltinFonts[13].m_nAscent+m_aBuiltinFonts[13].m_nDescent); // descent is negative
5212 [ # # ]: 0 : nCharYOffset *= aCheckRect.GetHeight();
5213 : 0 : nCharYOffset /= 2000;
5214 : :
5215 [ # # ][ # # ]: 0 : SvMemoryStream* pCheckStream = new SvMemoryStream( 256, 256 );
5216 [ # # ]: 0 : beginRedirect( pCheckStream, aCheckRect );
5217 [ # # ]: 0 : aDA.append( "/Tx BMC\nq BT\n" );
5218 [ # # ]: 0 : appendNonStrokingColor( replaceColor( rWidget.TextColor, rSettings.GetRadioCheckTextColor() ), aDA );
5219 [ # # ]: 0 : aDA.append( ' ' );
5220 [ # # ][ # # ]: 0 : aDA.append( m_aBuiltinFonts[nBest].getNameObject() );
5221 [ # # ]: 0 : aDA.append( ' ' );
5222 [ # # ][ # # ]: 0 : m_aPages[ m_nCurrentPage ].appendMappedLength( sal_Int32( aCheckRect.GetHeight() ), aDA );
5223 [ # # ]: 0 : aDA.append( " Tf\n" );
5224 [ # # ]: 0 : m_aPages[ m_nCurrentPage ].appendMappedLength( nCharXOffset, aDA );
5225 [ # # ]: 0 : aDA.append( " " );
5226 [ # # ]: 0 : m_aPages[ m_nCurrentPage ].appendMappedLength( nCharYOffset, aDA );
5227 [ # # ]: 0 : aDA.append( " Td (" );
5228 [ # # ]: 0 : aDA.append( cMark );
5229 [ # # ]: 0 : aDA.append( ") Tj\nET\nQ\nEMC\n" );
5230 [ # # ]: 0 : writeBuffer( aDA.getStr(), aDA.getLength() );
5231 [ # # ]: 0 : endRedirect();
5232 [ # # ][ # # ]: 0 : rBox.m_aAppearances[ "N" ][ "Yes" ] = pCheckStream;
5233 : :
5234 [ # # ][ # # ]: 0 : SvMemoryStream* pUncheckStream = new SvMemoryStream( 256, 256 );
5235 [ # # ]: 0 : beginRedirect( pUncheckStream, aCheckRect );
5236 [ # # ]: 0 : writeBuffer( "/Tx BMC\nEMC\n", 12 );
5237 [ # # ]: 0 : endRedirect();
5238 [ # # ][ # # ]: 0 : rBox.m_aAppearances[ "N" ][ "Off" ] = pUncheckStream;
[ # # ]
5239 : 0 : }
5240 : :
5241 : 0 : void PDFWriterImpl::createDefaultRadioButtonAppearance( PDFWidget& rBox, const PDFWriter::RadioButtonWidget& rWidget )
5242 : : {
5243 [ # # ]: 0 : const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
5244 : :
5245 : : // save graphics state
5246 [ # # ]: 0 : push( sal::static_int_cast<sal_uInt16>(~0U) );
5247 : :
5248 [ # # ][ # # ]: 0 : if( rWidget.Background || rWidget.Border )
5249 : : {
5250 [ # # ][ # # ]: 0 : setLineColor( rWidget.Border ? replaceColor( rWidget.BorderColor, rSettings.GetCheckedColor() ) : Color( COL_TRANSPARENT ) );
5251 [ # # ][ # # ]: 0 : setFillColor( rWidget.Background ? replaceColor( rWidget.BackgroundColor, rSettings.GetFieldColor() ) : Color( COL_TRANSPARENT ) );
5252 [ # # ]: 0 : drawRectangle( rBox.m_aRect );
5253 : : }
5254 : :
5255 [ # # ]: 0 : Font aFont = replaceFont( rWidget.TextFont, rSettings.GetRadioCheckFont() );
5256 [ # # ]: 0 : setFont( aFont );
5257 [ # # ]: 0 : Size aFontSize = aFont.GetSize();
5258 [ # # ][ # # ]: 0 : if( aFontSize.Height() > rBox.m_aRect.GetHeight() )
5259 [ # # ]: 0 : aFontSize.Height() = rBox.m_aRect.GetHeight();
5260 : 0 : sal_Int32 nDelta = aFontSize.Height()/10;
5261 [ # # ]: 0 : if( nDelta < 1 )
5262 : 0 : nDelta = 1;
5263 : :
5264 [ # # ][ # # ]: 0 : Rectangle aCheckRect, aTextRect;
5265 [ # # ]: 0 : if( rWidget.ButtonIsLeft )
5266 : : {
5267 : 0 : aCheckRect.Left() = rBox.m_aRect.Left() + nDelta;
5268 [ # # ]: 0 : aCheckRect.Top() = rBox.m_aRect.Top() + (rBox.m_aRect.GetHeight()-aFontSize.Height())/2;
5269 : 0 : aCheckRect.Right() = aCheckRect.Left() + aFontSize.Height();
5270 : 0 : aCheckRect.Bottom() = aCheckRect.Top() + aFontSize.Height();
5271 : :
5272 : : // #i74206# handle small controls without text area
5273 [ # # ][ # # ]: 0 : while( aCheckRect.GetWidth() > rBox.m_aRect.GetWidth() && aCheckRect.GetWidth() > nDelta )
[ # # ][ # # ]
[ # # ][ # # ]
5274 : : {
5275 : 0 : aCheckRect.Right() -= nDelta;
5276 : 0 : aCheckRect.Top() += nDelta/2;
5277 : 0 : aCheckRect.Bottom() -= nDelta - (nDelta/2);
5278 : : }
5279 : :
5280 [ # # ]: 0 : aTextRect.Left() = rBox.m_aRect.Left() + aCheckRect.GetWidth()+5*nDelta;
5281 : 0 : aTextRect.Top() = rBox.m_aRect.Top();
5282 [ # # ][ # # ]: 0 : aTextRect.Right() = aTextRect.Left() + rBox.m_aRect.GetWidth() - aCheckRect.GetWidth()-6*nDelta;
5283 : 0 : aTextRect.Bottom() = rBox.m_aRect.Bottom();
5284 : : }
5285 : : else
5286 : : {
5287 : 0 : aCheckRect.Left() = rBox.m_aRect.Right() - nDelta - aFontSize.Height();
5288 [ # # ]: 0 : aCheckRect.Top() = rBox.m_aRect.Top() + (rBox.m_aRect.GetHeight()-aFontSize.Height())/2;
5289 : 0 : aCheckRect.Right() = aCheckRect.Left() + aFontSize.Height();
5290 : 0 : aCheckRect.Bottom() = aCheckRect.Top() + aFontSize.Height();
5291 : :
5292 : : // #i74206# handle small controls without text area
5293 [ # # ][ # # ]: 0 : while( aCheckRect.GetWidth() > rBox.m_aRect.GetWidth() && aCheckRect.GetWidth() > nDelta )
[ # # ][ # # ]
[ # # ][ # # ]
5294 : : {
5295 : 0 : aCheckRect.Left() += nDelta;
5296 : 0 : aCheckRect.Top() += nDelta/2;
5297 : 0 : aCheckRect.Bottom() -= nDelta - (nDelta/2);
5298 : : }
5299 : :
5300 : 0 : aTextRect.Left() = rBox.m_aRect.Left();
5301 : 0 : aTextRect.Top() = rBox.m_aRect.Top();
5302 [ # # ][ # # ]: 0 : aTextRect.Right() = aTextRect.Left() + rBox.m_aRect.GetWidth() - aCheckRect.GetWidth()-6*nDelta;
5303 : 0 : aTextRect.Bottom() = rBox.m_aRect.Bottom();
5304 : : }
5305 [ # # ]: 0 : setLineColor( Color( COL_BLACK ) );
5306 [ # # ]: 0 : setFillColor( Color( COL_TRANSPARENT ) );
5307 : 0 : OStringBuffer aLW( 32 );
5308 [ # # ]: 0 : aLW.append( "q " );
5309 [ # # ]: 0 : m_aPages[ m_nCurrentPage ].appendMappedLength( nDelta, aLW );
5310 [ # # ]: 0 : aLW.append( " w " );
5311 [ # # ]: 0 : writeBuffer( aLW.getStr(), aLW.getLength() );
5312 [ # # ]: 0 : drawEllipse( aCheckRect );
5313 [ # # ]: 0 : writeBuffer( " Q\n", 3 );
5314 [ # # ]: 0 : setTextColor( replaceColor( rWidget.TextColor, rSettings.GetRadioCheckTextColor() ) );
5315 [ # # ][ # # ]: 0 : drawText( aTextRect, rBox.m_aText, rBox.m_nTextStyle );
[ # # ]
5316 : :
5317 [ # # ]: 0 : pop();
5318 : :
5319 : 0 : OStringBuffer aDA( 256 );
5320 [ # # ]: 0 : appendNonStrokingColor( replaceColor( rWidget.TextColor, rSettings.GetRadioCheckTextColor() ), aDA );
5321 [ # # ][ # # ]: 0 : sal_Int32 nBest = getBestBuiltinFont( Font( String( RTL_CONSTASCII_USTRINGPARAM( "ZapfDingbats" ) ), aFont.GetSize() ) );
[ # # ][ # # ]
[ # # ][ # # ]
5322 [ # # ]: 0 : aDA.append( ' ' );
5323 [ # # ][ # # ]: 0 : aDA.append( m_aBuiltinFonts[nBest].getNameObject() );
5324 [ # # ]: 0 : aDA.append( " 0 Tf" );
5325 : 0 : rBox.m_aDAString = aDA.makeStringAndClear();
5326 : : //to encrypt this (el)
5327 : 0 : rBox.m_aMKDict = "/CA";
5328 : : //after this assignement, to m_aMKDic cannot be added anything
5329 : 0 : rBox.m_aMKDictCAString = "l";
5330 : :
5331 : 0 : rBox.m_aRect = aCheckRect;
5332 : :
5333 : : // create appearance streams
5334 [ # # ]: 0 : push( sal::static_int_cast<sal_uInt16>(~0U) );
5335 [ # # ][ # # ]: 0 : SvMemoryStream* pCheckStream = new SvMemoryStream( 256, 256 );
5336 : :
5337 [ # # ]: 0 : beginRedirect( pCheckStream, aCheckRect );
5338 [ # # ]: 0 : aDA.append( "/Tx BMC\nq BT\n" );
5339 [ # # ]: 0 : appendNonStrokingColor( replaceColor( rWidget.TextColor, rSettings.GetRadioCheckTextColor() ), aDA );
5340 [ # # ]: 0 : aDA.append( ' ' );
5341 [ # # ][ # # ]: 0 : aDA.append( m_aBuiltinFonts[nBest].getNameObject() );
5342 [ # # ]: 0 : aDA.append( ' ' );
5343 [ # # ][ # # ]: 0 : m_aPages[m_nCurrentPage].appendMappedLength( sal_Int32( aCheckRect.GetHeight() ), aDA );
5344 [ # # ]: 0 : aDA.append( " Tf\n0 0 Td\nET\nQ\n" );
5345 [ # # ]: 0 : writeBuffer( aDA.getStr(), aDA.getLength() );
5346 [ # # ]: 0 : setFillColor( replaceColor( rWidget.TextColor, rSettings.GetRadioCheckTextColor() ) );
5347 [ # # ]: 0 : setLineColor( Color( COL_TRANSPARENT ) );
5348 : 0 : aCheckRect.Left() += 3*nDelta;
5349 : 0 : aCheckRect.Top() += 3*nDelta;
5350 : 0 : aCheckRect.Bottom() -= 3*nDelta;
5351 : 0 : aCheckRect.Right() -= 3*nDelta;
5352 [ # # ]: 0 : drawEllipse( aCheckRect );
5353 [ # # ]: 0 : writeBuffer( "\nEMC\n", 5 );
5354 [ # # ]: 0 : endRedirect();
5355 : :
5356 [ # # ]: 0 : pop();
5357 [ # # ][ # # ]: 0 : rBox.m_aAppearances[ "N" ][ "Yes" ] = pCheckStream;
5358 : :
5359 [ # # ][ # # ]: 0 : SvMemoryStream* pUncheckStream = new SvMemoryStream( 256, 256 );
5360 [ # # ]: 0 : beginRedirect( pUncheckStream, aCheckRect );
5361 [ # # ]: 0 : writeBuffer( "/Tx BMC\nEMC\n", 12 );
5362 [ # # ]: 0 : endRedirect();
5363 [ # # ][ # # ]: 0 : rBox.m_aAppearances[ "N" ][ "Off" ] = pUncheckStream;
[ # # ]
5364 : 0 : }
5365 : :
5366 : 0 : bool PDFWriterImpl::emitAppearances( PDFWidget& rWidget, OStringBuffer& rAnnotDict )
5367 : : {
5368 : :
5369 : : // TODO: check and insert default streams
5370 : 0 : rtl::OString aStandardAppearance;
5371 [ # # ]: 0 : switch( rWidget.m_eType )
5372 : : {
5373 : : case PDFWriter::CheckBox:
5374 [ # # ]: 0 : aStandardAppearance = OUStringToOString( rWidget.m_aValue, RTL_TEXTENCODING_ASCII_US );
5375 : 0 : break;
5376 : : default:
5377 : 0 : break;
5378 : : }
5379 : :
5380 [ # # ]: 0 : if( rWidget.m_aAppearances.size() )
5381 : : {
5382 [ # # ]: 0 : rAnnotDict.append( "/AP<<\n" );
5383 [ # # ][ # # ]: 0 : for( PDFAppearanceMap::iterator dict_it = rWidget.m_aAppearances.begin(); dict_it != rWidget.m_aAppearances.end(); ++dict_it )
[ # # ]
5384 : : {
5385 [ # # ]: 0 : rAnnotDict.append( "/" );
5386 [ # # ][ # # ]: 0 : rAnnotDict.append( dict_it->first );
5387 [ # # ]: 0 : bool bUseSubDict = (dict_it->second.size() > 1);
5388 [ # # ][ # # ]: 0 : rAnnotDict.append( bUseSubDict ? "<<" : " " );
5389 : :
5390 [ # # ][ # # ]: 0 : for( PDFAppearanceStreams::const_iterator stream_it = dict_it->second.begin();
[ # # ]
5391 [ # # ][ # # ]: 0 : stream_it != dict_it->second.end(); ++stream_it )
5392 : : {
5393 [ # # ]: 0 : SvMemoryStream* pApppearanceStream = stream_it->second;
5394 [ # # ][ # # ]: 0 : dict_it->second[ stream_it->first ] = NULL;
[ # # ]
5395 : :
5396 [ # # ]: 0 : bool bDeflate = compressStream( pApppearanceStream );
5397 : :
5398 [ # # ]: 0 : pApppearanceStream->Seek( STREAM_SEEK_TO_END );
5399 : 0 : sal_Int64 nStreamLen = pApppearanceStream->Tell();
5400 [ # # ]: 0 : pApppearanceStream->Seek( STREAM_SEEK_TO_BEGIN );
5401 [ # # ]: 0 : sal_Int32 nObject = createObject();
5402 [ # # ][ # # ]: 0 : CHECK_RETURN( updateObject( nObject ) );
5403 : : #if OSL_DEBUG_LEVEL > 1
5404 : : emitComment( "PDFWriterImpl::emitAppearances" );
5405 : : #endif
5406 : 0 : OStringBuffer aLine;
5407 [ # # ]: 0 : aLine.append( nObject );
5408 : :
5409 : : aLine.append( " 0 obj\n"
5410 : : "<</Type/XObject\n"
5411 : : "/Subtype/Form\n"
5412 [ # # ]: 0 : "/BBox[0 0 " );
5413 [ # # ][ # # ]: 0 : appendFixedInt( rWidget.m_aRect.GetWidth()-1, aLine );
5414 [ # # ]: 0 : aLine.append( " " );
5415 [ # # ][ # # ]: 0 : appendFixedInt( rWidget.m_aRect.GetHeight()-1, aLine );
5416 : : aLine.append( "]\n"
5417 [ # # ]: 0 : "/Resources " );
5418 [ # # ][ # # ]: 0 : aLine.append( getResourceDictObj() );
5419 : : aLine.append( " 0 R\n"
5420 [ # # ]: 0 : "/Length " );
5421 [ # # ]: 0 : aLine.append( nStreamLen );
5422 [ # # ]: 0 : aLine.append( "\n" );
5423 [ # # ]: 0 : if( bDeflate )
5424 [ # # ]: 0 : aLine.append( "/Filter/FlateDecode\n" );
5425 [ # # ]: 0 : aLine.append( ">>\nstream\n" );
5426 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
5427 [ # # ]: 0 : checkAndEnableStreamEncryption( nObject );
5428 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( pApppearanceStream->GetData(), nStreamLen ) );
[ # # ]
5429 : 0 : disableStreamEncryption();
5430 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( "\nendstream\nendobj\n\n", 19 ) );
5431 : :
5432 [ # # ]: 0 : if( bUseSubDict )
5433 : : {
5434 [ # # ]: 0 : rAnnotDict.append( " /" );
5435 [ # # ][ # # ]: 0 : rAnnotDict.append( stream_it->first );
5436 [ # # ]: 0 : rAnnotDict.append( " " );
5437 : : }
5438 [ # # ]: 0 : rAnnotDict.append( nObject );
5439 [ # # ]: 0 : rAnnotDict.append( " 0 R" );
5440 : :
5441 [ # # ][ # # ]: 0 : delete pApppearanceStream;
5442 [ # # ]: 0 : }
5443 : :
5444 [ # # ][ # # ]: 0 : rAnnotDict.append( bUseSubDict ? ">>\n" : "\n" );
5445 : : }
5446 [ # # ]: 0 : rAnnotDict.append( ">>\n" );
5447 [ # # ]: 0 : if( !aStandardAppearance.isEmpty() )
5448 : : {
5449 [ # # ]: 0 : rAnnotDict.append( "/AS /" );
5450 [ # # ]: 0 : rAnnotDict.append( aStandardAppearance );
5451 [ # # ]: 0 : rAnnotDict.append( "\n" );
5452 : : }
5453 : : }
5454 : :
5455 : 0 : return true;
5456 : : }
5457 : :
5458 : 0 : bool PDFWriterImpl::emitWidgetAnnotations()
5459 : : {
5460 : 0 : ensureUniqueRadioOnValues();
5461 : :
5462 : 0 : int nAnnots = m_aWidgets.size();
5463 [ # # ]: 0 : for( int a = 0; a < nAnnots; a++ )
5464 : : {
5465 : 0 : PDFWidget& rWidget = m_aWidgets[a];
5466 : :
5467 : 0 : OStringBuffer aLine( 1024 );
5468 : 0 : OStringBuffer aValue( 256 );
5469 [ # # ]: 0 : aLine.append( rWidget.m_nObject );
5470 : : aLine.append( " 0 obj\n"
5471 [ # # ]: 0 : "<<" );
5472 [ # # ]: 0 : if( rWidget.m_eType != PDFWriter::Hierarchy )
5473 : : {
5474 : : // emit widget annotation only for terminal fields
5475 [ # # ]: 0 : if( rWidget.m_aKids.empty() )
5476 : : {
5477 : : int iRectMargin;
5478 : :
5479 [ # # ]: 0 : aLine.append( "/Type/Annot/Subtype/Widget/F " );
5480 : :
5481 [ # # ]: 0 : if (rWidget.m_eType == PDFWriter::Signature)
5482 : : {
5483 [ # # ]: 0 : aLine.append( "132\n" ); // Print & Locked
5484 : 0 : iRectMargin = 0;
5485 : : }
5486 : : else
5487 : : {
5488 [ # # ]: 0 : aLine.append( "4\n" );
5489 : 0 : iRectMargin = 1;
5490 : : }
5491 : :
5492 [ # # ]: 0 : aLine.append("/Rect[" );
5493 [ # # ]: 0 : appendFixedInt( rWidget.m_aRect.Left()-iRectMargin, aLine );
5494 [ # # ]: 0 : aLine.append( ' ' );
5495 [ # # ]: 0 : appendFixedInt( rWidget.m_aRect.Top()+iRectMargin, aLine );
5496 [ # # ]: 0 : aLine.append( ' ' );
5497 [ # # ]: 0 : appendFixedInt( rWidget.m_aRect.Right()+iRectMargin, aLine );
5498 [ # # ]: 0 : aLine.append( ' ' );
5499 [ # # ]: 0 : appendFixedInt( rWidget.m_aRect.Bottom()-iRectMargin, aLine );
5500 [ # # ]: 0 : aLine.append( "]\n" );
5501 : : }
5502 [ # # ]: 0 : aLine.append( "/FT/" );
5503 [ # # # # : 0 : switch( rWidget.m_eType )
# # # # ]
5504 : : {
5505 : : case PDFWriter::RadioButton:
5506 : : case PDFWriter::CheckBox:
5507 : : // for radio buttons only the RadioButton field, not the
5508 : : // CheckBox children should have a value, else acrobat reader
5509 : : // does not always check the right button
5510 : : // of course real check boxes (not belonging to a readio group)
5511 : : // need their values, too
5512 [ # # ][ # # ]: 0 : if( rWidget.m_eType == PDFWriter::RadioButton || rWidget.m_nRadioGroup < 0 )
5513 : : {
5514 [ # # ]: 0 : aValue.append( "/" );
5515 : : // check for radio group with all buttons unpressed
5516 [ # # ]: 0 : if( rWidget.m_aValue.isEmpty() )
5517 [ # # ]: 0 : aValue.append( "Off" );
5518 : : else
5519 [ # # ]: 0 : appendName( rWidget.m_aValue, aValue );
5520 : : }
5521 : : case PDFWriter::PushButton:
5522 [ # # ]: 0 : aLine.append( "Btn" );
5523 : 0 : break;
5524 : : case PDFWriter::ListBox:
5525 [ # # ]: 0 : if( rWidget.m_nFlags & 0x200000 ) // multiselect
5526 : : {
5527 [ # # ]: 0 : aValue.append( "[" );
5528 [ # # ]: 0 : for( unsigned int i = 0; i < rWidget.m_aSelectedEntries.size(); i++ )
5529 : : {
5530 [ # # ]: 0 : sal_Int32 nEntry = rWidget.m_aSelectedEntries[i];
5531 [ # # ][ # # ]: 0 : if( nEntry >= 0 && nEntry < sal_Int32(rWidget.m_aListEntries.size()) )
[ # # ]
5532 [ # # ]: 0 : appendUnicodeTextStringEncrypt( rWidget.m_aListEntries[ nEntry ], rWidget.m_nObject, aValue );
5533 : : }
5534 [ # # ]: 0 : aValue.append( "]" );
5535 : : }
5536 [ # # ]: 0 : else if( rWidget.m_aSelectedEntries.size() > 0 &&
[ # # # # ]
[ # # ]
5537 [ # # ]: 0 : rWidget.m_aSelectedEntries[0] >= 0 &&
5538 [ # # ]: 0 : rWidget.m_aSelectedEntries[0] < sal_Int32(rWidget.m_aListEntries.size()) )
5539 : : {
5540 [ # # ][ # # ]: 0 : appendUnicodeTextStringEncrypt( rWidget.m_aListEntries[ rWidget.m_aSelectedEntries[0] ], rWidget.m_nObject, aValue );
5541 : : }
5542 : : else
5543 [ # # ]: 0 : appendUnicodeTextStringEncrypt( rtl::OUString(), rWidget.m_nObject, aValue );
5544 [ # # ]: 0 : aLine.append( "Ch" );
5545 : 0 : break;
5546 : : case PDFWriter::ComboBox:
5547 [ # # ]: 0 : appendUnicodeTextStringEncrypt( rWidget.m_aValue, rWidget.m_nObject, aValue );
5548 [ # # ]: 0 : aLine.append( "Ch" );
5549 : 0 : break;
5550 : : case PDFWriter::Edit:
5551 [ # # ]: 0 : aLine.append( "Tx" );
5552 [ # # ]: 0 : appendUnicodeTextStringEncrypt( rWidget.m_aValue, rWidget.m_nObject, aValue );
5553 : 0 : break;
5554 : : case PDFWriter::Signature:
5555 [ # # ]: 0 : aLine.append( "Sig" );
5556 [ # # ][ # # ]: 0 : aValue.append(OUStringToOString(rWidget.m_aValue, RTL_TEXTENCODING_ASCII_US));
5557 : 0 : break;
5558 : : case PDFWriter::Hierarchy: // make the compiler happy
5559 : 0 : break;
5560 : : }
5561 [ # # ]: 0 : aLine.append( "\n" );
5562 [ # # ]: 0 : aLine.append( "/P " );
5563 [ # # ]: 0 : aLine.append( m_aPages[ rWidget.m_nPage ].m_nPageObject );
5564 [ # # ]: 0 : aLine.append( " 0 R\n" );
5565 : : }
5566 [ # # ]: 0 : if( rWidget.m_nParent )
5567 : : {
5568 [ # # ]: 0 : aLine.append( "/Parent " );
5569 [ # # ]: 0 : aLine.append( rWidget.m_nParent );
5570 [ # # ]: 0 : aLine.append( " 0 R\n" );
5571 : : }
5572 [ # # ]: 0 : if( rWidget.m_aKids.size() )
5573 : : {
5574 [ # # ]: 0 : aLine.append( "/Kids[" );
5575 [ # # ]: 0 : for( unsigned int i = 0; i < rWidget.m_aKids.size(); i++ )
5576 : : {
5577 [ # # ][ # # ]: 0 : aLine.append( rWidget.m_aKids[i] );
5578 [ # # ]: 0 : aLine.append( " 0 R" );
5579 [ # # ][ # # ]: 0 : aLine.append( ( (i&15) == 15 ) ? "\n" : " " );
5580 : : }
5581 [ # # ]: 0 : aLine.append( "]\n" );
5582 : : }
5583 [ # # ]: 0 : if( !rWidget.m_aName.isEmpty() )
5584 : : {
5585 [ # # ]: 0 : aLine.append( "/T" );
5586 [ # # ]: 0 : appendLiteralStringEncrypt( rWidget.m_aName, rWidget.m_nObject, aLine );
5587 [ # # ]: 0 : aLine.append( "\n" );
5588 : : }
5589 [ # # ][ # # ]: 0 : if( m_aContext.Version > PDFWriter::PDF_1_2 && !rWidget.m_aDescription.isEmpty() )
[ # # ]
5590 : : {
5591 : : // the alternate field name should be unicode able since it is
5592 : : // supposed to be used in UI
5593 [ # # ]: 0 : aLine.append( "/TU" );
5594 [ # # ]: 0 : appendUnicodeTextStringEncrypt( rWidget.m_aDescription, rWidget.m_nObject, aLine );
5595 [ # # ]: 0 : aLine.append( "\n" );
5596 : : }
5597 : :
5598 [ # # ]: 0 : if( rWidget.m_nFlags )
5599 : : {
5600 [ # # ]: 0 : aLine.append( "/Ff " );
5601 [ # # ]: 0 : aLine.append( rWidget.m_nFlags );
5602 [ # # ]: 0 : aLine.append( "\n" );
5603 : : }
5604 [ # # ]: 0 : if( aValue.getLength() )
5605 : : {
5606 : 0 : OString aVal = aValue.makeStringAndClear();
5607 [ # # ]: 0 : aLine.append( "/V " );
5608 [ # # ]: 0 : aLine.append( aVal );
5609 : : aLine.append( "\n"
5610 [ # # ]: 0 : "/DV " );
5611 [ # # ]: 0 : aLine.append( aVal );
5612 [ # # ]: 0 : aLine.append( "\n" );
5613 : : }
5614 [ # # ][ # # ]: 0 : if( rWidget.m_eType == PDFWriter::ListBox || rWidget.m_eType == PDFWriter::ComboBox )
5615 : : {
5616 : 0 : sal_Int32 nTI = -1;
5617 [ # # ]: 0 : aLine.append( "/Opt[\n" );
5618 : 0 : sal_Int32 i = 0;
5619 [ # # ][ # # ]: 0 : for( std::vector< OUString >::const_iterator it = rWidget.m_aListEntries.begin(); it != rWidget.m_aListEntries.end(); ++it, ++i )
[ # # ]
5620 : : {
5621 [ # # ]: 0 : appendUnicodeTextStringEncrypt( *it, rWidget.m_nObject, aLine );
5622 [ # # ]: 0 : aLine.append( "\n" );
5623 [ # # ]: 0 : if( *it == rWidget.m_aValue )
5624 : 0 : nTI = i;
5625 : : }
5626 [ # # ]: 0 : aLine.append( "]\n" );
5627 [ # # ]: 0 : if( nTI > 0 )
5628 : : {
5629 [ # # ]: 0 : aLine.append( "/TI " );
5630 [ # # ]: 0 : aLine.append( nTI );
5631 [ # # ]: 0 : aLine.append( "\n" );
5632 [ # # ]: 0 : if( rWidget.m_nFlags & 0x200000 ) // Multiselect
5633 : : {
5634 [ # # ]: 0 : aLine.append( "/I [" );
5635 [ # # ]: 0 : aLine.append( nTI );
5636 [ # # ]: 0 : aLine.append( "]\n" );
5637 : : }
5638 : : }
5639 : : }
5640 [ # # ][ # # ]: 0 : if( rWidget.m_eType == PDFWriter::Edit && rWidget.m_nMaxLen > 0 )
5641 : : {
5642 [ # # ]: 0 : aLine.append( "/MaxLen " );
5643 [ # # ]: 0 : aLine.append( rWidget.m_nMaxLen );
5644 [ # # ]: 0 : aLine.append( "\n" );
5645 : : }
5646 [ # # ]: 0 : if( rWidget.m_eType == PDFWriter::PushButton )
5647 : : {
5648 [ # # ]: 0 : if(!m_bIsPDF_A1)
5649 : : {
5650 : 0 : OStringBuffer aDest;
5651 [ # # ][ # # ]: 0 : if( rWidget.m_nDest != -1 && appendDest( m_aDestinationIdTranslation[ rWidget.m_nDest ], aDest ) )
[ # # ][ # # ]
[ # # ]
5652 : : {
5653 [ # # ]: 0 : aLine.append( "/AA<</D<</Type/Action/S/GoTo/D " );
5654 [ # # ]: 0 : aLine.append( aDest.makeStringAndClear() );
5655 [ # # ]: 0 : aLine.append( ">>>>\n" );
5656 : : }
5657 [ # # ]: 0 : else if( rWidget.m_aListEntries.empty() )
5658 : : {
5659 : : // create a reset form action
5660 [ # # ]: 0 : aLine.append( "/AA<</D<</Type/Action/S/ResetForm>>>>\n" );
5661 : : }
5662 [ # # ]: 0 : else if( rWidget.m_bSubmit )
5663 : : {
5664 : : // create a submit form action
5665 [ # # ]: 0 : aLine.append( "/AA<</D<</Type/Action/S/SubmitForm/F" );
5666 [ # # ][ # # ]: 0 : appendLiteralStringEncrypt( rWidget.m_aListEntries.front(), rWidget.m_nObject, aLine, osl_getThreadTextEncoding() );
[ # # ]
5667 [ # # ]: 0 : aLine.append( "/Flags " );
5668 : :
5669 : 0 : sal_Int32 nFlags = 0;
5670 [ # # # # ]: 0 : switch( m_aContext.SubmitFormat )
5671 : : {
5672 : : case PDFWriter::HTML:
5673 : 0 : nFlags |= 4;
5674 : 0 : break;
5675 : : case PDFWriter::XML:
5676 [ # # ]: 0 : if( m_aContext.Version > PDFWriter::PDF_1_3 )
5677 : 0 : nFlags |= 32;
5678 : 0 : break;
5679 : : case PDFWriter::PDF:
5680 [ # # ]: 0 : if( m_aContext.Version > PDFWriter::PDF_1_3 )
5681 : 0 : nFlags |= 256;
5682 : 0 : break;
5683 : : case PDFWriter::FDF:
5684 : : default:
5685 : 0 : break;
5686 : : }
5687 [ # # ]: 0 : if( rWidget.m_bSubmitGet )
5688 : 0 : nFlags |= 8;
5689 [ # # ]: 0 : aLine.append( nFlags );
5690 [ # # ]: 0 : aLine.append( ">>>>\n" );
5691 : : }
5692 : : else
5693 : : {
5694 : : // create a URI action
5695 [ # # ]: 0 : aLine.append( "/AA<</D<</Type/Action/S/URI/URI(" );
5696 [ # # ][ # # ]: 0 : aLine.append( OUStringToOString( rWidget.m_aListEntries.front(), RTL_TEXTENCODING_ASCII_US ) );
[ # # ]
5697 [ # # ]: 0 : aLine.append( ")>>>>\n" );
5698 : 0 : }
5699 : : }
5700 : : else
5701 [ # # ]: 0 : m_aErrors.insert( PDFWriter::Warning_FormAction_Omitted_PDFA );
5702 : : }
5703 [ # # ]: 0 : if( !rWidget.m_aDAString.isEmpty() )
5704 : : {
5705 [ # # ]: 0 : if( !rWidget.m_aDRDict.isEmpty() )
5706 : : {
5707 [ # # ]: 0 : aLine.append( "/DR<<" );
5708 [ # # ]: 0 : aLine.append( rWidget.m_aDRDict );
5709 [ # # ]: 0 : aLine.append( ">>\n" );
5710 : : }
5711 : : else
5712 : : {
5713 [ # # ]: 0 : aLine.append( "/DR<</Font<<" );
5714 [ # # ]: 0 : appendBuiltinFontsToDict( aLine );
5715 [ # # ]: 0 : aLine.append( ">>>>\n" );
5716 : : }
5717 [ # # ]: 0 : aLine.append( "/DA" );
5718 [ # # ]: 0 : appendLiteralStringEncrypt( rWidget.m_aDAString, rWidget.m_nObject, aLine );
5719 [ # # ]: 0 : aLine.append( "\n" );
5720 [ # # ]: 0 : if( rWidget.m_nTextStyle & TEXT_DRAW_CENTER )
5721 [ # # ]: 0 : aLine.append( "/Q 1\n" );
5722 [ # # ]: 0 : else if( rWidget.m_nTextStyle & TEXT_DRAW_RIGHT )
5723 [ # # ]: 0 : aLine.append( "/Q 2\n" );
5724 : : }
5725 : : // appearance charactristics for terminal fields
5726 : : // which are supposed to have an appearance constructed
5727 : : // by the viewer application
5728 [ # # ]: 0 : if( !rWidget.m_aMKDict.isEmpty() )
5729 : : {
5730 [ # # ]: 0 : aLine.append( "/MK<<" );
5731 [ # # ]: 0 : aLine.append( rWidget.m_aMKDict );
5732 : : //add the CA string, encrypting it
5733 [ # # ]: 0 : appendLiteralStringEncrypt(rWidget.m_aMKDictCAString, rWidget.m_nObject, aLine);
5734 [ # # ]: 0 : aLine.append( ">>\n" );
5735 : : }
5736 : :
5737 [ # # ][ # # ]: 0 : CHECK_RETURN( emitAppearances( rWidget, aLine ) );
5738 : :
5739 : : aLine.append( ">>\n"
5740 [ # # ]: 0 : "endobj\n\n" );
5741 [ # # ][ # # ]: 0 : CHECK_RETURN( updateObject( rWidget.m_nObject ) );
5742 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
5743 [ # # ][ # # ]: 0 : }
5744 : 0 : return true;
5745 : : }
5746 : :
5747 : 0 : bool PDFWriterImpl::emitAnnotations()
5748 : : {
5749 [ # # ]: 0 : if( m_aPages.size() < 1 )
5750 : 0 : return false;
5751 : :
5752 [ # # ]: 0 : CHECK_RETURN( emitLinkAnnotations() );
5753 : :
5754 [ # # ]: 0 : CHECK_RETURN( emitNoteAnnotations() );
5755 : :
5756 [ # # ]: 0 : CHECK_RETURN( emitWidgetAnnotations() );
5757 : :
5758 : 0 : return true;
5759 : : }
5760 : :
5761 : : #undef CHECK_RETURN
5762 : : #define CHECK_RETURN( x ) if( !x ) return false
5763 : :
5764 : 0 : bool PDFWriterImpl::emitCatalog()
5765 : : {
5766 : : // build page tree
5767 : : // currently there is only one node that contains all leaves
5768 : :
5769 : : // first create a page tree node id
5770 [ # # ]: 0 : sal_Int32 nTreeNode = createObject();
5771 : :
5772 : : // emit global resource dictionary (page emit needs it)
5773 [ # # ][ # # ]: 0 : CHECK_RETURN( emitResources() );
5774 : :
5775 : : // emit all pages
5776 [ # # ][ # # ]: 0 : for( std::vector<PDFPage>::iterator it = m_aPages.begin(); it != m_aPages.end(); ++it )
5777 [ # # ][ # # ]: 0 : if( ! it->emit( nTreeNode ) )
5778 : 0 : return false;
5779 : :
5780 [ # # ]: 0 : sal_Int32 nNamedDestinationsDictionary = emitNamedDestinations();
5781 : :
5782 [ # # ]: 0 : sal_Int32 nOutlineDict = emitOutline();
5783 : :
5784 : : //emit Output intent i59651
5785 [ # # ]: 0 : sal_Int32 nOutputIntentObject = emitOutputIntent();
5786 : :
5787 : : //emit metadata
5788 [ # # ]: 0 : sal_Int32 nMetadataObject = emitDocumentMetadata();
5789 : :
5790 : 0 : sal_Int32 nStructureDict = 0;
5791 [ # # ]: 0 : if(m_aStructure.size() > 1)
5792 : : {
5793 : : ///check if dummy structure containers are needed
5794 [ # # ]: 0 : addInternalStructureContainer(m_aStructure[0]);
5795 [ # # ]: 0 : nStructureDict = m_aStructure[0].m_nObject = createObject();
5796 [ # # ]: 0 : emitStructure( m_aStructure[ 0 ] );
5797 : : }
5798 : :
5799 : : // adjust tree node file offset
5800 [ # # ][ # # ]: 0 : if( ! updateObject( nTreeNode ) )
5801 : 0 : return false;
5802 : :
5803 : : // emit tree node
5804 : 0 : OStringBuffer aLine( 2048 );
5805 [ # # ]: 0 : aLine.append( nTreeNode );
5806 [ # # ]: 0 : aLine.append( " 0 obj\n" );
5807 [ # # ]: 0 : aLine.append( "<</Type/Pages\n" );
5808 [ # # ]: 0 : aLine.append( "/Resources " );
5809 [ # # ][ # # ]: 0 : aLine.append( getResourceDictObj() );
5810 [ # # ]: 0 : aLine.append( " 0 R\n" );
5811 : :
5812 [ # # # ]: 0 : switch( m_eInheritedOrientation )
5813 : : {
5814 [ # # ]: 0 : case PDFWriter::Landscape: aLine.append( "/Rotate 90\n" );break;
5815 [ # # ]: 0 : case PDFWriter::Seascape: aLine.append( "/Rotate -90\n" );break;
5816 : :
5817 : : case PDFWriter::Inherit: // actually Inherit would be a bug, but insignificant
5818 : : case PDFWriter::Portrait:
5819 : : default:
5820 : 0 : break;
5821 : : }
5822 : 0 : sal_Int32 nMediaBoxWidth = 0;
5823 : 0 : sal_Int32 nMediaBoxHeight = 0;
5824 [ # # ]: 0 : if( m_aPages.empty() ) // sanity check, this should not happen
5825 : : {
5826 : 0 : nMediaBoxWidth = m_nInheritedPageWidth;
5827 : 0 : nMediaBoxHeight = m_nInheritedPageHeight;
5828 : : }
5829 : : else
5830 : : {
5831 [ # # ][ # # ]: 0 : for( std::vector<PDFPage>::const_iterator iter = m_aPages.begin(); iter != m_aPages.end(); ++iter )
[ # # ]
5832 : : {
5833 [ # # ]: 0 : if( iter->m_nPageWidth > nMediaBoxWidth )
5834 : 0 : nMediaBoxWidth = iter->m_nPageWidth;
5835 [ # # ]: 0 : if( iter->m_nPageHeight > nMediaBoxHeight )
5836 : 0 : nMediaBoxHeight = iter->m_nPageHeight;
5837 : : }
5838 : : }
5839 [ # # ]: 0 : aLine.append( "/MediaBox[ 0 0 " );
5840 [ # # ]: 0 : aLine.append( nMediaBoxWidth );
5841 [ # # ]: 0 : aLine.append( ' ' );
5842 [ # # ]: 0 : aLine.append( nMediaBoxHeight );
5843 : : aLine.append( " ]\n"
5844 [ # # ]: 0 : "/Kids[ " );
5845 : 0 : unsigned int i = 0;
5846 [ # # ][ # # ]: 0 : for( std::vector<PDFPage>::const_iterator iter = m_aPages.begin(); iter != m_aPages.end(); ++iter, i++ )
[ # # ]
5847 : : {
5848 [ # # ]: 0 : aLine.append( iter->m_nPageObject );
5849 [ # # ]: 0 : aLine.append( " 0 R" );
5850 [ # # ][ # # ]: 0 : aLine.append( ( (i&15) == 15 ) ? "\n" : " " );
5851 : : }
5852 : : aLine.append( "]\n"
5853 [ # # ]: 0 : "/Count " );
5854 [ # # ]: 0 : aLine.append( (sal_Int32)m_aPages.size() );
5855 : : aLine.append( ">>\n"
5856 [ # # ]: 0 : "endobj\n\n" );
5857 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
5858 : :
5859 : : // emit annotation objects
5860 [ # # ][ # # ]: 0 : CHECK_RETURN( emitAnnotations() );
5861 : :
5862 : : // emit Catalog
5863 [ # # ]: 0 : m_nCatalogObject = createObject();
5864 [ # # ][ # # ]: 0 : if( ! updateObject( m_nCatalogObject ) )
5865 : 0 : return false;
5866 [ # # ]: 0 : aLine.setLength( 0 );
5867 [ # # ]: 0 : aLine.append( m_nCatalogObject );
5868 : : aLine.append( " 0 obj\n"
5869 [ # # ]: 0 : "<</Type/Catalog/Pages " );
5870 [ # # ]: 0 : aLine.append( nTreeNode );
5871 [ # # ]: 0 : aLine.append( " 0 R\n" );
5872 : : //--->i56629
5873 : : //check if there are named destinations to emit (root must be inside the catalog)
5874 [ # # ]: 0 : if( nNamedDestinationsDictionary )
5875 : : {
5876 [ # # ]: 0 : aLine.append("/Dests ");
5877 [ # # ]: 0 : aLine.append( nNamedDestinationsDictionary );
5878 [ # # ]: 0 : aLine.append( " 0 R\n" );
5879 : : }
5880 : : //<----
5881 [ # # ]: 0 : if( m_aContext.PageLayout != PDFWriter::DefaultLayout )
5882 [ # # # ]: 0 : switch( m_aContext.PageLayout )
5883 : : {
5884 : : default :
5885 : : case PDFWriter::SinglePage :
5886 [ # # ]: 0 : aLine.append( "/PageLayout/SinglePage\n" );
5887 : 0 : break;
5888 : : case PDFWriter::Continuous :
5889 [ # # ]: 0 : aLine.append( "/PageLayout/OneColumn\n" );
5890 : 0 : break;
5891 : : case PDFWriter::ContinuousFacing :
5892 : : //the flag m_aContext.FirstPageLeft below is used to set the page on the left side
5893 [ # # ]: 0 : aLine.append( "/PageLayout/TwoColumnRight\n" );//odd page on the right side
5894 : 0 : break;
5895 : : }
5896 [ # # ][ # # ]: 0 : if( m_aContext.PDFDocumentMode != PDFWriter::ModeDefault && !m_aContext.OpenInFullScreenMode )
5897 [ # # # ]: 0 : switch( m_aContext.PDFDocumentMode )
5898 : : {
5899 : : default :
5900 [ # # ]: 0 : aLine.append( "/PageMode/UseNone\n" );
5901 : 0 : break;
5902 : : case PDFWriter::UseOutlines :
5903 [ # # ]: 0 : aLine.append( "/PageMode/UseOutlines\n" ); //document is opened with outline pane open
5904 : 0 : break;
5905 : : case PDFWriter::UseThumbs :
5906 [ # # ]: 0 : aLine.append( "/PageMode/UseThumbs\n" ); //document is opened with thumbnails pane open
5907 : 0 : break;
5908 : : }
5909 [ # # ]: 0 : else if( m_aContext.OpenInFullScreenMode )
5910 [ # # ]: 0 : aLine.append( "/PageMode/FullScreen\n" ); //document is opened full screen
5911 : :
5912 : 0 : OStringBuffer aInitPageRef;
5913 [ # # ][ # # ]: 0 : if( m_aContext.InitialPage >= 0 && m_aContext.InitialPage < (sal_Int32)m_aPages.size() )
[ # # ]
5914 : : {
5915 [ # # ]: 0 : aInitPageRef.append( m_aPages[m_aContext.InitialPage].m_nPageObject );
5916 [ # # ]: 0 : aInitPageRef.append( " 0 R" );
5917 : : }
5918 : : else
5919 [ # # ]: 0 : aInitPageRef.append( "0" );
5920 : :
5921 : : #if !defined(ANDROID) && !defined(IOS)
5922 [ # # ]: 0 : if (m_nSignatureObject != -1) // Document will be signed
5923 : : {
5924 [ # # ]: 0 : aLine.append("/Perms<</DocMDP ");
5925 [ # # ]: 0 : aLine.append(m_nSignatureObject);
5926 [ # # ]: 0 : aLine.append(" 0 R>>");
5927 : : }
5928 : : #endif
5929 : :
5930 [ # # # # : 0 : switch( m_aContext.PDFDocumentAction )
# ]
5931 : : {
5932 : : case PDFWriter::ActionDefault : //do nothing, this is the Acrobat default
5933 : : default:
5934 [ # # ]: 0 : if( aInitPageRef.getLength() > 1 )
5935 : : {
5936 [ # # ]: 0 : aLine.append( "/OpenAction[" );
5937 [ # # ]: 0 : aLine.append( aInitPageRef.makeStringAndClear() );
5938 [ # # ]: 0 : aLine.append( " /XYZ null null 0]\n" );
5939 : : }
5940 : 0 : break;
5941 : : case PDFWriter::FitInWindow :
5942 [ # # ]: 0 : aLine.append( "/OpenAction[" );
5943 [ # # ]: 0 : aLine.append( aInitPageRef.makeStringAndClear() );
5944 [ # # ]: 0 : aLine.append( " /Fit]\n" ); //Open fit page
5945 : 0 : break;
5946 : : case PDFWriter::FitWidth :
5947 [ # # ]: 0 : aLine.append( "/OpenAction[" );
5948 [ # # ]: 0 : aLine.append( aInitPageRef.makeStringAndClear() );
5949 [ # # ]: 0 : aLine.append( " /FitH " );
5950 [ # # ]: 0 : aLine.append( m_nInheritedPageHeight );//Open fit width
5951 [ # # ]: 0 : aLine.append( "]\n" );
5952 : 0 : break;
5953 : : case PDFWriter::FitVisible :
5954 [ # # ]: 0 : aLine.append( "/OpenAction[" );
5955 [ # # ]: 0 : aLine.append( aInitPageRef.makeStringAndClear() );
5956 [ # # ]: 0 : aLine.append( " /FitBH " );
5957 [ # # ]: 0 : aLine.append( m_nInheritedPageHeight );//Open fit visible
5958 [ # # ]: 0 : aLine.append( "]\n" );
5959 : 0 : break;
5960 : : case PDFWriter::ActionZoom :
5961 [ # # ]: 0 : aLine.append( "/OpenAction[" );
5962 [ # # ]: 0 : aLine.append( aInitPageRef.makeStringAndClear() );
5963 [ # # ]: 0 : aLine.append( " /XYZ null null " );
5964 [ # # ][ # # ]: 0 : if( m_aContext.Zoom >= 50 && m_aContext.Zoom <= 1600 )
5965 [ # # ]: 0 : aLine.append( (double)m_aContext.Zoom/100.0 );
5966 : : else
5967 [ # # ]: 0 : aLine.append( "0" );
5968 [ # # ]: 0 : aLine.append( "]\n" );
5969 : 0 : break;
5970 : : }
5971 : : // viewer preferences, if we had some, then emit
5972 [ # # ]: 0 : if( m_aContext.HideViewerToolbar ||
[ # # # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
5973 : 0 : ( m_aContext.Version > PDFWriter::PDF_1_3 && m_aContext.DocumentInfo.Title.Len() && m_aContext.DisplayPDFDocumentTitle ) ||
5974 : : m_aContext.HideViewerMenubar ||
5975 : : m_aContext.HideViewerWindowControls || m_aContext.FitWindow ||
5976 : : m_aContext.CenterWindow || (m_aContext.FirstPageLeft && m_aContext.PageLayout == PDFWriter::ContinuousFacing ) ||
5977 : : m_aContext.OpenInFullScreenMode )
5978 : : {
5979 [ # # ]: 0 : aLine.append( "/ViewerPreferences<<" );
5980 [ # # ]: 0 : if( m_aContext.HideViewerToolbar )
5981 [ # # ]: 0 : aLine.append( "/HideToolbar true\n" );
5982 [ # # ]: 0 : if( m_aContext.HideViewerMenubar )
5983 [ # # ]: 0 : aLine.append( "/HideMenubar true\n" );
5984 [ # # ]: 0 : if( m_aContext.HideViewerWindowControls )
5985 [ # # ]: 0 : aLine.append( "/HideWindowUI true\n" );
5986 [ # # ]: 0 : if( m_aContext.FitWindow )
5987 [ # # ]: 0 : aLine.append( "/FitWindow true\n" );
5988 [ # # ]: 0 : if( m_aContext.CenterWindow )
5989 [ # # ]: 0 : aLine.append( "/CenterWindow true\n" );
5990 [ # # ][ # # ]: 0 : if( m_aContext.Version > PDFWriter::PDF_1_3 && m_aContext.DocumentInfo.Title.Len() && m_aContext.DisplayPDFDocumentTitle )
[ # # ][ # # ]
5991 [ # # ]: 0 : aLine.append( "/DisplayDocTitle true\n" );
5992 [ # # ][ # # ]: 0 : if( m_aContext.FirstPageLeft && m_aContext.PageLayout == PDFWriter::ContinuousFacing )
5993 [ # # ]: 0 : aLine.append( "/Direction/R2L\n" );
5994 [ # # ]: 0 : if( m_aContext.OpenInFullScreenMode )
5995 [ # # # ]: 0 : switch( m_aContext.PDFDocumentMode )
5996 : : {
5997 : : default :
5998 : : case PDFWriter::ModeDefault :
5999 [ # # ]: 0 : aLine.append( "/NonFullScreenPageMode/UseNone\n" );
6000 : 0 : break;
6001 : : case PDFWriter::UseOutlines :
6002 [ # # ]: 0 : aLine.append( "/NonFullScreenPageMode/UseOutlines\n" );
6003 : 0 : break;
6004 : : case PDFWriter::UseThumbs :
6005 [ # # ]: 0 : aLine.append( "/NonFullScreenPageMode/UseThumbs\n" );
6006 : 0 : break;
6007 : : }
6008 [ # # ]: 0 : aLine.append( ">>\n" );
6009 : : }
6010 : :
6011 [ # # ]: 0 : if( nOutlineDict )
6012 : : {
6013 [ # # ]: 0 : aLine.append( "/Outlines " );
6014 [ # # ]: 0 : aLine.append( nOutlineDict );
6015 [ # # ]: 0 : aLine.append( " 0 R\n" );
6016 : : }
6017 [ # # ]: 0 : if( nStructureDict )
6018 : : {
6019 [ # # ]: 0 : aLine.append( "/StructTreeRoot " );
6020 [ # # ]: 0 : aLine.append( nStructureDict );
6021 [ # # ]: 0 : aLine.append( " 0 R\n" );
6022 : : }
6023 [ # # ]: 0 : if( !m_aContext.DocumentLocale.Language.isEmpty() )
6024 : : {
6025 : 0 : OUStringBuffer aLocBuf( 16 );
6026 [ # # ]: 0 : aLocBuf.append( m_aContext.DocumentLocale.Language.toAsciiLowerCase() );
6027 [ # # ]: 0 : if( !m_aContext.DocumentLocale.Country.isEmpty() )
6028 : : {
6029 [ # # ]: 0 : aLocBuf.append( sal_Unicode('-') );
6030 [ # # ]: 0 : aLocBuf.append( m_aContext.DocumentLocale.Country );
6031 : : }
6032 [ # # ]: 0 : aLine.append( "/Lang" );
6033 [ # # ][ # # ]: 0 : appendLiteralStringEncrypt( aLocBuf.makeStringAndClear(), m_nCatalogObject, aLine );
6034 [ # # ]: 0 : aLine.append( "\n" );
6035 : : }
6036 [ # # ][ # # ]: 0 : if( m_aContext.Tagged && m_aContext.Version > PDFWriter::PDF_1_3 )
6037 : : {
6038 [ # # ]: 0 : aLine.append( "/MarkInfo<</Marked true>>\n" );
6039 : : }
6040 [ # # ]: 0 : if( m_aWidgets.size() > 0 )
6041 : : {
6042 [ # # ]: 0 : aLine.append( "/AcroForm<</Fields[\n" );
6043 : 0 : int nWidgets = m_aWidgets.size();
6044 : 0 : int nOut = 0;
6045 [ # # ]: 0 : for( int j = 0; j < nWidgets; j++ )
6046 : : {
6047 : : // output only root fields
6048 [ # # ]: 0 : if( m_aWidgets[j].m_nParent < 1 )
6049 : : {
6050 [ # # ]: 0 : aLine.append( m_aWidgets[j].m_nObject );
6051 [ # # ][ # # ]: 0 : aLine.append( (nOut++ % 5)==4 ? " 0 R\n" : " 0 R " );
6052 : : }
6053 : : }
6054 [ # # ]: 0 : aLine.append( "\n]" );
6055 : :
6056 : : #if !defined(ANDROID) && !defined(IOS)
6057 [ # # ]: 0 : if (m_nSignatureObject != -1)
6058 [ # # ]: 0 : aLine.append( "/SigFlags 3");
6059 : : #endif
6060 : :
6061 [ # # ]: 0 : aLine.append( "/DR " );
6062 [ # # ][ # # ]: 0 : aLine.append( getResourceDictObj() );
6063 [ # # ]: 0 : aLine.append( " 0 R" );
6064 : : // /NeedAppearances must not be used if PDF is signed
6065 [ # # ][ # # ]: 0 : if( m_bIsPDF_A1
6066 : : #if !defined(ANDROID) && !defined(IOS)
6067 : : || ( m_nSignatureObject != -1 )
6068 : : #endif
6069 : : )
6070 [ # # ]: 0 : aLine.append( ">>\n" );
6071 : : else
6072 [ # # ]: 0 : aLine.append( "/NeedAppearances true>>\n" );
6073 : : }
6074 : : //--->i59651
6075 : : //check if there is a Metadata object
6076 [ # # ]: 0 : if( nOutputIntentObject )
6077 : : {
6078 [ # # ]: 0 : aLine.append("/OutputIntents[");
6079 [ # # ]: 0 : aLine.append( nOutputIntentObject );
6080 [ # # ]: 0 : aLine.append( " 0 R]" );
6081 : : }
6082 [ # # ]: 0 : if( nMetadataObject )
6083 : : {
6084 [ # # ]: 0 : aLine.append("/Metadata ");
6085 [ # # ]: 0 : aLine.append( nMetadataObject );
6086 [ # # ]: 0 : aLine.append( " 0 R" );
6087 : : }
6088 : : //<----
6089 : : aLine.append( ">>\n"
6090 [ # # ]: 0 : "endobj\n\n" );
6091 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
6092 : :
6093 : 0 : return true;
6094 : : }
6095 : :
6096 : : #if !defined(ANDROID) && !defined(IOS)
6097 : :
6098 : 0 : bool PDFWriterImpl::emitSignature()
6099 : : {
6100 [ # # ][ # # ]: 0 : if( !updateObject( m_nSignatureObject ) )
6101 : 0 : return false;
6102 : :
6103 : 0 : OStringBuffer aLine( 0x5000 );
6104 [ # # ]: 0 : aLine.append( m_nSignatureObject );
6105 [ # # ]: 0 : aLine.append( " 0 obj\n" );
6106 [ # # ]: 0 : aLine.append("<</Reference[<</Data ");
6107 [ # # ]: 0 : aLine.append( m_nCatalogObject );
6108 : : aLine.append(" 0 R/Type/SigRef/TransformParams<</Type/TransformParams"
6109 : : "/V/1.2/P 1>>/DigestMethod/MD5/DigestLocation[0 0]"
6110 [ # # ]: 0 : "/DigestValue(aa)/TransformMethod/DocMDP>>]/Contents <" );
6111 : :
6112 : 0 : sal_uInt64 nOffset = ~0U;
6113 [ # # ][ # # ]: 0 : CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nOffset ) ) );
6114 : :
6115 : 0 : m_nSignatureContentOffset = nOffset + aLine.getLength();
6116 : :
6117 : : // reserve some space for the PKCS#7 object
6118 : 0 : OStringBuffer aContentFiller( MAX_SIGNATURE_CONTENT_LENGTH );
6119 [ # # ]: 0 : comphelper::string::padToLength(aContentFiller, MAX_SIGNATURE_CONTENT_LENGTH, '0');
6120 [ # # ]: 0 : aLine.append( aContentFiller.makeStringAndClear() );
6121 [ # # ]: 0 : aLine.append( ">\n/Type/Sig/SubFilter/adbe.pkcs7.detached");
6122 : :
6123 [ # # ]: 0 : if( m_aContext.DocumentInfo.Author.Len() )
6124 : : {
6125 [ # # ]: 0 : aLine.append( "/Name" );
6126 [ # # ][ # # ]: 0 : appendUnicodeTextStringEncrypt( m_aContext.DocumentInfo.Author, m_nSignatureObject, aLine );
6127 : : }
6128 : :
6129 [ # # ]: 0 : aLine.append( " /M ");
6130 [ # # ]: 0 : appendLiteralStringEncrypt( m_aCreationDateString, m_nSignatureObject, aLine );
6131 : :
6132 [ # # ]: 0 : aLine.append( " /ByteRange [ 0 ");
6133 [ # # ]: 0 : aLine.append( m_nSignatureContentOffset - 1, 10 );
6134 [ # # ]: 0 : aLine.append( " " );
6135 [ # # ]: 0 : aLine.append( m_nSignatureContentOffset + MAX_SIGNATURE_CONTENT_LENGTH + 1, 10 );
6136 [ # # ]: 0 : aLine.append( " " );
6137 : :
6138 : 0 : m_nSignatureLastByteRangeNoOffset = nOffset + aLine.getLength();
6139 : :
6140 : : // mark the last ByteRange no and add some space. Now, we don't know
6141 : : // how many bytes we need for this ByteRange value
6142 : : // The real value will be overwritten in the finalizeSignature method
6143 : 0 : OStringBuffer aByteRangeFiller( 100 );
6144 [ # # ]: 0 : comphelper::string::padToLength(aByteRangeFiller, 100, ' ');
6145 [ # # ]: 0 : aLine.append( aByteRangeFiller.makeStringAndClear() );
6146 [ # # ]: 0 : aLine.append(" /Filter/Adobe.PPKMS");
6147 : :
6148 : : //emit reason, location and contactinfo
6149 [ # # ]: 0 : if ( !m_aContext.SignReason.isEmpty() )
6150 : : {
6151 [ # # ]: 0 : aLine.append("/Reason");
6152 [ # # ]: 0 : appendUnicodeTextStringEncrypt( m_aContext.SignReason, m_nSignatureObject, aLine );
6153 : : }
6154 : :
6155 [ # # ]: 0 : if ( !m_aContext.SignLocation.isEmpty() )
6156 : : {
6157 [ # # ]: 0 : aLine.append("/Location");
6158 [ # # ]: 0 : appendUnicodeTextStringEncrypt( m_aContext.SignLocation, m_nSignatureObject, aLine );
6159 : : }
6160 : :
6161 [ # # ]: 0 : if ( !m_aContext.SignContact.isEmpty() )
6162 : : {
6163 [ # # ]: 0 : aLine.append("/ContactInfo");
6164 [ # # ]: 0 : appendUnicodeTextStringEncrypt( m_aContext.SignContact, m_nSignatureObject, aLine );
6165 : : }
6166 : :
6167 [ # # ]: 0 : aLine.append(" >>\nendobj\n\n" );
6168 : :
6169 [ # # ][ # # ]: 0 : if (!writeBuffer( aLine.getStr(), aLine.getLength() ))
6170 : 0 : return false;
6171 : :
6172 : 0 : return true;
6173 : : }
6174 : :
6175 : 0 : char *PDFSigningPKCS7PasswordCallback(PK11SlotInfo * /*slot*/, PRBool /*retry*/, void *arg)
6176 : : {
6177 : 0 : return (char *)arg;
6178 : : }
6179 : :
6180 : 0 : bool PDFWriterImpl::finalizeSignature()
6181 : : {
6182 : :
6183 [ # # ]: 0 : if (!m_aContext.SignCertificate.is())
6184 : 0 : return false;
6185 : :
6186 : : // 1- calculate last ByteRange value
6187 : 0 : sal_uInt64 nOffset = ~0U;
6188 [ # # ][ # # ]: 0 : CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nOffset ) ) );
6189 : :
6190 : 0 : sal_Int64 nLastByteRangeNo = nOffset - (m_nSignatureContentOffset + MAX_SIGNATURE_CONTENT_LENGTH + 1);
6191 : :
6192 : : // 2- overwrite the value to the m_nSignatureLastByteRangeNoOffset position
6193 : 0 : sal_uInt64 nWritten = 0;
6194 [ # # ][ # # ]: 0 : CHECK_RETURN( (osl_File_E_None == osl_setFilePos( m_aFile, osl_Pos_Absolut, m_nSignatureLastByteRangeNoOffset ) ) );
6195 : 0 : OStringBuffer aByteRangeNo( 256 );
6196 [ # # ]: 0 : aByteRangeNo.append( nLastByteRangeNo, 10);
6197 [ # # ]: 0 : aByteRangeNo.append( " ]" );
6198 : :
6199 [ # # ][ # # ]: 0 : if( osl_writeFile( m_aFile, aByteRangeNo.getStr(), aByteRangeNo.getLength(), &nWritten ) != osl_File_E_None )
6200 : : {
6201 [ # # ][ # # ]: 0 : CHECK_RETURN( (osl_File_E_None == osl_setFilePos( m_aFile, osl_Pos_Absolut, nOffset ) ) );
6202 : 0 : return false;
6203 : : }
6204 : :
6205 : : // 3- create the PKCS#7 object using NSS
6206 [ # # ][ # # ]: 0 : com::sun::star::uno::Sequence< sal_Int8 > derEncoded = m_aContext.SignCertificate->getEncoded();
6207 : :
6208 [ # # ]: 0 : if (!derEncoded.hasElements())
6209 : 0 : return false;
6210 : :
6211 [ # # ]: 0 : sal_Int8* n_derArray = derEncoded.getArray();
6212 : 0 : sal_Int32 n_derLength = derEncoded.getLength();
6213 : :
6214 [ # # ]: 0 : NSS_NoDB_Init(".");
6215 : :
6216 [ # # ]: 0 : CERTCertificate *cert = CERT_DecodeCertFromPackage(reinterpret_cast<char *>(n_derArray), n_derLength);
6217 : :
6218 [ # # ]: 0 : if (!cert)
6219 : : {
6220 : : SAL_WARN("vcl.gdi", "PDF Signing: Error occured, certificate cannot be reconstructed.");
6221 : 0 : return false;
6222 : : }
6223 : :
6224 : : SAL_WARN("vcl.gdi", "PDF Signing: Certificate Subject: " << cert->subjectName << "\n\tCertificate Issuer: " << cert->issuerName);
6225 : :
6226 : : // Prepare buffer and calculate PDF file digest
6227 [ # # ][ # # ]: 0 : CHECK_RETURN( (osl_File_E_None == osl_setFilePos( m_aFile, osl_Pos_Absolut, 0) ) );
6228 : :
6229 [ # # ]: 0 : HASHContext *hc = HASH_Create(HASH_AlgSHA1);
6230 : :
6231 [ # # ]: 0 : if (!hc)
6232 : : {
6233 : : SAL_WARN("vcl.gdi", "PDF Signing: SHA1 HASH_Create failed!");
6234 : 0 : return false;
6235 : : }
6236 : :
6237 [ # # ]: 0 : HASH_Begin(hc);
6238 : :
6239 [ # # ]: 0 : char *buffer = new char[m_nSignatureContentOffset + 1];
6240 : : sal_uInt64 bytesRead;
6241 : :
6242 : : //FIXME: Check if SHA1 is calculated from the correct byterange
6243 : :
6244 [ # # ][ # # ]: 0 : CHECK_RETURN( (osl_File_E_None == osl_readFile( m_aFile, buffer, m_nSignatureContentOffset - 1 , &bytesRead ) ) );
6245 : 0 : if (bytesRead != (sal_uInt64)m_nSignatureContentOffset - 1)
6246 : : SAL_WARN("vcl.gdi", "PDF Signing: First buffer read failed!");
6247 : :
6248 [ # # ]: 0 : HASH_Update(hc, reinterpret_cast<const unsigned char*>(buffer), bytesRead);
6249 [ # # ]: 0 : delete[] buffer;
6250 : :
6251 [ # # ]: 0 : buffer = new char[nLastByteRangeNo + 1];
6252 [ # # ][ # # ]: 0 : CHECK_RETURN( (osl_File_E_None == osl_setFilePos( m_aFile, osl_Pos_Absolut, m_nSignatureContentOffset + MAX_SIGNATURE_CONTENT_LENGTH + 1) ) );
6253 [ # # ][ # # ]: 0 : CHECK_RETURN( (osl_File_E_None == osl_readFile( m_aFile, buffer, nLastByteRangeNo, &bytesRead ) ) );
6254 : 0 : if (bytesRead != (sal_uInt64) nLastByteRangeNo)
6255 : : SAL_WARN("vcl.gdi", "PDF Signing: Second buffer read failed!");
6256 : :
6257 [ # # ]: 0 : HASH_Update(hc, reinterpret_cast<const unsigned char*>(buffer), bytesRead);
6258 [ # # ]: 0 : delete[] buffer;
6259 : :
6260 : : SECItem digest;
6261 : : unsigned char hash[SHA1_LENGTH];
6262 : 0 : digest.data = hash;
6263 [ # # ]: 0 : HASH_End(hc, digest.data, &digest.len, SHA1_LENGTH);
6264 [ # # ]: 0 : HASH_Destroy(hc);
6265 : :
6266 [ # # ]: 0 : const char *pass = OUStringToOString( m_aContext.SignPassword, RTL_TEXTENCODING_UTF8 ).getStr();
6267 : :
6268 [ # # ]: 0 : NSSCMSMessage *cms_msg = NSS_CMSMessage_Create(NULL);
6269 [ # # ]: 0 : if (!cms_msg)
6270 : : {
6271 : : SAL_WARN("vcl.gdi", "PDF signing: can't create new CMS message.");
6272 : 0 : return false;
6273 : : }
6274 : :
6275 [ # # ]: 0 : NSSCMSSignedData *cms_sd = NSS_CMSSignedData_Create(cms_msg);
6276 [ # # ]: 0 : if (!cms_sd)
6277 : : {
6278 : : SAL_WARN("vcl.gdi", "PDF signing: can't create CMS SignedData.");
6279 : 0 : return false;
6280 : : }
6281 : :
6282 [ # # ]: 0 : NSSCMSContentInfo *cms_cinfo = NSS_CMSMessage_GetContentInfo(cms_msg);
6283 [ # # ][ # # ]: 0 : if (NSS_CMSContentInfo_SetContent_SignedData(cms_msg, cms_cinfo, cms_sd) != SECSuccess)
6284 : : {
6285 : : SAL_WARN("vcl.gdi", "PDF signing: Can't set CMS content signed data.");
6286 : 0 : return false;
6287 : : }
6288 : :
6289 [ # # ]: 0 : cms_cinfo = NSS_CMSSignedData_GetContentInfo(cms_sd);
6290 : : //attach NULL data as detached data
6291 [ # # ][ # # ]: 0 : if (NSS_CMSContentInfo_SetContent_Data(cms_msg, cms_cinfo, NULL, PR_TRUE) != SECSuccess)
6292 : : {
6293 : : SAL_WARN("vcl.gdi", "PDF signing: Can't set CMS content data.");
6294 : 0 : return false;
6295 : : }
6296 : :
6297 [ # # ]: 0 : NSSCMSSignerInfo *cms_signer = NSS_CMSSignerInfo_Create(cms_msg, cert, SEC_OID_SHA1);
6298 [ # # ]: 0 : if (!cms_signer)
6299 : : {
6300 : : SAL_WARN("vcl.gdi", "PDF signing: can't create CMS SignerInfo.");
6301 : 0 : return false;
6302 : : }
6303 : :
6304 [ # # ][ # # ]: 0 : if (NSS_CMSSignerInfo_IncludeCerts(cms_signer, NSSCMSCM_CertChain, certUsageEmailSigner) != SECSuccess)
6305 : : {
6306 : : SAL_WARN("vcl.gdi", "PDF signing: can't include cert chain.");
6307 : 0 : return false;
6308 : : }
6309 : :
6310 : : //NSS_CMSSignerInfo_AddSigningTime(cms_signer, PR_Now()); //TODO: Needs PDF 1.6?
6311 : :
6312 [ # # ][ # # ]: 0 : if (NSS_CMSSignedData_AddCertificate(cms_sd, cert) != SECSuccess)
6313 : : {
6314 : : SAL_WARN("vcl.gdi", "PDF signing: can't add signer certificate.");
6315 : 0 : return false;
6316 : : }
6317 : :
6318 [ # # ][ # # ]: 0 : if (NSS_CMSSignedData_AddSignerInfo(cms_sd, cms_signer) != SECSuccess)
6319 : : {
6320 : : SAL_WARN("vcl.gdi", "PDF signing: can't add signer info.");
6321 : 0 : return false;
6322 : : }
6323 : :
6324 [ # # ][ # # ]: 0 : if (NSS_CMSSignedData_SetDigestValue(cms_sd, SEC_OID_SHA1, &digest) != SECSuccess)
6325 : : {
6326 : : SAL_WARN("vcl.gdi", "PDF signing: can't set PDF digest value.");
6327 : 0 : return false;
6328 : : }
6329 : :
6330 : : SAL_WARN("vcl.gdi","PKCS7 Object created successfully!");
6331 : :
6332 : : SECItem cms_output;
6333 : 0 : cms_output.data = 0;
6334 : 0 : cms_output.len = 0;
6335 [ # # ]: 0 : PLArenaPool *arena = PORT_NewArena(MAX_SIGNATURE_CONTENT_LENGTH);
6336 : : NSSCMSEncoderContext *cms_ecx;
6337 : :
6338 : : //FIXME: Check if password is passed correctly to SEC_PKCS7CreateSignedData function
6339 [ # # ]: 0 : cms_ecx = NSS_CMSEncoder_Start(cms_msg, NULL, NULL, &cms_output, arena, (PK11PasswordFunc)::PDFSigningPKCS7PasswordCallback, (void *)pass, NULL, NULL, NULL, NULL);
6340 : :
6341 [ # # ]: 0 : if (!cms_ecx)
6342 : : {
6343 : : SAL_WARN("vcl.gdi", "PDF Signing: can't start DER encoder.");
6344 : 0 : return false;
6345 : : }
6346 : : SAL_WARN("vcl.gdi", "PDF Signing: Started DER encoding.");
6347 : :
6348 [ # # ][ # # ]: 0 : if (NSS_CMSEncoder_Finish(cms_ecx) != SECSuccess)
6349 : : {
6350 : : SAL_WARN("vcl.gdi", "PDF Signing: can't finish DER encoder.");
6351 : 0 : return false;
6352 : : }
6353 : : SAL_WARN("vcl.gdi", "PDF Signing: Finished DER encoding.");
6354 : :
6355 : 0 : OStringBuffer cms_hexbuffer;
6356 : :
6357 [ # # ]: 0 : for (unsigned int i = 0; i < cms_output.len ; i++)
6358 [ # # ]: 0 : appendHex(cms_output.data[i], cms_hexbuffer);
6359 : :
6360 : : SAL_WARN("vcl.gdi","PKCS7 object encoded successfully!");
6361 : :
6362 : : // Set file pointer to the m_nSignatureContentOffset, we're ready to overwrite PKCS7 object
6363 : 0 : nWritten = 0;
6364 [ # # ][ # # ]: 0 : CHECK_RETURN( (osl_File_E_None == osl_setFilePos( m_aFile, osl_Pos_Absolut, m_nSignatureContentOffset) ) );
6365 [ # # ]: 0 : osl_writeFile(m_aFile, cms_hexbuffer.getStr(), cms_hexbuffer.getLength(), &nWritten);
6366 : :
6367 [ # # ]: 0 : NSS_CMSMessage_Destroy(cms_msg);
6368 : :
6369 [ # # ][ # # ]: 0 : CHECK_RETURN( (osl_File_E_None == osl_setFilePos( m_aFile, osl_Pos_Absolut, nOffset ) ) );
6370 [ # # ]: 0 : return true;
6371 : : }
6372 : :
6373 : : #endif
6374 : :
6375 : 0 : sal_Int32 PDFWriterImpl::emitInfoDict( )
6376 : : {
6377 : 0 : sal_Int32 nObject = createObject();
6378 : :
6379 [ # # ]: 0 : if( updateObject( nObject ) )
6380 : : {
6381 : 0 : OStringBuffer aLine( 1024 );
6382 [ # # ]: 0 : aLine.append( nObject );
6383 : : aLine.append( " 0 obj\n"
6384 [ # # ]: 0 : "<<" );
6385 [ # # ]: 0 : if( m_aContext.DocumentInfo.Title.Len() )
6386 : : {
6387 [ # # ]: 0 : aLine.append( "/Title" );
6388 [ # # ][ # # ]: 0 : appendUnicodeTextStringEncrypt( m_aContext.DocumentInfo.Title, nObject, aLine );
6389 [ # # ]: 0 : aLine.append( "\n" );
6390 : : }
6391 [ # # ]: 0 : if( m_aContext.DocumentInfo.Author.Len() )
6392 : : {
6393 [ # # ]: 0 : aLine.append( "/Author" );
6394 [ # # ][ # # ]: 0 : appendUnicodeTextStringEncrypt( m_aContext.DocumentInfo.Author, nObject, aLine );
6395 [ # # ]: 0 : aLine.append( "\n" );
6396 : : }
6397 [ # # ]: 0 : if( m_aContext.DocumentInfo.Subject.Len() )
6398 : : {
6399 [ # # ]: 0 : aLine.append( "/Subject" );
6400 [ # # ][ # # ]: 0 : appendUnicodeTextStringEncrypt( m_aContext.DocumentInfo.Subject, nObject, aLine );
6401 [ # # ]: 0 : aLine.append( "\n" );
6402 : : }
6403 [ # # ]: 0 : if( m_aContext.DocumentInfo.Keywords.Len() )
6404 : : {
6405 [ # # ]: 0 : aLine.append( "/Keywords" );
6406 [ # # ][ # # ]: 0 : appendUnicodeTextStringEncrypt( m_aContext.DocumentInfo.Keywords, nObject, aLine );
6407 [ # # ]: 0 : aLine.append( "\n" );
6408 : : }
6409 [ # # ]: 0 : if( m_aContext.DocumentInfo.Creator.Len() )
6410 : : {
6411 [ # # ]: 0 : aLine.append( "/Creator" );
6412 [ # # ][ # # ]: 0 : appendUnicodeTextStringEncrypt( m_aContext.DocumentInfo.Creator, nObject, aLine );
6413 [ # # ]: 0 : aLine.append( "\n" );
6414 : : }
6415 [ # # ]: 0 : if( m_aContext.DocumentInfo.Producer.Len() )
6416 : : {
6417 [ # # ]: 0 : aLine.append( "/Producer" );
6418 [ # # ][ # # ]: 0 : appendUnicodeTextStringEncrypt( m_aContext.DocumentInfo.Producer, nObject, aLine );
6419 [ # # ]: 0 : aLine.append( "\n" );
6420 : : }
6421 : :
6422 [ # # ]: 0 : aLine.append( "/CreationDate" );
6423 [ # # ]: 0 : appendLiteralStringEncrypt( m_aCreationDateString, nObject, aLine );
6424 [ # # ]: 0 : aLine.append( ">>\nendobj\n\n" );
6425 [ # # ][ # # ]: 0 : if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) )
6426 : 0 : nObject = 0;
6427 : : }
6428 : : else
6429 : 0 : nObject = 0;
6430 : :
6431 : 0 : return nObject;
6432 : : }
6433 : :
6434 : : //--->i56629
6435 : : // Part of this function may be shared with method appendDest.
6436 : : //
6437 : 0 : sal_Int32 PDFWriterImpl::emitNamedDestinations()
6438 : : {
6439 : 0 : sal_Int32 nCount = m_aNamedDests.size();
6440 [ # # ]: 0 : if( nCount <= 0 )
6441 : 0 : return 0;//define internal error
6442 : :
6443 : : //get the object number for all the destinations
6444 : 0 : sal_Int32 nObject = createObject();
6445 : :
6446 [ # # ]: 0 : if( updateObject( nObject ) )
6447 : : {
6448 : : //emit the dictionary
6449 : 0 : OStringBuffer aLine( 1024 );
6450 [ # # ]: 0 : aLine.append( nObject );
6451 : : aLine.append( " 0 obj\n"
6452 [ # # ]: 0 : "<<" );
6453 : :
6454 : : sal_Int32 nDestID;
6455 [ # # ]: 0 : for( nDestID = 0; nDestID < nCount; nDestID++ )
6456 : : {
6457 : 0 : const PDFNamedDest& rDest = m_aNamedDests[ nDestID ];
6458 : : // In order to correctly function both under an Internet browser and
6459 : : // directly with a reader (provided the reader has the feature) we
6460 : : // need to set the name of the destination the same way it will be encoded
6461 : : // in an Internet link
6462 : : INetURLObject aLocalURL(
6463 [ # # ]: 0 : OUString( "http://ahost.ax" ) ); //dummy location, won't be used
6464 [ # # ]: 0 : aLocalURL.SetMark( rDest.m_aDestName );
6465 : :
6466 [ # # ]: 0 : const rtl::OUString aName = aLocalURL.GetMark( INetURLObject::NO_DECODE ); //same coding as
6467 : : // in link creation ( see PDFWriterImpl::emitLinkAnnotations )
6468 : 0 : const PDFPage& rDestPage = m_aPages[ rDest.m_nPage ];
6469 : :
6470 [ # # ]: 0 : aLine.append( '/' );
6471 [ # # ]: 0 : appendDestinationName( aName, aLine ); // this conversion must be done when forming the link to target ( see in emitCatalog )
6472 [ # # ]: 0 : aLine.append( '[' ); // the '[' can be emitted immediately, because the appendDestinationName function
6473 : : //maps the preceeding character properly
6474 [ # # ]: 0 : aLine.append( rDestPage.m_nPageObject );
6475 [ # # ]: 0 : aLine.append( " 0 R" );
6476 : :
6477 [ # # # # : 0 : switch( rDest.m_eType )
# # # # ]
6478 : : {
6479 : : case PDFWriter::XYZ:
6480 : : default:
6481 [ # # ]: 0 : aLine.append( "/XYZ " );
6482 [ # # ]: 0 : appendFixedInt( rDest.m_aRect.Left(), aLine );
6483 [ # # ]: 0 : aLine.append( ' ' );
6484 [ # # ]: 0 : appendFixedInt( rDest.m_aRect.Bottom(), aLine );
6485 [ # # ]: 0 : aLine.append( " 0" );
6486 : 0 : break;
6487 : : case PDFWriter::Fit:
6488 [ # # ]: 0 : aLine.append( "/Fit" );
6489 : 0 : break;
6490 : : case PDFWriter::FitRectangle:
6491 [ # # ]: 0 : aLine.append( "/FitR " );
6492 [ # # ]: 0 : appendFixedInt( rDest.m_aRect.Left(), aLine );
6493 [ # # ]: 0 : aLine.append( ' ' );
6494 [ # # ]: 0 : appendFixedInt( rDest.m_aRect.Top(), aLine );
6495 [ # # ]: 0 : aLine.append( ' ' );
6496 [ # # ]: 0 : appendFixedInt( rDest.m_aRect.Right(), aLine );
6497 [ # # ]: 0 : aLine.append( ' ' );
6498 [ # # ]: 0 : appendFixedInt( rDest.m_aRect.Bottom(), aLine );
6499 : 0 : break;
6500 : : case PDFWriter::FitHorizontal:
6501 [ # # ]: 0 : aLine.append( "/FitH " );
6502 [ # # ]: 0 : appendFixedInt( rDest.m_aRect.Bottom(), aLine );
6503 : 0 : break;
6504 : : case PDFWriter::FitVertical:
6505 [ # # ]: 0 : aLine.append( "/FitV " );
6506 [ # # ]: 0 : appendFixedInt( rDest.m_aRect.Left(), aLine );
6507 : 0 : break;
6508 : : case PDFWriter::FitPageBoundingBox:
6509 [ # # ]: 0 : aLine.append( "/FitB" );
6510 : 0 : break;
6511 : : case PDFWriter::FitPageBoundingBoxHorizontal:
6512 [ # # ]: 0 : aLine.append( "/FitBH " );
6513 [ # # ]: 0 : appendFixedInt( rDest.m_aRect.Bottom(), aLine );
6514 : 0 : break;
6515 : : case PDFWriter::FitPageBoundingBoxVertical:
6516 [ # # ]: 0 : aLine.append( "/FitBV " );
6517 [ # # ]: 0 : appendFixedInt( rDest.m_aRect.Left(), aLine );
6518 : 0 : break;
6519 : : }
6520 [ # # ]: 0 : aLine.append( "]\n" );
6521 [ # # ]: 0 : }
6522 : : //close
6523 : :
6524 [ # # ]: 0 : aLine.append( ">>\nendobj\n\n" );
6525 [ # # ][ # # ]: 0 : if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) )
6526 : 0 : nObject = 0;
6527 : : }
6528 : : else
6529 : 0 : nObject = 0;
6530 : :
6531 : 0 : return nObject;
6532 : : }
6533 : : //<--- i56629
6534 : :
6535 : : //--->i59651
6536 : : // emits the output intent dictionary
6537 : :
6538 : 0 : sal_Int32 PDFWriterImpl::emitOutputIntent()
6539 : : {
6540 [ # # ]: 0 : if( !m_bIsPDF_A1 )
6541 : 0 : return 0;
6542 : :
6543 : : //emit the sRGB standard profile, in ICC format, in a stream, per IEC61966-2.1
6544 : :
6545 : 0 : OStringBuffer aLine( 1024 );
6546 [ # # ]: 0 : sal_Int32 nICCObject = createObject();
6547 [ # # ]: 0 : sal_Int32 nStreamLengthObject = createObject();
6548 : :
6549 [ # # ]: 0 : aLine.append( nICCObject );
6550 : : // sRGB has 3 colors, hence /N 3 below (PDF 1.4 table 4.16)
6551 [ # # ]: 0 : aLine.append( " 0 obj\n<</N 3/Length " );
6552 [ # # ]: 0 : aLine.append( nStreamLengthObject );
6553 [ # # ]: 0 : aLine.append( " 0 R" );
6554 : : #ifndef DEBUG_DISABLE_PDFCOMPRESSION
6555 [ # # ]: 0 : aLine.append( "/Filter/FlateDecode" );
6556 : : #endif
6557 [ # # ]: 0 : aLine.append( ">>\nstream\n" );
6558 [ # # ][ # # ]: 0 : CHECK_RETURN( updateObject( nICCObject ) );
6559 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
6560 : : //get file position
6561 : 0 : sal_uInt64 nBeginStreamPos = 0;
6562 [ # # ]: 0 : osl_getFilePos( m_aFile, &nBeginStreamPos );
6563 [ # # ]: 0 : beginCompression();
6564 [ # # ]: 0 : checkAndEnableStreamEncryption( nICCObject );
6565 [ # # ]: 0 : cmsHPROFILE hProfile = cmsCreate_sRGBProfile();
6566 : 0 : cmsUInt32Number nBytesNeeded = 0;
6567 [ # # ]: 0 : cmsSaveProfileToMem(hProfile, NULL, &nBytesNeeded);
6568 [ # # ]: 0 : if (!nBytesNeeded)
6569 : 0 : return 0;
6570 [ # # ]: 0 : std::vector<unsigned char> xBuffer(nBytesNeeded);
6571 [ # # ][ # # ]: 0 : cmsSaveProfileToMem(hProfile, &xBuffer[0], &nBytesNeeded);
6572 [ # # ]: 0 : cmsCloseProfile(hProfile);
6573 [ # # ][ # # ]: 0 : sal_Int32 nStreamSize = writeBuffer( &xBuffer[0], (sal_Int32) xBuffer.size() );
6574 : 0 : disableStreamEncryption();
6575 [ # # ]: 0 : endCompression();
6576 : 0 : sal_uInt64 nEndStreamPos = 0;
6577 [ # # ]: 0 : osl_getFilePos( m_aFile, &nEndStreamPos );
6578 : :
6579 [ # # ]: 0 : if( nStreamSize == 0 )
6580 : 0 : return 0;
6581 [ # # ][ # # ]: 0 : if( ! writeBuffer( "\nendstream\nendobj\n\n", 19 ) )
6582 : 0 : return 0 ;
6583 [ # # ]: 0 : aLine.setLength( 0 );
6584 : :
6585 : : //emit the stream length object
6586 [ # # ][ # # ]: 0 : CHECK_RETURN( updateObject( nStreamLengthObject ) );
6587 [ # # ]: 0 : aLine.setLength( 0 );
6588 [ # # ]: 0 : aLine.append( nStreamLengthObject );
6589 [ # # ]: 0 : aLine.append( " 0 obj\n" );
6590 [ # # ]: 0 : aLine.append( (sal_Int64)(nEndStreamPos-nBeginStreamPos) );
6591 [ # # ]: 0 : aLine.append( "\nendobj\n\n" );
6592 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
6593 [ # # ]: 0 : aLine.setLength( 0 );
6594 : :
6595 : : //emit the OutputIntent dictionary
6596 [ # # ]: 0 : sal_Int32 nOIObject = createObject();
6597 [ # # ][ # # ]: 0 : CHECK_RETURN( updateObject( nOIObject ) );
6598 [ # # ]: 0 : aLine.append( nOIObject );
6599 : : aLine.append( " 0 obj\n"
6600 [ # # ]: 0 : "<</Type/OutputIntent/S/GTS_PDFA1/OutputConditionIdentifier");
6601 : :
6602 : 0 : rtl::OUString aComment( "sRGB IEC61966-2.1" );
6603 [ # # ]: 0 : appendLiteralStringEncrypt( aComment ,nOIObject, aLine );
6604 [ # # ]: 0 : aLine.append("/DestOutputProfile ");
6605 [ # # ]: 0 : aLine.append( nICCObject );
6606 [ # # ]: 0 : aLine.append( " 0 R>>\nendobj\n\n" );;
6607 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
6608 : :
6609 : 0 : return nOIObject;
6610 : : }
6611 : :
6612 : : // formats the string for the XML stream
6613 : 0 : static void escapeStringXML( const rtl::OUString& rStr, rtl::OUString &rValue)
6614 : : {
6615 : 0 : const sal_Unicode* pUni = rStr.getStr();
6616 : 0 : int nLen = rStr.getLength();
6617 [ # # ]: 0 : for( ; nLen; nLen--, pUni++ )
6618 : : {
6619 [ # # # # : 0 : switch( *pUni )
# # ]
6620 : : {
6621 : : case sal_Unicode('&'):
6622 : 0 : rValue += rtl::OUString( "&" );
6623 : 0 : break;
6624 : : case sal_Unicode('<'):
6625 : 0 : rValue += rtl::OUString( "<" );
6626 : 0 : break;
6627 : : case sal_Unicode('>'):
6628 : 0 : rValue += rtl::OUString( ">" );
6629 : 0 : break;
6630 : : case sal_Unicode('\''):
6631 : 0 : rValue += rtl::OUString( "'" );
6632 : 0 : break;
6633 : : case sal_Unicode('"'):
6634 : 0 : rValue += rtl::OUString( """ );
6635 : 0 : break;
6636 : : default:
6637 : 0 : rValue += rtl::OUString( *pUni );
6638 : 0 : break;
6639 : : }
6640 : : }
6641 : 0 : }
6642 : :
6643 : : // emits the document metadata
6644 : : //
6645 : 0 : sal_Int32 PDFWriterImpl::emitDocumentMetadata()
6646 : : {
6647 [ # # ]: 0 : if( !m_bIsPDF_A1 )
6648 : 0 : return 0;
6649 : :
6650 : : //get the object number for all the destinations
6651 : 0 : sal_Int32 nObject = createObject();
6652 : :
6653 [ # # ]: 0 : if( updateObject( nObject ) )
6654 : : {
6655 : : // the following string are written in UTF-8 unicode
6656 : 0 : OStringBuffer aMetadataStream( 8192 );
6657 : :
6658 [ # # ]: 0 : aMetadataStream.append( "<?xpacket begin=\"" );
6659 : : // this lines writes Unicode “zero width non-breaking space character” (U+FEFF) (aka byte-order mark ) used
6660 : : // as a byte-order marker.
6661 [ # # ][ # # ]: 0 : aMetadataStream.append( OUStringToOString( OUString( sal_Unicode( 0xFEFF ) ), RTL_TEXTENCODING_UTF8 ) );
6662 [ # # ]: 0 : aMetadataStream.append( "\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>\n" );
6663 [ # # ]: 0 : aMetadataStream.append( "<x:xmpmeta xmlns:x=\"adobe:ns:meta/\">\n" );
6664 [ # # ]: 0 : aMetadataStream.append( " <rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n" );
6665 : : //PDF/A part ( ISO 19005-1:2005 - 6.7.11 )
6666 [ # # ]: 0 : aMetadataStream.append( " <rdf:Description rdf:about=\"\"\n" );
6667 [ # # ]: 0 : aMetadataStream.append( " xmlns:pdfaid=\"http://www.aiim.org/pdfa/ns/id/\">\n" );
6668 [ # # ]: 0 : aMetadataStream.append( " <pdfaid:part>1</pdfaid:part>\n" );
6669 [ # # ]: 0 : aMetadataStream.append( " <pdfaid:conformance>A</pdfaid:conformance>\n" );
6670 [ # # ]: 0 : aMetadataStream.append( " </rdf:Description>\n" );
6671 : : //... Dublin Core properties go here
6672 [ # # # # : 0 : if( m_aContext.DocumentInfo.Title.Len() ||
# # ][ # # ]
6673 : 0 : m_aContext.DocumentInfo.Author.Len() ||
6674 : 0 : m_aContext.DocumentInfo.Subject.Len() )
6675 : : {
6676 [ # # ]: 0 : aMetadataStream.append( " <rdf:Description rdf:about=\"\"\n" );
6677 [ # # ]: 0 : aMetadataStream.append( " xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n" );
6678 [ # # ]: 0 : if( m_aContext.DocumentInfo.Title.Len() )
6679 : : {
6680 : : // this is according to PDF/A-1, technical corrigendum 1 (2007-04-01)
6681 [ # # ]: 0 : aMetadataStream.append( " <dc:title>\n" );
6682 [ # # ]: 0 : aMetadataStream.append( " <rdf:Alt>\n" );
6683 [ # # ]: 0 : aMetadataStream.append( " <rdf:li xml:lang=\"x-default\">" );
6684 : 0 : rtl::OUString aTitle;
6685 [ # # ][ # # ]: 0 : escapeStringXML( m_aContext.DocumentInfo.Title, aTitle );
6686 [ # # ][ # # ]: 0 : aMetadataStream.append( OUStringToOString( aTitle, RTL_TEXTENCODING_UTF8 ) );
6687 [ # # ]: 0 : aMetadataStream.append( "</rdf:li>\n" );
6688 [ # # ]: 0 : aMetadataStream.append( " </rdf:Alt>\n" );
6689 [ # # ]: 0 : aMetadataStream.append( " </dc:title>\n" );
6690 : : }
6691 [ # # ]: 0 : if( m_aContext.DocumentInfo.Author.Len() )
6692 : : {
6693 [ # # ]: 0 : aMetadataStream.append( " <dc:creator>\n" );
6694 [ # # ]: 0 : aMetadataStream.append( " <rdf:Seq>\n" );
6695 [ # # ]: 0 : aMetadataStream.append( " <rdf:li>" );
6696 : 0 : rtl::OUString aAuthor;
6697 [ # # ][ # # ]: 0 : escapeStringXML( m_aContext.DocumentInfo.Author, aAuthor );
6698 [ # # ][ # # ]: 0 : aMetadataStream.append( OUStringToOString( aAuthor , RTL_TEXTENCODING_UTF8 ) );
6699 [ # # ]: 0 : aMetadataStream.append( "</rdf:li>\n" );
6700 [ # # ]: 0 : aMetadataStream.append( " </rdf:Seq>\n" );
6701 [ # # ]: 0 : aMetadataStream.append( " </dc:creator>\n" );
6702 : : }
6703 [ # # ]: 0 : if( m_aContext.DocumentInfo.Subject.Len() )
6704 : : {
6705 : : // this is according to PDF/A-1, technical corrigendum 1 (2007-04-01)
6706 [ # # ]: 0 : aMetadataStream.append( " <dc:description>\n" );
6707 [ # # ]: 0 : aMetadataStream.append( " <rdf:Alt>\n" );
6708 [ # # ]: 0 : aMetadataStream.append( " <rdf:li xml:lang=\"x-default\">" );
6709 : 0 : rtl::OUString aSubject;
6710 [ # # ][ # # ]: 0 : escapeStringXML( m_aContext.DocumentInfo.Subject, aSubject );
6711 [ # # ][ # # ]: 0 : aMetadataStream.append( OUStringToOString( aSubject , RTL_TEXTENCODING_UTF8 ) );
6712 [ # # ]: 0 : aMetadataStream.append( "</rdf:li>\n" );
6713 [ # # ]: 0 : aMetadataStream.append( " </rdf:Alt>\n" );
6714 [ # # ]: 0 : aMetadataStream.append( " </dc:description>\n" );
6715 : : }
6716 [ # # ]: 0 : aMetadataStream.append( " </rdf:Description>\n" );
6717 : : }
6718 : :
6719 : : //... PDF properties go here
6720 [ # # # # ]: 0 : if( m_aContext.DocumentInfo.Producer.Len() ||
[ # # ]
6721 : 0 : m_aContext.DocumentInfo.Keywords.Len() )
6722 : : {
6723 [ # # ]: 0 : aMetadataStream.append( " <rdf:Description rdf:about=\"\"\n" );
6724 [ # # ]: 0 : aMetadataStream.append( " xmlns:pdf=\"http://ns.adobe.com/pdf/1.3/\">\n" );
6725 [ # # ]: 0 : if( m_aContext.DocumentInfo.Producer.Len() )
6726 : : {
6727 [ # # ]: 0 : aMetadataStream.append( " <pdf:Producer>" );
6728 : 0 : rtl::OUString aProducer;
6729 [ # # ][ # # ]: 0 : escapeStringXML( m_aContext.DocumentInfo.Producer, aProducer );
6730 [ # # ][ # # ]: 0 : aMetadataStream.append( OUStringToOString( aProducer , RTL_TEXTENCODING_UTF8 ) );
6731 [ # # ]: 0 : aMetadataStream.append( "</pdf:Producer>\n" );
6732 : : }
6733 [ # # ]: 0 : if( m_aContext.DocumentInfo.Keywords.Len() )
6734 : : {
6735 [ # # ]: 0 : aMetadataStream.append( " <pdf:Keywords>" );
6736 : 0 : rtl::OUString aKeywords;
6737 [ # # ][ # # ]: 0 : escapeStringXML( m_aContext.DocumentInfo.Keywords, aKeywords );
6738 [ # # ][ # # ]: 0 : aMetadataStream.append( OUStringToOString( aKeywords , RTL_TEXTENCODING_UTF8 ) );
6739 [ # # ]: 0 : aMetadataStream.append( "</pdf:Keywords>\n" );
6740 : : }
6741 [ # # ]: 0 : aMetadataStream.append( " </rdf:Description>\n" );
6742 : : }
6743 : :
6744 [ # # ]: 0 : aMetadataStream.append( " <rdf:Description rdf:about=\"\"\n" );
6745 [ # # ]: 0 : aMetadataStream.append( " xmlns:xmp=\"http://ns.adobe.com/xap/1.0/\">\n" );
6746 [ # # ]: 0 : if( m_aContext.DocumentInfo.Creator.Len() )
6747 : : {
6748 [ # # ]: 0 : aMetadataStream.append( " <xmp:CreatorTool>" );
6749 : 0 : rtl::OUString aCreator;
6750 [ # # ][ # # ]: 0 : escapeStringXML( m_aContext.DocumentInfo.Creator, aCreator );
6751 [ # # ][ # # ]: 0 : aMetadataStream.append( OUStringToOString( aCreator , RTL_TEXTENCODING_UTF8 ) );
6752 [ # # ]: 0 : aMetadataStream.append( "</xmp:CreatorTool>\n" );
6753 : : }
6754 : : //creation date
6755 [ # # ]: 0 : aMetadataStream.append( " <xmp:CreateDate>" );
6756 [ # # ]: 0 : aMetadataStream.append( m_aCreationMetaDateString );
6757 [ # # ]: 0 : aMetadataStream.append( "</xmp:CreateDate>\n" );
6758 : :
6759 [ # # ]: 0 : aMetadataStream.append( " </rdf:Description>\n" );
6760 [ # # ]: 0 : aMetadataStream.append( " </rdf:RDF>\n" );
6761 [ # # ]: 0 : aMetadataStream.append( "</x:xmpmeta>\n" );
6762 : :
6763 : : //add the padding
6764 [ # # ]: 0 : for( sal_Int32 nSpaces = 1; nSpaces <= 2100; nSpaces++ )
6765 : : {
6766 [ # # ]: 0 : aMetadataStream.append( " " );
6767 [ # # ]: 0 : if( nSpaces % 100 == 0 )
6768 [ # # ]: 0 : aMetadataStream.append( "\n" );
6769 : : }
6770 : :
6771 [ # # ]: 0 : aMetadataStream.append( "<?xpacket end=\"w\"?>\n" );
6772 : :
6773 : 0 : OStringBuffer aMetadataObj( 1024 );
6774 : :
6775 [ # # ]: 0 : aMetadataObj.append( nObject );
6776 [ # # ]: 0 : aMetadataObj.append( " 0 obj\n" );
6777 : :
6778 [ # # ]: 0 : aMetadataObj.append( "<</Type/Metadata/Subtype/XML/Length " );
6779 : :
6780 [ # # ]: 0 : aMetadataObj.append( (sal_Int32) aMetadataStream.getLength() );
6781 [ # # ]: 0 : aMetadataObj.append( ">>\nstream\n" );
6782 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aMetadataObj.getStr(), aMetadataObj.getLength() ) );
6783 : : //emit the stream
6784 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aMetadataStream.getStr(), aMetadataStream.getLength() ) );
6785 : :
6786 [ # # ]: 0 : aMetadataObj.setLength( 0 );
6787 [ # # ]: 0 : aMetadataObj.append( "\nendstream\nendobj\n\n" );
6788 [ # # ][ # # ]: 0 : if( ! writeBuffer( aMetadataObj.getStr(), aMetadataObj.getLength() ) )
6789 [ # # ][ # # ]: 0 : nObject = 0;
6790 : : }
6791 : : else
6792 : 0 : nObject = 0;
6793 : :
6794 : 0 : return nObject;
6795 : : }
6796 : : //<---i59651
6797 : :
6798 : 0 : bool PDFWriterImpl::emitTrailer()
6799 : : {
6800 : : // emit doc info
6801 : 0 : OString aInfoValuesOut;
6802 [ # # ]: 0 : sal_Int32 nDocInfoObject = emitInfoDict( );
6803 : :
6804 : 0 : sal_Int32 nSecObject = 0;
6805 : :
6806 [ # # ]: 0 : if( m_aContext.Encryption.Encrypt() )
6807 : : {
6808 : : //emit the security information
6809 : : //must be emitted as indirect dictionary object, since
6810 : : //Acrobat Reader 5 works only with this kind of implementation
6811 [ # # ]: 0 : nSecObject = createObject();
6812 : :
6813 [ # # ][ # # ]: 0 : if( updateObject( nSecObject ) )
6814 : : {
6815 : 0 : OStringBuffer aLineS( 1024 );
6816 [ # # ]: 0 : aLineS.append( nSecObject );
6817 : : aLineS.append( " 0 obj\n"
6818 [ # # ]: 0 : "<</Filter/Standard/V " );
6819 : : // check the version
6820 [ # # ]: 0 : if( m_aContext.Encryption.Security128bit )
6821 [ # # ]: 0 : aLineS.append( "2/Length 128/R 3" );
6822 : : else
6823 [ # # ]: 0 : aLineS.append( "1/R 2" );
6824 : :
6825 : : // emit the owner password, must not be encrypted
6826 [ # # ]: 0 : aLineS.append( "/O(" );
6827 [ # # ][ # # ]: 0 : appendLiteralString( (const sal_Char*)&m_aContext.Encryption.OValue[0], sal_Int32(m_aContext.Encryption.OValue.size()), aLineS );
6828 [ # # ]: 0 : aLineS.append( ")/U(" );
6829 [ # # ][ # # ]: 0 : appendLiteralString( (const sal_Char*)&m_aContext.Encryption.UValue[0], sal_Int32(m_aContext.Encryption.UValue.size()), aLineS );
6830 [ # # ]: 0 : aLineS.append( ")/P " );// the permission set
6831 [ # # ]: 0 : aLineS.append( m_nAccessPermissions );
6832 [ # # ]: 0 : aLineS.append( ">>\nendobj\n\n" );
6833 [ # # ][ # # ]: 0 : if( !writeBuffer( aLineS.getStr(), aLineS.getLength() ) )
6834 : 0 : nSecObject = 0;
6835 : : }
6836 : : else
6837 : 0 : nSecObject = 0;
6838 : : }
6839 : : // emit xref table
6840 : : // remember start
6841 : 0 : sal_uInt64 nXRefOffset = 0;
6842 [ # # ][ # # ]: 0 : CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nXRefOffset )) );
6843 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( "xref\n", 5 ) );
6844 : :
6845 : 0 : sal_Int32 nObjects = m_aObjects.size();
6846 : 0 : OStringBuffer aLine;
6847 [ # # ]: 0 : aLine.append( "0 " );
6848 [ # # ]: 0 : aLine.append( (sal_Int32)(nObjects+1) );
6849 [ # # ]: 0 : aLine.append( "\n" );
6850 [ # # ]: 0 : aLine.append( "0000000000 65535 f \n" );
6851 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
6852 : :
6853 [ # # ]: 0 : for( sal_Int32 i = 0; i < nObjects; i++ )
6854 : : {
6855 [ # # ]: 0 : aLine.setLength( 0 );
6856 [ # # ]: 0 : OString aOffset = OString::valueOf( (sal_Int64)m_aObjects[i] );
6857 [ # # ]: 0 : for( sal_Int32 j = 0; j < (10-aOffset.getLength()); j++ )
6858 [ # # ]: 0 : aLine.append( '0' );
6859 [ # # ]: 0 : aLine.append( aOffset );
6860 [ # # ]: 0 : aLine.append( " 00000 n \n" );
6861 : : DBG_ASSERT( aLine.getLength() == 20, "invalid xref entry" );
6862 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
6863 [ # # ]: 0 : }
6864 : :
6865 : : // prepare document checksum
6866 : 0 : OStringBuffer aDocChecksum( 2*RTL_DIGEST_LENGTH_MD5+1 );
6867 [ # # ]: 0 : if( m_aDocDigest )
6868 : : {
6869 : : sal_uInt8 nMD5Sum[ RTL_DIGEST_LENGTH_MD5 ];
6870 : 0 : rtl_digest_getMD5( m_aDocDigest, nMD5Sum, sizeof(nMD5Sum) );
6871 [ # # ]: 0 : for( unsigned int i = 0; i < RTL_DIGEST_LENGTH_MD5; i++ )
6872 [ # # ]: 0 : appendHex( nMD5Sum[i], aDocChecksum );
6873 : : }
6874 : : // document id set in setDocInfo method
6875 : : // emit trailer
6876 [ # # ]: 0 : aLine.setLength( 0 );
6877 : : aLine.append( "trailer\n"
6878 [ # # ]: 0 : "<</Size " );
6879 [ # # ]: 0 : aLine.append( (sal_Int32)(nObjects+1) );
6880 [ # # ]: 0 : aLine.append( "/Root " );
6881 [ # # ]: 0 : aLine.append( m_nCatalogObject );
6882 [ # # ]: 0 : aLine.append( " 0 R\n" );
6883 [ # # ]: 0 : if( nSecObject )
6884 : : {
6885 [ # # ]: 0 : aLine.append( "/Encrypt ");
6886 [ # # ]: 0 : aLine.append( nSecObject );
6887 [ # # ]: 0 : aLine.append( " 0 R\n" );
6888 : : }
6889 [ # # ]: 0 : if( nDocInfoObject )
6890 : : {
6891 [ # # ]: 0 : aLine.append( "/Info " );
6892 [ # # ]: 0 : aLine.append( nDocInfoObject );
6893 [ # # ]: 0 : aLine.append( " 0 R\n" );
6894 : : }
6895 [ # # ]: 0 : if( ! m_aContext.Encryption.DocumentIdentifier.empty() )
6896 : : {
6897 [ # # ]: 0 : aLine.append( "/ID [ <" );
6898 [ # # ]: 0 : for( std::vector< sal_uInt8 >::const_iterator it = m_aContext.Encryption.DocumentIdentifier.begin();
[ # # # # ]
[ # # ]
6899 : 0 : it != m_aContext.Encryption.DocumentIdentifier.end(); ++it )
6900 : : {
6901 [ # # ][ # # ]: 0 : appendHex( sal_Int8(*it), aLine );
6902 : : }
6903 : : aLine.append( ">\n"
6904 [ # # ]: 0 : "<" );
6905 [ # # ]: 0 : for( std::vector< sal_uInt8 >::const_iterator it = m_aContext.Encryption.DocumentIdentifier.begin();
[ # # # # ]
[ # # ]
6906 : 0 : it != m_aContext.Encryption.DocumentIdentifier.end(); ++it )
6907 : : {
6908 [ # # ][ # # ]: 0 : appendHex( sal_Int8(*it), aLine );
6909 : : }
6910 [ # # ]: 0 : aLine.append( "> ]\n" );
6911 : : }
6912 [ # # ]: 0 : if( aDocChecksum.getLength() )
6913 : : {
6914 [ # # ]: 0 : aLine.append( "/DocChecksum /" );
6915 [ # # ]: 0 : aLine.append( aDocChecksum.makeStringAndClear() );
6916 [ # # ]: 0 : aLine.append( "\n" );
6917 : : }
6918 [ # # ]: 0 : if( m_aAdditionalStreams.size() > 0 )
6919 : : {
6920 [ # # ]: 0 : aLine.append( "/AdditionalStreams [" );
6921 [ # # ]: 0 : for( unsigned int i = 0; i < m_aAdditionalStreams.size(); i++ )
6922 : : {
6923 [ # # ]: 0 : aLine.append( "/" );
6924 [ # # ]: 0 : appendName( m_aAdditionalStreams[i].m_aMimeType, aLine );
6925 [ # # ]: 0 : aLine.append( " " );
6926 [ # # ]: 0 : aLine.append( m_aAdditionalStreams[i].m_nStreamObject );
6927 [ # # ]: 0 : aLine.append( " 0 R\n" );
6928 : : }
6929 [ # # ]: 0 : aLine.append( "]\n" );
6930 : : }
6931 : : aLine.append( ">>\n"
6932 [ # # ]: 0 : "startxref\n" );
6933 [ # # ]: 0 : aLine.append( (sal_Int64)nXRefOffset );
6934 : : aLine.append( "\n"
6935 [ # # ]: 0 : "%%EOF\n" );
6936 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
6937 : :
6938 : 0 : return true;
6939 : : }
6940 : :
6941 : : struct AnnotationSortEntry
6942 : : {
6943 : : sal_Int32 nTabOrder;
6944 : : sal_Int32 nObject;
6945 : : sal_Int32 nWidgetIndex;
6946 : :
6947 : 0 : AnnotationSortEntry( sal_Int32 nTab, sal_Int32 nObj, sal_Int32 nI ) :
6948 : : nTabOrder( nTab ),
6949 : : nObject( nObj ),
6950 : 0 : nWidgetIndex( nI )
6951 : 0 : {}
6952 : : };
6953 : :
6954 [ # # ]: 0 : struct AnnotSortContainer
6955 : : {
6956 : : std::set< sal_Int32 > aObjects;
6957 : : std::vector< AnnotationSortEntry > aSortedAnnots;
6958 : : };
6959 : :
6960 : : struct AnnotSorterLess
6961 : : {
6962 : : std::vector< PDFWriterImpl::PDFWidget >& m_rWidgets;
6963 : :
6964 : 0 : AnnotSorterLess( std::vector< PDFWriterImpl::PDFWidget >& rWidgets ) : m_rWidgets( rWidgets ) {}
6965 : :
6966 : 0 : bool operator()( const AnnotationSortEntry& rLeft, const AnnotationSortEntry& rRight )
6967 : : {
6968 [ # # ]: 0 : if( rLeft.nTabOrder < rRight.nTabOrder )
6969 : 0 : return true;
6970 [ # # ]: 0 : if( rRight.nTabOrder < rLeft.nTabOrder )
6971 : 0 : return false;
6972 [ # # ][ # # ]: 0 : if( rLeft.nWidgetIndex < 0 && rRight.nWidgetIndex < 0 )
6973 : 0 : return false;
6974 [ # # ]: 0 : if( rRight.nWidgetIndex < 0 )
6975 : 0 : return true;
6976 [ # # ]: 0 : if( rLeft.nWidgetIndex < 0 )
6977 : 0 : return false;
6978 : : // remember: widget rects are in PDF coordinates, so they are ordered down up
6979 [ # # ]: 0 : if( m_rWidgets[ rLeft.nWidgetIndex ].m_aRect.Top() >
6980 : 0 : m_rWidgets[ rRight.nWidgetIndex ].m_aRect.Top() )
6981 : 0 : return true;
6982 [ # # ]: 0 : if( m_rWidgets[ rRight.nWidgetIndex ].m_aRect.Top() >
6983 : 0 : m_rWidgets[ rLeft.nWidgetIndex ].m_aRect.Top() )
6984 : 0 : return false;
6985 [ # # ]: 0 : if( m_rWidgets[ rLeft.nWidgetIndex ].m_aRect.Left() <
6986 : 0 : m_rWidgets[ rRight.nWidgetIndex ].m_aRect.Left() )
6987 : 0 : return true;
6988 : 0 : return false;
6989 : : }
6990 : : };
6991 : :
6992 : 0 : void PDFWriterImpl::sortWidgets()
6993 : : {
6994 : : // sort widget annotations on each page as per their
6995 : : // TabOrder attribute
6996 [ # # ]: 0 : boost::unordered_map< sal_Int32, AnnotSortContainer > sorted;
6997 : 0 : int nWidgets = m_aWidgets.size();
6998 [ # # ]: 0 : for( int nW = 0; nW < nWidgets; nW++ )
6999 : : {
7000 : 0 : const PDFWidget& rWidget = m_aWidgets[nW];
7001 [ # # ]: 0 : if( rWidget.m_nPage >= 0 )
7002 : : {
7003 [ # # ]: 0 : AnnotSortContainer& rCont = sorted[ rWidget.m_nPage ];
7004 : : // optimize vector allocation
7005 [ # # ]: 0 : if( rCont.aSortedAnnots.empty() )
7006 [ # # ]: 0 : rCont.aSortedAnnots.reserve( m_aPages[ rWidget.m_nPage ].m_aAnnotations.size() );
7007 : : // insert widget to tab sorter
7008 : : // RadioButtons are not page annotations, only their individual check boxes are
7009 [ # # ]: 0 : if( rWidget.m_eType != PDFWriter::RadioButton )
7010 : : {
7011 [ # # ]: 0 : rCont.aObjects.insert( rWidget.m_nObject );
7012 [ # # ]: 0 : rCont.aSortedAnnots.push_back( AnnotationSortEntry( rWidget.m_nTabOrder, rWidget.m_nObject, nW ) );
7013 : : }
7014 : : }
7015 : : }
7016 [ # # ][ # # ]: 0 : for( boost::unordered_map< sal_Int32, AnnotSortContainer >::iterator it = sorted.begin(); it != sorted.end(); ++it )
[ # # ]
7017 : : {
7018 : : // append entries for non widget annotations
7019 [ # # ]: 0 : PDFPage& rPage = m_aPages[ it->first ];
7020 : 0 : unsigned int nAnnots = rPage.m_aAnnotations.size();
7021 [ # # ]: 0 : for( unsigned int nA = 0; nA < nAnnots; nA++ )
7022 [ # # ][ # # ]: 0 : if( it->second.aObjects.find( rPage.m_aAnnotations[nA] ) == it->second.aObjects.end())
[ # # ][ # # ]
[ # # ][ # # ]
7023 [ # # ][ # # ]: 0 : it->second.aSortedAnnots.push_back( AnnotationSortEntry( 10000, rPage.m_aAnnotations[nA], -1 ) );
[ # # ]
7024 : :
7025 : 0 : AnnotSorterLess aLess( m_aWidgets );
7026 [ # # ][ # # ]: 0 : std::stable_sort( it->second.aSortedAnnots.begin(), it->second.aSortedAnnots.end(), aLess );
[ # # ]
7027 : : // sanity check
7028 [ # # ][ # # ]: 0 : if( it->second.aSortedAnnots.size() == nAnnots)
7029 : : {
7030 [ # # ]: 0 : for( unsigned int nA = 0; nA < nAnnots; nA++ )
7031 [ # # ][ # # ]: 0 : rPage.m_aAnnotations[nA] = it->second.aSortedAnnots[nA].nObject;
7032 : : }
7033 : : else
7034 : : {
7035 : : DBG_ASSERT( 0, "wrong number of sorted annotations" );
7036 : : #if OSL_DEBUG_LEVEL > 0
7037 : : fprintf( stderr, "PDFWriterImpl::sortWidgets(): wrong number of sorted assertions on page nr %ld\n"
7038 : : " %ld sorted and %ld unsorted\n", (long int)it->first, (long int)it->second.aSortedAnnots.size(), (long int)nAnnots );
7039 : : #endif
7040 : : }
7041 [ # # ]: 0 : }
7042 : :
7043 : : // FIXME: implement tab order in structure tree for PDF 1.5
7044 : 0 : }
7045 : :
7046 : : namespace vcl {
7047 : : class PDFStreamIf :
7048 : : public cppu::WeakImplHelper1< com::sun::star::io::XOutputStream >
7049 : : {
7050 : : PDFWriterImpl* m_pWriter;
7051 : : bool m_bWrite;
7052 : : public:
7053 : 0 : PDFStreamIf( PDFWriterImpl* pWriter ) : m_pWriter( pWriter ), m_bWrite( true ) {}
7054 : : virtual ~PDFStreamIf();
7055 : :
7056 : : virtual void SAL_CALL writeBytes( const com::sun::star::uno::Sequence< sal_Int8 >& aData ) throw();
7057 : : virtual void SAL_CALL flush() throw();
7058 : : virtual void SAL_CALL closeOutput() throw();
7059 : : };
7060 : : }
7061 : :
7062 : 0 : PDFStreamIf::~PDFStreamIf()
7063 : : {
7064 [ # # ]: 0 : }
7065 : :
7066 : 0 : void SAL_CALL PDFStreamIf::writeBytes( const com::sun::star::uno::Sequence< sal_Int8 >& aData ) throw()
7067 : : {
7068 [ # # ][ # # ]: 0 : if( m_bWrite && aData.getLength() )
[ # # ]
7069 : : {
7070 : 0 : sal_Int32 nBytes = aData.getLength();
7071 : 0 : m_pWriter->writeBuffer( aData.getConstArray(), nBytes );
7072 : : }
7073 : 0 : }
7074 : :
7075 : 0 : void SAL_CALL PDFStreamIf::flush() throw()
7076 : : {
7077 : 0 : }
7078 : :
7079 : 0 : void SAL_CALL PDFStreamIf::closeOutput() throw()
7080 : : {
7081 : 0 : m_bWrite = false;
7082 : 0 : }
7083 : :
7084 : 0 : bool PDFWriterImpl::emitAdditionalStreams()
7085 : : {
7086 : 0 : unsigned int nStreams = m_aAdditionalStreams.size();
7087 [ # # ]: 0 : for( unsigned int i = 0; i < nStreams; i++ )
7088 : : {
7089 : 0 : PDFAddStream& rStream = m_aAdditionalStreams[i];
7090 [ # # ]: 0 : rStream.m_nStreamObject = createObject();
7091 [ # # ]: 0 : sal_Int32 nSizeObject = createObject();
7092 : :
7093 [ # # ][ # # ]: 0 : if( ! updateObject( rStream.m_nStreamObject ) )
7094 : 0 : return false;
7095 : :
7096 : 0 : OStringBuffer aLine;
7097 [ # # ]: 0 : aLine.append( rStream.m_nStreamObject );
7098 [ # # ]: 0 : aLine.append( " 0 obj\n<</Length " );
7099 [ # # ]: 0 : aLine.append( nSizeObject );
7100 [ # # ]: 0 : aLine.append( " 0 R" );
7101 [ # # ]: 0 : if( rStream.m_bCompress )
7102 [ # # ]: 0 : aLine.append( "/Filter/FlateDecode" );
7103 [ # # ]: 0 : aLine.append( ">>\nstream\n" );
7104 [ # # ][ # # ]: 0 : if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) )
7105 : 0 : return false;
7106 : 0 : sal_uInt64 nBeginStreamPos = 0, nEndStreamPos = 0;
7107 [ # # ][ # # ]: 0 : if( osl_File_E_None != osl_getFilePos( m_aFile, &nBeginStreamPos ) )
7108 : : {
7109 [ # # ]: 0 : osl_closeFile( m_aFile );
7110 : 0 : m_bOpen = false;
7111 : : }
7112 [ # # ]: 0 : if( rStream.m_bCompress )
7113 [ # # ]: 0 : beginCompression();
7114 : :
7115 [ # # ]: 0 : checkAndEnableStreamEncryption( rStream.m_nStreamObject );
7116 [ # # ][ # # ]: 0 : com::sun::star::uno::Reference< com::sun::star::io::XOutputStream > xStream( new PDFStreamIf( this ) );
[ # # ]
7117 [ # # ]: 0 : rStream.m_pStream->write( xStream );
7118 : 0 : xStream.clear();
7119 [ # # ][ # # ]: 0 : delete rStream.m_pStream;
7120 : 0 : rStream.m_pStream = NULL;
7121 : 0 : disableStreamEncryption();
7122 : :
7123 [ # # ]: 0 : if( rStream.m_bCompress )
7124 [ # # ]: 0 : endCompression();
7125 : :
7126 [ # # ][ # # ]: 0 : if( osl_File_E_None != osl_getFilePos( m_aFile, &nEndStreamPos ) )
7127 : : {
7128 [ # # ]: 0 : osl_closeFile( m_aFile );
7129 : 0 : m_bOpen = false;
7130 : 0 : return false;
7131 : : }
7132 [ # # ][ # # ]: 0 : if( ! writeBuffer( "\nendstream\nendobj\n\n", 19 ) )
7133 : 0 : return false ;
7134 : : // emit stream length object
7135 [ # # ][ # # ]: 0 : if( ! updateObject( nSizeObject ) )
7136 : 0 : return false;
7137 [ # # ]: 0 : aLine.setLength( 0 );
7138 [ # # ]: 0 : aLine.append( nSizeObject );
7139 [ # # ]: 0 : aLine.append( " 0 obj\n" );
7140 [ # # ]: 0 : aLine.append( (sal_Int64)(nEndStreamPos-nBeginStreamPos) );
7141 [ # # ]: 0 : aLine.append( "\nendobj\n\n" );
7142 [ # # ][ # # ]: 0 : if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) )
7143 : 0 : return false;
7144 [ # # ][ # # ]: 0 : }
7145 : 0 : return true;
7146 : : }
7147 : :
7148 : 0 : bool PDFWriterImpl::emit()
7149 : : {
7150 : 0 : endPage();
7151 : :
7152 : : // resort structure tree and annotations if necessary
7153 : : // needed for widget tab order
7154 : 0 : sortWidgets();
7155 : :
7156 : : #if !defined(ANDROID) && !defined(IOS)
7157 [ # # ]: 0 : if( m_aContext.SignPDF )
7158 : : {
7159 : : // sign the document
7160 [ # # ]: 0 : PDFWriter::SignatureWidget aSignature;
7161 : 0 : aSignature.Name = OUString("Signature1");
7162 [ # # ][ # # ]: 0 : createControl( aSignature, 0 );
7163 : : }
7164 : : #endif
7165 : :
7166 : : // emit additional streams
7167 [ # # ]: 0 : CHECK_RETURN( emitAdditionalStreams() );
7168 : :
7169 : : // emit catalog
7170 [ # # ]: 0 : CHECK_RETURN( emitCatalog() );
7171 : :
7172 : : #if !defined(ANDROID) && !defined(IOS)
7173 [ # # ]: 0 : if (m_nSignatureObject != -1) // if document is signed, emit sigdict
7174 [ # # ]: 0 : CHECK_RETURN( emitSignature() );
7175 : : #endif
7176 : :
7177 : : // emit trailer
7178 [ # # ]: 0 : CHECK_RETURN( emitTrailer() );
7179 : :
7180 : : #if !defined(ANDROID) && !defined(IOS)
7181 [ # # ]: 0 : if (m_nSignatureObject != -1) // finalize the signature
7182 [ # # ]: 0 : CHECK_RETURN( finalizeSignature() );
7183 : : #endif
7184 : :
7185 : 0 : osl_closeFile( m_aFile );
7186 : 0 : m_bOpen = false;
7187 : :
7188 : 0 : return true;
7189 : : }
7190 : :
7191 : 0 : std::set< PDFWriter::ErrorCode > PDFWriterImpl::getErrors()
7192 : : {
7193 : 0 : return m_aErrors;
7194 : : }
7195 : :
7196 : 0 : sal_Int32 PDFWriterImpl::getSystemFont( const Font& i_rFont )
7197 : : {
7198 [ # # ][ # # ]: 0 : getReferenceDevice()->Push();
7199 [ # # ][ # # ]: 0 : getReferenceDevice()->SetFont( i_rFont );
7200 [ # # ][ # # ]: 0 : getReferenceDevice()->ImplNewFont();
7201 : :
7202 : 0 : const PhysicalFontFace* pDevFont = m_pReferenceDevice->mpFontEntry->maFontSelData.mpFontData;
7203 : 0 : sal_Int32 nFontID = 0;
7204 [ # # ]: 0 : FontEmbedData::iterator it = m_aSystemFonts.find( pDevFont );
7205 [ # # ]: 0 : if( it != m_aSystemFonts.end() )
7206 : 0 : nFontID = it->second.m_nNormalFontID;
7207 : : else
7208 : : {
7209 : 0 : nFontID = m_nNextFID++;
7210 [ # # ][ # # ]: 0 : m_aSystemFonts[ pDevFont ] = EmbedFont();
[ # # ]
7211 [ # # ]: 0 : m_aSystemFonts[ pDevFont ].m_nNormalFontID = nFontID;
7212 : : }
7213 : :
7214 [ # # ][ # # ]: 0 : getReferenceDevice()->Pop();
7215 [ # # ][ # # ]: 0 : getReferenceDevice()->ImplNewFont();
7216 : :
7217 : 0 : return nFontID;
7218 : : }
7219 : :
7220 : 0 : void PDFWriterImpl::registerGlyphs( int nGlyphs,
7221 : : sal_GlyphId* pGlyphs,
7222 : : sal_Int32* pGlyphWidths,
7223 : : sal_Ucs* pUnicodes,
7224 : : sal_Int32* pUnicodesPerGlyph,
7225 : : sal_uInt8* pMappedGlyphs,
7226 : : sal_Int32* pMappedFontObjects,
7227 : : const PhysicalFontFace* pFallbackFonts[] )
7228 : : {
7229 : 0 : const PhysicalFontFace* pDevFont = m_pReferenceDevice->mpFontEntry->maFontSelData.mpFontData;
7230 : 0 : sal_Ucs* pCurUnicode = pUnicodes;
7231 [ # # ]: 0 : for( int i = 0; i < nGlyphs; pCurUnicode += pUnicodesPerGlyph[i] , i++ )
7232 : : {
7233 : 0 : const int nFontGlyphId = pGlyphs[i] & (GF_IDXMASK | GF_ISCHAR | GF_GSUB);
7234 [ # # ]: 0 : const PhysicalFontFace* pCurrentFont = pFallbackFonts[i] ? pFallbackFonts[i] : pDevFont;
7235 : :
7236 [ # # ]: 0 : if( isBuiltinFont( pCurrentFont ) )
7237 : : {
7238 : 0 : sal_Int32 nFontID = 0;
7239 [ # # ]: 0 : FontEmbedData::iterator it = m_aEmbeddedFonts.find( pCurrentFont );
7240 [ # # ]: 0 : if( it != m_aEmbeddedFonts.end() )
7241 : 0 : nFontID = it->second.m_nNormalFontID;
7242 : : else
7243 : : {
7244 : 0 : nFontID = m_nNextFID++;
7245 [ # # ][ # # ]: 0 : m_aEmbeddedFonts[ pCurrentFont ] = EmbedFont();
[ # # ]
7246 [ # # ]: 0 : m_aEmbeddedFonts[ pCurrentFont ].m_nNormalFontID = nFontID;
7247 : : }
7248 : :
7249 : 0 : pGlyphWidths[ i ] = 0;
7250 : 0 : pMappedGlyphs[ i ] = sal::static_int_cast<sal_Int8>( nFontGlyphId );
7251 : 0 : pMappedFontObjects[ i ] = nFontID;
7252 : 0 : const ImplPdfBuiltinFontData* pFD = GetPdfFontData( pCurrentFont );
7253 [ # # ]: 0 : if( pFD )
7254 : : {
7255 : 0 : const BuiltinFont* pBuiltinFont = pFD->GetBuiltinFont();
7256 : 0 : pGlyphWidths[i] = pBuiltinFont->m_aWidths[ nFontGlyphId & 0x00ff ];
7257 : : }
7258 : : }
7259 [ # # ]: 0 : else if( pCurrentFont->mbSubsettable )
7260 : : {
7261 [ # # ]: 0 : FontSubset& rSubset = m_aSubsets[ pCurrentFont ];
7262 : : // search for font specific glyphID
7263 [ # # ]: 0 : FontMapping::iterator it = rSubset.m_aMapping.find( nFontGlyphId );
7264 [ # # ]: 0 : if( it != rSubset.m_aMapping.end() )
7265 : : {
7266 : 0 : pMappedFontObjects[i] = it->second.m_nFontID;
7267 : 0 : pMappedGlyphs[i] = it->second.m_nSubsetGlyphID;
7268 : : }
7269 : : else
7270 : : {
7271 : : // create new subset if necessary
7272 [ # # # # ]: 0 : if( rSubset.m_aSubsets.empty()
[ # # ]
7273 [ # # ]: 0 : || (rSubset.m_aSubsets.back().m_aMapping.size() > 254) )
7274 : : {
7275 [ # # ][ # # ]: 0 : rSubset.m_aSubsets.push_back( FontEmit( m_nNextFID++ ) );
7276 : : }
7277 : :
7278 : : // copy font id
7279 [ # # ]: 0 : pMappedFontObjects[i] = rSubset.m_aSubsets.back().m_nFontID;
7280 : : // create new glyph in subset
7281 [ # # ]: 0 : sal_uInt8 nNewId = sal::static_int_cast<sal_uInt8>(rSubset.m_aSubsets.back().m_aMapping.size()+1);
7282 : 0 : pMappedGlyphs[i] = nNewId;
7283 : :
7284 : : // add new glyph to emitted font subset
7285 [ # # ][ # # ]: 0 : GlyphEmit& rNewGlyphEmit = rSubset.m_aSubsets.back().m_aMapping[ nFontGlyphId ];
7286 : 0 : rNewGlyphEmit.setGlyphId( nNewId );
7287 [ # # ]: 0 : for( sal_Int32 n = 0; n < pUnicodesPerGlyph[i]; n++ )
7288 [ # # ]: 0 : rNewGlyphEmit.addCode( pCurUnicode[n] );
7289 : :
7290 : : // add new glyph to font mapping
7291 [ # # ]: 0 : Glyph& rNewGlyph = rSubset.m_aMapping[ nFontGlyphId ];
7292 : 0 : rNewGlyph.m_nFontID = pMappedFontObjects[i];
7293 : 0 : rNewGlyph.m_nSubsetGlyphID = nNewId;
7294 : : }
7295 [ # # ][ # # ]: 0 : getReferenceDevice()->ImplGetGraphics();
7296 : 0 : const bool bVertical = ((pGlyphs[i] & GF_ROTMASK) != 0);
7297 : 0 : pGlyphWidths[i] = m_aFontCache.getGlyphWidth( pCurrentFont,
7298 : : nFontGlyphId,
7299 : : bVertical,
7300 [ # # ]: 0 : m_pReferenceDevice->mpGraphics );
7301 : : }
7302 [ # # ]: 0 : else if( pCurrentFont->IsEmbeddable() )
7303 : : {
7304 : 0 : sal_Int32 nFontID = 0;
7305 [ # # ]: 0 : FontEmbedData::iterator it = m_aEmbeddedFonts.find( pCurrentFont );
7306 [ # # ]: 0 : if( it != m_aEmbeddedFonts.end() )
7307 : 0 : nFontID = it->second.m_nNormalFontID;
7308 : : else
7309 : : {
7310 : 0 : nFontID = m_nNextFID++;
7311 [ # # ][ # # ]: 0 : m_aEmbeddedFonts[ pCurrentFont ] = EmbedFont();
[ # # ]
7312 [ # # ]: 0 : m_aEmbeddedFonts[ pCurrentFont ].m_nNormalFontID = nFontID;
7313 : : }
7314 [ # # ]: 0 : EmbedFont& rEmbedFont = m_aEmbeddedFonts[pCurrentFont];
7315 : :
7316 : 0 : const Ucs2SIntMap* pEncoding = NULL;
7317 : 0 : const Ucs2OStrMap* pNonEncoded = NULL;
7318 [ # # ][ # # ]: 0 : getReferenceDevice()->ImplGetGraphics();
7319 [ # # ]: 0 : pEncoding = m_pReferenceDevice->mpGraphics->GetFontEncodingVector( pCurrentFont, &pNonEncoded );
7320 : :
7321 [ # # ]: 0 : Ucs2SIntMap::const_iterator enc_it;
7322 : 0 : Ucs2OStrMap::const_iterator nonenc_it;
7323 : :
7324 : 0 : sal_Int32 nCurFontID = nFontID;
7325 : 0 : sal_Ucs cChar = *pCurUnicode;
7326 [ # # ]: 0 : if( pEncoding )
7327 : : {
7328 [ # # ]: 0 : enc_it = pEncoding->find( cChar );
7329 [ # # ][ # # ]: 0 : if( enc_it != pEncoding->end() && enc_it->second > 0 )
[ # # ][ # # ]
[ # # ]
[ # # # # ]
7330 : : {
7331 : : DBG_ASSERT( (enc_it->second & 0xffffff00) == 0, "Invalid character code" );
7332 [ # # ]: 0 : cChar = (sal_Ucs)enc_it->second;
7333 : : }
7334 [ # # ][ # # ]: 0 : else if( (enc_it == pEncoding->end() || enc_it->second == -1) &&
[ # # ][ # # ]
[ # # # # ]
[ # # ]
[ # # # # ]
7335 : : pNonEncoded &&
7336 [ # # ][ # # ]: 0 : (nonenc_it = pNonEncoded->find( cChar )) != pNonEncoded->end() )
[ # # ]
7337 : : {
7338 : 0 : nCurFontID = 0;
7339 : : // find non encoded glyph
7340 [ # # ]: 0 : for( std::list< EmbedEncoding >::iterator nec_it = rEmbedFont.m_aExtendedEncodings.begin(); nec_it != rEmbedFont.m_aExtendedEncodings.end(); ++nec_it )
7341 : : {
7342 [ # # ][ # # ]: 0 : if( nec_it->m_aCMap.find( cChar ) != nec_it->m_aCMap.end() )
[ # # ]
7343 : : {
7344 : 0 : nCurFontID = nec_it->m_nFontID;
7345 [ # # ]: 0 : cChar = (sal_Ucs)nec_it->m_aCMap[ cChar ];
7346 : 0 : break;
7347 : : }
7348 : : }
7349 [ # # ]: 0 : if( nCurFontID == 0 ) // new nonencoded glyph
7350 : : {
7351 [ # # ][ # # ]: 0 : if( rEmbedFont.m_aExtendedEncodings.empty() || rEmbedFont.m_aExtendedEncodings.back().m_aEncVector.size() == 255 )
[ # # ][ # # ]
7352 : : {
7353 [ # # ][ # # ]: 0 : rEmbedFont.m_aExtendedEncodings.push_back( EmbedEncoding() );
7354 [ # # ]: 0 : rEmbedFont.m_aExtendedEncodings.back().m_nFontID = m_nNextFID++;
7355 : : }
7356 [ # # ]: 0 : EmbedEncoding& rEncoding = rEmbedFont.m_aExtendedEncodings.back();
7357 [ # # ]: 0 : rEncoding.m_aEncVector.push_back( EmbedCode() );
7358 [ # # ]: 0 : rEncoding.m_aEncVector.back().m_aUnicode = cChar;
7359 [ # # ]: 0 : rEncoding.m_aEncVector.back().m_aName = nonenc_it->second;
7360 [ # # ]: 0 : rEncoding.m_aCMap[ cChar ] = (sal_Int8)(rEncoding.m_aEncVector.size()-1);
7361 : 0 : nCurFontID = rEncoding.m_nFontID;
7362 [ # # ]: 0 : cChar = (sal_Ucs)rEncoding.m_aCMap[ cChar ];
7363 : : }
7364 : : }
7365 : : else
7366 : 0 : pEncoding = NULL;
7367 : : }
7368 [ # # ]: 0 : if( ! pEncoding )
7369 : : {
7370 [ # # ]: 0 : if( cChar & 0xff00 )
7371 : : {
7372 : : // some characters can be used by conversion
7373 [ # # ][ # # ]: 0 : if( cChar >= 0xf000 && cChar <= 0xf0ff ) // symbol encoding in private use area
7374 : 0 : cChar -= 0xf000;
7375 : : else
7376 : : {
7377 [ # # ]: 0 : rtl::OString aChar(&cChar, 1, RTL_TEXTENCODING_MS_1252);
7378 : 0 : cChar = ((sal_Ucs)aChar[0]) & 0x00ff;
7379 : : }
7380 : : }
7381 : : }
7382 : :
7383 : 0 : pMappedGlyphs[ i ] = (sal_Int8)cChar;
7384 : 0 : pMappedFontObjects[ i ] = nCurFontID;
7385 : 0 : pGlyphWidths[ i ] = m_aFontCache.getGlyphWidth( pCurrentFont,
7386 : : (pEncoding ? *pCurUnicode : cChar) | GF_ISCHAR,
7387 : : false,
7388 [ # # ][ # # ]: 0 : m_pReferenceDevice->mpGraphics );
7389 : : }
7390 : : }
7391 : 0 : }
7392 : :
7393 : 0 : void PDFWriterImpl::drawRelief( SalLayout& rLayout, const String& rText, bool bTextLines )
7394 : : {
7395 [ # # ]: 0 : push( PUSH_ALL );
7396 : :
7397 [ # # ]: 0 : FontRelief eRelief = m_aCurrentPDFState.m_aFont.GetRelief();
7398 : :
7399 [ # # ]: 0 : Color aTextColor = m_aCurrentPDFState.m_aFont.GetColor();
7400 : 0 : Color aTextLineColor = m_aCurrentPDFState.m_aTextLineColor;
7401 : 0 : Color aOverlineColor = m_aCurrentPDFState.m_aOverlineColor;
7402 : 0 : Color aReliefColor( COL_LIGHTGRAY );
7403 [ # # ]: 0 : if( aTextColor == COL_BLACK )
7404 : 0 : aTextColor = Color( COL_WHITE );
7405 [ # # ]: 0 : if( aTextLineColor == COL_BLACK )
7406 : 0 : aTextLineColor = Color( COL_WHITE );
7407 [ # # ]: 0 : if( aOverlineColor == COL_BLACK )
7408 : 0 : aOverlineColor = Color( COL_WHITE );
7409 [ # # ]: 0 : if( aTextColor == COL_WHITE )
7410 : 0 : aReliefColor = Color( COL_BLACK );
7411 : :
7412 [ # # ]: 0 : Font aSetFont = m_aCurrentPDFState.m_aFont;
7413 [ # # ]: 0 : aSetFont.SetRelief( RELIEF_NONE );
7414 [ # # ]: 0 : aSetFont.SetShadow( sal_False );
7415 : :
7416 [ # # ]: 0 : aSetFont.SetColor( aReliefColor );
7417 [ # # ]: 0 : setTextLineColor( aReliefColor );
7418 [ # # ]: 0 : setOverlineColor( aReliefColor );
7419 [ # # ]: 0 : setFont( aSetFont );
7420 [ # # ]: 0 : long nOff = 1 + getReferenceDevice()->mnDPIX/300;
7421 [ # # ]: 0 : if( eRelief == RELIEF_ENGRAVED )
7422 : 0 : nOff = -nOff;
7423 : :
7424 : 0 : rLayout.DrawOffset() += Point( nOff, nOff );
7425 [ # # ]: 0 : updateGraphicsState();
7426 [ # # ]: 0 : drawLayout( rLayout, rText, bTextLines );
7427 : :
7428 : 0 : rLayout.DrawOffset() -= Point( nOff, nOff );
7429 [ # # ]: 0 : setTextLineColor( aTextLineColor );
7430 [ # # ]: 0 : setOverlineColor( aOverlineColor );
7431 [ # # ]: 0 : aSetFont.SetColor( aTextColor );
7432 [ # # ]: 0 : setFont( aSetFont );
7433 [ # # ]: 0 : updateGraphicsState();
7434 [ # # ]: 0 : drawLayout( rLayout, rText, bTextLines );
7435 : :
7436 : : // clean up the mess
7437 [ # # ][ # # ]: 0 : pop();
7438 : 0 : }
7439 : :
7440 : 0 : void PDFWriterImpl::drawShadow( SalLayout& rLayout, const String& rText, bool bTextLines )
7441 : : {
7442 [ # # ]: 0 : Font aSaveFont = m_aCurrentPDFState.m_aFont;
7443 : 0 : Color aSaveTextLineColor = m_aCurrentPDFState.m_aTextLineColor;
7444 : 0 : Color aSaveOverlineColor = m_aCurrentPDFState.m_aOverlineColor;
7445 : :
7446 : 0 : Font& rFont = m_aCurrentPDFState.m_aFont;
7447 [ # # ][ # # ]: 0 : if( rFont.GetColor() == Color( COL_BLACK ) || rFont.GetColor().GetLuminance() < 8 )
[ # # ][ # # ]
[ # # ][ # # ]
[ # # # # ]
7448 [ # # ]: 0 : rFont.SetColor( Color( COL_LIGHTGRAY ) );
7449 : : else
7450 [ # # ]: 0 : rFont.SetColor( Color( COL_BLACK ) );
7451 [ # # ]: 0 : rFont.SetShadow( sal_False );
7452 [ # # ]: 0 : rFont.SetOutline( sal_False );
7453 [ # # ]: 0 : setFont( rFont );
7454 [ # # ][ # # ]: 0 : setTextLineColor( rFont.GetColor() );
7455 [ # # ][ # # ]: 0 : setOverlineColor( rFont.GetColor() );
7456 [ # # ]: 0 : updateGraphicsState();
7457 : :
7458 : 0 : long nOff = 1 + ((m_pReferenceDevice->mpFontEntry->mnLineHeight-24)/24);
7459 [ # # ][ # # ]: 0 : if( rFont.IsOutline() )
7460 : 0 : nOff++;
7461 : 0 : rLayout.DrawBase() += Point( nOff, nOff );
7462 [ # # ]: 0 : drawLayout( rLayout, rText, bTextLines );
7463 : 0 : rLayout.DrawBase() -= Point( nOff, nOff );
7464 : :
7465 [ # # ]: 0 : setFont( aSaveFont );
7466 [ # # ]: 0 : setTextLineColor( aSaveTextLineColor );
7467 [ # # ]: 0 : setOverlineColor( aSaveOverlineColor );
7468 [ # # ][ # # ]: 0 : updateGraphicsState();
7469 : 0 : }
7470 : :
7471 : 0 : void PDFWriterImpl::drawVerticalGlyphs(
7472 : : const std::vector<PDFWriterImpl::PDFGlyph>& rGlyphs,
7473 : : OStringBuffer& rLine,
7474 : : const Point& rAlignOffset,
7475 : : const Matrix3& rRotScale,
7476 : : double fAngle,
7477 : : double fXScale,
7478 : : double fSkew,
7479 : : sal_Int32 nFontHeight )
7480 : : {
7481 : 0 : long nXOffset = 0;
7482 : 0 : Point aCurPos( rGlyphs[0].m_aPos );
7483 [ # # ]: 0 : aCurPos = m_pReferenceDevice->PixelToLogic( aCurPos );
7484 : 0 : aCurPos += rAlignOffset;
7485 [ # # ]: 0 : for( size_t i = 0; i < rGlyphs.size(); i++ )
7486 : : {
7487 : : // have to emit each glyph on its own
7488 : 0 : double fDeltaAngle = 0.0;
7489 : 0 : double fYScale = 1.0;
7490 : 0 : double fTempXScale = fXScale;
7491 : 0 : double fSkewB = fSkew;
7492 : 0 : double fSkewA = 0.0;
7493 : :
7494 : 0 : Point aDeltaPos;
7495 [ # # ]: 0 : if( ( rGlyphs[i].m_nGlyphId & GF_ROTMASK ) == GF_ROTL )
7496 : : {
7497 : 0 : fDeltaAngle = M_PI/2.0;
7498 [ # # ][ # # ]: 0 : aDeltaPos.X() = m_pReferenceDevice->GetFontMetric().GetAscent();
[ # # ]
7499 [ # # ][ # # ]: 0 : aDeltaPos.Y() = (int)((double)m_pReferenceDevice->GetFontMetric().GetDescent() * fXScale);
[ # # ]
7500 : 0 : fYScale = fXScale;
7501 : 0 : fTempXScale = 1.0;
7502 : 0 : fSkewA = -fSkewB;
7503 : 0 : fSkewB = 0.0;
7504 : : }
7505 [ # # ]: 0 : else if( ( rGlyphs[i].m_nGlyphId & GF_ROTMASK ) == GF_ROTR )
7506 : : {
7507 : 0 : fDeltaAngle = -M_PI/2.0;
7508 [ # # ][ # # ]: 0 : aDeltaPos.X() = (int)((double)m_pReferenceDevice->GetFontMetric().GetDescent()*fXScale);
[ # # ]
7509 [ # # ][ # # ]: 0 : aDeltaPos.Y() = -m_pReferenceDevice->GetFontMetric().GetAscent();
[ # # ]
7510 : 0 : fYScale = fXScale;
7511 : 0 : fTempXScale = 1.0;
7512 : 0 : fSkewA = fSkewB;
7513 : 0 : fSkewB = 0.0;
7514 : : }
7515 [ # # ][ # # ]: 0 : aDeltaPos += (m_pReferenceDevice->PixelToLogic( Point( (int)((double)nXOffset/fXScale), 0 ) ) - m_pReferenceDevice->PixelToLogic( Point() ) );
7516 [ # # ]: 0 : if( i < rGlyphs.size()-1 )
7517 : 0 : nXOffset += rGlyphs[i+1].m_aPos.Y() - rGlyphs[i].m_aPos.Y();
7518 [ # # ]: 0 : if( ! rGlyphs[i].m_nGlyphId )
7519 : 0 : continue;
7520 : :
7521 : 0 : aDeltaPos = rRotScale.transform( aDeltaPos );
7522 : :
7523 : 0 : Matrix3 aMat;
7524 [ # # ][ # # ]: 0 : if( fSkewB != 0.0 || fSkewA != 0.0 )
7525 : 0 : aMat.skew( fSkewA, fSkewB );
7526 : 0 : aMat.scale( fTempXScale, fYScale );
7527 : 0 : aMat.rotate( fAngle+fDeltaAngle );
7528 : 0 : aMat.translate( aCurPos.X()+aDeltaPos.X(), aCurPos.Y()+aDeltaPos.Y() );
7529 [ # # ][ # # ]: 0 : aMat.append( m_aPages.back(), rLine );
7530 [ # # ]: 0 : rLine.append( " Tm" );
7531 [ # # ][ # # ]: 0 : if( i == 0 || rGlyphs[i-1].m_nMappedFontId != rGlyphs[i].m_nMappedFontId )
[ # # ]
7532 : : {
7533 [ # # ]: 0 : rLine.append( " /F" );
7534 [ # # ]: 0 : rLine.append( rGlyphs[i].m_nMappedFontId );
7535 [ # # ]: 0 : rLine.append( ' ' );
7536 [ # # ][ # # ]: 0 : m_aPages.back().appendMappedLength( nFontHeight, rLine, true );
7537 [ # # ]: 0 : rLine.append( " Tf" );
7538 : : }
7539 [ # # ]: 0 : rLine.append( "<" );
7540 [ # # ]: 0 : appendHex( rGlyphs[i].m_nMappedGlyphId, rLine );
7541 [ # # ]: 0 : rLine.append( ">Tj\n" );
7542 : 0 : }
7543 : 0 : }
7544 : :
7545 : 0 : void PDFWriterImpl::drawHorizontalGlyphs(
7546 : : const std::vector<PDFWriterImpl::PDFGlyph>& rGlyphs,
7547 : : OStringBuffer& rLine,
7548 : : const Point& rAlignOffset,
7549 : : double fAngle,
7550 : : double fXScale,
7551 : : double fSkew,
7552 : : sal_Int32 nFontHeight,
7553 : : sal_Int32 nPixelFontHeight
7554 : : )
7555 : : {
7556 : : // horizontal (= normal) case
7557 : :
7558 : : // fill in run end indices
7559 : : // end is marked by index of the first glyph of the next run
7560 : : // a run is marked by same mapped font id and same Y position
7561 [ # # ]: 0 : std::vector< sal_uInt32 > aRunEnds;
7562 [ # # ]: 0 : aRunEnds.reserve( rGlyphs.size() );
7563 [ # # ]: 0 : for( size_t i = 1; i < rGlyphs.size(); i++ )
7564 : : {
7565 [ # # # # ]: 0 : if( rGlyphs[i].m_nMappedFontId != rGlyphs[i-1].m_nMappedFontId ||
[ # # ]
7566 : 0 : rGlyphs[i].m_aPos.Y() != rGlyphs[i-1].m_aPos.Y() )
7567 : : {
7568 [ # # ]: 0 : aRunEnds.push_back(i);
7569 : : }
7570 : : }
7571 : : // last run ends at last glyph
7572 [ # # ]: 0 : aRunEnds.push_back( rGlyphs.size() );
7573 : :
7574 : : // loop over runs of the same font
7575 : 0 : sal_uInt32 nBeginRun = 0;
7576 [ # # ]: 0 : for( size_t nRun = 0; nRun < aRunEnds.size(); nRun++ )
7577 : : {
7578 : : // setup text matrix
7579 : 0 : Point aCurPos = rGlyphs[nBeginRun].m_aPos;
7580 : : // back transformation to current coordinate system
7581 [ # # ]: 0 : aCurPos = m_pReferenceDevice->PixelToLogic( aCurPos );
7582 : 0 : aCurPos += rAlignOffset;
7583 : : // the first run can be set with "Td" operator
7584 : : // subsequent use of that operator would move
7585 : : // the texline matrix relative to what was set before
7586 : : // making use of that would drive us into rounding issues
7587 : 0 : Matrix3 aMat;
7588 [ # # ][ # # ]: 0 : if( nRun == 0 && fAngle == 0.0 && fXScale == 1.0 && fSkew == 0.0 )
[ # # ][ # # ]
7589 : : {
7590 [ # # ][ # # ]: 0 : m_aPages.back().appendPoint( aCurPos, rLine, false );
7591 [ # # ]: 0 : rLine.append( " Td " );
7592 : : }
7593 : : else
7594 : : {
7595 [ # # ]: 0 : if( fSkew != 0.0 )
7596 : 0 : aMat.skew( 0.0, fSkew );
7597 : 0 : aMat.scale( fXScale, 1.0 );
7598 : 0 : aMat.rotate( fAngle );
7599 : 0 : aMat.translate( aCurPos.X(), aCurPos.Y() );
7600 [ # # ][ # # ]: 0 : aMat.append( m_aPages.back(), rLine );
7601 [ # # ]: 0 : rLine.append( " Tm\n" );
7602 : : }
7603 : : // set up correct font
7604 [ # # ]: 0 : rLine.append( "/F" );
7605 [ # # ]: 0 : rLine.append( rGlyphs[nBeginRun].m_nMappedFontId );
7606 [ # # ]: 0 : rLine.append( ' ' );
7607 [ # # ][ # # ]: 0 : m_aPages.back().appendMappedLength( nFontHeight, rLine, true );
7608 [ # # ]: 0 : rLine.append( " Tf" );
7609 : :
7610 : : // output glyphs using Tj or TJ
7611 : 0 : OStringBuffer aKernedLine( 256 ), aUnkernedLine( 256 );
7612 [ # # ]: 0 : aKernedLine.append( "[<" );
7613 [ # # ]: 0 : aUnkernedLine.append( '<' );
7614 [ # # ]: 0 : appendHex( rGlyphs[nBeginRun].m_nMappedGlyphId, aKernedLine );
7615 [ # # ]: 0 : appendHex( rGlyphs[nBeginRun].m_nMappedGlyphId, aUnkernedLine );
7616 : :
7617 : 0 : aMat.invert();
7618 : 0 : bool bNeedKern = false;
7619 [ # # ][ # # ]: 0 : for( sal_uInt32 nPos = nBeginRun+1; nPos < aRunEnds[nRun]; nPos++ )
7620 : : {
7621 [ # # ]: 0 : appendHex( rGlyphs[nPos].m_nMappedGlyphId, aUnkernedLine );
7622 : : // check if default glyph positioning is sufficient
7623 : 0 : const Point aThisPos = aMat.transform( rGlyphs[nPos].m_aPos );
7624 : 0 : const Point aPrevPos = aMat.transform( rGlyphs[nPos-1].m_aPos );
7625 : 0 : double fAdvance = aThisPos.X() - aPrevPos.X();
7626 : 0 : fAdvance *= 1000.0 / nPixelFontHeight;
7627 : 0 : const sal_Int32 nAdjustment = (sal_Int32)(rGlyphs[nPos-1].m_nNativeWidth - fAdvance + 0.5);
7628 [ # # ]: 0 : if( nAdjustment != 0 )
7629 : : {
7630 : : // apply individual glyph positioning
7631 : 0 : bNeedKern = true;
7632 [ # # ]: 0 : aKernedLine.append( ">" );
7633 [ # # ]: 0 : aKernedLine.append( nAdjustment );
7634 [ # # ]: 0 : aKernedLine.append( "<" );
7635 : : }
7636 [ # # ]: 0 : appendHex( rGlyphs[nPos].m_nMappedGlyphId, aKernedLine );
7637 : : }
7638 [ # # ]: 0 : aKernedLine.append( ">]TJ\n" );
7639 [ # # ]: 0 : aUnkernedLine.append( ">Tj\n" );
7640 : : rLine.append(
7641 [ # # ][ # # ]: 0 : (bNeedKern ? aKernedLine : aUnkernedLine).makeStringAndClear() );
7642 : :
7643 : : // set beginning of next run
7644 [ # # ]: 0 : nBeginRun = aRunEnds[nRun];
7645 : 0 : }
7646 : 0 : }
7647 : :
7648 : 0 : void PDFWriterImpl::drawLayout( SalLayout& rLayout, const String& rText, bool bTextLines )
7649 : : {
7650 : : // relief takes precedence over shadow (see outdev3.cxx)
7651 [ # # ][ # # ]: 0 : if( m_aCurrentPDFState.m_aFont.GetRelief() != RELIEF_NONE )
7652 : : {
7653 [ # # ]: 0 : drawRelief( rLayout, rText, bTextLines );
7654 : 0 : return;
7655 : : }
7656 [ # # ][ # # ]: 0 : else if( m_aCurrentPDFState.m_aFont.IsShadow() )
7657 [ # # ]: 0 : drawShadow( rLayout, rText, bTextLines );
7658 : :
7659 : 0 : OStringBuffer aLine( 512 );
7660 : :
7661 : 0 : const int nMaxGlyphs = 256;
7662 : :
7663 : : sal_GlyphId pGlyphs[nMaxGlyphs];
7664 : : sal_Int32 pGlyphWidths[nMaxGlyphs];
7665 : : sal_uInt8 pMappedGlyphs[nMaxGlyphs];
7666 : : sal_Int32 pMappedFontObjects[nMaxGlyphs];
7667 [ # # ]: 0 : std::vector<sal_Ucs> aUnicodes;
7668 [ # # ]: 0 : aUnicodes.reserve( nMaxGlyphs );
7669 : : sal_Int32 pUnicodesPerGlyph[nMaxGlyphs];
7670 : : int pCharPosAry[nMaxGlyphs];
7671 : : sal_Int32 nAdvanceWidths[nMaxGlyphs];
7672 : : const PhysicalFontFace* pFallbackFonts[nMaxGlyphs];
7673 [ # # ]: 0 : bool bVertical = m_aCurrentPDFState.m_aFont.IsVertical();
7674 : : int nGlyphs;
7675 : 0 : int nIndex = 0;
7676 : 0 : int nMinCharPos = 0, nMaxCharPos = rText.Len()-1;
7677 : 0 : double fXScale = 1.0;
7678 : 0 : double fSkew = 0.0;
7679 : 0 : sal_Int32 nPixelFontHeight = m_pReferenceDevice->mpFontEntry->maFontSelData.mnHeight;
7680 [ # # ]: 0 : TextAlign eAlign = m_aCurrentPDFState.m_aFont.GetAlign();
7681 : :
7682 : : // transform font height back to current units
7683 : : // note: the layout calculates in outdevs device pixel !!
7684 [ # # ]: 0 : sal_Int32 nFontHeight = m_pReferenceDevice->ImplDevicePixelToLogicHeight( nPixelFontHeight );
7685 [ # # ][ # # ]: 0 : if( m_aCurrentPDFState.m_aFont.GetWidth() )
7686 : : {
7687 [ # # ]: 0 : Font aFont( m_aCurrentPDFState.m_aFont );
7688 [ # # ]: 0 : aFont.SetWidth( 0 );
7689 [ # # ]: 0 : FontMetric aMetric = m_pReferenceDevice->GetFontMetric( aFont );
7690 [ # # ][ # # ]: 0 : if( aMetric.GetWidth() != m_aCurrentPDFState.m_aFont.GetWidth() )
[ # # ]
7691 : : {
7692 : : fXScale =
7693 [ # # ]: 0 : (double)m_aCurrentPDFState.m_aFont.GetWidth() /
7694 [ # # ]: 0 : (double)aMetric.GetWidth();
7695 : : }
7696 : : // force state before GetFontMetric
7697 [ # # ][ # # ]: 0 : m_pReferenceDevice->ImplNewFont();
[ # # ]
7698 : : }
7699 : :
7700 : : // perform artificial italics if necessary
7701 [ # # ][ # # ]: 0 : if( ( m_aCurrentPDFState.m_aFont.GetItalic() == ITALIC_NORMAL ||
[ # # # # ]
[ # # ]
7702 [ # # ]: 0 : m_aCurrentPDFState.m_aFont.GetItalic() == ITALIC_OBLIQUE ) &&
7703 : 0 : !( m_pReferenceDevice->mpFontEntry->maFontSelData.mpFontData->GetSlant() == ITALIC_NORMAL ||
7704 [ # # ]: 0 : m_pReferenceDevice->mpFontEntry->maFontSelData.mpFontData->GetSlant() == ITALIC_OBLIQUE )
7705 : : )
7706 : : {
7707 : 0 : fSkew = M_PI/12.0;
7708 : : }
7709 : :
7710 : : // if the mapmode is distorted we need to adjust for that also
7711 [ # # ][ # # ]: 0 : if( m_aCurrentPDFState.m_aMapMode.GetScaleX() != m_aCurrentPDFState.m_aMapMode.GetScaleY() )
7712 : : {
7713 [ # # ][ # # ]: 0 : fXScale *= double(m_aCurrentPDFState.m_aMapMode.GetScaleX()) / double(m_aCurrentPDFState.m_aMapMode.GetScaleY());
7714 : : }
7715 : :
7716 [ # # ]: 0 : int nAngle = m_aCurrentPDFState.m_aFont.GetOrientation();
7717 : : // normalize angles
7718 [ # # ]: 0 : while( nAngle < 0 )
7719 : 0 : nAngle += 3600;
7720 : 0 : nAngle = nAngle % 3600;
7721 : 0 : double fAngle = (double)nAngle * M_PI / 1800.0;
7722 : :
7723 : 0 : Matrix3 aRotScale;
7724 : 0 : aRotScale.scale( fXScale, 1.0 );
7725 [ # # ]: 0 : if( fAngle != 0.0 )
7726 : 0 : aRotScale.rotate( -fAngle );
7727 : :
7728 : 0 : bool bPop = false;
7729 : 0 : bool bABold = false;
7730 : : // artificial bold necessary ?
7731 [ # # # # ]: 0 : if( m_pReferenceDevice->mpFontEntry->maFontSelData.mpFontData->GetWeight() <= WEIGHT_MEDIUM &&
[ # # ]
7732 : 0 : m_pReferenceDevice->mpFontEntry->maFontSelData.GetWeight() > WEIGHT_MEDIUM )
7733 : : {
7734 [ # # ]: 0 : if( ! bPop )
7735 [ # # ]: 0 : aLine.append( "q " );
7736 : 0 : bPop = true;
7737 : 0 : bABold = true;
7738 : : }
7739 : : // setup text colors (if necessary)
7740 : 0 : Color aStrokeColor( COL_TRANSPARENT );
7741 : 0 : Color aNonStrokeColor( COL_TRANSPARENT );
7742 : :
7743 [ # # ][ # # ]: 0 : if( m_aCurrentPDFState.m_aFont.IsOutline() )
7744 : : {
7745 [ # # ]: 0 : aStrokeColor = m_aCurrentPDFState.m_aFont.GetColor();
7746 : 0 : aNonStrokeColor = Color( COL_WHITE );
7747 : : }
7748 : : else
7749 [ # # ]: 0 : aNonStrokeColor = m_aCurrentPDFState.m_aFont.GetColor();
7750 [ # # ]: 0 : if( bABold )
7751 [ # # ]: 0 : aStrokeColor = m_aCurrentPDFState.m_aFont.GetColor();
7752 : :
7753 [ # # ][ # # ]: 0 : if( aStrokeColor != Color( COL_TRANSPARENT ) && aStrokeColor != m_aCurrentPDFState.m_aLineColor )
[ # # ][ # # ]
7754 : : {
7755 [ # # ]: 0 : if( ! bPop )
7756 [ # # ]: 0 : aLine.append( "q " );
7757 : 0 : bPop = true;
7758 [ # # ]: 0 : appendStrokingColor( aStrokeColor, aLine );
7759 [ # # ]: 0 : aLine.append( "\n" );
7760 : : }
7761 [ # # ][ # # ]: 0 : if( aNonStrokeColor != Color( COL_TRANSPARENT ) && aNonStrokeColor != m_aCurrentPDFState.m_aFillColor )
[ # # ][ # # ]
7762 : : {
7763 [ # # ]: 0 : if( ! bPop )
7764 [ # # ]: 0 : aLine.append( "q " );
7765 : 0 : bPop = true;
7766 [ # # ]: 0 : appendNonStrokingColor( aNonStrokeColor, aLine );
7767 [ # # ]: 0 : aLine.append( "\n" );
7768 : : }
7769 : :
7770 : : // begin text object
7771 [ # # ]: 0 : aLine.append( "BT\n" );
7772 : : // outline attribute ?
7773 [ # # ][ # # ]: 0 : if( m_aCurrentPDFState.m_aFont.IsOutline() || bABold )
[ # # ][ # # ]
7774 : : {
7775 : : // set correct text mode, set stroke width
7776 [ # # ]: 0 : aLine.append( "2 Tr " ); // fill, then stroke
7777 : :
7778 [ # # ][ # # ]: 0 : if( m_aCurrentPDFState.m_aFont.IsOutline() )
7779 : : {
7780 : : // unclear what to do in case of outline and artificial bold
7781 : : // for the time being outline wins
7782 [ # # ]: 0 : aLine.append( "0.25 w \n" );
7783 : : }
7784 : : else
7785 : : {
7786 [ # # ]: 0 : double fW = (double)m_aCurrentPDFState.m_aFont.GetHeight() / 30.0;
7787 [ # # ][ # # ]: 0 : m_aPages.back().appendMappedLength( fW, aLine );
7788 [ # # ]: 0 : aLine.append ( " w\n" );
7789 : : }
7790 : : }
7791 : :
7792 [ # # ]: 0 : FontMetric aRefDevFontMetric = m_pReferenceDevice->GetFontMetric();
7793 : :
7794 : : // collect the glyphs into a single array
7795 [ # # ]: 0 : const int nTmpMaxGlyphs = rLayout.GetOrientation() ? 1 : nMaxGlyphs; // #i97991# temporary workaround for #i87686#
7796 [ # # ]: 0 : std::vector< PDFGlyph > aGlyphs;
7797 [ # # ]: 0 : aGlyphs.reserve( nTmpMaxGlyphs );
7798 : : // first get all the glyphs and register them; coordinates still in Pixel
7799 : 0 : Point aGNGlyphPos;
7800 [ # # ][ # # ]: 0 : while( (nGlyphs = rLayout.GetNextGlyphs( nTmpMaxGlyphs, pGlyphs, aGNGlyphPos, nIndex, nAdvanceWidths, pCharPosAry )) != 0 )
7801 : : {
7802 : 0 : aUnicodes.clear();
7803 [ # # ]: 0 : for( int i = 0; i < nGlyphs; i++ )
7804 : : {
7805 [ # # ]: 0 : pFallbackFonts[i] = rLayout.GetFallbackFontData( pGlyphs[i] );
7806 : :
7807 : : // default case: 1 glyph is one unicode
7808 : 0 : pUnicodesPerGlyph[i] = 1;
7809 [ # # ]: 0 : if( (pGlyphs[i] & GF_ISCHAR) )
7810 : : {
7811 [ # # ]: 0 : aUnicodes.push_back( static_cast<sal_Ucs>(pGlyphs[i] & GF_IDXMASK) );
7812 : : }
7813 [ # # ][ # # ]: 0 : else if( pCharPosAry[i] >= nMinCharPos && pCharPosAry[i] <= nMaxCharPos )
7814 : : {
7815 : 0 : int nChars = 1;
7816 [ # # ]: 0 : aUnicodes.push_back( rText.GetChar( sal::static_int_cast<xub_StrLen>(pCharPosAry[i]) ) );
7817 : 0 : pUnicodesPerGlyph[i] = 1;
7818 : : // try to handle ligatures and such
7819 [ # # ]: 0 : if( i < nGlyphs-1 )
7820 : : {
7821 : 0 : nChars = pCharPosAry[i+1] - pCharPosAry[i];
7822 : : // #i115618# fix for simple RTL+CTL cases
7823 : : // TODO: sanitize for RTL ligatures, more complex CTL, etc.
7824 [ # # ]: 0 : if( nChars < 0 )
7825 : 0 : nChars = -nChars;
7826 [ # # ]: 0 : else if( nChars == 0 )
7827 : 0 : nChars = 1;
7828 : 0 : pUnicodesPerGlyph[i] = nChars;
7829 [ # # ]: 0 : for( int n = 1; n < nChars; n++ )
7830 [ # # ]: 0 : aUnicodes.push_back( rText.GetChar( sal::static_int_cast<xub_StrLen>(pCharPosAry[i]+n) ) );
7831 : : }
7832 : : // #i36691# hack that is needed because currently the pGlyphs[]
7833 : : // argument is ignored for embeddable fonts and so the layout
7834 : : // engine's glyph work is ignored (i.e. char mirroring)
7835 : : // TODO: a real solution would be to map the layout engine's
7836 : : // glyphid (i.e. FreeType's synthetic glyphid for a Type1 font)
7837 : : // back to unicode and then to embeddable font's encoding
7838 [ # # ][ # # ]: 0 : if( getReferenceDevice()->GetLayoutMode() & TEXT_LAYOUT_BIDI_RTL )
7839 : : {
7840 : 0 : size_t nI = aUnicodes.size()-1;
7841 [ # # ]: 0 : for( int n = 0; n < nChars; n++, nI-- )
7842 [ # # ][ # # ]: 0 : aUnicodes[nI] = static_cast<sal_Ucs>(GetMirroredChar(aUnicodes[nI]));
[ # # ]
7843 : 0 : }
7844 : : }
7845 : : else
7846 [ # # ]: 0 : aUnicodes.push_back( 0 );
7847 : : // note: in case of ctl one character may result
7848 : : // in multiple glyphs. The current SalLayout
7849 : : // implementations set -1 then to indicate that no direct
7850 : : // mapping is possible
7851 : : }
7852 : :
7853 [ # # ][ # # ]: 0 : registerGlyphs( nGlyphs, pGlyphs, pGlyphWidths, &aUnicodes[0], pUnicodesPerGlyph, pMappedGlyphs, pMappedFontObjects, pFallbackFonts );
7854 : :
7855 [ # # ]: 0 : for( int i = 0; i < nGlyphs; i++ )
7856 : : {
7857 : : aGlyphs.push_back( PDFGlyph( aGNGlyphPos,
7858 : : pGlyphWidths[i],
7859 : 0 : pGlyphs[i],
7860 : : pMappedFontObjects[i],
7861 [ # # ]: 0 : pMappedGlyphs[i] ) );
7862 [ # # ]: 0 : if( bVertical )
7863 : 0 : aGNGlyphPos.Y() += nAdvanceWidths[i]/rLayout.GetUnitsPerPixel();
7864 : : else
7865 : 0 : aGNGlyphPos.X() += nAdvanceWidths[i]/rLayout.GetUnitsPerPixel();
7866 : : }
7867 : : }
7868 : :
7869 : 0 : Point aAlignOffset;
7870 [ # # ]: 0 : if ( eAlign == ALIGN_BOTTOM )
7871 [ # # ]: 0 : aAlignOffset.Y() -= aRefDevFontMetric.GetDescent();
7872 [ # # ]: 0 : else if ( eAlign == ALIGN_TOP )
7873 [ # # ]: 0 : aAlignOffset.Y() += aRefDevFontMetric.GetAscent();
7874 [ # # ][ # # ]: 0 : if( aAlignOffset.X() || aAlignOffset.Y() )
[ # # ]
7875 : 0 : aAlignOffset = aRotScale.transform( aAlignOffset );
7876 : :
7877 : : /* #159153# do not emit an empty glyph vector; this can happen if e.g. the original
7878 : : string contained only on of the UTF16 BOMs
7879 : : */
7880 [ # # ]: 0 : if( ! aGlyphs.empty() )
7881 : : {
7882 [ # # ]: 0 : if( bVertical )
7883 [ # # ]: 0 : drawVerticalGlyphs( aGlyphs, aLine, aAlignOffset, aRotScale, fAngle, fXScale, fSkew, nFontHeight );
7884 : : else
7885 [ # # ]: 0 : drawHorizontalGlyphs( aGlyphs, aLine, aAlignOffset, fAngle, fXScale, fSkew, nFontHeight, nPixelFontHeight );
7886 : : }
7887 : :
7888 : : // end textobject
7889 [ # # ]: 0 : aLine.append( "ET\n" );
7890 [ # # ]: 0 : if( bPop )
7891 [ # # ]: 0 : aLine.append( "Q\n" );
7892 : :
7893 [ # # ]: 0 : writeBuffer( aLine.getStr(), aLine.getLength() );
7894 : :
7895 : : // draw eventual textlines
7896 [ # # ]: 0 : FontStrikeout eStrikeout = m_aCurrentPDFState.m_aFont.GetStrikeout();
7897 [ # # ]: 0 : FontUnderline eUnderline = m_aCurrentPDFState.m_aFont.GetUnderline();
7898 [ # # ]: 0 : FontUnderline eOverline = m_aCurrentPDFState.m_aFont.GetOverline();
7899 [ # # ][ # # ]: 0 : if( bTextLines &&
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
7900 : : (
7901 : : ( eUnderline != UNDERLINE_NONE && eUnderline != UNDERLINE_DONTKNOW ) ||
7902 : : ( eOverline != UNDERLINE_NONE && eOverline != UNDERLINE_DONTKNOW ) ||
7903 : : ( eStrikeout != STRIKEOUT_NONE && eStrikeout != STRIKEOUT_DONTKNOW )
7904 : : )
7905 : : )
7906 : : {
7907 [ # # ]: 0 : sal_Bool bUnderlineAbove = OutputDevice::ImplIsUnderlineAbove( m_aCurrentPDFState.m_aFont );
7908 [ # # ][ # # ]: 0 : if( m_aCurrentPDFState.m_aFont.IsWordLineMode() )
7909 : : {
7910 : 0 : Point aPos, aStartPt;
7911 : 0 : sal_Int32 nWidth = 0, nAdvance=0;
7912 : 0 : for( int nStart = 0;;)
7913 : : {
7914 : : sal_GlyphId nGlyphIndex;
7915 [ # # ][ # # ]: 0 : if( !rLayout.GetNextGlyphs( 1, &nGlyphIndex, aPos, nStart, &nAdvance ) )
7916 : : break;
7917 : :
7918 [ # # ][ # # ]: 0 : if( !rLayout.IsSpacingGlyph( nGlyphIndex ) )
7919 : : {
7920 [ # # ]: 0 : if( !nWidth )
7921 : 0 : aStartPt = aPos;
7922 : :
7923 : 0 : nWidth += nAdvance;
7924 : : }
7925 [ # # ]: 0 : else if( nWidth > 0 )
7926 : : {
7927 : 0 : drawTextLine( m_pReferenceDevice->PixelToLogic( aStartPt ),
7928 : : m_pReferenceDevice->ImplDevicePixelToLogicWidth( nWidth ),
7929 [ # # ][ # # ]: 0 : eStrikeout, eUnderline, eOverline, bUnderlineAbove );
[ # # ]
7930 : 0 : nWidth = 0;
7931 : : }
7932 : : }
7933 : :
7934 [ # # ]: 0 : if( nWidth > 0 )
7935 : : {
7936 : 0 : drawTextLine( m_pReferenceDevice->PixelToLogic( aStartPt ),
7937 : : m_pReferenceDevice->ImplDevicePixelToLogicWidth( nWidth ),
7938 [ # # ][ # # ]: 0 : eStrikeout, eUnderline, eOverline, bUnderlineAbove );
[ # # ]
7939 : : }
7940 : : }
7941 : : else
7942 : : {
7943 [ # # ]: 0 : Point aStartPt = rLayout.GetDrawPosition();
7944 [ # # ]: 0 : int nWidth = rLayout.GetTextWidth() / rLayout.GetUnitsPerPixel();
7945 : 0 : drawTextLine( m_pReferenceDevice->PixelToLogic( aStartPt ),
7946 : : m_pReferenceDevice->ImplDevicePixelToLogicWidth( nWidth ),
7947 [ # # ][ # # ]: 0 : eStrikeout, eUnderline, eOverline, bUnderlineAbove );
[ # # ]
7948 : : }
7949 : : }
7950 : :
7951 : : // write eventual emphasis marks
7952 [ # # ][ # # ]: 0 : if( m_aCurrentPDFState.m_aFont.GetEmphasisMark() & EMPHASISMARK_STYLE )
7953 : : {
7954 [ # # ]: 0 : PolyPolygon aEmphPoly;
7955 [ # # ]: 0 : Rectangle aEmphRect1;
7956 [ # # ]: 0 : Rectangle aEmphRect2;
7957 : : long nEmphYOff;
7958 : : long nEmphWidth;
7959 : : long nEmphHeight;
7960 : : sal_Bool bEmphPolyLine;
7961 : : FontEmphasisMark nEmphMark;
7962 : :
7963 [ # # ]: 0 : push( PUSH_ALL );
7964 : :
7965 [ # # ]: 0 : aLine.setLength( 0 );
7966 [ # # ]: 0 : aLine.append( "q\n" );
7967 : :
7968 [ # # ]: 0 : nEmphMark = m_pReferenceDevice->ImplGetEmphasisMarkStyle( m_aCurrentPDFState.m_aFont );
7969 [ # # ]: 0 : if ( nEmphMark & EMPHASISMARK_POS_BELOW )
7970 : 0 : nEmphHeight = m_pReferenceDevice->mnEmphasisDescent;
7971 : : else
7972 : 0 : nEmphHeight = m_pReferenceDevice->mnEmphasisAscent;
7973 : : m_pReferenceDevice->ImplGetEmphasisMark( aEmphPoly,
7974 : : bEmphPolyLine,
7975 : : aEmphRect1,
7976 : : aEmphRect2,
7977 : : nEmphYOff,
7978 : : nEmphWidth,
7979 : : nEmphMark,
7980 : : m_pReferenceDevice->ImplDevicePixelToLogicWidth(nEmphHeight),
7981 [ # # ][ # # ]: 0 : m_pReferenceDevice->mpFontEntry->mnOrientation );
7982 [ # # ]: 0 : if ( bEmphPolyLine )
7983 : : {
7984 [ # # ][ # # ]: 0 : setLineColor( m_aCurrentPDFState.m_aFont.GetColor() );
7985 [ # # ]: 0 : setFillColor( Color( COL_TRANSPARENT ) );
7986 : : }
7987 : : else
7988 : : {
7989 [ # # ][ # # ]: 0 : setFillColor( m_aCurrentPDFState.m_aFont.GetColor() );
7990 [ # # ]: 0 : setLineColor( Color( COL_TRANSPARENT ) );
7991 : : }
7992 [ # # ]: 0 : writeBuffer( aLine.getStr(), aLine.getLength() );
7993 : :
7994 : 0 : Point aOffset = Point(0,0);
7995 : :
7996 [ # # ]: 0 : if ( nEmphMark & EMPHASISMARK_POS_BELOW )
7997 : 0 : aOffset.Y() += m_pReferenceDevice->mpFontEntry->maMetric.mnDescent + nEmphYOff;
7998 : : else
7999 : 0 : aOffset.Y() -= m_pReferenceDevice->mpFontEntry->maMetric.mnAscent + nEmphYOff;
8000 : :
8001 : 0 : long nEmphWidth2 = nEmphWidth / 2;
8002 : 0 : long nEmphHeight2 = nEmphHeight / 2;
8003 : 0 : aOffset += Point( nEmphWidth2, nEmphHeight2 );
8004 : :
8005 [ # # ]: 0 : if ( eAlign == ALIGN_BOTTOM )
8006 : 0 : aOffset.Y() -= m_pReferenceDevice->mpFontEntry->maMetric.mnDescent;
8007 [ # # ]: 0 : else if ( eAlign == ALIGN_TOP )
8008 : 0 : aOffset.Y() += m_pReferenceDevice->mpFontEntry->maMetric.mnAscent;
8009 : :
8010 : 0 : for( int nStart = 0;;)
8011 : : {
8012 : 0 : Point aPos;
8013 : : sal_GlyphId nGlyphIndex;
8014 : : sal_Int32 nAdvance;
8015 [ # # ][ # # ]: 0 : if( !rLayout.GetNextGlyphs( 1, &nGlyphIndex, aPos, nStart, &nAdvance ) )
8016 : : break;
8017 : :
8018 [ # # ][ # # ]: 0 : if( !rLayout.IsSpacingGlyph( nGlyphIndex ) )
8019 : : {
8020 : 0 : Point aAdjOffset = aOffset;
8021 : 0 : aAdjOffset.X() += (nAdvance - nEmphWidth) / 2;
8022 : 0 : aAdjOffset = aRotScale.transform( aAdjOffset );
8023 : :
8024 : 0 : aAdjOffset -= Point( nEmphWidth2, nEmphHeight2 );
8025 : :
8026 : 0 : aPos += aAdjOffset;
8027 [ # # ]: 0 : aPos = m_pReferenceDevice->PixelToLogic( aPos );
8028 : 0 : drawEmphasisMark( aPos.X(), aPos.Y(),
8029 : : aEmphPoly, bEmphPolyLine,
8030 [ # # ]: 0 : aEmphRect1, aEmphRect2 );
8031 : : }
8032 : : }
8033 : :
8034 [ # # ]: 0 : writeBuffer( "Q\n", 2 );
8035 [ # # ][ # # ]: 0 : pop();
8036 [ # # ]: 0 : }
8037 : :
8038 : : }
8039 : :
8040 : 0 : void PDFWriterImpl::drawEmphasisMark( long nX, long nY,
8041 : : const PolyPolygon& rPolyPoly, sal_Bool bPolyLine,
8042 : : const Rectangle& rRect1, const Rectangle& rRect2 )
8043 : : {
8044 : : // TODO: pass nWidth as width of this mark
8045 : : // long nWidth = 0;
8046 : :
8047 [ # # ]: 0 : if ( rPolyPoly.Count() )
8048 : : {
8049 [ # # ]: 0 : if ( bPolyLine )
8050 : : {
8051 [ # # ][ # # ]: 0 : Polygon aPoly = rPolyPoly.GetObject( 0 );
8052 [ # # ]: 0 : aPoly.Move( nX, nY );
8053 [ # # ][ # # ]: 0 : drawPolyLine( aPoly );
8054 : : }
8055 : : else
8056 : : {
8057 [ # # ]: 0 : PolyPolygon aPolyPoly = rPolyPoly;
8058 [ # # ]: 0 : aPolyPoly.Move( nX, nY );
8059 [ # # ][ # # ]: 0 : drawPolyPolygon( aPolyPoly );
8060 : : }
8061 : : }
8062 : :
8063 [ # # ]: 0 : if ( !rRect1.IsEmpty() )
8064 : : {
8065 : 0 : Rectangle aRect( Point( nX+rRect1.Left(),
8066 [ # # ][ # # ]: 0 : nY+rRect1.Top() ), rRect1.GetSize() );
8067 [ # # ]: 0 : drawRectangle( aRect );
8068 : : }
8069 : :
8070 [ # # ]: 0 : if ( !rRect2.IsEmpty() )
8071 : : {
8072 : 0 : Rectangle aRect( Point( nX+rRect2.Left(),
8073 [ # # ][ # # ]: 0 : nY+rRect2.Top() ), rRect2.GetSize() );
8074 : :
8075 [ # # ]: 0 : drawRectangle( aRect );
8076 : : }
8077 : 0 : }
8078 : :
8079 : 0 : void PDFWriterImpl::drawText( const Point& rPos, const String& rText, xub_StrLen nIndex, xub_StrLen nLen, bool bTextLines )
8080 : : {
8081 : 0 : MARK( "drawText" );
8082 : :
8083 : 0 : updateGraphicsState();
8084 : :
8085 : : // get a layout from the OuputDevice's SalGraphics
8086 : : // this also enforces font substitution and sets the font on SalGraphics
8087 : 0 : SalLayout* pLayout = m_pReferenceDevice->ImplLayout( rText, nIndex, nLen, rPos );
8088 [ # # ]: 0 : if( pLayout )
8089 : : {
8090 : 0 : drawLayout( *pLayout, rText, bTextLines );
8091 : 0 : pLayout->Release();
8092 : : }
8093 : 0 : }
8094 : :
8095 : 0 : void PDFWriterImpl::drawTextArray( const Point& rPos, const String& rText, const sal_Int32* pDXArray, xub_StrLen nIndex, xub_StrLen nLen, bool bTextLines )
8096 : : {
8097 : 0 : MARK( "drawText with array" );
8098 : :
8099 : 0 : updateGraphicsState();
8100 : :
8101 : : // get a layout from the OuputDevice's SalGraphics
8102 : : // this also enforces font substitution and sets the font on SalGraphics
8103 : 0 : SalLayout* pLayout = m_pReferenceDevice->ImplLayout( rText, nIndex, nLen, rPos, 0, pDXArray );
8104 [ # # ]: 0 : if( pLayout )
8105 : : {
8106 : 0 : drawLayout( *pLayout, rText, bTextLines );
8107 : 0 : pLayout->Release();
8108 : : }
8109 : 0 : }
8110 : :
8111 : 0 : void PDFWriterImpl::drawStretchText( const Point& rPos, sal_uLong nWidth, const String& rText, xub_StrLen nIndex, xub_StrLen nLen, bool bTextLines )
8112 : : {
8113 : 0 : MARK( "drawStretchText" );
8114 : :
8115 : 0 : updateGraphicsState();
8116 : :
8117 : : // get a layout from the OuputDevice's SalGraphics
8118 : : // this also enforces font substitution and sets the font on SalGraphics
8119 : 0 : SalLayout* pLayout = m_pReferenceDevice->ImplLayout( rText, nIndex, nLen, rPos, nWidth );
8120 [ # # ]: 0 : if( pLayout )
8121 : : {
8122 : 0 : drawLayout( *pLayout, rText, bTextLines );
8123 : 0 : pLayout->Release();
8124 : : }
8125 : 0 : }
8126 : :
8127 : 0 : void PDFWriterImpl::drawText( const Rectangle& rRect, const String& rOrigStr, sal_uInt16 nStyle, bool bTextLines )
8128 : : {
8129 [ # # ]: 0 : long nWidth = rRect.GetWidth();
8130 [ # # ]: 0 : long nHeight = rRect.GetHeight();
8131 : :
8132 [ # # ][ # # ]: 0 : if ( nWidth <= 0 || nHeight <= 0 )
8133 : 0 : return;
8134 : :
8135 [ # # ]: 0 : MARK( "drawText with rectangle" );
8136 : :
8137 [ # # ]: 0 : updateGraphicsState();
8138 : :
8139 : : // clip with rectangle
8140 : 0 : OStringBuffer aLine;
8141 [ # # ]: 0 : aLine.append( "q " );
8142 [ # # ][ # # ]: 0 : m_aPages.back().appendRect( rRect, aLine );
8143 [ # # ]: 0 : aLine.append( " W* n\n" );
8144 [ # # ]: 0 : writeBuffer( aLine.getStr(), aLine.getLength() );
8145 : :
8146 : : // if disabled text is needed, put in here
8147 : :
8148 : 0 : Point aPos = rRect.TopLeft();
8149 : :
8150 [ # # ]: 0 : long nTextHeight = m_pReferenceDevice->GetTextHeight();
8151 : 0 : xub_StrLen nMnemonicPos = STRING_NOTFOUND;
8152 : :
8153 [ # # ]: 0 : String aStr = rOrigStr;
8154 [ # # ]: 0 : if ( nStyle & TEXT_DRAW_MNEMONIC )
8155 [ # # ][ # # ]: 0 : aStr = m_pReferenceDevice->GetNonMnemonicString( aStr, nMnemonicPos );
[ # # ]
8156 : :
8157 : : // multiline text
8158 [ # # ]: 0 : if ( nStyle & TEXT_DRAW_MULTILINE )
8159 : : {
8160 : 0 : rtl::OUString aLastLine;
8161 [ # # ]: 0 : ImplMultiTextLineInfo aMultiLineInfo;
8162 : : ImplTextLineInfo* pLineInfo;
8163 : : xub_StrLen i;
8164 : : xub_StrLen nLines;
8165 : : xub_StrLen nFormatLines;
8166 : :
8167 [ # # ]: 0 : if ( nTextHeight )
8168 : : {
8169 : 0 : ::vcl::DefaultTextLayout aLayout( *m_pReferenceDevice );
8170 [ # # ]: 0 : OutputDevice::ImplGetTextLines( aMultiLineInfo, nWidth, aStr, nStyle, aLayout );
8171 : 0 : nLines = (xub_StrLen)(nHeight/nTextHeight);
8172 : 0 : nFormatLines = aMultiLineInfo.Count();
8173 [ # # ]: 0 : if ( !nLines )
8174 : 0 : nLines = 1;
8175 [ # # ]: 0 : if ( nFormatLines > nLines )
8176 : : {
8177 [ # # ]: 0 : if ( nStyle & TEXT_DRAW_ENDELLIPSIS )
8178 : : {
8179 : : // handle last line
8180 : 0 : nFormatLines = nLines-1;
8181 : :
8182 : 0 : pLineInfo = aMultiLineInfo.GetLine( nFormatLines );
8183 [ # # ][ # # ]: 0 : aLastLine = convertLineEnd(aStr.Copy(pLineInfo->GetIndex()), LINEEND_LF);
[ # # ][ # # ]
8184 : : // replace line feed by space
8185 : 0 : aLastLine = aLastLine.replace(_LF, ' ');
8186 [ # # ][ # # ]: 0 : aLastLine = m_pReferenceDevice->GetEllipsisString( aLastLine, nWidth, nStyle );
[ # # ][ # # ]
[ # # ]
8187 : 0 : nStyle &= ~(TEXT_DRAW_VCENTER | TEXT_DRAW_BOTTOM);
8188 : 0 : nStyle |= TEXT_DRAW_TOP;
8189 : : }
8190 : : }
8191 : :
8192 : : // vertical alignment
8193 [ # # ]: 0 : if ( nStyle & TEXT_DRAW_BOTTOM )
8194 : 0 : aPos.Y() += nHeight-(nFormatLines*nTextHeight);
8195 [ # # ]: 0 : else if ( nStyle & TEXT_DRAW_VCENTER )
8196 : 0 : aPos.Y() += (nHeight-(nFormatLines*nTextHeight))/2;
8197 : :
8198 : : // draw all lines excluding the last
8199 [ # # ]: 0 : for ( i = 0; i < nFormatLines; i++ )
8200 : : {
8201 : 0 : pLineInfo = aMultiLineInfo.GetLine( i );
8202 [ # # ]: 0 : if ( nStyle & TEXT_DRAW_RIGHT )
8203 : 0 : aPos.X() += nWidth-pLineInfo->GetWidth();
8204 [ # # ]: 0 : else if ( nStyle & TEXT_DRAW_CENTER )
8205 : 0 : aPos.X() += (nWidth-pLineInfo->GetWidth())/2;
8206 : 0 : xub_StrLen nIndex = pLineInfo->GetIndex();
8207 : 0 : xub_StrLen nLineLen = pLineInfo->GetLen();
8208 [ # # ]: 0 : drawText( aPos, aStr, nIndex, nLineLen, bTextLines );
8209 : : // mnemonics should not appear in documents,
8210 : : // if the need arises, put them in here
8211 : 0 : aPos.Y() += nTextHeight;
8212 : 0 : aPos.X() = rRect.Left();
8213 : : }
8214 : :
8215 : :
8216 : : // output last line left adjusted since it was shortened
8217 [ # # ]: 0 : if (!aLastLine.isEmpty())
8218 [ # # ][ # # ]: 0 : drawText( aPos, aLastLine, 0, STRING_LEN, bTextLines );
[ # # ][ # # ]
8219 [ # # ]: 0 : }
8220 : : }
8221 : : else
8222 : : {
8223 [ # # ]: 0 : long nTextWidth = m_pReferenceDevice->GetTextWidth( aStr );
8224 : :
8225 : : // Evt. Text kuerzen
8226 [ # # ]: 0 : if ( nTextWidth > nWidth )
8227 : : {
8228 [ # # ]: 0 : if ( nStyle & (TEXT_DRAW_ENDELLIPSIS | TEXT_DRAW_PATHELLIPSIS | TEXT_DRAW_NEWSELLIPSIS) )
8229 : : {
8230 [ # # ][ # # ]: 0 : aStr = m_pReferenceDevice->GetEllipsisString( aStr, nWidth, nStyle );
[ # # ]
8231 : 0 : nStyle &= ~(TEXT_DRAW_CENTER | TEXT_DRAW_RIGHT);
8232 : 0 : nStyle |= TEXT_DRAW_LEFT;
8233 [ # # ]: 0 : nTextWidth = m_pReferenceDevice->GetTextWidth( aStr );
8234 : : }
8235 : : }
8236 : :
8237 : : // vertical alignment
8238 [ # # ]: 0 : if ( nStyle & TEXT_DRAW_RIGHT )
8239 : 0 : aPos.X() += nWidth-nTextWidth;
8240 [ # # ]: 0 : else if ( nStyle & TEXT_DRAW_CENTER )
8241 : 0 : aPos.X() += (nWidth-nTextWidth)/2;
8242 : :
8243 [ # # ]: 0 : if ( nStyle & TEXT_DRAW_BOTTOM )
8244 : 0 : aPos.Y() += nHeight-nTextHeight;
8245 [ # # ]: 0 : else if ( nStyle & TEXT_DRAW_VCENTER )
8246 : 0 : aPos.Y() += (nHeight-nTextHeight)/2;
8247 : :
8248 : : // mnemonics should be inserted here if the need arises
8249 : :
8250 : : // draw the actual text
8251 [ # # ]: 0 : drawText( aPos, aStr, 0, STRING_LEN, bTextLines );
8252 : : }
8253 : :
8254 : : // reset clip region to original value
8255 [ # # ]: 0 : aLine.setLength( 0 );
8256 [ # # ]: 0 : aLine.append( "Q\n" );
8257 [ # # ][ # # ]: 0 : writeBuffer( aLine.getStr(), aLine.getLength() );
8258 : : }
8259 : :
8260 : 0 : void PDFWriterImpl::drawLine( const Point& rStart, const Point& rStop )
8261 : : {
8262 [ # # ]: 0 : MARK( "drawLine" );
8263 : :
8264 [ # # ]: 0 : updateGraphicsState();
8265 : :
8266 [ # # ][ # # ]: 0 : if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) )
8267 : 0 : return;
8268 : :
8269 : 0 : OStringBuffer aLine;
8270 [ # # ][ # # ]: 0 : m_aPages.back().appendPoint( rStart, aLine );
8271 [ # # ]: 0 : aLine.append( " m " );
8272 [ # # ][ # # ]: 0 : m_aPages.back().appendPoint( rStop, aLine );
8273 [ # # ]: 0 : aLine.append( " l S\n" );
8274 : :
8275 [ # # ]: 0 : writeBuffer( aLine.getStr(), aLine.getLength() );
8276 : : }
8277 : :
8278 : 0 : void PDFWriterImpl::drawLine( const Point& rStart, const Point& rStop, const LineInfo& rInfo )
8279 : : {
8280 [ # # ]: 0 : MARK( "drawLine with LineInfo" );
8281 [ # # ]: 0 : updateGraphicsState();
8282 : :
8283 [ # # ][ # # ]: 0 : if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) )
8284 : : return;
8285 : :
8286 [ # # ][ # # ]: 0 : if( rInfo.GetStyle() == LINE_SOLID && rInfo.GetWidth() < 2 )
[ # # ]
8287 : : {
8288 [ # # ]: 0 : drawLine( rStart, rStop );
8289 : : return;
8290 : : }
8291 : :
8292 : 0 : OStringBuffer aLine;
8293 : :
8294 [ # # ]: 0 : aLine.append( "q " );
8295 [ # # ][ # # ]: 0 : if( m_aPages.back().appendLineInfo( rInfo, aLine ) )
[ # # ]
8296 : : {
8297 [ # # ][ # # ]: 0 : m_aPages.back().appendPoint( rStart, aLine );
8298 [ # # ]: 0 : aLine.append( " m " );
8299 [ # # ][ # # ]: 0 : m_aPages.back().appendPoint( rStop, aLine );
8300 [ # # ]: 0 : aLine.append( " l S Q\n" );
8301 : :
8302 [ # # ]: 0 : writeBuffer( aLine.getStr(), aLine.getLength() );
8303 : : }
8304 : : else
8305 : : {
8306 [ # # ]: 0 : PDFWriter::ExtLineInfo aInfo;
8307 [ # # ]: 0 : convertLineInfoToExtLineInfo( rInfo, aInfo );
8308 : 0 : Point aPolyPoints[2] = { rStart, rStop };
8309 [ # # ]: 0 : Polygon aPoly( 2, aPolyPoints );
8310 [ # # ][ # # ]: 0 : drawPolyLine( aPoly, aInfo );
8311 : 0 : }
8312 : : }
8313 : :
8314 : : #define HCONV( x ) m_pReferenceDevice->ImplDevicePixelToLogicHeight( x )
8315 : :
8316 : 0 : void PDFWriterImpl::drawWaveTextLine( OStringBuffer& aLine, long nWidth, FontUnderline eTextLine, Color aColor, bool bIsAbove )
8317 : : {
8318 : : // note: units in pFontEntry are ref device pixel
8319 : 0 : ImplFontEntry* pFontEntry = m_pReferenceDevice->mpFontEntry;
8320 : 0 : long nLineHeight = 0;
8321 : 0 : long nLinePos = 0;
8322 : :
8323 : 0 : appendStrokingColor( aColor, aLine );
8324 : 0 : aLine.append( "\n" );
8325 : :
8326 [ # # ]: 0 : if ( bIsAbove )
8327 : : {
8328 [ # # ]: 0 : if ( !pFontEntry->maMetric.mnAboveWUnderlineSize )
8329 : 0 : m_pReferenceDevice->ImplInitAboveTextLineSize();
8330 : 0 : nLineHeight = HCONV( pFontEntry->maMetric.mnAboveWUnderlineSize );
8331 : 0 : nLinePos = HCONV( pFontEntry->maMetric.mnAboveWUnderlineOffset );
8332 : : }
8333 : : else
8334 : : {
8335 [ # # ]: 0 : if ( !pFontEntry->maMetric.mnWUnderlineSize )
8336 : 0 : m_pReferenceDevice->ImplInitTextLineSize();
8337 : 0 : nLineHeight = HCONV( pFontEntry->maMetric.mnWUnderlineSize );
8338 : 0 : nLinePos = HCONV( pFontEntry->maMetric.mnWUnderlineOffset );
8339 : : }
8340 [ # # ][ # # ]: 0 : if ( (eTextLine == UNDERLINE_SMALLWAVE) && (nLineHeight > 3) )
8341 : 0 : nLineHeight = 3;
8342 : :
8343 : 0 : long nLineWidth = getReferenceDevice()->mnDPIX/450;
8344 [ # # ]: 0 : if ( ! nLineWidth )
8345 : 0 : nLineWidth = 1;
8346 : :
8347 [ # # ]: 0 : if ( eTextLine == UNDERLINE_BOLDWAVE )
8348 : 0 : nLineWidth = 3*nLineWidth;
8349 : :
8350 : 0 : m_aPages.back().appendMappedLength( (sal_Int32)nLineWidth, aLine );
8351 : 0 : aLine.append( " w " );
8352 : :
8353 [ # # ]: 0 : if ( eTextLine == UNDERLINE_DOUBLEWAVE )
8354 : : {
8355 : 0 : long nOrgLineHeight = nLineHeight;
8356 : 0 : nLineHeight /= 3;
8357 [ # # ]: 0 : if ( nLineHeight < 2 )
8358 : : {
8359 [ # # ]: 0 : if ( nOrgLineHeight > 1 )
8360 : 0 : nLineHeight = 2;
8361 : : else
8362 : 0 : nLineHeight = 1;
8363 : : }
8364 : 0 : long nLineDY = nOrgLineHeight-(nLineHeight*2);
8365 [ # # ]: 0 : if ( nLineDY < nLineWidth )
8366 : 0 : nLineDY = nLineWidth;
8367 : 0 : long nLineDY2 = nLineDY/2;
8368 [ # # ]: 0 : if ( !nLineDY2 )
8369 : 0 : nLineDY2 = 1;
8370 : :
8371 : 0 : nLinePos -= nLineWidth-nLineDY2;
8372 : :
8373 : 0 : m_aPages.back().appendWaveLine( nWidth, -nLinePos, 2*nLineHeight, aLine );
8374 : :
8375 : 0 : nLinePos += nLineWidth+nLineDY;
8376 : 0 : m_aPages.back().appendWaveLine( nWidth, -nLinePos, 2*nLineHeight, aLine );
8377 : : }
8378 : : else
8379 : : {
8380 [ # # ]: 0 : if ( eTextLine != UNDERLINE_BOLDWAVE )
8381 : 0 : nLinePos -= nLineWidth/2;
8382 : 0 : m_aPages.back().appendWaveLine( nWidth, -nLinePos, nLineHeight, aLine );
8383 : : }
8384 : 0 : }
8385 : :
8386 : 0 : void PDFWriterImpl::drawStraightTextLine( OStringBuffer& aLine, long nWidth, FontUnderline eTextLine, Color aColor, bool bIsAbove )
8387 : : {
8388 : : // note: units in pFontEntry are ref device pixel
8389 : 0 : ImplFontEntry* pFontEntry = m_pReferenceDevice->mpFontEntry;
8390 : 0 : long nLineHeight = 0;
8391 : 0 : long nLinePos = 0;
8392 : 0 : long nLinePos2 = 0;
8393 : :
8394 [ # # ]: 0 : if ( eTextLine > UNDERLINE_BOLDWAVE )
8395 : 0 : eTextLine = UNDERLINE_SINGLE;
8396 : :
8397 [ # # # # ]: 0 : switch ( eTextLine )
8398 : : {
8399 : : case UNDERLINE_SINGLE:
8400 : : case UNDERLINE_DOTTED:
8401 : : case UNDERLINE_DASH:
8402 : : case UNDERLINE_LONGDASH:
8403 : : case UNDERLINE_DASHDOT:
8404 : : case UNDERLINE_DASHDOTDOT:
8405 [ # # ]: 0 : if ( bIsAbove )
8406 : : {
8407 [ # # ]: 0 : if ( !pFontEntry->maMetric.mnAboveUnderlineSize )
8408 : 0 : m_pReferenceDevice->ImplInitAboveTextLineSize();
8409 : 0 : nLineHeight = HCONV( pFontEntry->maMetric.mnAboveUnderlineSize );
8410 : 0 : nLinePos = HCONV( pFontEntry->maMetric.mnAboveUnderlineOffset );
8411 : : }
8412 : : else
8413 : : {
8414 [ # # ]: 0 : if ( !pFontEntry->maMetric.mnUnderlineSize )
8415 : 0 : m_pReferenceDevice->ImplInitTextLineSize();
8416 : 0 : nLineHeight = HCONV( pFontEntry->maMetric.mnUnderlineSize );
8417 : 0 : nLinePos = HCONV( pFontEntry->maMetric.mnUnderlineOffset );
8418 : : }
8419 : 0 : break;
8420 : : case UNDERLINE_BOLD:
8421 : : case UNDERLINE_BOLDDOTTED:
8422 : : case UNDERLINE_BOLDDASH:
8423 : : case UNDERLINE_BOLDLONGDASH:
8424 : : case UNDERLINE_BOLDDASHDOT:
8425 : : case UNDERLINE_BOLDDASHDOTDOT:
8426 [ # # ]: 0 : if ( bIsAbove )
8427 : : {
8428 [ # # ]: 0 : if ( !pFontEntry->maMetric.mnAboveBUnderlineSize )
8429 : 0 : m_pReferenceDevice->ImplInitAboveTextLineSize();
8430 : 0 : nLineHeight = HCONV( pFontEntry->maMetric.mnAboveBUnderlineSize );
8431 : 0 : nLinePos = HCONV( pFontEntry->maMetric.mnAboveBUnderlineOffset );
8432 : : }
8433 : : else
8434 : : {
8435 [ # # ]: 0 : if ( !pFontEntry->maMetric.mnBUnderlineSize )
8436 : 0 : m_pReferenceDevice->ImplInitTextLineSize();
8437 : 0 : nLineHeight = HCONV( pFontEntry->maMetric.mnBUnderlineSize );
8438 : 0 : nLinePos = HCONV( pFontEntry->maMetric.mnBUnderlineOffset );
8439 : 0 : nLinePos += nLineHeight/2;
8440 : : }
8441 : 0 : break;
8442 : : case UNDERLINE_DOUBLE:
8443 [ # # ]: 0 : if ( bIsAbove )
8444 : : {
8445 [ # # ]: 0 : if ( !pFontEntry->maMetric.mnAboveDUnderlineSize )
8446 : 0 : m_pReferenceDevice->ImplInitAboveTextLineSize();
8447 : 0 : nLineHeight = HCONV( pFontEntry->maMetric.mnAboveDUnderlineSize );
8448 : 0 : nLinePos = HCONV( pFontEntry->maMetric.mnAboveDUnderlineOffset1 );
8449 : 0 : nLinePos2 = HCONV( pFontEntry->maMetric.mnAboveDUnderlineOffset2 );
8450 : : }
8451 : : else
8452 : : {
8453 [ # # ]: 0 : if ( !pFontEntry->maMetric.mnDUnderlineSize )
8454 : 0 : m_pReferenceDevice->ImplInitTextLineSize();
8455 : 0 : nLineHeight = HCONV( pFontEntry->maMetric.mnDUnderlineSize );
8456 : 0 : nLinePos = HCONV( pFontEntry->maMetric.mnDUnderlineOffset1 );
8457 : 0 : nLinePos2 = HCONV( pFontEntry->maMetric.mnDUnderlineOffset2 );
8458 : : }
8459 : : default:
8460 : 0 : break;
8461 : : }
8462 : :
8463 [ # # ]: 0 : if ( nLineHeight )
8464 : : {
8465 : 0 : m_aPages.back().appendMappedLength( (sal_Int32)nLineHeight, aLine, true );
8466 : 0 : aLine.append( " w " );
8467 : 0 : appendStrokingColor( aColor, aLine );
8468 : 0 : aLine.append( "\n" );
8469 : :
8470 [ # # # # : 0 : switch ( eTextLine )
# ]
8471 : : {
8472 : : case UNDERLINE_DOTTED:
8473 : : case UNDERLINE_BOLDDOTTED:
8474 : 0 : aLine.append( "[ " );
8475 : 0 : m_aPages.back().appendMappedLength( (sal_Int32)nLineHeight, aLine, false );
8476 : 0 : aLine.append( " ] 0 d\n" );
8477 : 0 : break;
8478 : : case UNDERLINE_DASH:
8479 : : case UNDERLINE_LONGDASH:
8480 : : case UNDERLINE_BOLDDASH:
8481 : : case UNDERLINE_BOLDLONGDASH:
8482 : : {
8483 : 0 : sal_Int32 nDashLength = 4*nLineHeight;
8484 : 0 : sal_Int32 nVoidLength = 2*nLineHeight;
8485 [ # # ][ # # ]: 0 : if ( ( eTextLine == UNDERLINE_LONGDASH ) || ( eTextLine == UNDERLINE_BOLDLONGDASH ) )
8486 : 0 : nDashLength = 8*nLineHeight;
8487 : :
8488 : 0 : aLine.append( "[ " );
8489 : 0 : m_aPages.back().appendMappedLength( nDashLength, aLine, false );
8490 : 0 : aLine.append( ' ' );
8491 : 0 : m_aPages.back().appendMappedLength( nVoidLength, aLine, false );
8492 : 0 : aLine.append( " ] 0 d\n" );
8493 : : }
8494 : 0 : break;
8495 : : case UNDERLINE_DASHDOT:
8496 : : case UNDERLINE_BOLDDASHDOT:
8497 : : {
8498 : 0 : sal_Int32 nDashLength = 4*nLineHeight;
8499 : 0 : sal_Int32 nVoidLength = 2*nLineHeight;
8500 : 0 : aLine.append( "[ " );
8501 : 0 : m_aPages.back().appendMappedLength( nDashLength, aLine, false );
8502 : 0 : aLine.append( ' ' );
8503 : 0 : m_aPages.back().appendMappedLength( nVoidLength, aLine, false );
8504 : 0 : aLine.append( ' ' );
8505 : 0 : m_aPages.back().appendMappedLength( (sal_Int32)nLineHeight, aLine, false );
8506 : 0 : aLine.append( ' ' );
8507 : 0 : m_aPages.back().appendMappedLength( nVoidLength, aLine, false );
8508 : 0 : aLine.append( " ] 0 d\n" );
8509 : : }
8510 : 0 : break;
8511 : : case UNDERLINE_DASHDOTDOT:
8512 : : case UNDERLINE_BOLDDASHDOTDOT:
8513 : : {
8514 : 0 : sal_Int32 nDashLength = 4*nLineHeight;
8515 : 0 : sal_Int32 nVoidLength = 2*nLineHeight;
8516 : 0 : aLine.append( "[ " );
8517 : 0 : m_aPages.back().appendMappedLength( nDashLength, aLine, false );
8518 : 0 : aLine.append( ' ' );
8519 : 0 : m_aPages.back().appendMappedLength( nVoidLength, aLine, false );
8520 : 0 : aLine.append( ' ' );
8521 : 0 : m_aPages.back().appendMappedLength( (sal_Int32)nLineHeight, aLine, false );
8522 : 0 : aLine.append( ' ' );
8523 : 0 : m_aPages.back().appendMappedLength( nVoidLength, aLine, false );
8524 : 0 : aLine.append( ' ' );
8525 : 0 : m_aPages.back().appendMappedLength( (sal_Int32)nLineHeight, aLine, false );
8526 : 0 : aLine.append( ' ' );
8527 : 0 : m_aPages.back().appendMappedLength( nVoidLength, aLine, false );
8528 : 0 : aLine.append( " ] 0 d\n" );
8529 : : }
8530 : 0 : break;
8531 : : default:
8532 : 0 : break;
8533 : : }
8534 : :
8535 : 0 : aLine.append( "0 " );
8536 : 0 : m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos), aLine, true );
8537 : 0 : aLine.append( " m " );
8538 : 0 : m_aPages.back().appendMappedLength( (sal_Int32)nWidth, aLine, false );
8539 : 0 : aLine.append( ' ' );
8540 : 0 : m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos), aLine, true );
8541 : 0 : aLine.append( " l S\n" );
8542 [ # # ]: 0 : if ( eTextLine == UNDERLINE_DOUBLE )
8543 : : {
8544 : 0 : aLine.append( "0 " );
8545 : 0 : m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos2-nLineHeight), aLine, true );
8546 : 0 : aLine.append( " m " );
8547 : 0 : m_aPages.back().appendMappedLength( (sal_Int32)nWidth, aLine, false );
8548 : 0 : aLine.append( ' ' );
8549 : 0 : m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos2-nLineHeight), aLine, true );
8550 : 0 : aLine.append( " l S\n" );
8551 : : }
8552 : : }
8553 : 0 : }
8554 : :
8555 : 0 : void PDFWriterImpl::drawStrikeoutLine( OStringBuffer& aLine, long nWidth, FontStrikeout eStrikeout, Color aColor )
8556 : : {
8557 : : // note: units in pFontEntry are ref device pixel
8558 : 0 : ImplFontEntry* pFontEntry = m_pReferenceDevice->mpFontEntry;
8559 : 0 : long nLineHeight = 0;
8560 : 0 : long nLinePos = 0;
8561 : 0 : long nLinePos2 = 0;
8562 : :
8563 [ # # ]: 0 : if ( eStrikeout > STRIKEOUT_X )
8564 : 0 : eStrikeout = STRIKEOUT_SINGLE;
8565 : :
8566 [ # # # # ]: 0 : switch ( eStrikeout )
8567 : : {
8568 : : case STRIKEOUT_SINGLE:
8569 [ # # ]: 0 : if ( !pFontEntry->maMetric.mnStrikeoutSize )
8570 : 0 : m_pReferenceDevice->ImplInitTextLineSize();
8571 : 0 : nLineHeight = HCONV( pFontEntry->maMetric.mnStrikeoutSize );
8572 : 0 : nLinePos = HCONV( pFontEntry->maMetric.mnStrikeoutOffset );
8573 : 0 : break;
8574 : : case STRIKEOUT_BOLD:
8575 [ # # ]: 0 : if ( !pFontEntry->maMetric.mnBStrikeoutSize )
8576 : 0 : m_pReferenceDevice->ImplInitTextLineSize();
8577 : 0 : nLineHeight = HCONV( pFontEntry->maMetric.mnBStrikeoutSize );
8578 : 0 : nLinePos = HCONV( pFontEntry->maMetric.mnBStrikeoutOffset );
8579 : 0 : break;
8580 : : case STRIKEOUT_DOUBLE:
8581 [ # # ]: 0 : if ( !pFontEntry->maMetric.mnDStrikeoutSize )
8582 : 0 : m_pReferenceDevice->ImplInitTextLineSize();
8583 : 0 : nLineHeight = HCONV( pFontEntry->maMetric.mnDStrikeoutSize );
8584 : 0 : nLinePos = HCONV( pFontEntry->maMetric.mnDStrikeoutOffset1 );
8585 : 0 : nLinePos2 = HCONV( pFontEntry->maMetric.mnDStrikeoutOffset2 );
8586 : 0 : break;
8587 : : default:
8588 : 0 : break;
8589 : : }
8590 : :
8591 [ # # ]: 0 : if ( nLineHeight )
8592 : : {
8593 : 0 : m_aPages.back().appendMappedLength( (sal_Int32)nLineHeight, aLine, true );
8594 : 0 : aLine.append( " w " );
8595 : 0 : appendStrokingColor( aColor, aLine );
8596 : 0 : aLine.append( "\n" );
8597 : :
8598 : 0 : aLine.append( "0 " );
8599 : 0 : m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos), aLine, true );
8600 : 0 : aLine.append( " m " );
8601 : 0 : m_aPages.back().appendMappedLength( (sal_Int32)nWidth, aLine, true );
8602 : 0 : aLine.append( ' ' );
8603 : 0 : m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos), aLine, true );
8604 : 0 : aLine.append( " l S\n" );
8605 : :
8606 [ # # ]: 0 : if ( eStrikeout == STRIKEOUT_DOUBLE )
8607 : : {
8608 : 0 : aLine.append( "0 " );
8609 : 0 : m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos2-nLineHeight), aLine, true );
8610 : 0 : aLine.append( " m " );
8611 : 0 : m_aPages.back().appendMappedLength( (sal_Int32)nWidth, aLine, true );
8612 : 0 : aLine.append( ' ' );
8613 : 0 : m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos2-nLineHeight), aLine, true );
8614 : 0 : aLine.append( " l S\n" );
8615 : : }
8616 : : }
8617 : 0 : }
8618 : :
8619 : 0 : void PDFWriterImpl::drawStrikeoutChar( const Point& rPos, long nWidth, FontStrikeout eStrikeout )
8620 : : {
8621 : : //See qadevOOo/testdocs/StrikeThrough.odt for examples if you need
8622 : : //to tweak this
8623 : :
8624 [ # # ][ # # ]: 0 : rtl::OUString aStrikeoutChar = eStrikeout == STRIKEOUT_SLASH ? rtl::OUString("/") : rtl::OUString("X");
[ # # ]
8625 [ # # ]: 0 : String aStrikeout = aStrikeoutChar;
8626 [ # # ][ # # ]: 0 : while( m_pReferenceDevice->GetTextWidth( aStrikeout ) < nWidth )
8627 [ # # ]: 0 : aStrikeout.Append( aStrikeout );
8628 : :
8629 : : // do not get broader than nWidth modulo 1 character
8630 [ # # ][ # # ]: 0 : while( m_pReferenceDevice->GetTextWidth( aStrikeout ) >= nWidth )
8631 [ # # ]: 0 : aStrikeout.Erase( 0, 1 );
8632 [ # # ][ # # ]: 0 : aStrikeout.Append( aStrikeoutChar );
[ # # ]
8633 [ # # ]: 0 : sal_Bool bShadow = m_aCurrentPDFState.m_aFont.IsShadow();
8634 [ # # ]: 0 : if ( bShadow )
8635 : : {
8636 [ # # ]: 0 : Font aFont = m_aCurrentPDFState.m_aFont;
8637 [ # # ]: 0 : aFont.SetShadow( sal_False );
8638 [ # # ]: 0 : setFont( aFont );
8639 [ # # ][ # # ]: 0 : updateGraphicsState();
8640 : : }
8641 : :
8642 : : // strikeout string is left aligned non-CTL text
8643 : 0 : sal_uLong nOrigTLM = m_pReferenceDevice->GetLayoutMode();
8644 [ # # ]: 0 : m_pReferenceDevice->SetLayoutMode( TEXT_LAYOUT_BIDI_STRONG|TEXT_LAYOUT_COMPLEX_DISABLED );
8645 : :
8646 [ # # ]: 0 : push( PUSH_CLIPREGION );
8647 [ # # ]: 0 : FontMetric aRefDevFontMetric = m_pReferenceDevice->GetFontMetric();
8648 [ # # ]: 0 : Rectangle aRect;
8649 : 0 : aRect.nLeft = rPos.X();
8650 : 0 : aRect.nRight = aRect.nLeft+nWidth;
8651 [ # # ]: 0 : aRect.nBottom = rPos.Y()+aRefDevFontMetric.GetDescent();
8652 [ # # ]: 0 : aRect.nTop = rPos.Y()-aRefDevFontMetric.GetAscent();
8653 : :
8654 : 0 : ImplFontEntry* pFontEntry = m_pReferenceDevice->mpFontEntry;
8655 [ # # ]: 0 : if (pFontEntry->mnOrientation)
8656 : : {
8657 [ # # ]: 0 : Polygon aPoly( aRect );
8658 [ # # ]: 0 : aPoly.Rotate( rPos, pFontEntry->mnOrientation);
8659 [ # # ][ # # ]: 0 : aRect = aPoly.GetBoundRect();
8660 : : }
8661 : :
8662 [ # # ]: 0 : intersectClipRegion( aRect );
8663 [ # # ]: 0 : drawText( rPos, aStrikeout, 0, aStrikeout.Len(), false );
8664 [ # # ]: 0 : pop();
8665 : :
8666 [ # # ]: 0 : m_pReferenceDevice->SetLayoutMode( nOrigTLM );
8667 : :
8668 [ # # ]: 0 : if ( bShadow )
8669 : : {
8670 [ # # ]: 0 : Font aFont = m_aCurrentPDFState.m_aFont;
8671 [ # # ]: 0 : aFont.SetShadow( sal_True );
8672 [ # # ]: 0 : setFont( aFont );
8673 [ # # ][ # # ]: 0 : updateGraphicsState();
8674 [ # # ][ # # ]: 0 : }
8675 : 0 : }
8676 : :
8677 : 0 : void PDFWriterImpl::drawTextLine( const Point& rPos, long nWidth, FontStrikeout eStrikeout, FontUnderline eUnderline, FontUnderline eOverline, bool bUnderlineAbove )
8678 : : {
8679 [ # # ][ # # ]: 0 : if ( !nWidth ||
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
8680 : : ( ((eStrikeout == STRIKEOUT_NONE)||(eStrikeout == STRIKEOUT_DONTKNOW)) &&
8681 : : ((eUnderline == UNDERLINE_NONE)||(eUnderline == UNDERLINE_DONTKNOW)) &&
8682 : : ((eOverline == UNDERLINE_NONE)||(eOverline == UNDERLINE_DONTKNOW)) ) )
8683 : 0 : return;
8684 : :
8685 [ # # ]: 0 : MARK( "drawTextLine" );
8686 [ # # ]: 0 : updateGraphicsState();
8687 : :
8688 : : // note: units in pFontEntry are ref device pixel
8689 : 0 : ImplFontEntry* pFontEntry = m_pReferenceDevice->mpFontEntry;
8690 : 0 : Color aUnderlineColor = m_aCurrentPDFState.m_aTextLineColor;
8691 : 0 : Color aOverlineColor = m_aCurrentPDFState.m_aOverlineColor;
8692 [ # # ]: 0 : Color aStrikeoutColor = m_aCurrentPDFState.m_aFont.GetColor();
8693 : 0 : bool bStrikeoutDone = false;
8694 : 0 : bool bUnderlineDone = false;
8695 : 0 : bool bOverlineDone = false;
8696 : :
8697 [ # # ][ # # ]: 0 : if ( (eStrikeout == STRIKEOUT_SLASH) || (eStrikeout == STRIKEOUT_X) )
8698 : : {
8699 [ # # ]: 0 : drawStrikeoutChar( rPos, nWidth, eStrikeout );
8700 : 0 : bStrikeoutDone = true;
8701 : : }
8702 : :
8703 : 0 : Point aPos( rPos );
8704 [ # # ]: 0 : TextAlign eAlign = m_aCurrentPDFState.m_aFont.GetAlign();
8705 [ # # ]: 0 : if( eAlign == ALIGN_TOP )
8706 [ # # ]: 0 : aPos.Y() += HCONV( pFontEntry->maMetric.mnAscent );
8707 [ # # ]: 0 : else if( eAlign == ALIGN_BOTTOM )
8708 [ # # ]: 0 : aPos.Y() -= HCONV( pFontEntry->maMetric.mnDescent );
8709 : :
8710 : 0 : OStringBuffer aLine( 512 );
8711 : : // save GS
8712 [ # # ]: 0 : aLine.append( "q " );
8713 : :
8714 : : // rotate and translate matrix
8715 [ # # ]: 0 : double fAngle = (double)m_aCurrentPDFState.m_aFont.GetOrientation() * M_PI / 1800.0;
8716 : 0 : Matrix3 aMat;
8717 : 0 : aMat.rotate( fAngle );
8718 : 0 : aMat.translate( aPos.X(), aPos.Y() );
8719 [ # # ][ # # ]: 0 : aMat.append( m_aPages.back(), aLine );
8720 [ # # ]: 0 : aLine.append( " cm\n" );
8721 : :
8722 [ # # ]: 0 : if ( aUnderlineColor.GetTransparency() != 0 )
8723 : 0 : aUnderlineColor = aStrikeoutColor;
8724 : :
8725 [ # # ][ # # ]: 0 : if ( (eUnderline == UNDERLINE_SMALLWAVE) ||
[ # # ][ # # ]
8726 : : (eUnderline == UNDERLINE_WAVE) ||
8727 : : (eUnderline == UNDERLINE_DOUBLEWAVE) ||
8728 : : (eUnderline == UNDERLINE_BOLDWAVE) )
8729 : : {
8730 [ # # ]: 0 : drawWaveTextLine( aLine, nWidth, eUnderline, aUnderlineColor, bUnderlineAbove );
8731 : 0 : bUnderlineDone = true;
8732 : : }
8733 : :
8734 [ # # ][ # # ]: 0 : if ( (eOverline == UNDERLINE_SMALLWAVE) ||
[ # # ][ # # ]
8735 : : (eOverline == UNDERLINE_WAVE) ||
8736 : : (eOverline == UNDERLINE_DOUBLEWAVE) ||
8737 : : (eOverline == UNDERLINE_BOLDWAVE) )
8738 : : {
8739 [ # # ]: 0 : drawWaveTextLine( aLine, nWidth, eOverline, aOverlineColor, true );
8740 : 0 : bOverlineDone = true;
8741 : : }
8742 : :
8743 [ # # ]: 0 : if ( !bUnderlineDone )
8744 : : {
8745 [ # # ]: 0 : drawStraightTextLine( aLine, nWidth, eUnderline, aUnderlineColor, bUnderlineAbove );
8746 : : }
8747 : :
8748 [ # # ]: 0 : if ( !bOverlineDone )
8749 : : {
8750 [ # # ]: 0 : drawStraightTextLine( aLine, nWidth, eOverline, aOverlineColor, true );
8751 : : }
8752 : :
8753 [ # # ]: 0 : if ( !bStrikeoutDone )
8754 : : {
8755 [ # # ]: 0 : drawStrikeoutLine( aLine, nWidth, eStrikeout, aStrikeoutColor );
8756 : : }
8757 : :
8758 [ # # ]: 0 : aLine.append( "Q\n" );
8759 [ # # ]: 0 : writeBuffer( aLine.getStr(), aLine.getLength() );
8760 : : }
8761 : :
8762 : 0 : void PDFWriterImpl::drawPolygon( const Polygon& rPoly )
8763 : : {
8764 [ # # ]: 0 : MARK( "drawPolygon" );
8765 : :
8766 [ # # ]: 0 : updateGraphicsState();
8767 : :
8768 [ # # ]: 0 : if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) &&
[ # # # # ]
[ # # ]
[ # # # # ]
8769 [ # # ][ # # ]: 0 : m_aGraphicsStack.front().m_aFillColor == Color( COL_TRANSPARENT ) )
[ # # ]
8770 : 0 : return;
8771 : :
8772 [ # # ]: 0 : int nPoints = rPoly.GetSize();
8773 : 0 : OStringBuffer aLine( 20 * nPoints );
8774 [ # # ][ # # ]: 0 : m_aPages.back().appendPolygon( rPoly, aLine );
8775 [ # # ]: 0 : if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) &&
[ # # # # ]
[ # # ]
[ # # # # ]
8776 [ # # ][ # # ]: 0 : m_aGraphicsStack.front().m_aFillColor != Color( COL_TRANSPARENT ) )
[ # # ]
8777 [ # # ]: 0 : aLine.append( "B*\n" );
8778 [ # # ][ # # ]: 0 : else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
8779 [ # # ]: 0 : aLine.append( "S\n" );
8780 : : else
8781 [ # # ]: 0 : aLine.append( "f*\n" );
8782 : :
8783 [ # # ]: 0 : writeBuffer( aLine.getStr(), aLine.getLength() );
8784 : : }
8785 : :
8786 : 0 : void PDFWriterImpl::drawPolyPolygon( const PolyPolygon& rPolyPoly )
8787 : : {
8788 [ # # ]: 0 : MARK( "drawPolyPolygon" );
8789 : :
8790 [ # # ]: 0 : updateGraphicsState();
8791 : :
8792 [ # # ]: 0 : if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) &&
[ # # # # ]
[ # # ]
[ # # # # ]
8793 [ # # ][ # # ]: 0 : m_aGraphicsStack.front().m_aFillColor == Color( COL_TRANSPARENT ) )
[ # # ]
8794 : 0 : return;
8795 : :
8796 [ # # ]: 0 : int nPolygons = rPolyPoly.Count();
8797 : :
8798 : 0 : OStringBuffer aLine( 40 * nPolygons );
8799 [ # # ][ # # ]: 0 : m_aPages.back().appendPolyPolygon( rPolyPoly, aLine );
8800 [ # # ]: 0 : if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) &&
[ # # # # ]
[ # # ]
[ # # # # ]
8801 [ # # ][ # # ]: 0 : m_aGraphicsStack.front().m_aFillColor != Color( COL_TRANSPARENT ) )
[ # # ]
8802 [ # # ]: 0 : aLine.append( "B*\n" );
8803 [ # # ][ # # ]: 0 : else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
8804 [ # # ]: 0 : aLine.append( "S\n" );
8805 : : else
8806 [ # # ]: 0 : aLine.append( "f*\n" );
8807 : :
8808 [ # # ]: 0 : writeBuffer( aLine.getStr(), aLine.getLength() );
8809 : : }
8810 : :
8811 : 0 : void PDFWriterImpl::drawTransparent( const PolyPolygon& rPolyPoly, sal_uInt32 nTransparentPercent )
8812 : : {
8813 : : DBG_ASSERT( nTransparentPercent <= 100, "invalid alpha value" );
8814 : 0 : nTransparentPercent = nTransparentPercent % 100;
8815 : :
8816 [ # # ]: 0 : MARK( "drawTransparent" );
8817 : :
8818 [ # # ]: 0 : updateGraphicsState();
8819 : :
8820 [ # # ]: 0 : if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) &&
[ # # # # ]
[ # # ]
[ # # # # ]
8821 [ # # ][ # # ]: 0 : m_aGraphicsStack.front().m_aFillColor == Color( COL_TRANSPARENT ) )
[ # # ]
8822 : : return;
8823 : :
8824 [ # # ][ # # ]: 0 : if( m_bIsPDF_A1 || m_aContext.Version < PDFWriter::PDF_1_4 )
8825 : : {
8826 : : m_aErrors.insert( m_bIsPDF_A1 ?
8827 : : PDFWriter::Warning_Transparency_Omitted_PDFA :
8828 [ # # ]: 0 : PDFWriter::Warning_Transparency_Omitted_PDF13 );
8829 : :
8830 [ # # ]: 0 : drawPolyPolygon( rPolyPoly );
8831 : : return;
8832 : : }
8833 : :
8834 : : // create XObject
8835 [ # # ][ # # ]: 0 : m_aTransparentObjects.push_back( TransparencyEmit() );
[ # # ]
8836 : : // FIXME: polygons with beziers may yield incorrect bound rect
8837 [ # # ][ # # ]: 0 : m_aTransparentObjects.back().m_aBoundRect = rPolyPoly.GetBoundRect();
8838 : : // convert rectangle to default user space
8839 [ # # ][ # # ]: 0 : m_aPages.back().convertRect( m_aTransparentObjects.back().m_aBoundRect );
[ # # ]
8840 [ # # ][ # # ]: 0 : m_aTransparentObjects.back().m_nObject = createObject();
8841 [ # # ][ # # ]: 0 : m_aTransparentObjects.back().m_nExtGStateObject = createObject();
8842 [ # # ]: 0 : m_aTransparentObjects.back().m_fAlpha = (double)(100-nTransparentPercent) / 100.0;
8843 [ # # ][ # # ]: 0 : m_aTransparentObjects.back().m_pContentStream = new SvMemoryStream( 256, 256 );
[ # # ]
8844 : : // create XObject's content stream
8845 : 0 : OStringBuffer aContent( 256 );
8846 [ # # ][ # # ]: 0 : m_aPages.back().appendPolyPolygon( rPolyPoly, aContent );
8847 [ # # # # ]: 0 : if( m_aCurrentPDFState.m_aLineColor != Color( COL_TRANSPARENT ) &&
[ # # ][ # # ]
8848 [ # # ]: 0 : m_aCurrentPDFState.m_aFillColor != Color( COL_TRANSPARENT ) )
8849 [ # # ]: 0 : aContent.append( " B*\n" );
8850 [ # # ]: 0 : else if( m_aCurrentPDFState.m_aLineColor != Color( COL_TRANSPARENT ) )
8851 [ # # ]: 0 : aContent.append( " S\n" );
8852 : : else
8853 [ # # ]: 0 : aContent.append( " f*\n" );
8854 [ # # ][ # # ]: 0 : m_aTransparentObjects.back().m_pContentStream->Write( aContent.getStr(), aContent.getLength() );
8855 : :
8856 : 0 : OStringBuffer aObjName( 16 );
8857 [ # # ]: 0 : aObjName.append( "Tr" );
8858 [ # # ][ # # ]: 0 : aObjName.append( m_aTransparentObjects.back().m_nObject );
8859 : 0 : OString aTrName( aObjName.makeStringAndClear() );
8860 [ # # ]: 0 : aObjName.append( "EGS" );
8861 [ # # ][ # # ]: 0 : aObjName.append( m_aTransparentObjects.back().m_nExtGStateObject );
8862 : 0 : OString aExtName( aObjName.makeStringAndClear() );
8863 : :
8864 : 0 : OStringBuffer aLine( 80 );
8865 : : // insert XObject
8866 [ # # ]: 0 : aLine.append( "q /" );
8867 [ # # ]: 0 : aLine.append( aExtName );
8868 [ # # ]: 0 : aLine.append( " gs /" );
8869 [ # # ]: 0 : aLine.append( aTrName );
8870 [ # # ]: 0 : aLine.append( " Do Q\n" );
8871 [ # # ]: 0 : writeBuffer( aLine.getStr(), aLine.getLength() );
8872 : :
8873 [ # # ][ # # ]: 0 : pushResource( ResXObject, aTrName, m_aTransparentObjects.back().m_nObject );
8874 [ # # ][ # # ]: 0 : pushResource( ResExtGState, aExtName, m_aTransparentObjects.back().m_nExtGStateObject );
8875 : : }
8876 : :
8877 : 0 : void PDFWriterImpl::pushResource( ResourceKind eKind, const OString& rResource, sal_Int32 nObject )
8878 : : {
8879 [ # # ]: 0 : if( nObject >= 0 )
8880 : : {
8881 [ # # # # : 0 : switch( eKind )
# ]
8882 : : {
8883 : : case ResXObject:
8884 : 0 : m_aGlobalResourceDict.m_aXObjects[ rResource ] = nObject;
8885 [ # # ]: 0 : if( ! m_aOutputStreams.empty() )
8886 : 0 : m_aOutputStreams.front().m_aResourceDict.m_aXObjects[ rResource ] = nObject;
8887 : 0 : break;
8888 : : case ResExtGState:
8889 : 0 : m_aGlobalResourceDict.m_aExtGStates[ rResource ] = nObject;
8890 [ # # ]: 0 : if( ! m_aOutputStreams.empty() )
8891 : 0 : m_aOutputStreams.front().m_aResourceDict.m_aExtGStates[ rResource ] = nObject;
8892 : 0 : break;
8893 : : case ResShading:
8894 : 0 : m_aGlobalResourceDict.m_aShadings[ rResource ] = nObject;
8895 [ # # ]: 0 : if( ! m_aOutputStreams.empty() )
8896 : 0 : m_aOutputStreams.front().m_aResourceDict.m_aShadings[ rResource ] = nObject;
8897 : 0 : break;
8898 : : case ResPattern:
8899 : 0 : m_aGlobalResourceDict.m_aPatterns[ rResource ] = nObject;
8900 [ # # ]: 0 : if( ! m_aOutputStreams.empty() )
8901 : 0 : m_aOutputStreams.front().m_aResourceDict.m_aPatterns[ rResource ] = nObject;
8902 : 0 : break;
8903 : : }
8904 : : }
8905 : 0 : }
8906 : :
8907 : 0 : void PDFWriterImpl::beginRedirect( SvStream* pStream, const Rectangle& rTargetRect )
8908 : : {
8909 : 0 : push( PUSH_ALL );
8910 : :
8911 : : // force reemitting clip region
8912 : 0 : clearClipRegion();
8913 : 0 : updateGraphicsState();
8914 : :
8915 [ # # ]: 0 : m_aOutputStreams.push_front( StreamRedirect() );
8916 : 0 : m_aOutputStreams.front().m_pStream = pStream;
8917 : 0 : m_aOutputStreams.front().m_aMapMode = m_aMapMode;
8918 : :
8919 [ # # ]: 0 : if( !rTargetRect.IsEmpty() )
8920 : : {
8921 [ # # ]: 0 : m_aOutputStreams.front().m_aTargetRect =
8922 [ # # ]: 0 : lcl_convert( m_aGraphicsStack.front().m_aMapMode,
8923 : : m_aMapMode,
8924 : : getReferenceDevice(),
8925 [ # # ][ # # ]: 0 : rTargetRect );
8926 [ # # ][ # # ]: 0 : Point aDelta = m_aOutputStreams.front().m_aTargetRect.BottomLeft();
8927 : 0 : long nPageHeight = pointToPixel(m_aPages[m_nCurrentPage].getHeight());
8928 [ # # ]: 0 : aDelta.Y() = -(nPageHeight - m_aOutputStreams.front().m_aTargetRect.Bottom());
8929 [ # # ]: 0 : m_aMapMode.SetOrigin( m_aMapMode.GetOrigin() + aDelta );
8930 : : }
8931 : :
8932 : : // setup graphics state for independent object stream
8933 : :
8934 : : // force reemitting colors
8935 : 0 : m_aCurrentPDFState.m_aLineColor = Color( COL_TRANSPARENT );
8936 : 0 : m_aCurrentPDFState.m_aFillColor = Color( COL_TRANSPARENT );
8937 : 0 : }
8938 : :
8939 : 0 : SvStream* PDFWriterImpl::endRedirect()
8940 : : {
8941 : 0 : SvStream* pStream = NULL;
8942 [ # # ]: 0 : if( ! m_aOutputStreams.empty() )
8943 : : {
8944 : 0 : pStream = m_aOutputStreams.front().m_pStream;
8945 : 0 : m_aMapMode = m_aOutputStreams.front().m_aMapMode;
8946 : 0 : m_aOutputStreams.pop_front();
8947 : : }
8948 : :
8949 : 0 : pop();
8950 : : // force reemitting colors and clip region
8951 : 0 : clearClipRegion();
8952 : 0 : m_aCurrentPDFState.m_bClipRegion = m_aGraphicsStack.front().m_bClipRegion;
8953 : 0 : m_aCurrentPDFState.m_aClipRegion = m_aGraphicsStack.front().m_aClipRegion;
8954 : 0 : m_aCurrentPDFState.m_aLineColor = Color( COL_TRANSPARENT );
8955 : 0 : m_aCurrentPDFState.m_aFillColor = Color( COL_TRANSPARENT );
8956 : :
8957 : 0 : updateGraphicsState();
8958 : :
8959 : 0 : return pStream;
8960 : : }
8961 : :
8962 : 0 : void PDFWriterImpl::beginTransparencyGroup()
8963 : : {
8964 : 0 : updateGraphicsState();
8965 [ # # ]: 0 : if( m_aContext.Version >= PDFWriter::PDF_1_4 )
8966 [ # # ][ # # ]: 0 : beginRedirect( new SvMemoryStream( 1024, 1024 ), Rectangle() );
[ # # ]
8967 : 0 : }
8968 : :
8969 : 0 : void PDFWriterImpl::endTransparencyGroup( const Rectangle& rBoundingBox, sal_uInt32 nTransparentPercent )
8970 : : {
8971 : : DBG_ASSERT( nTransparentPercent <= 100, "invalid alpha value" );
8972 : 0 : nTransparentPercent = nTransparentPercent % 100;
8973 : :
8974 [ # # ]: 0 : if( m_aContext.Version >= PDFWriter::PDF_1_4 )
8975 : : {
8976 : : // create XObject
8977 [ # # ][ # # ]: 0 : m_aTransparentObjects.push_back( TransparencyEmit() );
[ # # ]
8978 [ # # ]: 0 : m_aTransparentObjects.back().m_aBoundRect = rBoundingBox;
8979 : : // convert rectangle to default user space
8980 [ # # ][ # # ]: 0 : m_aPages.back().convertRect( m_aTransparentObjects.back().m_aBoundRect );
[ # # ]
8981 [ # # ][ # # ]: 0 : m_aTransparentObjects.back().m_nObject = createObject();
8982 [ # # ]: 0 : m_aTransparentObjects.back().m_fAlpha = (double)(100-nTransparentPercent) / 100.0;
8983 : : // get XObject's content stream
8984 [ # # ][ # # ]: 0 : m_aTransparentObjects.back().m_pContentStream = static_cast<SvMemoryStream*>(endRedirect());
8985 [ # # ][ # # ]: 0 : m_aTransparentObjects.back().m_nExtGStateObject = createObject();
8986 : :
8987 : 0 : OStringBuffer aObjName( 16 );
8988 [ # # ]: 0 : aObjName.append( "Tr" );
8989 [ # # ][ # # ]: 0 : aObjName.append( m_aTransparentObjects.back().m_nObject );
8990 : 0 : OString aTrName( aObjName.makeStringAndClear() );
8991 [ # # ]: 0 : aObjName.append( "EGS" );
8992 [ # # ][ # # ]: 0 : aObjName.append( m_aTransparentObjects.back().m_nExtGStateObject );
8993 : 0 : OString aExtName( aObjName.makeStringAndClear() );
8994 : :
8995 : 0 : OStringBuffer aLine( 80 );
8996 : : // insert XObject
8997 [ # # ]: 0 : aLine.append( "q /" );
8998 [ # # ]: 0 : aLine.append( aExtName );
8999 [ # # ]: 0 : aLine.append( " gs /" );
9000 [ # # ]: 0 : aLine.append( aTrName );
9001 [ # # ]: 0 : aLine.append( " Do Q\n" );
9002 [ # # ]: 0 : writeBuffer( aLine.getStr(), aLine.getLength() );
9003 : :
9004 [ # # ][ # # ]: 0 : pushResource( ResXObject, aTrName, m_aTransparentObjects.back().m_nObject );
9005 [ # # ][ # # ]: 0 : pushResource( ResExtGState, aExtName, m_aTransparentObjects.back().m_nExtGStateObject );
9006 : : }
9007 : 0 : }
9008 : :
9009 : 0 : void PDFWriterImpl::drawRectangle( const Rectangle& rRect )
9010 : : {
9011 [ # # ]: 0 : MARK( "drawRectangle" );
9012 : :
9013 [ # # ]: 0 : updateGraphicsState();
9014 : :
9015 [ # # ]: 0 : if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) &&
[ # # # # ]
[ # # ]
[ # # # # ]
9016 [ # # ][ # # ]: 0 : m_aGraphicsStack.front().m_aFillColor == Color( COL_TRANSPARENT ) )
[ # # ]
9017 : 0 : return;
9018 : :
9019 : 0 : OStringBuffer aLine( 40 );
9020 [ # # ][ # # ]: 0 : m_aPages.back().appendRect( rRect, aLine );
9021 : :
9022 [ # # ]: 0 : if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) &&
[ # # # # ]
[ # # ]
[ # # # # ]
9023 [ # # ][ # # ]: 0 : m_aGraphicsStack.front().m_aFillColor != Color( COL_TRANSPARENT ) )
[ # # ]
9024 [ # # ]: 0 : aLine.append( " B*\n" );
9025 [ # # ][ # # ]: 0 : else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
9026 [ # # ]: 0 : aLine.append( " S\n" );
9027 : : else
9028 [ # # ]: 0 : aLine.append( " f*\n" );
9029 : :
9030 [ # # ]: 0 : writeBuffer( aLine.getStr(), aLine.getLength() );
9031 : : }
9032 : :
9033 : 0 : void PDFWriterImpl::drawRectangle( const Rectangle& rRect, sal_uInt32 nHorzRound, sal_uInt32 nVertRound )
9034 : : {
9035 [ # # ]: 0 : MARK( "drawRectangle with rounded edges" );
9036 : :
9037 [ # # ][ # # ]: 0 : if( !nHorzRound && !nVertRound )
9038 [ # # ]: 0 : drawRectangle( rRect );
9039 : :
9040 [ # # ]: 0 : updateGraphicsState();
9041 : :
9042 [ # # ]: 0 : if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) &&
[ # # # # ]
[ # # ]
[ # # # # ]
9043 [ # # ][ # # ]: 0 : m_aGraphicsStack.front().m_aFillColor == Color( COL_TRANSPARENT ) )
[ # # ]
9044 : 0 : return;
9045 : :
9046 [ # # ][ # # ]: 0 : if( nHorzRound > (sal_uInt32)rRect.GetWidth()/2 )
9047 [ # # ]: 0 : nHorzRound = rRect.GetWidth()/2;
9048 [ # # ][ # # ]: 0 : if( nVertRound > (sal_uInt32)rRect.GetHeight()/2 )
9049 [ # # ]: 0 : nVertRound = rRect.GetHeight()/2;
9050 : :
9051 [ # # ]: 0 : Point aPoints[16];
9052 : 0 : const double kappa = 0.5522847498;
9053 : 0 : const sal_uInt32 kx = (sal_uInt32)((kappa*(double)nHorzRound)+0.5);
9054 : 0 : const sal_uInt32 ky = (sal_uInt32)((kappa*(double)nVertRound)+0.5);
9055 : :
9056 : 0 : aPoints[1] = Point( rRect.TopLeft().X() + nHorzRound, rRect.TopLeft().Y() );
9057 : 0 : aPoints[0] = Point( aPoints[1].X() - kx, aPoints[1].Y() );
9058 [ # # ]: 0 : aPoints[2] = Point( rRect.TopRight().X()+1 - nHorzRound, aPoints[1].Y() );
9059 : 0 : aPoints[3] = Point( aPoints[2].X()+kx, aPoints[2].Y() );
9060 : :
9061 [ # # ][ # # ]: 0 : aPoints[5] = Point( rRect.TopRight().X()+1, rRect.TopRight().Y()+nVertRound );
9062 : 0 : aPoints[4] = Point( aPoints[5].X(), aPoints[5].Y()-ky );
9063 [ # # ]: 0 : aPoints[6] = Point( aPoints[5].X(), rRect.BottomRight().Y()+1 - nVertRound );
9064 : 0 : aPoints[7] = Point( aPoints[6].X(), aPoints[6].Y()+ky );
9065 : :
9066 [ # # ][ # # ]: 0 : aPoints[9] = Point( rRect.BottomRight().X()+1-nHorzRound, rRect.BottomRight().Y()+1 );
9067 : 0 : aPoints[8] = Point( aPoints[9].X()+kx, aPoints[9].Y() );
9068 [ # # ]: 0 : aPoints[10] = Point( rRect.BottomLeft().X() + nHorzRound, aPoints[9].Y() );
9069 : 0 : aPoints[11] = Point( aPoints[10].X()-kx, aPoints[10].Y() );
9070 : :
9071 [ # # ][ # # ]: 0 : aPoints[13] = Point( rRect.BottomLeft().X(), rRect.BottomLeft().Y()+1-nVertRound );
9072 : 0 : aPoints[12] = Point( aPoints[13].X(), aPoints[13].Y()+ky );
9073 : 0 : aPoints[14] = Point( rRect.TopLeft().X(), rRect.TopLeft().Y()+nVertRound );
9074 : 0 : aPoints[15] = Point( aPoints[14].X(), aPoints[14].Y()-ky );
9075 : :
9076 : :
9077 : 0 : OStringBuffer aLine( 80 );
9078 [ # # ][ # # ]: 0 : m_aPages.back().appendPoint( aPoints[1], aLine );
9079 [ # # ]: 0 : aLine.append( " m " );
9080 [ # # ][ # # ]: 0 : m_aPages.back().appendPoint( aPoints[2], aLine );
9081 [ # # ]: 0 : aLine.append( " l " );
9082 [ # # ][ # # ]: 0 : m_aPages.back().appendPoint( aPoints[3], aLine );
9083 [ # # ]: 0 : aLine.append( ' ' );
9084 [ # # ][ # # ]: 0 : m_aPages.back().appendPoint( aPoints[4], aLine );
9085 [ # # ]: 0 : aLine.append( ' ' );
9086 [ # # ][ # # ]: 0 : m_aPages.back().appendPoint( aPoints[5], aLine );
9087 [ # # ]: 0 : aLine.append( " c\n" );
9088 [ # # ][ # # ]: 0 : m_aPages.back().appendPoint( aPoints[6], aLine );
9089 [ # # ]: 0 : aLine.append( " l " );
9090 [ # # ][ # # ]: 0 : m_aPages.back().appendPoint( aPoints[7], aLine );
9091 [ # # ]: 0 : aLine.append( ' ' );
9092 [ # # ][ # # ]: 0 : m_aPages.back().appendPoint( aPoints[8], aLine );
9093 [ # # ]: 0 : aLine.append( ' ' );
9094 [ # # ][ # # ]: 0 : m_aPages.back().appendPoint( aPoints[9], aLine );
9095 [ # # ]: 0 : aLine.append( " c\n" );
9096 [ # # ][ # # ]: 0 : m_aPages.back().appendPoint( aPoints[10], aLine );
9097 [ # # ]: 0 : aLine.append( " l " );
9098 [ # # ][ # # ]: 0 : m_aPages.back().appendPoint( aPoints[11], aLine );
9099 [ # # ]: 0 : aLine.append( ' ' );
9100 [ # # ][ # # ]: 0 : m_aPages.back().appendPoint( aPoints[12], aLine );
9101 [ # # ]: 0 : aLine.append( ' ' );
9102 [ # # ][ # # ]: 0 : m_aPages.back().appendPoint( aPoints[13], aLine );
9103 [ # # ]: 0 : aLine.append( " c\n" );
9104 [ # # ][ # # ]: 0 : m_aPages.back().appendPoint( aPoints[14], aLine );
9105 [ # # ]: 0 : aLine.append( " l " );
9106 [ # # ][ # # ]: 0 : m_aPages.back().appendPoint( aPoints[15], aLine );
9107 [ # # ]: 0 : aLine.append( ' ' );
9108 [ # # ][ # # ]: 0 : m_aPages.back().appendPoint( aPoints[0], aLine );
9109 [ # # ]: 0 : aLine.append( ' ' );
9110 [ # # ][ # # ]: 0 : m_aPages.back().appendPoint( aPoints[1], aLine );
9111 [ # # ]: 0 : aLine.append( " c " );
9112 : :
9113 [ # # ]: 0 : if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) &&
[ # # # # ]
[ # # ]
[ # # # # ]
9114 [ # # ][ # # ]: 0 : m_aGraphicsStack.front().m_aFillColor != Color( COL_TRANSPARENT ) )
[ # # ]
9115 [ # # ]: 0 : aLine.append( "b*\n" );
9116 [ # # ][ # # ]: 0 : else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
9117 [ # # ]: 0 : aLine.append( "s\n" );
9118 : : else
9119 [ # # ]: 0 : aLine.append( "f*\n" );
9120 : :
9121 [ # # ]: 0 : writeBuffer( aLine.getStr(), aLine.getLength() );
9122 : : }
9123 : :
9124 : 0 : void PDFWriterImpl::drawEllipse( const Rectangle& rRect )
9125 : : {
9126 [ # # ]: 0 : MARK( "drawEllipse" );
9127 : :
9128 [ # # ]: 0 : updateGraphicsState();
9129 : :
9130 [ # # ]: 0 : if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) &&
[ # # # # ]
[ # # ]
[ # # # # ]
9131 [ # # ][ # # ]: 0 : m_aGraphicsStack.front().m_aFillColor == Color( COL_TRANSPARENT ) )
[ # # ]
9132 : 0 : return;
9133 : :
9134 [ # # ]: 0 : Point aPoints[12];
9135 : 0 : const double kappa = 0.5522847498;
9136 [ # # ]: 0 : const sal_uInt32 kx = (sal_uInt32)((kappa*(double)rRect.GetWidth()/2.0)+0.5);
9137 [ # # ]: 0 : const sal_uInt32 ky = (sal_uInt32)((kappa*(double)rRect.GetHeight()/2.0)+0.5);
9138 : :
9139 [ # # ]: 0 : aPoints[1] = Point( rRect.TopLeft().X() + rRect.GetWidth()/2, rRect.TopLeft().Y() );
9140 : 0 : aPoints[0] = Point( aPoints[1].X() - kx, aPoints[1].Y() );
9141 : 0 : aPoints[2] = Point( aPoints[1].X() + kx, aPoints[1].Y() );
9142 : :
9143 [ # # ][ # # ]: 0 : aPoints[4] = Point( rRect.TopRight().X()+1, rRect.TopRight().Y() + rRect.GetHeight()/2 );
[ # # ]
9144 : 0 : aPoints[3] = Point( aPoints[4].X(), aPoints[4].Y() - ky );
9145 : 0 : aPoints[5] = Point( aPoints[4].X(), aPoints[4].Y() + ky );
9146 : :
9147 [ # # ][ # # ]: 0 : aPoints[7] = Point( rRect.BottomLeft().X() + rRect.GetWidth()/2, rRect.BottomLeft().Y()+1 );
[ # # ]
9148 : 0 : aPoints[6] = Point( aPoints[7].X() + kx, aPoints[7].Y() );
9149 : 0 : aPoints[8] = Point( aPoints[7].X() - kx, aPoints[7].Y() );
9150 : :
9151 [ # # ]: 0 : aPoints[10] = Point( rRect.TopLeft().X(), rRect.TopLeft().Y() + rRect.GetHeight()/2 );
9152 : 0 : aPoints[9] = Point( aPoints[10].X(), aPoints[10].Y() + ky );
9153 : 0 : aPoints[11] = Point( aPoints[10].X(), aPoints[10].Y() - ky );
9154 : :
9155 : 0 : OStringBuffer aLine( 80 );
9156 [ # # ][ # # ]: 0 : m_aPages.back().appendPoint( aPoints[1], aLine );
9157 [ # # ]: 0 : aLine.append( " m " );
9158 [ # # ][ # # ]: 0 : m_aPages.back().appendPoint( aPoints[2], aLine );
9159 [ # # ]: 0 : aLine.append( ' ' );
9160 [ # # ][ # # ]: 0 : m_aPages.back().appendPoint( aPoints[3], aLine );
9161 [ # # ]: 0 : aLine.append( ' ' );
9162 [ # # ][ # # ]: 0 : m_aPages.back().appendPoint( aPoints[4], aLine );
9163 [ # # ]: 0 : aLine.append( " c\n" );
9164 [ # # ][ # # ]: 0 : m_aPages.back().appendPoint( aPoints[5], aLine );
9165 [ # # ]: 0 : aLine.append( ' ' );
9166 [ # # ][ # # ]: 0 : m_aPages.back().appendPoint( aPoints[6], aLine );
9167 [ # # ]: 0 : aLine.append( ' ' );
9168 [ # # ][ # # ]: 0 : m_aPages.back().appendPoint( aPoints[7], aLine );
9169 [ # # ]: 0 : aLine.append( " c\n" );
9170 [ # # ][ # # ]: 0 : m_aPages.back().appendPoint( aPoints[8], aLine );
9171 [ # # ]: 0 : aLine.append( ' ' );
9172 [ # # ][ # # ]: 0 : m_aPages.back().appendPoint( aPoints[9], aLine );
9173 [ # # ]: 0 : aLine.append( ' ' );
9174 [ # # ][ # # ]: 0 : m_aPages.back().appendPoint( aPoints[10], aLine );
9175 [ # # ]: 0 : aLine.append( " c\n" );
9176 [ # # ][ # # ]: 0 : m_aPages.back().appendPoint( aPoints[11], aLine );
9177 [ # # ]: 0 : aLine.append( ' ' );
9178 [ # # ][ # # ]: 0 : m_aPages.back().appendPoint( aPoints[0], aLine );
9179 [ # # ]: 0 : aLine.append( ' ' );
9180 [ # # ][ # # ]: 0 : m_aPages.back().appendPoint( aPoints[1], aLine );
9181 [ # # ]: 0 : aLine.append( " c " );
9182 : :
9183 [ # # ]: 0 : if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) &&
[ # # # # ]
[ # # ]
[ # # # # ]
9184 [ # # ][ # # ]: 0 : m_aGraphicsStack.front().m_aFillColor != Color( COL_TRANSPARENT ) )
[ # # ]
9185 [ # # ]: 0 : aLine.append( "b*\n" );
9186 [ # # ][ # # ]: 0 : else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
9187 [ # # ]: 0 : aLine.append( "s\n" );
9188 : : else
9189 [ # # ]: 0 : aLine.append( "f*\n" );
9190 : :
9191 [ # # ]: 0 : writeBuffer( aLine.getStr(), aLine.getLength() );
9192 : : }
9193 : :
9194 : 0 : static double calcAngle( const Rectangle& rRect, const Point& rPoint )
9195 : : {
9196 : 0 : Point aOrigin((rRect.Left()+rRect.Right()+1)/2,
9197 : 0 : (rRect.Top()+rRect.Bottom()+1)/2);
9198 : 0 : Point aPoint = rPoint - aOrigin;
9199 : :
9200 : 0 : double fX = (double)aPoint.X();
9201 : 0 : double fY = (double)-aPoint.Y();
9202 : :
9203 [ # # ][ # # ]: 0 : if( rRect.GetWidth() > rRect.GetHeight() )
[ # # ]
9204 [ # # ][ # # ]: 0 : fY = fY*((double)rRect.GetWidth()/(double)rRect.GetHeight());
9205 [ # # ][ # # ]: 0 : else if( rRect.GetHeight() > rRect.GetWidth() )
[ # # ]
9206 [ # # ][ # # ]: 0 : fX = fX*((double)rRect.GetHeight()/(double)rRect.GetWidth());
9207 : 0 : return atan2( fY, fX );
9208 : : }
9209 : :
9210 : 0 : void PDFWriterImpl::drawArc( const Rectangle& rRect, const Point& rStart, const Point& rStop, bool bWithPie, bool bWithChord )
9211 : : {
9212 [ # # ]: 0 : MARK( "drawArc" );
9213 : :
9214 [ # # ]: 0 : updateGraphicsState();
9215 : :
9216 [ # # ]: 0 : if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) &&
[ # # # # ]
[ # # ]
[ # # # # ]
9217 [ # # ][ # # ]: 0 : m_aGraphicsStack.front().m_aFillColor == Color( COL_TRANSPARENT ) )
[ # # ]
9218 : 0 : return;
9219 : :
9220 : : // calculate start and stop angles
9221 [ # # ]: 0 : const double fStartAngle = calcAngle( rRect, rStart );
9222 [ # # ]: 0 : double fStopAngle = calcAngle( rRect, rStop );
9223 [ # # ]: 0 : while( fStopAngle < fStartAngle )
9224 : 0 : fStopAngle += 2.0*M_PI;
9225 : 0 : const int nFragments = (int)((fStopAngle-fStartAngle)/(M_PI/2.0))+1;
9226 : 0 : const double fFragmentDelta = (fStopAngle-fStartAngle)/(double)nFragments;
9227 : 0 : const double kappa = fabs( 4.0 * (1.0-cos(fFragmentDelta/2.0))/sin(fFragmentDelta/2.0) / 3.0);
9228 [ # # ]: 0 : const double halfWidth = (double)rRect.GetWidth()/2.0;
9229 [ # # ]: 0 : const double halfHeight = (double)rRect.GetHeight()/2.0;
9230 : :
9231 : 0 : const Point aCenter( (rRect.Left()+rRect.Right()+1)/2,
9232 : 0 : (rRect.Top()+rRect.Bottom()+1)/2 );
9233 : :
9234 : 0 : OStringBuffer aLine( 30*nFragments );
9235 : 0 : Point aPoint( (int)(halfWidth * cos(fStartAngle) ),
9236 : 0 : -(int)(halfHeight * sin(fStartAngle) ) );
9237 : 0 : aPoint += aCenter;
9238 [ # # ][ # # ]: 0 : m_aPages.back().appendPoint( aPoint, aLine );
9239 [ # # ]: 0 : aLine.append( " m " );
9240 [ # # ]: 0 : if( !basegfx::fTools::equal(fStartAngle, fStopAngle) )
9241 : : {
9242 [ # # ]: 0 : for( int i = 0; i < nFragments; i++ )
9243 : : {
9244 : 0 : const double fStartFragment = fStartAngle + (double)i*fFragmentDelta;
9245 : 0 : const double fStopFragment = fStartFragment + fFragmentDelta;
9246 : 0 : aPoint = Point( (int)(halfWidth * (cos(fStartFragment) - kappa*sin(fStartFragment) ) ),
9247 : 0 : -(int)(halfHeight * (sin(fStartFragment) + kappa*cos(fStartFragment) ) ) );
9248 : 0 : aPoint += aCenter;
9249 [ # # ][ # # ]: 0 : m_aPages.back().appendPoint( aPoint, aLine );
9250 [ # # ]: 0 : aLine.append( ' ' );
9251 : :
9252 : 0 : aPoint = Point( (int)(halfWidth * (cos(fStopFragment) + kappa*sin(fStopFragment) ) ),
9253 : 0 : -(int)(halfHeight * (sin(fStopFragment) - kappa*cos(fStopFragment) ) ) );
9254 : 0 : aPoint += aCenter;
9255 [ # # ][ # # ]: 0 : m_aPages.back().appendPoint( aPoint, aLine );
9256 [ # # ]: 0 : aLine.append( ' ' );
9257 : :
9258 : 0 : aPoint = Point( (int)(halfWidth * cos(fStopFragment) ),
9259 : 0 : -(int)(halfHeight * sin(fStopFragment) ) );
9260 : 0 : aPoint += aCenter;
9261 [ # # ][ # # ]: 0 : m_aPages.back().appendPoint( aPoint, aLine );
9262 [ # # ]: 0 : aLine.append( " c\n" );
9263 : : }
9264 : : }
9265 [ # # ][ # # ]: 0 : if( bWithChord || bWithPie )
9266 : : {
9267 [ # # ]: 0 : if( bWithPie )
9268 : : {
9269 [ # # ][ # # ]: 0 : m_aPages.back().appendPoint( aCenter, aLine );
9270 [ # # ]: 0 : aLine.append( " l " );
9271 : : }
9272 [ # # ]: 0 : aLine.append( "h " );
9273 : : }
9274 [ # # ][ # # ]: 0 : if( ! bWithChord && ! bWithPie )
9275 [ # # ]: 0 : aLine.append( "S\n" );
9276 [ # # ]: 0 : else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) &&
[ # # # # ]
[ # # ]
[ # # # # ]
9277 [ # # ][ # # ]: 0 : m_aGraphicsStack.front().m_aFillColor != Color( COL_TRANSPARENT ) )
[ # # ]
9278 [ # # ]: 0 : aLine.append( "B*\n" );
9279 [ # # ][ # # ]: 0 : else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
9280 [ # # ]: 0 : aLine.append( "S\n" );
9281 : : else
9282 [ # # ]: 0 : aLine.append( "f*\n" );
9283 : :
9284 [ # # ]: 0 : writeBuffer( aLine.getStr(), aLine.getLength() );
9285 : : }
9286 : :
9287 : 0 : void PDFWriterImpl::drawPolyLine( const Polygon& rPoly )
9288 : : {
9289 [ # # ]: 0 : MARK( "drawPolyLine" );
9290 : :
9291 [ # # ]: 0 : sal_uInt16 nPoints = rPoly.GetSize();
9292 [ # # ]: 0 : if( nPoints < 2 )
9293 : : return;
9294 : :
9295 [ # # ]: 0 : updateGraphicsState();
9296 : :
9297 [ # # ][ # # ]: 0 : if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) )
9298 : : return;
9299 : :
9300 : 0 : OStringBuffer aLine( 20 * nPoints );
9301 [ # # ][ # # ]: 0 : m_aPages.back().appendPolygon( rPoly, aLine, rPoly[0] == rPoly[nPoints-1] );
[ # # ][ # # ]
9302 [ # # ]: 0 : aLine.append( "S\n" );
9303 : :
9304 [ # # ]: 0 : writeBuffer( aLine.getStr(), aLine.getLength() );
9305 : : }
9306 : :
9307 : 0 : void PDFWriterImpl::drawPolyLine( const Polygon& rPoly, const LineInfo& rInfo )
9308 : : {
9309 [ # # ]: 0 : MARK( "drawPolyLine with LineInfo" );
9310 : :
9311 [ # # ]: 0 : updateGraphicsState();
9312 : :
9313 [ # # ][ # # ]: 0 : if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) )
9314 : 0 : return;
9315 : :
9316 : 0 : OStringBuffer aLine;
9317 [ # # ]: 0 : aLine.append( "q " );
9318 [ # # ][ # # ]: 0 : if( m_aPages.back().appendLineInfo( rInfo, aLine ) )
[ # # ]
9319 : : {
9320 [ # # ]: 0 : writeBuffer( aLine.getStr(), aLine.getLength() );
9321 [ # # ]: 0 : drawPolyLine( rPoly );
9322 [ # # ]: 0 : writeBuffer( "Q\n", 2 );
9323 : : }
9324 : : else
9325 : : {
9326 [ # # ]: 0 : PDFWriter::ExtLineInfo aInfo;
9327 [ # # ]: 0 : convertLineInfoToExtLineInfo( rInfo, aInfo );
9328 [ # # ]: 0 : drawPolyLine( rPoly, aInfo );
9329 : 0 : }
9330 : : }
9331 : :
9332 : 0 : void PDFWriterImpl::convertLineInfoToExtLineInfo( const LineInfo& rIn, PDFWriter::ExtLineInfo& rOut )
9333 : : {
9334 : : DBG_ASSERT( rIn.GetStyle() == LINE_DASH, "invalid conversion" );
9335 : 0 : rOut.m_fLineWidth = rIn.GetWidth();
9336 : 0 : rOut.m_fTransparency = 0.0;
9337 : 0 : rOut.m_eCap = PDFWriter::capButt;
9338 : 0 : rOut.m_eJoin = PDFWriter::joinMiter;
9339 : 0 : rOut.m_fMiterLimit = 10;
9340 : 0 : rOut.m_aDashArray.clear();
9341 : :
9342 : 0 : int nDashes = rIn.GetDashCount();
9343 : 0 : int nDashLen = rIn.GetDashLen();
9344 : 0 : int nDistance = rIn.GetDistance();
9345 [ # # ]: 0 : for( int n = 0; n < nDashes; n++ )
9346 : : {
9347 [ # # ]: 0 : rOut.m_aDashArray.push_back( nDashLen );
9348 [ # # ]: 0 : rOut.m_aDashArray.push_back( nDistance );
9349 : : }
9350 : 0 : int nDots = rIn.GetDotCount();
9351 : 0 : int nDotLen = rIn.GetDotLen();
9352 [ # # ]: 0 : for( int n = 0; n < nDots; n++ )
9353 : : {
9354 [ # # ]: 0 : rOut.m_aDashArray.push_back( nDotLen );
9355 [ # # ]: 0 : rOut.m_aDashArray.push_back( nDistance );
9356 : : }
9357 : 0 : }
9358 : :
9359 : 0 : void PDFWriterImpl::drawPolyLine( const Polygon& rPoly, const PDFWriter::ExtLineInfo& rInfo )
9360 : : {
9361 [ # # ]: 0 : MARK( "drawPolyLine with ExtLineInfo" );
9362 : :
9363 [ # # ]: 0 : updateGraphicsState();
9364 : :
9365 [ # # ][ # # ]: 0 : if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) )
9366 : : return;
9367 : :
9368 [ # # ]: 0 : if( rInfo.m_fTransparency >= 1.0 )
9369 : : return;
9370 : :
9371 [ # # ]: 0 : if( rInfo.m_fTransparency != 0.0 )
9372 [ # # ]: 0 : beginTransparencyGroup();
9373 : :
9374 : 0 : OStringBuffer aLine;
9375 [ # # ]: 0 : aLine.append( "q " );
9376 [ # # ][ # # ]: 0 : m_aPages.back().appendMappedLength( rInfo.m_fLineWidth, aLine );
9377 [ # # ]: 0 : aLine.append( " w" );
9378 [ # # ]: 0 : if( rInfo.m_aDashArray.size() < 10 ) // implmentation limit of acrobat reader
9379 : : {
9380 [ # # # ]: 0 : switch( rInfo.m_eCap )
9381 : : {
9382 : : default:
9383 [ # # ]: 0 : case PDFWriter::capButt: aLine.append( " 0 J" );break;
9384 [ # # ]: 0 : case PDFWriter::capRound: aLine.append( " 1 J" );break;
9385 [ # # ]: 0 : case PDFWriter::capSquare: aLine.append( " 2 J" );break;
9386 : : }
9387 [ # # # ]: 0 : switch( rInfo.m_eJoin )
9388 : : {
9389 : : default:
9390 : : case PDFWriter::joinMiter:
9391 : : {
9392 : 0 : double fLimit = rInfo.m_fMiterLimit;
9393 [ # # ]: 0 : if( rInfo.m_fLineWidth < rInfo.m_fMiterLimit )
9394 : 0 : fLimit = fLimit / rInfo.m_fLineWidth;
9395 [ # # ]: 0 : if( fLimit < 1.0 )
9396 : 0 : fLimit = 1.0;
9397 [ # # ]: 0 : aLine.append( " 0 j " );
9398 [ # # ]: 0 : appendDouble( fLimit, aLine );
9399 [ # # ]: 0 : aLine.append( " M" );
9400 : : }
9401 : 0 : break;
9402 [ # # ]: 0 : case PDFWriter::joinRound: aLine.append( " 1 j" );break;
9403 [ # # ]: 0 : case PDFWriter::joinBevel: aLine.append( " 2 j" );break;
9404 : : }
9405 [ # # ]: 0 : if( rInfo.m_aDashArray.size() > 0 )
9406 : : {
9407 [ # # ]: 0 : aLine.append( " [ " );
9408 [ # # # # ]: 0 : for( std::vector<double>::const_iterator it = rInfo.m_aDashArray.begin();
[ # # ]
9409 : 0 : it != rInfo.m_aDashArray.end(); ++it )
9410 : : {
9411 [ # # ][ # # ]: 0 : m_aPages.back().appendMappedLength( *it, aLine );
[ # # ]
9412 [ # # ]: 0 : aLine.append( ' ' );
9413 : : }
9414 [ # # ]: 0 : aLine.append( "] 0 d" );
9415 : : }
9416 [ # # ]: 0 : aLine.append( "\n" );
9417 [ # # ]: 0 : writeBuffer( aLine.getStr(), aLine.getLength() );
9418 [ # # ]: 0 : drawPolyLine( rPoly );
9419 : : }
9420 : : else
9421 : : {
9422 [ # # ]: 0 : basegfx::B2DPolygon aPoly(rPoly.getB2DPolygon());
9423 [ # # ]: 0 : basegfx::B2DPolyPolygon aPolyPoly;
9424 : :
9425 [ # # ]: 0 : basegfx::tools::applyLineDashing(aPoly, rInfo.m_aDashArray, &aPolyPoly);
9426 : :
9427 : : // Old applyLineDashing subdivided the polygon. New one will create bezier curve segments.
9428 : : // To mimic old behaviour, apply subdivide here. If beziers shall be written (better quality)
9429 : : // this line needs to be removed and the loop below adapted accordingly
9430 [ # # ][ # # ]: 0 : aPolyPoly = basegfx::tools::adaptiveSubdivideByAngle(aPolyPoly);
[ # # ]
9431 : :
9432 [ # # ]: 0 : const sal_uInt32 nPolygonCount(aPolyPoly.count());
9433 : :
9434 [ # # ]: 0 : for( sal_uInt32 nPoly = 0; nPoly < nPolygonCount; nPoly++ )
9435 : : {
9436 [ # # ][ # # ]: 0 : aLine.append( (nPoly != 0 && (nPoly & 7) == 0) ? "\n" : " " );
[ # # ]
9437 [ # # ][ # # ]: 0 : aPoly = aPolyPoly.getB2DPolygon( nPoly );
[ # # ]
9438 [ # # ]: 0 : const sal_uInt32 nPointCount(aPoly.count());
9439 : :
9440 [ # # ]: 0 : if(nPointCount)
9441 : : {
9442 [ # # ][ # # ]: 0 : const sal_uInt32 nEdgeCount(aPoly.isClosed() ? nPointCount : nPointCount - 1);
9443 [ # # ]: 0 : basegfx::B2DPoint aCurrent(aPoly.getB2DPoint(0));
9444 : :
9445 [ # # ]: 0 : for(sal_uInt32 a(0); a < nEdgeCount; a++)
9446 : : {
9447 [ # # ]: 0 : if( a > 0 )
9448 [ # # ]: 0 : aLine.append( " " );
9449 : 0 : const sal_uInt32 nNextIndex((a + 1) % nPointCount);
9450 [ # # ]: 0 : const basegfx::B2DPoint aNext(aPoly.getB2DPoint(nNextIndex));
9451 : :
9452 [ # # ]: 0 : m_aPages.back().appendPoint( Point( FRound(aCurrent.getX()),
9453 : : FRound(aCurrent.getY()) ),
9454 [ # # ]: 0 : aLine );
9455 [ # # ]: 0 : aLine.append( " m " );
9456 [ # # ]: 0 : m_aPages.back().appendPoint( Point( FRound(aNext.getX()),
9457 : : FRound(aNext.getY()) ),
9458 [ # # ]: 0 : aLine );
9459 [ # # ]: 0 : aLine.append( " l" );
9460 : :
9461 : : // prepare next edge
9462 : 0 : aCurrent = aNext;
9463 : 0 : }
9464 : : }
9465 : : }
9466 [ # # ]: 0 : aLine.append( " S " );
9467 [ # # ][ # # ]: 0 : writeBuffer( aLine.getStr(), aLine.getLength() );
[ # # ]
9468 : : }
9469 [ # # ]: 0 : writeBuffer( "Q\n", 2 );
9470 : :
9471 [ # # ]: 0 : if( rInfo.m_fTransparency != 0.0 )
9472 : : {
9473 : : // FIXME: actually this may be incorrect with bezier polygons
9474 [ # # ]: 0 : Rectangle aBoundRect( rPoly.GetBoundRect() );
9475 : : // avoid clipping with thick lines
9476 [ # # ]: 0 : if( rInfo.m_fLineWidth > 0.0 )
9477 : : {
9478 : 0 : sal_Int32 nLW = sal_Int32(rInfo.m_fLineWidth);
9479 : 0 : aBoundRect.Top() -= nLW;
9480 : 0 : aBoundRect.Left() -= nLW;
9481 : 0 : aBoundRect.Right() += nLW;
9482 : 0 : aBoundRect.Bottom() += nLW;
9483 : : }
9484 [ # # ]: 0 : endTransparencyGroup( aBoundRect, (sal_uInt16)(100.0*rInfo.m_fTransparency) );
9485 : 0 : }
9486 : : }
9487 : :
9488 : 0 : void PDFWriterImpl::drawPixel( const Point& rPoint, const Color& rColor )
9489 : : {
9490 [ # # ]: 0 : MARK( "drawPixel" );
9491 : :
9492 [ # # ][ # # ]: 0 : Color aColor = ( rColor == Color( COL_TRANSPARENT ) ? m_aGraphicsStack.front().m_aLineColor : rColor );
9493 : :
9494 [ # # ]: 0 : if( aColor == Color( COL_TRANSPARENT ) )
9495 : 0 : return;
9496 : :
9497 : : // pixels are drawn in line color, so have to set
9498 : : // the nonstroking color to line color
9499 [ # # ]: 0 : Color aOldFillColor = m_aGraphicsStack.front().m_aFillColor;
9500 [ # # ]: 0 : setFillColor( aColor );
9501 : :
9502 [ # # ]: 0 : updateGraphicsState();
9503 : :
9504 : 0 : OStringBuffer aLine( 20 );
9505 [ # # ][ # # ]: 0 : m_aPages.back().appendPoint( rPoint, aLine );
9506 [ # # ]: 0 : aLine.append( ' ' );
9507 [ # # ][ # # ]: 0 : appendDouble( 1.0/double(getReferenceDevice()->ImplGetDPIX()), aLine );
9508 [ # # ]: 0 : aLine.append( ' ' );
9509 [ # # ][ # # ]: 0 : appendDouble( 1.0/double(getReferenceDevice()->ImplGetDPIY()), aLine );
9510 [ # # ]: 0 : aLine.append( " re f\n" );
9511 [ # # ]: 0 : writeBuffer( aLine.getStr(), aLine.getLength() );
9512 : :
9513 [ # # ]: 0 : setFillColor( aOldFillColor );
9514 : : }
9515 : :
9516 : : class AccessReleaser
9517 : : {
9518 : : BitmapReadAccess* m_pAccess;
9519 : : public:
9520 : 0 : AccessReleaser( BitmapReadAccess* pAccess ) : m_pAccess( pAccess ){}
9521 [ # # ]: 0 : ~AccessReleaser() { delete m_pAccess; }
9522 : : };
9523 : :
9524 : 0 : bool PDFWriterImpl::writeTransparentObject( TransparencyEmit& rObject )
9525 : : {
9526 [ # # ][ # # ]: 0 : CHECK_RETURN( updateObject( rObject.m_nObject ) );
9527 : :
9528 [ # # ]: 0 : bool bFlateFilter = compressStream( rObject.m_pContentStream );
9529 [ # # ]: 0 : rObject.m_pContentStream->Seek( STREAM_SEEK_TO_END );
9530 : 0 : sal_uLong nSize = rObject.m_pContentStream->Tell();
9531 [ # # ]: 0 : rObject.m_pContentStream->Seek( STREAM_SEEK_TO_BEGIN );
9532 : : #if OSL_DEBUG_LEVEL > 1
9533 : : emitComment( "PDFWriterImpl::writeTransparentObject" );
9534 : : #endif
9535 : 0 : OStringBuffer aLine( 512 );
9536 [ # # ][ # # ]: 0 : CHECK_RETURN( updateObject( rObject.m_nObject ) );
9537 [ # # ]: 0 : aLine.append( rObject.m_nObject );
9538 : : aLine.append( " 0 obj\n"
9539 : : "<</Type/XObject\n"
9540 : : "/Subtype/Form\n"
9541 [ # # ]: 0 : "/BBox[ " );
9542 [ # # ]: 0 : appendFixedInt( rObject.m_aBoundRect.Left(), aLine );
9543 [ # # ]: 0 : aLine.append( ' ' );
9544 [ # # ]: 0 : appendFixedInt( rObject.m_aBoundRect.Top(), aLine );
9545 [ # # ]: 0 : aLine.append( ' ' );
9546 [ # # ]: 0 : appendFixedInt( rObject.m_aBoundRect.Right(), aLine );
9547 [ # # ]: 0 : aLine.append( ' ' );
9548 [ # # ]: 0 : appendFixedInt( rObject.m_aBoundRect.Bottom()+1, aLine );
9549 [ # # ]: 0 : aLine.append( " ]\n" );
9550 [ # # ]: 0 : if( ! rObject.m_pSoftMaskStream )
9551 : : {
9552 [ # # ]: 0 : if( ! m_bIsPDF_A1 )
9553 : : {
9554 [ # # ]: 0 : aLine.append( "/Group<</S/Transparency/CS/DeviceRGB/K true>>\n" );
9555 : : }
9556 : : }
9557 : : /* #i42884# the PDF reference recommends that each Form XObject
9558 : : * should have a resource dict; alas if that is the same object
9559 : : * as the one of the page it triggers an endless recursion in
9560 : : * acroread 5 (6 and up have that fixed). Since we have only one
9561 : : * resource dict anyway, let's use the one from the page by NOT
9562 : : * emitting a Resources entry.
9563 : : */
9564 : :
9565 [ # # ]: 0 : aLine.append( "/Length " );
9566 [ # # ]: 0 : aLine.append( (sal_Int32)(nSize) );
9567 [ # # ]: 0 : aLine.append( "\n" );
9568 [ # # ]: 0 : if( bFlateFilter )
9569 [ # # ]: 0 : aLine.append( "/Filter/FlateDecode\n" );
9570 : : aLine.append( ">>\n"
9571 [ # # ]: 0 : "stream\n" );
9572 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
9573 [ # # ]: 0 : checkAndEnableStreamEncryption( rObject.m_nObject );
9574 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( rObject.m_pContentStream->GetData(), nSize ) );
[ # # ]
9575 : 0 : disableStreamEncryption();
9576 [ # # ]: 0 : aLine.setLength( 0 );
9577 : : aLine.append( "\n"
9578 : : "endstream\n"
9579 [ # # ]: 0 : "endobj\n\n" );
9580 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
9581 : :
9582 : : // write ExtGState dict for this XObject
9583 [ # # ]: 0 : aLine.setLength( 0 );
9584 [ # # ]: 0 : aLine.append( rObject.m_nExtGStateObject );
9585 : : aLine.append( " 0 obj\n"
9586 [ # # ]: 0 : "<<" );
9587 [ # # ]: 0 : if( ! rObject.m_pSoftMaskStream )
9588 : : {
9589 : : //i59651
9590 [ # # ]: 0 : if( m_bIsPDF_A1 )
9591 : : {
9592 [ # # ]: 0 : aLine.append( "/CA 1.0/ca 1.0" );
9593 [ # # ]: 0 : m_aErrors.insert( PDFWriter::Warning_Transparency_Omitted_PDFA );
9594 : : }
9595 : : else
9596 : : {
9597 [ # # ]: 0 : aLine.append( "/CA " );
9598 [ # # ]: 0 : appendDouble( rObject.m_fAlpha, aLine );
9599 : : aLine.append( "\n"
9600 [ # # ]: 0 : " /ca " );
9601 [ # # ]: 0 : appendDouble( rObject.m_fAlpha, aLine );
9602 : : }
9603 [ # # ]: 0 : aLine.append( "\n" );
9604 : : }
9605 : : else
9606 : : {
9607 [ # # ]: 0 : if( m_bIsPDF_A1 )
9608 : : {
9609 [ # # ]: 0 : aLine.append( "/SMask/None" );
9610 [ # # ]: 0 : m_aErrors.insert( PDFWriter::Warning_Transparency_Omitted_PDFA );
9611 : : }
9612 : : else
9613 : : {
9614 [ # # ]: 0 : rObject.m_pSoftMaskStream->Seek( STREAM_SEEK_TO_END );
9615 : 0 : sal_Int32 nMaskSize = (sal_Int32)rObject.m_pSoftMaskStream->Tell();
9616 [ # # ]: 0 : rObject.m_pSoftMaskStream->Seek( STREAM_SEEK_TO_BEGIN );
9617 [ # # ]: 0 : sal_Int32 nMaskObject = createObject();
9618 [ # # ]: 0 : aLine.append( "/SMask<</Type/Mask/S/Luminosity/G " );
9619 [ # # ]: 0 : aLine.append( nMaskObject );
9620 [ # # ]: 0 : aLine.append( " 0 R>>\n" );
9621 : :
9622 : 0 : OStringBuffer aMask;
9623 [ # # ]: 0 : aMask.append( nMaskObject );
9624 : : aMask.append( " 0 obj\n"
9625 : : "<</Type/XObject\n"
9626 : : "/Subtype/Form\n"
9627 [ # # ]: 0 : "/BBox[" );
9628 [ # # ]: 0 : appendFixedInt( rObject.m_aBoundRect.Left(), aMask );
9629 [ # # ]: 0 : aMask.append( ' ' );
9630 [ # # ]: 0 : appendFixedInt( rObject.m_aBoundRect.Top(), aMask );
9631 [ # # ]: 0 : aMask.append( ' ' );
9632 [ # # ]: 0 : appendFixedInt( rObject.m_aBoundRect.Right(), aMask );
9633 [ # # ]: 0 : aMask.append( ' ' );
9634 [ # # ]: 0 : appendFixedInt( rObject.m_aBoundRect.Bottom()+1, aMask );
9635 [ # # ]: 0 : aMask.append( "]\n" );
9636 : :
9637 : : /* #i42884# see above */
9638 [ # # ]: 0 : aMask.append( "/Group<</S/Transparency/CS/DeviceRGB>>\n" );
9639 [ # # ]: 0 : aMask.append( "/Length " );
9640 [ # # ]: 0 : aMask.append( nMaskSize );
9641 : : aMask.append( ">>\n"
9642 [ # # ]: 0 : "stream\n" );
9643 [ # # ][ # # ]: 0 : CHECK_RETURN( updateObject( nMaskObject ) );
9644 [ # # ]: 0 : checkAndEnableStreamEncryption( nMaskObject );
9645 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aMask.getStr(), aMask.getLength() ) );
9646 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( rObject.m_pSoftMaskStream->GetData(), nMaskSize ) );
[ # # ]
9647 : 0 : disableStreamEncryption();
9648 [ # # ]: 0 : aMask.setLength( 0 );
9649 : : aMask.append( "\nendstream\n"
9650 [ # # ]: 0 : "endobj\n\n" );
9651 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aMask.getStr(), aMask.getLength() ) );
[ # # ]
9652 : : }
9653 : : }
9654 : : aLine.append( ">>\n"
9655 [ # # ]: 0 : "endobj\n\n" );
9656 [ # # ][ # # ]: 0 : CHECK_RETURN( updateObject( rObject.m_nExtGStateObject ) );
9657 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
9658 : :
9659 : 0 : return true;
9660 : : }
9661 : :
9662 : 0 : bool PDFWriterImpl::writeGradientFunction( GradientEmit& rObject )
9663 : : {
9664 [ # # ]: 0 : sal_Int32 nFunctionObject = createObject();
9665 [ # # ][ # # ]: 0 : CHECK_RETURN( updateObject( nFunctionObject ) );
9666 : :
9667 [ # # ]: 0 : VirtualDevice aDev;
9668 [ # # ]: 0 : aDev.SetOutputSizePixel( rObject.m_aSize );
9669 [ # # ][ # # ]: 0 : aDev.SetMapMode( MapMode( MAP_PIXEL ) );
[ # # ]
9670 [ # # ]: 0 : if( m_aContext.ColorMode == PDFWriter::DrawGreyscale )
9671 : 0 : aDev.SetDrawMode( aDev.GetDrawMode() |
9672 : : ( DRAWMODE_GRAYLINE | DRAWMODE_GRAYFILL | DRAWMODE_GRAYTEXT |
9673 [ # # ]: 0 : DRAWMODE_GRAYBITMAP | DRAWMODE_GRAYGRADIENT ) );
9674 [ # # ][ # # ]: 0 : aDev.DrawGradient( Rectangle( Point( 0, 0 ), rObject.m_aSize ), rObject.m_aGradient );
9675 : :
9676 [ # # ]: 0 : Bitmap aSample = aDev.GetBitmap( Point( 0, 0 ), rObject.m_aSize );
9677 [ # # ]: 0 : BitmapReadAccess* pAccess = aSample.AcquireReadAccess();
9678 : 0 : AccessReleaser aReleaser( pAccess );
9679 : :
9680 [ # # ]: 0 : Size aSize = aSample.GetSizePixel();
9681 : :
9682 [ # # ]: 0 : sal_Int32 nStreamLengthObject = createObject();
9683 : : #if OSL_DEBUG_LEVEL > 1
9684 : : emitComment( "PDFWriterImpl::writeGradientFunction" );
9685 : : #endif
9686 : 0 : OStringBuffer aLine( 120 );
9687 [ # # ]: 0 : aLine.append( nFunctionObject );
9688 : : aLine.append( " 0 obj\n"
9689 : : "<</FunctionType 0\n"
9690 : : "/Domain[ 0 1 0 1 ]\n"
9691 [ # # ]: 0 : "/Size[ " );
9692 [ # # ]: 0 : aLine.append( (sal_Int32)aSize.Width() );
9693 [ # # ]: 0 : aLine.append( ' ' );
9694 [ # # ]: 0 : aLine.append( (sal_Int32)aSize.Height() );
9695 : : aLine.append( " ]\n"
9696 : : "/BitsPerSample 8\n"
9697 : : "/Range[ 0 1 0 1 0 1 ]\n"
9698 : : "/Order 3\n"
9699 [ # # ]: 0 : "/Length " );
9700 [ # # ]: 0 : aLine.append( nStreamLengthObject );
9701 : : aLine.append( " 0 R\n"
9702 : : #ifndef DEBUG_DISABLE_PDFCOMPRESSION
9703 : : "/Filter/FlateDecode"
9704 : : #endif
9705 : : ">>\n"
9706 [ # # ]: 0 : "stream\n" );
9707 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
9708 : :
9709 : 0 : sal_uInt64 nStartStreamPos = 0;
9710 [ # # ][ # # ]: 0 : CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nStartStreamPos )) );
9711 : :
9712 [ # # ]: 0 : checkAndEnableStreamEncryption( nFunctionObject );
9713 [ # # ]: 0 : beginCompression();
9714 [ # # ]: 0 : for( int y = aSize.Height()-1; y >= 0; y-- )
9715 : : {
9716 [ # # ]: 0 : for( int x = 0; x < aSize.Width(); x++ )
9717 : : {
9718 : : sal_uInt8 aCol[3];
9719 [ # # ]: 0 : BitmapColor aColor = pAccess->GetColor( y, x );
9720 : 0 : aCol[0] = aColor.GetRed();
9721 : 0 : aCol[1] = aColor.GetGreen();
9722 : 0 : aCol[2] = aColor.GetBlue();
9723 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aCol, 3 ) );
9724 [ # # ]: 0 : }
9725 : : }
9726 [ # # ]: 0 : endCompression();
9727 : 0 : disableStreamEncryption();
9728 : :
9729 : 0 : sal_uInt64 nEndStreamPos = 0;
9730 [ # # ][ # # ]: 0 : CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nEndStreamPos )) );
9731 : :
9732 [ # # ]: 0 : aLine.setLength( 0 );
9733 [ # # ]: 0 : aLine.append( "\nendstream\nendobj\n\n" );
9734 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
9735 : :
9736 : : // write stream length
9737 [ # # ][ # # ]: 0 : CHECK_RETURN( updateObject( nStreamLengthObject ) );
9738 [ # # ]: 0 : aLine.setLength( 0 );
9739 [ # # ]: 0 : aLine.append( nStreamLengthObject );
9740 [ # # ]: 0 : aLine.append( " 0 obj\n" );
9741 [ # # ]: 0 : aLine.append( (sal_Int64)(nEndStreamPos-nStartStreamPos) );
9742 [ # # ]: 0 : aLine.append( "\nendobj\n\n" );
9743 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
9744 : :
9745 [ # # ][ # # ]: 0 : CHECK_RETURN( updateObject( rObject.m_nObject ) );
9746 [ # # ]: 0 : aLine.setLength( 0 );
9747 [ # # ]: 0 : aLine.append( rObject.m_nObject );
9748 : : aLine.append( " 0 obj\n"
9749 : : "<</ShadingType 1\n"
9750 : : "/ColorSpace/DeviceRGB\n"
9751 : : "/AntiAlias true\n"
9752 : : "/Domain[ 0 1 0 1 ]\n"
9753 [ # # ]: 0 : "/Matrix[ " );
9754 [ # # ]: 0 : aLine.append( (sal_Int32)aSize.Width() );
9755 [ # # ]: 0 : aLine.append( " 0 0 " );
9756 [ # # ]: 0 : aLine.append( (sal_Int32)aSize.Height() );
9757 : : aLine.append( " 0 0 ]\n"
9758 [ # # ]: 0 : "/Function " );
9759 [ # # ]: 0 : aLine.append( nFunctionObject );
9760 : : aLine.append( " 0 R\n"
9761 : : ">>\n"
9762 [ # # ]: 0 : "endobj\n\n" );
9763 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
9764 : :
9765 [ # # ][ # # ]: 0 : return true;
[ # # ]
9766 : : }
9767 : :
9768 : 0 : bool PDFWriterImpl::writeJPG( JPGEmit& rObject )
9769 : : {
9770 [ # # ]: 0 : CHECK_RETURN( rObject.m_pStream );
9771 [ # # ][ # # ]: 0 : CHECK_RETURN( updateObject( rObject.m_nObject ) );
9772 : :
9773 : 0 : sal_Int32 nLength = 0;
9774 [ # # ]: 0 : rObject.m_pStream->Seek( STREAM_SEEK_TO_END );
9775 : 0 : nLength = rObject.m_pStream->Tell();
9776 [ # # ]: 0 : rObject.m_pStream->Seek( STREAM_SEEK_TO_BEGIN );
9777 : :
9778 : 0 : sal_Int32 nMaskObject = 0;
9779 [ # # ]: 0 : if( !!rObject.m_aMask )
9780 : : {
9781 [ # # ][ # # ]: 0 : if( rObject.m_aMask.GetBitCount() == 1 ||
[ # # ][ # # ]
[ # # ][ # # ]
9782 [ # # ]: 0 : ( rObject.m_aMask.GetBitCount() == 8 && m_aContext.Version >= PDFWriter::PDF_1_4 && !m_bIsPDF_A1 )//i59651
9783 : : )
9784 : : {
9785 [ # # ]: 0 : nMaskObject = createObject();
9786 : : }
9787 [ # # ]: 0 : else if( m_bIsPDF_A1 )
9788 [ # # ]: 0 : m_aErrors.insert( PDFWriter::Warning_Transparency_Omitted_PDFA );
9789 [ # # ]: 0 : else if( m_aContext.Version < PDFWriter::PDF_1_4 )
9790 [ # # ]: 0 : m_aErrors.insert( PDFWriter::Warning_Transparency_Omitted_PDF13 );
9791 : :
9792 : : }
9793 : : #if OSL_DEBUG_LEVEL > 1
9794 : : emitComment( "PDFWriterImpl::writeJPG" );
9795 : : #endif
9796 : :
9797 : 0 : OStringBuffer aLine(200);
9798 [ # # ]: 0 : aLine.append( rObject.m_nObject );
9799 : : aLine.append( " 0 obj\n"
9800 [ # # ]: 0 : "<</Type/XObject/Subtype/Image/Width " );
9801 [ # # ]: 0 : aLine.append( (sal_Int32)rObject.m_aID.m_aPixelSize.Width() );
9802 [ # # ]: 0 : aLine.append( " /Height " );
9803 [ # # ]: 0 : aLine.append( (sal_Int32)rObject.m_aID.m_aPixelSize.Height() );
9804 [ # # ]: 0 : aLine.append( " /BitsPerComponent 8 " );
9805 [ # # ]: 0 : if( rObject.m_bTrueColor )
9806 [ # # ]: 0 : aLine.append( "/ColorSpace/DeviceRGB" );
9807 : : else
9808 [ # # ]: 0 : aLine.append( "/ColorSpace/DeviceGray" );
9809 [ # # ]: 0 : aLine.append( "/Filter/DCTDecode/Length " );
9810 [ # # ]: 0 : aLine.append( nLength );
9811 [ # # ]: 0 : if( nMaskObject )
9812 : : {
9813 [ # # ][ # # ]: 0 : aLine.append( rObject.m_aMask.GetBitCount() == 1 ? " /Mask " : " /SMask " );
[ # # ]
9814 [ # # ]: 0 : aLine.append( nMaskObject );
9815 [ # # ]: 0 : aLine.append( " 0 R " );
9816 : : }
9817 [ # # ]: 0 : aLine.append( ">>\nstream\n" );
9818 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
9819 : :
9820 [ # # ]: 0 : checkAndEnableStreamEncryption( rObject.m_nObject );
9821 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( rObject.m_pStream->GetData(), nLength ) );
[ # # ]
9822 : 0 : disableStreamEncryption();
9823 : :
9824 [ # # ]: 0 : aLine.setLength( 0 );
9825 [ # # ]: 0 : aLine.append( "\nendstream\nendobj\n\n" );
9826 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
9827 : :
9828 [ # # ]: 0 : if( nMaskObject )
9829 : : {
9830 [ # # ]: 0 : BitmapEmit aEmit;
9831 : 0 : aEmit.m_nObject = nMaskObject;
9832 [ # # ][ # # ]: 0 : if( rObject.m_aMask.GetBitCount() == 1 )
9833 [ # # ][ # # ]: 0 : aEmit.m_aBitmap = BitmapEx( rObject.m_aMask, rObject.m_aMask );
[ # # ]
9834 [ # # ][ # # ]: 0 : else if( rObject.m_aMask.GetBitCount() == 8 )
9835 [ # # ][ # # ]: 0 : aEmit.m_aBitmap = BitmapEx( rObject.m_aMask, AlphaMask( rObject.m_aMask ) );
[ # # ][ # # ]
[ # # ]
9836 [ # # ][ # # ]: 0 : writeBitmapObject( aEmit, true );
9837 : : }
9838 : :
9839 : 0 : return true;
9840 : : }
9841 : :
9842 : 0 : bool PDFWriterImpl::writeBitmapObject( BitmapEmit& rObject, bool bMask )
9843 : : {
9844 [ # # ][ # # ]: 0 : CHECK_RETURN( updateObject( rObject.m_nObject ) );
9845 : :
9846 [ # # ]: 0 : Bitmap aBitmap;
9847 : 0 : Color aTransparentColor( COL_TRANSPARENT );
9848 : 0 : bool bWriteMask = false;
9849 [ # # ]: 0 : if( ! bMask )
9850 : : {
9851 [ # # ][ # # ]: 0 : aBitmap = rObject.m_aBitmap.GetBitmap();
[ # # ]
9852 [ # # ][ # # ]: 0 : if( rObject.m_aBitmap.IsAlpha() )
9853 : : {
9854 [ # # ]: 0 : if( m_aContext.Version >= PDFWriter::PDF_1_4 )
9855 : 0 : bWriteMask = true;
9856 : : // else draw without alpha channel
9857 : : }
9858 : : else
9859 : : {
9860 [ # # # # ]: 0 : switch( rObject.m_aBitmap.GetTransparentType() )
9861 : : {
9862 : : case TRANSPARENT_NONE:
9863 : : // comes from drawMask function
9864 [ # # ][ # # ]: 0 : if( aBitmap.GetBitCount() == 1 && rObject.m_bDrawMask )
[ # # ][ # # ]
9865 : 0 : bMask = true;
9866 : 0 : break;
9867 : : case TRANSPARENT_COLOR:
9868 : 0 : aTransparentColor = rObject.m_aBitmap.GetTransparentColor();
9869 : 0 : break;
9870 : : case TRANSPARENT_BITMAP:
9871 : 0 : bWriteMask = true;
9872 : 0 : break;
9873 : : }
9874 : : }
9875 : : }
9876 : : else
9877 : : {
9878 [ # # ][ # # ]: 0 : if( m_aContext.Version < PDFWriter::PDF_1_4 || ! rObject.m_aBitmap.IsAlpha() )
[ # # ][ # # ]
9879 : : {
9880 [ # # ][ # # ]: 0 : aBitmap = rObject.m_aBitmap.GetMask();
[ # # ]
9881 [ # # ]: 0 : aBitmap.Convert( BMP_CONVERSION_1BIT_THRESHOLD );
9882 : : DBG_ASSERT( aBitmap.GetBitCount() == 1, "mask conversion failed" );
9883 : : }
9884 [ # # ][ # # ]: 0 : else if( aBitmap.GetBitCount() != 8 )
9885 : : {
9886 [ # # ][ # # ]: 0 : aBitmap = rObject.m_aBitmap.GetAlpha().GetBitmap();
[ # # ][ # # ]
[ # # ]
9887 [ # # ]: 0 : aBitmap.Convert( BMP_CONVERSION_8BIT_GREYS );
9888 : : DBG_ASSERT( aBitmap.GetBitCount() == 8, "alpha mask conversion failed" );
9889 : : }
9890 : : }
9891 : :
9892 [ # # ]: 0 : BitmapReadAccess* pAccess = aBitmap.AcquireReadAccess();
9893 : 0 : AccessReleaser aReleaser( pAccess );
9894 : :
9895 : : bool bTrueColor;
9896 : : sal_Int32 nBitsPerComponent;
9897 [ # # ][ # # ]: 0 : switch( aBitmap.GetBitCount() )
9898 : : {
9899 : : case 1:
9900 : : case 2:
9901 : : case 4:
9902 : : case 8:
9903 : 0 : bTrueColor = false;
9904 [ # # ]: 0 : nBitsPerComponent = aBitmap.GetBitCount();
9905 : 0 : break;
9906 : : default:
9907 : 0 : bTrueColor = true;
9908 : 0 : nBitsPerComponent = 8;
9909 : 0 : break;
9910 : : }
9911 : :
9912 [ # # ]: 0 : sal_Int32 nStreamLengthObject = createObject();
9913 : 0 : sal_Int32 nMaskObject = 0;
9914 : :
9915 : : #if OSL_DEBUG_LEVEL > 1
9916 : : emitComment( "PDFWriterImpl::writeBitmapObject" );
9917 : : #endif
9918 : 0 : OStringBuffer aLine(1024);
9919 [ # # ]: 0 : aLine.append( rObject.m_nObject );
9920 : : aLine.append( " 0 obj\n"
9921 [ # # ]: 0 : "<</Type/XObject/Subtype/Image/Width " );
9922 [ # # ][ # # ]: 0 : aLine.append( (sal_Int32)aBitmap.GetSizePixel().Width() );
9923 [ # # ]: 0 : aLine.append( "/Height " );
9924 [ # # ][ # # ]: 0 : aLine.append( (sal_Int32)aBitmap.GetSizePixel().Height() );
9925 [ # # ]: 0 : aLine.append( "/BitsPerComponent " );
9926 [ # # ]: 0 : aLine.append( nBitsPerComponent );
9927 [ # # ]: 0 : aLine.append( "/Length " );
9928 [ # # ]: 0 : aLine.append( nStreamLengthObject );
9929 [ # # ]: 0 : aLine.append( " 0 R\n" );
9930 : : #ifndef DEBUG_DISABLE_PDFCOMPRESSION
9931 [ # # ]: 0 : if( nBitsPerComponent != 1 )
9932 : : {
9933 [ # # ]: 0 : aLine.append( "/Filter/FlateDecode" );
9934 : : }
9935 : : else
9936 : : {
9937 [ # # ]: 0 : aLine.append( "/Filter/CCITTFaxDecode/DecodeParms<</K -1/BlackIs1 true/Columns " );
9938 [ # # ][ # # ]: 0 : aLine.append( (sal_Int32)aBitmap.GetSizePixel().Width() );
9939 [ # # ]: 0 : aLine.append( ">>\n" );
9940 : : }
9941 : : #endif
9942 [ # # ]: 0 : if( ! bMask )
9943 : : {
9944 [ # # ]: 0 : aLine.append( "/ColorSpace" );
9945 [ # # ]: 0 : if( bTrueColor )
9946 [ # # ]: 0 : aLine.append( "/DeviceRGB\n" );
9947 [ # # ][ # # ]: 0 : else if( aBitmap.HasGreyPalette() )
9948 : : {
9949 [ # # ]: 0 : aLine.append( "/DeviceGray\n" );
9950 [ # # ][ # # ]: 0 : if( aBitmap.GetBitCount() == 1 )
9951 : : {
9952 : : // #i47395# 1 bit bitmaps occasionally have an inverted grey palette
9953 [ # # ]: 0 : sal_Int32 nBlackIndex = pAccess->GetBestPaletteIndex( BitmapColor( Color( COL_BLACK ) ) );
9954 : : DBG_ASSERT( nBlackIndex == 0 || nBlackIndex == 1, "wrong black index" );
9955 [ # # ]: 0 : if( nBlackIndex == 1 )
9956 [ # # ]: 0 : aLine.append( "/Decode[1 0]\n" );
9957 : : }
9958 : : }
9959 : : else
9960 : : {
9961 [ # # ]: 0 : aLine.append( "[ /Indexed/DeviceRGB " );
9962 [ # # ]: 0 : aLine.append( (sal_Int32)(pAccess->GetPaletteEntryCount()-1) );
9963 [ # # ]: 0 : aLine.append( "\n<" );
9964 [ # # ]: 0 : if( m_aContext.Encryption.Encrypt() )
9965 : : {
9966 [ # # ]: 0 : enableStringEncryption( rObject.m_nObject );
9967 : : //check encryption buffer size
9968 [ # # ][ # # ]: 0 : if( checkEncryptionBufferSize( pAccess->GetPaletteEntryCount()*3 ) )
9969 : : {
9970 : 0 : int nChar = 0;
9971 : : //fill the encryption buffer
9972 [ # # ]: 0 : for( sal_uInt16 i = 0; i < pAccess->GetPaletteEntryCount(); i++ )
9973 : : {
9974 : 0 : const BitmapColor& rColor = pAccess->GetPaletteColor( i );
9975 : 0 : m_pEncryptionBuffer[nChar++] = rColor.GetRed();
9976 : 0 : m_pEncryptionBuffer[nChar++] = rColor.GetGreen();
9977 : 0 : m_pEncryptionBuffer[nChar++] = rColor.GetBlue();
9978 : : }
9979 : : //encrypt the colorspace lookup table
9980 : 0 : rtl_cipher_encodeARCFOUR( m_aCipher, m_pEncryptionBuffer, nChar, m_pEncryptionBuffer, nChar );
9981 : : //now queue the data for output
9982 : 0 : nChar = 0;
9983 [ # # ]: 0 : for( sal_uInt16 i = 0; i < pAccess->GetPaletteEntryCount(); i++ )
9984 : : {
9985 [ # # ]: 0 : appendHex(m_pEncryptionBuffer[nChar++], aLine );
9986 [ # # ]: 0 : appendHex(m_pEncryptionBuffer[nChar++], aLine );
9987 [ # # ]: 0 : appendHex(m_pEncryptionBuffer[nChar++], aLine );
9988 : : }
9989 : : }
9990 : : }
9991 : : else //no encryption requested (PDF/A-1a program flow drops here)
9992 : : {
9993 [ # # ]: 0 : for( sal_uInt16 i = 0; i < pAccess->GetPaletteEntryCount(); i++ )
9994 : : {
9995 : 0 : const BitmapColor& rColor = pAccess->GetPaletteColor( i );
9996 [ # # ]: 0 : appendHex( rColor.GetRed(), aLine );
9997 [ # # ]: 0 : appendHex( rColor.GetGreen(), aLine );
9998 [ # # ]: 0 : appendHex( rColor.GetBlue(), aLine );
9999 : : }
10000 : : }
10001 [ # # ]: 0 : aLine.append( ">\n]\n" );
10002 : : }
10003 : : }
10004 : : else
10005 : : {
10006 [ # # ][ # # ]: 0 : if( aBitmap.GetBitCount() == 1 )
10007 : : {
10008 [ # # ]: 0 : aLine.append( "/ImageMask true\n" );
10009 [ # # ]: 0 : sal_Int32 nBlackIndex = pAccess->GetBestPaletteIndex( BitmapColor( Color( COL_BLACK ) ) );
10010 : : DBG_ASSERT( nBlackIndex == 0 || nBlackIndex == 1, "wrong black index" );
10011 [ # # ]: 0 : if( nBlackIndex )
10012 [ # # ]: 0 : aLine.append( "/Decode[ 1 0 ]\n" );
10013 : : else
10014 [ # # ]: 0 : aLine.append( "/Decode[ 0 1 ]\n" );
10015 : : }
10016 [ # # ][ # # ]: 0 : else if( aBitmap.GetBitCount() == 8 )
10017 : : {
10018 : : aLine.append( "/ColorSpace/DeviceGray\n"
10019 [ # # ]: 0 : "/Decode [ 1 0 ]\n" );
10020 : : }
10021 : : }
10022 : :
10023 [ # # ][ # # ]: 0 : if( ! bMask && m_aContext.Version > PDFWriter::PDF_1_2 && !m_bIsPDF_A1 )//i59651
[ # # ]
10024 : : {
10025 [ # # ]: 0 : if( bWriteMask )
10026 : : {
10027 [ # # ]: 0 : nMaskObject = createObject();
10028 [ # # ][ # # ]: 0 : if( rObject.m_aBitmap.IsAlpha() && m_aContext.Version > PDFWriter::PDF_1_3 )
[ # # ][ # # ]
10029 [ # # ]: 0 : aLine.append( "/SMask " );
10030 : : else
10031 [ # # ]: 0 : aLine.append( "/Mask " );
10032 [ # # ]: 0 : aLine.append( nMaskObject );
10033 [ # # ]: 0 : aLine.append( " 0 R\n" );
10034 : : }
10035 [ # # ]: 0 : else if( aTransparentColor != Color( COL_TRANSPARENT ) )
10036 : : {
10037 [ # # ]: 0 : aLine.append( "/Mask[ " );
10038 [ # # ]: 0 : if( bTrueColor )
10039 : : {
10040 [ # # ]: 0 : aLine.append( (sal_Int32)aTransparentColor.GetRed() );
10041 [ # # ]: 0 : aLine.append( ' ' );
10042 [ # # ]: 0 : aLine.append( (sal_Int32)aTransparentColor.GetRed() );
10043 [ # # ]: 0 : aLine.append( ' ' );
10044 [ # # ]: 0 : aLine.append( (sal_Int32)aTransparentColor.GetGreen() );
10045 [ # # ]: 0 : aLine.append( ' ' );
10046 [ # # ]: 0 : aLine.append( (sal_Int32)aTransparentColor.GetGreen() );
10047 [ # # ]: 0 : aLine.append( ' ' );
10048 [ # # ]: 0 : aLine.append( (sal_Int32)aTransparentColor.GetBlue() );
10049 [ # # ]: 0 : aLine.append( ' ' );
10050 [ # # ]: 0 : aLine.append( (sal_Int32)aTransparentColor.GetBlue() );
10051 : : }
10052 : : else
10053 : : {
10054 [ # # ]: 0 : sal_Int32 nIndex = pAccess->GetBestPaletteIndex( BitmapColor( aTransparentColor ) );
10055 [ # # ]: 0 : aLine.append( nIndex );
10056 : : }
10057 [ # # ]: 0 : aLine.append( " ]\n" );
10058 : 0 : }
10059 : : }
10060 [ # # ][ # # ]: 0 : else if( m_bIsPDF_A1 && (bWriteMask || aTransparentColor != Color( COL_TRANSPARENT )) )
[ # # ][ # # ]
[ # # ]
10061 [ # # ]: 0 : m_aErrors.insert( PDFWriter::Warning_Transparency_Omitted_PDFA );
10062 : :
10063 : : aLine.append( ">>\n"
10064 [ # # ]: 0 : "stream\n" );
10065 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
10066 : 0 : sal_uInt64 nStartPos = 0;
10067 [ # # ][ # # ]: 0 : CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nStartPos )) );
10068 : :
10069 [ # # ]: 0 : checkAndEnableStreamEncryption( rObject.m_nObject );
10070 : : #ifndef DEBUG_DISABLE_PDFCOMPRESSION
10071 [ # # ]: 0 : if( nBitsPerComponent == 1 )
10072 : : {
10073 [ # # ]: 0 : writeG4Stream( pAccess );
10074 : : }
10075 : : else
10076 : : #endif
10077 : : {
10078 [ # # ]: 0 : beginCompression();
10079 [ # # ][ # # ]: 0 : if( ! bTrueColor || pAccess->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB )
[ # # ]
10080 : : {
10081 : 0 : const int nScanLineBytes = 1 + ( pAccess->GetBitCount() * ( pAccess->Width() - 1 ) / 8U );
10082 : :
10083 [ # # ]: 0 : for( int i = 0; i < pAccess->Height(); i++ )
10084 : : {
10085 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( pAccess->GetScanline( i ), nScanLineBytes ) );
10086 : : }
10087 : : }
10088 : : else
10089 : : {
10090 : 0 : const int nScanLineBytes = pAccess->Width()*3;
10091 [ # # ][ # # ]: 0 : boost::shared_array<sal_uInt8> pCol( new sal_uInt8[ nScanLineBytes ] );
10092 [ # # ]: 0 : for( int y = 0; y < pAccess->Height(); y++ )
10093 : : {
10094 [ # # ]: 0 : for( int x = 0; x < pAccess->Width(); x++ )
10095 : : {
10096 [ # # ]: 0 : BitmapColor aColor = pAccess->GetColor( y, x );
10097 : 0 : pCol[3*x+0] = aColor.GetRed();
10098 : 0 : pCol[3*x+1] = aColor.GetGreen();
10099 : 0 : pCol[3*x+2] = aColor.GetBlue();
10100 : 0 : }
10101 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( pCol.get(), nScanLineBytes ) );
10102 [ # # ][ # # ]: 0 : }
10103 : : }
10104 [ # # ]: 0 : endCompression();
10105 : : }
10106 : 0 : disableStreamEncryption();
10107 : :
10108 : 0 : sal_uInt64 nEndPos = 0;
10109 [ # # ][ # # ]: 0 : CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nEndPos )) );
10110 [ # # ]: 0 : aLine.setLength( 0 );
10111 [ # # ]: 0 : aLine.append( "\nendstream\nendobj\n\n" );
10112 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
10113 [ # # ][ # # ]: 0 : CHECK_RETURN( updateObject( nStreamLengthObject ) );
10114 [ # # ]: 0 : aLine.setLength( 0 );
10115 [ # # ]: 0 : aLine.append( nStreamLengthObject );
10116 [ # # ]: 0 : aLine.append( " 0 obj\n" );
10117 [ # # ]: 0 : aLine.append( (sal_Int64)(nEndPos-nStartPos) );
10118 [ # # ]: 0 : aLine.append( "\nendobj\n\n" );
10119 [ # # ][ # # ]: 0 : CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
10120 : :
10121 [ # # ]: 0 : if( nMaskObject )
10122 : : {
10123 [ # # ]: 0 : BitmapEmit aEmit;
10124 : 0 : aEmit.m_nObject = nMaskObject;
10125 [ # # ]: 0 : aEmit.m_aBitmap = rObject.m_aBitmap;
10126 [ # # ][ # # ]: 0 : return writeBitmapObject( aEmit, true );
10127 : : }
10128 : :
10129 [ # # ][ # # ]: 0 : return true;
10130 : : }
10131 : :
10132 : 0 : void PDFWriterImpl::drawJPGBitmap( SvStream& rDCTData, bool bIsTrueColor, const Size& rSizePixel, const Rectangle& rTargetArea, const Bitmap& rMask )
10133 : : {
10134 [ # # ]: 0 : MARK( "drawJPGBitmap" );
10135 : :
10136 : 0 : OStringBuffer aLine( 80 );
10137 [ # # ]: 0 : updateGraphicsState();
10138 : :
10139 : : // #i40055# sanity check
10140 [ # # ][ # # ]: 0 : if( ! (rTargetArea.GetWidth() && rTargetArea.GetHeight() ) )
[ # # ][ # # ]
[ # # ]
10141 : : return;
10142 [ # # ][ # # ]: 0 : if( ! (rSizePixel.Width() && rSizePixel.Height()) )
[ # # ]
10143 : : return;
10144 : :
10145 [ # # ]: 0 : rDCTData.Seek( 0 );
10146 [ # # ][ # # ]: 0 : if( bIsTrueColor && m_aContext.ColorMode == PDFWriter::DrawGreyscale )
10147 : : {
10148 : : // need to convert to grayscale;
10149 : : // load stream to bitmap and draw the bitmap instead
10150 [ # # ]: 0 : Graphic aGraphic;
10151 [ # # ]: 0 : GraphicConverter::Import( rDCTData, aGraphic, CVT_JPG );
10152 [ # # ]: 0 : Bitmap aBmp( aGraphic.GetBitmap() );
10153 [ # # ][ # # ]: 0 : if( !!rMask && rMask.GetSizePixel() == aBmp.GetSizePixel() )
[ # # ][ # # ]
[ # # ][ # # ]
[ # # # #
# # ]
10154 : : {
10155 [ # # ]: 0 : BitmapEx aBmpEx( aBmp, rMask );
10156 [ # # ][ # # ]: 0 : drawBitmap( rTargetArea.TopLeft(), rTargetArea.GetSize(), aBmpEx );
[ # # ]
10157 : : }
10158 : : else
10159 [ # # ][ # # ]: 0 : drawBitmap( rTargetArea.TopLeft(), rTargetArea.GetSize(), aBmp );
10160 [ # # ][ # # ]: 0 : return;
10161 : : }
10162 : :
10163 [ # # ][ # # ]: 0 : SvMemoryStream* pStream = new SvMemoryStream;
10164 [ # # ]: 0 : *pStream << rDCTData;
10165 [ # # ]: 0 : pStream->Seek( STREAM_SEEK_TO_END );
10166 : :
10167 : 0 : BitmapID aID;
10168 : 0 : aID.m_aPixelSize = rSizePixel;
10169 : 0 : aID.m_nSize = pStream->Tell();
10170 [ # # ]: 0 : pStream->Seek( STREAM_SEEK_TO_BEGIN );
10171 [ # # ]: 0 : aID.m_nChecksum = rtl_crc32( 0, pStream->GetData(), aID.m_nSize );
10172 [ # # ]: 0 : if( ! rMask.IsEmpty() )
10173 [ # # ]: 0 : aID.m_nMaskChecksum = rMask.GetChecksum();
10174 : :
10175 : 0 : std::list< JPGEmit >::const_iterator it;
10176 [ # # ][ # # ]: 0 : for( it = m_aJPGs.begin(); it != m_aJPGs.end() && ! (aID == it->m_aID); ++it )
[ # # ][ # # ]
[ # # ]
10177 : : ;
10178 [ # # ]: 0 : if( it == m_aJPGs.end() )
10179 : : {
10180 [ # # ][ # # ]: 0 : m_aJPGs.push_front( JPGEmit() );
[ # # ]
10181 : 0 : JPGEmit& rEmit = m_aJPGs.front();
10182 [ # # ]: 0 : rEmit.m_nObject = createObject();
10183 : 0 : rEmit.m_aID = aID;
10184 : 0 : rEmit.m_pStream = pStream;
10185 : 0 : rEmit.m_bTrueColor = bIsTrueColor;
10186 [ # # ][ # # ]: 0 : if( !! rMask && rMask.GetSizePixel() == rSizePixel )
[ # # ]
[ # # # # ]
[ # # ]
10187 [ # # ]: 0 : rEmit.m_aMask = rMask;
10188 : :
10189 : 0 : it = m_aJPGs.begin();
10190 : : }
10191 : : else
10192 [ # # ][ # # ]: 0 : delete pStream;
10193 : :
10194 [ # # ]: 0 : aLine.append( "q " );
10195 : 0 : sal_Int32 nCheckWidth = 0;
10196 [ # # ][ # # ]: 0 : m_aPages.back().appendMappedLength( (sal_Int32)rTargetArea.GetWidth(), aLine, false, &nCheckWidth );
[ # # ]
10197 [ # # ]: 0 : aLine.append( " 0 0 " );
10198 : 0 : sal_Int32 nCheckHeight = 0;
10199 [ # # ][ # # ]: 0 : m_aPages.back().appendMappedLength( (sal_Int32)rTargetArea.GetHeight(), aLine, true, &nCheckHeight );
[ # # ]
10200 [ # # ]: 0 : aLine.append( ' ' );
10201 [ # # ][ # # ]: 0 : m_aPages.back().appendPoint( rTargetArea.BottomLeft(), aLine );
[ # # ]
10202 [ # # ]: 0 : aLine.append( " cm\n/Im" );
10203 [ # # ]: 0 : aLine.append( it->m_nObject );
10204 [ # # ]: 0 : aLine.append( " Do Q\n" );
10205 [ # # ][ # # ]: 0 : if( nCheckWidth == 0 || nCheckHeight == 0 )
10206 : : {
10207 : : // #i97512# avoid invalid current matrix
10208 [ # # ]: 0 : aLine.setLength( 0 );
10209 [ # # ]: 0 : aLine.append( "\n%jpeg image /Im" );
10210 [ # # ]: 0 : aLine.append( it->m_nObject );
10211 [ # # ]: 0 : aLine.append( " scaled to zero size, omitted\n" );
10212 : : }
10213 [ # # ]: 0 : writeBuffer( aLine.getStr(), aLine.getLength() );
10214 : :
10215 : 0 : OStringBuffer aObjName( 16 );
10216 [ # # ]: 0 : aObjName.append( "Im" );
10217 [ # # ]: 0 : aObjName.append( it->m_nObject );
10218 [ # # ][ # # ]: 0 : pushResource( ResXObject, aObjName.makeStringAndClear(), it->m_nObject );
10219 : :
10220 : : }
10221 : :
10222 : 0 : void PDFWriterImpl::drawBitmap( const Point& rDestPoint, const Size& rDestSize, const BitmapEmit& rBitmap, const Color& rFillColor )
10223 : : {
10224 : 0 : OStringBuffer aLine( 80 );
10225 [ # # ]: 0 : updateGraphicsState();
10226 : :
10227 [ # # ]: 0 : aLine.append( "q " );
10228 [ # # ]: 0 : if( rFillColor != Color( COL_TRANSPARENT ) )
10229 : : {
10230 [ # # ]: 0 : appendNonStrokingColor( rFillColor, aLine );
10231 [ # # ]: 0 : aLine.append( ' ' );
10232 : : }
10233 : 0 : sal_Int32 nCheckWidth = 0;
10234 [ # # ][ # # ]: 0 : m_aPages.back().appendMappedLength( (sal_Int32)rDestSize.Width(), aLine, false, &nCheckWidth );
10235 [ # # ]: 0 : aLine.append( " 0 0 " );
10236 : 0 : sal_Int32 nCheckHeight = 0;
10237 [ # # ][ # # ]: 0 : m_aPages.back().appendMappedLength( (sal_Int32)rDestSize.Height(), aLine, true, &nCheckHeight );
10238 [ # # ]: 0 : aLine.append( ' ' );
10239 [ # # ][ # # ]: 0 : m_aPages.back().appendPoint( rDestPoint + Point( 0, rDestSize.Height()-1 ), aLine );
10240 [ # # ]: 0 : aLine.append( " cm\n/Im" );
10241 [ # # ]: 0 : aLine.append( rBitmap.m_nObject );
10242 [ # # ]: 0 : aLine.append( " Do Q\n" );
10243 [ # # ][ # # ]: 0 : if( nCheckWidth == 0 || nCheckHeight == 0 )
10244 : : {
10245 : : // #i97512# avoid invalid current matrix
10246 [ # # ]: 0 : aLine.setLength( 0 );
10247 [ # # ]: 0 : aLine.append( "\n%bitmap image /Im" );
10248 [ # # ]: 0 : aLine.append( rBitmap.m_nObject );
10249 [ # # ]: 0 : aLine.append( " scaled to zero size, omitted\n" );
10250 : : }
10251 [ # # ]: 0 : writeBuffer( aLine.getStr(), aLine.getLength() );
10252 : 0 : }
10253 : :
10254 : 0 : const PDFWriterImpl::BitmapEmit& PDFWriterImpl::createBitmapEmit( const BitmapEx& i_rBitmap, bool bDrawMask )
10255 : : {
10256 [ # # ]: 0 : BitmapEx aBitmap( i_rBitmap );
10257 [ # # ]: 0 : if( m_aContext.ColorMode == PDFWriter::DrawGreyscale )
10258 : : {
10259 : 0 : BmpConversion eConv = BMP_CONVERSION_8BIT_GREYS;
10260 [ # # ][ # # ]: 0 : int nDepth = aBitmap.GetBitmap().GetBitCount();
[ # # ]
10261 [ # # ]: 0 : if( nDepth <= 4 )
10262 : 0 : eConv = BMP_CONVERSION_4BIT_GREYS;
10263 [ # # ]: 0 : if( nDepth > 1 )
10264 [ # # ]: 0 : aBitmap.Convert( eConv );
10265 : : }
10266 : 0 : BitmapID aID;
10267 : 0 : aID.m_aPixelSize = aBitmap.GetSizePixel();
10268 [ # # ]: 0 : aID.m_nSize = aBitmap.GetBitCount();
10269 [ # # ][ # # ]: 0 : aID.m_nChecksum = aBitmap.GetBitmap().GetChecksum();
[ # # ]
10270 : 0 : aID.m_nMaskChecksum = 0;
10271 [ # # ][ # # ]: 0 : if( aBitmap.IsAlpha() )
10272 [ # # ][ # # ]: 0 : aID.m_nMaskChecksum = aBitmap.GetAlpha().GetChecksum();
[ # # ]
10273 : : else
10274 : : {
10275 [ # # ]: 0 : Bitmap aMask = aBitmap.GetMask();
10276 [ # # ]: 0 : if( ! aMask.IsEmpty() )
10277 [ # # ][ # # ]: 0 : aID.m_nMaskChecksum = aMask.GetChecksum();
10278 : : }
10279 : 0 : std::list< BitmapEmit >::const_iterator it;
10280 [ # # ]: 0 : for( it = m_aBitmaps.begin(); it != m_aBitmaps.end(); ++it )
10281 : : {
10282 [ # # ]: 0 : if( aID == it->m_aID )
10283 : 0 : break;
10284 : : }
10285 [ # # ]: 0 : if( it == m_aBitmaps.end() )
10286 : : {
10287 [ # # ][ # # ]: 0 : m_aBitmaps.push_front( BitmapEmit() );
[ # # ]
10288 : 0 : m_aBitmaps.front().m_aID = aID;
10289 [ # # ]: 0 : m_aBitmaps.front().m_aBitmap = aBitmap;
10290 [ # # ]: 0 : m_aBitmaps.front().m_nObject = createObject();
10291 : 0 : m_aBitmaps.front().m_bDrawMask = bDrawMask;
10292 : 0 : it = m_aBitmaps.begin();
10293 : : }
10294 : :
10295 : 0 : OStringBuffer aObjName( 16 );
10296 [ # # ]: 0 : aObjName.append( "Im" );
10297 [ # # ]: 0 : aObjName.append( it->m_nObject );
10298 [ # # ]: 0 : pushResource( ResXObject, aObjName.makeStringAndClear(), it->m_nObject );
10299 : :
10300 [ # # ]: 0 : return *it;
10301 : : }
10302 : :
10303 : 0 : void PDFWriterImpl::drawBitmap( const Point& rDestPoint, const Size& rDestSize, const Bitmap& rBitmap )
10304 : : {
10305 : 0 : MARK( "drawBitmap (Bitmap)" );
10306 : :
10307 : : // #i40055# sanity check
10308 [ # # ][ # # ]: 0 : if( ! (rDestSize.Width() && rDestSize.Height()) )
[ # # ]
10309 : 0 : return;
10310 : :
10311 [ # # ]: 0 : const BitmapEmit& rEmit = createBitmapEmit( BitmapEx( rBitmap ) );
10312 [ # # ]: 0 : drawBitmap( rDestPoint, rDestSize, rEmit, Color( COL_TRANSPARENT ) );
10313 : : }
10314 : :
10315 : 0 : void PDFWriterImpl::drawBitmap( const Point& rDestPoint, const Size& rDestSize, const BitmapEx& rBitmap )
10316 : : {
10317 : 0 : MARK( "drawBitmap (BitmapEx)" );
10318 : :
10319 : : // #i40055# sanity check
10320 [ # # ][ # # ]: 0 : if( ! (rDestSize.Width() && rDestSize.Height()) )
[ # # ]
10321 : 0 : return;
10322 : :
10323 : 0 : const BitmapEmit& rEmit = createBitmapEmit( rBitmap );
10324 [ # # ]: 0 : drawBitmap( rDestPoint, rDestSize, rEmit, Color( COL_TRANSPARENT ) );
10325 : : }
10326 : :
10327 : 0 : sal_Int32 PDFWriterImpl::createGradient( const Gradient& rGradient, const Size& rSize )
10328 : : {
10329 [ # # ]: 0 : Size aPtSize( lcl_convert( m_aGraphicsStack.front().m_aMapMode,
10330 : : MapMode( MAP_POINT ),
10331 : : getReferenceDevice(),
10332 [ # # ][ # # ]: 0 : rSize ) );
[ # # ][ # # ]
10333 : : // check if we already have this gradient
10334 : 0 : std::list<GradientEmit>::iterator it;
10335 : : // rounding to point will generally lose some pixels
10336 : : // round up to point boundary
10337 : 0 : aPtSize.Width()++;
10338 : 0 : aPtSize.Height()++;
10339 [ # # ]: 0 : for( it = m_aGradients.begin(); it != m_aGradients.end(); ++it )
10340 : : {
10341 [ # # ][ # # ]: 0 : if( it->m_aGradient == rGradient )
10342 : : {
10343 [ # # ]: 0 : if( it->m_aSize == aPtSize )
10344 : 0 : break;
10345 : : }
10346 : : }
10347 [ # # ]: 0 : if( it == m_aGradients.end() )
10348 : : {
10349 [ # # ][ # # ]: 0 : m_aGradients.push_front( GradientEmit() );
[ # # ]
10350 [ # # ]: 0 : m_aGradients.front().m_aGradient = rGradient;
10351 [ # # ]: 0 : m_aGradients.front().m_nObject = createObject();
10352 : 0 : m_aGradients.front().m_aSize = aPtSize;
10353 : 0 : it = m_aGradients.begin();
10354 : : }
10355 : :
10356 : 0 : OStringBuffer aObjName( 16 );
10357 [ # # ]: 0 : aObjName.append( 'P' );
10358 [ # # ]: 0 : aObjName.append( it->m_nObject );
10359 [ # # ]: 0 : pushResource( ResShading, aObjName.makeStringAndClear(), it->m_nObject );
10360 : :
10361 : 0 : return it->m_nObject;
10362 : : }
10363 : :
10364 : 0 : void PDFWriterImpl::drawGradient( const Rectangle& rRect, const Gradient& rGradient )
10365 : : {
10366 [ # # ]: 0 : MARK( "drawGradient (Rectangle)" );
10367 : :
10368 [ # # ]: 0 : if( m_aContext.Version == PDFWriter::PDF_1_2 )
10369 : : {
10370 [ # # ]: 0 : drawRectangle( rRect );
10371 : 0 : return;
10372 : : }
10373 : :
10374 [ # # ][ # # ]: 0 : sal_Int32 nGradient = createGradient( rGradient, rRect.GetSize() );
10375 : :
10376 [ # # ]: 0 : Point aTranslate( rRect.BottomLeft() );
10377 : 0 : aTranslate += Point( 0, 1 );
10378 : :
10379 [ # # ]: 0 : updateGraphicsState();
10380 : :
10381 : 0 : OStringBuffer aLine( 80 );
10382 [ # # ]: 0 : aLine.append( "q 1 0 0 1 " );
10383 [ # # ][ # # ]: 0 : m_aPages.back().appendPoint( aTranslate, aLine );
10384 [ # # ]: 0 : aLine.append( " cm " );
10385 : : // if a stroke is appended reset the clip region before stroke
10386 [ # # ][ # # ]: 0 : if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
10387 [ # # ]: 0 : aLine.append( "q " );
10388 [ # # ]: 0 : aLine.append( "0 0 " );
10389 [ # # ][ # # ]: 0 : m_aPages.back().appendMappedLength( (sal_Int32)rRect.GetWidth(), aLine, false );
[ # # ]
10390 [ # # ]: 0 : aLine.append( ' ' );
10391 [ # # ][ # # ]: 0 : m_aPages.back().appendMappedLength( (sal_Int32)rRect.GetHeight(), aLine, true );
[ # # ]
10392 [ # # ]: 0 : aLine.append( " re W n\n" );
10393 : :
10394 [ # # ]: 0 : aLine.append( "/P" );
10395 [ # # ]: 0 : aLine.append( nGradient );
10396 [ # # ]: 0 : aLine.append( " sh " );
10397 [ # # ][ # # ]: 0 : if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
10398 : : {
10399 [ # # ]: 0 : aLine.append( "Q 0 0 " );
10400 [ # # ][ # # ]: 0 : m_aPages.back().appendMappedLength( (sal_Int32)rRect.GetWidth(), aLine, false );
[ # # ]
10401 [ # # ]: 0 : aLine.append( ' ' );
10402 [ # # ][ # # ]: 0 : m_aPages.back().appendMappedLength( (sal_Int32)rRect.GetHeight(), aLine, true );
[ # # ]
10403 [ # # ]: 0 : aLine.append( " re S " );
10404 : : }
10405 [ # # ]: 0 : aLine.append( "Q\n" );
10406 [ # # ]: 0 : writeBuffer( aLine.getStr(), aLine.getLength() );
10407 : : }
10408 : :
10409 : 0 : void PDFWriterImpl::drawHatch( const PolyPolygon& rPolyPoly, const Hatch& rHatch )
10410 : : {
10411 : 0 : MARK( "drawHatch" );
10412 : :
10413 : 0 : updateGraphicsState();
10414 : :
10415 [ # # ]: 0 : if( rPolyPoly.Count() )
10416 : : {
10417 [ # # ]: 0 : PolyPolygon aPolyPoly( rPolyPoly );
10418 : :
10419 [ # # ]: 0 : aPolyPoly.Optimize( POLY_OPTIMIZE_NO_SAME );
10420 [ # # ]: 0 : push( PUSH_LINECOLOR );
10421 [ # # ]: 0 : setLineColor( rHatch.GetColor() );
10422 [ # # ][ # # ]: 0 : getReferenceDevice()->ImplDrawHatch( aPolyPoly, rHatch, sal_False );
10423 [ # # ][ # # ]: 0 : pop();
10424 : : }
10425 : 0 : }
10426 : :
10427 : 0 : void PDFWriterImpl::drawWallpaper( const Rectangle& rRect, const Wallpaper& rWall )
10428 : : {
10429 [ # # ]: 0 : MARK( "drawWallpaper" );
10430 : :
10431 : 0 : bool bDrawColor = false;
10432 : 0 : bool bDrawGradient = false;
10433 : 0 : bool bDrawBitmap = false;
10434 : :
10435 [ # # ]: 0 : BitmapEx aBitmap;
10436 : 0 : Point aBmpPos = rRect.TopLeft();
10437 : 0 : Size aBmpSize;
10438 [ # # ][ # # ]: 0 : if( rWall.IsBitmap() )
10439 : : {
10440 [ # # ][ # # ]: 0 : aBitmap = rWall.GetBitmap();
[ # # ]
10441 : 0 : aBmpSize = lcl_convert( aBitmap.GetPrefMapMode(),
10442 [ # # ]: 0 : getMapMode(),
10443 : : getReferenceDevice(),
10444 [ # # # # ]: 0 : aBitmap.GetPrefSize() );
10445 : 0 : Rectangle aRect( rRect );
10446 [ # # ][ # # ]: 0 : if( rWall.IsRect() )
10447 : : {
10448 [ # # ]: 0 : aRect = rWall.GetRect();
10449 : 0 : aBmpPos = aRect.TopLeft();
10450 [ # # ]: 0 : aBmpSize = aRect.GetSize();
10451 : : }
10452 [ # # ][ # # ]: 0 : if( rWall.GetStyle() != WALLPAPER_SCALE )
10453 : : {
10454 [ # # ][ # # ]: 0 : if( rWall.GetStyle() != WALLPAPER_TILE )
10455 : : {
10456 : 0 : bDrawBitmap = true;
10457 [ # # ][ # # ]: 0 : if( rWall.IsGradient() )
10458 : 0 : bDrawGradient = true;
10459 : : else
10460 : 0 : bDrawColor = true;
10461 [ # # ][ # # : 0 : switch( rWall.GetStyle() )
# # # # #
# # # ]
10462 : : {
10463 : : case WALLPAPER_TOPLEFT:
10464 : 0 : break;
10465 : : case WALLPAPER_TOP:
10466 [ # # ]: 0 : aBmpPos.X() += (aRect.GetWidth()-aBmpSize.Width())/2;
10467 : 0 : break;
10468 : : case WALLPAPER_LEFT:
10469 [ # # ]: 0 : aBmpPos.Y() += (aRect.GetHeight()-aBmpSize.Height())/2;
10470 : 0 : break;
10471 : : case WALLPAPER_TOPRIGHT:
10472 [ # # ]: 0 : aBmpPos.X() += aRect.GetWidth()-aBmpSize.Width();
10473 : 0 : break;
10474 : : case WALLPAPER_CENTER:
10475 [ # # ]: 0 : aBmpPos.X() += (aRect.GetWidth()-aBmpSize.Width())/2;
10476 [ # # ]: 0 : aBmpPos.Y() += (aRect.GetHeight()-aBmpSize.Height())/2;
10477 : 0 : break;
10478 : : case WALLPAPER_RIGHT:
10479 [ # # ]: 0 : aBmpPos.X() += aRect.GetWidth()-aBmpSize.Width();
10480 [ # # ]: 0 : aBmpPos.Y() += (aRect.GetHeight()-aBmpSize.Height())/2;
10481 : 0 : break;
10482 : : case WALLPAPER_BOTTOMLEFT:
10483 [ # # ]: 0 : aBmpPos.Y() += aRect.GetHeight()-aBmpSize.Height();
10484 : 0 : break;
10485 : : case WALLPAPER_BOTTOM:
10486 [ # # ]: 0 : aBmpPos.X() += (aRect.GetWidth()-aBmpSize.Width())/2;
10487 [ # # ]: 0 : aBmpPos.Y() += aRect.GetHeight()-aBmpSize.Height();
10488 : 0 : break;
10489 : : case WALLPAPER_BOTTOMRIGHT:
10490 [ # # ]: 0 : aBmpPos.X() += aRect.GetWidth()-aBmpSize.Width();
10491 [ # # ]: 0 : aBmpPos.Y() += aRect.GetHeight()-aBmpSize.Height();
10492 : 0 : break;
10493 : : default: ;
10494 : : }
10495 : : }
10496 : : else
10497 : : {
10498 : : // push the bitmap
10499 [ # # ][ # # ]: 0 : const BitmapEmit& rEmit = createBitmapEmit( BitmapEx( aBitmap ) );
[ # # ]
10500 : :
10501 : : // convert to page coordinates; this needs to be done here
10502 : : // since the emit does not know the page anymore
10503 [ # # ]: 0 : Rectangle aConvertRect( aBmpPos, aBmpSize );
10504 [ # # ][ # # ]: 0 : m_aPages.back().convertRect( aConvertRect );
10505 : :
10506 : 0 : OStringBuffer aNameBuf(16);
10507 [ # # ]: 0 : aNameBuf.append( "Im" );
10508 [ # # ]: 0 : aNameBuf.append( rEmit.m_nObject );
10509 : 0 : OString aImageName( aNameBuf.makeStringAndClear() );
10510 : :
10511 : : // push the pattern
10512 : 0 : OStringBuffer aTilingStream( 32 );
10513 [ # # ][ # # ]: 0 : appendFixedInt( aConvertRect.GetWidth(), aTilingStream );
10514 [ # # ]: 0 : aTilingStream.append( " 0 0 " );
10515 [ # # ][ # # ]: 0 : appendFixedInt( aConvertRect.GetHeight(), aTilingStream );
10516 [ # # ]: 0 : aTilingStream.append( " 0 0 cm\n/" );
10517 [ # # ]: 0 : aTilingStream.append( aImageName );
10518 [ # # ]: 0 : aTilingStream.append( " Do\n" );
10519 : :
10520 [ # # ][ # # ]: 0 : m_aTilings.push_back( TilingEmit() );
10521 [ # # ][ # # ]: 0 : m_aTilings.back().m_nObject = createObject();
10522 [ # # ][ # # ]: 0 : m_aTilings.back().m_aRectangle = Rectangle( Point( 0, 0 ), aConvertRect.GetSize() );
[ # # ]
10523 [ # # ][ # # ]: 0 : m_aTilings.back().m_pTilingStream = new SvMemoryStream();
[ # # ]
10524 [ # # ][ # # ]: 0 : m_aTilings.back().m_pTilingStream->Write( aTilingStream.getStr(), aTilingStream.getLength() );
10525 : : // phase the tiling so wallpaper begins on upper left
10526 [ # # ][ # # ]: 0 : m_aTilings.back().m_aTransform.matrix[2] = double(aConvertRect.Left() % aConvertRect.GetWidth()) / fDivisor;
10527 [ # # ][ # # ]: 0 : m_aTilings.back().m_aTransform.matrix[5] = double(aConvertRect.Top() % aConvertRect.GetHeight()) / fDivisor;
10528 [ # # ][ # # ]: 0 : m_aTilings.back().m_aResources.m_aXObjects[aImageName] = rEmit.m_nObject;
10529 : :
10530 [ # # ]: 0 : updateGraphicsState();
10531 : :
10532 : 0 : OStringBuffer aObjName( 16 );
10533 [ # # ]: 0 : aObjName.append( 'P' );
10534 [ # # ][ # # ]: 0 : aObjName.append( m_aTilings.back().m_nObject );
10535 : 0 : OString aPatternName( aObjName.makeStringAndClear() );
10536 [ # # ][ # # ]: 0 : pushResource( ResPattern, aPatternName, m_aTilings.back().m_nObject );
10537 : :
10538 : : // fill a rRect with the pattern
10539 : 0 : OStringBuffer aLine( 100 );
10540 [ # # ]: 0 : aLine.append( "q /Pattern cs /" );
10541 [ # # ]: 0 : aLine.append( aPatternName );
10542 [ # # ]: 0 : aLine.append( " scn " );
10543 [ # # ][ # # ]: 0 : m_aPages.back().appendRect( rRect, aLine );
10544 [ # # ]: 0 : aLine.append( " f Q\n" );
10545 [ # # ]: 0 : writeBuffer( aLine.getStr(), aLine.getLength() );
10546 : : }
10547 : : }
10548 : : else
10549 : : {
10550 : 0 : aBmpPos = aRect.TopLeft();
10551 [ # # ]: 0 : aBmpSize = aRect.GetSize();
10552 : 0 : bDrawBitmap = true;
10553 : : }
10554 : :
10555 [ # # ][ # # ]: 0 : if( aBitmap.IsTransparent() )
10556 : : {
10557 [ # # ][ # # ]: 0 : if( rWall.IsGradient() )
10558 : 0 : bDrawGradient = true;
10559 : : else
10560 : 0 : bDrawColor = true;
10561 : : }
10562 : : }
10563 [ # # ][ # # ]: 0 : else if( rWall.IsGradient() )
10564 : 0 : bDrawGradient = true;
10565 : : else
10566 : 0 : bDrawColor = true;
10567 : :
10568 [ # # ]: 0 : if( bDrawGradient )
10569 : : {
10570 [ # # ][ # # ]: 0 : drawGradient( rRect, rWall.GetGradient() );
[ # # ]
10571 : : }
10572 [ # # ]: 0 : if( bDrawColor )
10573 : : {
10574 [ # # ]: 0 : Color aOldLineColor = m_aGraphicsStack.front().m_aLineColor;
10575 [ # # ]: 0 : Color aOldFillColor = m_aGraphicsStack.front().m_aFillColor;
10576 [ # # ]: 0 : setLineColor( Color( COL_TRANSPARENT ) );
10577 [ # # ][ # # ]: 0 : setFillColor( rWall.GetColor() );
10578 [ # # ]: 0 : drawRectangle( rRect );
10579 [ # # ]: 0 : setLineColor( aOldLineColor );
10580 [ # # ]: 0 : setFillColor( aOldFillColor );
10581 : : }
10582 [ # # ]: 0 : if( bDrawBitmap )
10583 : : {
10584 : : // set temporary clip region since aBmpPos and aBmpSize
10585 : : // may be outside rRect
10586 : 0 : OStringBuffer aLine( 20 );
10587 [ # # ]: 0 : aLine.append( "q " );
10588 [ # # ][ # # ]: 0 : m_aPages.back().appendRect( rRect, aLine );
10589 [ # # ]: 0 : aLine.append( " W n\n" );
10590 [ # # ]: 0 : writeBuffer( aLine.getStr(), aLine.getLength() );
10591 [ # # ]: 0 : drawBitmap( aBmpPos, aBmpSize, aBitmap );
10592 [ # # ]: 0 : writeBuffer( "Q\n", 2 );
10593 [ # # ]: 0 : }
10594 : 0 : }
10595 : :
10596 : 0 : void PDFWriterImpl::updateGraphicsState()
10597 : : {
10598 : 0 : OStringBuffer aLine( 256 );
10599 [ # # ]: 0 : GraphicsState& rNewState = m_aGraphicsStack.front();
10600 : : // first set clip region since it might invalidate everything else
10601 : :
10602 [ # # ]: 0 : if( (rNewState.m_nUpdateFlags & GraphicsState::updateClipRegion) )
10603 : : {
10604 : 0 : rNewState.m_nUpdateFlags &= ~GraphicsState::updateClipRegion;
10605 : :
10606 [ # # ][ # # ]: 0 : if( m_aCurrentPDFState.m_bClipRegion != rNewState.m_bClipRegion ||
[ # # ][ # # ]
10607 [ # # ]: 0 : ( rNewState.m_bClipRegion && m_aCurrentPDFState.m_aClipRegion != rNewState.m_aClipRegion ) )
10608 : : {
10609 [ # # ][ # # ]: 0 : if( m_aCurrentPDFState.m_bClipRegion && m_aCurrentPDFState.m_aClipRegion.count() )
[ # # ][ # # ]
10610 : : {
10611 [ # # ]: 0 : aLine.append( "Q " );
10612 : : // invalidate everything but the clip region
10613 [ # # ][ # # ]: 0 : m_aCurrentPDFState = GraphicsState();
[ # # ]
10614 : 0 : rNewState.m_nUpdateFlags = sal::static_int_cast<sal_uInt16>(~GraphicsState::updateClipRegion);
10615 : : }
10616 [ # # ][ # # ]: 0 : if( rNewState.m_bClipRegion && rNewState.m_aClipRegion.count() )
[ # # ][ # # ]
10617 : : {
10618 : : // clip region is always stored in private PDF mapmode
10619 [ # # ]: 0 : MapMode aNewMapMode = rNewState.m_aMapMode;
10620 [ # # ]: 0 : rNewState.m_aMapMode = m_aMapMode;
10621 [ # # ][ # # ]: 0 : getReferenceDevice()->SetMapMode( rNewState.m_aMapMode );
10622 [ # # ]: 0 : m_aCurrentPDFState.m_aMapMode = rNewState.m_aMapMode;
10623 : :
10624 [ # # ]: 0 : aLine.append( "q " );
10625 [ # # ][ # # ]: 0 : m_aPages.back().appendPolyPolygon( rNewState.m_aClipRegion, aLine );
10626 [ # # ]: 0 : aLine.append( "W* n\n" );
10627 [ # # ]: 0 : rNewState.m_aMapMode = aNewMapMode;
10628 [ # # ][ # # ]: 0 : getReferenceDevice()->SetMapMode( rNewState.m_aMapMode );
10629 [ # # ][ # # ]: 0 : m_aCurrentPDFState.m_aMapMode = rNewState.m_aMapMode;
10630 : : }
10631 : : }
10632 : : }
10633 : :
10634 [ # # ]: 0 : if( (rNewState.m_nUpdateFlags & GraphicsState::updateMapMode) )
10635 : : {
10636 : 0 : rNewState.m_nUpdateFlags &= ~GraphicsState::updateMapMode;
10637 [ # # ][ # # ]: 0 : getReferenceDevice()->SetMapMode( rNewState.m_aMapMode );
10638 : : }
10639 : :
10640 [ # # ]: 0 : if( (rNewState.m_nUpdateFlags & GraphicsState::updateFont) )
10641 : : {
10642 : 0 : rNewState.m_nUpdateFlags &= ~GraphicsState::updateFont;
10643 [ # # ][ # # ]: 0 : getReferenceDevice()->SetFont( rNewState.m_aFont );
10644 [ # # ][ # # ]: 0 : getReferenceDevice()->ImplNewFont();
10645 : : }
10646 : :
10647 [ # # ]: 0 : if( (rNewState.m_nUpdateFlags & GraphicsState::updateLayoutMode) )
10648 : : {
10649 : 0 : rNewState.m_nUpdateFlags &= ~GraphicsState::updateLayoutMode;
10650 [ # # ][ # # ]: 0 : getReferenceDevice()->SetLayoutMode( rNewState.m_nLayoutMode );
10651 : : }
10652 : :
10653 [ # # ]: 0 : if( (rNewState.m_nUpdateFlags & GraphicsState::updateDigitLanguage) )
10654 : : {
10655 : 0 : rNewState.m_nUpdateFlags &= ~GraphicsState::updateDigitLanguage;
10656 [ # # ][ # # ]: 0 : getReferenceDevice()->SetDigitLanguage( rNewState.m_aDigitLanguage );
10657 : : }
10658 : :
10659 [ # # ]: 0 : if( (rNewState.m_nUpdateFlags & GraphicsState::updateLineColor) )
10660 : : {
10661 : 0 : rNewState.m_nUpdateFlags &= ~GraphicsState::updateLineColor;
10662 [ # # # # ]: 0 : if( m_aCurrentPDFState.m_aLineColor != rNewState.m_aLineColor &&
[ # # ]
10663 [ # # ]: 0 : rNewState.m_aLineColor != Color( COL_TRANSPARENT ) )
10664 : : {
10665 [ # # ]: 0 : appendStrokingColor( rNewState.m_aLineColor, aLine );
10666 [ # # ]: 0 : aLine.append( "\n" );
10667 : : }
10668 : : }
10669 : :
10670 [ # # ]: 0 : if( (rNewState.m_nUpdateFlags & GraphicsState::updateFillColor) )
10671 : : {
10672 : 0 : rNewState.m_nUpdateFlags &= ~GraphicsState::updateFillColor;
10673 [ # # # # ]: 0 : if( m_aCurrentPDFState.m_aFillColor != rNewState.m_aFillColor &&
[ # # ]
10674 [ # # ]: 0 : rNewState.m_aFillColor != Color( COL_TRANSPARENT ) )
10675 : : {
10676 [ # # ]: 0 : appendNonStrokingColor( rNewState.m_aFillColor, aLine );
10677 [ # # ]: 0 : aLine.append( "\n" );
10678 : : }
10679 : : }
10680 : :
10681 [ # # ]: 0 : if( (rNewState.m_nUpdateFlags & GraphicsState::updateTransparentPercent) )
10682 : : {
10683 : 0 : rNewState.m_nUpdateFlags &= ~GraphicsState::updateTransparentPercent;
10684 [ # # ]: 0 : if( m_aContext.Version >= PDFWriter::PDF_1_4 && m_aCurrentPDFState.m_nTransparentPercent != rNewState.m_nTransparentPercent )
10685 : : {
10686 : : // TODO: switch extended graphicsstate
10687 : : }
10688 : : }
10689 : :
10690 : : // everything is up to date now
10691 [ # # ][ # # ]: 0 : m_aCurrentPDFState = m_aGraphicsStack.front();
10692 [ # # ]: 0 : if( aLine.getLength() )
10693 [ # # ]: 0 : writeBuffer( aLine.getStr(), aLine.getLength() );
10694 : 0 : }
10695 : :
10696 : : /* #i47544# imitate OutputDevice behaviour:
10697 : : * if a font with a nontransparent color is set, it overwrites the current
10698 : : * text color. OTOH setting the text color will overwrite the color of the font.
10699 : : */
10700 : 0 : void PDFWriterImpl::setFont( const Font& rFont )
10701 : : {
10702 [ # # ]: 0 : Color aColor = rFont.GetColor();
10703 [ # # ]: 0 : if( aColor == Color( COL_TRANSPARENT ) )
10704 [ # # ][ # # ]: 0 : aColor = m_aGraphicsStack.front().m_aFont.GetColor();
10705 [ # # ][ # # ]: 0 : m_aGraphicsStack.front().m_aFont = rFont;
10706 [ # # ][ # # ]: 0 : m_aGraphicsStack.front().m_aFont.SetColor( aColor );
10707 [ # # ]: 0 : m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsState::updateFont;
10708 : 0 : }
10709 : :
10710 : 0 : void PDFWriterImpl::push( sal_uInt16 nFlags )
10711 : : {
10712 : : OSL_ENSURE( m_aGraphicsStack.size() > 0, "invalid graphics stack" );
10713 : 0 : m_aGraphicsStack.push_front( m_aGraphicsStack.front() );
10714 : 0 : m_aGraphicsStack.front().m_nFlags = nFlags;
10715 : 0 : }
10716 : :
10717 : 0 : void PDFWriterImpl::pop()
10718 : : {
10719 : : OSL_ENSURE( m_aGraphicsStack.size() > 1, "pop without push" );
10720 [ # # ]: 0 : if( m_aGraphicsStack.size() < 2 )
10721 : 0 : return;
10722 : :
10723 [ # # ][ # # ]: 0 : GraphicsState aState = m_aGraphicsStack.front();
10724 [ # # ]: 0 : m_aGraphicsStack.pop_front();
10725 [ # # ]: 0 : GraphicsState& rOld = m_aGraphicsStack.front();
10726 : :
10727 : : // move those parameters back that were not pushed
10728 : : // in the first place
10729 [ # # ]: 0 : if( ! (aState.m_nFlags & PUSH_LINECOLOR) )
10730 [ # # ]: 0 : setLineColor( aState.m_aLineColor );
10731 [ # # ]: 0 : if( ! (aState.m_nFlags & PUSH_FILLCOLOR) )
10732 [ # # ]: 0 : setFillColor( aState.m_aFillColor );
10733 [ # # ]: 0 : if( ! (aState.m_nFlags & PUSH_FONT) )
10734 [ # # ]: 0 : setFont( aState.m_aFont );
10735 [ # # ]: 0 : if( ! (aState.m_nFlags & PUSH_TEXTCOLOR) )
10736 [ # # ][ # # ]: 0 : setTextColor( aState.m_aFont.GetColor() );
10737 [ # # ]: 0 : if( ! (aState.m_nFlags & PUSH_MAPMODE) )
10738 [ # # ]: 0 : setMapMode( aState.m_aMapMode );
10739 [ # # ]: 0 : if( ! (aState.m_nFlags & PUSH_CLIPREGION) )
10740 : : {
10741 : : // do not use setClipRegion here
10742 : : // it would convert again assuming the current mapmode
10743 [ # # ]: 0 : rOld.m_aClipRegion = aState.m_aClipRegion;
10744 : 0 : rOld.m_bClipRegion = aState.m_bClipRegion;
10745 : : }
10746 [ # # ]: 0 : if( ! (aState.m_nFlags & PUSH_TEXTLINECOLOR ) )
10747 [ # # ]: 0 : setTextLineColor( aState.m_aTextLineColor );
10748 [ # # ]: 0 : if( ! (aState.m_nFlags & PUSH_OVERLINECOLOR ) )
10749 [ # # ]: 0 : setOverlineColor( aState.m_aOverlineColor );
10750 [ # # ]: 0 : if( ! (aState.m_nFlags & PUSH_TEXTALIGN ) )
10751 [ # # ][ # # ]: 0 : setTextAlign( aState.m_aFont.GetAlign() );
10752 [ # # ]: 0 : if( ! (aState.m_nFlags & PUSH_TEXTFILLCOLOR) )
10753 [ # # ][ # # ]: 0 : setTextFillColor( aState.m_aFont.GetFillColor() );
10754 : 0 : if( ! (aState.m_nFlags & PUSH_REFPOINT) )
10755 : : {
10756 : : // what ?
10757 : : }
10758 : : // invalidate graphics state
10759 [ # # ][ # # ]: 0 : m_aGraphicsStack.front().m_nUpdateFlags = sal::static_int_cast<sal_uInt16>(~0U);
10760 : : }
10761 : :
10762 : 0 : void PDFWriterImpl::setMapMode( const MapMode& rMapMode )
10763 : : {
10764 : 0 : m_aGraphicsStack.front().m_aMapMode = rMapMode;
10765 : 0 : getReferenceDevice()->SetMapMode( rMapMode );
10766 : 0 : m_aCurrentPDFState.m_aMapMode = rMapMode;
10767 : 0 : }
10768 : :
10769 : 0 : void PDFWriterImpl::setClipRegion( const basegfx::B2DPolyPolygon& rRegion )
10770 : : {
10771 [ # # ][ # # ]: 0 : basegfx::B2DPolyPolygon aRegion = getReferenceDevice()->LogicToPixel( rRegion, m_aGraphicsStack.front().m_aMapMode );
[ # # ]
10772 [ # # ][ # # ]: 0 : aRegion = getReferenceDevice()->PixelToLogic( aRegion, m_aMapMode );
[ # # ][ # # ]
10773 [ # # ][ # # ]: 0 : m_aGraphicsStack.front().m_aClipRegion = aRegion;
10774 [ # # ]: 0 : m_aGraphicsStack.front().m_bClipRegion = true;
10775 [ # # ][ # # ]: 0 : m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsState::updateClipRegion;
10776 : 0 : }
10777 : :
10778 : 0 : void PDFWriterImpl::moveClipRegion( sal_Int32 nX, sal_Int32 nY )
10779 : : {
10780 [ # # ][ # # ]: 0 : if( m_aGraphicsStack.front().m_bClipRegion && m_aGraphicsStack.front().m_aClipRegion.count() )
[ # # ]
10781 : : {
10782 [ # # ]: 0 : Point aPoint( lcl_convert( m_aGraphicsStack.front().m_aMapMode,
10783 : : m_aMapMode,
10784 : : getReferenceDevice(),
10785 [ # # ][ # # ]: 0 : Point( nX, nY ) ) );
10786 [ # # ]: 0 : aPoint -= lcl_convert( m_aGraphicsStack.front().m_aMapMode,
10787 : : m_aMapMode,
10788 : : getReferenceDevice(),
10789 [ # # ][ # # ]: 0 : Point() );
10790 [ # # ]: 0 : basegfx::B2DHomMatrix aMat;
10791 [ # # ]: 0 : aMat.translate( aPoint.X(), aPoint.Y() );
10792 [ # # ][ # # ]: 0 : m_aGraphicsStack.front().m_aClipRegion.transform( aMat );
10793 [ # # ][ # # ]: 0 : m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsState::updateClipRegion;
10794 : : }
10795 : 0 : }
10796 : :
10797 : 0 : bool PDFWriterImpl::intersectClipRegion( const Rectangle& rRect )
10798 : : {
10799 : : basegfx::B2DPolyPolygon aRect( basegfx::tools::createPolygonFromRect(
10800 [ # # ][ # # ]: 0 : basegfx::B2DRectangle( rRect.Left(), rRect.Top(), rRect.Right(), rRect.Bottom() ) ) );
[ # # ][ # # ]
10801 [ # # ][ # # ]: 0 : return intersectClipRegion( aRect );
10802 : : }
10803 : :
10804 : :
10805 : 0 : bool PDFWriterImpl::intersectClipRegion( const basegfx::B2DPolyPolygon& rRegion )
10806 : : {
10807 [ # # ][ # # ]: 0 : basegfx::B2DPolyPolygon aRegion( getReferenceDevice()->LogicToPixel( rRegion, m_aGraphicsStack.front().m_aMapMode ) );
[ # # ]
10808 [ # # ][ # # ]: 0 : aRegion = getReferenceDevice()->PixelToLogic( aRegion, m_aMapMode );
[ # # ][ # # ]
10809 [ # # ]: 0 : m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsState::updateClipRegion;
10810 [ # # ][ # # ]: 0 : if( m_aGraphicsStack.front().m_bClipRegion )
10811 : : {
10812 [ # # ][ # # ]: 0 : basegfx::B2DPolyPolygon aOld( basegfx::tools::prepareForPolygonOperation( m_aGraphicsStack.front().m_aClipRegion ) );
10813 [ # # ][ # # ]: 0 : aRegion = basegfx::tools::prepareForPolygonOperation( aRegion );
[ # # ]
10814 [ # # ][ # # ]: 0 : m_aGraphicsStack.front().m_aClipRegion = basegfx::tools::solvePolygonOperationAnd( aOld, aRegion );
[ # # ][ # # ]
[ # # ]
10815 : : }
10816 : : else
10817 : : {
10818 [ # # ][ # # ]: 0 : m_aGraphicsStack.front().m_aClipRegion = aRegion;
10819 [ # # ]: 0 : m_aGraphicsStack.front().m_bClipRegion = true;
10820 : : }
10821 [ # # ]: 0 : return true;
10822 : : }
10823 : :
10824 : 0 : void PDFWriterImpl::createNote( const Rectangle& rRect, const PDFNote& rNote, sal_Int32 nPageNr )
10825 : : {
10826 [ # # ]: 0 : if( nPageNr < 0 )
10827 : 0 : nPageNr = m_nCurrentPage;
10828 : :
10829 [ # # ][ # # ]: 0 : if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() )
[ # # ]
10830 : 0 : return;
10831 : :
10832 [ # # ]: 0 : m_aNotes.push_back( PDFNoteEntry() );
10833 : 0 : m_aNotes.back().m_nObject = createObject();
10834 : 0 : m_aNotes.back().m_aContents = rNote;
10835 : 0 : m_aNotes.back().m_aRect = rRect;
10836 : : // convert to default user space now, since the mapmode may change
10837 : 0 : m_aPages[nPageNr].convertRect( m_aNotes.back().m_aRect );
10838 : :
10839 : : // insert note to page's annotation list
10840 : 0 : m_aPages[ nPageNr ].m_aAnnotations.push_back( m_aNotes.back().m_nObject );
10841 : : }
10842 : :
10843 : 0 : sal_Int32 PDFWriterImpl::createLink( const Rectangle& rRect, sal_Int32 nPageNr )
10844 : : {
10845 [ # # ]: 0 : if( nPageNr < 0 )
10846 : 0 : nPageNr = m_nCurrentPage;
10847 : :
10848 [ # # ][ # # ]: 0 : if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() )
[ # # ]
10849 : 0 : return -1;
10850 : :
10851 : 0 : sal_Int32 nRet = m_aLinks.size();
10852 : :
10853 [ # # ]: 0 : m_aLinks.push_back( PDFLink() );
10854 : 0 : m_aLinks.back().m_nObject = createObject();
10855 : 0 : m_aLinks.back().m_nPage = nPageNr;
10856 : 0 : m_aLinks.back().m_aRect = rRect;
10857 : : // convert to default user space now, since the mapmode may change
10858 : 0 : m_aPages[nPageNr].convertRect( m_aLinks.back().m_aRect );
10859 : :
10860 : : // insert link to page's annotation list
10861 : 0 : m_aPages[ nPageNr ].m_aAnnotations.push_back( m_aLinks.back().m_nObject );
10862 : :
10863 : 0 : return nRet;
10864 : : }
10865 : :
10866 : : //--->i56629
10867 : 0 : sal_Int32 PDFWriterImpl::createNamedDest( const rtl::OUString& sDestName, const Rectangle& rRect, sal_Int32 nPageNr, PDFWriter::DestAreaType eType )
10868 : : {
10869 [ # # ]: 0 : if( nPageNr < 0 )
10870 : 0 : nPageNr = m_nCurrentPage;
10871 : :
10872 [ # # ][ # # ]: 0 : if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() )
[ # # ]
10873 : 0 : return -1;
10874 : :
10875 : 0 : sal_Int32 nRet = m_aNamedDests.size();
10876 : :
10877 [ # # ]: 0 : m_aNamedDests.push_back( PDFNamedDest() );
10878 : 0 : m_aNamedDests.back().m_aDestName = sDestName;
10879 : 0 : m_aNamedDests.back().m_nPage = nPageNr;
10880 : 0 : m_aNamedDests.back().m_eType = eType;
10881 : 0 : m_aNamedDests.back().m_aRect = rRect;
10882 : : // convert to default user space now, since the mapmode may change
10883 : 0 : m_aPages[nPageNr].convertRect( m_aNamedDests.back().m_aRect );
10884 : :
10885 : 0 : return nRet;
10886 : : }
10887 : : //<---i56629
10888 : :
10889 : 0 : sal_Int32 PDFWriterImpl::createDest( const Rectangle& rRect, sal_Int32 nPageNr, PDFWriter::DestAreaType eType )
10890 : : {
10891 [ # # ]: 0 : if( nPageNr < 0 )
10892 : 0 : nPageNr = m_nCurrentPage;
10893 : :
10894 [ # # ][ # # ]: 0 : if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() )
[ # # ]
10895 : 0 : return -1;
10896 : :
10897 : 0 : sal_Int32 nRet = m_aDests.size();
10898 : :
10899 [ # # ]: 0 : m_aDests.push_back( PDFDest() );
10900 : 0 : m_aDests.back().m_nPage = nPageNr;
10901 : 0 : m_aDests.back().m_eType = eType;
10902 : 0 : m_aDests.back().m_aRect = rRect;
10903 : : // convert to default user space now, since the mapmode may change
10904 : 0 : m_aPages[nPageNr].convertRect( m_aDests.back().m_aRect );
10905 : :
10906 : 0 : return nRet;
10907 : : }
10908 : :
10909 : 0 : sal_Int32 PDFWriterImpl::registerDestReference( sal_Int32 nDestId, const Rectangle& rRect, sal_Int32 nPageNr, PDFWriter::DestAreaType eType )
10910 : : {
10911 : 0 : return m_aDestinationIdTranslation[ nDestId ] = createDest( rRect, nPageNr, eType );
10912 : : }
10913 : :
10914 : 0 : sal_Int32 PDFWriterImpl::setLinkDest( sal_Int32 nLinkId, sal_Int32 nDestId )
10915 : : {
10916 [ # # ][ # # ]: 0 : if( nLinkId < 0 || nLinkId >= (sal_Int32)m_aLinks.size() )
[ # # ]
10917 : 0 : return -1;
10918 [ # # ][ # # ]: 0 : if( nDestId < 0 || nDestId >= (sal_Int32)m_aDests.size() )
[ # # ]
10919 : 0 : return -2;
10920 : :
10921 : 0 : m_aLinks[ nLinkId ].m_nDest = nDestId;
10922 : :
10923 : 0 : return 0;
10924 : : }
10925 : :
10926 : 0 : sal_Int32 PDFWriterImpl::setLinkURL( sal_Int32 nLinkId, const OUString& rURL )
10927 : : {
10928 [ # # ][ # # ]: 0 : if( nLinkId < 0 || nLinkId >= (sal_Int32)m_aLinks.size() )
[ # # ]
10929 : 0 : return -1;
10930 : :
10931 : 0 : m_aLinks[ nLinkId ].m_nDest = -1;
10932 : :
10933 : : using namespace ::com::sun::star;
10934 : :
10935 [ # # ]: 0 : if (!m_xTrans.is())
10936 : : {
10937 [ # # ]: 0 : uno::Reference< uno::XComponentContext > xContext( comphelper::getProcessComponentContext() );
10938 [ # # ][ # # ]: 0 : m_xTrans = util::URLTransformer::create(xContext);;
10939 : : }
10940 : :
10941 : 0 : util::URL aURL;
10942 : 0 : aURL.Complete = rURL;
10943 : :
10944 [ # # ][ # # ]: 0 : m_xTrans->parseStrict( aURL );
10945 : :
10946 : 0 : m_aLinks[ nLinkId ].m_aURL = aURL.Complete;
10947 : :
10948 : 0 : return 0;
10949 : : }
10950 : :
10951 : 0 : void PDFWriterImpl::setLinkPropertyId( sal_Int32 nLinkId, sal_Int32 nPropertyId )
10952 : : {
10953 : 0 : m_aLinkPropertyMap[ nPropertyId ] = nLinkId;
10954 : 0 : }
10955 : :
10956 : 0 : sal_Int32 PDFWriterImpl::createOutlineItem( sal_Int32 nParent, const OUString& rText, sal_Int32 nDestID )
10957 : : {
10958 : : // create new item
10959 : 0 : sal_Int32 nNewItem = m_aOutline.size();
10960 [ # # ]: 0 : m_aOutline.push_back( PDFOutlineEntry() );
10961 : :
10962 : : // set item attributes
10963 : 0 : setOutlineItemParent( nNewItem, nParent );
10964 : 0 : setOutlineItemText( nNewItem, rText );
10965 : 0 : setOutlineItemDest( nNewItem, nDestID );
10966 : :
10967 : 0 : return nNewItem;
10968 : : }
10969 : :
10970 : 0 : sal_Int32 PDFWriterImpl::setOutlineItemParent( sal_Int32 nItem, sal_Int32 nNewParent )
10971 : : {
10972 [ # # ][ # # ]: 0 : if( nItem < 1 || nItem >= (sal_Int32)m_aOutline.size() )
[ # # ]
10973 : 0 : return -1;
10974 : :
10975 : 0 : int nRet = 0;
10976 : :
10977 [ # # ][ # # ]: 0 : if( nNewParent < 0 || nNewParent >= (sal_Int32)m_aOutline.size() || nNewParent == nItem )
[ # # ][ # # ]
10978 : : {
10979 : 0 : nNewParent = 0;
10980 : 0 : nRet = -2;
10981 : : }
10982 : : // remove item from previous parent
10983 : 0 : sal_Int32 nParentID = m_aOutline[ nItem ].m_nParentID;
10984 [ # # ][ # # ]: 0 : if( nParentID >= 0 && nParentID < (sal_Int32)m_aOutline.size() )
[ # # ]
10985 : : {
10986 : 0 : PDFOutlineEntry& rParent = m_aOutline[ nParentID ];
10987 : :
10988 [ # # # # ]: 0 : for( std::vector<sal_Int32>::iterator it = rParent.m_aChildren.begin();
[ # # ]
10989 : 0 : it != rParent.m_aChildren.end(); ++it )
10990 : : {
10991 [ # # ][ # # ]: 0 : if( *it == nItem )
10992 : : {
10993 [ # # ]: 0 : rParent.m_aChildren.erase( it );
10994 : 0 : break;
10995 : : }
10996 : : }
10997 : : }
10998 : :
10999 : : // insert item to new parent's list of children
11000 : 0 : m_aOutline[ nNewParent ].m_aChildren.push_back( nItem );
11001 : :
11002 : 0 : return nRet;
11003 : : }
11004 : :
11005 : 0 : sal_Int32 PDFWriterImpl::setOutlineItemText( sal_Int32 nItem, const OUString& rText )
11006 : : {
11007 [ # # ][ # # ]: 0 : if( nItem < 1 || nItem >= (sal_Int32)m_aOutline.size() )
[ # # ]
11008 : 0 : return -1;
11009 : :
11010 [ # # ][ # # ]: 0 : m_aOutline[ nItem ].m_aTitle = psp::WhitespaceToSpace( rText );
[ # # ]
11011 : 0 : return 0;
11012 : : }
11013 : :
11014 : 0 : sal_Int32 PDFWriterImpl::setOutlineItemDest( sal_Int32 nItem, sal_Int32 nDestID )
11015 : : {
11016 [ # # ][ # # ]: 0 : if( nItem < 1 || nItem >= (sal_Int32)m_aOutline.size() ) // item does not exist
[ # # ]
11017 : 0 : return -1;
11018 [ # # ][ # # ]: 0 : if( nDestID < 0 || nDestID >= (sal_Int32)m_aDests.size() ) // dest does not exist
[ # # ]
11019 : 0 : return -2;
11020 : 0 : m_aOutline[nItem].m_nDestID = nDestID;
11021 : 0 : return 0;
11022 : : }
11023 : :
11024 : 0 : const sal_Char* PDFWriterImpl::getStructureTag( PDFWriter::StructElement eType )
11025 : : {
11026 [ # # ][ # # ]: 0 : static std::map< PDFWriter::StructElement, const char* > aTagStrings;
[ # # ][ # # ]
11027 [ # # ]: 0 : if( aTagStrings.empty() )
11028 : : {
11029 [ # # ]: 0 : aTagStrings[ PDFWriter::NonStructElement] = "NonStruct";
11030 [ # # ]: 0 : aTagStrings[ PDFWriter::Document ] = "Document";
11031 [ # # ]: 0 : aTagStrings[ PDFWriter::Part ] = "Part";
11032 [ # # ]: 0 : aTagStrings[ PDFWriter::Article ] = "Art";
11033 [ # # ]: 0 : aTagStrings[ PDFWriter::Section ] = "Sect";
11034 [ # # ]: 0 : aTagStrings[ PDFWriter::Division ] = "Div";
11035 [ # # ]: 0 : aTagStrings[ PDFWriter::BlockQuote ] = "BlockQuote";
11036 [ # # ]: 0 : aTagStrings[ PDFWriter::Caption ] = "Caption";
11037 [ # # ]: 0 : aTagStrings[ PDFWriter::TOC ] = "TOC";
11038 [ # # ]: 0 : aTagStrings[ PDFWriter::TOCI ] = "TOCI";
11039 [ # # ]: 0 : aTagStrings[ PDFWriter::Index ] = "Index";
11040 [ # # ]: 0 : aTagStrings[ PDFWriter::Paragraph ] = "P";
11041 [ # # ]: 0 : aTagStrings[ PDFWriter::Heading ] = "H";
11042 [ # # ]: 0 : aTagStrings[ PDFWriter::H1 ] = "H1";
11043 [ # # ]: 0 : aTagStrings[ PDFWriter::H2 ] = "H2";
11044 [ # # ]: 0 : aTagStrings[ PDFWriter::H3 ] = "H3";
11045 [ # # ]: 0 : aTagStrings[ PDFWriter::H4 ] = "H4";
11046 [ # # ]: 0 : aTagStrings[ PDFWriter::H5 ] = "H5";
11047 [ # # ]: 0 : aTagStrings[ PDFWriter::H6 ] = "H6";
11048 [ # # ]: 0 : aTagStrings[ PDFWriter::List ] = "L";
11049 [ # # ]: 0 : aTagStrings[ PDFWriter::ListItem ] = "LI";
11050 [ # # ]: 0 : aTagStrings[ PDFWriter::LILabel ] = "Lbl";
11051 [ # # ]: 0 : aTagStrings[ PDFWriter::LIBody ] = "LBody";
11052 [ # # ]: 0 : aTagStrings[ PDFWriter::Table ] = "Table";
11053 [ # # ]: 0 : aTagStrings[ PDFWriter::TableRow ] = "TR";
11054 [ # # ]: 0 : aTagStrings[ PDFWriter::TableHeader ] = "TH";
11055 [ # # ]: 0 : aTagStrings[ PDFWriter::TableData ] = "TD";
11056 [ # # ]: 0 : aTagStrings[ PDFWriter::Span ] = "Span";
11057 [ # # ]: 0 : aTagStrings[ PDFWriter::Quote ] = "Quote";
11058 [ # # ]: 0 : aTagStrings[ PDFWriter::Note ] = "Note";
11059 [ # # ]: 0 : aTagStrings[ PDFWriter::Reference ] = "Reference";
11060 [ # # ]: 0 : aTagStrings[ PDFWriter::BibEntry ] = "BibEntry";
11061 [ # # ]: 0 : aTagStrings[ PDFWriter::Code ] = "Code";
11062 [ # # ]: 0 : aTagStrings[ PDFWriter::Link ] = "Link";
11063 [ # # ]: 0 : aTagStrings[ PDFWriter::Figure ] = "Figure";
11064 [ # # ]: 0 : aTagStrings[ PDFWriter::Formula ] = "Formula";
11065 [ # # ]: 0 : aTagStrings[ PDFWriter::Form ] = "Form";
11066 : : }
11067 : :
11068 [ # # ][ # # ]: 0 : std::map< PDFWriter::StructElement, const char* >::const_iterator it = aTagStrings.find( eType );
11069 : :
11070 [ # # ][ # # ]: 0 : return it != aTagStrings.end() ? it->second : "Div";
[ # # ][ # # ]
11071 : : }
11072 : :
11073 : 0 : void PDFWriterImpl::beginStructureElementMCSeq()
11074 : : {
11075 [ # # ]: 0 : if( m_bEmitStructure &&
[ # # # # ]
[ # # ]
11076 : : m_nCurrentStructElement > 0 && // StructTreeRoot
11077 : 0 : ! m_aStructure[ m_nCurrentStructElement ].m_bOpenMCSeq // already opened sequence
11078 : : )
11079 : : {
11080 : 0 : PDFStructureElement& rEle = m_aStructure[ m_nCurrentStructElement ];
11081 : 0 : OStringBuffer aLine( 128 );
11082 : 0 : sal_Int32 nMCID = m_aPages[ m_nCurrentPage ].m_aMCIDParents.size();
11083 [ # # ]: 0 : aLine.append( "/" );
11084 [ # # ]: 0 : if( !rEle.m_aAlias.isEmpty() )
11085 [ # # ]: 0 : aLine.append( rEle.m_aAlias );
11086 : : else
11087 [ # # ][ # # ]: 0 : aLine.append( getStructureTag( rEle.m_eType ) );
11088 [ # # ]: 0 : aLine.append( "<</MCID " );
11089 [ # # ]: 0 : aLine.append( nMCID );
11090 [ # # ]: 0 : aLine.append( ">>BDC\n" );
11091 [ # # ]: 0 : writeBuffer( aLine.getStr(), aLine.getLength() );
11092 : :
11093 : : // update the element's content list
11094 : : #if OSL_DEBUG_LEVEL > 1
11095 : : fprintf( stderr, "beginning marked content id %" SAL_PRIdINT32 " on page object %" SAL_PRIdINT32 ", structure first page = %" SAL_PRIdINT32 "\n",
11096 : : nMCID,
11097 : : m_aPages[ m_nCurrentPage ].m_nPageObject,
11098 : : rEle.m_nFirstPageObject );
11099 : : #endif
11100 [ # # ]: 0 : rEle.m_aKids.push_back( PDFStructureElementKid( nMCID, m_aPages[m_nCurrentPage].m_nPageObject ) );
11101 : : // update the page's mcid parent list
11102 [ # # ]: 0 : m_aPages[ m_nCurrentPage ].m_aMCIDParents.push_back( rEle.m_nObject );
11103 : : // mark element MC sequence as open
11104 : 0 : rEle.m_bOpenMCSeq = true;
11105 : : }
11106 : : // handle artifacts
11107 [ # # ][ # # ]: 0 : else if( ! m_bEmitStructure && m_aContext.Tagged &&
[ # # # #
# # ][ # # ]
11108 : : m_nCurrentStructElement > 0 &&
11109 : 0 : m_aStructure[ m_nCurrentStructElement ].m_eType == PDFWriter::NonStructElement &&
11110 : 0 : ! m_aStructure[ m_nCurrentStructElement ].m_bOpenMCSeq // already opened sequence
11111 : : )
11112 : : {
11113 : 0 : OStringBuffer aLine( 128 );
11114 [ # # ]: 0 : aLine.append( "/Artifact BMC\n" );
11115 [ # # ]: 0 : writeBuffer( aLine.getStr(), aLine.getLength() );
11116 : : // mark element MC sequence as open
11117 : 0 : m_aStructure[ m_nCurrentStructElement ].m_bOpenMCSeq = true;
11118 : : }
11119 : 0 : }
11120 : :
11121 : 0 : void PDFWriterImpl::endStructureElementMCSeq()
11122 : : {
11123 [ # # ][ # # : 0 : if( m_nCurrentStructElement > 0 && // StructTreeRoot
# # # # ]
[ # # ]
11124 : 0 : ( m_bEmitStructure || m_aStructure[ m_nCurrentStructElement ].m_eType == PDFWriter::NonStructElement ) &&
11125 : 0 : m_aStructure[ m_nCurrentStructElement ].m_bOpenMCSeq // must have an opened MC sequence
11126 : : )
11127 : : {
11128 : 0 : writeBuffer( "EMC\n", 4 );
11129 : 0 : m_aStructure[ m_nCurrentStructElement ].m_bOpenMCSeq = false;
11130 : : }
11131 : 0 : }
11132 : :
11133 : 0 : bool PDFWriterImpl::checkEmitStructure()
11134 : : {
11135 : 0 : bool bEmit = false;
11136 [ # # ]: 0 : if( m_aContext.Tagged )
11137 : : {
11138 : 0 : bEmit = true;
11139 : 0 : sal_Int32 nEle = m_nCurrentStructElement;
11140 [ # # ][ # # ]: 0 : while( nEle > 0 && nEle < sal_Int32(m_aStructure.size()) )
[ # # ]
11141 : : {
11142 [ # # ]: 0 : if( m_aStructure[ nEle ].m_eType == PDFWriter::NonStructElement )
11143 : : {
11144 : 0 : bEmit = false;
11145 : 0 : break;
11146 : : }
11147 : 0 : nEle = m_aStructure[ nEle ].m_nParentElement;
11148 : : }
11149 : : }
11150 : 0 : return bEmit;
11151 : : }
11152 : :
11153 : 0 : sal_Int32 PDFWriterImpl::beginStructureElement( PDFWriter::StructElement eType, const rtl::OUString& rAlias )
11154 : : {
11155 [ # # ]: 0 : if( m_nCurrentPage < 0 )
11156 : 0 : return -1;
11157 : :
11158 [ # # ]: 0 : if( ! m_aContext.Tagged )
11159 : 0 : return -1;
11160 : :
11161 : : // close eventual current MC sequence
11162 [ # # ]: 0 : endStructureElementMCSeq();
11163 : :
11164 [ # # ][ # # ]: 0 : if( m_nCurrentStructElement == 0 &&
[ # # ]
11165 : : eType != PDFWriter::Document && eType != PDFWriter::NonStructElement )
11166 : : {
11167 : : // struct tree root hit, but not beginning document
11168 : : // this might happen with setCurrentStructureElement
11169 : : // silently insert structure into document again if one properly exists
11170 [ # # ]: 0 : if( ! m_aStructure[ 0 ].m_aChildren.empty() )
11171 : : {
11172 : 0 : PDFWriter::StructElement childType = PDFWriter::NonStructElement;
11173 : 0 : sal_Int32 nNewCurElement = 0;
11174 : 0 : const std::list< sal_Int32 >& rRootChildren = m_aStructure[0].m_aChildren;
11175 [ # # ][ # # ]: 0 : for( std::list< sal_Int32 >::const_iterator it = rRootChildren.begin();
[ # # ][ # # ]
11176 [ # # ][ # # ]: 0 : childType != PDFWriter::Document && it != rRootChildren.end(); ++it )
[ # # ]
11177 : : {
11178 [ # # ]: 0 : nNewCurElement = *it;
11179 : 0 : childType = m_aStructure[ nNewCurElement ].m_eType;
11180 : : }
11181 [ # # ]: 0 : if( childType == PDFWriter::Document )
11182 : : {
11183 : 0 : m_nCurrentStructElement = nNewCurElement;
11184 : : DBG_ASSERT( 0, "Structure element inserted to StructTreeRoot that is not a document" );
11185 : : }
11186 : : else {
11187 : : OSL_FAIL( "document structure in disorder !" );
11188 : : }
11189 : : }
11190 : : else {
11191 : : OSL_FAIL( "PDF document structure MUST be contained in a Document element" );
11192 : : }
11193 : : }
11194 : :
11195 : 0 : sal_Int32 nNewId = sal_Int32(m_aStructure.size());
11196 [ # # ][ # # ]: 0 : m_aStructure.push_back( PDFStructureElement() );
11197 [ # # ]: 0 : PDFStructureElement& rEle = m_aStructure.back();
11198 : 0 : rEle.m_eType = eType;
11199 : 0 : rEle.m_nOwnElement = nNewId;
11200 : 0 : rEle.m_nParentElement = m_nCurrentStructElement;
11201 : 0 : rEle.m_nFirstPageObject = m_aPages[ m_nCurrentPage ].m_nPageObject;
11202 [ # # ]: 0 : m_aStructure[ m_nCurrentStructElement ].m_aChildren.push_back( nNewId );
11203 : 0 : m_nCurrentStructElement = nNewId;
11204 : :
11205 : : // handle alias names
11206 [ # # ][ # # ]: 0 : if( !rAlias.isEmpty() && eType != PDFWriter::NonStructElement )
[ # # ]
11207 : : {
11208 : 0 : OStringBuffer aNameBuf( rAlias.getLength() );
11209 [ # # ]: 0 : appendName( rAlias, aNameBuf );
11210 : 0 : OString aAliasName( aNameBuf.makeStringAndClear() );
11211 : 0 : rEle.m_aAlias = aAliasName;
11212 [ # # ][ # # ]: 0 : m_aRoleMap[ aAliasName ] = getStructureTag( eType );
11213 : : }
11214 : :
11215 : : #if OSL_DEBUG_LEVEL > 1
11216 : : OStringBuffer aLine( "beginStructureElement " );
11217 : : aLine.append( m_nCurrentStructElement );
11218 : : aLine.append( ": " );
11219 : : aLine.append( getStructureTag( eType ) );
11220 : : if( !rEle.m_aAlias.isEmpty() )
11221 : : {
11222 : : aLine.append( " aliased as \"" );
11223 : : aLine.append( rEle.m_aAlias );
11224 : : aLine.append( '\"' );
11225 : : }
11226 : : emitComment( aLine.getStr() );
11227 : : #endif
11228 : :
11229 : : // check whether to emit structure henceforth
11230 [ # # ]: 0 : m_bEmitStructure = checkEmitStructure();
11231 : :
11232 [ # # ]: 0 : if( m_bEmitStructure ) // don't create nonexistant objects
11233 : : {
11234 [ # # ]: 0 : rEle.m_nObject = createObject();
11235 : : // update parent's kids list
11236 [ # # ]: 0 : m_aStructure[ rEle.m_nParentElement ].m_aKids.push_back( rEle.m_nObject );
11237 : : }
11238 : 0 : return nNewId;
11239 : : }
11240 : :
11241 : 0 : void PDFWriterImpl::endStructureElement()
11242 : : {
11243 [ # # ]: 0 : if( m_nCurrentPage < 0 )
11244 : 0 : return;
11245 : :
11246 [ # # ]: 0 : if( ! m_aContext.Tagged )
11247 : 0 : return;
11248 : :
11249 [ # # ]: 0 : if( m_nCurrentStructElement == 0 )
11250 : : {
11251 : : // hit the struct tree root, that means there is an endStructureElement
11252 : : // without corresponding beginStructureElement
11253 : 0 : return;
11254 : : }
11255 : :
11256 : : // end the marked content sequence
11257 : 0 : endStructureElementMCSeq();
11258 : :
11259 : : #if OSL_DEBUG_LEVEL > 1
11260 : : OStringBuffer aLine( "endStructureElement " );
11261 : : aLine.append( m_nCurrentStructElement );
11262 : : aLine.append( ": " );
11263 : : aLine.append( getStructureTag( m_aStructure[ m_nCurrentStructElement ].m_eType ) );
11264 : : if( !m_aStructure[ m_nCurrentStructElement ].m_aAlias.isEmpty() )
11265 : : {
11266 : : aLine.append( " aliased as \"" );
11267 : : aLine.append( m_aStructure[ m_nCurrentStructElement ].m_aAlias );
11268 : : aLine.append( '\"' );
11269 : : }
11270 : : #endif
11271 : :
11272 : : // "end" the structure element, the parent becomes current element
11273 : 0 : m_nCurrentStructElement = m_aStructure[ m_nCurrentStructElement ].m_nParentElement;
11274 : :
11275 : : // check whether to emit structure henceforth
11276 : 0 : m_bEmitStructure = checkEmitStructure();
11277 : :
11278 : : #if OSL_DEBUG_LEVEL > 1
11279 : : if( m_bEmitStructure )
11280 : : emitComment( aLine.getStr() );
11281 : : #endif
11282 : : }
11283 : :
11284 : : //---> i94258
11285 : : /*
11286 : : * This function adds an internal structure list container to overcome the 8191 elements array limitation
11287 : : * in kids element emission.
11288 : : * Recursive function
11289 : : *
11290 : : */
11291 : 0 : void PDFWriterImpl::addInternalStructureContainer( PDFStructureElement& rEle )
11292 : : {
11293 [ # # ][ # # ]: 0 : if( rEle.m_eType == PDFWriter::NonStructElement &&
11294 : : rEle.m_nOwnElement != rEle.m_nParentElement )
11295 : 0 : return;
11296 : :
11297 [ # # ][ # # ]: 0 : for( std::list< sal_Int32 >::const_iterator it = rEle.m_aChildren.begin(); it != rEle.m_aChildren.end(); ++it )
[ # # ][ # # ]
[ # # ]
11298 : : {
11299 [ # # ][ # # ]: 0 : if( *it > 0 && *it < sal_Int32(m_aStructure.size()) )
[ # # ][ # # ]
[ # # ]
11300 : : {
11301 [ # # ]: 0 : PDFStructureElement& rChild = m_aStructure[ *it ];
11302 [ # # ]: 0 : if( rChild.m_eType != PDFWriter::NonStructElement )
11303 : : {
11304 : : //triggered when a child of the rEle element is found
11305 [ # # ]: 0 : if( rChild.m_nParentElement == rEle.m_nOwnElement )
11306 [ # # ]: 0 : addInternalStructureContainer( rChild );//examine the child
11307 : : else
11308 : : {
11309 : : OSL_FAIL( "PDFWriterImpl::addInternalStructureContainer: invalid child structure element" );
11310 : : #if OSL_DEBUG_LEVEL > 1
11311 : : fprintf( stderr, "PDFWriterImpl::addInternalStructureContainer: invalid child structure elemnt with id %" SAL_PRIdINT32 "\n", *it );
11312 : : #endif
11313 : : }
11314 : : }
11315 : : }
11316 : : else
11317 : : {
11318 : : OSL_FAIL( "PDFWriterImpl::emitStructure: invalid child structure id" );
11319 : : #if OSL_DEBUG_LEVEL > 1
11320 : : fprintf( stderr, "PDFWriterImpl::addInternalStructureContainer: invalid child structure id %" SAL_PRIdINT32 "\n", *it );
11321 : : #endif
11322 : : }
11323 : : }
11324 : :
11325 [ # # ]: 0 : if( rEle.m_nOwnElement != rEle.m_nParentElement )
11326 : : {
11327 [ # # ]: 0 : if( !rEle.m_aKids.empty() )
11328 : : {
11329 [ # # ]: 0 : if( rEle.m_aKids.size() > ncMaxPDFArraySize ) {
11330 : : //then we need to add the containers for the kids elements
11331 : : // a list to be used for the new kid element
11332 [ # # ]: 0 : std::list< PDFStructureElementKid > aNewKids;
11333 [ # # ]: 0 : std::list< sal_Int32 > aNewChildren;
11334 : :
11335 : : // add Div in RoleMap, in case no one else did (TODO: is it needed? Is it dangerous?)
11336 : 0 : OStringBuffer aNameBuf( "Div" );
11337 : 0 : OString aAliasName( aNameBuf.makeStringAndClear() );
11338 [ # # ][ # # ]: 0 : m_aRoleMap[ aAliasName ] = getStructureTag( PDFWriter::Division );
11339 : :
11340 [ # # ]: 0 : while( rEle.m_aKids.size() > ncMaxPDFArraySize )
11341 : : {
11342 : 0 : sal_Int32 nCurrentStructElement = rEle.m_nOwnElement;
11343 : 0 : sal_Int32 nNewId = sal_Int32(m_aStructure.size());
11344 [ # # ][ # # ]: 0 : m_aStructure.push_back( PDFStructureElement() );
11345 [ # # ]: 0 : PDFStructureElement& rEleNew = m_aStructure.back();
11346 : 0 : rEleNew.m_aAlias = aAliasName;
11347 : 0 : rEleNew.m_eType = PDFWriter::Division; // a new Div type container
11348 : 0 : rEleNew.m_nOwnElement = nNewId;
11349 : 0 : rEleNew.m_nParentElement = nCurrentStructElement;
11350 : : //inherit the same page as the first child to be reparented
11351 [ # # ]: 0 : rEleNew.m_nFirstPageObject = m_aStructure[ rEle.m_aChildren.front() ].m_nFirstPageObject;
11352 [ # # ]: 0 : rEleNew.m_nObject = createObject();//assign a PDF object number
11353 : : //add the object to the kid list of the parent
11354 [ # # ]: 0 : aNewKids.push_back( PDFStructureElementKid( rEleNew.m_nObject ) );
11355 [ # # ]: 0 : aNewChildren.push_back( nNewId );
11356 : :
11357 : 0 : std::list< sal_Int32 >::iterator aChildEndIt( rEle.m_aChildren.begin() );
11358 : 0 : std::list< PDFStructureElementKid >::iterator aKidEndIt( rEle.m_aKids.begin() );
11359 [ # # ]: 0 : advance( aChildEndIt, ncMaxPDFArraySize );
11360 [ # # ]: 0 : advance( aKidEndIt, ncMaxPDFArraySize );
11361 : :
11362 : : rEleNew.m_aKids.splice( rEleNew.m_aKids.begin(),
11363 : : rEle.m_aKids,
11364 : : rEle.m_aKids.begin(),
11365 [ # # ]: 0 : aKidEndIt );
11366 : : rEleNew.m_aChildren.splice( rEleNew.m_aChildren.begin(),
11367 : : rEle.m_aChildren,
11368 : : rEle.m_aChildren.begin(),
11369 [ # # ]: 0 : aChildEndIt );
11370 : : // set the kid's new parent
11371 [ # # ][ # # ]: 0 : for( std::list< sal_Int32 >::const_iterator it = rEleNew.m_aChildren.begin();
[ # # ][ # # ]
11372 [ # # ]: 0 : it != rEleNew.m_aChildren.end(); ++it )
11373 : : {
11374 [ # # ]: 0 : m_aStructure[ *it ].m_nParentElement = nNewId;
11375 : : }
11376 : : }
11377 : : //finally add the new kids resulting from the container added
11378 [ # # ]: 0 : rEle.m_aKids.insert( rEle.m_aKids.begin(), aNewKids.begin(), aNewKids.end() );
11379 [ # # ]: 0 : rEle.m_aChildren.insert( rEle.m_aChildren.begin(), aNewChildren.begin(), aNewChildren.end() );
11380 : : }
11381 : : }
11382 : : }
11383 : : }
11384 : : //<--- i94258
11385 : :
11386 : 0 : bool PDFWriterImpl::setCurrentStructureElement( sal_Int32 nEle )
11387 : : {
11388 : 0 : bool bSuccess = false;
11389 : :
11390 [ # # ][ # # ]: 0 : if( m_aContext.Tagged && nEle >= 0 && nEle < sal_Int32(m_aStructure.size()) )
[ # # ][ # # ]
11391 : : {
11392 : : // end eventual previous marked content sequence
11393 : 0 : endStructureElementMCSeq();
11394 : :
11395 : 0 : m_nCurrentStructElement = nEle;
11396 : 0 : m_bEmitStructure = checkEmitStructure();
11397 : : #if OSL_DEBUG_LEVEL > 1
11398 : : OStringBuffer aLine( "setCurrentStructureElement " );
11399 : : aLine.append( m_nCurrentStructElement );
11400 : : aLine.append( ": " );
11401 : : aLine.append( getStructureTag( m_aStructure[ m_nCurrentStructElement ].m_eType ) );
11402 : : if( !m_aStructure[ m_nCurrentStructElement ].m_aAlias.isEmpty() )
11403 : : {
11404 : : aLine.append( " aliased as \"" );
11405 : : aLine.append( m_aStructure[ m_nCurrentStructElement ].m_aAlias );
11406 : : aLine.append( '\"' );
11407 : : }
11408 : : if( ! m_bEmitStructure )
11409 : : aLine.append( " (inside NonStruct)" );
11410 : : emitComment( aLine.getStr() );
11411 : : #endif
11412 : 0 : bSuccess = true;
11413 : : }
11414 : :
11415 : 0 : return bSuccess;
11416 : : }
11417 : :
11418 : 0 : bool PDFWriterImpl::setStructureAttribute( enum PDFWriter::StructAttribute eAttr, enum PDFWriter::StructAttributeValue eVal )
11419 : : {
11420 [ # # ]: 0 : if( !m_aContext.Tagged )
11421 : 0 : return false;
11422 : :
11423 : 0 : bool bInsert = false;
11424 [ # # ][ # # ]: 0 : if( m_nCurrentStructElement > 0 && m_bEmitStructure )
11425 : : {
11426 : 0 : PDFWriter::StructElement eType = m_aStructure[ m_nCurrentStructElement ].m_eType;
11427 [ # # # # : 0 : switch( eAttr )
# # # # #
# ]
11428 : : {
11429 : : case PDFWriter::Placement:
11430 [ # # ][ # # ]: 0 : if( eVal == PDFWriter::Block ||
[ # # ][ # # ]
[ # # ]
11431 : : eVal == PDFWriter::Inline ||
11432 : : eVal == PDFWriter::Before ||
11433 : : eVal == PDFWriter::Start ||
11434 : : eVal == PDFWriter::End )
11435 : 0 : bInsert = true;
11436 : 0 : break;
11437 : : case PDFWriter::WritingMode:
11438 [ # # ][ # # ]: 0 : if( eVal == PDFWriter::LrTb ||
[ # # ]
11439 : : eVal == PDFWriter::RlTb ||
11440 : : eVal == PDFWriter::TbRl )
11441 : : {
11442 : 0 : bInsert = true;
11443 : : }
11444 : 0 : break;
11445 : : case PDFWriter::TextAlign:
11446 [ # # ][ # # ]: 0 : if( eVal == PDFWriter::Start ||
[ # # ][ # # ]
11447 : : eVal == PDFWriter::Center ||
11448 : : eVal == PDFWriter::End ||
11449 : : eVal == PDFWriter::Justify )
11450 : : {
11451 [ # # ][ # # ]: 0 : if( eType == PDFWriter::Paragraph ||
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
11452 : : eType == PDFWriter::Heading ||
11453 : : eType == PDFWriter::H1 ||
11454 : : eType == PDFWriter::H2 ||
11455 : : eType == PDFWriter::H3 ||
11456 : : eType == PDFWriter::H4 ||
11457 : : eType == PDFWriter::H5 ||
11458 : : eType == PDFWriter::H6 ||
11459 : : eType == PDFWriter::List ||
11460 : : eType == PDFWriter::ListItem ||
11461 : : eType == PDFWriter::LILabel ||
11462 : : eType == PDFWriter::LIBody ||
11463 : : eType == PDFWriter::Table ||
11464 : : eType == PDFWriter::TableRow ||
11465 : : eType == PDFWriter::TableHeader ||
11466 : : eType == PDFWriter::TableData )
11467 : : {
11468 : 0 : bInsert = true;
11469 : : }
11470 : : }
11471 : 0 : break;
11472 : : case PDFWriter::Width:
11473 : : case PDFWriter::Height:
11474 [ # # ]: 0 : if( eVal == PDFWriter::Auto )
11475 : : {
11476 [ # # ][ # # ]: 0 : if( eType == PDFWriter::Figure ||
[ # # ][ # # ]
[ # # ][ # # ]
11477 : : eType == PDFWriter::Formula ||
11478 : : eType == PDFWriter::Form ||
11479 : : eType == PDFWriter::Table ||
11480 : : eType == PDFWriter::TableHeader ||
11481 : : eType == PDFWriter::TableData )
11482 : : {
11483 : 0 : bInsert = true;
11484 : : }
11485 : : }
11486 : 0 : break;
11487 : : case PDFWriter::BlockAlign:
11488 [ # # ][ # # ]: 0 : if( eVal == PDFWriter::Before ||
[ # # ][ # # ]
11489 : : eVal == PDFWriter::Middle ||
11490 : : eVal == PDFWriter::After ||
11491 : : eVal == PDFWriter::Justify )
11492 : : {
11493 [ # # ][ # # ]: 0 : if( eType == PDFWriter::TableHeader ||
11494 : : eType == PDFWriter::TableData )
11495 : : {
11496 : 0 : bInsert = true;
11497 : : }
11498 : : }
11499 : 0 : break;
11500 : : case PDFWriter::InlineAlign:
11501 [ # # ][ # # ]: 0 : if( eVal == PDFWriter::Start ||
[ # # ]
11502 : : eVal == PDFWriter::Center ||
11503 : : eVal == PDFWriter::End )
11504 : : {
11505 [ # # ][ # # ]: 0 : if( eType == PDFWriter::TableHeader ||
11506 : : eType == PDFWriter::TableData )
11507 : : {
11508 : 0 : bInsert = true;
11509 : : }
11510 : : }
11511 : 0 : break;
11512 : : case PDFWriter::LineHeight:
11513 [ # # ][ # # ]: 0 : if( eVal == PDFWriter::Normal ||
11514 : : eVal == PDFWriter::Auto )
11515 : : {
11516 : : // only for ILSE and BLSE
11517 [ # # ][ # # ]: 0 : if( eType == PDFWriter::Paragraph ||
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
11518 : : eType == PDFWriter::Heading ||
11519 : : eType == PDFWriter::H1 ||
11520 : : eType == PDFWriter::H2 ||
11521 : : eType == PDFWriter::H3 ||
11522 : : eType == PDFWriter::H4 ||
11523 : : eType == PDFWriter::H5 ||
11524 : : eType == PDFWriter::H6 ||
11525 : : eType == PDFWriter::List ||
11526 : : eType == PDFWriter::ListItem ||
11527 : : eType == PDFWriter::LILabel ||
11528 : : eType == PDFWriter::LIBody ||
11529 : : eType == PDFWriter::Table ||
11530 : : eType == PDFWriter::TableRow ||
11531 : : eType == PDFWriter::TableHeader ||
11532 : : eType == PDFWriter::TableData ||
11533 : : eType == PDFWriter::Span ||
11534 : : eType == PDFWriter::Quote ||
11535 : : eType == PDFWriter::Note ||
11536 : : eType == PDFWriter::Reference ||
11537 : : eType == PDFWriter::BibEntry ||
11538 : : eType == PDFWriter::Code ||
11539 : : eType == PDFWriter::Link )
11540 : : {
11541 : 0 : bInsert = true;
11542 : : }
11543 : : }
11544 : 0 : break;
11545 : : case PDFWriter::TextDecorationType:
11546 [ # # ][ # # ]: 0 : if( eVal == PDFWriter::NONE ||
[ # # ][ # # ]
11547 : : eVal == PDFWriter::Underline ||
11548 : : eVal == PDFWriter::Overline ||
11549 : : eVal == PDFWriter::LineThrough )
11550 : : {
11551 : : // only for ILSE and BLSE
11552 [ # # ][ # # ]: 0 : if( eType == PDFWriter::Paragraph ||
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
11553 : : eType == PDFWriter::Heading ||
11554 : : eType == PDFWriter::H1 ||
11555 : : eType == PDFWriter::H2 ||
11556 : : eType == PDFWriter::H3 ||
11557 : : eType == PDFWriter::H4 ||
11558 : : eType == PDFWriter::H5 ||
11559 : : eType == PDFWriter::H6 ||
11560 : : eType == PDFWriter::List ||
11561 : : eType == PDFWriter::ListItem ||
11562 : : eType == PDFWriter::LILabel ||
11563 : : eType == PDFWriter::LIBody ||
11564 : : eType == PDFWriter::Table ||
11565 : : eType == PDFWriter::TableRow ||
11566 : : eType == PDFWriter::TableHeader ||
11567 : : eType == PDFWriter::TableData ||
11568 : : eType == PDFWriter::Span ||
11569 : : eType == PDFWriter::Quote ||
11570 : : eType == PDFWriter::Note ||
11571 : : eType == PDFWriter::Reference ||
11572 : : eType == PDFWriter::BibEntry ||
11573 : : eType == PDFWriter::Code ||
11574 : : eType == PDFWriter::Link )
11575 : : {
11576 : 0 : bInsert = true;
11577 : : }
11578 : : }
11579 : 0 : break;
11580 : : case PDFWriter::ListNumbering:
11581 [ # # ][ # # ]: 0 : if( eVal == PDFWriter::NONE ||
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
11582 : : eVal == PDFWriter::Disc ||
11583 : : eVal == PDFWriter::Circle ||
11584 : : eVal == PDFWriter::Square ||
11585 : : eVal == PDFWriter::Decimal ||
11586 : : eVal == PDFWriter::UpperRoman ||
11587 : : eVal == PDFWriter::LowerRoman ||
11588 : : eVal == PDFWriter::UpperAlpha ||
11589 : : eVal == PDFWriter::LowerAlpha )
11590 : : {
11591 [ # # ]: 0 : if( eType == PDFWriter::List )
11592 : 0 : bInsert = true;
11593 : : }
11594 : 0 : break;
11595 : 0 : default: break;
11596 : : }
11597 : : }
11598 : :
11599 [ # # ]: 0 : if( bInsert )
11600 : 0 : m_aStructure[ m_nCurrentStructElement ].m_aAttributes[ eAttr ] = PDFStructureAttribute( eVal );
11601 : : #if OSL_DEBUG_LEVEL > 1
11602 : : else if( m_nCurrentStructElement > 0 && m_bEmitStructure )
11603 : : fprintf( stderr, "rejecting setStructureAttribute( %s, %s ) on %s (%s) element\n",
11604 : : getAttributeTag( eAttr ),
11605 : : getAttributeValueTag( eVal ),
11606 : : getStructureTag( m_aStructure[ m_nCurrentStructElement ].m_eType ),
11607 : : m_aStructure[ m_nCurrentStructElement ].m_aAlias.getStr()
11608 : : );
11609 : : #endif
11610 : :
11611 : 0 : return bInsert;
11612 : : }
11613 : :
11614 : 0 : bool PDFWriterImpl::setStructureAttributeNumerical( enum PDFWriter::StructAttribute eAttr, sal_Int32 nValue )
11615 : : {
11616 [ # # ]: 0 : if( ! m_aContext.Tagged )
11617 : 0 : return false;
11618 : :
11619 : 0 : bool bInsert = false;
11620 [ # # ][ # # ]: 0 : if( m_nCurrentStructElement > 0 && m_bEmitStructure )
11621 : : {
11622 [ # # ]: 0 : if( eAttr == PDFWriter::Language )
11623 : : {
11624 : 0 : m_aStructure[ m_nCurrentStructElement ].m_aLocale = MsLangId::convertLanguageToLocale( (LanguageType)nValue );
11625 : 0 : return true;
11626 : : }
11627 : :
11628 : 0 : PDFWriter::StructElement eType = m_aStructure[ m_nCurrentStructElement ].m_eType;
11629 [ # # # # : 0 : switch( eAttr )
# # # ]
11630 : : {
11631 : : case PDFWriter::SpaceBefore:
11632 : : case PDFWriter::SpaceAfter:
11633 : : case PDFWriter::StartIndent:
11634 : : case PDFWriter::EndIndent:
11635 : : // just for BLSE
11636 [ # # ][ # # ]: 0 : if( eType == PDFWriter::Paragraph ||
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
11637 : : eType == PDFWriter::Heading ||
11638 : : eType == PDFWriter::H1 ||
11639 : : eType == PDFWriter::H2 ||
11640 : : eType == PDFWriter::H3 ||
11641 : : eType == PDFWriter::H4 ||
11642 : : eType == PDFWriter::H5 ||
11643 : : eType == PDFWriter::H6 ||
11644 : : eType == PDFWriter::List ||
11645 : : eType == PDFWriter::ListItem ||
11646 : : eType == PDFWriter::LILabel ||
11647 : : eType == PDFWriter::LIBody ||
11648 : : eType == PDFWriter::Table ||
11649 : : eType == PDFWriter::TableRow ||
11650 : : eType == PDFWriter::TableHeader ||
11651 : : eType == PDFWriter::TableData )
11652 : : {
11653 : 0 : bInsert = true;
11654 : : }
11655 : 0 : break;
11656 : : case PDFWriter::TextIndent:
11657 : : // paragraph like BLSE and additional elements
11658 [ # # ][ # # ]: 0 : if( eType == PDFWriter::Paragraph ||
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
11659 : : eType == PDFWriter::Heading ||
11660 : : eType == PDFWriter::H1 ||
11661 : : eType == PDFWriter::H2 ||
11662 : : eType == PDFWriter::H3 ||
11663 : : eType == PDFWriter::H4 ||
11664 : : eType == PDFWriter::H5 ||
11665 : : eType == PDFWriter::H6 ||
11666 : : eType == PDFWriter::LILabel ||
11667 : : eType == PDFWriter::LIBody ||
11668 : : eType == PDFWriter::TableHeader ||
11669 : : eType == PDFWriter::TableData )
11670 : : {
11671 : 0 : bInsert = true;
11672 : : }
11673 : 0 : break;
11674 : : case PDFWriter::Width:
11675 : : case PDFWriter::Height:
11676 [ # # ][ # # ]: 0 : if( eType == PDFWriter::Figure ||
[ # # ][ # # ]
[ # # ][ # # ]
11677 : : eType == PDFWriter::Formula ||
11678 : : eType == PDFWriter::Form ||
11679 : : eType == PDFWriter::Table ||
11680 : : eType == PDFWriter::TableHeader ||
11681 : : eType == PDFWriter::TableData )
11682 : : {
11683 : 0 : bInsert = true;
11684 : : }
11685 : 0 : break;
11686 : : case PDFWriter::LineHeight:
11687 : : case PDFWriter::BaselineShift:
11688 : : // only for ILSE and BLSE
11689 [ # # ][ # # ]: 0 : if( eType == PDFWriter::Paragraph ||
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
11690 : : eType == PDFWriter::Heading ||
11691 : : eType == PDFWriter::H1 ||
11692 : : eType == PDFWriter::H2 ||
11693 : : eType == PDFWriter::H3 ||
11694 : : eType == PDFWriter::H4 ||
11695 : : eType == PDFWriter::H5 ||
11696 : : eType == PDFWriter::H6 ||
11697 : : eType == PDFWriter::List ||
11698 : : eType == PDFWriter::ListItem ||
11699 : : eType == PDFWriter::LILabel ||
11700 : : eType == PDFWriter::LIBody ||
11701 : : eType == PDFWriter::Table ||
11702 : : eType == PDFWriter::TableRow ||
11703 : : eType == PDFWriter::TableHeader ||
11704 : : eType == PDFWriter::TableData ||
11705 : : eType == PDFWriter::Span ||
11706 : : eType == PDFWriter::Quote ||
11707 : : eType == PDFWriter::Note ||
11708 : : eType == PDFWriter::Reference ||
11709 : : eType == PDFWriter::BibEntry ||
11710 : : eType == PDFWriter::Code ||
11711 : : eType == PDFWriter::Link )
11712 : : {
11713 : 0 : bInsert = true;
11714 : : }
11715 : 0 : break;
11716 : : case PDFWriter::RowSpan:
11717 : : case PDFWriter::ColSpan:
11718 : : // only for table cells
11719 [ # # ][ # # ]: 0 : if( eType == PDFWriter::TableHeader ||
11720 : : eType == PDFWriter::TableData )
11721 : : {
11722 : 0 : bInsert = true;
11723 : : }
11724 : 0 : break;
11725 : : case PDFWriter::LinkAnnotation:
11726 [ # # ]: 0 : if( eType == PDFWriter::Link )
11727 : 0 : bInsert = true;
11728 : 0 : break;
11729 : 0 : default: break;
11730 : : }
11731 : : }
11732 : :
11733 [ # # ]: 0 : if( bInsert )
11734 : 0 : m_aStructure[ m_nCurrentStructElement ].m_aAttributes[ eAttr ] = PDFStructureAttribute( nValue );
11735 : : #if OSL_DEBUG_LEVEL > 1
11736 : : else if( m_nCurrentStructElement > 0 && m_bEmitStructure )
11737 : : fprintf( stderr, "rejecting setStructureAttributeNumerical( %s, %d ) on %s (%s) element\n",
11738 : : getAttributeTag( eAttr ),
11739 : : (int)nValue,
11740 : : getStructureTag( m_aStructure[ m_nCurrentStructElement ].m_eType ),
11741 : : m_aStructure[ m_nCurrentStructElement ].m_aAlias.getStr() );
11742 : : #endif
11743 : :
11744 : 0 : return bInsert;
11745 : : }
11746 : :
11747 : 0 : void PDFWriterImpl::setStructureBoundingBox( const Rectangle& rRect )
11748 : : {
11749 : 0 : sal_Int32 nPageNr = m_nCurrentPage;
11750 [ # # ][ # # ]: 0 : if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() || !m_aContext.Tagged )
[ # # ][ # # ]
11751 : 0 : return;
11752 : :
11753 : :
11754 [ # # ][ # # ]: 0 : if( m_nCurrentStructElement > 0 && m_bEmitStructure )
11755 : : {
11756 : 0 : PDFWriter::StructElement eType = m_aStructure[ m_nCurrentStructElement ].m_eType;
11757 [ # # ][ # # ]: 0 : if( eType == PDFWriter::Figure ||
[ # # ][ # # ]
11758 : : eType == PDFWriter::Formula ||
11759 : : eType == PDFWriter::Form ||
11760 : : eType == PDFWriter::Table )
11761 : : {
11762 : 0 : m_aStructure[ m_nCurrentStructElement ].m_aBBox = rRect;
11763 : : // convert to default user space now, since the mapmode may change
11764 : 0 : m_aPages[nPageNr].convertRect( m_aStructure[ m_nCurrentStructElement ].m_aBBox );
11765 : : }
11766 : : }
11767 : : }
11768 : :
11769 : 0 : void PDFWriterImpl::setActualText( const String& rText )
11770 : : {
11771 [ # # ][ # # ]: 0 : if( m_aContext.Tagged && m_nCurrentStructElement > 0 && m_bEmitStructure )
[ # # ]
11772 : : {
11773 : 0 : m_aStructure[ m_nCurrentStructElement ].m_aActualText = rText;
11774 : : }
11775 : 0 : }
11776 : :
11777 : 0 : void PDFWriterImpl::setAlternateText( const String& rText )
11778 : : {
11779 [ # # ][ # # ]: 0 : if( m_aContext.Tagged && m_nCurrentStructElement > 0 && m_bEmitStructure )
[ # # ]
11780 : : {
11781 : 0 : m_aStructure[ m_nCurrentStructElement ].m_aAltText = rText;
11782 : : }
11783 : 0 : }
11784 : :
11785 : 0 : void PDFWriterImpl::setAutoAdvanceTime( sal_uInt32 nSeconds, sal_Int32 nPageNr )
11786 : : {
11787 [ # # ]: 0 : if( nPageNr < 0 )
11788 : 0 : nPageNr = m_nCurrentPage;
11789 : :
11790 [ # # ][ # # ]: 0 : if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() )
[ # # ]
11791 : 0 : return;
11792 : :
11793 : 0 : m_aPages[ nPageNr ].m_nDuration = nSeconds;
11794 : : }
11795 : :
11796 : 0 : void PDFWriterImpl::setPageTransition( PDFWriter::PageTransition eType, sal_uInt32 nMilliSec, sal_Int32 nPageNr )
11797 : : {
11798 [ # # ]: 0 : if( nPageNr < 0 )
11799 : 0 : nPageNr = m_nCurrentPage;
11800 : :
11801 [ # # ][ # # ]: 0 : if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() )
[ # # ]
11802 : 0 : return;
11803 : :
11804 : 0 : m_aPages[ nPageNr ].m_eTransition = eType;
11805 : 0 : m_aPages[ nPageNr ].m_nTransTime = nMilliSec;
11806 : : }
11807 : :
11808 : 0 : void PDFWriterImpl::ensureUniqueRadioOnValues()
11809 : : {
11810 : : // loop over radio groups
11811 [ # # ][ # # ]: 0 : for( std::map<sal_Int32,sal_Int32>::const_iterator group = m_aRadioGroupWidgets.begin();
[ # # ][ # # ]
11812 [ # # ]: 0 : group != m_aRadioGroupWidgets.end(); ++group )
11813 : : {
11814 [ # # ]: 0 : PDFWidget& rGroupWidget = m_aWidgets[ group->second ];
11815 : : // check whether all kids have a unique OnValue
11816 [ # # ]: 0 : boost::unordered_map< OUString, sal_Int32, OUStringHash > aOnValues;
11817 : 0 : int nChildren = rGroupWidget.m_aKidsIndex.size();
11818 : 0 : bool bIsUnique = true;
11819 [ # # ][ # # ]: 0 : for( int nKid = 0; nKid < nChildren && bIsUnique; nKid++ )
[ # # ]
11820 : : {
11821 [ # # ]: 0 : int nKidIndex = rGroupWidget.m_aKidsIndex[nKid];
11822 : 0 : const OUString& rVal = m_aWidgets[nKidIndex].m_aOnValue;
11823 : : #if OSL_DEBUG_LEVEL > 1
11824 : : fprintf( stderr, "OnValue: %s\n", OUStringToOString( rVal, RTL_TEXTENCODING_UTF8 ).getStr() );
11825 : : #endif
11826 [ # # ][ # # ]: 0 : if( aOnValues.find( rVal ) == aOnValues.end() )
[ # # ]
11827 : : {
11828 [ # # ]: 0 : aOnValues[ rVal ] = 1;
11829 : : }
11830 : : else
11831 : : {
11832 : 0 : bIsUnique = false;
11833 : : }
11834 : : }
11835 [ # # ]: 0 : if( ! bIsUnique )
11836 : : {
11837 : : #if OSL_DEBUG_LEVEL > 1
11838 : : fprintf( stderr, "enforcing unique OnValues\n" );
11839 : : #endif
11840 : : // make unique by using ascending OnValues
11841 [ # # ]: 0 : for( int nKid = 0; nKid < nChildren; nKid++ )
11842 : : {
11843 [ # # ]: 0 : int nKidIndex = rGroupWidget.m_aKidsIndex[nKid];
11844 : 0 : PDFWidget& rKid = m_aWidgets[nKidIndex];
11845 : 0 : rKid.m_aOnValue = OUString::valueOf( sal_Int32(nKid+1) );
11846 [ # # ]: 0 : if( rKid.m_aValue != "Off" )
11847 : 0 : rKid.m_aValue = rKid.m_aOnValue;
11848 : : }
11849 : : }
11850 : : // finally move the "Yes" appearance to the OnValue appearance
11851 [ # # ]: 0 : for( int nKid = 0; nKid < nChildren; nKid++ )
11852 : : {
11853 [ # # ]: 0 : int nKidIndex = rGroupWidget.m_aKidsIndex[nKid];
11854 : 0 : PDFWidget& rKid = m_aWidgets[nKidIndex];
11855 [ # # ]: 0 : PDFAppearanceMap::iterator app_it = rKid.m_aAppearances.find( "N" );
11856 [ # # ][ # # ]: 0 : if( app_it != rKid.m_aAppearances.end() )
11857 : : {
11858 [ # # ][ # # ]: 0 : PDFAppearanceStreams::iterator stream_it = app_it->second.find( "Yes" );
11859 [ # # ][ # # ]: 0 : if( stream_it != app_it->second.end() )
[ # # ]
11860 : : {
11861 [ # # ]: 0 : SvMemoryStream* pStream = stream_it->second;
11862 [ # # ][ # # ]: 0 : app_it->second.erase( stream_it );
11863 : 0 : OStringBuffer aBuf( rKid.m_aOnValue.getLength()*2 );
11864 [ # # ]: 0 : appendName( rKid.m_aOnValue, aBuf );
11865 [ # # ][ # # ]: 0 : (app_it->second)[ aBuf.makeStringAndClear() ] = pStream;
11866 : : }
11867 : : #if OSL_DEBUG_LEVEL > 1
11868 : : else
11869 : : fprintf( stderr, "error: RadioButton without \"Yes\" stream\n" );
11870 : : #endif
11871 : : }
11872 : : // update selected radio button
11873 [ # # ]: 0 : if( rKid.m_aValue != "Off" )
11874 : : {
11875 : 0 : rGroupWidget.m_aValue = rKid.m_aValue;
11876 : : }
11877 : : }
11878 [ # # ]: 0 : }
11879 : 0 : }
11880 : :
11881 : 0 : sal_Int32 PDFWriterImpl::findRadioGroupWidget( const PDFWriter::RadioButtonWidget& rBtn )
11882 : : {
11883 : 0 : sal_Int32 nRadioGroupWidget = -1;
11884 : :
11885 [ # # ][ # # ]: 0 : std::map< sal_Int32, sal_Int32 >::const_iterator it = m_aRadioGroupWidgets.find( rBtn.RadioGroup );
11886 : :
11887 [ # # ][ # # ]: 0 : if( it == m_aRadioGroupWidgets.end() )
[ # # ]
11888 : : {
11889 [ # # ]: 0 : m_aRadioGroupWidgets[ rBtn.RadioGroup ] = nRadioGroupWidget =
11890 : 0 : sal_Int32(m_aWidgets.size());
11891 : :
11892 : : // new group, insert the radiobutton
11893 [ # # ][ # # ]: 0 : m_aWidgets.push_back( PDFWidget() );
[ # # ]
11894 [ # # ][ # # ]: 0 : m_aWidgets.back().m_nObject = createObject();
11895 [ # # ]: 0 : m_aWidgets.back().m_nPage = m_nCurrentPage;
11896 [ # # ]: 0 : m_aWidgets.back().m_eType = PDFWriter::RadioButton;
11897 [ # # ]: 0 : m_aWidgets.back().m_nRadioGroup = rBtn.RadioGroup;
11898 [ # # ]: 0 : m_aWidgets.back().m_nFlags |= 0x0000C000; // NoToggleToOff and Radio bits
11899 : :
11900 [ # # ]: 0 : createWidgetFieldName( sal_Int32(m_aWidgets.size()-1), rBtn );
11901 : : }
11902 : : else
11903 [ # # ]: 0 : nRadioGroupWidget = it->second;
11904 : :
11905 : 0 : return nRadioGroupWidget;
11906 : : }
11907 : :
11908 : 0 : sal_Int32 PDFWriterImpl::createControl( const PDFWriter::AnyWidget& rControl, sal_Int32 nPageNr )
11909 : : {
11910 [ # # ]: 0 : if( nPageNr < 0 )
11911 : 0 : nPageNr = m_nCurrentPage;
11912 : :
11913 [ # # ][ # # ]: 0 : if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() )
[ # # ]
11914 : 0 : return -1;
11915 : :
11916 : 0 : bool sigHidden(true);
11917 : 0 : sal_Int32 nNewWidget = m_aWidgets.size();
11918 [ # # ][ # # ]: 0 : m_aWidgets.push_back( PDFWidget() );
[ # # ]
11919 : :
11920 [ # # ][ # # ]: 0 : m_aWidgets.back().m_nObject = createObject();
11921 [ # # ]: 0 : m_aWidgets.back().m_aRect = rControl.Location;
11922 [ # # ]: 0 : m_aWidgets.back().m_nPage = nPageNr;
11923 [ # # ]: 0 : m_aWidgets.back().m_eType = rControl.getType();
11924 : :
11925 : 0 : sal_Int32 nRadioGroupWidget = -1;
11926 : : // for unknown reasons the radio buttons of a radio group must not have a
11927 : : // field name, else the buttons are in fact check boxes -
11928 : : // that is multiple buttons of the radio group can be selected
11929 [ # # ]: 0 : if( rControl.getType() == PDFWriter::RadioButton )
11930 [ # # ]: 0 : nRadioGroupWidget = findRadioGroupWidget( static_cast<const PDFWriter::RadioButtonWidget&>(rControl) );
11931 : : else
11932 : : {
11933 [ # # ]: 0 : createWidgetFieldName( nNewWidget, rControl );
11934 : : }
11935 : :
11936 : : // caution: m_aWidgets must not be changed after here or rNewWidget may be invalid
11937 : 0 : PDFWidget& rNewWidget = m_aWidgets[nNewWidget];
11938 : 0 : rNewWidget.m_aDescription = rControl.Description;
11939 : 0 : rNewWidget.m_aText = rControl.Text;
11940 : : rNewWidget.m_nTextStyle = rControl.TextStyle &
11941 : : ( TEXT_DRAW_LEFT | TEXT_DRAW_CENTER | TEXT_DRAW_RIGHT | TEXT_DRAW_TOP |
11942 : : TEXT_DRAW_VCENTER | TEXT_DRAW_BOTTOM |
11943 : 0 : TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK );
11944 : 0 : rNewWidget.m_nTabOrder = rControl.TabOrder;
11945 : :
11946 : : // various properties are set via the flags (/Ff) property of the field dict
11947 [ # # ]: 0 : if( rControl.ReadOnly )
11948 : 0 : rNewWidget.m_nFlags |= 1;
11949 [ # # ]: 0 : if( rControl.getType() == PDFWriter::PushButton )
11950 : : {
11951 : 0 : const PDFWriter::PushButtonWidget& rBtn = static_cast<const PDFWriter::PushButtonWidget&>(rControl);
11952 [ # # ]: 0 : if( rNewWidget.m_nTextStyle == 0 )
11953 : : rNewWidget.m_nTextStyle =
11954 : : TEXT_DRAW_CENTER | TEXT_DRAW_VCENTER |
11955 : 0 : TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK;
11956 : :
11957 : 0 : rNewWidget.m_nFlags |= 0x00010000;
11958 [ # # ]: 0 : if( !rBtn.URL.isEmpty() )
11959 [ # # ]: 0 : rNewWidget.m_aListEntries.push_back( rBtn.URL );
11960 : 0 : rNewWidget.m_bSubmit = rBtn.Submit;
11961 : 0 : rNewWidget.m_bSubmitGet = rBtn.SubmitGet;
11962 : 0 : rNewWidget.m_nDest = rBtn.Dest;
11963 [ # # ]: 0 : createDefaultPushButtonAppearance( rNewWidget, rBtn );
11964 : : }
11965 [ # # ]: 0 : else if( rControl.getType() == PDFWriter::RadioButton )
11966 : : {
11967 : 0 : const PDFWriter::RadioButtonWidget& rBtn = static_cast<const PDFWriter::RadioButtonWidget&>(rControl);
11968 [ # # ]: 0 : if( rNewWidget.m_nTextStyle == 0 )
11969 : : rNewWidget.m_nTextStyle =
11970 : 0 : TEXT_DRAW_VCENTER | TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK;
11971 : : /* PDF sees a RadioButton group as one radio button with
11972 : : * children which are in turn check boxes
11973 : : *
11974 : : * so we need to create a radio button on demand for a new group
11975 : : * and insert a checkbox for each RadioButtonWidget as its child
11976 : : */
11977 : 0 : rNewWidget.m_eType = PDFWriter::CheckBox;
11978 : 0 : rNewWidget.m_nRadioGroup = rBtn.RadioGroup;
11979 : :
11980 : : DBG_ASSERT( nRadioGroupWidget >= 0 && nRadioGroupWidget < (sal_Int32)m_aWidgets.size(), "no radio group parent" );
11981 : :
11982 : 0 : PDFWidget& rRadioButton = m_aWidgets[nRadioGroupWidget];
11983 [ # # ]: 0 : rRadioButton.m_aKids.push_back( rNewWidget.m_nObject );
11984 [ # # ]: 0 : rRadioButton.m_aKidsIndex.push_back( nNewWidget );
11985 : 0 : rNewWidget.m_nParent = rRadioButton.m_nObject;
11986 : :
11987 : 0 : rNewWidget.m_aValue = OUString( "Off" );
11988 : 0 : rNewWidget.m_aOnValue = rBtn.OnValue;
11989 [ # # ][ # # ]: 0 : if( rRadioButton.m_aValue.isEmpty() && rBtn.Selected )
[ # # ]
11990 : : {
11991 : 0 : rNewWidget.m_aValue = rNewWidget.m_aOnValue;
11992 : 0 : rRadioButton.m_aValue = rNewWidget.m_aOnValue;
11993 : : }
11994 [ # # ]: 0 : createDefaultRadioButtonAppearance( rNewWidget, rBtn );
11995 : :
11996 : : // union rect of radio group
11997 : 0 : Rectangle aRect = rNewWidget.m_aRect;
11998 [ # # ]: 0 : m_aPages[ nPageNr ].convertRect( aRect );
11999 [ # # ]: 0 : rRadioButton.m_aRect.Union( aRect );
12000 : : }
12001 [ # # ]: 0 : else if( rControl.getType() == PDFWriter::CheckBox )
12002 : : {
12003 : 0 : const PDFWriter::CheckBoxWidget& rBox = static_cast<const PDFWriter::CheckBoxWidget&>(rControl);
12004 [ # # ]: 0 : if( rNewWidget.m_nTextStyle == 0 )
12005 : : rNewWidget.m_nTextStyle =
12006 : 0 : TEXT_DRAW_VCENTER | TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK;
12007 : :
12008 [ # # ][ # # ]: 0 : rNewWidget.m_aValue = rBox.Checked ? OUString("Yes") : OUString("Off" );
[ # # ]
12009 : : // create default appearance before m_aRect gets transformed
12010 [ # # ]: 0 : createDefaultCheckBoxAppearance( rNewWidget, rBox );
12011 : : }
12012 [ # # ]: 0 : else if( rControl.getType() == PDFWriter::ListBox )
12013 : : {
12014 [ # # ]: 0 : if( rNewWidget.m_nTextStyle == 0 )
12015 : 0 : rNewWidget.m_nTextStyle = TEXT_DRAW_VCENTER;
12016 : :
12017 : 0 : const PDFWriter::ListBoxWidget& rLstBox = static_cast<const PDFWriter::ListBoxWidget&>(rControl);
12018 [ # # ]: 0 : rNewWidget.m_aListEntries = rLstBox.Entries;
12019 [ # # ]: 0 : rNewWidget.m_aSelectedEntries = rLstBox.SelectedEntries;
12020 : 0 : rNewWidget.m_aValue = rLstBox.Text;
12021 [ # # ]: 0 : if( rLstBox.DropDown )
12022 : 0 : rNewWidget.m_nFlags |= 0x00020000;
12023 [ # # ]: 0 : if( rLstBox.Sort )
12024 : 0 : rNewWidget.m_nFlags |= 0x00080000;
12025 [ # # ][ # # ]: 0 : if( rLstBox.MultiSelect && !rLstBox.DropDown && (int)m_aContext.Version > (int)PDFWriter::PDF_1_3 )
[ # # ]
12026 : 0 : rNewWidget.m_nFlags |= 0x00200000;
12027 : :
12028 [ # # ]: 0 : createDefaultListBoxAppearance( rNewWidget, rLstBox );
12029 : : }
12030 [ # # ]: 0 : else if( rControl.getType() == PDFWriter::ComboBox )
12031 : : {
12032 [ # # ]: 0 : if( rNewWidget.m_nTextStyle == 0 )
12033 : 0 : rNewWidget.m_nTextStyle = TEXT_DRAW_VCENTER;
12034 : :
12035 : 0 : const PDFWriter::ComboBoxWidget& rBox = static_cast<const PDFWriter::ComboBoxWidget&>(rControl);
12036 : 0 : rNewWidget.m_aValue = rBox.Text;
12037 [ # # ]: 0 : rNewWidget.m_aListEntries = rBox.Entries;
12038 : 0 : rNewWidget.m_nFlags |= 0x00060000; // combo and edit flag
12039 [ # # ]: 0 : if( rBox.Sort )
12040 : 0 : rNewWidget.m_nFlags |= 0x00080000;
12041 : :
12042 [ # # ]: 0 : PDFWriter::ListBoxWidget aLBox;
12043 : 0 : aLBox.Name = rBox.Name;
12044 : 0 : aLBox.Description = rBox.Description;
12045 : 0 : aLBox.Text = rBox.Text;
12046 : 0 : aLBox.TextStyle = rBox.TextStyle;
12047 : 0 : aLBox.ReadOnly = rBox.ReadOnly;
12048 : 0 : aLBox.Border = rBox.Border;
12049 : 0 : aLBox.BorderColor = rBox.BorderColor;
12050 : 0 : aLBox.Background = rBox.Background;
12051 : 0 : aLBox.BackgroundColor = rBox.BackgroundColor;
12052 [ # # ]: 0 : aLBox.TextFont = rBox.TextFont;
12053 : 0 : aLBox.TextColor = rBox.TextColor;
12054 : 0 : aLBox.DropDown = true;
12055 : 0 : aLBox.Sort = rBox.Sort;
12056 : 0 : aLBox.MultiSelect = false;
12057 [ # # ]: 0 : aLBox.Entries = rBox.Entries;
12058 : :
12059 [ # # ][ # # ]: 0 : createDefaultListBoxAppearance( rNewWidget, aLBox );
12060 : : }
12061 [ # # ]: 0 : else if( rControl.getType() == PDFWriter::Edit )
12062 : : {
12063 [ # # ]: 0 : if( rNewWidget.m_nTextStyle == 0 )
12064 : 0 : rNewWidget.m_nTextStyle = TEXT_DRAW_LEFT | TEXT_DRAW_VCENTER;
12065 : :
12066 : 0 : const PDFWriter::EditWidget& rEdit = static_cast<const PDFWriter::EditWidget&>(rControl);
12067 [ # # ]: 0 : if( rEdit.MultiLine )
12068 : : {
12069 : 0 : rNewWidget.m_nFlags |= 0x00001000;
12070 : 0 : rNewWidget.m_nTextStyle |= TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK;
12071 : : }
12072 [ # # ]: 0 : if( rEdit.Password )
12073 : 0 : rNewWidget.m_nFlags |= 0x00002000;
12074 [ # # ][ # # ]: 0 : if( rEdit.FileSelect && m_aContext.Version > PDFWriter::PDF_1_3 )
12075 : 0 : rNewWidget.m_nFlags |= 0x00100000;
12076 : 0 : rNewWidget.m_nMaxLen = rEdit.MaxLen;
12077 : 0 : rNewWidget.m_aValue = rEdit.Text;
12078 : :
12079 [ # # ]: 0 : createDefaultEditAppearance( rNewWidget, rEdit );
12080 : : }
12081 : : #if !defined(ANDROID) && !defined(IOS)
12082 [ # # ]: 0 : else if( rControl.getType() == PDFWriter::Signature)
12083 : : {
12084 : 0 : const PDFWriter::SignatureWidget& rSig = static_cast<const PDFWriter::SignatureWidget&>(rControl);
12085 : 0 : sigHidden = rSig.SigHidden;
12086 : :
12087 [ # # ]: 0 : if ( sigHidden )
12088 [ # # ]: 0 : rNewWidget.m_aRect = Rectangle(0, 0, 0, 0);
12089 : :
12090 [ # # ]: 0 : m_nSignatureObject = createObject();
12091 : 0 : rNewWidget.m_aValue = OUString::valueOf( m_nSignatureObject );
12092 : 0 : rNewWidget.m_aValue += OUString(" 0 R");
12093 : : //createDefaultSignatureAppearance( rNewWidget, rSig );
12094 : : // let's add a fake appearance
12095 [ # # ][ # # ]: 0 : rNewWidget.m_aAppearances[ "N" ][ "Standard" ] = new SvMemoryStream();
[ # # ][ # # ]
12096 : : }
12097 : : #endif
12098 : :
12099 : : // if control is a hidden signature, do not convert coordinates since we
12100 : : // need /Rect [ 0 0 0 0 ]
12101 [ # # ][ # # ]: 0 : if ( ! ( ( rControl.getType() == PDFWriter::Signature ) && ( sigHidden ) ) )
[ # # ]
12102 : : {
12103 : : // convert to default user space now, since the mapmode may change
12104 : : // note: create default appearances before m_aRect gets transformed
12105 [ # # ]: 0 : m_aPages[ nPageNr ].convertRect( rNewWidget.m_aRect );
12106 : : }
12107 : :
12108 : : // insert widget to page's annotation list
12109 [ # # ]: 0 : m_aPages[ nPageNr ].m_aAnnotations.push_back( rNewWidget.m_nObject );
12110 : :
12111 : : // mark page as having widgets
12112 : 0 : m_aPages[ nPageNr ].m_bHasWidgets = true;
12113 : :
12114 : 0 : return nNewWidget;
12115 : : }
12116 : :
12117 : 0 : void PDFWriterImpl::addStream( const String& rMimeType, PDFOutputStream* pStream, bool bCompress )
12118 : : {
12119 [ # # ]: 0 : if( pStream )
12120 : : {
12121 [ # # ]: 0 : m_aAdditionalStreams.push_back( PDFAddStream() );
12122 : 0 : PDFAddStream& rStream = m_aAdditionalStreams.back();
12123 : 0 : rStream.m_aMimeType = rMimeType.Len()
12124 : : ? OUString( rMimeType )
12125 [ # # ][ # # ]: 0 : : OUString( "application/octet-stream" );
[ # # ][ # # ]
12126 : 0 : rStream.m_pStream = pStream;
12127 : 0 : rStream.m_bCompress = bCompress;
12128 : : }
12129 : 0 : }
12130 : :
12131 : :
12132 : :
12133 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|