LCOV - code coverage report
Current view: top level - vcl/source/gdi - pdfwriter_impl.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 1 7168 0.1 %
Date: 2015-06-13 12:38:46 Functions: 2 245 0.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include <sal/types.h>
      21             : 
      22             : #include <math.h>
      23             : #include <algorithm>
      24             : #include <lcms2.h>
      25             : 
      26             : #include <basegfx/matrix/b2dhommatrix.hxx>
      27             : #include <basegfx/polygon/b2dpolygon.hxx>
      28             : #include <basegfx/polygon/b2dpolygontools.hxx>
      29             : #include <basegfx/polygon/b2dpolypolygon.hxx>
      30             : #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
      31             : #include <basegfx/polygon/b2dpolypolygontools.hxx>
      32             : #include <boost/scoped_array.hpp>
      33             : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
      34             : #include <com/sun/star/util/URL.hpp>
      35             : #include <com/sun/star/util/URLTransformer.hpp>
      36             : #include <comphelper/processfactory.hxx>
      37             : #include <comphelper/random.hxx>
      38             : #include <comphelper/string.hxx>
      39             : #include <cppuhelper/implbase1.hxx>
      40             : #include <i18nlangtag/languagetag.hxx>
      41             : #include <o3tl/numeric.hxx>
      42             : #include <osl/file.hxx>
      43             : #include <osl/thread.h>
      44             : #include <rtl/crc.h>
      45             : #include <rtl/digest.h>
      46             : #include <rtl/ustrbuf.hxx>
      47             : #include <tools/debug.hxx>
      48             : #include <tools/fract.hxx>
      49             : #include <tools/stream.hxx>
      50             : #include <tools/urlobj.hxx>
      51             : #include <tools/zcodec.hxx>
      52             : #include <vcl/bitmapex.hxx>
      53             : #include <vcl/bmpacc.hxx>
      54             : #include <vcl/cvtgrf.hxx>
      55             : #include <vcl/image.hxx>
      56             : #include <vcl/lineinfo.hxx>
      57             : #include <vcl/metric.hxx>
      58             : #include <vcl/settings.hxx>
      59             : #include <vcl/strhelper.hxx>
      60             : #include <vcl/svapp.hxx>
      61             : #include <vcl/virdev.hxx>
      62             : 
      63             : #include "fontsubset.hxx"
      64             : #include "outdev.h"
      65             : #include "PhysicalFontFace.hxx"
      66             : #include "salgdi.hxx"
      67             : #include "sallayout.hxx"
      68             : #include "textlayout.hxx"
      69             : 
      70             : #include "pdfwriter_impl.hxx"
      71             : 
      72             : #if !defined(ANDROID) && !defined(IOS) && !defined(_WIN32)
      73             : // NSS headers for PDF signing
      74             : #include "nss.h"
      75             : #include "cert.h"
      76             : #include "hasht.h"
      77             : #include "secerr.h"
      78             : #include "sechash.h"
      79             : #include "cms.h"
      80             : #include "cmst.h"
      81             : 
      82             : // We use curl for RFC3161 time stamp requests
      83             : #include <curl/curl.h>
      84             : #endif
      85             : 
      86             : #ifdef _WIN32
      87             : // WinCrypt headers for PDF signing
      88             : // Note: this uses Windows 7 APIs and requires the relevant data types;
      89             : // the functions that don't exist in WinXP must be looked up at runtime!
      90             : #undef _WIN32_WINNT
      91             : #define _WIN32_WINNT _WIN32_WINNT_WIN7
      92             : #include <prewin.h>
      93             : #include <wincrypt.h>
      94             : #include <postwin.h>
      95             : #endif
      96             : 
      97             : #include <config_eot.h>
      98             : 
      99             : #if ENABLE_EOT
     100             : #include <libeot/libeot.h>
     101             : #endif
     102             : 
     103             : using namespace vcl;
     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             : #if !defined(ANDROID) && !defined(IOS)
     112             : // Is this length truly the maximum possible, or just a number that
     113             : // seemed large enough when the author tested this (with some type of
     114             : // certificates)? I suspect the latter.
     115             : 
     116             : // Used to be 0x4000 = 16384, but a sample signed PDF (produced by
     117             : // some other software) provided by the customer has a signature
     118             : // content that is 30000 bytes. The SampleSignedPDFDocument.pdf from
     119             : // Adobe has one that is 21942 bytes. So let's be careful. Pity this
     120             : // can't be dynamic, at least not without restructuring the code. Also
     121             : // note that the checks in the code for this being too small
     122             : // apparently are broken, if this overflows you end up with an invalid
     123             : // PDF. Need to fix that.
     124             : 
     125             : #define MAX_SIGNATURE_CONTENT_LENGTH 50000
     126             : #endif
     127             : 
     128             : #ifdef DO_TEST_PDF
     129             : class PDFTestOutputStream : public PDFOutputStream
     130             : {
     131             :     public:
     132             :     virtual ~PDFTestOutputStream();
     133             :     virtual void write( const com::sun::star::uno::Reference< com::sun::star::io::XOutputStream >& xStream );
     134             : };
     135             : 
     136             : PDFTestOutputStream::~PDFTestOutputStream()
     137             : {
     138             : }
     139             : 
     140             : void PDFTestOutputStream::write( const com::sun::star::uno::Reference< com::sun::star::io::XOutputStream >& xStream )
     141             : {
     142             :     OString aStr( "lalala\ntest\ntest\ntest" );
     143             :     com::sun::star::uno::Sequence< sal_Int8 > aData( aStr.getLength() );
     144             :     memcpy( aData.getArray(), aStr.getStr(), aStr.getLength() );
     145             :     xStream->writeBytes( aData );
     146             : }
     147             : 
     148             : // this test code cannot be used to test PDF/A-1 because it forces
     149             : // control item (widgets) to bypass the structure controlling
     150             : // the embedding of such elements in actual run
     151             : void doTestCode()
     152             : {
     153             :     static const char* pHome = getenv( "HOME"  );
     154             :     OUString aTestFile( "file://"  );
     155             :     aTestFile += OUString( pHome, strlen( pHome ), RTL_TEXTENCODING_MS_1252 );
     156             :     aTestFile += "/pdf_export_test.pdf";
     157             : 
     158             :     PDFWriter::PDFWriterContext aContext;
     159             :     aContext.URL            = aTestFile;
     160             :     aContext.Version        = PDFWriter::PDF_1_4;
     161             :     aContext.Tagged         = true;
     162             :     aContext.InitialPage    = 2;
     163             :     aContext.DocumentInfo.Title = "PDF export test document";
     164             :     aContext.DocumentInfo.Producer = "VCL";
     165             : 
     166             :     aContext.SignPDF        = true;
     167             :     aContext.SignLocation   = "Burdur";
     168             :     aContext.SignReason     = "Some valid reason to sign";
     169             :     aContext.SignContact    = "signer@example.com";
     170             : 
     171             :     com::sun::star::uno::Reference< com::sun::star::beans::XMaterialHolder > xEnc;
     172             :     PDFWriter aWriter( aContext, xEnc );
     173             :     aWriter.NewPage( 595, 842 );
     174             :     aWriter.BeginStructureElement( PDFWriter::Document );
     175             :     // set duration of 3 sec for first page
     176             :     aWriter.SetAutoAdvanceTime( 3 );
     177             :     aWriter.SetMapMode( MapMode( MAP_100TH_MM ) );
     178             : 
     179             :     aWriter.SetFillColor( Color( COL_LIGHTRED ) );
     180             :     aWriter.SetLineColor( Color( COL_LIGHTGREEN ) );
     181             :     aWriter.DrawRect( Rectangle( Point( 2000, 200 ), Size( 8000, 3000 ) ), 5000, 2000 );
     182             : 
     183             :     aWriter.SetFont( Font( OUString( "Times" ), Size( 0, 500 ) ) );
     184             :     aWriter.SetTextColor( Color( COL_BLACK ) );
     185             :     aWriter.SetLineColor( Color( COL_BLACK ) );
     186             :     aWriter.SetFillColor( Color( COL_LIGHTBLUE ) );
     187             : 
     188             :     Rectangle aRect( Point( 5000, 5000 ), Size( 6000, 3000 ) );
     189             :     aWriter.DrawRect( aRect );
     190             :     aWriter.DrawText( aRect, OUString( "Link annot 1" ) );
     191             :     sal_Int32 nFirstLink = aWriter.CreateLink( aRect );
     192             :     PDFNote aNote;
     193             :     aNote.Title = "A small test note";
     194             :     aNote.Contents = "There is no business like show business like no business i know. Everything about it is appealing.";
     195             :     aWriter.CreateNote( Rectangle( Point( aRect.Right(), aRect.Top() ), Size( 6000, 3000 ) ), aNote );
     196             : 
     197             :     Rectangle aTargetRect( Point( 3000, 23000 ), Size( 12000, 6000 ) );
     198             :     aWriter.SetFillColor( Color( COL_LIGHTGREEN ) );
     199             :     aWriter.DrawRect( aTargetRect );
     200             :     aWriter.DrawText( aTargetRect, "Dest second link" );
     201             :     sal_Int32 nSecondDest = aWriter.CreateDest( aTargetRect );
     202             : 
     203             :     aWriter.BeginStructureElement( PDFWriter::Section );
     204             :     aWriter.BeginStructureElement( PDFWriter::Heading );
     205             :     aWriter.DrawText( Point(4500, 9000), "A small structure test" );
     206             :     aWriter.EndStructureElement();
     207             :     aWriter.BeginStructureElement( PDFWriter::Paragraph );
     208             :     aWriter.SetStructureAttribute( PDFWriter::WritingMode, PDFWriter::LrTb );
     209             :     aWriter.SetStructureAttribute( PDFWriter::TextDecorationType, PDFWriter::Underline );
     210             :     aWriter.DrawText( Rectangle( Point( 4500, 10000 ), Size( 12000, 6000 ) ),
     211             :                      "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.",
     212             :                       DrawTextFlags::MultiLine | DrawTextFlags::WordBreak
     213             :                       );
     214             :     aWriter.SetActualText( "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." );
     215             :     aWriter.SetAlternateText( "This paragraph contains some lengthy nonsense to test structural element emission of PDFWriter." );
     216             :     aWriter.EndStructureElement();
     217             :     aWriter.BeginStructureElement( PDFWriter::Paragraph );
     218             :     aWriter.SetStructureAttribute( PDFWriter::WritingMode, PDFWriter::LrTb );
     219             :     aWriter.DrawText( Rectangle( Point( 4500, 19000 ), Size( 12000, 1000 ) ),
     220             :                       "This paragraph is nothing special either but ends on the next page structurewise",
     221             :                       DrawTextFlags::MultiLine | DrawTextFlags::WordBreak
     222             :                       );
     223             : 
     224             :     aWriter.NewPage( 595, 842 );
     225             :     // test AddStream interface
     226             :     aWriter.AddStream( "text/plain", new PDFTestOutputStream(), true );
     227             :     // set transitional mode
     228             :     aWriter.SetPageTransition( PDFWriter::WipeRightToLeft, 1500 );
     229             :     aWriter.SetMapMode( MapMode( MAP_100TH_MM ) );
     230             :     aWriter.SetTextColor( Color( COL_BLACK ) );
     231             :     aWriter.SetFont( Font( OUString( "Times" ), Size( 0, 500 ) ) );
     232             :     aWriter.DrawText( Rectangle( Point( 4500, 1500 ), Size( 12000, 3000 ) ),
     233             :                       "Here's where all things come to an end ... well at least the paragraph from the last page.",
     234             :                       DrawTextFlags::MultiLine | DrawTextFlags::WordBreak
     235             :                       );
     236             :     aWriter.EndStructureElement();
     237             : 
     238             :     aWriter.SetFillColor( Color( COL_LIGHTBLUE ) );
     239             :     // disable structure
     240             :     aWriter.BeginStructureElement( PDFWriter::NonStructElement );
     241             :     aWriter.DrawRect( aRect );
     242             :     aWriter.BeginStructureElement( PDFWriter::Paragraph );
     243             :     aWriter.DrawText( aRect, "Link annot 2" );
     244             :     sal_Int32 nSecondLink = aWriter.CreateLink( aRect );
     245             : 
     246             :     aWriter.SetFillColor( Color( COL_LIGHTGREEN ) );
     247             :     aWriter.BeginStructureElement( PDFWriter::ListItem );
     248             :     aWriter.DrawRect( aTargetRect );
     249             :     aWriter.DrawText( aTargetRect, "Dest first link" );
     250             :     sal_Int32 nFirstDest = aWriter.CreateDest( aTargetRect );
     251             :     // enable structure
     252             :     aWriter.EndStructureElement();
     253             : 
     254             :     aWriter.EndStructureElement();
     255             :     aWriter.EndStructureElement();
     256             :     aWriter.BeginStructureElement( PDFWriter::Figure );
     257             :     aWriter.BeginStructureElement( PDFWriter::Caption );
     258             :     aWriter.DrawText( Point( 4500, 9000 ), "Some drawing stuff inside the structure" );
     259             :     aWriter.EndStructureElement();
     260             : 
     261             :     // test clipping
     262             :     basegfx::B2DPolyPolygon aClip;
     263             :     basegfx::B2DPolygon aClipPoly;
     264             :     aClipPoly.append( basegfx::B2DPoint( 8250, 9600 ) );
     265             :     aClipPoly.append( basegfx::B2DPoint( 16500, 11100 ) );
     266             :     aClipPoly.append( basegfx::B2DPoint( 8250, 12600 ) );
     267             :     aClipPoly.append( basegfx::B2DPoint( 4500, 11100 ) );
     268             :     aClipPoly.setClosed( true );
     269             :     aClip.append( aClipPoly );
     270             : 
     271             :     aWriter.Push( PushFlags::CLIPREGION | PushFlags::FILLCOLOR );
     272             :     aWriter.SetClipRegion( aClip );
     273             :     aWriter.DrawEllipse( Rectangle( Point( 4500, 9600 ), Size( 12000, 3000 ) ) );
     274             :     aWriter.MoveClipRegion( 1000, 500 );
     275             :     aWriter.SetFillColor( Color( COL_RED ) );
     276             :     aWriter.DrawEllipse( Rectangle( Point( 4500, 9600 ), Size( 12000, 3000 ) ) );
     277             :     aWriter.Pop();
     278             :     // test transparency
     279             :     // draw background
     280             :     Rectangle aTranspRect( Point( 7500, 13500 ), Size( 9000, 6000 ) );
     281             :     aWriter.SetFillColor( Color( COL_LIGHTRED ) );
     282             :     aWriter.DrawRect( aTranspRect );
     283             :     aWriter.BeginTransparencyGroup();
     284             : 
     285             :     aWriter.SetFillColor( Color( COL_LIGHTGREEN ) );
     286             :     aWriter.DrawEllipse( aTranspRect );
     287             :     aWriter.SetTextColor( Color( COL_LIGHTBLUE ) );
     288             :     aWriter.DrawText( aTranspRect,
     289             :                       "Some transparent text",
     290             :                       DrawTextFlags::Center | DrawTextFlags::VCenter | DrawTextFlags::MultiLine | DrawTextFlags::WordBreak );
     291             : 
     292             :     aWriter.EndTransparencyGroup( aTranspRect, 50 );
     293             : 
     294             :     // prepare an alpha mask
     295             :     Bitmap aTransMask( Size( 256, 256 ), 8, &Bitmap::GetGreyPalette( 256 ) );
     296             :     BitmapWriteAccess* pAcc = aTransMask.AcquireWriteAccess();
     297             :     for( int nX = 0; nX < 256; nX++ )
     298             :         for( int nY = 0; nY < 256; nY++ )
     299             :             pAcc->SetPixel( nX, nY, BitmapColor( (sal_uInt8)((nX+nY)/2) ) );
     300             :     aTransMask.ReleaseAccess( pAcc );
     301             :     aTransMask.SetPrefMapMode( MAP_MM );
     302             :     aTransMask.SetPrefSize( Size( 10, 10 ) );
     303             : 
     304             :     aWriter.DrawBitmap( Point( 600, 13500 ), Size( 3000, 3000 ), aTransMask );
     305             : 
     306             :     aTranspRect = Rectangle( Point( 4200, 13500 ), Size( 3000, 3000 ) );
     307             :     aWriter.SetFillColor( Color( COL_LIGHTRED ) );
     308             :     aWriter.DrawRect( aTranspRect );
     309             :     aWriter.SetFillColor( Color( COL_LIGHTGREEN ) );
     310             :     aWriter.DrawEllipse( aTranspRect );
     311             :     aWriter.SetTextColor( Color( COL_LIGHTBLUE ) );
     312             :     aWriter.DrawText( aTranspRect,
     313             :                       "Some transparent text",
     314             :                       DrawTextFlags::Center | DrawTextFlags::VCenter | DrawTextFlags::MultiLine | DrawTextFlags::WordBreak );
     315             :     aTranspRect = Rectangle( Point( 1500, 16500 ), Size( 4800, 3000 ) );
     316             :     aWriter.SetFillColor( Color( COL_LIGHTRED ) );
     317             :     aWriter.DrawRect( aTranspRect );
     318             : 
     319             :     Bitmap aImageBmp( Size( 256, 256 ), 24 );
     320             :     pAcc = aImageBmp.AcquireWriteAccess();
     321             :     pAcc->SetFillColor( Color( 0xff, 0, 0xff ) );
     322             :     pAcc->FillRect( Rectangle( Point( 0, 0 ), Size( 256, 256 ) ) );
     323             :     aImageBmp.ReleaseAccess( pAcc );
     324             :     BitmapEx aBmpEx( aImageBmp, AlphaMask( aTransMask ) );
     325             :     aWriter.DrawBitmapEx( Point( 1500, 19500 ), Size( 4800, 3000 ), aBmpEx );
     326             : 
     327             :     aWriter.EndStructureElement();
     328             :     aWriter.EndStructureElement();
     329             : 
     330             :     LineInfo aLI( LINE_DASH, 3 );
     331             :     aLI.SetDashCount( 2 );
     332             :     aLI.SetDashLen( 50 );
     333             :     aLI.SetDotCount( 2 );
     334             :     aLI.SetDotLen( 25 );
     335             :     aLI.SetDistance( 15 );
     336             :     Point aLIPoints[] = { Point( 4000, 10000 ),
     337             :                           Point( 8000, 12000 ),
     338             :                           Point( 3000, 19000 ) };
     339             :     Polygon aLIPoly( 3, aLIPoints );
     340             :     aWriter.SetLineColor( Color( COL_BLUE ) );
     341             :     aWriter.SetFillColor();
     342             :     aWriter.DrawPolyLine( aLIPoly, aLI );
     343             : 
     344             :     aLI.SetDashCount( 4 );
     345             :     aLIPoly.Move( 1000, 1000 );
     346             :     aWriter.DrawPolyLine( aLIPoly, aLI );
     347             : 
     348             :     aWriter.NewPage( 595, 842 );
     349             :     aWriter.SetMapMode( MapMode( MAP_100TH_MM ) );
     350             :     Wallpaper aWall( aTransMask );
     351             :     aWall.SetStyle( WALLPAPER_TILE );
     352             :     aWriter.DrawWallpaper( Rectangle( Point( 4400, 4200 ), Size( 10200, 6300 ) ), aWall );
     353             : 
     354             :     aWriter.NewPage( 595, 842 );
     355             :     aWriter.SetMapMode( MapMode( MAP_100TH_MM ) );
     356             :     aWriter.SetFont( Font( OUString( "Times" ), Size( 0, 500 ) ) );
     357             :     aWriter.SetTextColor( Color( COL_BLACK ) );
     358             :     aRect = Rectangle( Point( 4500, 6000 ), Size( 6000, 1500 ) );
     359             :     aWriter.DrawRect( aRect );
     360             :     aWriter.DrawText( aRect, "www.heise.de" );
     361             :     sal_Int32 nURILink = aWriter.CreateLink( aRect );
     362             :     aWriter.SetLinkURL( nURILink, OUString( "http://www.heise.de" ) );
     363             : 
     364             :     aWriter.SetLinkDest( nFirstLink, nFirstDest );
     365             :     aWriter.SetLinkDest( nSecondLink, nSecondDest );
     366             : 
     367             :     // include a button
     368             :     PDFWriter::PushButtonWidget aBtn;
     369             :     aBtn.Name = "testButton";
     370             :     aBtn.Description = "A test button";
     371             :     aBtn.Text = "hit me";
     372             :     aBtn.Location = Rectangle( Point( 4500, 9000 ), Size( 4500, 3000 ) );
     373             :     aBtn.Border = aBtn.Background = true;
     374             :     aWriter.CreateControl( aBtn );
     375             : 
     376             :     // include a uri button
     377             :     PDFWriter::PushButtonWidget aUriBtn;
     378             :     aUriBtn.Name = "wwwButton";
     379             :     aUriBtn.Description = "A URI button";
     380             :     aUriBtn.Text = "to www";
     381             :     aUriBtn.Location = Rectangle( Point( 9500, 9000 ), Size( 4500, 3000 ) );
     382             :     aUriBtn.Border = aUriBtn.Background = true;
     383             :     aUriBtn.URL = "http://www.heise.de";
     384             :     aWriter.CreateControl( aUriBtn );
     385             : 
     386             :     // include a dest button
     387             :     PDFWriter::PushButtonWidget aDstBtn;
     388             :     aDstBtn.Name = "destButton";
     389             :     aDstBtn.Description = "A Dest button";
     390             :     aDstBtn.Text = "to paragraph";
     391             :     aDstBtn.Location = Rectangle( Point( 14500, 9000 ), Size( 4500, 3000 ) );
     392             :     aDstBtn.Border = aDstBtn.Background = true;
     393             :     aDstBtn.Dest = nFirstDest;
     394             :     aWriter.CreateControl( aDstBtn );
     395             : 
     396             :     PDFWriter::CheckBoxWidget aCBox;
     397             :     aCBox.Name = "textCheckBox";
     398             :     aCBox.Description = "A test check box";
     399             :     aCBox.Text = "check me";
     400             :     aCBox.Location = Rectangle( Point( 4500, 13500 ), Size( 3000, 750 ) );
     401             :     aCBox.Checked = true;
     402             :     aCBox.Border = aCBox.Background = false;
     403             :     aWriter.CreateControl( aCBox );
     404             : 
     405             :     PDFWriter::CheckBoxWidget aCBox2;
     406             :     aCBox2.Name = "textCheckBox2";
     407             :     aCBox2.Description = "Another test check box";
     408             :     aCBox2.Text = "check me right";
     409             :     aCBox2.Location = Rectangle( Point( 4500, 14250 ), Size( 3000, 750 ) );
     410             :     aCBox2.Checked = true;
     411             :     aCBox2.Border = aCBox2.Background = false;
     412             :     aCBox2.ButtonIsLeft = false;
     413             :     aWriter.CreateControl( aCBox2 );
     414             : 
     415             :     PDFWriter::RadioButtonWidget aRB1;
     416             :     aRB1.Name = "rb1_1";
     417             :     aRB1.Description = "radio 1 button 1";
     418             :     aRB1.Text = "Despair";
     419             :     aRB1.Location = Rectangle( Point( 4500, 15000 ), Size( 6000, 1000 ) );
     420             :     aRB1.Selected = true;
     421             :     aRB1.RadioGroup = 1;
     422             :     aRB1.Border = aRB1.Background = true;
     423             :     aRB1.ButtonIsLeft = false;
     424             :     aRB1.BorderColor = Color( COL_LIGHTGREEN );
     425             :     aRB1.BackgroundColor = Color( COL_LIGHTBLUE );
     426             :     aRB1.TextColor = Color( COL_LIGHTRED );
     427             :     aRB1.TextFont = Font( OUString( "Courier" ), Size( 0, 800 ) );
     428             :     aWriter.CreateControl( aRB1 );
     429             : 
     430             :     PDFWriter::RadioButtonWidget aRB2;
     431             :     aRB2.Name = "rb2_1";
     432             :     aRB2.Description = "radio 2 button 1";
     433             :     aRB2.Text = "Joy";
     434             :     aRB2.Location = Rectangle( Point( 10500, 15000 ), Size( 3000, 1000 ) );
     435             :     aRB2.Selected = true;
     436             :     aRB2.RadioGroup = 2;
     437             :     aWriter.CreateControl( aRB2 );
     438             : 
     439             :     PDFWriter::RadioButtonWidget aRB3;
     440             :     aRB3.Name = "rb1_2";
     441             :     aRB3.Description = "radio 1 button 2";
     442             :     aRB3.Text = "Desperation";
     443             :     aRB3.Location = Rectangle( Point( 4500, 16000 ), Size( 3000, 1000 ) );
     444             :     aRB3.Selected = true;
     445             :     aRB3.RadioGroup = 1;
     446             :     aWriter.CreateControl( aRB3 );
     447             : 
     448             :     PDFWriter::EditWidget aEditBox;
     449             :     aEditBox.Name = "testEdit";
     450             :     aEditBox.Description = "A test edit field";
     451             :     aEditBox.Text = "A little test text";
     452             :     aEditBox.TextStyle = DrawTextFlags::Left | DrawTextFlags::VCenter;
     453             :     aEditBox.Location = Rectangle( Point( 10000, 18000 ), Size( 5000, 1500 ) );
     454             :     aEditBox.MaxLen = 100;
     455             :     aEditBox.Border = aEditBox.Background = true;
     456             :     aEditBox.BorderColor = Color( COL_BLACK );
     457             :     aWriter.CreateControl( aEditBox );
     458             : 
     459             :     // normal list box
     460             :     PDFWriter::ListBoxWidget aLstBox;
     461             :     aLstBox.Name = "testListBox";
     462             :     aLstBox.Text = "One";
     463             :     aLstBox.Description = "select me";
     464             :     aLstBox.Location = Rectangle( Point( 4500, 18000 ), Size( 3000, 1500 ) );
     465             :     aLstBox.Sort = true;
     466             :     aLstBox.MultiSelect = true;
     467             :     aLstBox.Border = aLstBox.Background = true;
     468             :     aLstBox.BorderColor = Color( COL_BLACK );
     469             :     aLstBox.Entries.push_back( OUString( "One"  ) );
     470             :     aLstBox.Entries.push_back( OUString( "Two"  ) );
     471             :     aLstBox.Entries.push_back( OUString( "Three"  ) );
     472             :     aLstBox.Entries.push_back( OUString( "Four"  ) );
     473             :     aLstBox.SelectedEntries.push_back( 1 );
     474             :     aLstBox.SelectedEntries.push_back( 2 );
     475             :     aWriter.CreateControl( aLstBox );
     476             : 
     477             :     // dropdown list box
     478             :     aLstBox.Name = "testDropDownListBox";
     479             :     aLstBox.DropDown = true;
     480             :     aLstBox.Location = Rectangle( Point( 4500, 19500 ), Size( 3000, 500 ) );
     481             :     aWriter.CreateControl( aLstBox );
     482             : 
     483             :     // combo box
     484             :     PDFWriter::ComboBoxWidget aComboBox;
     485             :     aComboBox.Name = "testComboBox";
     486             :     aComboBox.Text = "test a combobox";
     487             :     aComboBox.Entries.push_back( OUString( "Larry"  ) );
     488             :     aComboBox.Entries.push_back( OUString( "Curly"  ) );
     489             :     aComboBox.Entries.push_back( OUString( "Moe"  ) );
     490             :     aComboBox.Location = Rectangle( Point( 4500, 20000 ), Size( 3000, 500 ) );
     491             :     aWriter.CreateControl( aComboBox );
     492             : 
     493             :     // test outlines
     494             :     sal_Int32 nPage1OL = aWriter.CreateOutlineItem();
     495             :     aWriter.SetOutlineItemText( nPage1OL, OUString( "Page 1"  ) );
     496             :     aWriter.SetOutlineItemDest( nPage1OL, nSecondDest );
     497             :     aWriter.CreateOutlineItem( nPage1OL, OUString( "Dest 2"  ), nSecondDest );
     498             :     aWriter.CreateOutlineItem( nPage1OL, OUString( "Dest 2 revisited"  ), nSecondDest );
     499             :     aWriter.CreateOutlineItem( nPage1OL, OUString( "Dest 2 again"  ), nSecondDest );
     500             :     sal_Int32 nPage2OL = aWriter.CreateOutlineItem();
     501             :     aWriter.SetOutlineItemText( nPage2OL, OUString( "Page 2"  ) );
     502             :     aWriter.CreateOutlineItem( nPage2OL, OUString( "Dest 1"  ), nFirstDest );
     503             : 
     504             :     aWriter.EndStructureElement(); // close document
     505             : 
     506             :     aWriter.Emit();
     507             : }
     508             : #endif
     509             : 
     510             : static const sal_Int32 nLog10Divisor = 1;
     511             : static const double fDivisor = 10.0;
     512             : 
     513           0 : static inline double pixelToPoint( double px ) { return px/fDivisor; }
     514           0 : static inline sal_Int32 pointToPixel( double pt ) { return sal_Int32(pt*fDivisor); }
     515             : 
     516             : const sal_uInt8 PDFWriterImpl::s_nPadString[32] =
     517             : {
     518             :     0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08,
     519             :     0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80, 0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A
     520             : };
     521             : 
     522           0 : static void appendHex( sal_Int8 nInt, OStringBuffer& rBuffer )
     523             : {
     524             :     static const sal_Char pHexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7',
     525             :                                            '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
     526           0 :     rBuffer.append( pHexDigits[ (nInt >> 4) & 15 ] );
     527           0 :     rBuffer.append( pHexDigits[ nInt & 15 ] );
     528           0 : }
     529             : 
     530           0 : static void appendName( const OUString& rStr, OStringBuffer& rBuffer )
     531             : {
     532             : // FIXME i59651 add a check for max length of 127 chars? Per PDF spec 1.4, appendix C.1
     533             : // I guess than when reading the #xx sequence it will count for a single character.
     534           0 :     OString aStr( OUStringToOString( rStr, RTL_TEXTENCODING_UTF8 ) );
     535           0 :     const sal_Char* pStr = aStr.getStr();
     536           0 :     int nLen = aStr.getLength();
     537           0 :     for( int i = 0; i < nLen; i++ )
     538             :     {
     539             :         /*  #i16920# PDF recommendation: output UTF8, any byte
     540             :          *  outside the interval [33(=ASCII'!');126(=ASCII'~')]
     541             :          *  should be escaped hexadecimal
     542             :          *  for the sake of ghostscript which also reads PDF
     543             :          *  but has a narrower acceptance rate we only pass
     544             :          *  alphanumerics and '-' literally.
     545             :          */
     546           0 :         if( (pStr[i] >= 'A' && pStr[i] <= 'Z' ) ||
     547           0 :             (pStr[i] >= 'a' && pStr[i] <= 'z' ) ||
     548           0 :             (pStr[i] >= '0' && pStr[i] <= '9' ) ||
     549           0 :             pStr[i] == '-' )
     550             :         {
     551           0 :             rBuffer.append( pStr[i] );
     552             :         }
     553             :         else
     554             :         {
     555           0 :             rBuffer.append( '#' );
     556           0 :             appendHex( (sal_Int8)pStr[i], rBuffer );
     557             :         }
     558           0 :     }
     559           0 : }
     560             : 
     561           0 : static void appendName( const sal_Char* pStr, OStringBuffer& rBuffer )
     562             : {
     563             : //FIXME i59651 see above
     564           0 :     while( pStr && *pStr )
     565             :     {
     566           0 :         if( (*pStr >= 'A' && *pStr <= 'Z' ) ||
     567           0 :             (*pStr >= 'a' && *pStr <= 'z' ) ||
     568           0 :             (*pStr >= '0' && *pStr <= '9' ) ||
     569           0 :             *pStr == '-' )
     570             :         {
     571           0 :             rBuffer.append( *pStr );
     572             :         }
     573             :         else
     574             :         {
     575           0 :             rBuffer.append( '#' );
     576           0 :             appendHex( (sal_Int8)*pStr, rBuffer );
     577             :         }
     578           0 :         pStr++;
     579             :     }
     580           0 : }
     581             : 
     582             : //used only to emit encoded passwords
     583           0 : static void appendLiteralString( const sal_Char* pStr, sal_Int32 nLength, OStringBuffer& rBuffer )
     584             : {
     585           0 :     while( nLength )
     586             :     {
     587           0 :         switch( *pStr )
     588             :         {
     589             :         case '\n' :
     590           0 :             rBuffer.append( "\\n" );
     591           0 :             break;
     592             :         case '\r' :
     593           0 :             rBuffer.append( "\\r" );
     594           0 :             break;
     595             :         case '\t' :
     596           0 :             rBuffer.append( "\\t" );
     597           0 :             break;
     598             :         case '\b' :
     599           0 :             rBuffer.append( "\\b" );
     600           0 :             break;
     601             :         case '\f' :
     602           0 :             rBuffer.append( "\\f" );
     603           0 :             break;
     604             :         case '(' :
     605             :         case ')' :
     606             :         case '\\' :
     607           0 :             rBuffer.append( "\\" );
     608           0 :             rBuffer.append( (sal_Char) *pStr );
     609           0 :             break;
     610             :         default:
     611           0 :             rBuffer.append( (sal_Char) *pStr );
     612           0 :             break;
     613             :         }
     614           0 :         pStr++;
     615           0 :         nLength--;
     616             :     }
     617           0 : }
     618             : 
     619             : /**--->i56629
     620             :  * Convert a string before using it.
     621             :  *
     622             :  * This string conversion function is needed because the destination name
     623             :  * in a PDF file seen through an Internet browser should be
     624             :  * specially crafted, in order to be used directly by the browser.
     625             :  * In this way the fragment part of a hyperlink to a PDF file (e.g. something
     626             :  * as 'test1/test2/a-file.pdf\#thefragment) will be (hopefully) interpreted by the
     627             :  * PDF reader (currently only Adobe Reader plug-in seems to be working that way) called
     628             :  * from inside the Internet browser as: 'open the file test1/test2/a-file.pdf
     629             :  * and go to named destination thefragment using default zoom'.
     630             :  * The conversion is needed because in case of a fragment in the form: Slide%201
     631             :  * (meaning Slide 1) as it is converted obeying the Inet rules, it will become Slide25201
     632             :  * using this conversion, in both the generated named destinations, fragment and GoToR
     633             :  * destination.
     634             :  *
     635             :  * The names for destinations are name objects and so they don't need to be encrypted
     636             :  * even though they expose the content of PDF file (e.g. guessing the PDF content from the
     637             :  * destination name).
     638             :  *
     639             :  * Fhurter limitation: it is advisable to use standard ASCII characters for
     640             :  * OOo bookmarks.
     641             : */
     642           0 : static void appendDestinationName( const OUString& rString, OStringBuffer& rBuffer )
     643             : {
     644           0 :     const sal_Unicode* pStr = rString.getStr();
     645           0 :     sal_Int32 nLen = rString.getLength();
     646           0 :     for( int i = 0; i < nLen; i++ )
     647             :     {
     648           0 :         sal_Unicode aChar = pStr[i];
     649           0 :         if( (aChar >= '0' && aChar <= '9' ) ||
     650           0 :             (aChar >= 'a' && aChar <= 'z' ) ||
     651           0 :             (aChar >= 'A' && aChar <= 'Z' ) ||
     652             :             aChar == '-' )
     653             :         {
     654           0 :             rBuffer.append((sal_Char)aChar);
     655             :         }
     656             :         else
     657             :         {
     658           0 :             sal_Int8 aValueHigh = sal_Int8(aChar >> 8);
     659           0 :             if(aValueHigh > 0)
     660           0 :                 appendHex( aValueHigh, rBuffer );
     661           0 :             appendHex( (sal_Int8)(aChar & 255 ), rBuffer );
     662             :         }
     663             :     }
     664           0 : }
     665             : //<--- i56629
     666             : 
     667           0 : static void appendUnicodeTextString( const OUString& rString, OStringBuffer& rBuffer )
     668             : {
     669           0 :     rBuffer.append( "FEFF" );
     670           0 :     const sal_Unicode* pStr = rString.getStr();
     671           0 :     sal_Int32 nLen = rString.getLength();
     672           0 :     for( int i = 0; i < nLen; i++ )
     673             :     {
     674           0 :         sal_Unicode aChar = pStr[i];
     675           0 :         appendHex( (sal_Int8)(aChar >> 8), rBuffer );
     676           0 :         appendHex( (sal_Int8)(aChar & 255 ), rBuffer );
     677             :     }
     678           0 : }
     679             : 
     680           0 : void PDFWriterImpl::createWidgetFieldName( sal_Int32 i_nWidgetIndex, const PDFWriter::AnyWidget& i_rControl )
     681             : {
     682             :     /* #i80258# previously we use appendName here
     683             :        however we need a slightly different coding scheme than the normal
     684             :        name encoding for field names
     685             :     */
     686           0 :     const OUString& rName = (m_aContext.Version > PDFWriter::PDF_1_2) ? i_rControl.Name : i_rControl.Text;
     687           0 :     OString aStr( OUStringToOString( rName, RTL_TEXTENCODING_UTF8 ) );
     688           0 :     const sal_Char* pStr = aStr.getStr();
     689           0 :     int nLen = aStr.getLength();
     690             : 
     691           0 :     OStringBuffer aBuffer( rName.getLength()+64 );
     692           0 :     for( int i = 0; i < nLen; i++ )
     693             :     {
     694             :         /*  #i16920# PDF recommendation: output UTF8, any byte
     695             :          *  outside the interval [32(=ASCII' ');126(=ASCII'~')]
     696             :          *  should be escaped hexadecimal
     697             :          */
     698           0 :         if( (pStr[i] >= 32 && pStr[i] <= 126 ) )
     699           0 :             aBuffer.append( pStr[i] );
     700             :         else
     701             :         {
     702           0 :             aBuffer.append( '#' );
     703           0 :             appendHex( (sal_Int8)pStr[i], aBuffer );
     704             :         }
     705             :     }
     706             : 
     707           0 :     OString aFullName( aBuffer.makeStringAndClear() );
     708             : 
     709             :     /* #i82785# create hierarchical fields down to the for each dot in i_rName */
     710           0 :     sal_Int32 nTokenIndex = 0, nLastTokenIndex = 0;
     711           0 :     OString aPartialName;
     712           0 :     OString aDomain;
     713           0 :     do
     714             :     {
     715           0 :         nLastTokenIndex = nTokenIndex;
     716           0 :         aPartialName = aFullName.getToken( 0, '.', nTokenIndex );
     717           0 :         if( nTokenIndex != -1 )
     718             :         {
     719             :             // find or create a hierarchical field
     720             :             // first find the fully qualified name up to this field
     721           0 :             aDomain = aFullName.copy( 0, nTokenIndex-1 );
     722           0 :             std::unordered_map< OString, sal_Int32, OStringHash >::const_iterator it = m_aFieldNameMap.find( aDomain );
     723           0 :             if( it == m_aFieldNameMap.end() )
     724             :             {
     725             :                  // create new hierarchy field
     726           0 :                 sal_Int32 nNewWidget = m_aWidgets.size();
     727           0 :                 m_aWidgets.push_back( PDFWidget() );
     728           0 :                 m_aWidgets[nNewWidget].m_nObject = createObject();
     729           0 :                 m_aWidgets[nNewWidget].m_eType = PDFWriter::Hierarchy;
     730           0 :                 m_aWidgets[nNewWidget].m_aName = aPartialName;
     731           0 :                 m_aWidgets[i_nWidgetIndex].m_nParent = m_aWidgets[nNewWidget].m_nObject;
     732           0 :                 m_aFieldNameMap[aDomain] = nNewWidget;
     733           0 :                 m_aWidgets[i_nWidgetIndex].m_nParent = m_aWidgets[nNewWidget].m_nObject;
     734           0 :                 if( nLastTokenIndex > 0 )
     735             :                 {
     736             :                     // this field is not a root field and
     737             :                     // needs to be inserted to its parent
     738           0 :                     OString aParentDomain( aDomain.copy( 0, nLastTokenIndex-1 ) );
     739           0 :                     it = m_aFieldNameMap.find( aParentDomain );
     740             :                     OSL_ENSURE( it != m_aFieldNameMap.end(), "field name not found" );
     741           0 :                     if( it != m_aFieldNameMap.end()  )
     742             :                     {
     743             :                         OSL_ENSURE( it->second < sal_Int32(m_aWidgets.size()), "invalid field number entry" );
     744           0 :                         if( it->second < sal_Int32(m_aWidgets.size()) )
     745             :                         {
     746           0 :                             PDFWidget& rParentField( m_aWidgets[it->second] );
     747           0 :                             rParentField.m_aKids.push_back( m_aWidgets[nNewWidget].m_nObject );
     748           0 :                             rParentField.m_aKidsIndex.push_back( nNewWidget );
     749           0 :                             m_aWidgets[nNewWidget].m_nParent = rParentField.m_nObject;
     750             :                         }
     751           0 :                     }
     752             :                 }
     753             :             }
     754           0 :             else if( m_aWidgets[it->second].m_eType != PDFWriter::Hierarchy )
     755             :             {
     756             :                 // this is invalid, someone tries to have a terminal field as parent
     757             :                 // example: a button with the name foo.bar exists and
     758             :                 // another button is named foo.bar.no
     759             :                 // workaround: put the second terminal field as much up in the hierarchy as
     760             :                 // necessary to have a non-terminal field as parent (or none at all)
     761             :                 // since it->second already is terminal, we just need to use its parent
     762           0 :                 aDomain.clear();
     763           0 :                 aPartialName = aFullName.copy( aFullName.lastIndexOf( '.' )+1 );
     764           0 :                 if( nLastTokenIndex > 0 )
     765             :                 {
     766           0 :                     aDomain = aFullName.copy( 0, nLastTokenIndex-1 );
     767           0 :                     OStringBuffer aBuf( aDomain.getLength() + 1 + aPartialName.getLength() );
     768           0 :                     aBuf.append( aDomain );
     769           0 :                     aBuf.append( '.' );
     770           0 :                     aBuf.append( aPartialName );
     771           0 :                     aFullName = aBuf.makeStringAndClear();
     772             :                 }
     773             :                 else
     774           0 :                     aFullName = aPartialName;
     775           0 :                 break;
     776             :             }
     777             :         }
     778           0 :     } while( nTokenIndex != -1 );
     779             : 
     780             :     // insert widget into its hierarchy field
     781           0 :     if( !aDomain.isEmpty() )
     782             :     {
     783           0 :         std::unordered_map< OString, sal_Int32, OStringHash >::const_iterator it = m_aFieldNameMap.find( aDomain );
     784           0 :         if( it != m_aFieldNameMap.end() )
     785             :         {
     786             :             OSL_ENSURE( it->second >= 0 && it->second < sal_Int32( m_aWidgets.size() ), "invalid field index" );
     787           0 :             if( it->second >= 0 && it->second < sal_Int32(m_aWidgets.size()) )
     788             :             {
     789           0 :                 m_aWidgets[i_nWidgetIndex].m_nParent = m_aWidgets[it->second].m_nObject;
     790           0 :                 m_aWidgets[it->second].m_aKids.push_back( m_aWidgets[i_nWidgetIndex].m_nObject);
     791           0 :                 m_aWidgets[it->second].m_aKidsIndex.push_back( i_nWidgetIndex );
     792             :             }
     793             :         }
     794             :     }
     795             : 
     796           0 :     if( aPartialName.isEmpty() )
     797             :     {
     798             :         // how funny, an empty field name
     799           0 :         if( i_rControl.getType() == PDFWriter::RadioButton )
     800             :         {
     801           0 :             aPartialName  = "RadioGroup";
     802           0 :             aPartialName += OString::number( static_cast<const PDFWriter::RadioButtonWidget&>(i_rControl).RadioGroup );
     803             :         }
     804             :         else
     805           0 :             aPartialName = OString( "Widget" );
     806             :     }
     807             : 
     808           0 :     if( ! m_aContext.AllowDuplicateFieldNames )
     809             :     {
     810           0 :         std::unordered_map<OString, sal_Int32, OStringHash>::iterator it = m_aFieldNameMap.find( aFullName );
     811             : 
     812           0 :         if( it != m_aFieldNameMap.end() ) // not unique
     813             :         {
     814           0 :             std::unordered_map< OString, sal_Int32, OStringHash >::const_iterator check_it;
     815           0 :             OString aTry;
     816           0 :             sal_Int32 nTry = 2;
     817           0 :             do
     818             :             {
     819           0 :                 OStringBuffer aUnique( aFullName.getLength() + 16 );
     820           0 :                 aUnique.append( aFullName );
     821           0 :                 aUnique.append( '_' );
     822           0 :                 aUnique.append( nTry++ );
     823           0 :                 aTry = aUnique.makeStringAndClear();
     824           0 :                 check_it = m_aFieldNameMap.find( aTry );
     825           0 :             } while( check_it != m_aFieldNameMap.end() );
     826           0 :             aFullName = aTry;
     827           0 :             m_aFieldNameMap[ aFullName ] = i_nWidgetIndex;
     828           0 :             aPartialName = aFullName.copy( aFullName.lastIndexOf( '.' )+1 );
     829             :         }
     830             :         else
     831           0 :             m_aFieldNameMap[ aFullName ] = i_nWidgetIndex;
     832             :     }
     833             : 
     834             :     // finally
     835           0 :     m_aWidgets[i_nWidgetIndex].m_aName = aPartialName;
     836           0 : }
     837             : 
     838           0 : static void appendFixedInt( sal_Int32 nValue, OStringBuffer& rBuffer, sal_Int32 nPrecision = nLog10Divisor )
     839             : {
     840           0 :     if( nValue < 0 )
     841             :     {
     842           0 :         rBuffer.append( '-' );
     843           0 :         nValue = -nValue;
     844             :     }
     845           0 :     sal_Int32 nFactor = 1, nDiv = nPrecision;
     846           0 :     while( nDiv-- )
     847           0 :         nFactor *= 10;
     848             : 
     849           0 :     sal_Int32 nInt      = nValue / nFactor;
     850           0 :     rBuffer.append( nInt );
     851           0 :     if( nFactor > 1 )
     852             :     {
     853           0 :         sal_Int32 nDecimal  = nValue % nFactor;
     854           0 :         if( nDecimal )
     855             :         {
     856           0 :             rBuffer.append( '.' );
     857             :             // omit trailing zeros
     858           0 :             while( (nDecimal % 10) == 0 )
     859           0 :                 nDecimal /= 10;
     860           0 :             rBuffer.append( nDecimal );
     861             :         }
     862             :     }
     863           0 : }
     864             : 
     865             : // appends a double. PDF does not accept exponential format, only fixed point
     866           0 : static void appendDouble( double fValue, OStringBuffer& rBuffer, sal_Int32 nPrecision = 5 )
     867             : {
     868           0 :     bool bNeg = false;
     869           0 :     if( fValue < 0.0 )
     870             :     {
     871           0 :         bNeg = true;
     872           0 :         fValue=-fValue;
     873             :     }
     874             : 
     875           0 :     sal_Int64 nInt = (sal_Int64)fValue;
     876           0 :     fValue -= (double)nInt;
     877             :     // optimizing hardware may lead to a value of 1.0 after the subtraction
     878           0 :     if( fValue == 1.0 || log10( 1.0-fValue ) <= -nPrecision )
     879             :     {
     880           0 :         nInt++;
     881           0 :         fValue = 0.0;
     882             :     }
     883           0 :     sal_Int64 nFrac = 0;
     884           0 :     if( fValue )
     885             :     {
     886           0 :         fValue *= pow( 10.0, (double)nPrecision );
     887           0 :         nFrac = (sal_Int64)fValue;
     888             :     }
     889           0 :     if( bNeg && ( nInt || nFrac ) )
     890           0 :         rBuffer.append( '-' );
     891           0 :     rBuffer.append( nInt );
     892           0 :     if( nFrac )
     893             :     {
     894             :         int i;
     895           0 :         rBuffer.append( '.' );
     896           0 :         sal_Int64 nBound = (sal_Int64)(pow( 10.0, nPrecision - 1.0 )+0.5);
     897           0 :         for ( i = 0; ( i < nPrecision ) && nFrac; i++ )
     898             :         {
     899           0 :             sal_Int64 nNumb = nFrac / nBound;
     900           0 :             nFrac -= nNumb * nBound;
     901           0 :             rBuffer.append( nNumb );
     902           0 :             nBound /= 10;
     903             :         }
     904             :     }
     905           0 : }
     906             : 
     907           0 : static void appendColor( const Color& rColor, OStringBuffer& rBuffer, bool bConvertToGrey = false )
     908             : {
     909             : 
     910           0 :     if( rColor != Color( COL_TRANSPARENT ) )
     911             :     {
     912           0 :         if( bConvertToGrey )
     913             :         {
     914           0 :             sal_uInt8 cByte = rColor.GetLuminance();
     915           0 :             appendDouble( (double)cByte / 255.0, rBuffer );
     916             :         }
     917             :         else
     918             :         {
     919           0 :             appendDouble( (double)rColor.GetRed() / 255.0, rBuffer );
     920           0 :             rBuffer.append( ' ' );
     921           0 :             appendDouble( (double)rColor.GetGreen() / 255.0, rBuffer );
     922           0 :             rBuffer.append( ' ' );
     923           0 :             appendDouble( (double)rColor.GetBlue() / 255.0, rBuffer );
     924             :         }
     925             :     }
     926           0 : }
     927             : 
     928           0 : void PDFWriterImpl::appendStrokingColor( const Color& rColor, OStringBuffer& rBuffer )
     929             : {
     930           0 :     if( rColor != Color( COL_TRANSPARENT ) )
     931             :     {
     932           0 :         bool bGrey = m_aContext.ColorMode == PDFWriter::DrawGreyscale;
     933           0 :         appendColor( rColor, rBuffer, bGrey );
     934           0 :         rBuffer.append( bGrey ? " G" : " RG" );
     935             :     }
     936           0 : }
     937             : 
     938           0 : void PDFWriterImpl::appendNonStrokingColor( const Color& rColor, OStringBuffer& rBuffer )
     939             : {
     940           0 :     if( rColor != Color( COL_TRANSPARENT ) )
     941             :     {
     942           0 :         bool bGrey = m_aContext.ColorMode == PDFWriter::DrawGreyscale;
     943           0 :         appendColor( rColor, rBuffer, bGrey );
     944           0 :         rBuffer.append( bGrey ? " g" : " rg" );
     945             :     }
     946           0 : }
     947             : 
     948             : // matrix helper class
     949             : // TODO: use basegfx matrix class instead or derive from it
     950             : namespace vcl // TODO: use anonymous namespace to keep this class local
     951             : {
     952             : /*  for sparse matrices of the form (2D linear transformations)
     953             :  *  f[0] f[1] 0
     954             :  *  f[2] f[3] 0
     955             :  *  f[4] f[5] 1
     956             :  */
     957             : class Matrix3
     958             : {
     959             :     double f[6];
     960             : 
     961           0 :     void set( double *pn ) { for( int i = 0 ; i < 6; i++ ) f[i] = pn[i]; }
     962             : public:
     963             :     Matrix3();
     964           0 :     ~Matrix3() {}
     965             : 
     966             :     void skew( double alpha, double beta );
     967             :     void scale( double sx, double sy );
     968             :     void rotate( double angle );
     969             :     void translate( double tx, double ty );
     970             :     bool invert();
     971             : 
     972             :     void append( PDFWriterImpl::PDFPage& rPage, OStringBuffer& rBuffer, Point* pBack = NULL );
     973             : 
     974             :     Point transform( const Point& rPoint ) const;
     975             : };
     976             : }
     977             : 
     978           0 : Matrix3::Matrix3()
     979             : {
     980             :     // initialize to unity
     981           0 :     f[0] = 1.0;
     982           0 :     f[1] = 0.0;
     983           0 :     f[2] = 0.0;
     984           0 :     f[3] = 1.0;
     985           0 :     f[4] = 0.0;
     986           0 :     f[5] = 0.0;
     987           0 : }
     988             : 
     989           0 : Point Matrix3::transform( const Point& rOrig ) const
     990             : {
     991           0 :     double x = (double)rOrig.X(), y = (double)rOrig.Y();
     992           0 :     return Point( (int)(x*f[0] + y*f[2] + f[4]), (int)(x*f[1] + y*f[3] + f[5]) );
     993             : }
     994             : 
     995           0 : void Matrix3::skew( double alpha, double beta )
     996             : {
     997             :     double fn[6];
     998           0 :     double tb = tan( beta );
     999           0 :     fn[0] = f[0] + f[2]*tb;
    1000           0 :     fn[1] = f[1];
    1001           0 :     fn[2] = f[2] + f[3]*tb;
    1002           0 :     fn[3] = f[3];
    1003           0 :     fn[4] = f[4] + f[5]*tb;
    1004           0 :     fn[5] = f[5];
    1005           0 :     if( alpha != 0.0 )
    1006             :     {
    1007           0 :         double ta = tan( alpha );
    1008           0 :         fn[1] += f[0]*ta;
    1009           0 :         fn[3] += f[2]*ta;
    1010           0 :         fn[5] += f[4]*ta;
    1011             :     }
    1012           0 :     set( fn );
    1013           0 : }
    1014             : 
    1015           0 : void Matrix3::scale( double sx, double sy )
    1016             : {
    1017             :     double fn[6];
    1018           0 :     fn[0] = sx*f[0];
    1019           0 :     fn[1] = sy*f[1];
    1020           0 :     fn[2] = sx*f[2];
    1021           0 :     fn[3] = sy*f[3];
    1022           0 :     fn[4] = sx*f[4];
    1023           0 :     fn[5] = sy*f[5];
    1024           0 :     set( fn );
    1025           0 : }
    1026             : 
    1027           0 : void Matrix3::rotate( double angle )
    1028             : {
    1029             :     double fn[6];
    1030           0 :     double fSin = sin(angle);
    1031           0 :     double fCos = cos(angle);
    1032           0 :     fn[0] = f[0]*fCos - f[1]*fSin;
    1033           0 :     fn[1] = f[0]*fSin + f[1]*fCos;
    1034           0 :     fn[2] = f[2]*fCos - f[3]*fSin;
    1035           0 :     fn[3] = f[2]*fSin + f[3]*fCos;
    1036           0 :     fn[4] = f[4]*fCos - f[5]*fSin;
    1037           0 :     fn[5] = f[4]*fSin + f[5]*fCos;
    1038           0 :     set( fn );
    1039           0 : }
    1040             : 
    1041           0 : void Matrix3::translate( double tx, double ty )
    1042             : {
    1043           0 :     f[4] += tx;
    1044           0 :     f[5] += ty;
    1045           0 : }
    1046             : 
    1047           0 : bool Matrix3::invert()
    1048             : {
    1049             :     // short circuit trivial cases
    1050           0 :     if( f[1]==f[2] && f[1]==0.0 && f[0]==f[3] && f[0]==1.0 )
    1051             :     {
    1052           0 :         f[4] = -f[4];
    1053           0 :         f[5] = -f[5];
    1054           0 :         return true;
    1055             :     }
    1056             : 
    1057             :     // check determinant
    1058           0 :     const double fDet = f[0]*f[3]-f[1]*f[2];
    1059           0 :     if( fDet == 0.0 )
    1060           0 :         return false;
    1061             : 
    1062             :     // invert the matrix
    1063             :     double fn[6];
    1064           0 :     fn[0] = +f[3] / fDet;
    1065           0 :     fn[1] = -f[1] / fDet;
    1066           0 :     fn[2] = -f[2] / fDet;
    1067           0 :     fn[3] = +f[0] / fDet;
    1068             : 
    1069             :     // apply inversion to translation
    1070           0 :     fn[4] = -(f[4]*fn[0] + f[5]*fn[2]);
    1071           0 :     fn[5] = -(f[4]*fn[1] + f[5]*fn[3]);
    1072             : 
    1073           0 :     set( fn );
    1074           0 :     return true;
    1075             : }
    1076             : 
    1077           0 : void Matrix3::append( PDFWriterImpl::PDFPage& rPage, OStringBuffer& rBuffer, Point* pBack )
    1078             : {
    1079           0 :     appendDouble( f[0], rBuffer );
    1080           0 :     rBuffer.append( ' ' );
    1081           0 :     appendDouble( f[1], rBuffer );
    1082           0 :     rBuffer.append( ' ' );
    1083           0 :     appendDouble( f[2], rBuffer );
    1084           0 :     rBuffer.append( ' ' );
    1085           0 :     appendDouble( f[3], rBuffer );
    1086           0 :     rBuffer.append( ' ' );
    1087           0 :     rPage.appendPoint( Point( (long)f[4], (long)f[5] ), rBuffer, false, pBack );
    1088           0 : }
    1089             : 
    1090           0 : static void appendResourceMap( OStringBuffer& rBuf, const char* pPrefix, const PDFWriterImpl::ResourceMap& rList )
    1091             : {
    1092           0 :     if( rList.empty() )
    1093           0 :         return;
    1094           0 :     rBuf.append( '/' );
    1095           0 :     rBuf.append( pPrefix );
    1096           0 :     rBuf.append( "<<" );
    1097           0 :     int ni = 0;
    1098           0 :     for( PDFWriterImpl::ResourceMap::const_iterator it = rList.begin(); it != rList.end(); ++it )
    1099             :     {
    1100           0 :         if( !it->first.isEmpty() && it->second > 0 )
    1101             :         {
    1102           0 :             rBuf.append( '/' );
    1103           0 :             rBuf.append( it->first );
    1104           0 :             rBuf.append( ' ' );
    1105           0 :             rBuf.append( it->second );
    1106           0 :             rBuf.append( " 0 R" );
    1107           0 :             if( ((++ni) & 7) == 0 )
    1108           0 :                 rBuf.append( '\n' );
    1109             :         }
    1110             :     }
    1111           0 :     rBuf.append( ">>\n" );
    1112             : }
    1113             : 
    1114           0 : void PDFWriterImpl::ResourceDict::append( OStringBuffer& rBuf, sal_Int32 nFontDictObject )
    1115             : {
    1116           0 :     rBuf.append( "<</Font " );
    1117           0 :     rBuf.append( nFontDictObject );
    1118           0 :     rBuf.append( " 0 R\n" );
    1119           0 :     appendResourceMap( rBuf, "XObject", m_aXObjects );
    1120           0 :     appendResourceMap( rBuf, "ExtGState", m_aExtGStates );
    1121           0 :     appendResourceMap( rBuf, "Shading", m_aShadings );
    1122           0 :     appendResourceMap( rBuf, "Pattern", m_aPatterns );
    1123           0 :     rBuf.append( "/ProcSet[/PDF/Text" );
    1124           0 :     if( !m_aXObjects.empty() )
    1125           0 :         rBuf.append( "/ImageC/ImageI/ImageB" );
    1126           0 :     rBuf.append( "]\n>>\n" );
    1127           0 : };
    1128             : 
    1129           0 : PDFWriterImpl::PDFPage::PDFPage( PDFWriterImpl* pWriter, sal_Int32 nPageWidth, sal_Int32 nPageHeight, PDFWriter::Orientation eOrientation )
    1130             :         :
    1131             :         m_pWriter( pWriter ),
    1132             :         m_nPageWidth( nPageWidth ),
    1133             :         m_nPageHeight( nPageHeight ),
    1134             :         m_eOrientation( eOrientation ),
    1135             :         m_nPageObject( 0 ),  // invalid object number
    1136             :         m_nPageIndex( -1 ), // invalid index
    1137             :         m_nStreamLengthObject( 0 ),
    1138             :         m_nBeginStreamPos( 0 ),
    1139             :         m_eTransition( PDFWriter::Regular ),
    1140             :         m_nTransTime( 0 ),
    1141             :         m_nDuration( 0 ),
    1142           0 :         m_bHasWidgets( false )
    1143             : {
    1144             :     // object ref must be only ever updated in emit()
    1145           0 :     m_nPageObject = m_pWriter->createObject();
    1146           0 : }
    1147             : 
    1148           0 : PDFWriterImpl::PDFPage::~PDFPage()
    1149             : {
    1150           0 : }
    1151             : 
    1152           0 : void PDFWriterImpl::PDFPage::beginStream()
    1153             : {
    1154             : #if OSL_DEBUG_LEVEL > 1
    1155             :     {
    1156             :         OStringBuffer aLine( "PDFWriterImpl::PDFPage::beginStream, +" );
    1157             :          m_pWriter->emitComment( aLine.getStr() );
    1158             :     }
    1159             : #endif
    1160           0 :     m_aStreamObjects.push_back(m_pWriter->createObject());
    1161           0 :     if( ! m_pWriter->updateObject( m_aStreamObjects.back() ) )
    1162           0 :         return;
    1163             : 
    1164           0 :     m_nStreamLengthObject = m_pWriter->createObject();
    1165             :     // write content stream header
    1166           0 :     OStringBuffer aLine;
    1167           0 :     aLine.append( m_aStreamObjects.back() );
    1168           0 :     aLine.append( " 0 obj\n<</Length " );
    1169           0 :     aLine.append( m_nStreamLengthObject );
    1170           0 :     aLine.append( " 0 R" );
    1171             : #if defined ( COMPRESS_PAGES ) && !defined ( DEBUG_DISABLE_PDFCOMPRESSION )
    1172           0 :     aLine.append( "/Filter/FlateDecode" );
    1173             : #endif
    1174           0 :     aLine.append( ">>\nstream\n" );
    1175           0 :     if( ! m_pWriter->writeBuffer( aLine.getStr(), aLine.getLength() ) )
    1176           0 :         return;
    1177           0 :     if (osl::File::E_None != m_pWriter->m_aFile.getPos(m_nBeginStreamPos))
    1178             :     {
    1179           0 :         m_pWriter->m_aFile.close();
    1180           0 :         m_pWriter->m_bOpen = false;
    1181             :     }
    1182             : #if defined ( COMPRESS_PAGES ) && !defined ( DEBUG_DISABLE_PDFCOMPRESSION )
    1183           0 :     m_pWriter->beginCompression();
    1184             : #endif
    1185           0 :     m_pWriter->checkAndEnableStreamEncryption( m_aStreamObjects.back() );
    1186             : }
    1187             : 
    1188           0 : void PDFWriterImpl::PDFPage::endStream()
    1189             : {
    1190             : #if defined ( COMPRESS_PAGES ) && !defined ( DEBUG_DISABLE_PDFCOMPRESSION )
    1191           0 :     m_pWriter->endCompression();
    1192             : #endif
    1193             :     sal_uInt64 nEndStreamPos;
    1194           0 :     if (osl::File::E_None != m_pWriter->m_aFile.getPos(nEndStreamPos))
    1195             :     {
    1196           0 :         m_pWriter->m_aFile.close();
    1197           0 :         m_pWriter->m_bOpen = false;
    1198           0 :         return;
    1199             :     }
    1200           0 :     m_pWriter->disableStreamEncryption();
    1201           0 :     if( ! m_pWriter->writeBuffer( "\nendstream\nendobj\n\n", 19 ) )
    1202           0 :         return;
    1203             :     // emit stream length object
    1204           0 :     if( ! m_pWriter->updateObject( m_nStreamLengthObject ) )
    1205           0 :         return;
    1206           0 :     OStringBuffer aLine;
    1207           0 :     aLine.append( m_nStreamLengthObject );
    1208           0 :     aLine.append( " 0 obj\n" );
    1209           0 :     aLine.append( (sal_Int64)(nEndStreamPos-m_nBeginStreamPos) );
    1210           0 :     aLine.append( "\nendobj\n\n" );
    1211           0 :     m_pWriter->writeBuffer( aLine.getStr(), aLine.getLength() );
    1212             : }
    1213             : 
    1214           0 : bool PDFWriterImpl::PDFPage::emit(sal_Int32 nParentObject )
    1215             : {
    1216             :     // emit page object
    1217           0 :     if( ! m_pWriter->updateObject( m_nPageObject ) )
    1218           0 :         return false;
    1219           0 :     OStringBuffer aLine;
    1220             : 
    1221           0 :     aLine.append( m_nPageObject );
    1222             :     aLine.append( " 0 obj\n"
    1223           0 :                   "<</Type/Page/Parent " );
    1224           0 :     aLine.append( nParentObject );
    1225           0 :     aLine.append( " 0 R" );
    1226           0 :     aLine.append( "/Resources " );
    1227           0 :     aLine.append( m_pWriter->getResourceDictObj() );
    1228           0 :     aLine.append( " 0 R" );
    1229           0 :     if( m_nPageWidth && m_nPageHeight )
    1230             :     {
    1231           0 :         aLine.append( "/MediaBox[0 0 " );
    1232           0 :         aLine.append( m_nPageWidth );
    1233           0 :         aLine.append( ' ' );
    1234           0 :         aLine.append( m_nPageHeight );
    1235           0 :         aLine.append( "]" );
    1236             :     }
    1237           0 :     switch( m_eOrientation )
    1238             :     {
    1239           0 :         case PDFWriter::Landscape: aLine.append( "/Rotate 90\n" );break;
    1240           0 :         case PDFWriter::Seascape:  aLine.append( "/Rotate -90\n" );break;
    1241           0 :         case PDFWriter::Portrait:  aLine.append( "/Rotate 0\n" );break;
    1242             : 
    1243             :         case PDFWriter::Inherit:
    1244             :         default:
    1245           0 :             break;
    1246             :     }
    1247           0 :     int nAnnots = m_aAnnotations.size();
    1248           0 :     if( nAnnots > 0 )
    1249             :     {
    1250           0 :         aLine.append( "/Annots[\n" );
    1251           0 :         for( int i = 0; i < nAnnots; i++ )
    1252             :         {
    1253           0 :             aLine.append( m_aAnnotations[i] );
    1254           0 :             aLine.append( " 0 R" );
    1255           0 :             aLine.append( ((i+1)%15) ? " " : "\n" );
    1256             :         }
    1257           0 :         aLine.append( "]\n" );
    1258             :     }
    1259           0 :     if( m_aMCIDParents.size() > 0 )
    1260             :     {
    1261           0 :         OStringBuffer aStructParents( 1024 );
    1262           0 :         aStructParents.append( "[ " );
    1263           0 :         int nParents = m_aMCIDParents.size();
    1264           0 :         for( int i = 0; i < nParents; i++ )
    1265             :         {
    1266           0 :             aStructParents.append( m_aMCIDParents[i] );
    1267           0 :             aStructParents.append( " 0 R" );
    1268           0 :             aStructParents.append( ((i%10) == 9) ? "\n" : " " );
    1269             :         }
    1270           0 :         aStructParents.append( "]" );
    1271           0 :         m_pWriter->m_aStructParentTree.push_back( aStructParents.makeStringAndClear() );
    1272             : 
    1273           0 :         aLine.append( "/StructParents " );
    1274           0 :         aLine.append( sal_Int32(m_pWriter->m_aStructParentTree.size()-1) );
    1275           0 :         aLine.append( "\n" );
    1276             :     }
    1277           0 :     if( m_nDuration > 0 )
    1278             :     {
    1279           0 :         aLine.append( "/Dur " );
    1280           0 :         aLine.append( (sal_Int32)m_nDuration );
    1281           0 :         aLine.append( "\n" );
    1282             :     }
    1283           0 :     if( m_eTransition != PDFWriter::Regular && m_nTransTime > 0 )
    1284             :     {
    1285             :         // transition duration
    1286           0 :         aLine.append( "/Trans<</D " );
    1287           0 :         appendDouble( (double)m_nTransTime/1000.0, aLine, 3 );
    1288           0 :         aLine.append( "\n" );
    1289           0 :         const char *pStyle = NULL, *pDm = NULL, *pM = NULL, *pDi = NULL;
    1290           0 :         switch( m_eTransition )
    1291             :         {
    1292             :             case PDFWriter::SplitHorizontalInward:
    1293           0 :                 pStyle = "Split"; pDm = "H"; pM = "I"; break;
    1294             :             case PDFWriter::SplitHorizontalOutward:
    1295           0 :                 pStyle = "Split"; pDm = "H"; pM = "O"; break;
    1296             :             case PDFWriter::SplitVerticalInward:
    1297           0 :                 pStyle = "Split"; pDm = "V"; pM = "I"; break;
    1298             :             case PDFWriter::SplitVerticalOutward:
    1299           0 :                 pStyle = "Split"; pDm = "V"; pM = "O"; break;
    1300             :             case PDFWriter::BlindsHorizontal:
    1301           0 :                 pStyle = "Blinds"; pDm = "H"; break;
    1302             :             case PDFWriter::BlindsVertical:
    1303           0 :                 pStyle = "Blinds"; pDm = "V"; break;
    1304             :             case PDFWriter::BoxInward:
    1305           0 :                 pStyle = "Box"; pM = "I"; break;
    1306             :             case PDFWriter::BoxOutward:
    1307           0 :                 pStyle = "Box"; pM = "O"; break;
    1308             :             case PDFWriter::WipeLeftToRight:
    1309           0 :                 pStyle = "Wipe"; pDi = "0"; break;
    1310             :             case PDFWriter::WipeBottomToTop:
    1311           0 :                 pStyle = "Wipe"; pDi = "90"; break;
    1312             :             case PDFWriter::WipeRightToLeft:
    1313           0 :                 pStyle = "Wipe"; pDi = "180"; break;
    1314             :             case PDFWriter::WipeTopToBottom:
    1315           0 :                 pStyle = "Wipe"; pDi = "270"; break;
    1316             :             case PDFWriter::Dissolve:
    1317           0 :                 pStyle = "Dissolve"; break;
    1318             :             case PDFWriter::GlitterLeftToRight:
    1319           0 :                 pStyle = "Glitter"; pDi = "0"; break;
    1320             :             case PDFWriter::GlitterTopToBottom:
    1321           0 :                 pStyle = "Glitter"; pDi = "270"; break;
    1322             :             case PDFWriter::GlitterTopLeftToBottomRight:
    1323           0 :                 pStyle = "Glitter"; pDi = "315"; break;
    1324             :             case PDFWriter::Regular:
    1325           0 :                 break;
    1326             :         }
    1327             :         // transition style
    1328           0 :         if( pStyle )
    1329             :         {
    1330           0 :             aLine.append( "/S/" );
    1331           0 :             aLine.append( pStyle );
    1332           0 :             aLine.append( "\n" );
    1333             :         }
    1334           0 :         if( pDm )
    1335             :         {
    1336           0 :             aLine.append( "/Dm/" );
    1337           0 :             aLine.append( pDm );
    1338           0 :             aLine.append( "\n" );
    1339             :         }
    1340           0 :         if( pM )
    1341             :         {
    1342           0 :             aLine.append( "/M/" );
    1343           0 :             aLine.append( pM );
    1344           0 :             aLine.append( "\n" );
    1345             :         }
    1346           0 :         if( pDi  )
    1347             :         {
    1348           0 :             aLine.append( "/Di " );
    1349           0 :             aLine.append( pDi );
    1350           0 :             aLine.append( "\n" );
    1351             :         }
    1352           0 :         aLine.append( ">>\n" );
    1353             :     }
    1354           0 :     if( m_pWriter->getVersion() > PDFWriter::PDF_1_3 && ! m_pWriter->m_bIsPDF_A1 )
    1355             :     {
    1356           0 :         aLine.append( "/Group<</S/Transparency/CS/DeviceRGB/I true>>" );
    1357             :     }
    1358           0 :     aLine.append( "/Contents" );
    1359           0 :     unsigned int nStreamObjects = m_aStreamObjects.size();
    1360           0 :     if( nStreamObjects > 1 )
    1361           0 :         aLine.append( '[' );
    1362           0 :     for( size_t i = 0; i < m_aStreamObjects.size(); i++ )
    1363             :     {
    1364           0 :         aLine.append( ' ' );
    1365           0 :         aLine.append( m_aStreamObjects[i] );
    1366           0 :         aLine.append( " 0 R" );
    1367             :     }
    1368           0 :     if( nStreamObjects > 1 )
    1369           0 :         aLine.append( ']' );
    1370           0 :     aLine.append( ">>\nendobj\n\n" );
    1371           0 :     return m_pWriter->writeBuffer( aLine.getStr(), aLine.getLength() );
    1372             : }
    1373             : 
    1374             : namespace vcl
    1375             : {
    1376             : template < class GEOMETRY >
    1377           0 : GEOMETRY lcl_convert( const MapMode& _rSource, const MapMode& _rDest, OutputDevice* _pPixelConversion, const GEOMETRY& _rObject )
    1378             : {
    1379           0 :     GEOMETRY aPoint;
    1380           0 :     if ( MAP_PIXEL == _rSource.GetMapUnit() )
    1381             :     {
    1382           0 :         aPoint = _pPixelConversion->PixelToLogic( _rObject, _rDest );
    1383             :     }
    1384             :     else
    1385             :     {
    1386           0 :         aPoint = OutputDevice::LogicToLogic( _rObject, _rSource, _rDest );
    1387             :     }
    1388           0 :     return aPoint;
    1389             : }
    1390             : }
    1391             : 
    1392           0 : void PDFWriterImpl::PDFPage::appendPoint( const Point& rPoint, OStringBuffer& rBuffer, bool bNeg, Point* pOutPoint ) const
    1393             : {
    1394           0 :     if( pOutPoint )
    1395             :     {
    1396           0 :         Point aPoint( lcl_convert( m_pWriter->m_aGraphicsStack.front().m_aMapMode,
    1397             :                                    m_pWriter->m_aMapMode,
    1398             :                                    m_pWriter->getReferenceDevice(),
    1399           0 :                                    rPoint ) );
    1400           0 :         *pOutPoint = aPoint;
    1401             :     }
    1402             : 
    1403           0 :     Point aPoint( lcl_convert( m_pWriter->m_aGraphicsStack.front().m_aMapMode,
    1404             :                                m_pWriter->m_aMapMode,
    1405             :                                m_pWriter->getReferenceDevice(),
    1406           0 :                                rPoint ) );
    1407             : 
    1408           0 :     sal_Int32 nValue    = aPoint.X();
    1409           0 :     if( bNeg )
    1410           0 :         nValue = -nValue;
    1411             : 
    1412           0 :     appendFixedInt( nValue, rBuffer );
    1413             : 
    1414           0 :     rBuffer.append( ' ' );
    1415             : 
    1416           0 :     nValue      = pointToPixel(getHeight()) - aPoint.Y();
    1417           0 :     if( bNeg )
    1418           0 :         nValue = -nValue;
    1419             : 
    1420           0 :     appendFixedInt( nValue, rBuffer );
    1421           0 : }
    1422             : 
    1423           0 : void PDFWriterImpl::PDFPage::appendPixelPoint( const basegfx::B2DPoint& rPoint, OStringBuffer& rBuffer ) const
    1424             : {
    1425           0 :     double fValue   = pixelToPoint(rPoint.getX());
    1426             : 
    1427           0 :     appendDouble( fValue, rBuffer, nLog10Divisor );
    1428           0 :     rBuffer.append( ' ' );
    1429           0 :     fValue      = double(getHeight()) - pixelToPoint(rPoint.getY());
    1430           0 :     appendDouble( fValue, rBuffer, nLog10Divisor );
    1431           0 : }
    1432             : 
    1433           0 : void PDFWriterImpl::PDFPage::appendRect( const Rectangle& rRect, OStringBuffer& rBuffer ) const
    1434             : {
    1435           0 :     appendPoint( rRect.BottomLeft() + Point( 0, 1 ), rBuffer );
    1436           0 :     rBuffer.append( ' ' );
    1437           0 :     appendMappedLength( (sal_Int32)rRect.GetWidth(), rBuffer, false );
    1438           0 :     rBuffer.append( ' ' );
    1439           0 :     appendMappedLength( (sal_Int32)rRect.GetHeight(), rBuffer, true );
    1440           0 :     rBuffer.append( " re" );
    1441           0 : }
    1442             : 
    1443           0 : void PDFWriterImpl::PDFPage::convertRect( Rectangle& rRect ) const
    1444             : {
    1445           0 :     Point aLL = lcl_convert( m_pWriter->m_aGraphicsStack.front().m_aMapMode,
    1446             :                              m_pWriter->m_aMapMode,
    1447             :                              m_pWriter->getReferenceDevice(),
    1448           0 :                              rRect.BottomLeft() + Point( 0, 1 )
    1449           0 :                              );
    1450           0 :     Size aSize = lcl_convert( m_pWriter->m_aGraphicsStack.front().m_aMapMode,
    1451             :                               m_pWriter->m_aMapMode,
    1452             :                               m_pWriter->getReferenceDevice(),
    1453           0 :                               rRect.GetSize() );
    1454           0 :     rRect.Left()    = aLL.X();
    1455           0 :     rRect.Right()   = aLL.X() + aSize.Width();
    1456           0 :     rRect.Top()     = pointToPixel(getHeight()) - aLL.Y();
    1457           0 :     rRect.Bottom()  = rRect.Top() + aSize.Height();
    1458           0 : }
    1459             : 
    1460           0 : void PDFWriterImpl::PDFPage::appendPolygon( const Polygon& rPoly, OStringBuffer& rBuffer, bool bClose ) const
    1461             : {
    1462           0 :     sal_uInt16 nPoints = rPoly.GetSize();
    1463             :     /*
    1464             :      *  #108582# applications do weird things
    1465             :      */
    1466           0 :     sal_uInt32 nBufLen = rBuffer.getLength();
    1467           0 :     if( nPoints > 0 )
    1468             :     {
    1469           0 :         const sal_uInt8* pFlagArray = rPoly.GetConstFlagAry();
    1470           0 :         appendPoint( rPoly[0], rBuffer );
    1471           0 :         rBuffer.append( " m\n" );
    1472           0 :         for( sal_uInt16 i = 1; i < nPoints; i++ )
    1473             :         {
    1474           0 :             if( pFlagArray && pFlagArray[i] == POLY_CONTROL && nPoints-i > 2 )
    1475             :             {
    1476             :                 // bezier
    1477             :                 DBG_ASSERT( pFlagArray[i+1] == POLY_CONTROL && pFlagArray[i+2] != POLY_CONTROL, "unexpected sequence of control points" );
    1478           0 :                 appendPoint( rPoly[i], rBuffer );
    1479           0 :                 rBuffer.append( " " );
    1480           0 :                 appendPoint( rPoly[i+1], rBuffer );
    1481           0 :                 rBuffer.append( " " );
    1482           0 :                 appendPoint( rPoly[i+2], rBuffer );
    1483           0 :                 rBuffer.append( " c" );
    1484           0 :                 i += 2; // add additionally consumed points
    1485             :             }
    1486             :             else
    1487             :             {
    1488             :                 // line
    1489           0 :                 appendPoint( rPoly[i], rBuffer );
    1490           0 :                 rBuffer.append( " l" );
    1491             :             }
    1492           0 :             if( (rBuffer.getLength() - nBufLen) > 65 )
    1493             :             {
    1494           0 :                 rBuffer.append( "\n" );
    1495           0 :                 nBufLen = rBuffer.getLength();
    1496             :             }
    1497             :             else
    1498           0 :                 rBuffer.append( " " );
    1499             :         }
    1500           0 :         if( bClose )
    1501           0 :             rBuffer.append( "h\n" );
    1502             :     }
    1503           0 : }
    1504             : 
    1505           0 : void PDFWriterImpl::PDFPage::appendPolygon( const basegfx::B2DPolygon& rPoly, OStringBuffer& rBuffer, bool bClose ) const
    1506             : {
    1507           0 :     basegfx::B2DPolygon aPoly( lcl_convert( m_pWriter->m_aGraphicsStack.front().m_aMapMode,
    1508             :                                             m_pWriter->m_aMapMode,
    1509             :                                             m_pWriter->getReferenceDevice(),
    1510           0 :                                             rPoly ) );
    1511             : 
    1512           0 :     if( basegfx::tools::isRectangle( aPoly ) )
    1513             :     {
    1514           0 :         basegfx::B2DRange aRange( aPoly.getB2DRange() );
    1515           0 :         basegfx::B2DPoint aBL( aRange.getMinX(), aRange.getMaxY() );
    1516           0 :         appendPixelPoint( aBL, rBuffer );
    1517           0 :         rBuffer.append( ' ' );
    1518           0 :         appendMappedLength( aRange.getWidth(), rBuffer, false, NULL, nLog10Divisor );
    1519           0 :         rBuffer.append( ' ' );
    1520           0 :         appendMappedLength( aRange.getHeight(), rBuffer, true, NULL, nLog10Divisor );
    1521           0 :         rBuffer.append( " re\n" );
    1522           0 :         return;
    1523             :     }
    1524           0 :     sal_uInt32 nPoints = aPoly.count();
    1525           0 :     if( nPoints > 0 )
    1526             :     {
    1527           0 :         sal_uInt32 nBufLen = rBuffer.getLength();
    1528           0 :         basegfx::B2DPoint aLastPoint( aPoly.getB2DPoint( 0 ) );
    1529           0 :         appendPixelPoint( aLastPoint, rBuffer );
    1530           0 :         rBuffer.append( " m\n" );
    1531           0 :         for( sal_uInt32 i = 1; i <= nPoints; i++ )
    1532             :         {
    1533           0 :             if( i != nPoints || aPoly.isClosed() )
    1534             :             {
    1535           0 :                 sal_uInt32 nCurPoint  = i % nPoints;
    1536           0 :                 sal_uInt32 nLastPoint = i-1;
    1537           0 :                 basegfx::B2DPoint aPoint( aPoly.getB2DPoint( nCurPoint ) );
    1538           0 :                 if( aPoly.isNextControlPointUsed( nLastPoint ) &&
    1539           0 :                     aPoly.isPrevControlPointUsed( nCurPoint ) )
    1540             :                 {
    1541           0 :                     appendPixelPoint( aPoly.getNextControlPoint( nLastPoint ), rBuffer );
    1542           0 :                     rBuffer.append( ' ' );
    1543           0 :                     appendPixelPoint( aPoly.getPrevControlPoint( nCurPoint ), rBuffer );
    1544           0 :                     rBuffer.append( ' ' );
    1545           0 :                     appendPixelPoint( aPoint, rBuffer );
    1546           0 :                     rBuffer.append( " c" );
    1547             :                 }
    1548           0 :                 else if( aPoly.isNextControlPointUsed( nLastPoint ) )
    1549             :                 {
    1550           0 :                     appendPixelPoint( aPoly.getNextControlPoint( nLastPoint ), rBuffer );
    1551           0 :                     rBuffer.append( ' ' );
    1552           0 :                     appendPixelPoint( aPoint, rBuffer );
    1553           0 :                     rBuffer.append( " y" );
    1554             :                 }
    1555           0 :                 else if( aPoly.isPrevControlPointUsed( nCurPoint ) )
    1556             :                 {
    1557           0 :                     appendPixelPoint( aPoly.getPrevControlPoint( nCurPoint ), rBuffer );
    1558           0 :                     rBuffer.append( ' ' );
    1559           0 :                     appendPixelPoint( aPoint, rBuffer );
    1560           0 :                     rBuffer.append( " v" );
    1561             :                 }
    1562             :                 else
    1563             :                 {
    1564           0 :                     appendPixelPoint( aPoint, rBuffer );
    1565           0 :                     rBuffer.append( " l" );
    1566             :                 }
    1567           0 :                 if( (rBuffer.getLength() - nBufLen) > 65 )
    1568             :                 {
    1569           0 :                     rBuffer.append( "\n" );
    1570           0 :                     nBufLen = rBuffer.getLength();
    1571             :                 }
    1572             :                 else
    1573           0 :                     rBuffer.append( " " );
    1574             :             }
    1575             :         }
    1576           0 :         if( bClose )
    1577           0 :             rBuffer.append( "h\n" );
    1578           0 :     }
    1579             : }
    1580             : 
    1581           0 : void PDFWriterImpl::PDFPage::appendPolyPolygon( const tools::PolyPolygon& rPolyPoly, OStringBuffer& rBuffer, bool bClose ) const
    1582             : {
    1583           0 :     sal_uInt16 nPolygons = rPolyPoly.Count();
    1584           0 :     for( sal_uInt16 n = 0; n < nPolygons; n++ )
    1585           0 :         appendPolygon( rPolyPoly[n], rBuffer, bClose );
    1586           0 : }
    1587             : 
    1588           0 : void PDFWriterImpl::PDFPage::appendPolyPolygon( const basegfx::B2DPolyPolygon& rPolyPoly, OStringBuffer& rBuffer, bool bClose ) const
    1589             : {
    1590           0 :     sal_uInt32 nPolygons = rPolyPoly.count();
    1591           0 :     for( sal_uInt32 n = 0; n < nPolygons; n++ )
    1592           0 :         appendPolygon( rPolyPoly.getB2DPolygon( n ), rBuffer, bClose );
    1593           0 : }
    1594             : 
    1595           0 : void PDFWriterImpl::PDFPage::appendMappedLength( sal_Int32 nLength, OStringBuffer& rBuffer, bool bVertical, sal_Int32* pOutLength ) const
    1596             : {
    1597           0 :     sal_Int32 nValue = nLength;
    1598           0 :     if ( nLength < 0 )
    1599             :     {
    1600           0 :         rBuffer.append( '-' );
    1601           0 :         nValue = -nLength;
    1602             :     }
    1603           0 :     Size aSize( lcl_convert( m_pWriter->m_aGraphicsStack.front().m_aMapMode,
    1604             :                              m_pWriter->m_aMapMode,
    1605             :                              m_pWriter->getReferenceDevice(),
    1606           0 :                              Size( nValue, nValue ) ) );
    1607           0 :     nValue = bVertical ? aSize.Height() : aSize.Width();
    1608           0 :     if( pOutLength )
    1609           0 :         *pOutLength = ((nLength < 0 ) ? -nValue : nValue);
    1610             : 
    1611           0 :     appendFixedInt( nValue, rBuffer, 1 );
    1612           0 : }
    1613             : 
    1614           0 : void PDFWriterImpl::PDFPage::appendMappedLength( double fLength, OStringBuffer& rBuffer, bool bVertical, sal_Int32* pOutLength, sal_Int32 nPrecision ) const
    1615             : {
    1616           0 :     Size aSize( lcl_convert( m_pWriter->m_aGraphicsStack.front().m_aMapMode,
    1617             :                              m_pWriter->m_aMapMode,
    1618             :                              m_pWriter->getReferenceDevice(),
    1619           0 :                              Size( 1000, 1000 ) ) );
    1620           0 :     if( pOutLength )
    1621           0 :         *pOutLength = (sal_Int32)(fLength*(double)(bVertical ? aSize.Height() : aSize.Width())/1000.0);
    1622           0 :     fLength *= pixelToPoint((double)(bVertical ? aSize.Height() : aSize.Width()) / 1000.0);
    1623           0 :     appendDouble( fLength, rBuffer, nPrecision );
    1624           0 : }
    1625             : 
    1626           0 : bool PDFWriterImpl::PDFPage::appendLineInfo( const LineInfo& rInfo, OStringBuffer& rBuffer ) const
    1627             : {
    1628           0 :     if(LINE_DASH == rInfo.GetStyle() && rInfo.GetDashLen() != rInfo.GetDotLen())
    1629             :     {
    1630             :         // dashed and non-degraded case, check for implementation limits of dash array
    1631             :         // in PDF reader apps (e.g. acroread)
    1632           0 :         if(2 * (rInfo.GetDashCount() + rInfo.GetDotCount()) > 10)
    1633             :         {
    1634           0 :             return false;
    1635             :         }
    1636             :     }
    1637             : 
    1638           0 :     if(basegfx::B2DLineJoin::NONE != rInfo.GetLineJoin())
    1639             :     {
    1640             :         // LineJoin used, ExtLineInfo required
    1641           0 :         return false;
    1642             :     }
    1643             : 
    1644           0 :     if(com::sun::star::drawing::LineCap_BUTT != rInfo.GetLineCap())
    1645             :     {
    1646             :         // LineCap used, ExtLineInfo required
    1647           0 :         return false;
    1648             :     }
    1649             : 
    1650           0 :     if( rInfo.GetStyle() == LINE_DASH )
    1651             :     {
    1652           0 :         rBuffer.append( "[ " );
    1653           0 :         if( rInfo.GetDashLen() == rInfo.GetDotLen() ) // degraded case
    1654             :         {
    1655           0 :             appendMappedLength( (sal_Int32)rInfo.GetDashLen(), rBuffer );
    1656           0 :             rBuffer.append( ' ' );
    1657           0 :             appendMappedLength( (sal_Int32)rInfo.GetDistance(), rBuffer );
    1658           0 :             rBuffer.append( ' ' );
    1659             :         }
    1660             :         else
    1661             :         {
    1662           0 :             for( int n = 0; n < rInfo.GetDashCount(); n++ )
    1663             :             {
    1664           0 :                 appendMappedLength( (sal_Int32)rInfo.GetDashLen(), rBuffer );
    1665           0 :                 rBuffer.append( ' ' );
    1666           0 :                 appendMappedLength( (sal_Int32)rInfo.GetDistance(), rBuffer );
    1667           0 :                 rBuffer.append( ' ' );
    1668             :             }
    1669           0 :             for( int m = 0; m < rInfo.GetDotCount(); m++ )
    1670             :             {
    1671           0 :                 appendMappedLength( (sal_Int32)rInfo.GetDotLen(), rBuffer );
    1672           0 :                 rBuffer.append( ' ' );
    1673           0 :                 appendMappedLength( (sal_Int32)rInfo.GetDistance(), rBuffer );
    1674           0 :                 rBuffer.append( ' ' );
    1675             :             }
    1676             :         }
    1677           0 :         rBuffer.append( "] 0 d\n" );
    1678             :     }
    1679             : 
    1680           0 :     if( rInfo.GetWidth() > 1 )
    1681             :     {
    1682           0 :         appendMappedLength( (sal_Int32)rInfo.GetWidth(), rBuffer );
    1683           0 :         rBuffer.append( " w\n" );
    1684             :     }
    1685           0 :     else if( rInfo.GetWidth() == 0 )
    1686             :     {
    1687             :         // "pixel" line
    1688           0 :         appendDouble( 72.0/double(m_pWriter->getReferenceDevice()->GetDPIX()), rBuffer );
    1689           0 :         rBuffer.append( " w\n" );
    1690             :     }
    1691             : 
    1692           0 :     return true;
    1693             : }
    1694             : 
    1695           0 : void PDFWriterImpl::PDFPage::appendWaveLine( sal_Int32 nWidth, sal_Int32 nY, sal_Int32 nDelta, OStringBuffer& rBuffer ) const
    1696             : {
    1697           0 :     if( nWidth <= 0 )
    1698           0 :         return;
    1699           0 :     if( nDelta < 1 )
    1700           0 :         nDelta = 1;
    1701             : 
    1702           0 :     rBuffer.append( "0 " );
    1703           0 :     appendMappedLength( nY, rBuffer, true );
    1704           0 :     rBuffer.append( " m\n" );
    1705           0 :     for( sal_Int32 n = 0; n < nWidth; )
    1706             :     {
    1707           0 :         n += nDelta;
    1708           0 :         appendMappedLength( n, rBuffer, false );
    1709           0 :         rBuffer.append( ' ' );
    1710           0 :         appendMappedLength( nDelta+nY, rBuffer, true );
    1711           0 :         rBuffer.append( ' ' );
    1712           0 :         n += nDelta;
    1713           0 :         appendMappedLength( n, rBuffer, false );
    1714           0 :         rBuffer.append( ' ' );
    1715           0 :         appendMappedLength( nY, rBuffer, true );
    1716           0 :         rBuffer.append( " v " );
    1717           0 :         if( n < nWidth )
    1718             :         {
    1719           0 :             n += nDelta;
    1720           0 :             appendMappedLength( n, rBuffer, false );
    1721           0 :             rBuffer.append( ' ' );
    1722           0 :             appendMappedLength( nY-nDelta, rBuffer, true );
    1723           0 :             rBuffer.append( ' ' );
    1724           0 :             n += nDelta;
    1725           0 :             appendMappedLength( n, rBuffer, false );
    1726           0 :             rBuffer.append( ' ' );
    1727           0 :             appendMappedLength( nY, rBuffer, true );
    1728           0 :             rBuffer.append( " v\n" );
    1729             :         }
    1730             :     }
    1731           0 :     rBuffer.append( "S\n" );
    1732             : }
    1733             : 
    1734           0 :  PDFWriterImpl::PDFWriterImpl( const PDFWriter::PDFWriterContext& rContext,
    1735             :                                const com::sun::star::uno::Reference< com::sun::star::beans::XMaterialHolder >& xEnc,
    1736             :                                PDFWriter& i_rOuterFace)
    1737             :         :
    1738             :         m_pReferenceDevice( NULL ),
    1739           0 :         m_aMapMode( MAP_POINT, Point(), Fraction( 1L, pointToPixel(1) ), Fraction( 1L, pointToPixel(1) ) ),
    1740             :         m_nCurrentStructElement( 0 ),
    1741             :         m_bEmitStructure( true ),
    1742             :         m_bNewMCID( false ),
    1743             :         m_nNextFID( 1 ),
    1744             :         m_nInheritedPageWidth( 595 ),  // default A4
    1745             :         m_nInheritedPageHeight( 842 ), // default A4
    1746             :         m_eInheritedOrientation( PDFWriter::Portrait ),
    1747             :         m_nCurrentPage( -1 ),
    1748             :         m_nCatalogObject(0),
    1749             :         m_nSignatureObject( -1 ),
    1750             :         m_nSignatureContentOffset( 0 ),
    1751             :         m_nSignatureLastByteRangeNoOffset( 0 ),
    1752             :         m_nResourceDict( -1 ),
    1753             :         m_nFontDictObject( -1 ),
    1754             :         m_aContext(rContext),
    1755             :         m_aFile(m_aContext.URL),
    1756             :         m_bOpen(false),
    1757             :         m_pCodec( NULL ),
    1758             :         m_pMemStream(NULL),
    1759           0 :         m_aDocDigest( rtl_digest_createMD5() ),
    1760             :         m_aCipher( nullptr ),
    1761             :         m_aDigest( NULL ),
    1762             :         m_nKeyLength(0),
    1763             :         m_nRC4KeyLength(0),
    1764             :         m_bEncryptThisStream( false ),
    1765             :         m_nAccessPermissions(0),
    1766             :         m_pEncryptionBuffer( NULL ),
    1767             :         m_nEncryptionBufferSize( 0 ),
    1768             :         m_bIsPDF_A1( false ),
    1769           0 :         m_rOuterFace( i_rOuterFace )
    1770             : {
    1771             : #ifdef DO_TEST_PDF
    1772             :     static bool bOnce = true;
    1773             :     if( bOnce )
    1774             :     {
    1775             :         bOnce = false;
    1776             :         doTestCode();
    1777             :     }
    1778             : #endif
    1779           0 :     m_aStructure.push_back( PDFStructureElement() );
    1780           0 :     m_aStructure[0].m_nOwnElement       = 0;
    1781           0 :     m_aStructure[0].m_nParentElement    = 0;
    1782             : 
    1783           0 :     Font aFont;
    1784           0 :     aFont.SetName( OUString( "Times" ) );
    1785           0 :     aFont.SetSize( Size( 0, 12 ) );
    1786             : 
    1787           0 :     GraphicsState aState;
    1788           0 :     aState.m_aMapMode       = m_aMapMode;
    1789           0 :     aState.m_aFont          = aFont;
    1790           0 :     m_aGraphicsStack.push_front( aState );
    1791             : 
    1792           0 :     osl::File::RC aError = m_aFile.open(osl_File_OpenFlag_Write | osl_File_OpenFlag_Create);
    1793           0 :     if (aError != osl::File::E_None)
    1794             :     {
    1795           0 :         if (aError == osl::File::E_EXIST)
    1796             :         {
    1797           0 :             aError = m_aFile.open(osl_File_OpenFlag_Write);
    1798           0 :             if (aError == osl::File::E_None)
    1799           0 :                 aError = m_aFile.setSize(0);
    1800             :         }
    1801             :     }
    1802           0 :     if (aError != osl::File::E_None)
    1803           0 :         return;
    1804             : 
    1805           0 :     m_bOpen = true;
    1806             : 
    1807             :     // setup DocInfo
    1808           0 :     setupDocInfo();
    1809             : 
    1810             :     /* prepare the cypher engine, can be done in CTOR, free in DTOR */
    1811           0 :     m_aCipher = rtl_cipher_createARCFOUR( rtl_Cipher_ModeStream );
    1812           0 :     m_aDigest = rtl_digest_createMD5();
    1813             : 
    1814             :     /* the size of the Codec default maximum */
    1815             :     /* is this 0x4000 required to be the same as MAX_SIGNATURE_CONTENT_LENGTH or just coincidentally the same at the moment? */
    1816           0 :     if (!checkEncryptionBufferSize(0x4000))
    1817             :     {
    1818           0 :         m_aFile.close();
    1819           0 :         m_bOpen = false;
    1820           0 :         return;
    1821             :     }
    1822             : 
    1823           0 :     if( xEnc.is() )
    1824           0 :         prepareEncryption( xEnc );
    1825             : 
    1826           0 :     if( m_aContext.Encryption.Encrypt() )
    1827             :     {
    1828             :         // sanity check
    1829           0 :         if( m_aContext.Encryption.OValue.size() != ENCRYPTED_PWD_SIZE ||
    1830           0 :             m_aContext.Encryption.UValue.size() != ENCRYPTED_PWD_SIZE ||
    1831           0 :             m_aContext.Encryption.EncryptionKey.size() != MAXIMUM_RC4_KEY_LENGTH
    1832             :            )
    1833             :         {
    1834             :             // the field lengths are invalid ? This was not setup by initEncryption.
    1835             :             // do not encrypt after all
    1836           0 :             m_aContext.Encryption.OValue.clear();
    1837           0 :             m_aContext.Encryption.UValue.clear();
    1838             :             OSL_ENSURE( false, "encryption data failed sanity check, encryption disabled" );
    1839             :         }
    1840             :         else // setup key lengths
    1841           0 :             m_nAccessPermissions = computeAccessPermissions( m_aContext.Encryption, m_nKeyLength, m_nRC4KeyLength );
    1842             :     }
    1843             : 
    1844             :     // write header
    1845           0 :     OStringBuffer aBuffer( 20 );
    1846           0 :     aBuffer.append( "%PDF-" );
    1847           0 :     switch( m_aContext.Version )
    1848             :     {
    1849           0 :         case PDFWriter::PDF_1_2: aBuffer.append( "1.2" );break;
    1850           0 :         case PDFWriter::PDF_1_3: aBuffer.append( "1.3" );break;
    1851             :         case PDFWriter::PDF_A_1:
    1852             :         default:
    1853           0 :         case PDFWriter::PDF_1_4: aBuffer.append( "1.4" );break;
    1854           0 :         case PDFWriter::PDF_1_5: aBuffer.append( "1.5" );break;
    1855             :     }
    1856             :     // append something binary as comment (suggested in PDF Reference)
    1857           0 :     aBuffer.append( "\n%\303\244\303\274\303\266\303\237\n" );
    1858           0 :     if( !writeBuffer( aBuffer.getStr(), aBuffer.getLength() ) )
    1859             :     {
    1860           0 :         m_aFile.close();
    1861           0 :         m_bOpen = false;
    1862           0 :         return;
    1863             :     }
    1864             : 
    1865             :     // insert outline root
    1866           0 :     m_aOutline.push_back( PDFOutlineEntry() );
    1867             : 
    1868           0 :     m_bIsPDF_A1 = (m_aContext.Version == PDFWriter::PDF_A_1);
    1869           0 :     if( m_bIsPDF_A1 )
    1870           0 :         m_aContext.Version = PDFWriter::PDF_1_4; //meaning we need PDF 1.4, PDF/A flavour
    1871             : }
    1872             : 
    1873           0 : PDFWriterImpl::~PDFWriterImpl()
    1874             : {
    1875           0 :     if( m_aDocDigest )
    1876           0 :         rtl_digest_destroyMD5( m_aDocDigest );
    1877           0 :     m_pReferenceDevice.disposeAndClear();
    1878             : 
    1879           0 :     if( m_aCipher )
    1880           0 :         rtl_cipher_destroyARCFOUR( m_aCipher );
    1881           0 :     if( m_aDigest )
    1882           0 :         rtl_digest_destroyMD5( m_aDigest );
    1883             : 
    1884           0 :     rtl_freeMemory( m_pEncryptionBuffer );
    1885           0 : }
    1886             : 
    1887           0 : void PDFWriterImpl::setupDocInfo()
    1888             : {
    1889           0 :     std::vector< sal_uInt8 > aId;
    1890           0 :     computeDocumentIdentifier( aId, m_aContext.DocumentInfo, m_aCreationDateString, m_aCreationMetaDateString );
    1891           0 :     if( m_aContext.Encryption.DocumentIdentifier.empty() )
    1892           0 :         m_aContext.Encryption.DocumentIdentifier = aId;
    1893           0 : }
    1894             : 
    1895           0 : void PDFWriterImpl::computeDocumentIdentifier( std::vector< sal_uInt8 >& o_rIdentifier,
    1896             :                                                const vcl::PDFWriter::PDFDocInfo& i_rDocInfo,
    1897             :                                                OString& o_rCString1,
    1898             :                                                OString& o_rCString2
    1899             :                                                )
    1900             : {
    1901           0 :     o_rIdentifier.clear();
    1902             : 
    1903             :     //build the document id
    1904           0 :     OString aInfoValuesOut;
    1905           0 :     OStringBuffer aID( 1024 );
    1906           0 :     if( !i_rDocInfo.Title.isEmpty() )
    1907           0 :         appendUnicodeTextString( i_rDocInfo.Title, aID );
    1908           0 :     if( !i_rDocInfo.Author.isEmpty() )
    1909           0 :         appendUnicodeTextString( i_rDocInfo.Author, aID );
    1910           0 :     if( !i_rDocInfo.Subject.isEmpty() )
    1911           0 :         appendUnicodeTextString( i_rDocInfo.Subject, aID );
    1912           0 :     if( !i_rDocInfo.Keywords.isEmpty() )
    1913           0 :         appendUnicodeTextString( i_rDocInfo.Keywords, aID );
    1914           0 :     if( !i_rDocInfo.Creator.isEmpty() )
    1915           0 :         appendUnicodeTextString( i_rDocInfo.Creator, aID );
    1916           0 :     if( !i_rDocInfo.Producer.isEmpty() )
    1917           0 :         appendUnicodeTextString( i_rDocInfo.Producer, aID );
    1918             : 
    1919             :     TimeValue aTVal, aGMT;
    1920             :     oslDateTime aDT;
    1921           0 :     osl_getSystemTime( &aGMT );
    1922           0 :     osl_getLocalTimeFromSystemTime( &aGMT, &aTVal );
    1923           0 :     osl_getDateTimeFromTimeValue( &aTVal, &aDT );
    1924           0 :     OStringBuffer aCreationDateString(64), aCreationMetaDateString(64);
    1925           0 :     aCreationDateString.append( "D:" );
    1926           0 :     aCreationDateString.append( (sal_Char)('0' + ((aDT.Year/1000)%10)) );
    1927           0 :     aCreationDateString.append( (sal_Char)('0' + ((aDT.Year/100)%10)) );
    1928           0 :     aCreationDateString.append( (sal_Char)('0' + ((aDT.Year/10)%10)) );
    1929           0 :     aCreationDateString.append( (sal_Char)('0' + ((aDT.Year)%10)) );
    1930           0 :     aCreationDateString.append( (sal_Char)('0' + ((aDT.Month/10)%10)) );
    1931           0 :     aCreationDateString.append( (sal_Char)('0' + ((aDT.Month)%10)) );
    1932           0 :     aCreationDateString.append( (sal_Char)('0' + ((aDT.Day/10)%10)) );
    1933           0 :     aCreationDateString.append( (sal_Char)('0' + ((aDT.Day)%10)) );
    1934           0 :     aCreationDateString.append( (sal_Char)('0' + ((aDT.Hours/10)%10)) );
    1935           0 :     aCreationDateString.append( (sal_Char)('0' + ((aDT.Hours)%10)) );
    1936           0 :     aCreationDateString.append( (sal_Char)('0' + ((aDT.Minutes/10)%10)) );
    1937           0 :     aCreationDateString.append( (sal_Char)('0' + ((aDT.Minutes)%10)) );
    1938           0 :     aCreationDateString.append( (sal_Char)('0' + ((aDT.Seconds/10)%10)) );
    1939           0 :     aCreationDateString.append( (sal_Char)('0' + ((aDT.Seconds)%10)) );
    1940             : 
    1941             :     //--> i59651, we fill the Metadata date string as well, if PDF/A is requested
    1942             :     // according to ISO 19005-1:2005 6.7.3 the date is corrected for
    1943             :     // local time zone offset UTC only, whereas Acrobat 8 seems
    1944             :     // to use the localtime notation only
    1945             :     // according to a recommendation in XMP Specification (Jan 2004, page 75)
    1946             :     // the Acrobat way seems the right approach
    1947           0 :     aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Year/1000)%10)) );
    1948           0 :     aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Year/100)%10)) );
    1949           0 :     aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Year/10)%10)) );
    1950           0 :     aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Year)%10)) );
    1951           0 :     aCreationMetaDateString.append( "-" );
    1952           0 :     aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Month/10)%10)) );
    1953           0 :     aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Month)%10)) );
    1954           0 :     aCreationMetaDateString.append( "-" );
    1955           0 :     aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Day/10)%10)) );
    1956           0 :     aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Day)%10)) );
    1957           0 :     aCreationMetaDateString.append( "T" );
    1958           0 :     aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Hours/10)%10)) );
    1959           0 :     aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Hours)%10)) );
    1960           0 :     aCreationMetaDateString.append( ":" );
    1961           0 :     aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Minutes/10)%10)) );
    1962           0 :     aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Minutes)%10)) );
    1963           0 :     aCreationMetaDateString.append( ":" );
    1964           0 :     aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Seconds/10)%10)) );
    1965           0 :     aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Seconds)%10)) );
    1966             : 
    1967           0 :     sal_uInt32 nDelta = 0;
    1968           0 :     if( aGMT.Seconds > aTVal.Seconds )
    1969             :     {
    1970           0 :         aCreationDateString.append( "-" );
    1971           0 :         nDelta = aGMT.Seconds-aTVal.Seconds;
    1972           0 :         aCreationMetaDateString.append( "-" );
    1973             :     }
    1974           0 :     else if( aGMT.Seconds < aTVal.Seconds )
    1975             :     {
    1976           0 :         aCreationDateString.append( "+" );
    1977           0 :         nDelta = aTVal.Seconds-aGMT.Seconds;
    1978           0 :         aCreationMetaDateString.append( "+" );
    1979             :     }
    1980             :     else
    1981             :     {
    1982           0 :         aCreationDateString.append( "Z" );
    1983           0 :         aCreationMetaDateString.append( "Z" );
    1984             : 
    1985             :     }
    1986           0 :     if( nDelta )
    1987             :     {
    1988           0 :         aCreationDateString.append( (sal_Char)('0' + ((nDelta/36000)%10)) );
    1989           0 :         aCreationDateString.append( (sal_Char)('0' + ((nDelta/3600)%10)) );
    1990           0 :         aCreationDateString.append( "'" );
    1991           0 :         aCreationDateString.append( (sal_Char)('0' + ((nDelta/600)%6)) );
    1992           0 :         aCreationDateString.append( (sal_Char)('0' + ((nDelta/60)%10)) );
    1993             : 
    1994           0 :         aCreationMetaDateString.append( (sal_Char)('0' + ((nDelta/36000)%10)) );
    1995           0 :         aCreationMetaDateString.append( (sal_Char)('0' + ((nDelta/3600)%10)) );
    1996           0 :         aCreationMetaDateString.append( ":" );
    1997           0 :         aCreationMetaDateString.append( (sal_Char)('0' + ((nDelta/600)%6)) );
    1998           0 :         aCreationMetaDateString.append( (sal_Char)('0' + ((nDelta/60)%10)) );
    1999             :     }
    2000           0 :     aCreationDateString.append( "'" );
    2001           0 :     aID.append( aCreationDateString.getStr(), aCreationDateString.getLength() );
    2002             : 
    2003           0 :     aInfoValuesOut = aID.makeStringAndClear();
    2004           0 :     o_rCString1 = aCreationDateString.makeStringAndClear();
    2005           0 :     o_rCString2 = aCreationMetaDateString.makeStringAndClear();
    2006             : 
    2007           0 :     rtlDigest aDigest = rtl_digest_createMD5();
    2008             :     OSL_ENSURE( aDigest != NULL, "PDFWriterImpl::computeDocumentIdentifier: cannot obtain a digest object !" );
    2009           0 :     if( aDigest )
    2010             :     {
    2011           0 :         rtlDigestError nError = rtl_digest_updateMD5( aDigest, &aGMT, sizeof( aGMT ) );
    2012           0 :         if( nError == rtl_Digest_E_None )
    2013           0 :             nError = rtl_digest_updateMD5( aDigest, aInfoValuesOut.getStr(), aInfoValuesOut.getLength() );
    2014           0 :         if( nError == rtl_Digest_E_None )
    2015             :         {
    2016           0 :             o_rIdentifier = std::vector< sal_uInt8 >( 16, 0 );
    2017             :             //the binary form of the doc id is needed for encryption stuff
    2018           0 :             rtl_digest_getMD5( aDigest, &o_rIdentifier[0], 16 );
    2019             :         }
    2020           0 :         rtl_digest_destroyMD5(aDigest);
    2021           0 :     }
    2022           0 : }
    2023             : 
    2024             : /* i12626 methods */
    2025             : /*
    2026             : check if the Unicode string must be encrypted or not, perform the requested task,
    2027             : append the string as unicode hex, encrypted if needed
    2028             :  */
    2029           0 : inline void PDFWriterImpl::appendUnicodeTextStringEncrypt( const OUString& rInString, const sal_Int32 nInObjectNumber, OStringBuffer& rOutBuffer )
    2030             : {
    2031           0 :     rOutBuffer.append( "<" );
    2032           0 :     if( m_aContext.Encryption.Encrypt() )
    2033             :     {
    2034           0 :         const sal_Unicode* pStr = rInString.getStr();
    2035           0 :         sal_Int32 nLen = rInString.getLength();
    2036             :         //prepare a unicode string, encrypt it
    2037           0 :         if( checkEncryptionBufferSize( nLen*2 ) )
    2038             :         {
    2039           0 :             enableStringEncryption( nInObjectNumber );
    2040           0 :             sal_uInt8 *pCopy = m_pEncryptionBuffer;
    2041           0 :             sal_Int32 nChars = 2;
    2042           0 :             *pCopy++ = 0xFE;
    2043           0 :             *pCopy++ = 0xFF;
    2044             :             // we need to prepare a byte stream from the unicode string buffer
    2045           0 :             for( int i = 0; i < nLen; i++ )
    2046             :             {
    2047           0 :                 sal_Unicode aUnChar = pStr[i];
    2048           0 :                 *pCopy++ = (sal_uInt8)( aUnChar >> 8 );
    2049           0 :                 *pCopy++ = (sal_uInt8)( aUnChar & 255 );
    2050           0 :                 nChars += 2;
    2051             :             }
    2052             :             //encrypt in place
    2053           0 :             rtl_cipher_encodeARCFOUR( m_aCipher, m_pEncryptionBuffer, nChars, m_pEncryptionBuffer, nChars );
    2054             :             //now append, hexadecimal (appendHex), the encrypted result
    2055           0 :             for(int i = 0; i < nChars; i++)
    2056           0 :                 appendHex( m_pEncryptionBuffer[i], rOutBuffer );
    2057             :         }
    2058             :     }
    2059             :     else
    2060           0 :         appendUnicodeTextString( rInString, rOutBuffer );
    2061           0 :     rOutBuffer.append( ">" );
    2062           0 : }
    2063             : 
    2064           0 : inline void PDFWriterImpl::appendLiteralStringEncrypt( OStringBuffer& rInString, const sal_Int32 nInObjectNumber, OStringBuffer& rOutBuffer )
    2065             : {
    2066           0 :     rOutBuffer.append( "(" );
    2067           0 :     sal_Int32 nChars = rInString.getLength();
    2068             :     //check for encryption, if ok, encrypt the string, then convert with appndLiteralString
    2069           0 :     if( m_aContext.Encryption.Encrypt() && checkEncryptionBufferSize( nChars ) )
    2070             :     {
    2071             :         //encrypt the string in a buffer, then append it
    2072           0 :         enableStringEncryption( nInObjectNumber );
    2073           0 :         rtl_cipher_encodeARCFOUR( m_aCipher, rInString.getStr(), nChars, m_pEncryptionBuffer, nChars );
    2074           0 :         appendLiteralString( reinterpret_cast<sal_Char*>(m_pEncryptionBuffer), nChars, rOutBuffer );
    2075             :     }
    2076             :     else
    2077           0 :         appendLiteralString( rInString.getStr(), nChars , rOutBuffer );
    2078           0 :     rOutBuffer.append( ")" );
    2079           0 : }
    2080             : 
    2081           0 : inline void PDFWriterImpl::appendLiteralStringEncrypt( const OString& rInString, const sal_Int32 nInObjectNumber, OStringBuffer& rOutBuffer )
    2082             : {
    2083           0 :     OStringBuffer aBufferString( rInString );
    2084           0 :     appendLiteralStringEncrypt( aBufferString, nInObjectNumber, rOutBuffer);
    2085           0 : }
    2086             : 
    2087           0 : void PDFWriterImpl::appendLiteralStringEncrypt( const OUString& rInString, const sal_Int32 nInObjectNumber, OStringBuffer& rOutBuffer, rtl_TextEncoding nEnc )
    2088             : {
    2089           0 :     OString aBufferString( OUStringToOString( rInString, nEnc ) );
    2090           0 :     sal_Int32 nLen = aBufferString.getLength();
    2091           0 :     OStringBuffer aBuf( nLen );
    2092           0 :     const sal_Char* pT = aBufferString.getStr();
    2093             : 
    2094           0 :     for( sal_Int32 i = 0; i < nLen; i++, pT++ )
    2095             :     {
    2096           0 :         if( (*pT & 0x80) == 0 )
    2097           0 :             aBuf.append( *pT );
    2098             :         else
    2099             :         {
    2100           0 :             aBuf.append( '<' );
    2101           0 :             appendHex( *pT, aBuf );
    2102           0 :             aBuf.append( '>' );
    2103             :         }
    2104             :     }
    2105           0 :     aBufferString = aBuf.makeStringAndClear();
    2106           0 :     appendLiteralStringEncrypt( aBufferString, nInObjectNumber, rOutBuffer);
    2107           0 : }
    2108             : 
    2109             : /* end i12626 methods */
    2110             : 
    2111           0 : void PDFWriterImpl::emitComment( const char* pComment )
    2112             : {
    2113           0 :     OStringBuffer aLine( 64 );
    2114           0 :     aLine.append( "% " );
    2115           0 :     aLine.append( pComment );
    2116           0 :     aLine.append( "\n" );
    2117           0 :     writeBuffer( aLine.getStr(), aLine.getLength() );
    2118           0 : }
    2119             : 
    2120           0 : bool PDFWriterImpl::compressStream( SvMemoryStream* pStream )
    2121             : {
    2122             : #ifndef DEBUG_DISABLE_PDFCOMPRESSION
    2123           0 :     pStream->Seek( STREAM_SEEK_TO_END );
    2124           0 :     sal_uLong nEndPos = pStream->Tell();
    2125           0 :     pStream->Seek( STREAM_SEEK_TO_BEGIN );
    2126           0 :     ZCodec pCodec( 0x4000, 0x4000 );
    2127           0 :     SvMemoryStream aStream;
    2128           0 :     pCodec.BeginCompression();
    2129           0 :     pCodec.Write( aStream, static_cast<const sal_uInt8*>(pStream->GetData()), nEndPos );
    2130           0 :     pCodec.EndCompression();
    2131           0 :     nEndPos = aStream.Tell();
    2132           0 :     pStream->Seek( STREAM_SEEK_TO_BEGIN );
    2133           0 :     aStream.Seek( STREAM_SEEK_TO_BEGIN );
    2134           0 :     pStream->SetStreamSize( nEndPos );
    2135           0 :     pStream->Write( aStream.GetData(), nEndPos );
    2136           0 :     return true;
    2137             : #else
    2138             :     (void)pStream;
    2139             :     return false;
    2140             : #endif
    2141             : }
    2142             : 
    2143           0 : void PDFWriterImpl::beginCompression()
    2144             : {
    2145             : #ifndef DEBUG_DISABLE_PDFCOMPRESSION
    2146           0 :     m_pCodec = new ZCodec( 0x4000, 0x4000 );
    2147           0 :     m_pMemStream = new SvMemoryStream();
    2148           0 :     m_pCodec->BeginCompression();
    2149             : #endif
    2150           0 : }
    2151             : 
    2152           0 : void PDFWriterImpl::endCompression()
    2153             : {
    2154             : #ifndef DEBUG_DISABLE_PDFCOMPRESSION
    2155           0 :     if( m_pCodec )
    2156             :     {
    2157           0 :         m_pCodec->EndCompression();
    2158           0 :         delete m_pCodec;
    2159           0 :         m_pCodec = NULL;
    2160           0 :         sal_uInt64 nLen = m_pMemStream->Tell();
    2161           0 :         m_pMemStream->Seek( 0 );
    2162           0 :         writeBuffer( m_pMemStream->GetData(), nLen );
    2163           0 :         delete m_pMemStream;
    2164           0 :         m_pMemStream = NULL;
    2165             :     }
    2166             : #endif
    2167           0 : }
    2168             : 
    2169           0 : bool PDFWriterImpl::writeBuffer( const void* pBuffer, sal_uInt64 nBytes )
    2170             : {
    2171           0 :     if( ! m_bOpen ) // we are already down the drain
    2172           0 :         return false;
    2173             : 
    2174           0 :     if( ! nBytes ) // huh ?
    2175           0 :         return true;
    2176             : 
    2177           0 :     if( m_aOutputStreams.begin() != m_aOutputStreams.end() )
    2178             :     {
    2179           0 :         m_aOutputStreams.front().m_pStream->Seek( STREAM_SEEK_TO_END );
    2180           0 :         m_aOutputStreams.front().m_pStream->Write( pBuffer, sal::static_int_cast<sal_Size>(nBytes) );
    2181           0 :         return true;
    2182             :     }
    2183             : 
    2184             :     sal_uInt64 nWritten;
    2185           0 :     if( m_pCodec )
    2186             :     {
    2187           0 :         m_pCodec->Write( *m_pMemStream, static_cast<const sal_uInt8*>(pBuffer), (sal_uLong)nBytes );
    2188           0 :         nWritten = nBytes;
    2189             :     }
    2190             :     else
    2191             :     {
    2192           0 :         bool  buffOK = true;
    2193           0 :         if( m_bEncryptThisStream )
    2194             :         {
    2195             :             /* implement the encryption part of the PDF spec encryption algorithm 3.1 */
    2196           0 :             if( ( buffOK = checkEncryptionBufferSize( static_cast<sal_Int32>(nBytes) ) ) )
    2197             :                 rtl_cipher_encodeARCFOUR( m_aCipher,
    2198             :                                           pBuffer, static_cast<sal_Size>(nBytes),
    2199           0 :                                           m_pEncryptionBuffer, static_cast<sal_Size>(nBytes) );
    2200             :         }
    2201             : 
    2202           0 :         const void* pWriteBuffer = ( m_bEncryptThisStream && buffOK ) ? m_pEncryptionBuffer  : pBuffer;
    2203           0 :         if( m_aDocDigest )
    2204           0 :             rtl_digest_updateMD5( m_aDocDigest, pWriteBuffer, static_cast<sal_uInt32>(nBytes) );
    2205             : 
    2206           0 :         if (m_aFile.write(pWriteBuffer, nBytes, nWritten) != osl::File::E_None)
    2207           0 :             nWritten = 0;
    2208             : 
    2209           0 :         if( nWritten != nBytes )
    2210             :         {
    2211           0 :             m_aFile.close();
    2212           0 :             m_bOpen = false;
    2213             :         }
    2214             :     }
    2215             : 
    2216           0 :     return nWritten == nBytes;
    2217             : }
    2218             : 
    2219           0 : OutputDevice* PDFWriterImpl::getReferenceDevice()
    2220             : {
    2221           0 :     if( ! m_pReferenceDevice )
    2222             :     {
    2223           0 :         VclPtrInstance<VirtualDevice> pVDev( 0 );
    2224             : 
    2225           0 :         m_pReferenceDevice = pVDev;
    2226             : 
    2227           0 :         if( m_aContext.DPIx == 0 || m_aContext.DPIy == 0 )
    2228           0 :             pVDev->SetReferenceDevice( VirtualDevice::REFDEV_MODE_PDF1 );
    2229             :         else
    2230           0 :             pVDev->SetReferenceDevice( m_aContext.DPIx, m_aContext.DPIy );
    2231             : 
    2232           0 :         pVDev->SetOutputSizePixel( Size( 640, 480 ) );
    2233           0 :         pVDev->SetMapMode( MAP_MM );
    2234             : 
    2235           0 :         m_pReferenceDevice->mpPDFWriter = this;
    2236           0 :         m_pReferenceDevice->ImplUpdateFontData( true );
    2237             :     }
    2238           0 :     return m_pReferenceDevice;
    2239             : }
    2240             : 
    2241           0 : class ImplPdfBuiltinFontData : public PhysicalFontFace
    2242             : {
    2243             : private:
    2244             :     const PDFWriterImpl::BuiltinFont& mrBuiltin;
    2245             : 
    2246             : public:
    2247             :     enum {PDF_FONT_MAGIC = 0xBDFF0A1C };
    2248             :     explicit                            ImplPdfBuiltinFontData( const PDFWriterImpl::BuiltinFont& );
    2249           0 :     const PDFWriterImpl::BuiltinFont&   GetBuiltinFont() const  { return mrBuiltin; }
    2250             : 
    2251           0 :     virtual PhysicalFontFace*           Clone() const SAL_OVERRIDE { return new ImplPdfBuiltinFontData(*this); }
    2252             :     virtual ImplFontEntry*              CreateFontInstance( FontSelectPattern& ) const SAL_OVERRIDE;
    2253           0 :     virtual sal_IntPtr                  GetFontId() const SAL_OVERRIDE { return reinterpret_cast<sal_IntPtr>(&mrBuiltin); }
    2254             : };
    2255             : 
    2256           0 : inline const ImplPdfBuiltinFontData* GetPdfFontData( const PhysicalFontFace* pFontData )
    2257             : {
    2258           0 :     const ImplPdfBuiltinFontData* pFD = NULL;
    2259           0 :     if( pFontData && pFontData->CheckMagic( ImplPdfBuiltinFontData::PDF_FONT_MAGIC ) )
    2260           0 :         pFD = static_cast<const ImplPdfBuiltinFontData*>( pFontData );
    2261           0 :     return pFD;
    2262             : }
    2263             : 
    2264           0 : static ImplDevFontAttributes GetDevFontAttributes( const PDFWriterImpl::BuiltinFont& rBuiltin )
    2265             : {
    2266           0 :     ImplDevFontAttributes aDFA;
    2267           0 :     aDFA.SetFamilyName( OUString::createFromAscii( rBuiltin.m_pName ) );
    2268           0 :     aDFA.SetStyleName( OUString::createFromAscii( rBuiltin.m_pStyleName ) );
    2269           0 :     aDFA.SetFamilyType( rBuiltin.m_eFamily );
    2270           0 :     aDFA.SetSymbolFlag( rBuiltin.m_eCharSet != RTL_TEXTENCODING_MS_1252 );
    2271           0 :     aDFA.SetPitch( rBuiltin.m_ePitch );
    2272           0 :     aDFA.SetWeight( rBuiltin.m_eWeight );
    2273           0 :     aDFA.SetItalic( rBuiltin.m_eItalic );
    2274           0 :     aDFA.SetWidthType( rBuiltin.m_eWidthType );
    2275             : 
    2276           0 :     aDFA.mbOrientation  = true;
    2277           0 :     aDFA.mbDevice       = true;
    2278           0 :     aDFA.mnQuality      = 50000;
    2279           0 :     aDFA.mbSubsettable  = false;
    2280           0 :     aDFA.mbEmbeddable   = false;
    2281           0 :     return aDFA;
    2282             : }
    2283             : 
    2284           0 : ImplPdfBuiltinFontData::ImplPdfBuiltinFontData( const PDFWriterImpl::BuiltinFont& rBuiltin )
    2285             : :   PhysicalFontFace( GetDevFontAttributes(rBuiltin), PDF_FONT_MAGIC ),
    2286           0 :     mrBuiltin( rBuiltin )
    2287           0 : {}
    2288             : 
    2289           0 : ImplFontEntry* ImplPdfBuiltinFontData::CreateFontInstance( FontSelectPattern& rFSD ) const
    2290             : {
    2291           0 :     ImplFontEntry* pEntry = new ImplFontEntry( rFSD );
    2292           0 :     return pEntry;
    2293             : }
    2294             : 
    2295             : // - PDFWriterImpl -
    2296             : 
    2297           0 : sal_Int32 PDFWriterImpl::newPage( sal_Int32 nPageWidth, sal_Int32 nPageHeight, PDFWriter::Orientation eOrientation )
    2298             : {
    2299           0 :     endPage();
    2300           0 :     m_nCurrentPage = m_aPages.size();
    2301           0 :     m_aPages.push_back( PDFPage(this, nPageWidth, nPageHeight, eOrientation ) );
    2302           0 :     m_aPages.back().m_nPageIndex = m_nCurrentPage;
    2303           0 :     m_aPages.back().beginStream();
    2304             : 
    2305             :     // setup global graphics state
    2306             :     // linewidth is "1 pixel" by default
    2307           0 :     OStringBuffer aBuf( 16 );
    2308           0 :     appendDouble( 72.0/double(getReferenceDevice()->GetDPIX()), aBuf );
    2309           0 :     aBuf.append( " w\n" );
    2310           0 :     writeBuffer( aBuf.getStr(), aBuf.getLength() );
    2311             : 
    2312           0 :     return m_nCurrentPage;
    2313             : }
    2314             : 
    2315           0 : void PDFWriterImpl::endPage()
    2316             : {
    2317           0 :     if( m_aPages.begin() != m_aPages.end() )
    2318             :     {
    2319             :         // close eventual MC sequence
    2320           0 :         endStructureElementMCSeq();
    2321             : 
    2322             :         // sanity check
    2323           0 :         if( m_aOutputStreams.begin() != m_aOutputStreams.end() )
    2324             :         {
    2325             :             OSL_FAIL( "redirection across pages !!!" );
    2326           0 :             m_aOutputStreams.clear(); // leak !
    2327           0 :             m_aMapMode.SetOrigin( Point() );
    2328             :         }
    2329             : 
    2330           0 :         m_aGraphicsStack.clear();
    2331           0 :         m_aGraphicsStack.push_back( GraphicsState() );
    2332             : 
    2333             :         // this should pop the PDF graphics stack if necessary
    2334           0 :         updateGraphicsState();
    2335             : 
    2336           0 :         m_aPages.back().endStream();
    2337             : 
    2338             :         // reset the default font
    2339           0 :         Font aFont;
    2340           0 :         aFont.SetName( OUString( "Times" ) );
    2341           0 :         aFont.SetSize( Size( 0, 12 ) );
    2342             : 
    2343           0 :         m_aCurrentPDFState = m_aGraphicsStack.front();
    2344           0 :         m_aGraphicsStack.front().m_aFont =  aFont;
    2345             : 
    2346           0 :         for( std::list<BitmapEmit>::iterator it = m_aBitmaps.begin();
    2347           0 :              it != m_aBitmaps.end(); ++it )
    2348             :         {
    2349           0 :             if( ! it->m_aBitmap.IsEmpty() )
    2350             :             {
    2351           0 :                 writeBitmapObject( *it );
    2352           0 :                 it->m_aBitmap = BitmapEx();
    2353             :             }
    2354             :         }
    2355           0 :         for( std::list<JPGEmit>::iterator jpeg = m_aJPGs.begin(); jpeg != m_aJPGs.end(); ++jpeg )
    2356             :         {
    2357           0 :             if( jpeg->m_pStream )
    2358             :             {
    2359           0 :                 writeJPG( *jpeg );
    2360           0 :                 delete jpeg->m_pStream;
    2361           0 :                 jpeg->m_pStream = NULL;
    2362           0 :                 jpeg->m_aMask = Bitmap();
    2363             :             }
    2364             :         }
    2365           0 :         for( std::list<TransparencyEmit>::iterator t = m_aTransparentObjects.begin();
    2366           0 :              t != m_aTransparentObjects.end(); ++t )
    2367             :         {
    2368           0 :             if( t->m_pContentStream )
    2369             :             {
    2370           0 :                 writeTransparentObject( *t );
    2371           0 :                 delete t->m_pContentStream;
    2372           0 :                 t->m_pContentStream = NULL;
    2373             :             }
    2374           0 :         }
    2375             :     }
    2376           0 : }
    2377             : 
    2378           0 : sal_Int32 PDFWriterImpl::createObject()
    2379             : {
    2380           0 :     m_aObjects.push_back( ~0U );
    2381           0 :     return m_aObjects.size();
    2382             : }
    2383             : 
    2384           0 : bool PDFWriterImpl::updateObject( sal_Int32 n )
    2385             : {
    2386           0 :     if( ! m_bOpen )
    2387           0 :         return false;
    2388             : 
    2389           0 :     sal_uInt64 nOffset = ~0U;
    2390           0 :     osl::File::RC aError = m_aFile.getPos(nOffset);
    2391             :     DBG_ASSERT( aError == osl::File::E_None, "could not register object" );
    2392           0 :     if (aError != osl::File::E_None)
    2393             :     {
    2394           0 :         m_aFile.close();
    2395           0 :         m_bOpen = false;
    2396             :     }
    2397           0 :     m_aObjects[ n-1 ] = nOffset;
    2398           0 :     return aError == osl::File::E_None;
    2399             : }
    2400             : 
    2401             : #define CHECK_RETURN( x ) if( !(x) ) return 0
    2402             : 
    2403           0 : sal_Int32 PDFWriterImpl::emitStructParentTree( sal_Int32 nObject )
    2404             : {
    2405           0 :     if( nObject > 0 )
    2406             :     {
    2407           0 :         OStringBuffer aLine( 1024 );
    2408             : 
    2409           0 :         aLine.append( nObject );
    2410             :         aLine.append( " 0 obj\n"
    2411           0 :                       "<</Nums[\n" );
    2412           0 :         sal_Int32 nTreeItems = m_aStructParentTree.size();
    2413           0 :         for( sal_Int32 n = 0; n < nTreeItems; n++ )
    2414             :         {
    2415           0 :             aLine.append( n );
    2416           0 :             aLine.append( ' ' );
    2417           0 :             aLine.append( m_aStructParentTree[n] );
    2418           0 :             aLine.append( "\n" );
    2419             :         }
    2420           0 :         aLine.append( "]>>\nendobj\n\n" );
    2421           0 :         CHECK_RETURN( updateObject( nObject ) );
    2422           0 :         CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
    2423             :     }
    2424           0 :     return nObject;
    2425             : }
    2426             : 
    2427           0 : const sal_Char* PDFWriterImpl::getAttributeTag( PDFWriter::StructAttribute eAttr )
    2428             : {
    2429           0 :     static std::map< PDFWriter::StructAttribute, const char* > aAttributeStrings;
    2430             :     // fill maps once
    2431           0 :     if( aAttributeStrings.empty() )
    2432             :     {
    2433           0 :         aAttributeStrings[ PDFWriter::Placement ]           = "Placement";
    2434           0 :         aAttributeStrings[ PDFWriter::WritingMode ]         = "WritingMode";
    2435           0 :         aAttributeStrings[ PDFWriter::SpaceBefore ]         = "SpaceBefore";
    2436           0 :         aAttributeStrings[ PDFWriter::SpaceAfter ]          = "SpaceAfter";
    2437           0 :         aAttributeStrings[ PDFWriter::StartIndent ]         = "StartIndent";
    2438           0 :         aAttributeStrings[ PDFWriter::EndIndent ]           = "EndIndent";
    2439           0 :         aAttributeStrings[ PDFWriter::TextIndent ]          = "TextIndent";
    2440           0 :         aAttributeStrings[ PDFWriter::TextAlign ]           = "TextAlign";
    2441           0 :         aAttributeStrings[ PDFWriter::Width ]               = "Width";
    2442           0 :         aAttributeStrings[ PDFWriter::Height ]              = "Height";
    2443           0 :         aAttributeStrings[ PDFWriter::BlockAlign ]          = "BlockAlign";
    2444           0 :         aAttributeStrings[ PDFWriter::InlineAlign ]         = "InlineAlign";
    2445           0 :         aAttributeStrings[ PDFWriter::LineHeight ]          = "LineHeight";
    2446           0 :         aAttributeStrings[ PDFWriter::BaselineShift ]       = "BaselineShift";
    2447           0 :         aAttributeStrings[ PDFWriter::TextDecorationType ]  = "TextDecorationType";
    2448           0 :         aAttributeStrings[ PDFWriter::ListNumbering ]       = "ListNumbering";
    2449           0 :         aAttributeStrings[ PDFWriter::RowSpan ]             = "RowSpan";
    2450           0 :         aAttributeStrings[ PDFWriter::ColSpan ]             = "ColSpan";
    2451           0 :         aAttributeStrings[ PDFWriter::LinkAnnotation ]      = "LinkAnnotation";
    2452             :     }
    2453             : 
    2454             :     std::map< PDFWriter::StructAttribute, const char* >::const_iterator it =
    2455           0 :         aAttributeStrings.find( eAttr );
    2456             : 
    2457             : #if OSL_DEBUG_LEVEL > 1
    2458             :     if( it == aAttributeStrings.end() )
    2459             :         fprintf( stderr, "invalid PDFWriter::StructAttribute %d\n", eAttr );
    2460             : #endif
    2461             : 
    2462           0 :     return it != aAttributeStrings.end() ? it->second : "";
    2463             : }
    2464             : 
    2465           0 : const sal_Char* PDFWriterImpl::getAttributeValueTag( PDFWriter::StructAttributeValue eVal )
    2466             : {
    2467           0 :     static std::map< PDFWriter::StructAttributeValue, const char* > aValueStrings;
    2468             : 
    2469           0 :     if( aValueStrings.empty() )
    2470             :     {
    2471           0 :         aValueStrings[ PDFWriter::NONE ]                    = "None";
    2472           0 :         aValueStrings[ PDFWriter::Block ]                   = "Block";
    2473           0 :         aValueStrings[ PDFWriter::Inline ]                  = "Inline";
    2474           0 :         aValueStrings[ PDFWriter::Before ]                  = "Before";
    2475           0 :         aValueStrings[ PDFWriter::After ]                   = "After";
    2476           0 :         aValueStrings[ PDFWriter::Start ]                   = "Start";
    2477           0 :         aValueStrings[ PDFWriter::End ]                     = "End";
    2478           0 :         aValueStrings[ PDFWriter::LrTb ]                    = "LrTb";
    2479           0 :         aValueStrings[ PDFWriter::RlTb ]                    = "RlTb";
    2480           0 :         aValueStrings[ PDFWriter::TbRl ]                    = "TbRl";
    2481           0 :         aValueStrings[ PDFWriter::Center ]                  = "Center";
    2482           0 :         aValueStrings[ PDFWriter::Justify ]                 = "Justify";
    2483           0 :         aValueStrings[ PDFWriter::Auto ]                    = "Auto";
    2484           0 :         aValueStrings[ PDFWriter::Middle ]                  = "Middle";
    2485           0 :         aValueStrings[ PDFWriter::Normal ]                  = "Normal";
    2486           0 :         aValueStrings[ PDFWriter::Underline ]               = "Underline";
    2487           0 :         aValueStrings[ PDFWriter::Overline ]                = "Overline";
    2488           0 :         aValueStrings[ PDFWriter::LineThrough ]             = "LineThrough";
    2489           0 :         aValueStrings[ PDFWriter::Disc ]                    = "Disc";
    2490           0 :         aValueStrings[ PDFWriter::Circle ]                  = "Circle";
    2491           0 :         aValueStrings[ PDFWriter::Square ]                  = "Square";
    2492           0 :         aValueStrings[ PDFWriter::Decimal ]                 = "Decimal";
    2493           0 :         aValueStrings[ PDFWriter::UpperRoman ]              = "UpperRoman";
    2494           0 :         aValueStrings[ PDFWriter::LowerRoman ]              = "LowerRoman";
    2495           0 :         aValueStrings[ PDFWriter::UpperAlpha ]              = "UpperAlpha";
    2496           0 :         aValueStrings[ PDFWriter::LowerAlpha ]              = "LowerAlpha";
    2497             :     }
    2498             : 
    2499             :     std::map< PDFWriter::StructAttributeValue, const char* >::const_iterator it =
    2500           0 :         aValueStrings.find( eVal );
    2501             : 
    2502             : #if OSL_DEBUG_LEVEL > 1
    2503             :     if( it == aValueStrings.end() )
    2504             :         fprintf( stderr, "invalid PDFWriter::StructAttributeValue %d\n", eVal );
    2505             : #endif
    2506             : 
    2507           0 :     return it != aValueStrings.end() ? it->second : "";
    2508             : }
    2509             : 
    2510           0 : static void appendStructureAttributeLine( PDFWriter::StructAttribute i_eAttr, const PDFWriterImpl::PDFStructureAttribute& i_rVal, OStringBuffer& o_rLine, bool i_bIsFixedInt )
    2511             : {
    2512           0 :     o_rLine.append( "/" );
    2513           0 :     o_rLine.append( PDFWriterImpl::getAttributeTag( i_eAttr ) );
    2514             : 
    2515           0 :     if( i_rVal.eValue != PDFWriter::Invalid )
    2516             :     {
    2517           0 :         o_rLine.append( "/" );
    2518           0 :         o_rLine.append( PDFWriterImpl::getAttributeValueTag( i_rVal.eValue ) );
    2519             :     }
    2520             :     else
    2521             :     {
    2522             :         // numerical value
    2523           0 :         o_rLine.append( " " );
    2524           0 :         if( i_bIsFixedInt )
    2525           0 :             appendFixedInt( i_rVal.nValue, o_rLine );
    2526             :         else
    2527           0 :             o_rLine.append( i_rVal.nValue );
    2528             :     }
    2529           0 :     o_rLine.append( "\n" );
    2530           0 : }
    2531             : 
    2532           0 : OString PDFWriterImpl::emitStructureAttributes( PDFStructureElement& i_rEle )
    2533             : {
    2534             :     // create layout, list and table attribute sets
    2535           0 :     OStringBuffer aLayout(256), aList(64), aTable(64);
    2536           0 :     for( PDFStructAttributes::const_iterator it = i_rEle.m_aAttributes.begin();
    2537           0 :          it != i_rEle.m_aAttributes.end(); ++it )
    2538             :     {
    2539           0 :         if( it->first == PDFWriter::ListNumbering )
    2540           0 :             appendStructureAttributeLine( it->first, it->second, aList, true );
    2541           0 :         else if( it->first == PDFWriter::RowSpan ||
    2542           0 :                  it->first == PDFWriter::ColSpan )
    2543           0 :             appendStructureAttributeLine( it->first, it->second, aTable, false );
    2544           0 :         else if( it->first == PDFWriter::LinkAnnotation )
    2545             :         {
    2546           0 :             sal_Int32 nLink = it->second.nValue;
    2547             :             std::map< sal_Int32, sal_Int32 >::const_iterator link_it =
    2548           0 :                 m_aLinkPropertyMap.find( nLink );
    2549           0 :             if( link_it != m_aLinkPropertyMap.end() )
    2550           0 :                 nLink = link_it->second;
    2551           0 :             if( nLink >= 0 && nLink < (sal_Int32)m_aLinks.size() )
    2552             :             {
    2553             :                 // update struct parent of link
    2554           0 :                 OStringBuffer aStructParentEntry( 32 );
    2555           0 :                 aStructParentEntry.append( i_rEle.m_nObject );
    2556           0 :                 aStructParentEntry.append( " 0 R" );
    2557           0 :                 m_aStructParentTree.push_back( aStructParentEntry.makeStringAndClear() );
    2558           0 :                 m_aLinks[ nLink ].m_nStructParent = m_aStructParentTree.size()-1;
    2559             : 
    2560           0 :                 sal_Int32 nRefObject = createObject();
    2561           0 :                 OStringBuffer aRef( 256 );
    2562           0 :                 aRef.append( nRefObject );
    2563             :                 aRef.append( " 0 obj\n"
    2564           0 :                              "<</Type/OBJR/Obj " );
    2565           0 :                 aRef.append( m_aLinks[ nLink ].m_nObject );
    2566             :                 aRef.append( " 0 R>>\n"
    2567             :                              "endobj\n\n"
    2568           0 :                              );
    2569           0 :                 if (updateObject(nRefObject))
    2570             :                 {
    2571           0 :                     writeBuffer( aRef.getStr(), aRef.getLength() );
    2572             :                 }
    2573             : 
    2574           0 :                 i_rEle.m_aKids.push_back( PDFStructureElementKid( nRefObject ) );
    2575             :             }
    2576             :             else
    2577             :             {
    2578             :                 OSL_FAIL( "unresolved link id for Link structure" );
    2579             : #if OSL_DEBUG_LEVEL > 1
    2580             :                 fprintf( stderr, "unresolved link id %" SAL_PRIdINT32 " for Link structure\n", nLink );
    2581             :                 {
    2582             :                     OStringBuffer aLine( "unresolved link id " );
    2583             :                     aLine.append( nLink );
    2584             :                     aLine.append( " for Link structure" );
    2585             :                     emitComment( aLine.getStr() );
    2586             :                 }
    2587             : #endif
    2588             :             }
    2589             :         }
    2590             :         else
    2591           0 :             appendStructureAttributeLine( it->first, it->second, aLayout, true );
    2592             :     }
    2593           0 :     if( ! i_rEle.m_aBBox.IsEmpty() )
    2594             :     {
    2595           0 :         aLayout.append( "/BBox[" );
    2596           0 :         appendFixedInt( i_rEle.m_aBBox.Left(), aLayout );
    2597           0 :         aLayout.append( " " );
    2598           0 :         appendFixedInt( i_rEle.m_aBBox.Top(), aLayout );
    2599           0 :         aLayout.append( " " );
    2600           0 :         appendFixedInt( i_rEle.m_aBBox.Right(), aLayout );
    2601           0 :         aLayout.append( " " );
    2602           0 :         appendFixedInt( i_rEle.m_aBBox.Bottom(), aLayout );
    2603           0 :         aLayout.append( "]\n" );
    2604             :     }
    2605             : 
    2606           0 :     std::vector< sal_Int32 > aAttribObjects;
    2607           0 :     if( !aLayout.isEmpty() )
    2608             :     {
    2609           0 :         aAttribObjects.push_back( createObject() );
    2610           0 :         if (updateObject( aAttribObjects.back() ))
    2611             :         {
    2612           0 :             OStringBuffer aObj( 64 );
    2613           0 :             aObj.append( aAttribObjects.back() );
    2614             :             aObj.append( " 0 obj\n"
    2615           0 :                          "<</O/Layout\n" );
    2616           0 :             aLayout.append( ">>\nendobj\n\n" );
    2617           0 :             writeBuffer( aObj.getStr(), aObj.getLength() );
    2618           0 :             writeBuffer( aLayout.getStr(), aLayout.getLength() );
    2619             :         }
    2620             :     }
    2621           0 :     if( !aList.isEmpty() )
    2622             :     {
    2623           0 :         aAttribObjects.push_back( createObject() );
    2624           0 :         if (updateObject( aAttribObjects.back() ))
    2625             :         {
    2626           0 :             OStringBuffer aObj( 64 );
    2627           0 :             aObj.append( aAttribObjects.back() );
    2628             :             aObj.append( " 0 obj\n"
    2629           0 :                          "<</O/List\n" );
    2630           0 :             aList.append( ">>\nendobj\n\n" );
    2631           0 :             writeBuffer( aObj.getStr(), aObj.getLength() );
    2632           0 :             writeBuffer( aList.getStr(), aList.getLength() );
    2633             :         }
    2634             :     }
    2635           0 :     if( !aTable.isEmpty() )
    2636             :     {
    2637           0 :         aAttribObjects.push_back( createObject() );
    2638           0 :         if (updateObject( aAttribObjects.back() ))
    2639             :         {
    2640           0 :             OStringBuffer aObj( 64 );
    2641           0 :             aObj.append( aAttribObjects.back() );
    2642             :             aObj.append( " 0 obj\n"
    2643           0 :                          "<</O/Table\n" );
    2644           0 :             aTable.append( ">>\nendobj\n\n" );
    2645           0 :             writeBuffer( aObj.getStr(), aObj.getLength() );
    2646           0 :             writeBuffer( aTable.getStr(), aTable.getLength() );
    2647             :         }
    2648             :     }
    2649             : 
    2650           0 :     OStringBuffer aRet( 64 );
    2651           0 :     if( aAttribObjects.size() > 1 )
    2652           0 :         aRet.append( " [" );
    2653           0 :     for( std::vector< sal_Int32 >::const_iterator at_it = aAttribObjects.begin();
    2654           0 :          at_it != aAttribObjects.end(); ++at_it )
    2655             :     {
    2656           0 :         aRet.append( " " );
    2657           0 :         aRet.append( *at_it );
    2658           0 :         aRet.append( " 0 R" );
    2659             :     }
    2660           0 :     if( aAttribObjects.size() > 1 )
    2661           0 :         aRet.append( " ]" );
    2662           0 :     return aRet.makeStringAndClear();
    2663             : }
    2664             : 
    2665           0 : sal_Int32 PDFWriterImpl::emitStructure( PDFStructureElement& rEle )
    2666             : {
    2667           0 :     if(
    2668             :        // do not emit NonStruct and its children
    2669           0 :        rEle.m_eType == PDFWriter::NonStructElement &&
    2670           0 :        rEle.m_nOwnElement != rEle.m_nParentElement // but of course emit the struct tree root
    2671             :        )
    2672           0 :         return 0;
    2673             : 
    2674           0 :     for( std::list< sal_Int32 >::const_iterator it = rEle.m_aChildren.begin(); it != rEle.m_aChildren.end(); ++it )
    2675             :     {
    2676           0 :         if( *it > 0 && *it < sal_Int32(m_aStructure.size()) )
    2677             :         {
    2678           0 :             PDFStructureElement& rChild = m_aStructure[ *it ];
    2679           0 :             if( rChild.m_eType != PDFWriter::NonStructElement )
    2680             :             {
    2681           0 :                 if( rChild.m_nParentElement == rEle.m_nOwnElement )
    2682           0 :                     emitStructure( rChild );
    2683             :                 else
    2684             :                 {
    2685             :                     OSL_FAIL( "PDFWriterImpl::emitStructure: invalid child structure element" );
    2686             : #if OSL_DEBUG_LEVEL > 1
    2687             :                     fprintf( stderr, "PDFWriterImpl::emitStructure: invalid child structure elemnt with id %" SAL_PRIdINT32 "\n", *it );
    2688             : #endif
    2689             :                 }
    2690             :             }
    2691             :         }
    2692             :         else
    2693             :         {
    2694             :             OSL_FAIL( "PDFWriterImpl::emitStructure: invalid child structure id" );
    2695             : #if OSL_DEBUG_LEVEL > 1
    2696             :             fprintf( stderr, "PDFWriterImpl::emitStructure: invalid child structure id %" SAL_PRIdINT32 "\n", *it );
    2697             : #endif
    2698             :         }
    2699             :     }
    2700             : 
    2701           0 :     OStringBuffer aLine( 512 );
    2702           0 :     aLine.append( rEle.m_nObject );
    2703             :     aLine.append( " 0 obj\n"
    2704           0 :                   "<</Type" );
    2705           0 :     sal_Int32 nParentTree = -1;
    2706           0 :     if( rEle.m_nOwnElement == rEle.m_nParentElement )
    2707             :     {
    2708           0 :         nParentTree = createObject();
    2709           0 :         CHECK_RETURN( nParentTree );
    2710           0 :         aLine.append( "/StructTreeRoot\n" );
    2711           0 :         aLine.append( "/ParentTree " );
    2712           0 :         aLine.append( nParentTree );
    2713           0 :         aLine.append( " 0 R\n" );
    2714           0 :         if( ! m_aRoleMap.empty() )
    2715             :         {
    2716           0 :             aLine.append( "/RoleMap<<" );
    2717           0 :             for( std::unordered_map<OString,OString,OStringHash>::const_iterator
    2718           0 :                  it = m_aRoleMap.begin(); it != m_aRoleMap.end(); ++it )
    2719             :             {
    2720           0 :                 aLine.append( '/' );
    2721           0 :                 aLine.append(it->first);
    2722           0 :                 aLine.append( '/' );
    2723           0 :                 aLine.append( it->second );
    2724           0 :                 aLine.append( '\n' );
    2725             :             }
    2726           0 :             aLine.append( ">>\n" );
    2727             :         }
    2728             :     }
    2729             :     else
    2730             :     {
    2731             :         aLine.append( "/StructElem\n"
    2732           0 :                       "/S/" );
    2733           0 :         if( !rEle.m_aAlias.isEmpty() )
    2734           0 :             aLine.append( rEle.m_aAlias );
    2735             :         else
    2736           0 :             aLine.append( getStructureTag( rEle.m_eType ) );
    2737             :         aLine.append( "\n"
    2738           0 :                       "/P " );
    2739           0 :         aLine.append( m_aStructure[ rEle.m_nParentElement ].m_nObject );
    2740             :         aLine.append( " 0 R\n"
    2741           0 :                       "/Pg " );
    2742           0 :         aLine.append( rEle.m_nFirstPageObject );
    2743           0 :         aLine.append( " 0 R\n" );
    2744           0 :         if( !rEle.m_aActualText.isEmpty() )
    2745             :         {
    2746           0 :             aLine.append( "/ActualText" );
    2747           0 :             appendUnicodeTextStringEncrypt( rEle.m_aActualText, rEle.m_nObject, aLine );
    2748           0 :             aLine.append( "\n" );
    2749             :         }
    2750           0 :         if( !rEle.m_aAltText.isEmpty() )
    2751             :         {
    2752           0 :             aLine.append( "/Alt" );
    2753           0 :             appendUnicodeTextStringEncrypt( rEle.m_aAltText, rEle.m_nObject, aLine );
    2754           0 :             aLine.append( "\n" );
    2755             :         }
    2756             :     }
    2757           0 :     if( (! rEle.m_aBBox.IsEmpty()) || (! rEle.m_aAttributes.empty()) )
    2758             :     {
    2759           0 :         OString aAttribs =  emitStructureAttributes( rEle );
    2760           0 :         if( !aAttribs.isEmpty() )
    2761             :         {
    2762           0 :             aLine.append( "/A" );
    2763           0 :             aLine.append( aAttribs );
    2764           0 :             aLine.append( "\n" );
    2765           0 :         }
    2766             :     }
    2767           0 :     if( !rEle.m_aLocale.Language.isEmpty() )
    2768             :     {
    2769             :         /* PDF allows only RFC 3066, which is only partly BCP 47 and does not
    2770             :          * include script tags and others.
    2771             :          * http://pdf.editme.com/pdfua-naturalLanguageSpecification
    2772             :          * http://partners.adobe.com/public/developer/en/pdf/PDFReference16.pdf#page=886
    2773             :          * https://www.adobe.com/content/dam/Adobe/en/devnet/pdf/pdfs/PDF32000_2008.pdf#M13.9.19332.1Heading.97.Natural.Language.Specification
    2774             :          * */
    2775           0 :         LanguageTag aLanguageTag( rEle.m_aLocale);
    2776           0 :         OUString aLanguage, aScript, aCountry;
    2777           0 :         aLanguageTag.getIsoLanguageScriptCountry( aLanguage, aScript, aCountry);
    2778           0 :         if (!aLanguage.isEmpty())
    2779             :         {
    2780           0 :             OUStringBuffer aLocBuf( 16 );
    2781           0 :             aLocBuf.append( aLanguage );
    2782           0 :             if( !aCountry.isEmpty() )
    2783             :             {
    2784           0 :                 aLocBuf.append( '-' );
    2785           0 :                 aLocBuf.append( aCountry );
    2786             :             }
    2787           0 :             aLine.append( "/Lang" );
    2788           0 :             appendLiteralStringEncrypt( aLocBuf.makeStringAndClear(), rEle.m_nObject, aLine );
    2789           0 :             aLine.append( "\n" );
    2790           0 :         }
    2791             :     }
    2792           0 :     if( ! rEle.m_aKids.empty() )
    2793             :     {
    2794           0 :         unsigned int i = 0;
    2795           0 :         aLine.append( "/K[" );
    2796           0 :         for( std::list< PDFStructureElementKid >::const_iterator it =
    2797           0 :                  rEle.m_aKids.begin(); it != rEle.m_aKids.end(); ++it, i++ )
    2798             :         {
    2799           0 :             if( it->nMCID == -1 )
    2800             :             {
    2801           0 :                 aLine.append( it->nObject );
    2802           0 :                 aLine.append( " 0 R" );
    2803           0 :                 aLine.append( ( (i & 15) == 15 ) ? "\n" : " " );
    2804             :             }
    2805             :             else
    2806             :             {
    2807           0 :                 if( it->nObject == rEle.m_nFirstPageObject )
    2808             :                 {
    2809           0 :                     aLine.append( it->nMCID );
    2810           0 :                     aLine.append( " " );
    2811             :                 }
    2812             :                 else
    2813             :                 {
    2814           0 :                     aLine.append( "<</Type/MCR/Pg " );
    2815           0 :                     aLine.append( it->nObject );
    2816           0 :                     aLine.append( " 0 R /MCID " );
    2817           0 :                     aLine.append( it->nMCID );
    2818           0 :                     aLine.append( ">>\n" );
    2819             :                 }
    2820             :             }
    2821             :         }
    2822           0 :         aLine.append( "]\n" );
    2823             :     }
    2824           0 :     aLine.append( ">>\nendobj\n\n" );
    2825             : 
    2826           0 :     CHECK_RETURN( updateObject( rEle.m_nObject ) );
    2827           0 :     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
    2828             : 
    2829           0 :     CHECK_RETURN( emitStructParentTree( nParentTree ) );
    2830             : 
    2831           0 :     return rEle.m_nObject;
    2832             : }
    2833             : 
    2834           0 : bool PDFWriterImpl::emitGradients()
    2835             : {
    2836           0 :     for( std::list<GradientEmit>::iterator it = m_aGradients.begin();
    2837           0 :          it != m_aGradients.end(); ++it )
    2838             :     {
    2839           0 :         if ( !writeGradientFunction( *it ) ) return false;
    2840             :     }
    2841           0 :     return true;
    2842             : }
    2843             : 
    2844           0 : bool PDFWriterImpl::emitTilings()
    2845             : {
    2846           0 :     OStringBuffer aTilingObj( 1024 );
    2847             : 
    2848           0 :     for( std::vector<TilingEmit>::iterator it = m_aTilings.begin(); it != m_aTilings.end(); ++it )
    2849             :     {
    2850             :         DBG_ASSERT( it->m_pTilingStream, "tiling without stream" );
    2851           0 :         if( ! it->m_pTilingStream )
    2852           0 :             continue;
    2853             : 
    2854           0 :         aTilingObj.setLength( 0 );
    2855             : 
    2856             :         #if OSL_DEBUG_LEVEL > 1
    2857             :         emitComment( "PDFWriterImpl::emitTilings" );
    2858             :         #endif
    2859             : 
    2860           0 :         sal_Int32 nX = (sal_Int32)it->m_aRectangle.Left();
    2861           0 :         sal_Int32 nY = (sal_Int32)it->m_aRectangle.Top();
    2862           0 :         sal_Int32 nW = (sal_Int32)it->m_aRectangle.GetWidth();
    2863           0 :         sal_Int32 nH = (sal_Int32)it->m_aRectangle.GetHeight();
    2864           0 :         if( it->m_aCellSize.Width() == 0 )
    2865           0 :             it->m_aCellSize.Width() = nW;
    2866           0 :         if( it->m_aCellSize.Height() == 0 )
    2867           0 :             it->m_aCellSize.Height() = nH;
    2868             : 
    2869           0 :         bool bDeflate = compressStream( it->m_pTilingStream );
    2870           0 :         it->m_pTilingStream->Seek( STREAM_SEEK_TO_END );
    2871           0 :         sal_Size nTilingStreamSize = it->m_pTilingStream->Tell();
    2872           0 :         it->m_pTilingStream->Seek( STREAM_SEEK_TO_BEGIN );
    2873             : 
    2874             :         // write pattern object
    2875           0 :         aTilingObj.append( it->m_nObject );
    2876           0 :         aTilingObj.append( " 0 obj\n" );
    2877             :         aTilingObj.append( "<</Type/Pattern/PatternType 1\n"
    2878             :                            "/PaintType 1\n"
    2879             :                            "/TilingType 2\n"
    2880           0 :                            "/BBox[" );
    2881           0 :         appendFixedInt( nX, aTilingObj );
    2882           0 :         aTilingObj.append( ' ' );
    2883           0 :         appendFixedInt( nY, aTilingObj );
    2884           0 :         aTilingObj.append( ' ' );
    2885           0 :         appendFixedInt( nX+nW, aTilingObj );
    2886           0 :         aTilingObj.append( ' ' );
    2887           0 :         appendFixedInt( nY+nH, aTilingObj );
    2888             :         aTilingObj.append( "]\n"
    2889           0 :                            "/XStep " );
    2890           0 :         appendFixedInt( it->m_aCellSize.Width(), aTilingObj );
    2891             :         aTilingObj.append( "\n"
    2892           0 :                            "/YStep " );
    2893           0 :         appendFixedInt( it->m_aCellSize.Height(), aTilingObj );
    2894           0 :         aTilingObj.append( "\n" );
    2895           0 :         if( it->m_aTransform.matrix[0] != 1.0 ||
    2896           0 :             it->m_aTransform.matrix[1] != 0.0 ||
    2897           0 :             it->m_aTransform.matrix[3] != 0.0 ||
    2898           0 :             it->m_aTransform.matrix[4] != 1.0 ||
    2899           0 :             it->m_aTransform.matrix[2] != 0.0 ||
    2900           0 :             it->m_aTransform.matrix[5] != 0.0 )
    2901             :         {
    2902           0 :             aTilingObj.append( "/Matrix [" );
    2903             :             // TODO: scaling, mirroring on y, etc
    2904           0 :             appendDouble( it->m_aTransform.matrix[0], aTilingObj );
    2905           0 :             aTilingObj.append( ' ' );
    2906           0 :             appendDouble( it->m_aTransform.matrix[1], aTilingObj );
    2907           0 :             aTilingObj.append( ' ' );
    2908           0 :             appendDouble( it->m_aTransform.matrix[3], aTilingObj );
    2909           0 :             aTilingObj.append( ' ' );
    2910           0 :             appendDouble( it->m_aTransform.matrix[4], aTilingObj );
    2911           0 :             aTilingObj.append( ' ' );
    2912           0 :             appendDouble( it->m_aTransform.matrix[2], aTilingObj );
    2913           0 :             aTilingObj.append( ' ' );
    2914           0 :             appendDouble( it->m_aTransform.matrix[5], aTilingObj );
    2915           0 :             aTilingObj.append( "]\n" );
    2916             :         }
    2917           0 :         aTilingObj.append( "/Resources" );
    2918           0 :         it->m_aResources.append( aTilingObj, getFontDictObject() );
    2919           0 :         if( bDeflate )
    2920           0 :             aTilingObj.append( "/Filter/FlateDecode" );
    2921           0 :         aTilingObj.append( "/Length " );
    2922           0 :         aTilingObj.append( (sal_Int32)nTilingStreamSize );
    2923           0 :         aTilingObj.append( ">>\nstream\n" );
    2924           0 :         if ( !updateObject( it->m_nObject ) ) return false;
    2925           0 :         if ( !writeBuffer( aTilingObj.getStr(), aTilingObj.getLength() ) ) return false;
    2926           0 :         checkAndEnableStreamEncryption( it->m_nObject );
    2927           0 :         bool written = writeBuffer( it->m_pTilingStream->GetData(), nTilingStreamSize );
    2928           0 :         delete it->m_pTilingStream;
    2929           0 :         it->m_pTilingStream = NULL;
    2930           0 :         if( !written )
    2931           0 :             return false;
    2932           0 :         disableStreamEncryption();
    2933           0 :         aTilingObj.setLength( 0 );
    2934           0 :         aTilingObj.append( "\nendstream\nendobj\n\n" );
    2935           0 :         if ( !writeBuffer( aTilingObj.getStr(), aTilingObj.getLength() ) ) return false;
    2936             :     }
    2937           0 :     return true;
    2938             : }
    2939             : 
    2940           0 : sal_Int32 PDFWriterImpl::emitBuiltinFont( const PhysicalFontFace* pFont, sal_Int32 nFontObject )
    2941             : {
    2942           0 :     const ImplPdfBuiltinFontData* pFD = GetPdfFontData( pFont );
    2943           0 :     if( !pFD )
    2944           0 :         return 0;
    2945           0 :     const BuiltinFont& rBuiltinFont = pFD->GetBuiltinFont();
    2946             : 
    2947           0 :     OStringBuffer aLine( 1024 );
    2948             : 
    2949           0 :     if( nFontObject <= 0 )
    2950           0 :         nFontObject = createObject();
    2951           0 :     CHECK_RETURN( updateObject( nFontObject ) );
    2952           0 :     aLine.append( nFontObject );
    2953             :     aLine.append( " 0 obj\n"
    2954           0 :                   "<</Type/Font/Subtype/Type1/BaseFont/" );
    2955           0 :     appendName( rBuiltinFont.m_pPSName, aLine );
    2956           0 :     aLine.append( "\n" );
    2957           0 :     if( rBuiltinFont.m_eCharSet == RTL_TEXTENCODING_MS_1252 )
    2958           0 :          aLine.append( "/Encoding/WinAnsiEncoding\n" );
    2959           0 :     aLine.append( ">>\nendobj\n\n" );
    2960           0 :     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
    2961           0 :     return nFontObject;
    2962             : }
    2963             : 
    2964           0 : std::map< sal_Int32, sal_Int32 > PDFWriterImpl::emitSystemFont( const PhysicalFontFace* pFont, EmbedFont& rEmbed )
    2965             : {
    2966           0 :     std::map< sal_Int32, sal_Int32 > aRet;
    2967             : 
    2968           0 :     sal_Int32 nFontDescriptor = 0;
    2969           0 :     OString aSubType( "/Type1" );
    2970           0 :     FontSubsetInfo aInfo;
    2971             :     // fill in dummy values
    2972           0 :     aInfo.m_nAscent = 1000;
    2973           0 :     aInfo.m_nDescent = 200;
    2974           0 :     aInfo.m_nCapHeight = 1000;
    2975           0 :     aInfo.m_aFontBBox = Rectangle( Point( -200, -200 ), Size( 1700, 1700 ) );
    2976           0 :     aInfo.m_aPSName = pFont->GetFamilyName();
    2977             :     sal_Int32 pWidths[256];
    2978           0 :     memset( pWidths, 0, sizeof(pWidths) );
    2979             : 
    2980           0 :     SalGraphics *pGraphics = m_pReferenceDevice->GetGraphics();
    2981             : 
    2982             :     assert(pGraphics);
    2983             : 
    2984           0 :     if( pFont->IsEmbeddable() )
    2985             :     {
    2986           0 :         const unsigned char* pFontData = NULL;
    2987           0 :         long nFontLen = 0;
    2988             :         sal_Ucs nEncodedCodes[256];
    2989             :         sal_Int32 pEncWidths[256];
    2990             : 
    2991             :         //TODO: surely this is utterly broken because GetEmbedFontData loops over the uninitialized nEncodedCodes as input
    2992           0 :         pFontData = static_cast<const unsigned char*>(pGraphics->GetEmbedFontData( pFont, nEncodedCodes, pEncWidths, 256, aInfo, &nFontLen ));
    2993             : 
    2994           0 :         if( pFontData )
    2995             :         {
    2996           0 :             pGraphics->FreeEmbedFontData( pFontData, nFontLen );
    2997           0 :             for( int i = 0; i < 256; i++ )
    2998             :             {
    2999           0 :                 if( nEncodedCodes[i] >= 32 && nEncodedCodes[i] < 256 )
    3000             :                 {
    3001           0 :                     pWidths[i] = pEncWidths[ i ];
    3002             :                 }
    3003             :             }
    3004             :         }
    3005             :     }
    3006           0 :     else if( pFont->mbSubsettable )
    3007             :     {
    3008           0 :         aSubType = OString( "/TrueType" );
    3009           0 :         Int32Vector aGlyphWidths;
    3010           0 :         Ucs2UIntMap aUnicodeMap;
    3011           0 :         pGraphics->GetGlyphWidths( pFont, false, aGlyphWidths, aUnicodeMap );
    3012             : 
    3013           0 :         OUString aTmpName;
    3014           0 :         osl_createTempFile( NULL, NULL, &aTmpName.pData );
    3015             :         sal_GlyphId aGlyphIds[ 256 ];
    3016             :         sal_uInt8 pEncoding[ 256 ];
    3017             :         sal_Int32 pDuWidths[ 256 ];
    3018             : 
    3019           0 :         memset( aGlyphIds, 0, sizeof( aGlyphIds ) );
    3020           0 :         memset( pEncoding, 0, sizeof( pEncoding ) );
    3021           0 :         memset( pDuWidths, 0, sizeof( pDuWidths ) );
    3022             : 
    3023           0 :         for( sal_Ucs c = 32; c < 256; c++ )
    3024             :         {
    3025           0 :             pEncoding[c] = c;
    3026           0 :             aGlyphIds[c] = 0;
    3027           0 :             if( aUnicodeMap.find( c ) != aUnicodeMap.end() )
    3028           0 :                 pWidths[ c ] = aGlyphWidths[ aUnicodeMap[ c ] ];
    3029             :         }
    3030             :         //TODO: surely this is utterly broken because aGlyphIds is just all zeros, if we
    3031             :         //had the right glyphids here then I imagine we could replace pDuWidths with
    3032             :         //pWidths and remove pWidths assignment above. i.e. start with the glyph ids
    3033             :         //and map those to unicode rather than try and reverse map them ?
    3034           0 :         pGraphics->CreateFontSubset( aTmpName, pFont, aGlyphIds, pEncoding, pDuWidths, 256, aInfo );
    3035           0 :         osl_removeFile( aTmpName.pData );
    3036             :     }
    3037             :     else
    3038             :     {
    3039             :         OSL_FAIL( "system font neither embeddable nor subsettable" );
    3040             :     }
    3041             : 
    3042             :     // write font descriptor
    3043           0 :     nFontDescriptor = emitFontDescriptor( pFont, aInfo, 0, 0 );
    3044           0 :     if( nFontDescriptor )
    3045             :     {
    3046             :         // write font object
    3047           0 :         sal_Int32 nObject = createObject();
    3048           0 :         if( updateObject( nObject ) )
    3049             :         {
    3050           0 :             OStringBuffer aLine( 1024 );
    3051           0 :             aLine.append( nObject );
    3052             :             aLine.append( " 0 obj\n"
    3053           0 :                           "<</Type/Font/Subtype" );
    3054           0 :             aLine.append( aSubType );
    3055           0 :             aLine.append( "/BaseFont/" );
    3056           0 :             appendName( aInfo.m_aPSName, aLine );
    3057           0 :             aLine.append( "\n" );
    3058           0 :             if( !pFont->IsSymbolFont() )
    3059           0 :                 aLine.append( "/Encoding/WinAnsiEncoding\n" );
    3060             :             aLine.append( "/FirstChar 32 /LastChar 255\n"
    3061           0 :                           "/Widths[" );
    3062           0 :             for( int i = 32; i < 256; i++ )
    3063             :             {
    3064           0 :                 aLine.append( pWidths[i] );
    3065           0 :                 aLine.append( ((i&15) == 15) ? "\n" : " " );
    3066             :             }
    3067             :             aLine.append( "]\n"
    3068           0 :                           "/FontDescriptor " );
    3069           0 :             aLine.append( nFontDescriptor );
    3070             :             aLine.append( " 0 R>>\n"
    3071           0 :                           "endobj\n\n" );
    3072           0 :             writeBuffer( aLine.getStr(), aLine.getLength() );
    3073             : 
    3074           0 :             aRet[ rEmbed.m_nNormalFontID ] = nObject;
    3075             :         }
    3076             :     }
    3077             : 
    3078           0 :     return aRet;
    3079             : }
    3080             : 
    3081             : typedef int ThreeInts[3];
    3082           0 : static bool getPfbSegmentLengths( const unsigned char* pFontBytes, int nByteLen,
    3083             :     ThreeInts& rSegmentLengths )
    3084             : {
    3085           0 :     if( !pFontBytes || (nByteLen < 0) )
    3086           0 :         return false;
    3087           0 :     const unsigned char* pPtr = pFontBytes;
    3088           0 :     const unsigned char* pEnd = pFontBytes + nByteLen;
    3089             : 
    3090           0 :     for( int i = 0; i < 3; ++i) {
    3091             :         // read segment1 header
    3092           0 :         if( pPtr+6 >= pEnd )
    3093           0 :             return false;
    3094           0 :         if( (pPtr[0] != 0x80) || (pPtr[1] >= 0x03) )
    3095           0 :             return false;
    3096           0 :         const int nLen = (pPtr[5]<<24) + (pPtr[4]<<16) + (pPtr[3]<<8) + pPtr[2];
    3097           0 :         if( nLen <= 0)
    3098           0 :             return false;
    3099           0 :         rSegmentLengths[i] = nLen;
    3100           0 :         pPtr += nLen + 6;
    3101             :     }
    3102             : 
    3103             :     // read segment-end header
    3104           0 :     if( pPtr+2 >= pEnd )
    3105           0 :         return false;
    3106           0 :     if( (pPtr[0] != 0x80) || (pPtr[1] != 0x03) )
    3107           0 :         return false;
    3108             : 
    3109           0 :     return true;
    3110             : }
    3111             : 
    3112           0 : struct FontException : public std::exception
    3113             : {
    3114             : };
    3115             : 
    3116             : // TODO: always subset instead of embedding the full font => this method becomes obsolete then
    3117           0 : std::map< sal_Int32, sal_Int32 > PDFWriterImpl::emitEmbeddedFont( const PhysicalFontFace* pFont, EmbedFont& rEmbed )
    3118             : {
    3119           0 :     std::map< sal_Int32, sal_Int32 > aRet;
    3120             : 
    3121           0 :     sal_Int32 nStreamObject = 0;
    3122           0 :     sal_Int32 nFontDescriptor = 0;
    3123             : 
    3124           0 :     SalGraphics *pGraphics = m_pReferenceDevice->GetGraphics();
    3125             : 
    3126             :     assert(pGraphics);
    3127             : 
    3128             :     // prepare font encoding
    3129           0 :     std::set<sal_Unicode> const * pPriority(0);
    3130             :     const Ucs2SIntMap *const pEncoding =
    3131           0 :         pGraphics->GetFontEncodingVector( pFont, nullptr, &pPriority );
    3132           0 :     sal_Int32 nToUnicodeStream = 0;
    3133             :     sal_uInt8 nEncoding[256];
    3134             :     sal_Ucs nEncodedCodes[256];
    3135           0 :     std::vector<sal_Ucs> aUnicodes;
    3136           0 :     aUnicodes.reserve( 256 );
    3137             :     sal_Int32 pUnicodesPerGlyph[256];
    3138             :     sal_Int32 pEncToUnicodeIndex[256];
    3139           0 :     if( pEncoding )
    3140             :     {
    3141           0 :         memset( nEncoding, 0, sizeof(nEncoding) );
    3142           0 :         memset( nEncodedCodes, 0, sizeof(nEncodedCodes) );
    3143           0 :         memset( pUnicodesPerGlyph, 0, sizeof(pUnicodesPerGlyph) );
    3144           0 :         memset( pEncToUnicodeIndex, 0, sizeof(pEncToUnicodeIndex) );
    3145           0 :         for( Ucs2SIntMap::const_iterator it = pEncoding->begin(); it != pEncoding->end(); ++it )
    3146             :         {
    3147           0 :             if(it->second == -1)
    3148           0 :                 continue;
    3149           0 :             sal_Int32 nCode = (sal_Int32)(it->second & 0x000000ff);
    3150             :             SAL_WARN_IF(nCode != it->second, "vcl.gdi", "emitEmbeddedFont: FIXME: cannot handle Type 1 font with code points > 256");
    3151             :             //We're not doing this right here. We have taken a unicode-to-font_index map
    3152             :             //and are trying to generate a font_index-to-unicode mapping from it
    3153             :             //Which assumes that there is a 1-to-1 mapping there, but that might not be
    3154             :             //true.
    3155             :             //
    3156             :             //Instead perhaps we could try and get the GetFontCharMap and loop
    3157             :             //over sal_UCS4 GetCharFromIndex( int nCharIndex ) const from 0 to 255
    3158             :             //to build it up
    3159           0 :             if (nEncoding[nCode] != 0)
    3160             :             {
    3161             :                 // should not have 2 identical mappings
    3162             :                 assert(nEncodedCodes[nCode] != it->first);
    3163           0 :                 if (pPriority)
    3164             :                 {
    3165           0 :                     bool bExist = pPriority->find(nEncodedCodes[nCode]) != pPriority->end();
    3166           0 :                     bool bIter  = pPriority->find(it->first) != pPriority->end();
    3167             :                     SAL_WARN_IF(bExist && bIter, "vcl.gdi", "both are preferred? odd...");
    3168           0 :                     if (bExist)
    3169             :                     {
    3170           0 :                         continue;
    3171             :                     }
    3172             :                     // note: aUnicodes will contain the old one but that
    3173             :                     // does not matter because there's nothing iterating it
    3174             :                 }
    3175             :                 else
    3176             :                 {
    3177             :                     // is this fallback important? let's prefer lower one.
    3178             :                     // actually the map is sorted so just rely on that
    3179             :                     assert(nEncodedCodes[nCode] < it->first);
    3180             :                     SAL_WARN("vcl.gdi", "emitEmbeddedFont: ignoring code " << nCode << " mapping to " << it->first << " in favor of " << nEncodedCodes[nCode]);
    3181           0 :                     continue;
    3182             :                 }
    3183             :             }
    3184           0 :             nEncodedCodes[ nCode ] = it->first;
    3185           0 :             nEncoding[ nCode ] = static_cast<sal_uInt8>( nCode );
    3186           0 :             pEncToUnicodeIndex[ nCode ] = static_cast<sal_Int32>(aUnicodes.size());
    3187           0 :             aUnicodes.push_back( it->first );
    3188           0 :             pUnicodesPerGlyph[ nCode ] = 1;
    3189             :         }
    3190             :     }
    3191             : 
    3192           0 :     FontSubsetInfo aInfo;
    3193             :     sal_Int32 pWidths[256];
    3194           0 :     const unsigned char* pFontData = NULL;
    3195           0 :     long nFontLen = 0;
    3196             :     sal_Int32 nLength1, nLength2;
    3197             :     try
    3198             :     {
    3199           0 :         if( (pFontData = static_cast<const unsigned char*>(pGraphics->GetEmbedFontData(pFont, nEncodedCodes, pWidths, 256, aInfo, &nFontLen))) != NULL )
    3200             :         {
    3201           0 :             if( (aInfo.m_nFontType & FontSubsetInfo::ANY_TYPE1) == 0 )
    3202           0 :                 throw FontException();
    3203             :             // see whether it is pfb or pfa; if it is a pfb, fill ranges
    3204             :             // of 6 bytes that are not part of the font program
    3205           0 :             std::list< int > aSections;
    3206           0 :             std::list< int >::const_iterator it;
    3207           0 :             int nIndex = 0;
    3208           0 :             while( (nIndex < nFontLen-1) && pFontData[nIndex] == 0x80 )
    3209             :             {
    3210           0 :                 aSections.push_back( nIndex );
    3211           0 :                 if( pFontData[nIndex+1] == 0x03 )
    3212           0 :                     break;
    3213             :                 sal_Int32 nBytes =
    3214           0 :                 ((sal_Int32)pFontData[nIndex+2])            |
    3215           0 :                 ((sal_Int32)pFontData[nIndex+3]) << 8       |
    3216           0 :                 ((sal_Int32)pFontData[nIndex+4]) << 16      |
    3217           0 :                 ((sal_Int32)pFontData[nIndex+5]) << 24;
    3218           0 :                 nIndex += nBytes+6;
    3219             :             }
    3220             : 
    3221             :             // search for eexec
    3222             :             // TODO: use getPfbSegmentLengths() if possible to skip the search thingies below
    3223           0 :             nIndex = 0;
    3224             :             int nEndAsciiIndex;
    3225             :             int nBeginBinaryIndex;
    3226             :             int nEndBinaryIndex;
    3227           0 :             do
    3228             :             {
    3229           0 :                 while( nIndex < nFontLen-4 &&
    3230           0 :                     ( pFontData[nIndex] != 'e'  ||
    3231           0 :                         pFontData[nIndex+1] != 'e' ||
    3232           0 :                         pFontData[nIndex+2] != 'x' ||
    3233           0 :                         pFontData[nIndex+3] != 'e' ||
    3234           0 :                         pFontData[nIndex+4] != 'c'
    3235             :                         )
    3236             :                     )
    3237             :                 {
    3238           0 :                     ++nIndex;
    3239             :                 }
    3240             :                 // check whether we are in a excluded section
    3241           0 :                 for( it = aSections.begin(); it != aSections.end() && (nIndex < *it || nIndex > ((*it) + 5) ); ++it )
    3242             :                     ;
    3243           0 :             } while( it != aSections.end() && nIndex < nFontLen-4 );
    3244             :             // this should end the ascii part
    3245           0 :             if( nIndex > nFontLen-5 )
    3246           0 :                 throw FontException();
    3247             : 
    3248           0 :             nEndAsciiIndex = nIndex+4;
    3249             :             // now count backwards until we can account for 512 '0'
    3250             :             // which is the endmarker of the (hopefully) binary data
    3251             :             // do not count the pfb header sections
    3252           0 :             int nFound = 0;
    3253           0 :             nIndex =  nFontLen-1;
    3254           0 :             while( nIndex > 0 && nFound < 512 )
    3255             :             {
    3256           0 :                 for( it = aSections.begin(); it != aSections.end() && (nIndex < *it || nIndex > ((*it) + 5) ); ++it )
    3257             :                     ;
    3258           0 :                 if( it == aSections.end() )
    3259             :                 {
    3260             :                     // inside the 512 '0' block there may only be whitespace
    3261             :                     // according to T1 spec; probably it would be to simple
    3262             :                     // if all fonts complied
    3263           0 :                     if( pFontData[nIndex] == '0' )
    3264           0 :                         nFound++;
    3265           0 :                         else if( nFound > 0                 &&
    3266           0 :                             pFontData[nIndex] != '\r'       &&
    3267           0 :                         pFontData[nIndex] != '\t'       &&
    3268           0 :                         pFontData[nIndex] != '\n'       &&
    3269           0 :                         pFontData[nIndex] != ' ' )
    3270           0 :                         break;
    3271             :                 }
    3272           0 :                 nIndex--;
    3273             :             }
    3274             : 
    3275           0 :             if( nIndex < 1 || nIndex <= nEndAsciiIndex )
    3276           0 :                 throw FontException();
    3277             : 
    3278             :             // nLength3 is the rest of the file - excluding any section headers
    3279             :             // nIndex now points before the first of the 512 '0' characters marking the
    3280             :             // fixed content portion
    3281           0 :             sal_Int32 nLength3 = nFontLen - nIndex - 1;
    3282           0 :             for( it = aSections.begin(); it != aSections.end(); ++it )
    3283             :             {
    3284             :                 // special case: nIndex inside a section marker
    3285           0 :                 if( nIndex >= (*it) && (*it)+6 > nIndex )
    3286           0 :                     nLength3 -= (*it)+6 - nIndex;
    3287           0 :                 else if( *it >= nIndex  )
    3288             :                 {
    3289           0 :                     if( *it < nFontLen - 6 )
    3290           0 :                         nLength3 -= 6;
    3291             :                     else // the last section 0x8003 is only 2 bytes after all
    3292           0 :                         nLength3 -= (nFontLen - *it);
    3293             :                 }
    3294             :             }
    3295             : 
    3296             :             // there may be whitespace to ignore before the 512 '0'
    3297           0 :             while( pFontData[nIndex] == '\r' || pFontData[nIndex] == '\n' )
    3298             :             {
    3299           0 :                 nIndex--;
    3300           0 :                 for( it = aSections.begin(); it != aSections.end() && (nIndex < *it || nIndex > ((*it) + 5) ); ++it )
    3301             :                     ;
    3302           0 :                 if( it != aSections.end() )
    3303             :                 {
    3304           0 :                     nIndex = (*it)-1;
    3305           0 :                     break; // this is surely a binary boundary, in ascii case it wouldn't matter
    3306             :                 }
    3307             :             }
    3308           0 :             nEndBinaryIndex = nIndex;
    3309             : 
    3310             :             // search for beginning of binary section
    3311           0 :             nBeginBinaryIndex = nEndAsciiIndex;
    3312           0 :             do
    3313             :             {
    3314           0 :                 nBeginBinaryIndex++;
    3315           0 :                 for( it = aSections.begin(); it != aSections.end() && (nBeginBinaryIndex < *it || nBeginBinaryIndex > ((*it) + 5) ); ++it )
    3316             :                     ;
    3317           0 :                     } while( nBeginBinaryIndex < nEndBinaryIndex &&
    3318           0 :                         ( pFontData[nBeginBinaryIndex] == '\r'  ||
    3319           0 :                             pFontData[nBeginBinaryIndex] == '\n'    ||
    3320           0 :                             it != aSections.end() ) );
    3321             : 
    3322             :                     // it seems to be vital to copy the exact whitespace between binary data
    3323             :                     // and eexec, else a invalid font results. so make nEndAsciiIndex
    3324             :                     // always immediate in front of nBeginBinaryIndex
    3325           0 :                     nEndAsciiIndex = nBeginBinaryIndex-1;
    3326           0 :                     for( it = aSections.begin(); it != aSections.end() && (nEndAsciiIndex < *it || nEndAsciiIndex > ((*it)+5)); ++it )
    3327             :                         ;
    3328           0 :                     if( it != aSections.end() )
    3329           0 :                         nEndAsciiIndex = (*it)-1;
    3330             : 
    3331           0 :                     nLength1 = nEndAsciiIndex+1; // including the last character
    3332           0 :                     for( it = aSections.begin(); it != aSections.end() && *it < nEndAsciiIndex; ++it )
    3333           0 :                         nLength1 -= 6; // decrease by pfb section size
    3334             : 
    3335             :                     // if the first four bytes are all ascii hex characters, then binary data
    3336             :                     // has to be converted to real binary data
    3337           0 :                     for( nIndex = 0; nIndex < 4 &&
    3338           0 :                         ( ( pFontData[ nBeginBinaryIndex+nIndex ] >= '0' && pFontData[ nBeginBinaryIndex+nIndex ] <= '9' ) ||
    3339           0 :                             ( pFontData[ nBeginBinaryIndex+nIndex ] >= 'a' && pFontData[ nBeginBinaryIndex+nIndex ] <= 'f' ) ||
    3340           0 :                             ( pFontData[ nBeginBinaryIndex+nIndex ] >= 'A' && pFontData[ nBeginBinaryIndex+nIndex ] <= 'F' )
    3341             :                             ); ++nIndex )
    3342             :                         ;
    3343           0 :                     bool bConvertHexData = true;
    3344           0 :                     if( nIndex < 4 )
    3345             :                     {
    3346           0 :                         bConvertHexData = false;
    3347           0 :                         nLength2 = nEndBinaryIndex - nBeginBinaryIndex + 1; // include the last byte
    3348           0 :                         for( it = aSections.begin(); it != aSections.end(); ++it )
    3349           0 :                             if( *it > nBeginBinaryIndex && *it < nEndBinaryIndex )
    3350           0 :                                 nLength2 -= 6;
    3351             :                     }
    3352             :                     else
    3353             :                     {
    3354             :                         // count the hex ascii characters to get nLength2
    3355           0 :                         nLength2 = 0;
    3356           0 :                         int nNextSectionIndex = 0;
    3357           0 :                         for( it = aSections.begin(); it != aSections.end() && *it < nBeginBinaryIndex; ++it )
    3358             :                             ;
    3359           0 :                         if( it != aSections.end() )
    3360           0 :                             nNextSectionIndex = *it;
    3361           0 :                         for( nIndex = nBeginBinaryIndex; nIndex <= nEndBinaryIndex; nIndex++ )
    3362             :                         {
    3363           0 :                             if( nIndex == nNextSectionIndex )
    3364             :                             {
    3365           0 :                                 nIndex += 6;
    3366           0 :                                 ++it;
    3367           0 :                                 nNextSectionIndex = (it == aSections.end() ? 0 : *it );
    3368             :                             }
    3369           0 :                             if( ( pFontData[ nIndex ] >= '0' && pFontData[ nIndex ] <= '9' ) ||
    3370           0 :                                 ( pFontData[ nIndex ] >= 'a' && pFontData[ nIndex ] <= 'f' ) ||
    3371           0 :                             ( pFontData[ nIndex ] >= 'A' && pFontData[ nIndex ] <= 'F' ) )
    3372           0 :                             nLength2++;
    3373             :                         }
    3374             :                         DBG_ASSERT( !(nLength2 & 1), "uneven number of hex chars in binary pfa section" );
    3375           0 :                         nLength2 /= 2;
    3376             :                     }
    3377             : 
    3378             :                     // now we can actually write the font stream !
    3379             :                     #if OSL_DEBUG_LEVEL > 1
    3380             :                     emitComment( " PDFWriterImpl::emitEmbeddedFont" );
    3381             :                     #endif
    3382           0 :                     OStringBuffer aLine( 512 );
    3383           0 :                     nStreamObject = createObject();
    3384           0 :                     if( !updateObject(nStreamObject))
    3385           0 :                         throw FontException();
    3386           0 :                     sal_Int32 nStreamLengthObject = createObject();
    3387           0 :                     aLine.append( nStreamObject );
    3388             :                     aLine.append( " 0 obj\n"
    3389           0 :                         "<</Length " );
    3390           0 :                     aLine.append( nStreamLengthObject );
    3391             :                     aLine.append( " 0 R"
    3392             :                         #ifndef DEBUG_DISABLE_PDFCOMPRESSION
    3393             :                         "/Filter/FlateDecode"
    3394             :                         #endif
    3395           0 :                         "/Length1 " );
    3396           0 :                     aLine.append( nLength1 );
    3397           0 :                     aLine.append( " /Length2 " );
    3398           0 :                     aLine.append( nLength2 );
    3399           0 :                     aLine.append( " /Length3 ");
    3400           0 :                     aLine.append( nLength3 );
    3401             :                     aLine.append( ">>\n"
    3402           0 :                         "stream\n" );
    3403           0 :                     if( !writeBuffer( aLine.getStr(), aLine.getLength() ) )
    3404           0 :                         throw FontException();
    3405             : 
    3406           0 :                     sal_uInt64 nBeginStreamPos = 0;
    3407           0 :                     m_aFile.getPos(nBeginStreamPos);
    3408             : 
    3409           0 :                     beginCompression();
    3410           0 :                     checkAndEnableStreamEncryption( nStreamObject );
    3411             : 
    3412             :                     // write ascii section
    3413           0 :                     if( aSections.begin() == aSections.end() )
    3414             :                     {
    3415           0 :                         if( ! writeBuffer( pFontData, nEndAsciiIndex+1 ) )
    3416           0 :                             throw FontException();
    3417             :                     }
    3418             :                     else
    3419             :                     {
    3420             :                         // first section always starts at 0
    3421           0 :                         it = aSections.begin();
    3422           0 :                         nIndex = (*it)+6;
    3423           0 :                         ++it;
    3424           0 :                         while( *it < nEndAsciiIndex )
    3425             :                         {
    3426           0 :                             if( ! writeBuffer( pFontData+nIndex, (*it)-nIndex ) )
    3427           0 :                                 throw FontException();
    3428           0 :                             nIndex = (*it)+6;
    3429           0 :                             ++it;
    3430             :                         }
    3431             :                         // write partial last section
    3432           0 :                         if( ! writeBuffer( pFontData+nIndex, nEndAsciiIndex-nIndex+1 ) )
    3433           0 :                             throw FontException();
    3434             :                     }
    3435             : 
    3436             :                     // write binary section
    3437           0 :                     if( ! bConvertHexData )
    3438             :                     {
    3439           0 :                         if( aSections.begin() == aSections.end() )
    3440             :                         {
    3441           0 :                             if( ! writeBuffer( pFontData+nBeginBinaryIndex, nFontLen-nBeginBinaryIndex ) )
    3442           0 :                                 throw FontException();
    3443             :                         }
    3444             :                         else
    3445             :                         {
    3446           0 :                             for( it = aSections.begin(); *it < nBeginBinaryIndex; ++it )
    3447             :                                 ;
    3448             :                             // write first partial section
    3449           0 :                             if( ! writeBuffer( pFontData+nBeginBinaryIndex, (*it) - nBeginBinaryIndex ) )
    3450           0 :                                 throw FontException();
    3451             :                             // write following sections
    3452           0 :                             while( it != aSections.end() )
    3453             :                             {
    3454           0 :                                 nIndex = (*it)+6;
    3455           0 :                                 ++it;
    3456           0 :                                 if( nIndex < nFontLen ) // last section marker is usually the EOF which has only 2 bytes
    3457             :                                 {
    3458           0 :                                     sal_Int32 nSectionLen = (it == aSections.end()) ? nFontLen - nIndex : (*it) - nIndex;
    3459           0 :                                     if( ! writeBuffer( pFontData+nIndex, nSectionLen ) )
    3460           0 :                                         throw FontException();
    3461             :                                 }
    3462             :                             }
    3463             :                         }
    3464             :                     }
    3465             :                     else
    3466             :                     {
    3467           0 :                         boost::shared_array<unsigned char> pWriteBuffer( new unsigned char[ nLength2 ] );
    3468           0 :                         memset( pWriteBuffer.get(), 0, nLength2 );
    3469           0 :                         int nWriteIndex = 0;
    3470             : 
    3471           0 :                         int nNextSectionIndex = 0;
    3472           0 :                         for( it = aSections.begin(); it != aSections.end() && *it < nBeginBinaryIndex; ++it )
    3473             :                             ;
    3474           0 :                         if( it != aSections.end() )
    3475           0 :                             nNextSectionIndex = *it;
    3476           0 :                         for( nIndex = nBeginBinaryIndex; nIndex <= nEndBinaryIndex; nIndex++ )
    3477             :                         {
    3478           0 :                             if( nIndex == nNextSectionIndex )
    3479             :                             {
    3480           0 :                                 nIndex += 6;
    3481           0 :                                 ++it;
    3482           0 :                                 nNextSectionIndex = (it == aSections.end() ? nFontLen : *it );
    3483             :                             }
    3484           0 :                             unsigned char cNibble = 0x80;
    3485           0 :                             if( pFontData[ nIndex ] >= '0' && pFontData[ nIndex ] <= '9' )
    3486           0 :                                 cNibble = pFontData[nIndex] - '0';
    3487           0 :                             else if( pFontData[ nIndex ] >= 'a' && pFontData[ nIndex ] <= 'f' )
    3488           0 :                                 cNibble = pFontData[nIndex] - 'a' + 10;
    3489           0 :                             else if( pFontData[ nIndex ] >= 'A' && pFontData[ nIndex ] <= 'F' )
    3490           0 :                                 cNibble = pFontData[nIndex] - 'A' + 10;
    3491           0 :                             if( cNibble != 0x80 )
    3492             :                             {
    3493           0 :                                 if( !(nWriteIndex & 1 ) )
    3494           0 :                                     cNibble <<= 4;
    3495           0 :                                 pWriteBuffer.get()[ nWriteIndex/2 ] |= cNibble;
    3496           0 :                                 nWriteIndex++;
    3497             :                             }
    3498             :                         }
    3499           0 :                         if( ! writeBuffer( pWriteBuffer.get(), nLength2 ) )
    3500           0 :                             throw FontException();
    3501           0 :                         if( aSections.empty() )
    3502             :                         {
    3503           0 :                             if( ! writeBuffer( pFontData+nIndex, nFontLen-nIndex ) )
    3504           0 :                                 throw FontException();
    3505             :                         }
    3506             :                         else
    3507             :                         {
    3508             :                             // write rest of this section
    3509           0 :                             if( nIndex < nNextSectionIndex )
    3510             :                             {
    3511           0 :                                 if( ! writeBuffer( pFontData+nIndex, nNextSectionIndex - nIndex ) )
    3512           0 :                                     throw FontException();
    3513             :                             }
    3514             :                             // write following sections
    3515           0 :                             while( it != aSections.end() )
    3516             :                             {
    3517           0 :                                 nIndex = (*it)+6;
    3518           0 :                                 ++it;
    3519           0 :                                 if( nIndex < nFontLen ) // last section marker is usually the EOF which has only 2 bytes
    3520             :                                 {
    3521           0 :                                     sal_Int32 nSectionLen = (it == aSections.end()) ? nFontLen - nIndex : (*it) - nIndex;
    3522           0 :                                     if( ! writeBuffer( pFontData+nIndex, nSectionLen ) )
    3523           0 :                                         throw FontException();
    3524             :                                 }
    3525             :                             }
    3526           0 :                         }
    3527             :                     }
    3528           0 :                     endCompression();
    3529           0 :                     disableStreamEncryption();
    3530             : 
    3531           0 :                     sal_uInt64 nEndStreamPos = 0;
    3532           0 :                     m_aFile.getPos(nEndStreamPos);
    3533             : 
    3534             :                     // and finally close the stream
    3535           0 :                     aLine.setLength( 0 );
    3536           0 :                     aLine.append( "\nendstream\nendobj\n\n" );
    3537           0 :                     if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) )
    3538           0 :                         throw FontException();
    3539             : 
    3540             :                     // write stream length object
    3541           0 :                     aLine.setLength( 0 );
    3542           0 :                     if( ! updateObject( nStreamLengthObject ) )
    3543           0 :                         throw FontException();
    3544           0 :                     aLine.append( nStreamLengthObject );
    3545           0 :                     aLine.append( " 0 obj\n" );
    3546           0 :                     aLine.append( (sal_Int64)(nEndStreamPos-nBeginStreamPos ) );
    3547           0 :                     aLine.append( "\nendobj\n\n" );
    3548           0 :                     if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) )
    3549           0 :                         throw FontException();
    3550             :         }
    3551             :         else
    3552             :         {
    3553           0 :             OStringBuffer aErrorComment( 256 );
    3554           0 :             aErrorComment.append( "GetEmbedFontData failed for font \"" );
    3555           0 :             aErrorComment.append( OUStringToOString( pFont->GetFamilyName(), RTL_TEXTENCODING_UTF8 ) );
    3556           0 :             aErrorComment.append( '\"' );
    3557           0 :             if( pFont->GetSlant() == ITALIC_NORMAL )
    3558           0 :                 aErrorComment.append( " italic" );
    3559           0 :             else if( pFont->GetSlant() == ITALIC_OBLIQUE )
    3560           0 :                 aErrorComment.append( " oblique" );
    3561           0 :             aErrorComment.append( " weight=" );
    3562           0 :             aErrorComment.append( sal_Int32(pFont->GetWeight()) );
    3563           0 :             emitComment( aErrorComment.getStr() );
    3564             :         }
    3565             : 
    3566           0 :         if( nStreamObject )
    3567             :         {
    3568             :             // write font descriptor
    3569           0 :             nFontDescriptor = emitFontDescriptor( pFont, aInfo, 0, nStreamObject );
    3570             :         }
    3571             : 
    3572           0 :         if( nFontDescriptor )
    3573             :         {
    3574           0 :             if( pEncoding )
    3575           0 :                 nToUnicodeStream = createToUnicodeCMap( nEncoding, &aUnicodes[0], pUnicodesPerGlyph, pEncToUnicodeIndex, SAL_N_ELEMENTS(nEncoding) );
    3576             : 
    3577             :             // write font object
    3578           0 :             sal_Int32 nObject = createObject();
    3579           0 :             if( ! updateObject( nObject ) )
    3580           0 :                 throw FontException();
    3581             : 
    3582           0 :             OStringBuffer aLine( 1024 );
    3583           0 :             aLine.append( nObject );
    3584             :             aLine.append( " 0 obj\n"
    3585           0 :                 "<</Type/Font/Subtype/Type1/BaseFont/" );
    3586           0 :             appendName( aInfo.m_aPSName, aLine );
    3587           0 :             aLine.append( "\n" );
    3588           0 :             if( !pFont->IsSymbolFont() &&  pEncoding == 0 )
    3589           0 :                 aLine.append( "/Encoding/WinAnsiEncoding\n" );
    3590           0 :             if( nToUnicodeStream )
    3591             :             {
    3592           0 :                 aLine.append( "/ToUnicode " );
    3593           0 :                 aLine.append( nToUnicodeStream );
    3594           0 :                 aLine.append( " 0 R\n" );
    3595             :             }
    3596             :             aLine.append( "/FirstChar 0 /LastChar 255\n"
    3597           0 :                 "/Widths[" );
    3598           0 :             for( int i = 0; i < 256; i++ )
    3599             :             {
    3600           0 :                 aLine.append( pWidths[i] );
    3601           0 :                 aLine.append( ((i&15) == 15) ? "\n" : " " );
    3602             :             }
    3603             :             aLine.append( "]\n"
    3604           0 :                 "/FontDescriptor " );
    3605           0 :             aLine.append( nFontDescriptor );
    3606             :             aLine.append( " 0 R>>\n"
    3607           0 :                 "endobj\n\n" );
    3608           0 :             if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) )
    3609           0 :                 throw FontException();
    3610             : 
    3611           0 :             aRet[ rEmbed.m_nNormalFontID ] = nObject;
    3612             : 
    3613             :             // write additional encodings
    3614           0 :             for( std::list< EmbedEncoding >::iterator enc_it = rEmbed.m_aExtendedEncodings.begin(); enc_it != rEmbed.m_aExtendedEncodings.end(); ++enc_it )
    3615             :             {
    3616             :                 sal_Int32 aEncWidths[ 256 ];
    3617             :                 // emit encoding dict
    3618           0 :                 sal_Int32 nEncObject = createObject();
    3619           0 :                 if( ! updateObject( nEncObject ) )
    3620           0 :                     throw FontException();
    3621             : 
    3622           0 :                 OutputDevice* pRef = getReferenceDevice();
    3623           0 :                 pRef->Push( PushFlags::FONT | PushFlags::MAPMODE );
    3624           0 :                 pRef->SetMapMode( MapMode( MAP_PIXEL ) );
    3625           0 :                 Font aFont( pFont->GetFamilyName(), pFont->GetStyleName(), Size( 0, 1000 ) );
    3626           0 :                 aFont.SetWeight( pFont->GetWeight() );
    3627           0 :                 aFont.SetItalic( pFont->GetSlant() );
    3628           0 :                 aFont.SetPitch( pFont->GetPitch() );
    3629           0 :                 pRef->SetFont( aFont );
    3630           0 :                 pRef->ImplNewFont();
    3631             : 
    3632           0 :                 aLine.setLength( 0 );
    3633           0 :                 aLine.append( nEncObject );
    3634             :                 aLine.append( " 0 obj\n"
    3635           0 :                     "<</Type/Encoding/Differences[ 0\n" );
    3636           0 :                 int nEncoded = 0;
    3637           0 :                 aUnicodes.clear();
    3638           0 :                 for( std::vector< EmbedCode >::iterator str_it = enc_it->m_aEncVector.begin(); str_it != enc_it->m_aEncVector.end(); ++str_it )
    3639             :                 {
    3640           0 :                     OUString aStr( str_it->m_aUnicode );
    3641           0 :                     aEncWidths[nEncoded] = pRef->GetTextWidth( aStr );
    3642           0 :                     nEncodedCodes[nEncoded] = str_it->m_aUnicode;
    3643           0 :                     nEncoding[nEncoded] = sal::static_int_cast<sal_uInt8>(nEncoded);
    3644           0 :                     pEncToUnicodeIndex[nEncoded] = static_cast<sal_Int32>(aUnicodes.size());
    3645           0 :                     aUnicodes.push_back( nEncodedCodes[nEncoded] );
    3646           0 :                     pUnicodesPerGlyph[nEncoded] = 1;
    3647             : 
    3648           0 :                     aLine.append( " /" );
    3649           0 :                     aLine.append( str_it->m_aName );
    3650           0 :                     if( !((++nEncoded) & 15) )
    3651           0 :                         aLine.append( "\n" );
    3652           0 :                 }
    3653             :                 aLine.append( "]>>\n"
    3654           0 :                     "endobj\n\n" );
    3655             : 
    3656           0 :                 pRef->Pop();
    3657             : 
    3658           0 :                 if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) )
    3659           0 :                     throw FontException();
    3660             : 
    3661           0 :                 nToUnicodeStream = createToUnicodeCMap( nEncoding, &aUnicodes[0], pUnicodesPerGlyph, pEncToUnicodeIndex, nEncoded );
    3662             : 
    3663           0 :                 nObject = createObject();
    3664           0 :                 if( ! updateObject( nObject ) )
    3665           0 :                     throw FontException();
    3666             : 
    3667           0 :                 aLine.setLength( 0 );
    3668           0 :                 aLine.append( nObject );
    3669             :                 aLine.append( " 0 obj\n"
    3670           0 :                     "<</Type/Font/Subtype/Type1/BaseFont/" );
    3671           0 :                 appendName( aInfo.m_aPSName, aLine );
    3672           0 :                 aLine.append( "\n" );
    3673           0 :                 aLine.append( "/Encoding " );
    3674           0 :                 aLine.append( nEncObject );
    3675           0 :                 aLine.append( " 0 R\n" );
    3676           0 :                 if( nToUnicodeStream )
    3677             :                 {
    3678           0 :                     aLine.append( "/ToUnicode " );
    3679           0 :                     aLine.append( nToUnicodeStream );
    3680           0 :                     aLine.append( " 0 R\n" );
    3681             :                 }
    3682             :                 aLine.append( "/FirstChar 0\n"
    3683           0 :                     "/LastChar " );
    3684           0 :                 aLine.append( (sal_Int32)(nEncoded-1) );
    3685             :                 aLine.append( "\n"
    3686           0 :                     "/Widths[" );
    3687           0 :                 for( int i = 0; i < nEncoded; i++ )
    3688             :                 {
    3689           0 :                     aLine.append( aEncWidths[i] );
    3690           0 :                     aLine.append( ((i&15) == 15) ? "\n" : " " );
    3691             :                 }
    3692             :                 aLine.append( " ]\n"
    3693           0 :                     "/FontDescriptor " );
    3694           0 :                 aLine.append( nFontDescriptor );
    3695             :                 aLine.append( " 0 R>>\n"
    3696           0 :                     "endobj\n\n" );
    3697           0 :                 if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) )
    3698           0 :                     throw FontException();
    3699             : 
    3700           0 :                 aRet[ enc_it->m_nFontID ] = nObject;
    3701           0 :             }
    3702             :         }
    3703             :     }
    3704           0 :     catch( FontException& )
    3705             :     {
    3706             :         // these do nothing in case there was no compression or encryption ongoing
    3707           0 :         endCompression();
    3708           0 :         disableStreamEncryption();
    3709             :     }
    3710             : 
    3711           0 :     if( pFontData )
    3712           0 :         pGraphics->FreeEmbedFontData( pFontData, nFontLen );
    3713             : 
    3714           0 :     return aRet;
    3715             : }
    3716             : 
    3717           0 : static void appendSubsetName( int nSubsetID, const OUString& rPSName, OStringBuffer& rBuffer )
    3718             : {
    3719           0 :     if( nSubsetID )
    3720             :     {
    3721           0 :         for( int i = 0; i < 6; i++ )
    3722             :         {
    3723           0 :             int nOffset = (nSubsetID % 26);
    3724           0 :             nSubsetID /= 26;
    3725           0 :             rBuffer.append( (sal_Char)('A'+nOffset) );
    3726             :         }
    3727           0 :         rBuffer.append( '+' );
    3728             :     }
    3729           0 :     appendName( rPSName, rBuffer );
    3730           0 : }
    3731             : 
    3732           0 : sal_Int32 PDFWriterImpl::createToUnicodeCMap( sal_uInt8* pEncoding,
    3733             :                                               sal_Ucs* pUnicodes,
    3734             :                                               sal_Int32* pUnicodesPerGlyph,
    3735             :                                               sal_Int32* pEncToUnicodeIndex,
    3736             :                                               int nGlyphs )
    3737             : {
    3738           0 :     int nMapped = 0, n = 0;
    3739           0 :     for( n = 0; n < nGlyphs; n++ )
    3740           0 :         if( pUnicodes[pEncToUnicodeIndex[n]] && pUnicodesPerGlyph[n] )
    3741           0 :             nMapped++;
    3742             : 
    3743           0 :     if( nMapped == 0 )
    3744           0 :         return 0;
    3745             : 
    3746           0 :     sal_Int32 nStream = createObject();
    3747           0 :     CHECK_RETURN( updateObject( nStream ) );
    3748             : 
    3749           0 :     OStringBuffer aContents( 1024 );
    3750             :     aContents.append(
    3751             :                      "/CIDInit/ProcSet findresource begin\n"
    3752             :                      "12 dict begin\n"
    3753             :                      "begincmap\n"
    3754             :                      "/CIDSystemInfo<<\n"
    3755             :                      "/Registry (Adobe)\n"
    3756             :                      "/Ordering (UCS)\n"
    3757             :                      "/Supplement 0\n"
    3758             :                      ">> def\n"
    3759             :                      "/CMapName/Adobe-Identity-UCS def\n"
    3760             :                      "/CMapType 2 def\n"
    3761             :                      "1 begincodespacerange\n"
    3762             :                      "<00> <FF>\n"
    3763             :                      "endcodespacerange\n"
    3764           0 :                      );
    3765           0 :     int nCount = 0;
    3766           0 :     for( n = 0; n < nGlyphs; n++ )
    3767             :     {
    3768           0 :         if( pUnicodes[pEncToUnicodeIndex[n]] && pUnicodesPerGlyph[n] )
    3769             :         {
    3770           0 :             if( (nCount % 100) == 0 )
    3771             :             {
    3772           0 :                 if( nCount )
    3773           0 :                     aContents.append( "endbfchar\n" );
    3774           0 :                 aContents.append( (sal_Int32)((nMapped-nCount > 100) ? 100 : nMapped-nCount ) );
    3775           0 :                 aContents.append( " beginbfchar\n" );
    3776             :             }
    3777           0 :             aContents.append( '<' );
    3778           0 :             appendHex( (sal_Int8)pEncoding[n], aContents );
    3779           0 :             aContents.append( "> <" );
    3780             :             // TODO: handle unicodes>U+FFFF
    3781           0 :             sal_Int32 nIndex = pEncToUnicodeIndex[n];
    3782           0 :             for( sal_Int32 j = 0; j < pUnicodesPerGlyph[n]; j++ )
    3783             :             {
    3784           0 :                 appendHex( (sal_Int8)(pUnicodes[nIndex + j] / 256), aContents );
    3785           0 :                 appendHex( (sal_Int8)(pUnicodes[nIndex + j] & 255), aContents );
    3786             :             }
    3787           0 :             aContents.append( ">\n" );
    3788           0 :             nCount++;
    3789             :         }
    3790             :     }
    3791             :     aContents.append( "endbfchar\n"
    3792             :                       "endcmap\n"
    3793             :                       "CMapName currentdict /CMap defineresource pop\n"
    3794             :                       "end\n"
    3795           0 :                       "end\n" );
    3796             : #ifndef DEBUG_DISABLE_PDFCOMPRESSION
    3797           0 :     ZCodec pCodec( 0x4000, 0x4000 );
    3798           0 :     SvMemoryStream aStream;
    3799           0 :     pCodec.BeginCompression();
    3800           0 :     pCodec.Write( aStream, reinterpret_cast<const sal_uInt8*>(aContents.getStr()), aContents.getLength() );
    3801           0 :     pCodec.EndCompression();
    3802             : #endif
    3803             : 
    3804             :     #if OSL_DEBUG_LEVEL > 1
    3805             :     emitComment( "PDFWriterImpl::createToUnicodeCMap" );
    3806             :     #endif
    3807           0 :     OStringBuffer aLine( 40 );
    3808             : 
    3809           0 :     aLine.append( nStream );
    3810           0 :     aLine.append( " 0 obj\n<</Length " );
    3811             : #ifndef DEBUG_DISABLE_PDFCOMPRESSION
    3812           0 :     sal_Int32 nLen = (sal_Int32)aStream.Tell();
    3813           0 :     aStream.Seek( 0 );
    3814           0 :     aLine.append( nLen );
    3815           0 :     aLine.append( "/Filter/FlateDecode" );
    3816             : #else
    3817             :     aLine.append( aContents.getLength() );
    3818             : #endif
    3819           0 :     aLine.append( ">>\nstream\n" );
    3820           0 :     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
    3821           0 :     checkAndEnableStreamEncryption( nStream );
    3822             : #ifndef DEBUG_DISABLE_PDFCOMPRESSION
    3823           0 :     CHECK_RETURN( writeBuffer( aStream.GetData(), nLen ) );
    3824             : #else
    3825             :     CHECK_RETURN( writeBuffer( aContents.getStr(), aContents.getLength() ) );
    3826             : #endif
    3827           0 :     disableStreamEncryption();
    3828           0 :     aLine.setLength( 0 );
    3829             :     aLine.append( "\nendstream\n"
    3830           0 :                   "endobj\n\n" );
    3831           0 :     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
    3832           0 :     return nStream;
    3833             : }
    3834             : 
    3835           0 : sal_Int32 PDFWriterImpl::emitFontDescriptor( const PhysicalFontFace* pFont, FontSubsetInfo& rInfo, sal_Int32 nSubsetID, sal_Int32 nFontStream )
    3836             : {
    3837           0 :     OStringBuffer aLine( 1024 );
    3838             :     // get font flags, see PDF reference 1.4 p. 358
    3839             :     // possibly characters outside Adobe standard encoding
    3840             :     // so set Symbolic flag
    3841           0 :     sal_Int32 nFontFlags = (1<<2);
    3842           0 :     if( pFont->GetSlant() == ITALIC_NORMAL || pFont->GetSlant() == ITALIC_OBLIQUE )
    3843           0 :         nFontFlags |= (1 << 6);
    3844           0 :     if( pFont->GetPitch() == PITCH_FIXED )
    3845           0 :         nFontFlags |= 1;
    3846           0 :     if( pFont->GetFamilyType() == FAMILY_SCRIPT )
    3847           0 :         nFontFlags |= (1 << 3);
    3848           0 :     else if( pFont->GetFamilyType() == FAMILY_ROMAN )
    3849           0 :         nFontFlags |= (1 << 1);
    3850             : 
    3851           0 :     sal_Int32 nFontDescriptor = createObject();
    3852           0 :     CHECK_RETURN( updateObject( nFontDescriptor ) );
    3853           0 :     aLine.setLength( 0 );
    3854           0 :     aLine.append( nFontDescriptor );
    3855             :     aLine.append( " 0 obj\n"
    3856           0 :                   "<</Type/FontDescriptor/FontName/" );
    3857           0 :     appendSubsetName( nSubsetID, rInfo.m_aPSName, aLine );
    3858             :     aLine.append( "\n"
    3859           0 :                   "/Flags " );
    3860           0 :     aLine.append( nFontFlags );
    3861             :     aLine.append( "\n"
    3862           0 :                   "/FontBBox[" );
    3863             :     // note: Top and Bottom are reversed in VCL and PDF rectangles
    3864           0 :     aLine.append( (sal_Int32)rInfo.m_aFontBBox.TopLeft().X() );
    3865           0 :     aLine.append( ' ' );
    3866           0 :     aLine.append( (sal_Int32)rInfo.m_aFontBBox.TopLeft().Y() );
    3867           0 :     aLine.append( ' ' );
    3868           0 :     aLine.append( (sal_Int32)rInfo.m_aFontBBox.BottomRight().X() );
    3869           0 :     aLine.append( ' ' );
    3870           0 :     aLine.append( (sal_Int32)(rInfo.m_aFontBBox.BottomRight().Y()+1) );
    3871           0 :     aLine.append( "]/ItalicAngle " );
    3872           0 :     if( pFont->GetSlant() == ITALIC_OBLIQUE || pFont->GetSlant() == ITALIC_NORMAL )
    3873           0 :         aLine.append( "-30" );
    3874             :     else
    3875           0 :         aLine.append( "0" );
    3876             :     aLine.append( "\n"
    3877           0 :                   "/Ascent " );
    3878           0 :     aLine.append( (sal_Int32)rInfo.m_nAscent );
    3879             :     aLine.append( "\n"
    3880           0 :                   "/Descent " );
    3881           0 :     aLine.append( (sal_Int32)-rInfo.m_nDescent );
    3882             :     aLine.append( "\n"
    3883           0 :                   "/CapHeight " );
    3884           0 :     aLine.append( (sal_Int32)rInfo.m_nCapHeight );
    3885             :     // According to PDF reference 1.4 StemV is required
    3886             :     // seems a tad strange to me, but well ...
    3887             :     aLine.append( "\n"
    3888           0 :                   "/StemV 80\n" );
    3889           0 :     if( nFontStream )
    3890             :     {
    3891           0 :         aLine.append( "/FontFile" );
    3892           0 :         switch( rInfo.m_nFontType )
    3893             :         {
    3894             :             case FontSubsetInfo::SFNT_TTF:
    3895           0 :                 aLine.append( '2' );
    3896           0 :                 break;
    3897             :             case FontSubsetInfo::TYPE1_PFA:
    3898             :             case FontSubsetInfo::TYPE1_PFB:
    3899             :             case FontSubsetInfo::ANY_TYPE1:
    3900           0 :                 break;
    3901             :             default:
    3902             :                 OSL_FAIL( "unknown fonttype in PDF font descriptor" );
    3903           0 :                 return 0;
    3904             :         }
    3905           0 :         aLine.append( ' ' );
    3906           0 :         aLine.append( nFontStream );
    3907           0 :         aLine.append( " 0 R\n" );
    3908             :     }
    3909             :     aLine.append( ">>\n"
    3910           0 :                   "endobj\n\n" );
    3911           0 :     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
    3912             : 
    3913           0 :     return nFontDescriptor;
    3914             : }
    3915             : 
    3916           0 : void PDFWriterImpl::appendBuiltinFontsToDict( OStringBuffer& rDict ) const
    3917             : {
    3918           0 :     for( std::map< sal_Int32, sal_Int32 >::const_iterator it =
    3919           0 :          m_aBuiltinFontToObjectMap.begin(); it != m_aBuiltinFontToObjectMap.end(); ++it )
    3920             :     {
    3921           0 :         rDict.append( m_aBuiltinFonts[it->first].getNameObject() );
    3922           0 :         rDict.append( ' ' );
    3923           0 :         rDict.append( it->second );
    3924           0 :         rDict.append( " 0 R" );
    3925             :     }
    3926           0 : }
    3927             : 
    3928           0 : bool PDFWriterImpl::emitFonts()
    3929             : {
    3930           0 :     SalGraphics *pGraphics = m_pReferenceDevice->GetGraphics();
    3931             : 
    3932           0 :     if (!pGraphics)
    3933           0 :         return false;
    3934             : 
    3935           0 :     OStringBuffer aLine( 1024 );
    3936             : 
    3937           0 :     std::map< sal_Int32, sal_Int32 > aFontIDToObject;
    3938             : 
    3939           0 :     OUString aTmpName;
    3940           0 :     osl_createTempFile( NULL, NULL, &aTmpName.pData );
    3941           0 :     for( FontSubsetData::iterator it = m_aSubsets.begin(); it != m_aSubsets.end(); ++it )
    3942             :     {
    3943           0 :         for( FontEmitList::iterator lit = it->second.m_aSubsets.begin(); lit != it->second.m_aSubsets.end(); ++lit )
    3944             :         {
    3945             :             sal_GlyphId aGlyphIds[ 256 ];
    3946             :             sal_Int32 pWidths[ 256 ];
    3947             :             sal_uInt8 pEncoding[ 256 ];
    3948             :             sal_Int32 pEncToUnicodeIndex[ 256 ];
    3949             :             sal_Int32 pUnicodesPerGlyph[ 256 ];
    3950           0 :             std::vector<sal_Ucs> aUnicodes;
    3951           0 :             aUnicodes.reserve( 256 );
    3952           0 :             int nGlyphs = 1;
    3953             :             // fill arrays and prepare encoding index map
    3954           0 :             sal_Int32 nToUnicodeStream = 0;
    3955             : 
    3956           0 :             memset( aGlyphIds, 0, sizeof( aGlyphIds ) );
    3957           0 :             memset( pEncoding, 0, sizeof( pEncoding ) );
    3958           0 :             memset( pUnicodesPerGlyph, 0, sizeof( pUnicodesPerGlyph ) );
    3959           0 :             memset( pEncToUnicodeIndex, 0, sizeof( pEncToUnicodeIndex ) );
    3960           0 :             for( FontEmitMapping::iterator fit = lit->m_aMapping.begin(); fit != lit->m_aMapping.end();++fit )
    3961             :             {
    3962           0 :                 sal_uInt8 nEnc = fit->second.getGlyphId();
    3963             : 
    3964             :                 DBG_ASSERT( aGlyphIds[nEnc] == 0 && pEncoding[nEnc] == 0, "duplicate glyph" );
    3965             :                 DBG_ASSERT( nEnc <= lit->m_aMapping.size(), "invalid glyph encoding" );
    3966             : 
    3967           0 :                 aGlyphIds[ nEnc ] = fit->first;
    3968           0 :                 pEncoding[ nEnc ] = nEnc;
    3969           0 :                 pEncToUnicodeIndex[ nEnc ] = static_cast<sal_Int32>(aUnicodes.size());
    3970           0 :                 pUnicodesPerGlyph[ nEnc ] = fit->second.countCodes();
    3971           0 :                 for( sal_Int32 n = 0; n < pUnicodesPerGlyph[ nEnc ]; n++ )
    3972           0 :                     aUnicodes.push_back( fit->second.getCode( n ) );
    3973           0 :                 if( fit->second.getCode(0) )
    3974           0 :                     nToUnicodeStream = 1;
    3975           0 :                 if( nGlyphs < 256 )
    3976           0 :                     nGlyphs++;
    3977             :                 else
    3978             :                 {
    3979             :                     OSL_FAIL( "too many glyphs for subset" );
    3980             :                 }
    3981             :             }
    3982           0 :             FontSubsetInfo aSubsetInfo;
    3983           0 :             if( pGraphics->CreateFontSubset( aTmpName, it->first, aGlyphIds, pEncoding, pWidths, nGlyphs, aSubsetInfo ) )
    3984             :             {
    3985             :                 // create font stream
    3986           0 :                 osl::File aFontFile(aTmpName);
    3987           0 :                 if (osl::File::E_None != aFontFile.open(osl_File_OpenFlag_Read)) return false;
    3988             :                 // get file size
    3989             :                 sal_uInt64 nLength1;
    3990           0 :                 if ( osl::File::E_None != aFontFile.setPos(osl_Pos_End, 0) ) return false;
    3991           0 :                 if ( osl::File::E_None != aFontFile.getPos(nLength1) ) return false;
    3992           0 :                 if ( osl::File::E_None != aFontFile.setPos(osl_Pos_Absolut, 0) ) return false;
    3993             : 
    3994             :                 #if OSL_DEBUG_LEVEL > 1
    3995             :                 emitComment( "PDFWriterImpl::emitFonts" );
    3996             :                 #endif
    3997           0 :                 sal_Int32 nFontStream = createObject();
    3998           0 :                 sal_Int32 nStreamLengthObject = createObject();
    3999           0 :                 if ( !updateObject( nFontStream ) ) return false;
    4000           0 :                 aLine.setLength( 0 );
    4001           0 :                 aLine.append( nFontStream );
    4002             :                 aLine.append( " 0 obj\n"
    4003           0 :                              "<</Length " );
    4004           0 :                 aLine.append( (sal_Int32)nStreamLengthObject );
    4005             :                 aLine.append( " 0 R"
    4006             :                              #ifndef DEBUG_DISABLE_PDFCOMPRESSION
    4007             :                              "/Filter/FlateDecode"
    4008             :                              #endif
    4009           0 :                              "/Length1 " );
    4010             : 
    4011           0 :                 sal_uInt64 nStartPos = 0;
    4012           0 :                 if( aSubsetInfo.m_nFontType == FontSubsetInfo::SFNT_TTF )
    4013             :                 {
    4014           0 :                     aLine.append( (sal_Int32)nLength1 );
    4015             : 
    4016             :                     aLine.append( ">>\n"
    4017           0 :                                  "stream\n" );
    4018           0 :                     if ( !writeBuffer( aLine.getStr(), aLine.getLength() ) ) return false;
    4019           0 :                     if ( osl::File::E_None != m_aFile.getPos(nStartPos) ) return false;
    4020             : 
    4021             :                     // copy font file
    4022           0 :                     beginCompression();
    4023           0 :                     checkAndEnableStreamEncryption( nFontStream );
    4024           0 :                     sal_Bool bEOF = sal_False;
    4025           0 :                     do
    4026             :                     {
    4027             :                         char buf[8192];
    4028             :                         sal_uInt64 nRead;
    4029           0 :                         if ( osl::File::E_None != aFontFile.read(buf, sizeof(buf), nRead) ) return false;
    4030           0 :                         if ( !writeBuffer( buf, nRead ) ) return false;
    4031           0 :                         if ( osl::File::E_None != aFontFile.isEndOfFile(&bEOF) ) return false;
    4032           0 :                     } while( ! bEOF );
    4033             :                 }
    4034           0 :                 else if( (aSubsetInfo.m_nFontType & FontSubsetInfo::CFF_FONT) != 0 )
    4035             :                 {
    4036             :                     // TODO: implement
    4037             :                     OSL_FAIL( "PDFWriterImpl does not support CFF-font subsets yet!" );
    4038             :                 }
    4039           0 :                 else if( (aSubsetInfo.m_nFontType & FontSubsetInfo::TYPE1_PFB) != 0 ) // TODO: also support PFA?
    4040             :                 {
    4041           0 :                     boost::shared_array<unsigned char> pBuffer( new unsigned char[ nLength1 ] );
    4042             : 
    4043           0 :                     sal_uInt64 nBytesRead = 0;
    4044           0 :                     if ( osl::File::E_None != aFontFile.read(pBuffer.get(), nLength1, nBytesRead) ) return false;
    4045             :                     DBG_ASSERT( nBytesRead==nLength1, "PDF-FontSubset read incomplete!" );
    4046           0 :                     if ( osl::File::E_None != aFontFile.setPos(osl_Pos_Absolut, 0) ) return false;
    4047             :                     // get the PFB-segment lengths
    4048           0 :                     ThreeInts aSegmentLengths = {0,0,0};
    4049           0 :                     getPfbSegmentLengths( pBuffer.get(), (int)nBytesRead, aSegmentLengths );
    4050             :                     // the lengths below are mandatory for PDF-exported Type1 fonts
    4051             :                     // because the PFB segment headers get stripped! WhyOhWhy.
    4052           0 :                     aLine.append( (sal_Int32)aSegmentLengths[0] );
    4053           0 :                     aLine.append( "/Length2 " );
    4054           0 :                     aLine.append( (sal_Int32)aSegmentLengths[1] );
    4055           0 :                     aLine.append( "/Length3 " );
    4056           0 :                     aLine.append( (sal_Int32)aSegmentLengths[2] );
    4057             : 
    4058             :                     aLine.append( ">>\n"
    4059           0 :                                  "stream\n" );
    4060           0 :                     if ( !writeBuffer( aLine.getStr(), aLine.getLength() ) ) return false;
    4061           0 :                     if ( osl::File::E_None != m_aFile.getPos(nStartPos) ) return false;
    4062             : 
    4063             :                     // emit PFB-sections without section headers
    4064           0 :                     beginCompression();
    4065           0 :                     checkAndEnableStreamEncryption( nFontStream );
    4066           0 :                     if ( !writeBuffer( &pBuffer[6], aSegmentLengths[0] ) ) return false;
    4067           0 :                     if ( !writeBuffer( &pBuffer[12] + aSegmentLengths[0], aSegmentLengths[1] ) ) return false;
    4068           0 :                     if ( !writeBuffer( &pBuffer[18] + aSegmentLengths[0] + aSegmentLengths[1], aSegmentLengths[2] ) ) return false;
    4069             :                 }
    4070             :                 else
    4071             :                 {
    4072           0 :                     fprintf( stderr, "PDF: CreateFontSubset result in not yet supported format=%d\n",aSubsetInfo.m_nFontType);
    4073           0 :                     aLine.append( "0 >>\nstream\n" );
    4074             :                 }
    4075             : 
    4076           0 :                 endCompression();
    4077           0 :                 disableStreamEncryption();
    4078             :                 // close the file
    4079           0 :                 aFontFile.close();
    4080             : 
    4081           0 :                 sal_uInt64 nEndPos = 0;
    4082           0 :                 if ( osl::File::E_None != m_aFile.getPos(nEndPos) ) return false;
    4083             :                 // end the stream
    4084           0 :                 aLine.setLength( 0 );
    4085           0 :                 aLine.append( "\nendstream\nendobj\n\n" );
    4086           0 :                 if ( !writeBuffer( aLine.getStr(), aLine.getLength() ) ) return false;
    4087             : 
    4088             :                 // emit stream length object
    4089           0 :                 if ( !updateObject( nStreamLengthObject ) ) return false;
    4090           0 :                 aLine.setLength( 0 );
    4091           0 :                 aLine.append( nStreamLengthObject );
    4092           0 :                 aLine.append( " 0 obj\n" );
    4093           0 :                 aLine.append( (sal_Int64)(nEndPos-nStartPos) );
    4094           0 :                 aLine.append( "\nendobj\n\n" );
    4095           0 :                 if ( !writeBuffer( aLine.getStr(), aLine.getLength() ) ) return false;
    4096             : 
    4097             :                 // write font descriptor
    4098           0 :                 sal_Int32 nFontDescriptor = emitFontDescriptor( it->first, aSubsetInfo, lit->m_nFontID, nFontStream );
    4099             : 
    4100           0 :                 if( nToUnicodeStream )
    4101           0 :                     nToUnicodeStream = createToUnicodeCMap( pEncoding, &aUnicodes[0], pUnicodesPerGlyph, pEncToUnicodeIndex, nGlyphs );
    4102             : 
    4103           0 :                 sal_Int32 nFontObject = createObject();
    4104           0 :                 if ( !updateObject( nFontObject ) ) return false;
    4105           0 :                 aLine.setLength( 0 );
    4106           0 :                 aLine.append( nFontObject );
    4107             : 
    4108           0 :                 aLine.append( " 0 obj\n" );
    4109           0 :                 aLine.append( ((aSubsetInfo.m_nFontType & FontSubsetInfo::ANY_TYPE1) != 0) ?
    4110             :                              "<</Type/Font/Subtype/Type1/BaseFont/" :
    4111           0 :                              "<</Type/Font/Subtype/TrueType/BaseFont/" );
    4112           0 :                 appendSubsetName( lit->m_nFontID, aSubsetInfo.m_aPSName, aLine );
    4113             :                 aLine.append( "\n"
    4114             :                              "/FirstChar 0\n"
    4115           0 :                              "/LastChar " );
    4116           0 :                 aLine.append( (sal_Int32)(nGlyphs-1) );
    4117             :                 aLine.append( "\n"
    4118           0 :                              "/Widths[" );
    4119           0 :                 for( int i = 0; i < nGlyphs; i++ )
    4120             :                 {
    4121           0 :                     aLine.append( pWidths[ i ] );
    4122           0 :                     aLine.append( ((i & 15) == 15) ? "\n" : " " );
    4123             :                 }
    4124             :                 aLine.append( "]\n"
    4125           0 :                              "/FontDescriptor " );
    4126           0 :                 aLine.append( nFontDescriptor );
    4127           0 :                 aLine.append( " 0 R\n" );
    4128           0 :                 if( nToUnicodeStream )
    4129             :                 {
    4130           0 :                     aLine.append( "/ToUnicode " );
    4131           0 :                     aLine.append( nToUnicodeStream );
    4132           0 :                     aLine.append( " 0 R\n" );
    4133             :                 }
    4134             :                 aLine.append( ">>\n"
    4135           0 :                              "endobj\n\n" );
    4136           0 :                 if ( !writeBuffer( aLine.getStr(), aLine.getLength() ) ) return false;
    4137             : 
    4138           0 :                 aFontIDToObject[ lit->m_nFontID ] = nFontObject;
    4139             :             }
    4140             :             else
    4141             :             {
    4142           0 :                 const PhysicalFontFace* pFont = it->first;
    4143           0 :                 OStringBuffer aErrorComment( 256 );
    4144           0 :                 aErrorComment.append( "CreateFontSubset failed for font \"" );
    4145           0 :                 aErrorComment.append( OUStringToOString( pFont->GetFamilyName(), RTL_TEXTENCODING_UTF8 ) );
    4146           0 :                 aErrorComment.append( '\"' );
    4147           0 :                 if( pFont->GetSlant() == ITALIC_NORMAL )
    4148           0 :                     aErrorComment.append( " italic" );
    4149           0 :                 else if( pFont->GetSlant() == ITALIC_OBLIQUE )
    4150           0 :                     aErrorComment.append( " oblique" );
    4151           0 :                 aErrorComment.append( " weight=" );
    4152           0 :                 aErrorComment.append( sal_Int32(pFont->GetWeight()) );
    4153           0 :                 emitComment( aErrorComment.getStr() );
    4154             :             }
    4155           0 :         }
    4156             :     }
    4157           0 :     osl_removeFile( aTmpName.pData );
    4158             : 
    4159             :     // emit embedded fonts
    4160           0 :     for( FontEmbedData::iterator eit = m_aEmbeddedFonts.begin(); eit != m_aEmbeddedFonts.end(); ++eit )
    4161             :     {
    4162           0 :         std::map< sal_Int32, sal_Int32 > aObjects = emitEmbeddedFont( eit->first, eit->second );
    4163           0 :         for( std::map< sal_Int32, sal_Int32 >::iterator fit = aObjects.begin(); fit != aObjects.end(); ++fit )
    4164             :         {
    4165           0 :             if ( !fit->second ) return false;
    4166           0 :             aFontIDToObject[ fit->first ] = fit->second;
    4167             :         }
    4168           0 :     }
    4169             : 
    4170             :     // emit system fonts
    4171           0 :     for( FontEmbedData::iterator sit = m_aSystemFonts.begin(); sit != m_aSystemFonts.end(); ++sit )
    4172             :     {
    4173           0 :         std::map< sal_Int32, sal_Int32 > aObjects = emitSystemFont( sit->first, sit->second );
    4174           0 :         for( std::map< sal_Int32, sal_Int32 >::iterator fit = aObjects.begin(); fit != aObjects.end(); ++fit )
    4175             :         {
    4176           0 :             if ( !fit->second ) return false;
    4177           0 :             aFontIDToObject[ fit->first ] = fit->second;
    4178             :         }
    4179           0 :     }
    4180             : 
    4181           0 :     OStringBuffer aFontDict( 1024 );
    4182           0 :     aFontDict.append( getFontDictObject() );
    4183             :     aFontDict.append( " 0 obj\n"
    4184           0 :                      "<<" );
    4185           0 :     int ni = 0;
    4186           0 :     for( std::map< sal_Int32, sal_Int32 >::iterator mit = aFontIDToObject.begin(); mit != aFontIDToObject.end(); ++mit )
    4187             :     {
    4188           0 :         aFontDict.append( "/F" );
    4189           0 :         aFontDict.append( mit->first );
    4190           0 :         aFontDict.append( ' ' );
    4191           0 :         aFontDict.append( mit->second );
    4192           0 :         aFontDict.append( " 0 R" );
    4193           0 :         if( ((++ni) & 7) == 0 )
    4194           0 :             aFontDict.append( '\n' );
    4195             :     }
    4196             :     // emit builtin font for widget appearances / variable text
    4197           0 :     for( std::map< sal_Int32, sal_Int32 >::iterator it = m_aBuiltinFontToObjectMap.begin();
    4198           0 :         it != m_aBuiltinFontToObjectMap.end(); ++it )
    4199             :     {
    4200           0 :         ImplPdfBuiltinFontData aData(m_aBuiltinFonts[it->first]);
    4201           0 :         it->second = emitBuiltinFont( &aData, it->second );
    4202           0 :     }
    4203           0 :     appendBuiltinFontsToDict( aFontDict );
    4204           0 :     aFontDict.append( "\n>>\nendobj\n\n" );
    4205             : 
    4206           0 :     if ( !updateObject( getFontDictObject() ) ) return false;
    4207           0 :     if ( !writeBuffer( aFontDict.getStr(), aFontDict.getLength() ) ) return false;
    4208           0 :     return true;
    4209             : }
    4210             : 
    4211           0 : sal_Int32 PDFWriterImpl::emitResources()
    4212             : {
    4213             :     // emit shadings
    4214           0 :     if( ! m_aGradients.empty() )
    4215           0 :         CHECK_RETURN( emitGradients() );
    4216             :     // emit tilings
    4217           0 :     if( ! m_aTilings.empty() )
    4218           0 :         CHECK_RETURN( emitTilings() );
    4219             : 
    4220             :     // emit font dict
    4221           0 :     CHECK_RETURN( emitFonts() );
    4222             : 
    4223             :     // emit Resource dict
    4224           0 :     OStringBuffer aLine( 512 );
    4225           0 :     sal_Int32 nResourceDict = getResourceDictObj();
    4226           0 :     CHECK_RETURN( updateObject( nResourceDict ) );
    4227           0 :     aLine.setLength( 0 );
    4228           0 :     aLine.append( nResourceDict );
    4229           0 :     aLine.append( " 0 obj\n" );
    4230           0 :     m_aGlobalResourceDict.append( aLine, getFontDictObject() );
    4231           0 :     aLine.append( "endobj\n\n" );
    4232           0 :     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
    4233           0 :     return nResourceDict;
    4234             : }
    4235             : 
    4236           0 : sal_Int32 PDFWriterImpl::updateOutlineItemCount( std::vector< sal_Int32 >& rCounts,
    4237             :                                                  sal_Int32 nItemLevel,
    4238             :                                                  sal_Int32 nCurrentItemId )
    4239             : {
    4240             :     /* The /Count number of an item is
    4241             :        positive: the number of visible subitems
    4242             :        negative: the negative number of subitems that will become visible if
    4243             :                  the item gets opened
    4244             :        see PDF ref 1.4 p 478
    4245             :     */
    4246             : 
    4247           0 :     sal_Int32 nCount = 0;
    4248             : 
    4249           0 :     if( m_aContext.OpenBookmarkLevels < 0           || // all levels arevisible
    4250           0 :         m_aContext.OpenBookmarkLevels >= nItemLevel    // this level is visible
    4251             :       )
    4252             :     {
    4253           0 :         PDFOutlineEntry& rItem = m_aOutline[ nCurrentItemId ];
    4254           0 :         sal_Int32 nChildren = rItem.m_aChildren.size();
    4255           0 :         for( sal_Int32 i = 0; i < nChildren; i++ )
    4256           0 :             nCount += updateOutlineItemCount( rCounts, nItemLevel+1, rItem.m_aChildren[i] );
    4257           0 :         rCounts[nCurrentItemId] = nCount;
    4258             :         // return 1 (this item) + visible sub items
    4259           0 :         if( nCount < 0 )
    4260           0 :             nCount = 0;
    4261           0 :         nCount++;
    4262             :     }
    4263             :     else
    4264             :     {
    4265             :         // this bookmark level is invisible
    4266           0 :         PDFOutlineEntry& rItem = m_aOutline[ nCurrentItemId ];
    4267           0 :         sal_Int32 nChildren = rItem.m_aChildren.size();
    4268           0 :         rCounts[ nCurrentItemId ] = -sal_Int32(rItem.m_aChildren.size());
    4269           0 :         for( sal_Int32 i = 0; i < nChildren; i++ )
    4270           0 :             updateOutlineItemCount( rCounts, nItemLevel+1, rItem.m_aChildren[i] );
    4271           0 :         nCount = -1;
    4272             :     }
    4273             : 
    4274           0 :     return nCount;
    4275             : }
    4276             : 
    4277           0 : sal_Int32 PDFWriterImpl::emitOutline()
    4278             : {
    4279           0 :     int i, nItems = m_aOutline.size();
    4280             : 
    4281             :     // do we have an outline at all ?
    4282           0 :     if( nItems < 2 )
    4283           0 :         return 0;
    4284             : 
    4285             :     // reserve object numbers for all outline items
    4286           0 :     for( i = 0; i < nItems; ++i )
    4287           0 :         m_aOutline[i].m_nObject = createObject();
    4288             : 
    4289             :     // update all parent, next and prev object ids
    4290           0 :     for( i = 0; i < nItems; ++i )
    4291             :     {
    4292           0 :         PDFOutlineEntry& rItem = m_aOutline[i];
    4293           0 :         int nChildren = rItem.m_aChildren.size();
    4294             : 
    4295           0 :         if( nChildren )
    4296             :         {
    4297           0 :             for( int n = 0; n < nChildren; ++n )
    4298             :             {
    4299           0 :                 PDFOutlineEntry& rChild = m_aOutline[ rItem.m_aChildren[n] ];
    4300             : 
    4301           0 :                 rChild.m_nParentObject = rItem.m_nObject;
    4302           0 :                 rChild.m_nPrevObject = (n > 0) ? m_aOutline[ rItem.m_aChildren[n-1] ].m_nObject : 0;
    4303           0 :                 rChild.m_nNextObject = (n < nChildren-1) ? m_aOutline[ rItem.m_aChildren[n+1] ].m_nObject : 0;
    4304             :             }
    4305             : 
    4306             :         }
    4307             :     }
    4308             : 
    4309             :     // calculate Count entries for all items
    4310           0 :     std::vector< sal_Int32 > aCounts( nItems );
    4311           0 :     updateOutlineItemCount( aCounts, 0, 0 );
    4312             : 
    4313             :     // emit hierarchy
    4314           0 :     for( i = 0; i < nItems; ++i )
    4315             :     {
    4316           0 :         PDFOutlineEntry& rItem = m_aOutline[i];
    4317           0 :         OStringBuffer aLine( 1024 );
    4318             : 
    4319           0 :         CHECK_RETURN( updateObject( rItem.m_nObject ) );
    4320           0 :         aLine.append( rItem.m_nObject );
    4321           0 :         aLine.append( " 0 obj\n" );
    4322           0 :         aLine.append( "<<" );
    4323             :         // number of visible children (all levels)
    4324           0 :         if( i > 0 || aCounts[0] > 0 )
    4325             :         {
    4326           0 :             aLine.append( "/Count " );
    4327           0 :             aLine.append( aCounts[i] );
    4328             :         }
    4329           0 :         if( ! rItem.m_aChildren.empty() )
    4330             :         {
    4331             :             // children list: First, Last
    4332           0 :             aLine.append( "/First " );
    4333           0 :             aLine.append( m_aOutline[rItem.m_aChildren.front()].m_nObject );
    4334           0 :             aLine.append( " 0 R/Last " );
    4335           0 :             aLine.append( m_aOutline[rItem.m_aChildren.back()].m_nObject );
    4336           0 :             aLine.append( " 0 R\n" );
    4337             :         }
    4338           0 :         if( i > 0 )
    4339             :         {
    4340             :             // Title, Dest, Parent, Prev, Next
    4341           0 :             aLine.append( "/Title" );
    4342           0 :             appendUnicodeTextStringEncrypt( rItem.m_aTitle, rItem.m_nObject, aLine );
    4343           0 :             aLine.append( "\n" );
    4344             :             // Dest is not required
    4345           0 :             if( rItem.m_nDestID >= 0 && rItem.m_nDestID < (sal_Int32)m_aDests.size() )
    4346             :             {
    4347           0 :                 aLine.append( "/Dest" );
    4348           0 :                 appendDest( rItem.m_nDestID, aLine );
    4349             :             }
    4350           0 :             aLine.append( "/Parent " );
    4351           0 :             aLine.append( rItem.m_nParentObject );
    4352           0 :             aLine.append( " 0 R" );
    4353           0 :             if( rItem.m_nPrevObject )
    4354             :             {
    4355           0 :                 aLine.append( "/Prev " );
    4356           0 :                 aLine.append( rItem.m_nPrevObject );
    4357           0 :                 aLine.append( " 0 R" );
    4358             :             }
    4359           0 :             if( rItem.m_nNextObject )
    4360             :             {
    4361           0 :                 aLine.append( "/Next " );
    4362           0 :                 aLine.append( rItem.m_nNextObject );
    4363           0 :                 aLine.append( " 0 R" );
    4364             :             }
    4365             :         }
    4366           0 :         aLine.append( ">>\nendobj\n\n" );
    4367           0 :         CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
    4368           0 :     }
    4369             : 
    4370           0 :     return m_aOutline[0].m_nObject;
    4371             : }
    4372             : 
    4373             : #undef CHECK_RETURN
    4374             : #define CHECK_RETURN( x ) if( !x ) return false
    4375             : 
    4376           0 : bool PDFWriterImpl::appendDest( sal_Int32 nDestID, OStringBuffer& rBuffer )
    4377             : {
    4378           0 :     if( nDestID < 0 || nDestID >= (sal_Int32)m_aDests.size() )
    4379             :     {
    4380             : #if OSL_DEBUG_LEVEL > 1
    4381             :         fprintf( stderr, "ERROR: invalid dest %d requested\n", (int)nDestID );
    4382             : #endif
    4383           0 :         return false;
    4384             :     }
    4385             : 
    4386           0 :     const PDFDest& rDest        = m_aDests[ nDestID ];
    4387           0 :     const PDFPage& rDestPage    = m_aPages[ rDest.m_nPage ];
    4388             : 
    4389           0 :     rBuffer.append( '[' );
    4390           0 :     rBuffer.append( rDestPage.m_nPageObject );
    4391           0 :     rBuffer.append( " 0 R" );
    4392             : 
    4393           0 :     switch( rDest.m_eType )
    4394             :     {
    4395             :         case PDFWriter::XYZ:
    4396             :         default:
    4397           0 :             rBuffer.append( "/XYZ " );
    4398           0 :             appendFixedInt( rDest.m_aRect.Left(), rBuffer );
    4399           0 :             rBuffer.append( ' ' );
    4400           0 :             appendFixedInt( rDest.m_aRect.Bottom(), rBuffer );
    4401           0 :             rBuffer.append( " 0" );
    4402           0 :             break;
    4403             :         case PDFWriter::Fit:
    4404           0 :             rBuffer.append( "/Fit" );
    4405           0 :             break;
    4406             :         case PDFWriter::FitRectangle:
    4407           0 :             rBuffer.append( "/FitR " );
    4408           0 :             appendFixedInt( rDest.m_aRect.Left(), rBuffer );
    4409           0 :             rBuffer.append( ' ' );
    4410           0 :             appendFixedInt( rDest.m_aRect.Top(), rBuffer );
    4411           0 :             rBuffer.append( ' ' );
    4412           0 :             appendFixedInt( rDest.m_aRect.Right(), rBuffer );
    4413           0 :             rBuffer.append( ' ' );
    4414           0 :             appendFixedInt( rDest.m_aRect.Bottom(), rBuffer );
    4415           0 :             break;
    4416             :         case PDFWriter::FitHorizontal:
    4417           0 :             rBuffer.append( "/FitH " );
    4418           0 :             appendFixedInt( rDest.m_aRect.Bottom(), rBuffer );
    4419           0 :             break;
    4420             :         case PDFWriter::FitVertical:
    4421           0 :             rBuffer.append( "/FitV " );
    4422           0 :             appendFixedInt( rDest.m_aRect.Left(), rBuffer );
    4423           0 :             break;
    4424             :         case PDFWriter::FitPageBoundingBox:
    4425           0 :             rBuffer.append( "/FitB" );
    4426           0 :             break;
    4427             :         case PDFWriter::FitPageBoundingBoxHorizontal:
    4428           0 :             rBuffer.append( "/FitBH " );
    4429           0 :             appendFixedInt( rDest.m_aRect.Bottom(), rBuffer );
    4430           0 :             break;
    4431             :         case PDFWriter::FitPageBoundingBoxVertical:
    4432           0 :             rBuffer.append( "/FitBV " );
    4433           0 :             appendFixedInt( rDest.m_aRect.Left(), rBuffer );
    4434           0 :             break;
    4435             :     }
    4436           0 :     rBuffer.append( ']' );
    4437             : 
    4438           0 :     return true;
    4439             : }
    4440             : 
    4441           0 : bool PDFWriterImpl::emitLinkAnnotations()
    4442             : {
    4443           0 :     int nAnnots = m_aLinks.size();
    4444           0 :     for( int i = 0; i < nAnnots; i++ )
    4445             :     {
    4446           0 :         const PDFLink& rLink            = m_aLinks[i];
    4447           0 :         if( ! updateObject( rLink.m_nObject ) )
    4448           0 :             continue;
    4449             : 
    4450           0 :         OStringBuffer aLine( 1024 );
    4451           0 :         aLine.append( rLink.m_nObject );
    4452           0 :         aLine.append( " 0 obj\n" );
    4453             : //i59651  key /F set bits Print to 1 rest to 0. We don't set NoZoom NoRotate to 1, since it's a 'should'
    4454             : // see PDF 8.4.2 and ISO 19005-1:2005 6.5.3
    4455           0 :         aLine.append( "<</Type/Annot" );
    4456           0 :         if( m_bIsPDF_A1 )
    4457           0 :             aLine.append( "/F 4" );
    4458           0 :         aLine.append( "/Subtype/Link/Border[0 0 0]/Rect[" );
    4459             : 
    4460           0 :         appendFixedInt( rLink.m_aRect.Left()-7, aLine );//the +7 to have a better shape of the border rectangle
    4461           0 :         aLine.append( ' ' );
    4462           0 :         appendFixedInt( rLink.m_aRect.Top(), aLine );
    4463           0 :         aLine.append( ' ' );
    4464           0 :         appendFixedInt( rLink.m_aRect.Right()+7, aLine );//the +7 to have a better shape of the border rectangle
    4465           0 :         aLine.append( ' ' );
    4466           0 :         appendFixedInt( rLink.m_aRect.Bottom(), aLine );
    4467           0 :         aLine.append( "]" );
    4468           0 :         if( rLink.m_nDest >= 0 )
    4469             :         {
    4470           0 :             aLine.append( "/Dest" );
    4471           0 :             appendDest( rLink.m_nDest, aLine );
    4472             :         }
    4473             :         else
    4474             :         {
    4475             : /*--->i56629
    4476             : destination is external to the document, so
    4477             : we check in the following sequence:
    4478             : 
    4479             :  if target type is neither .pdf, nor .od[tpgs], then
    4480             :           check if relative or absolute and act accordingly (use URI or 'launch application' as requested)
    4481             :                              end processing
    4482             :  else if target is .od[tpgs]: then
    4483             :       if conversion of type from od[tpgs]  to pdf is requested, convert it and this becomes the new target file
    4484             :       processing continue
    4485             : 
    4486             :  if (new)target is .pdf : then
    4487             :      if GotToR is requested, then
    4488             :            convert the target in GoToR where the fragment of the URI is
    4489             :            considered the named destination in the target file, set relative or absolute as requested
    4490             :      else strip the fragment from URL and then set URI or 'launch application' as requested
    4491             : */
    4492             : 
    4493             : // FIXME: check if the decode mechanisms for URL processing throughout this implementation
    4494             : // are the correct one!!
    4495             : 
    4496             : // extract target file type
    4497           0 :             INetURLObject aDocumentURL( m_aContext.BaseURL );
    4498           0 :             INetURLObject aTargetURL( rLink.m_aURL );
    4499           0 :             sal_Int32   nSetGoToRMode = 0;
    4500           0 :             bool    bTargetHasPDFExtension = false;
    4501           0 :             INetProtocol eTargetProtocol = aTargetURL.GetProtocol();
    4502           0 :             bool    bIsUNCPath = false;
    4503             : 
    4504             :             // check if the protocol is a known one, or if there is no protocol at all (on target only)
    4505             :             // if there is no protocol, make the target relative to the current document directory
    4506             :             // getting the needed URL information from the current document path
    4507           0 :             if( eTargetProtocol == INetProtocol::NotValid )
    4508             :             {
    4509           0 :                 if( rLink.m_aURL.getLength() > 4 && rLink.m_aURL.startsWith("\\\\\\\\"))
    4510             :                 {
    4511           0 :                     bIsUNCPath = true;
    4512             :                 }
    4513             :                 else
    4514             :                 {
    4515           0 :                     INetURLObject aNewBase( aDocumentURL );//duplicate document URL
    4516           0 :                     aNewBase.removeSegment(); //remove last segment from it, obtaining the base URL of the
    4517             :                                               //target document
    4518           0 :                     aNewBase.insertName( rLink.m_aURL );
    4519           0 :                     aTargetURL = aNewBase;//reassign the new target URL
    4520             :                     //recompute the target protocol, with the new URL
    4521             :                     //normal URL processing resumes
    4522           0 :                     eTargetProtocol = aTargetURL.GetProtocol();
    4523             :                 }
    4524             :             }
    4525             : 
    4526           0 :             OUString aFileExtension = aTargetURL.GetFileExtension();
    4527             : 
    4528             :             // Check if the URL ends in '/': if yes it's a directory,
    4529             :             // it will be forced to a URI link.
    4530             :             // possibly a malformed URI, leave it as it is, force as URI
    4531           0 :             if( aTargetURL.hasFinalSlash() )
    4532           0 :                 m_aContext.DefaultLinkAction = PDFWriter::URIAction;
    4533             : 
    4534           0 :             if( !aFileExtension.isEmpty() )
    4535             :             {
    4536           0 :                 if( m_aContext.ConvertOOoTargetToPDFTarget )
    4537             :                 {
    4538           0 :                     bool bChangeFileExtensionToPDF = false;
    4539             :                     //examine the file type (.odm .odt. .odp, odg, ods)
    4540           0 :                     if( aFileExtension.equalsIgnoreAsciiCase( "odm" ) )
    4541           0 :                         bChangeFileExtensionToPDF = true;
    4542           0 :                     if( aFileExtension.equalsIgnoreAsciiCase( "odt" ) )
    4543           0 :                         bChangeFileExtensionToPDF = true;
    4544           0 :                     else if( aFileExtension.equalsIgnoreAsciiCase( "odp" ) )
    4545           0 :                         bChangeFileExtensionToPDF = true;
    4546           0 :                     else if( aFileExtension.equalsIgnoreAsciiCase( "odg" ) )
    4547           0 :                         bChangeFileExtensionToPDF = true;
    4548           0 :                     else if( aFileExtension.equalsIgnoreAsciiCase( "ods" ) )
    4549           0 :                         bChangeFileExtensionToPDF = true;
    4550           0 :                     if( bChangeFileExtensionToPDF )
    4551           0 :                         aTargetURL.setExtension(OUString( "pdf"  ) );
    4552             :                 }
    4553             :                 //check if extension is pdf, see if GoToR should be forced
    4554           0 :                 bTargetHasPDFExtension = aTargetURL.GetFileExtension().equalsIgnoreAsciiCase( "pdf" );
    4555           0 :                 if( m_aContext.ForcePDFAction && bTargetHasPDFExtension )
    4556           0 :                     nSetGoToRMode++;
    4557             :             }
    4558             :             //prepare the URL, if relative or not
    4559           0 :             INetProtocol eBaseProtocol = aDocumentURL.GetProtocol();
    4560             :             //queue the string common to all types of actions
    4561           0 :             aLine.append( "/A<</Type/Action/S");
    4562           0 :             if( bIsUNCPath ) // handle Win UNC paths
    4563             :             {
    4564           0 :                 aLine.append( "/Launch/Win<</F" );
    4565             :                 // INetURLObject is not good with UNC paths, use original path
    4566           0 :                 appendLiteralStringEncrypt(  rLink.m_aURL, rLink.m_nObject, aLine, osl_getThreadTextEncoding() );
    4567           0 :                 aLine.append( ">>" );
    4568             :             }
    4569             :             else
    4570             :             {
    4571           0 :                 bool bSetRelative = false;
    4572           0 :                 bool bFileSpec = false;
    4573             :                 //check if relative file link is requested and if the protocol is 'file://'
    4574           0 :                 if( m_aContext.RelFsys && eBaseProtocol == eTargetProtocol && eTargetProtocol == INetProtocol::File )
    4575           0 :                     bSetRelative = true;
    4576             : 
    4577           0 :                 OUString aFragment = aTargetURL.GetMark( INetURLObject::NO_DECODE /*DECODE_WITH_CHARSET*/ ); //fragment as is,
    4578           0 :                 if( nSetGoToRMode == 0 )
    4579             :                 {
    4580           0 :                     switch( m_aContext.DefaultLinkAction )
    4581             :                     {
    4582             :                     default:
    4583             :                     case PDFWriter::URIAction :
    4584             :                     case PDFWriter::URIActionDestination :
    4585           0 :                         aLine.append( "/URI/URI" );
    4586           0 :                         break;
    4587             :                     case PDFWriter::LaunchAction:
    4588             :                         // now:
    4589             :                         // if a launch action is requested and the hyperlink target has a fragment
    4590             :                         // and the target file does not have a pdf extension, or it's not a 'file:://'
    4591             :                         // protocol then force the uri action on it
    4592             :                         // This code will permit the correct opening of application on web pages,
    4593             :                         // the one that normally have fragments (but I may be wrong...)
    4594             :                         // and will force the use of URI when the protocol is not file:
    4595           0 :                         if( (!aFragment.isEmpty() && !bTargetHasPDFExtension) ||
    4596             :                                         eTargetProtocol != INetProtocol::File )
    4597             :                         {
    4598           0 :                             aLine.append( "/URI/URI" );
    4599             :                         }
    4600             :                         else
    4601             :                         {
    4602           0 :                             aLine.append( "/Launch/F" );
    4603           0 :                             bFileSpec = true;
    4604             :                         }
    4605           0 :                         break;
    4606             :                     }
    4607             :                 }
    4608             : 
    4609             :                 //fragment are encoded in the same way as in the named destination processing
    4610           0 :                 if( nSetGoToRMode )
    4611             :                 {
    4612             :                     //add the fragment
    4613           0 :                     OUString aURLNoMark = aTargetURL.GetURLNoMark( INetURLObject::DECODE_WITH_CHARSET );
    4614           0 :                     aLine.append("/GoToR");
    4615           0 :                     aLine.append("/F");
    4616           0 :                     bFileSpec = true;
    4617             :                     appendLiteralStringEncrypt( bSetRelative ? INetURLObject::GetRelURL( m_aContext.BaseURL, aURLNoMark,
    4618             :                                                                                          INetURLObject::WAS_ENCODED,
    4619             :                                                                                          INetURLObject::DECODE_WITH_CHARSET ) :
    4620           0 :                                                                    aURLNoMark, rLink.m_nObject, aLine, osl_getThreadTextEncoding() );
    4621           0 :                     if( !aFragment.isEmpty() )
    4622             :                     {
    4623           0 :                         aLine.append("/D/");
    4624           0 :                         appendDestinationName( aFragment , aLine );
    4625           0 :                     }
    4626             :                 }
    4627             :                 else
    4628             :                 {
    4629             :                     // change the fragment to accommodate the bookmark (only if the file extension
    4630             :                     // is PDF and the requested action is of the correct type)
    4631           0 :                     if(m_aContext.DefaultLinkAction == PDFWriter::URIActionDestination &&
    4632           0 :                                bTargetHasPDFExtension && !aFragment.isEmpty() )
    4633             :                     {
    4634           0 :                         OStringBuffer aLineLoc( 1024 );
    4635           0 :                         appendDestinationName( aFragment , aLineLoc );
    4636             :                         //substitute the fragment
    4637           0 :                         aTargetURL.SetMark( OStringToOUString(aLineLoc.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US) );
    4638             :                     }
    4639           0 :                     OUString aURL = aTargetURL.GetMainURL( bFileSpec ? INetURLObject::DECODE_WITH_CHARSET : INetURLObject::NO_DECODE );
    4640             :                     appendLiteralStringEncrypt(bSetRelative ? INetURLObject::GetRelURL( m_aContext.BaseURL, aURL,
    4641             :                                                                                         INetURLObject::WAS_ENCODED,
    4642             :                                                                                             bFileSpec ? INetURLObject::DECODE_WITH_CHARSET : INetURLObject::NO_DECODE
    4643             :                                                                                             ) :
    4644           0 :                                                                                aURL , rLink.m_nObject, aLine, osl_getThreadTextEncoding() );
    4645           0 :                 }
    4646             : //<--- i56629
    4647             :             }
    4648           0 :             aLine.append( ">>\n" );
    4649             :         }
    4650           0 :         if( rLink.m_nStructParent > 0 )
    4651             :         {
    4652           0 :             aLine.append( "/StructParent " );
    4653           0 :             aLine.append( rLink.m_nStructParent );
    4654             :         }
    4655           0 :         aLine.append( ">>\nendobj\n\n" );
    4656           0 :         CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
    4657           0 :     }
    4658             : 
    4659           0 :     return true;
    4660             : }
    4661             : 
    4662           0 : bool PDFWriterImpl::emitNoteAnnotations()
    4663             : {
    4664             :     // emit note annotations
    4665           0 :     int nAnnots = m_aNotes.size();
    4666           0 :     for( int i = 0; i < nAnnots; i++ )
    4667             :     {
    4668           0 :         const PDFNoteEntry& rNote       = m_aNotes[i];
    4669           0 :         if( ! updateObject( rNote.m_nObject ) )
    4670           0 :             return false;
    4671             : 
    4672           0 :         OStringBuffer aLine( 1024 );
    4673           0 :         aLine.append( rNote.m_nObject );
    4674           0 :         aLine.append( " 0 obj\n" );
    4675             : //i59651  key /F set bits Print to 1 rest to 0. We don't set NoZoom NoRotate to 1, since it's a 'should'
    4676             : // see PDF 8.4.2 and ISO 19005-1:2005 6.5.3
    4677           0 :         aLine.append( "<</Type/Annot" );
    4678           0 :         if( m_bIsPDF_A1 )
    4679           0 :             aLine.append( "/F 4" );
    4680           0 :         aLine.append( "/Subtype/Text/Rect[" );
    4681             : 
    4682           0 :         appendFixedInt( rNote.m_aRect.Left(), aLine );
    4683           0 :         aLine.append( ' ' );
    4684           0 :         appendFixedInt( rNote.m_aRect.Top(), aLine );
    4685           0 :         aLine.append( ' ' );
    4686           0 :         appendFixedInt( rNote.m_aRect.Right(), aLine );
    4687           0 :         aLine.append( ' ' );
    4688           0 :         appendFixedInt( rNote.m_aRect.Bottom(), aLine );
    4689           0 :         aLine.append( "]" );
    4690             : 
    4691             :         // contents of the note (type text string)
    4692           0 :         aLine.append( "/Contents\n" );
    4693           0 :         appendUnicodeTextStringEncrypt( rNote.m_aContents.Contents, rNote.m_nObject, aLine );
    4694           0 :         aLine.append( "\n" );
    4695             : 
    4696             :         // optional title
    4697           0 :         if( !rNote.m_aContents.Title.isEmpty() )
    4698             :         {
    4699           0 :             aLine.append( "/T" );
    4700           0 :             appendUnicodeTextStringEncrypt( rNote.m_aContents.Title, rNote.m_nObject, aLine );
    4701           0 :             aLine.append( "\n" );
    4702             :         }
    4703             : 
    4704           0 :         aLine.append( ">>\nendobj\n\n" );
    4705           0 :         CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
    4706           0 :     }
    4707           0 :     return true;
    4708             : }
    4709             : 
    4710           0 : Font PDFWriterImpl::replaceFont( const vcl::Font& rControlFont, const vcl::Font&  rAppSetFont )
    4711             : {
    4712           0 :     bool bAdjustSize = false;
    4713             : 
    4714           0 :     Font aFont( rControlFont );
    4715           0 :     if( aFont.GetName().isEmpty() )
    4716             :     {
    4717           0 :         aFont = rAppSetFont;
    4718           0 :         if( rControlFont.GetHeight() )
    4719           0 :             aFont.SetSize( Size( 0, rControlFont.GetHeight() ) );
    4720             :         else
    4721           0 :             bAdjustSize = true;
    4722           0 :         if( rControlFont.GetItalic() != ITALIC_DONTKNOW )
    4723           0 :             aFont.SetItalic( rControlFont.GetItalic() );
    4724           0 :         if( rControlFont.GetWeight() != WEIGHT_DONTKNOW )
    4725           0 :             aFont.SetWeight( rControlFont.GetWeight() );
    4726             :     }
    4727           0 :     else if( ! aFont.GetHeight() )
    4728             :     {
    4729           0 :         aFont.SetSize( rAppSetFont.GetSize() );
    4730           0 :         bAdjustSize = true;
    4731             :     }
    4732           0 :     if( bAdjustSize )
    4733             :     {
    4734           0 :         Size aFontSize = aFont.GetSize();
    4735           0 :         OutputDevice* pDefDev = Application::GetDefaultDevice();
    4736           0 :         aFontSize = OutputDevice::LogicToLogic( aFontSize, pDefDev->GetMapMode(), getMapMode() );
    4737           0 :         aFont.SetSize( aFontSize );
    4738             :     }
    4739           0 :     return aFont;
    4740             : }
    4741             : 
    4742           0 : sal_Int32 PDFWriterImpl::getBestBuiltinFont( const vcl::Font& rFont )
    4743             : {
    4744           0 :     sal_Int32 nBest = 4; // default to Helvetica
    4745           0 :     OUString aFontName( rFont.GetName() );
    4746           0 :     aFontName = aFontName.toAsciiLowerCase();
    4747             : 
    4748           0 :     if( aFontName.indexOf( "times" ) != -1 )
    4749           0 :         nBest = 8;
    4750           0 :     else if( aFontName.indexOf( "courier" ) != -1 )
    4751           0 :         nBest = 0;
    4752           0 :     else if( aFontName.indexOf( "dingbats" ) != -1 )
    4753           0 :         nBest = 13;
    4754           0 :     else if( aFontName.indexOf( "symbol" ) != -1 )
    4755           0 :         nBest = 12;
    4756           0 :     if( nBest < 12 )
    4757             :     {
    4758           0 :         if( rFont.GetItalic() == ITALIC_OBLIQUE || rFont.GetItalic() == ITALIC_NORMAL )
    4759           0 :             nBest += 1;
    4760           0 :         if( rFont.GetWeight() > WEIGHT_MEDIUM )
    4761           0 :             nBest += 2;
    4762             :     }
    4763             : 
    4764           0 :     if( m_aBuiltinFontToObjectMap.find( nBest ) == m_aBuiltinFontToObjectMap.end() )
    4765           0 :         m_aBuiltinFontToObjectMap[ nBest ] = createObject();
    4766             : 
    4767           0 :     return nBest;
    4768             : }
    4769             : 
    4770           0 : static inline const Color& replaceColor( const Color& rCol1, const Color& rCol2 )
    4771             : {
    4772           0 :     return (rCol1 == Color( COL_TRANSPARENT )) ? rCol2 : rCol1;
    4773             : }
    4774             : 
    4775           0 : void PDFWriterImpl::createDefaultPushButtonAppearance( PDFWidget& rButton, const PDFWriter::PushButtonWidget& rWidget )
    4776             : {
    4777           0 :     const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
    4778             : 
    4779             :     // save graphics state
    4780           0 :     push( PushFlags::ALL );
    4781             : 
    4782             :     // transform relative to control's coordinates since an
    4783             :     // appearance stream is a form XObject
    4784             :     // this relies on the m_aRect member of rButton NOT already being transformed
    4785             :     // to default user space
    4786           0 :     if( rWidget.Background || rWidget.Border )
    4787             :     {
    4788           0 :         setLineColor( rWidget.Border ? replaceColor( rWidget.BorderColor, rSettings.GetLightColor() ) : Color( COL_TRANSPARENT ) );
    4789           0 :         setFillColor( rWidget.Background ? replaceColor( rWidget.BackgroundColor, rSettings.GetDialogColor() ) : Color( COL_TRANSPARENT ) );
    4790           0 :         drawRectangle( rWidget.Location );
    4791             :     }
    4792             :     // prepare font to use
    4793           0 :     Font aFont = replaceFont( rWidget.TextFont, rSettings.GetPushButtonFont() );
    4794           0 :     setFont( aFont );
    4795           0 :     setTextColor( replaceColor( rWidget.TextColor, rSettings.GetButtonTextColor() ) );
    4796             : 
    4797           0 :     drawText( rButton.m_aRect, rButton.m_aText, rButton.m_nTextStyle );
    4798             : 
    4799             :     // create DA string while local mapmode is still in place
    4800             :     // (that is before endRedirect())
    4801           0 :     OStringBuffer aDA( 256 );
    4802           0 :     appendNonStrokingColor( replaceColor( rWidget.TextColor, rSettings.GetButtonTextColor() ), aDA );
    4803           0 :     Font aDummyFont( OUString( "Helvetica" ), aFont.GetSize() );
    4804           0 :     sal_Int32 nDummyBuiltin = getBestBuiltinFont( aDummyFont );
    4805           0 :     aDA.append( ' ' );
    4806           0 :     aDA.append( m_aBuiltinFonts[nDummyBuiltin].getNameObject() );
    4807           0 :     aDA.append( ' ' );
    4808           0 :     m_aPages[m_nCurrentPage].appendMappedLength( sal_Int32( aFont.GetHeight() ), aDA );
    4809           0 :     aDA.append( " Tf" );
    4810           0 :     rButton.m_aDAString = aDA.makeStringAndClear();
    4811             : 
    4812           0 :     pop();
    4813             : 
    4814           0 :     rButton.m_aAppearances[ "N" ][ "Standard" ] = new SvMemoryStream();
    4815             : 
    4816             :     /* seems like a bad hack but at least works in both AR5 and 6:
    4817             :        we draw the button ourselves and tell AR
    4818             :        the button would be totally transparent with no text
    4819             : 
    4820             :        One would expect that simply setting a normal appearance
    4821             :        should suffice, but no, as soon as the user actually presses
    4822             :        the button and an action is tied to it (gasp! a button that
    4823             :        does something) the appearance gets replaced by some crap that AR
    4824             :        creates on the fly even if no DA or MK is given. On AR6 at least
    4825             :        the DA and MK work as expected, but on AR5 this creates a region
    4826             :        filled with the background color but nor text. Urgh.
    4827             :     */
    4828           0 :     rButton.m_aMKDict = "/BC [] /BG [] /CA";
    4829           0 :     rButton.m_aMKDictCAString = "";
    4830           0 : }
    4831             : 
    4832           0 : Font PDFWriterImpl::drawFieldBorder( PDFWidget& rIntern,
    4833             :                                      const PDFWriter::AnyWidget& rWidget,
    4834             :                                      const StyleSettings& rSettings )
    4835             : {
    4836           0 :     Font aFont = replaceFont( rWidget.TextFont, rSettings.GetFieldFont() );
    4837             : 
    4838           0 :     if( rWidget.Background || rWidget.Border )
    4839             :     {
    4840           0 :         if( rWidget.Border && rWidget.BorderColor == Color( COL_TRANSPARENT ) )
    4841             :         {
    4842           0 :             sal_Int32 nDelta = getReferenceDevice()->GetDPIX() / 500;
    4843           0 :             if( nDelta < 1 )
    4844           0 :                 nDelta = 1;
    4845           0 :             setLineColor( Color( COL_TRANSPARENT ) );
    4846           0 :             Rectangle aRect = rIntern.m_aRect;
    4847           0 :             setFillColor( rSettings.GetLightBorderColor() );
    4848           0 :             drawRectangle( aRect );
    4849           0 :             aRect.Left()  += nDelta; aRect.Top()     += nDelta;
    4850           0 :             aRect.Right() -= nDelta; aRect.Bottom()  -= nDelta;
    4851           0 :             setFillColor( rSettings.GetFieldColor() );
    4852           0 :             drawRectangle( aRect );
    4853           0 :             setFillColor( rSettings.GetLightColor() );
    4854           0 :             drawRectangle( Rectangle( Point( aRect.Left(), aRect.Bottom()-nDelta ), aRect.BottomRight() ) );
    4855           0 :             drawRectangle( Rectangle( Point( aRect.Right()-nDelta, aRect.Top() ), aRect.BottomRight() ) );
    4856           0 :             setFillColor( rSettings.GetDarkShadowColor() );
    4857           0 :             drawRectangle( Rectangle( aRect.TopLeft(), Point( aRect.Left()+nDelta, aRect.Bottom() ) ) );
    4858           0 :             drawRectangle( Rectangle( aRect.TopLeft(), Point( aRect.Right(), aRect.Top()+nDelta ) ) );
    4859             :         }
    4860             :         else
    4861             :         {
    4862           0 :             setLineColor( rWidget.Border ? replaceColor( rWidget.BorderColor, rSettings.GetShadowColor() ) : Color( COL_TRANSPARENT ) );
    4863           0 :             setFillColor( rWidget.Background ? replaceColor( rWidget.BackgroundColor, rSettings.GetFieldColor() ) : Color( COL_TRANSPARENT ) );
    4864           0 :             drawRectangle( rIntern.m_aRect );
    4865             :         }
    4866             : 
    4867           0 :         if( rWidget.Border )
    4868             :         {
    4869             :             // adjust edit area accounting for border
    4870           0 :             sal_Int32 nDelta = aFont.GetHeight()/4;
    4871           0 :             if( nDelta < 1 )
    4872           0 :                 nDelta = 1;
    4873           0 :             rIntern.m_aRect.Left()  += nDelta;
    4874           0 :             rIntern.m_aRect.Top()   += nDelta;
    4875           0 :             rIntern.m_aRect.Right() -= nDelta;
    4876           0 :             rIntern.m_aRect.Bottom()-= nDelta;
    4877             :         }
    4878             :     }
    4879           0 :     return aFont;
    4880             : }
    4881             : 
    4882           0 : void PDFWriterImpl::createDefaultEditAppearance( PDFWidget& rEdit, const PDFWriter::EditWidget& rWidget )
    4883             : {
    4884           0 :     const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
    4885           0 :     SvMemoryStream* pEditStream = new SvMemoryStream( 1024, 1024 );
    4886             : 
    4887           0 :     push( PushFlags::ALL );
    4888             : 
    4889             :     // prepare font to use, draw field border
    4890           0 :     Font aFont = drawFieldBorder( rEdit, rWidget, rSettings );
    4891           0 :     sal_Int32 nBest = m_aContext.FieldsUseSystemFonts ? getSystemFont( aFont ): getBestBuiltinFont( aFont );
    4892             : 
    4893             :     // prepare DA string
    4894           0 :     OStringBuffer aDA( 32 );
    4895           0 :     appendNonStrokingColor( replaceColor( rWidget.TextColor, rSettings.GetFieldTextColor() ), aDA );
    4896           0 :     aDA.append( ' ' );
    4897           0 :     if( m_aContext.FieldsUseSystemFonts )
    4898             :     {
    4899           0 :         aDA.append( "/F" );
    4900           0 :         aDA.append( nBest );
    4901             : 
    4902           0 :         OStringBuffer aDR( 32 );
    4903           0 :         aDR.append( "/Font " );
    4904           0 :         aDR.append( getFontDictObject() );
    4905           0 :         aDR.append( " 0 R" );
    4906           0 :         rEdit.m_aDRDict = aDR.makeStringAndClear();
    4907             :     }
    4908             :     else
    4909           0 :         aDA.append( m_aBuiltinFonts[nBest].getNameObject() );
    4910           0 :     aDA.append( ' ' );
    4911           0 :     m_aPages[ m_nCurrentPage ].appendMappedLength( sal_Int32( aFont.GetHeight() ), aDA );
    4912           0 :     aDA.append( " Tf" );
    4913             : 
    4914             :     /*  create an empty appearance stream, let the viewer create
    4915             :         the appearance at runtime. This is because AR5 seems to
    4916             :         paint the widget appearance always, and a dynamically created
    4917             :         appearance on top of it. AR6 is well behaved in that regard, so
    4918             :         that behaviour seems to be a bug. Anyway this empty appearance
    4919             :         relies on /NeedAppearances in the AcroForm dictionary set to "true"
    4920             :      */
    4921           0 :     beginRedirect( pEditStream, rEdit.m_aRect );
    4922           0 :     OStringBuffer aAppearance( 32 );
    4923           0 :     aAppearance.append( "/Tx BMC\nEMC\n" );
    4924           0 :     writeBuffer( aAppearance.getStr(), aAppearance.getLength() );
    4925             : 
    4926           0 :     endRedirect();
    4927           0 :     pop();
    4928             : 
    4929           0 :     rEdit.m_aAppearances[ "N" ][ "Standard" ] = pEditStream;
    4930             : 
    4931           0 :     rEdit.m_aDAString = aDA.makeStringAndClear();
    4932           0 : }
    4933             : 
    4934           0 : void PDFWriterImpl::createDefaultListBoxAppearance( PDFWidget& rBox, const PDFWriter::ListBoxWidget& rWidget )
    4935             : {
    4936           0 :     const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
    4937           0 :     SvMemoryStream* pListBoxStream = new SvMemoryStream( 1024, 1024 );
    4938             : 
    4939           0 :     push( PushFlags::ALL );
    4940             : 
    4941             :     // prepare font to use, draw field border
    4942           0 :     Font aFont = drawFieldBorder( rBox, rWidget, rSettings );
    4943           0 :     sal_Int32 nBest = m_aContext.FieldsUseSystemFonts ? getSystemFont( aFont ): getBestBuiltinFont( aFont );
    4944             : 
    4945           0 :     beginRedirect( pListBoxStream, rBox.m_aRect );
    4946           0 :     OStringBuffer aAppearance( 64 );
    4947             : 
    4948           0 :     setLineColor( Color( COL_TRANSPARENT ) );
    4949           0 :     setFillColor( replaceColor( rWidget.BackgroundColor, rSettings.GetFieldColor() ) );
    4950           0 :     drawRectangle( rBox.m_aRect );
    4951             : 
    4952             :     // empty appearance, see createDefaultEditAppearance for reference
    4953           0 :     aAppearance.append( "/Tx BMC\nEMC\n" );
    4954           0 :     writeBuffer( aAppearance.getStr(), aAppearance.getLength() );
    4955             : 
    4956           0 :     endRedirect();
    4957           0 :     pop();
    4958             : 
    4959           0 :     rBox.m_aAppearances[ "N" ][ "Standard" ] = pListBoxStream;
    4960             : 
    4961             :     // prepare DA string
    4962           0 :     OStringBuffer aDA( 256 );
    4963             :     // prepare DA string
    4964           0 :     appendNonStrokingColor( replaceColor( rWidget.TextColor, rSettings.GetFieldTextColor() ), aDA );
    4965           0 :     aDA.append( ' ' );
    4966           0 :     if( m_aContext.FieldsUseSystemFonts )
    4967             :     {
    4968           0 :         aDA.append( "/F" );
    4969           0 :         aDA.append( nBest );
    4970             : 
    4971           0 :         OStringBuffer aDR( 32 );
    4972           0 :         aDR.append( "/Font " );
    4973           0 :         aDR.append( getFontDictObject() );
    4974           0 :         aDR.append( " 0 R" );
    4975           0 :         rBox.m_aDRDict = aDR.makeStringAndClear();
    4976             :     }
    4977             :     else
    4978           0 :         aDA.append( m_aBuiltinFonts[nBest].getNameObject() );
    4979           0 :     aDA.append( ' ' );
    4980           0 :     m_aPages[ m_nCurrentPage ].appendMappedLength( sal_Int32( aFont.GetHeight() ), aDA );
    4981           0 :     aDA.append( " Tf" );
    4982           0 :     rBox.m_aDAString = aDA.makeStringAndClear();
    4983           0 : }
    4984             : 
    4985           0 : void PDFWriterImpl::createDefaultCheckBoxAppearance( PDFWidget& rBox, const PDFWriter::CheckBoxWidget& rWidget )
    4986             : {
    4987           0 :     const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
    4988             : 
    4989             :     // save graphics state
    4990           0 :     push( PushFlags::ALL );
    4991             : 
    4992           0 :     if( rWidget.Background || rWidget.Border )
    4993             :     {
    4994           0 :         setLineColor( rWidget.Border ? replaceColor( rWidget.BorderColor, rSettings.GetCheckedColor() ) : Color( COL_TRANSPARENT ) );
    4995           0 :         setFillColor( rWidget.Background ? replaceColor( rWidget.BackgroundColor, rSettings.GetFieldColor() ) : Color( COL_TRANSPARENT ) );
    4996           0 :         drawRectangle( rBox.m_aRect );
    4997             :     }
    4998             : 
    4999           0 :     Font aFont = replaceFont( rWidget.TextFont, rSettings.GetRadioCheckFont() );
    5000           0 :     setFont( aFont );
    5001           0 :     Size aFontSize = aFont.GetSize();
    5002           0 :     if( aFontSize.Height() > rBox.m_aRect.GetHeight() )
    5003           0 :         aFontSize.Height() = rBox.m_aRect.GetHeight();
    5004           0 :     sal_Int32 nDelta = aFontSize.Height()/10;
    5005           0 :     if( nDelta < 1 )
    5006           0 :         nDelta = 1;
    5007             : 
    5008           0 :     Rectangle aCheckRect, aTextRect;
    5009           0 :     if( rWidget.ButtonIsLeft )
    5010             :     {
    5011           0 :         aCheckRect.Left()   = rBox.m_aRect.Left() + nDelta;
    5012           0 :         aCheckRect.Top()    = rBox.m_aRect.Top() + (rBox.m_aRect.GetHeight()-aFontSize.Height())/2;
    5013           0 :         aCheckRect.Right()  = aCheckRect.Left() + aFontSize.Height();
    5014           0 :         aCheckRect.Bottom() = aCheckRect.Top() + aFontSize.Height();
    5015             : 
    5016             :         // #i74206# handle small controls without text area
    5017           0 :         while( aCheckRect.GetWidth() > rBox.m_aRect.GetWidth() && aCheckRect.GetWidth() > nDelta )
    5018             :         {
    5019           0 :             aCheckRect.Right()  -= nDelta;
    5020           0 :             aCheckRect.Top()    += nDelta/2;
    5021           0 :             aCheckRect.Bottom() -= nDelta - (nDelta/2);
    5022             :         }
    5023             : 
    5024           0 :         aTextRect.Left()    = rBox.m_aRect.Left() + aCheckRect.GetWidth()+5*nDelta;
    5025           0 :         aTextRect.Top()     = rBox.m_aRect.Top();
    5026           0 :         aTextRect.Right()   = aTextRect.Left() + rBox.m_aRect.GetWidth() - aCheckRect.GetWidth()-6*nDelta;
    5027           0 :         aTextRect.Bottom()  = rBox.m_aRect.Bottom();
    5028             :     }
    5029             :     else
    5030             :     {
    5031           0 :         aCheckRect.Left()   = rBox.m_aRect.Right() - nDelta - aFontSize.Height();
    5032           0 :         aCheckRect.Top()    = rBox.m_aRect.Top() + (rBox.m_aRect.GetHeight()-aFontSize.Height())/2;
    5033           0 :         aCheckRect.Right()  = aCheckRect.Left() + aFontSize.Height();
    5034           0 :         aCheckRect.Bottom() = aCheckRect.Top() + aFontSize.Height();
    5035             : 
    5036             :         // #i74206# handle small controls without text area
    5037           0 :         while( aCheckRect.GetWidth() > rBox.m_aRect.GetWidth() && aCheckRect.GetWidth() > nDelta )
    5038             :         {
    5039           0 :             aCheckRect.Left()   += nDelta;
    5040           0 :             aCheckRect.Top()    += nDelta/2;
    5041           0 :             aCheckRect.Bottom() -= nDelta - (nDelta/2);
    5042             :         }
    5043             : 
    5044           0 :         aTextRect.Left()    = rBox.m_aRect.Left();
    5045           0 :         aTextRect.Top()     = rBox.m_aRect.Top();
    5046           0 :         aTextRect.Right()   = aTextRect.Left() + rBox.m_aRect.GetWidth() - aCheckRect.GetWidth()-6*nDelta;
    5047           0 :         aTextRect.Bottom()  = rBox.m_aRect.Bottom();
    5048             :     }
    5049           0 :     setLineColor( Color( COL_BLACK ) );
    5050           0 :     setFillColor( Color( COL_TRANSPARENT ) );
    5051           0 :     OStringBuffer aLW( 32 );
    5052           0 :     aLW.append( "q " );
    5053           0 :     m_aPages[m_nCurrentPage].appendMappedLength( nDelta, aLW );
    5054           0 :     aLW.append( " w " );
    5055           0 :     writeBuffer( aLW.getStr(), aLW.getLength() );
    5056           0 :     drawRectangle( aCheckRect );
    5057           0 :     writeBuffer( " Q\n", 3 );
    5058           0 :     setTextColor( replaceColor( rWidget.TextColor, rSettings.GetRadioCheckTextColor() ) );
    5059           0 :     drawText( aTextRect, rBox.m_aText, rBox.m_nTextStyle );
    5060             : 
    5061           0 :     pop();
    5062             : 
    5063           0 :     OStringBuffer aDA( 256 );
    5064           0 :     appendNonStrokingColor( replaceColor( rWidget.TextColor, rSettings.GetRadioCheckTextColor() ), aDA );
    5065           0 :     sal_Int32 nBest = getBestBuiltinFont( Font( OUString( "ZapfDingbats" ), aFont.GetSize() ) );
    5066           0 :     aDA.append( ' ' );
    5067           0 :     aDA.append( m_aBuiltinFonts[nBest].getNameObject() );
    5068           0 :     aDA.append( " 0 Tf" );
    5069           0 :     rBox.m_aDAString = aDA.makeStringAndClear();
    5070           0 :     rBox.m_aMKDict = "/CA";
    5071           0 :     rBox.m_aMKDictCAString = "8";
    5072           0 :     rBox.m_aRect = aCheckRect;
    5073             : 
    5074             :     // create appearance streams
    5075           0 :     sal_Char cMark = '8';
    5076           0 :     sal_Int32 nCharXOffset = 1000-m_aBuiltinFonts[13].m_aWidths[sal_Int32(cMark)];
    5077           0 :     nCharXOffset *= aCheckRect.GetHeight();
    5078           0 :     nCharXOffset /= 2000;
    5079             :     sal_Int32 nCharYOffset = 1000-
    5080           0 :         (m_aBuiltinFonts[13].m_nAscent+m_aBuiltinFonts[13].m_nDescent); // descent is negative
    5081           0 :     nCharYOffset *= aCheckRect.GetHeight();
    5082           0 :     nCharYOffset /= 2000;
    5083             : 
    5084           0 :     SvMemoryStream* pCheckStream = new SvMemoryStream( 256, 256 );
    5085           0 :     beginRedirect( pCheckStream, aCheckRect );
    5086           0 :     aDA.append( "/Tx BMC\nq BT\n" );
    5087           0 :     appendNonStrokingColor( replaceColor( rWidget.TextColor, rSettings.GetRadioCheckTextColor() ), aDA );
    5088           0 :     aDA.append( ' ' );
    5089           0 :     aDA.append( m_aBuiltinFonts[nBest].getNameObject() );
    5090           0 :     aDA.append( ' ' );
    5091           0 :     m_aPages[ m_nCurrentPage ].appendMappedLength( sal_Int32( aCheckRect.GetHeight() ), aDA );
    5092           0 :     aDA.append( " Tf\n" );
    5093           0 :     m_aPages[ m_nCurrentPage ].appendMappedLength( nCharXOffset, aDA );
    5094           0 :     aDA.append( " " );
    5095           0 :     m_aPages[ m_nCurrentPage ].appendMappedLength( nCharYOffset, aDA );
    5096           0 :     aDA.append( " Td (" );
    5097           0 :     aDA.append( cMark );
    5098           0 :     aDA.append( ") Tj\nET\nQ\nEMC\n" );
    5099           0 :     writeBuffer( aDA.getStr(), aDA.getLength() );
    5100           0 :     endRedirect();
    5101           0 :     rBox.m_aAppearances[ "N" ][ "Yes" ] = pCheckStream;
    5102             : 
    5103           0 :     SvMemoryStream* pUncheckStream = new SvMemoryStream( 256, 256 );
    5104           0 :     beginRedirect( pUncheckStream, aCheckRect );
    5105           0 :     writeBuffer( "/Tx BMC\nEMC\n", 12 );
    5106           0 :     endRedirect();
    5107           0 :     rBox.m_aAppearances[ "N" ][ "Off" ] = pUncheckStream;
    5108           0 : }
    5109             : 
    5110           0 : void PDFWriterImpl::createDefaultRadioButtonAppearance( PDFWidget& rBox, const PDFWriter::RadioButtonWidget& rWidget )
    5111             : {
    5112           0 :     const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
    5113             : 
    5114             :     // save graphics state
    5115           0 :     push( PushFlags::ALL );
    5116             : 
    5117           0 :     if( rWidget.Background || rWidget.Border )
    5118             :     {
    5119           0 :         setLineColor( rWidget.Border ? replaceColor( rWidget.BorderColor, rSettings.GetCheckedColor() ) : Color( COL_TRANSPARENT ) );
    5120           0 :         setFillColor( rWidget.Background ? replaceColor( rWidget.BackgroundColor, rSettings.GetFieldColor() ) : Color( COL_TRANSPARENT ) );
    5121           0 :         drawRectangle( rBox.m_aRect );
    5122             :     }
    5123             : 
    5124           0 :     Font aFont = replaceFont( rWidget.TextFont, rSettings.GetRadioCheckFont() );
    5125           0 :     setFont( aFont );
    5126           0 :     Size aFontSize = aFont.GetSize();
    5127           0 :     if( aFontSize.Height() > rBox.m_aRect.GetHeight() )
    5128           0 :         aFontSize.Height() = rBox.m_aRect.GetHeight();
    5129           0 :     sal_Int32 nDelta = aFontSize.Height()/10;
    5130           0 :     if( nDelta < 1 )
    5131           0 :         nDelta = 1;
    5132             : 
    5133           0 :     Rectangle aCheckRect, aTextRect;
    5134           0 :     if( rWidget.ButtonIsLeft )
    5135             :     {
    5136           0 :         aCheckRect.Left()   = rBox.m_aRect.Left() + nDelta;
    5137           0 :         aCheckRect.Top()    = rBox.m_aRect.Top() + (rBox.m_aRect.GetHeight()-aFontSize.Height())/2;
    5138           0 :         aCheckRect.Right()  = aCheckRect.Left() + aFontSize.Height();
    5139           0 :         aCheckRect.Bottom() = aCheckRect.Top() + aFontSize.Height();
    5140             : 
    5141             :         // #i74206# handle small controls without text area
    5142           0 :         while( aCheckRect.GetWidth() > rBox.m_aRect.GetWidth() && aCheckRect.GetWidth() > nDelta )
    5143             :         {
    5144           0 :             aCheckRect.Right()  -= nDelta;
    5145           0 :             aCheckRect.Top()    += nDelta/2;
    5146           0 :             aCheckRect.Bottom() -= nDelta - (nDelta/2);
    5147             :         }
    5148             : 
    5149           0 :         aTextRect.Left()    = rBox.m_aRect.Left() + aCheckRect.GetWidth()+5*nDelta;
    5150           0 :         aTextRect.Top()     = rBox.m_aRect.Top();
    5151           0 :         aTextRect.Right()   = aTextRect.Left() + rBox.m_aRect.GetWidth() - aCheckRect.GetWidth()-6*nDelta;
    5152           0 :         aTextRect.Bottom()  = rBox.m_aRect.Bottom();
    5153             :     }
    5154             :     else
    5155             :     {
    5156           0 :         aCheckRect.Left()   = rBox.m_aRect.Right() - nDelta - aFontSize.Height();
    5157           0 :         aCheckRect.Top()    = rBox.m_aRect.Top() + (rBox.m_aRect.GetHeight()-aFontSize.Height())/2;
    5158           0 :         aCheckRect.Right()  = aCheckRect.Left() + aFontSize.Height();
    5159           0 :         aCheckRect.Bottom() = aCheckRect.Top() + aFontSize.Height();
    5160             : 
    5161             :         // #i74206# handle small controls without text area
    5162           0 :         while( aCheckRect.GetWidth() > rBox.m_aRect.GetWidth() && aCheckRect.GetWidth() > nDelta )
    5163             :         {
    5164           0 :             aCheckRect.Left()   += nDelta;
    5165           0 :             aCheckRect.Top()    += nDelta/2;
    5166           0 :             aCheckRect.Bottom() -= nDelta - (nDelta/2);
    5167             :         }
    5168             : 
    5169           0 :         aTextRect.Left()    = rBox.m_aRect.Left();
    5170           0 :         aTextRect.Top()     = rBox.m_aRect.Top();
    5171           0 :         aTextRect.Right()   = aTextRect.Left() + rBox.m_aRect.GetWidth() - aCheckRect.GetWidth()-6*nDelta;
    5172           0 :         aTextRect.Bottom()  = rBox.m_aRect.Bottom();
    5173             :     }
    5174           0 :     setLineColor( Color( COL_BLACK ) );
    5175           0 :     setFillColor( Color( COL_TRANSPARENT ) );
    5176           0 :     OStringBuffer aLW( 32 );
    5177           0 :     aLW.append( "q " );
    5178           0 :     m_aPages[ m_nCurrentPage ].appendMappedLength( nDelta, aLW );
    5179           0 :     aLW.append( " w " );
    5180           0 :     writeBuffer( aLW.getStr(), aLW.getLength() );
    5181           0 :     drawEllipse( aCheckRect );
    5182           0 :     writeBuffer( " Q\n", 3 );
    5183           0 :     setTextColor( replaceColor( rWidget.TextColor, rSettings.GetRadioCheckTextColor() ) );
    5184           0 :     drawText( aTextRect, rBox.m_aText, rBox.m_nTextStyle );
    5185             : 
    5186           0 :     pop();
    5187             : 
    5188           0 :     OStringBuffer aDA( 256 );
    5189           0 :     appendNonStrokingColor( replaceColor( rWidget.TextColor, rSettings.GetRadioCheckTextColor() ), aDA );
    5190           0 :     sal_Int32 nBest = getBestBuiltinFont( Font( OUString( "ZapfDingbats" ), aFont.GetSize() ) );
    5191           0 :     aDA.append( ' ' );
    5192           0 :     aDA.append( m_aBuiltinFonts[nBest].getNameObject() );
    5193           0 :     aDA.append( " 0 Tf" );
    5194           0 :     rBox.m_aDAString = aDA.makeStringAndClear();
    5195             :     //to encrypt this (el)
    5196           0 :     rBox.m_aMKDict = "/CA";
    5197             :     //after this assignement, to m_aMKDic cannot be added anything
    5198           0 :     rBox.m_aMKDictCAString = "l";
    5199             : 
    5200           0 :     rBox.m_aRect = aCheckRect;
    5201             : 
    5202             :     // create appearance streams
    5203           0 :     push( PushFlags::ALL);
    5204           0 :     SvMemoryStream* pCheckStream = new SvMemoryStream( 256, 256 );
    5205             : 
    5206           0 :     beginRedirect( pCheckStream, aCheckRect );
    5207           0 :     aDA.append( "/Tx BMC\nq BT\n" );
    5208           0 :     appendNonStrokingColor( replaceColor( rWidget.TextColor, rSettings.GetRadioCheckTextColor() ), aDA );
    5209           0 :     aDA.append( ' ' );
    5210           0 :     aDA.append( m_aBuiltinFonts[nBest].getNameObject() );
    5211           0 :     aDA.append( ' ' );
    5212           0 :     m_aPages[m_nCurrentPage].appendMappedLength( sal_Int32( aCheckRect.GetHeight() ), aDA );
    5213           0 :     aDA.append( " Tf\n0 0 Td\nET\nQ\n" );
    5214           0 :     writeBuffer( aDA.getStr(), aDA.getLength() );
    5215           0 :     setFillColor( replaceColor( rWidget.TextColor, rSettings.GetRadioCheckTextColor() ) );
    5216           0 :     setLineColor( Color( COL_TRANSPARENT ) );
    5217           0 :     aCheckRect.Left()   += 3*nDelta;
    5218           0 :     aCheckRect.Top()    += 3*nDelta;
    5219           0 :     aCheckRect.Bottom() -= 3*nDelta;
    5220           0 :     aCheckRect.Right()  -= 3*nDelta;
    5221           0 :     drawEllipse( aCheckRect );
    5222           0 :     writeBuffer( "\nEMC\n", 5 );
    5223           0 :     endRedirect();
    5224             : 
    5225           0 :     pop();
    5226           0 :     rBox.m_aAppearances[ "N" ][ "Yes" ] = pCheckStream;
    5227             : 
    5228           0 :     SvMemoryStream* pUncheckStream = new SvMemoryStream( 256, 256 );
    5229           0 :     beginRedirect( pUncheckStream, aCheckRect );
    5230           0 :     writeBuffer( "/Tx BMC\nEMC\n", 12 );
    5231           0 :     endRedirect();
    5232           0 :     rBox.m_aAppearances[ "N" ][ "Off" ] = pUncheckStream;
    5233           0 : }
    5234             : 
    5235           0 : bool PDFWriterImpl::emitAppearances( PDFWidget& rWidget, OStringBuffer& rAnnotDict )
    5236             : {
    5237             :     // TODO: check and insert default streams
    5238           0 :     OString aStandardAppearance;
    5239           0 :     switch( rWidget.m_eType )
    5240             :     {
    5241             :         case PDFWriter::CheckBox:
    5242           0 :             aStandardAppearance = OUStringToOString( rWidget.m_aValue, RTL_TEXTENCODING_ASCII_US );
    5243           0 :             break;
    5244             :         default:
    5245           0 :             break;
    5246             :     }
    5247             : 
    5248           0 :     if( !rWidget.m_aAppearances.empty() )
    5249             :     {
    5250           0 :         rAnnotDict.append( "/AP<<\n" );
    5251           0 :         for( PDFAppearanceMap::iterator dict_it = rWidget.m_aAppearances.begin(); dict_it != rWidget.m_aAppearances.end(); ++dict_it )
    5252             :         {
    5253           0 :             rAnnotDict.append( "/" );
    5254           0 :             rAnnotDict.append( dict_it->first );
    5255           0 :             bool bUseSubDict = (dict_it->second.size() > 1);
    5256           0 :             rAnnotDict.append( bUseSubDict ? "<<" : " " );
    5257             : 
    5258           0 :             for( PDFAppearanceStreams::const_iterator stream_it = dict_it->second.begin();
    5259           0 :                  stream_it != dict_it->second.end(); ++stream_it )
    5260             :             {
    5261           0 :                 SvMemoryStream* pApppearanceStream = stream_it->second;
    5262           0 :                 dict_it->second[ stream_it->first ] = NULL;
    5263             : 
    5264           0 :                 bool bDeflate = compressStream( pApppearanceStream );
    5265             : 
    5266           0 :                 pApppearanceStream->Seek( STREAM_SEEK_TO_END );
    5267           0 :                 sal_Int64 nStreamLen = pApppearanceStream->Tell();
    5268           0 :                 pApppearanceStream->Seek( STREAM_SEEK_TO_BEGIN );
    5269           0 :                 sal_Int32 nObject = createObject();
    5270           0 :                 CHECK_RETURN( updateObject( nObject ) );
    5271             :                 #if OSL_DEBUG_LEVEL > 1
    5272             :                 emitComment( "PDFWriterImpl::emitAppearances" );
    5273             :                 #endif
    5274           0 :                 OStringBuffer aLine;
    5275           0 :                 aLine.append( nObject );
    5276             : 
    5277             :                 aLine.append( " 0 obj\n"
    5278             :                               "<</Type/XObject\n"
    5279             :                               "/Subtype/Form\n"
    5280           0 :                               "/BBox[0 0 " );
    5281           0 :                 appendFixedInt( rWidget.m_aRect.GetWidth()-1, aLine );
    5282           0 :                 aLine.append( " " );
    5283           0 :                 appendFixedInt( rWidget.m_aRect.GetHeight()-1, aLine );
    5284             :                 aLine.append( "]\n"
    5285           0 :                               "/Resources " );
    5286           0 :                 aLine.append( getResourceDictObj() );
    5287             :                 aLine.append( " 0 R\n"
    5288           0 :                               "/Length " );
    5289           0 :                 aLine.append( nStreamLen );
    5290           0 :                 aLine.append( "\n" );
    5291           0 :                 if( bDeflate )
    5292           0 :                     aLine.append( "/Filter/FlateDecode\n" );
    5293           0 :                 aLine.append( ">>\nstream\n" );
    5294           0 :                 CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
    5295           0 :                 checkAndEnableStreamEncryption( nObject );
    5296           0 :                 CHECK_RETURN( writeBuffer( pApppearanceStream->GetData(), nStreamLen ) );
    5297           0 :                 disableStreamEncryption();
    5298           0 :                 CHECK_RETURN( writeBuffer( "\nendstream\nendobj\n\n", 19 ) );
    5299             : 
    5300           0 :                 if( bUseSubDict )
    5301             :                 {
    5302           0 :                     rAnnotDict.append( " /" );
    5303           0 :                     rAnnotDict.append( stream_it->first );
    5304           0 :                     rAnnotDict.append( " " );
    5305             :                 }
    5306           0 :                 rAnnotDict.append( nObject );
    5307           0 :                 rAnnotDict.append( " 0 R" );
    5308             : 
    5309           0 :                 delete pApppearanceStream;
    5310           0 :             }
    5311             : 
    5312           0 :             rAnnotDict.append( bUseSubDict ? ">>\n" : "\n" );
    5313             :         }
    5314           0 :         rAnnotDict.append( ">>\n" );
    5315           0 :         if( !aStandardAppearance.isEmpty() )
    5316             :         {
    5317           0 :             rAnnotDict.append( "/AS /" );
    5318           0 :             rAnnotDict.append( aStandardAppearance );
    5319           0 :             rAnnotDict.append( "\n" );
    5320             :         }
    5321             :     }
    5322             : 
    5323           0 :     return true;
    5324             : }
    5325             : 
    5326           0 : bool PDFWriterImpl::emitWidgetAnnotations()
    5327             : {
    5328           0 :     ensureUniqueRadioOnValues();
    5329             : 
    5330           0 :     int nAnnots = m_aWidgets.size();
    5331           0 :     for( int a = 0; a < nAnnots; a++ )
    5332             :     {
    5333           0 :         PDFWidget& rWidget = m_aWidgets[a];
    5334             : 
    5335           0 :         OStringBuffer aLine( 1024 );
    5336           0 :         OStringBuffer aValue( 256 );
    5337           0 :         aLine.append( rWidget.m_nObject );
    5338             :         aLine.append( " 0 obj\n"
    5339           0 :                       "<<" );
    5340           0 :         if( rWidget.m_eType != PDFWriter::Hierarchy )
    5341             :         {
    5342             :             // emit widget annotation only for terminal fields
    5343           0 :             if( rWidget.m_aKids.empty() )
    5344             :             {
    5345             :                 int iRectMargin;
    5346             : 
    5347           0 :                 aLine.append( "/Type/Annot/Subtype/Widget/F " );
    5348             : 
    5349           0 :                 if (rWidget.m_eType == PDFWriter::Signature)
    5350             :                 {
    5351           0 :                     aLine.append( "132\n" ); // Print & Locked
    5352           0 :                     iRectMargin = 0;
    5353             :                 }
    5354             :                 else
    5355             :                 {
    5356           0 :                     aLine.append( "4\n" );
    5357           0 :                     iRectMargin = 1;
    5358             :                 }
    5359             : 
    5360           0 :                 aLine.append("/Rect[" );
    5361           0 :                 appendFixedInt( rWidget.m_aRect.Left()-iRectMargin, aLine );
    5362           0 :                 aLine.append( ' ' );
    5363           0 :                 appendFixedInt( rWidget.m_aRect.Top()+iRectMargin, aLine );
    5364           0 :                 aLine.append( ' ' );
    5365           0 :                 appendFixedInt( rWidget.m_aRect.Right()+iRectMargin, aLine );
    5366           0 :                 aLine.append( ' ' );
    5367           0 :                 appendFixedInt( rWidget.m_aRect.Bottom()-iRectMargin, aLine );
    5368           0 :                 aLine.append( "]\n" );
    5369             :             }
    5370           0 :             aLine.append( "/FT/" );
    5371           0 :             switch( rWidget.m_eType )
    5372             :             {
    5373             :                 case PDFWriter::RadioButton:
    5374             :                 case PDFWriter::CheckBox:
    5375             :                     // for radio buttons only the RadioButton field, not the
    5376             :                     // CheckBox children should have a value, else acrobat reader
    5377             :                     // does not always check the right button
    5378             :                     // of course real check boxes (not belonging to a radio group)
    5379             :                     // need their values, too
    5380           0 :                     if( rWidget.m_eType == PDFWriter::RadioButton || rWidget.m_nRadioGroup < 0 )
    5381             :                     {
    5382           0 :                         aValue.append( "/" );
    5383             :                         // check for radio group with all buttons unpressed
    5384           0 :                         if( rWidget.m_aValue.isEmpty() )
    5385           0 :                             aValue.append( "Off" );
    5386             :                         else
    5387           0 :                             appendName( rWidget.m_aValue, aValue );
    5388             :                     }
    5389             :                     // fall-through
    5390             :                 case PDFWriter::PushButton:
    5391           0 :                     aLine.append( "Btn" );
    5392           0 :                     break;
    5393             :                 case PDFWriter::ListBox:
    5394           0 :                     if( rWidget.m_nFlags & 0x200000 ) // multiselect
    5395             :                     {
    5396           0 :                         aValue.append( "[" );
    5397           0 :                         for( size_t i = 0; i < rWidget.m_aSelectedEntries.size(); i++ )
    5398             :                         {
    5399           0 :                             sal_Int32 nEntry = rWidget.m_aSelectedEntries[i];
    5400           0 :                             if( nEntry >= 0 && nEntry < sal_Int32(rWidget.m_aListEntries.size()) )
    5401           0 :                                 appendUnicodeTextStringEncrypt( rWidget.m_aListEntries[ nEntry ], rWidget.m_nObject, aValue );
    5402             :                         }
    5403           0 :                         aValue.append( "]" );
    5404             :                     }
    5405           0 :                     else if( rWidget.m_aSelectedEntries.size() > 0 &&
    5406           0 :                              rWidget.m_aSelectedEntries[0] >= 0 &&
    5407           0 :                              rWidget.m_aSelectedEntries[0] < sal_Int32(rWidget.m_aListEntries.size()) )
    5408             :                     {
    5409           0 :                         appendUnicodeTextStringEncrypt( rWidget.m_aListEntries[ rWidget.m_aSelectedEntries[0] ], rWidget.m_nObject, aValue );
    5410             :                     }
    5411             :                     else
    5412           0 :                         appendUnicodeTextStringEncrypt( OUString(), rWidget.m_nObject, aValue );
    5413           0 :                     aLine.append( "Ch" );
    5414           0 :                     break;
    5415             :                 case PDFWriter::ComboBox:
    5416           0 :                     appendUnicodeTextStringEncrypt( rWidget.m_aValue, rWidget.m_nObject, aValue );
    5417           0 :                     aLine.append( "Ch" );
    5418           0 :                     break;
    5419             :                 case PDFWriter::Edit:
    5420           0 :                     aLine.append( "Tx" );
    5421           0 :                     appendUnicodeTextStringEncrypt( rWidget.m_aValue, rWidget.m_nObject, aValue );
    5422           0 :                     break;
    5423             :                 case PDFWriter::Signature:
    5424           0 :                     aLine.append( "Sig" );
    5425           0 :                     aValue.append(OUStringToOString(rWidget.m_aValue, RTL_TEXTENCODING_ASCII_US));
    5426           0 :                     break;
    5427             :                 case PDFWriter::Hierarchy: // make the compiler happy
    5428           0 :                     break;
    5429             :             }
    5430           0 :             aLine.append( "\n" );
    5431           0 :             aLine.append( "/P " );
    5432           0 :             aLine.append( m_aPages[ rWidget.m_nPage ].m_nPageObject );
    5433           0 :             aLine.append( " 0 R\n" );
    5434             :         }
    5435           0 :         if( rWidget.m_nParent )
    5436             :         {
    5437           0 :             aLine.append( "/Parent " );
    5438           0 :             aLine.append( rWidget.m_nParent );
    5439           0 :             aLine.append( " 0 R\n" );
    5440             :         }
    5441           0 :         if( rWidget.m_aKids.size() )
    5442             :         {
    5443           0 :             aLine.append( "/Kids[" );
    5444           0 :             for( size_t i = 0; i < rWidget.m_aKids.size(); i++ )
    5445             :             {
    5446           0 :                 aLine.append( rWidget.m_aKids[i] );
    5447           0 :                 aLine.append( " 0 R" );
    5448           0 :                 aLine.append( ( (i&15) == 15 ) ? "\n" : " " );
    5449             :             }
    5450           0 :             aLine.append( "]\n" );
    5451             :         }
    5452           0 :         if( !rWidget.m_aName.isEmpty() )
    5453             :         {
    5454           0 :             aLine.append( "/T" );
    5455           0 :             appendLiteralStringEncrypt( rWidget.m_aName, rWidget.m_nObject, aLine );
    5456           0 :             aLine.append( "\n" );
    5457             :         }
    5458           0 :         if( m_aContext.Version > PDFWriter::PDF_1_2 && !rWidget.m_aDescription.isEmpty() )
    5459             :         {
    5460             :             // the alternate field name should be unicode able since it is
    5461             :             // supposed to be used in UI
    5462           0 :             aLine.append( "/TU" );
    5463           0 :             appendUnicodeTextStringEncrypt( rWidget.m_aDescription, rWidget.m_nObject, aLine );
    5464           0 :             aLine.append( "\n" );
    5465             :         }
    5466             : 
    5467           0 :         if( rWidget.m_nFlags )
    5468             :         {
    5469           0 :             aLine.append( "/Ff " );
    5470           0 :             aLine.append( rWidget.m_nFlags );
    5471           0 :             aLine.append( "\n" );
    5472             :         }
    5473           0 :         if( !aValue.isEmpty() )
    5474             :         {
    5475           0 :             OString aVal = aValue.makeStringAndClear();
    5476           0 :             aLine.append( "/V " );
    5477           0 :             aLine.append( aVal );
    5478             :             aLine.append( "\n"
    5479           0 :                           "/DV " );
    5480           0 :             aLine.append( aVal );
    5481           0 :             aLine.append( "\n" );
    5482             :         }
    5483           0 :         if( rWidget.m_eType == PDFWriter::ListBox || rWidget.m_eType == PDFWriter::ComboBox )
    5484             :         {
    5485           0 :             sal_Int32 nTI = -1;
    5486           0 :             aLine.append( "/Opt[\n" );
    5487           0 :             sal_Int32 i = 0;
    5488           0 :             for( std::vector< OUString >::const_iterator it = rWidget.m_aListEntries.begin(); it != rWidget.m_aListEntries.end(); ++it, ++i )
    5489             :             {
    5490           0 :                 appendUnicodeTextStringEncrypt( *it, rWidget.m_nObject, aLine );
    5491           0 :                 aLine.append( "\n" );
    5492           0 :                 if( *it == rWidget.m_aValue )
    5493           0 :                     nTI = i;
    5494             :             }
    5495           0 :             aLine.append( "]\n" );
    5496           0 :             if( nTI > 0 )
    5497             :             {
    5498           0 :                 aLine.append( "/TI " );
    5499           0 :                 aLine.append( nTI );
    5500           0 :                 aLine.append( "\n" );
    5501           0 :                 if( rWidget.m_nFlags & 0x200000 ) // Multiselect
    5502             :                 {
    5503           0 :                     aLine.append( "/I [" );
    5504           0 :                     aLine.append( nTI );
    5505           0 :                     aLine.append( "]\n" );
    5506             :                 }
    5507             :             }
    5508             :         }
    5509           0 :         if( rWidget.m_eType == PDFWriter::Edit && rWidget.m_nMaxLen > 0 )
    5510             :         {
    5511           0 :             aLine.append( "/MaxLen " );
    5512           0 :             aLine.append( rWidget.m_nMaxLen );
    5513           0 :             aLine.append( "\n" );
    5514             :         }
    5515           0 :         if( rWidget.m_eType == PDFWriter::PushButton )
    5516             :         {
    5517           0 :             if(!m_bIsPDF_A1)
    5518             :             {
    5519           0 :                 OStringBuffer aDest;
    5520           0 :                 if( rWidget.m_nDest != -1 && appendDest( m_aDestinationIdTranslation[ rWidget.m_nDest ], aDest ) )
    5521             :                 {
    5522           0 :                     aLine.append( "/AA<</D<</Type/Action/S/GoTo/D " );
    5523           0 :                     aLine.append( aDest.makeStringAndClear() );
    5524           0 :                     aLine.append( ">>>>\n" );
    5525             :                 }
    5526           0 :                 else if( rWidget.m_aListEntries.empty() )
    5527             :                 {
    5528             :                     // create a reset form action
    5529           0 :                     aLine.append( "/AA<</D<</Type/Action/S/ResetForm>>>>\n" );
    5530             :                 }
    5531           0 :                 else if( rWidget.m_bSubmit )
    5532             :                 {
    5533             :                     // create a submit form action
    5534           0 :                     aLine.append( "/AA<</D<</Type/Action/S/SubmitForm/F" );
    5535           0 :                     appendLiteralStringEncrypt( rWidget.m_aListEntries.front(), rWidget.m_nObject, aLine, osl_getThreadTextEncoding() );
    5536           0 :                     aLine.append( "/Flags " );
    5537             : 
    5538           0 :                     sal_Int32 nFlags = 0;
    5539           0 :                     switch( m_aContext.SubmitFormat )
    5540             :                     {
    5541             :                     case PDFWriter::HTML:
    5542           0 :                         nFlags |= 4;
    5543           0 :                         break;
    5544             :                     case PDFWriter::XML:
    5545           0 :                         if( m_aContext.Version > PDFWriter::PDF_1_3 )
    5546           0 :                             nFlags |= 32;
    5547           0 :                         break;
    5548             :                     case PDFWriter::PDF:
    5549           0 :                         if( m_aContext.Version > PDFWriter::PDF_1_3 )
    5550           0 :                             nFlags |= 256;
    5551           0 :                         break;
    5552             :                     case PDFWriter::FDF:
    5553             :                     default:
    5554           0 :                         break;
    5555             :                     }
    5556           0 :                     if( rWidget.m_bSubmitGet )
    5557           0 :                         nFlags |= 8;
    5558           0 :                     aLine.append( nFlags );
    5559           0 :                     aLine.append( ">>>>\n" );
    5560             :                 }
    5561             :                 else
    5562             :                 {
    5563             :                     // create a URI action
    5564           0 :                     aLine.append( "/AA<</D<</Type/Action/S/URI/URI(" );
    5565           0 :                     aLine.append( OUStringToOString( rWidget.m_aListEntries.front(), RTL_TEXTENCODING_ASCII_US ) );
    5566           0 :                     aLine.append( ")>>>>\n" );
    5567           0 :                 }
    5568             :             }
    5569             :             else
    5570           0 :                 m_aErrors.insert( PDFWriter::Warning_FormAction_Omitted_PDFA );
    5571             :         }
    5572           0 :         if( !rWidget.m_aDAString.isEmpty() )
    5573             :         {
    5574           0 :             if( !rWidget.m_aDRDict.isEmpty() )
    5575             :             {
    5576           0 :                 aLine.append( "/DR<<" );
    5577           0 :                 aLine.append( rWidget.m_aDRDict );
    5578           0 :                 aLine.append( ">>\n" );
    5579             :             }
    5580             :             else
    5581             :             {
    5582           0 :                 aLine.append( "/DR<</Font<<" );
    5583           0 :                 appendBuiltinFontsToDict( aLine );
    5584           0 :                 aLine.append( ">>>>\n" );
    5585             :             }
    5586           0 :             aLine.append( "/DA" );
    5587           0 :             appendLiteralStringEncrypt( rWidget.m_aDAString, rWidget.m_nObject, aLine );
    5588           0 :             aLine.append( "\n" );
    5589           0 :             if( rWidget.m_nTextStyle & DrawTextFlags::Center )
    5590           0 :                 aLine.append( "/Q 1\n" );
    5591           0 :             else if( rWidget.m_nTextStyle & DrawTextFlags::Right )
    5592           0 :                 aLine.append( "/Q 2\n" );
    5593             :         }
    5594             :         // appearance charactristics for terminal fields
    5595             :         // which are supposed to have an appearance constructed
    5596             :         // by the viewer application
    5597           0 :         if( !rWidget.m_aMKDict.isEmpty() )
    5598             :         {
    5599           0 :             aLine.append( "/MK<<" );
    5600           0 :             aLine.append( rWidget.m_aMKDict );
    5601             :             //add the CA string, encrypting it
    5602           0 :             appendLiteralStringEncrypt(rWidget.m_aMKDictCAString, rWidget.m_nObject, aLine);
    5603           0 :             aLine.append( ">>\n" );
    5604             :         }
    5605             : 
    5606           0 :         CHECK_RETURN( emitAppearances( rWidget, aLine ) );
    5607             : 
    5608             :         aLine.append( ">>\n"
    5609           0 :                       "endobj\n\n" );
    5610           0 :         CHECK_RETURN( updateObject( rWidget.m_nObject ) );
    5611           0 :         CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
    5612           0 :     }
    5613           0 :     return true;
    5614             : }
    5615             : 
    5616           0 : bool PDFWriterImpl::emitAnnotations()
    5617             : {
    5618           0 :     if( m_aPages.size() < 1 )
    5619           0 :         return false;
    5620             : 
    5621           0 :     CHECK_RETURN( emitLinkAnnotations() );
    5622           0 :     CHECK_RETURN( emitNoteAnnotations() );
    5623           0 :     CHECK_RETURN( emitWidgetAnnotations() );
    5624             : 
    5625           0 :     return true;
    5626             : }
    5627             : 
    5628             : #undef CHECK_RETURN
    5629             : #define CHECK_RETURN( x ) if( !x ) return false
    5630             : 
    5631           0 : bool PDFWriterImpl::emitCatalog()
    5632             : {
    5633             :     // build page tree
    5634             :     // currently there is only one node that contains all leaves
    5635             : 
    5636             :     // first create a page tree node id
    5637           0 :     sal_Int32 nTreeNode = createObject();
    5638             : 
    5639             :     // emit global resource dictionary (page emit needs it)
    5640           0 :     CHECK_RETURN( emitResources() );
    5641             : 
    5642             :     // emit all pages
    5643           0 :     for( std::vector<PDFPage>::iterator it = m_aPages.begin(); it != m_aPages.end(); ++it )
    5644           0 :         if( ! it->emit( nTreeNode ) )
    5645           0 :             return false;
    5646             : 
    5647           0 :     sal_Int32 nNamedDestinationsDictionary = emitNamedDestinations();
    5648             : 
    5649           0 :     sal_Int32 nOutlineDict = emitOutline();
    5650             : 
    5651             :     // emit Output intent i59651
    5652           0 :     sal_Int32 nOutputIntentObject = emitOutputIntent();
    5653             : 
    5654             :     // emit metadata
    5655           0 :     sal_Int32 nMetadataObject = emitDocumentMetadata();
    5656             : 
    5657           0 :     sal_Int32 nStructureDict = 0;
    5658           0 :     if(m_aStructure.size() > 1)
    5659             :     {
    5660             :         // check if dummy structure containers are needed
    5661           0 :         addInternalStructureContainer(m_aStructure[0]);
    5662           0 :         nStructureDict = m_aStructure[0].m_nObject = createObject();
    5663           0 :         emitStructure( m_aStructure[ 0 ] );
    5664             :     }
    5665             : 
    5666             :     // adjust tree node file offset
    5667           0 :     if( ! updateObject( nTreeNode ) )
    5668           0 :         return false;
    5669             : 
    5670             :     // emit tree node
    5671           0 :     OStringBuffer aLine( 2048 );
    5672           0 :     aLine.append( nTreeNode );
    5673           0 :     aLine.append( " 0 obj\n" );
    5674           0 :     aLine.append( "<</Type/Pages\n" );
    5675           0 :     aLine.append( "/Resources " );
    5676           0 :     aLine.append( getResourceDictObj() );
    5677           0 :     aLine.append( " 0 R\n" );
    5678             : 
    5679           0 :     switch( m_eInheritedOrientation )
    5680             :     {
    5681           0 :         case PDFWriter::Landscape: aLine.append( "/Rotate 90\n" );break;
    5682           0 :         case PDFWriter::Seascape: aLine.append( "/Rotate -90\n" );break;
    5683             : 
    5684             :         case PDFWriter::Inherit: // actually Inherit would be a bug, but insignificant
    5685             :         case PDFWriter::Portrait:
    5686             :         default:
    5687           0 :             break;
    5688             :     }
    5689           0 :     sal_Int32 nMediaBoxWidth = 0;
    5690           0 :     sal_Int32 nMediaBoxHeight = 0;
    5691           0 :     if( m_aPages.empty() ) // sanity check, this should not happen
    5692             :     {
    5693           0 :         nMediaBoxWidth = m_nInheritedPageWidth;
    5694           0 :         nMediaBoxHeight = m_nInheritedPageHeight;
    5695             :     }
    5696             :     else
    5697             :     {
    5698           0 :         for( std::vector<PDFPage>::const_iterator iter = m_aPages.begin(); iter != m_aPages.end(); ++iter )
    5699             :         {
    5700           0 :             if( iter->m_nPageWidth > nMediaBoxWidth )
    5701           0 :                 nMediaBoxWidth = iter->m_nPageWidth;
    5702           0 :             if( iter->m_nPageHeight > nMediaBoxHeight )
    5703           0 :                 nMediaBoxHeight = iter->m_nPageHeight;
    5704             :         }
    5705             :     }
    5706           0 :     aLine.append( "/MediaBox[ 0 0 " );
    5707           0 :     aLine.append( nMediaBoxWidth );
    5708           0 :     aLine.append( ' ' );
    5709           0 :     aLine.append( nMediaBoxHeight );
    5710             :     aLine.append( " ]\n"
    5711           0 :                   "/Kids[ " );
    5712           0 :     unsigned int i = 0;
    5713           0 :     for( std::vector<PDFPage>::const_iterator iter = m_aPages.begin(); iter != m_aPages.end(); ++iter, i++ )
    5714             :     {
    5715           0 :         aLine.append( iter->m_nPageObject );
    5716           0 :         aLine.append( " 0 R" );
    5717           0 :         aLine.append( ( (i&15) == 15 ) ? "\n" : " " );
    5718             :     }
    5719             :     aLine.append( "]\n"
    5720           0 :                   "/Count " );
    5721           0 :     aLine.append( (sal_Int32)m_aPages.size() );
    5722             :     aLine.append( ">>\n"
    5723           0 :                   "endobj\n\n" );
    5724           0 :     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
    5725             : 
    5726             :     // emit annotation objects
    5727           0 :     CHECK_RETURN( emitAnnotations() );
    5728             : 
    5729             :     // emit Catalog
    5730           0 :     m_nCatalogObject = createObject();
    5731           0 :     if( ! updateObject( m_nCatalogObject ) )
    5732           0 :         return false;
    5733           0 :     aLine.setLength( 0 );
    5734           0 :     aLine.append( m_nCatalogObject );
    5735             :     aLine.append( " 0 obj\n"
    5736           0 :                   "<</Type/Catalog/Pages " );
    5737           0 :     aLine.append( nTreeNode );
    5738           0 :     aLine.append( " 0 R\n" );
    5739             : //--->i56629
    5740             :     // check if there are named destinations to emit (root must be inside the catalog)
    5741           0 :     if( nNamedDestinationsDictionary )
    5742             :     {
    5743           0 :         aLine.append("/Dests ");
    5744           0 :         aLine.append( nNamedDestinationsDictionary );
    5745           0 :         aLine.append( " 0 R\n" );
    5746             :     }
    5747             : //<----
    5748           0 :     if( m_aContext.PageLayout != PDFWriter::DefaultLayout )
    5749           0 :         switch(  m_aContext.PageLayout )
    5750             :         {
    5751             :         default :
    5752             :         case  PDFWriter::SinglePage :
    5753           0 :             aLine.append( "/PageLayout/SinglePage\n" );
    5754           0 :             break;
    5755             :         case  PDFWriter::Continuous :
    5756           0 :             aLine.append( "/PageLayout/OneColumn\n" );
    5757           0 :             break;
    5758             :         case  PDFWriter::ContinuousFacing :
    5759             :             // the flag m_aContext.FirstPageLeft below is used to set the page on the left side
    5760           0 :             aLine.append( "/PageLayout/TwoColumnRight\n" );//odd page on the right side
    5761           0 :             break;
    5762             :         }
    5763           0 :     if( m_aContext.PDFDocumentMode != PDFWriter::ModeDefault && !m_aContext.OpenInFullScreenMode )
    5764           0 :         switch(  m_aContext.PDFDocumentMode )
    5765             :         {
    5766             :         default :
    5767           0 :             aLine.append( "/PageMode/UseNone\n" );
    5768           0 :             break;
    5769             :         case PDFWriter::UseOutlines :
    5770           0 :             aLine.append( "/PageMode/UseOutlines\n" ); //document is opened with outline pane open
    5771           0 :             break;
    5772             :         case PDFWriter::UseThumbs :
    5773           0 :             aLine.append( "/PageMode/UseThumbs\n" ); //document is opened with thumbnails pane open
    5774           0 :             break;
    5775             :         }
    5776           0 :     else if( m_aContext.OpenInFullScreenMode )
    5777           0 :         aLine.append( "/PageMode/FullScreen\n" ); //document is opened full screen
    5778             : 
    5779           0 :     OStringBuffer aInitPageRef;
    5780           0 :     if( m_aContext.InitialPage >= 0 && m_aContext.InitialPage < (sal_Int32)m_aPages.size() )
    5781             :     {
    5782           0 :         aInitPageRef.append( m_aPages[m_aContext.InitialPage].m_nPageObject );
    5783           0 :         aInitPageRef.append( " 0 R" );
    5784             :     }
    5785             :     else
    5786           0 :         aInitPageRef.append( "0" );
    5787             : 
    5788           0 :     switch( m_aContext.PDFDocumentAction )
    5789             :     {
    5790             :     case PDFWriter::ActionDefault :     //do nothing, this is the Acrobat default
    5791             :     default:
    5792           0 :         if( aInitPageRef.getLength() > 1 )
    5793             :         {
    5794           0 :             aLine.append( "/OpenAction[" );
    5795           0 :             aLine.append( aInitPageRef.makeStringAndClear() );
    5796           0 :             aLine.append( " /XYZ null null 0]\n" );
    5797             :         }
    5798           0 :         break;
    5799             :     case PDFWriter::FitInWindow :
    5800           0 :         aLine.append( "/OpenAction[" );
    5801           0 :         aLine.append( aInitPageRef.makeStringAndClear() );
    5802           0 :         aLine.append( " /Fit]\n" ); //Open fit page
    5803           0 :         break;
    5804             :     case PDFWriter::FitWidth :
    5805           0 :         aLine.append( "/OpenAction[" );
    5806           0 :         aLine.append( aInitPageRef.makeStringAndClear() );
    5807           0 :         aLine.append( " /FitH " );
    5808           0 :         aLine.append( m_nInheritedPageHeight );//Open fit width
    5809           0 :         aLine.append( "]\n" );
    5810           0 :         break;
    5811             :     case PDFWriter::FitVisible :
    5812           0 :         aLine.append( "/OpenAction[" );
    5813           0 :         aLine.append( aInitPageRef.makeStringAndClear() );
    5814           0 :         aLine.append( " /FitBH " );
    5815           0 :         aLine.append( m_nInheritedPageHeight );//Open fit visible
    5816           0 :         aLine.append( "]\n" );
    5817           0 :         break;
    5818             :     case PDFWriter::ActionZoom :
    5819           0 :         aLine.append( "/OpenAction[" );
    5820           0 :         aLine.append( aInitPageRef.makeStringAndClear() );
    5821           0 :         aLine.append( " /XYZ null null " );
    5822           0 :         if( m_aContext.Zoom >= 50 && m_aContext.Zoom <= 1600 )
    5823           0 :             aLine.append( (double)m_aContext.Zoom/100.0 );
    5824             :         else
    5825           0 :             aLine.append( "0" );
    5826           0 :         aLine.append( "]\n" );
    5827           0 :         break;
    5828             :     }
    5829             : 
    5830             :     // viewer preferences, if we had some, then emit
    5831           0 :     if( m_aContext.HideViewerToolbar ||
    5832           0 :         ( m_aContext.Version > PDFWriter::PDF_1_3 && !m_aContext.DocumentInfo.Title.isEmpty() && m_aContext.DisplayPDFDocumentTitle ) ||
    5833           0 :         m_aContext.HideViewerMenubar ||
    5834           0 :         m_aContext.HideViewerWindowControls || m_aContext.FitWindow ||
    5835           0 :         m_aContext.CenterWindow || (m_aContext.FirstPageLeft  &&  m_aContext.PageLayout == PDFWriter::ContinuousFacing ) ||
    5836             :         m_aContext.OpenInFullScreenMode )
    5837             :     {
    5838           0 :         aLine.append( "/ViewerPreferences<<" );
    5839           0 :         if( m_aContext.HideViewerToolbar )
    5840           0 :             aLine.append( "/HideToolbar true\n" );
    5841           0 :         if( m_aContext.HideViewerMenubar )
    5842           0 :             aLine.append( "/HideMenubar true\n" );
    5843           0 :         if( m_aContext.HideViewerWindowControls )
    5844           0 :             aLine.append( "/HideWindowUI true\n" );
    5845           0 :         if( m_aContext.FitWindow )
    5846           0 :             aLine.append( "/FitWindow true\n" );
    5847           0 :         if( m_aContext.CenterWindow )
    5848           0 :             aLine.append( "/CenterWindow true\n" );
    5849           0 :         if( m_aContext.Version > PDFWriter::PDF_1_3 && !m_aContext.DocumentInfo.Title.isEmpty() && m_aContext.DisplayPDFDocumentTitle )
    5850           0 :             aLine.append( "/DisplayDocTitle true\n" );
    5851           0 :         if( m_aContext.FirstPageLeft &&  m_aContext.PageLayout == PDFWriter::ContinuousFacing )
    5852           0 :             aLine.append( "/Direction/R2L\n" );
    5853           0 :         if( m_aContext.OpenInFullScreenMode )
    5854           0 :             switch( m_aContext.PDFDocumentMode )
    5855             :             {
    5856             :             default :
    5857             :             case PDFWriter::ModeDefault :
    5858           0 :                 aLine.append( "/NonFullScreenPageMode/UseNone\n" );
    5859           0 :                 break;
    5860             :             case PDFWriter::UseOutlines :
    5861           0 :                 aLine.append( "/NonFullScreenPageMode/UseOutlines\n" );
    5862           0 :                 break;
    5863             :             case PDFWriter::UseThumbs :
    5864           0 :                 aLine.append( "/NonFullScreenPageMode/UseThumbs\n" );
    5865           0 :                 break;
    5866             :             }
    5867           0 :         aLine.append( ">>\n" );
    5868             :     }
    5869             : 
    5870           0 :     if( nOutlineDict )
    5871             :     {
    5872           0 :         aLine.append( "/Outlines " );
    5873           0 :         aLine.append( nOutlineDict );
    5874           0 :         aLine.append( " 0 R\n" );
    5875             :     }
    5876           0 :     if( nStructureDict )
    5877             :     {
    5878           0 :         aLine.append( "/StructTreeRoot " );
    5879           0 :         aLine.append( nStructureDict );
    5880           0 :         aLine.append( " 0 R\n" );
    5881             :     }
    5882           0 :     if( !m_aContext.DocumentLocale.Language.isEmpty() )
    5883             :     {
    5884             :         /* PDF allows only RFC 3066, see above in emitStructure(). */
    5885           0 :         LanguageTag aLanguageTag( m_aContext.DocumentLocale);
    5886           0 :         OUString aLanguage, aScript, aCountry;
    5887           0 :         aLanguageTag.getIsoLanguageScriptCountry( aLanguage, aScript, aCountry);
    5888           0 :         if (!aLanguage.isEmpty())
    5889             :         {
    5890           0 :             OUStringBuffer aLocBuf( 16 );
    5891           0 :             aLocBuf.append( aLanguage );
    5892           0 :             if( !aCountry.isEmpty() )
    5893             :             {
    5894           0 :                 aLocBuf.append( '-' );
    5895           0 :                 aLocBuf.append( aCountry );
    5896             :             }
    5897           0 :             aLine.append( "/Lang" );
    5898           0 :             appendLiteralStringEncrypt( aLocBuf.makeStringAndClear(), m_nCatalogObject, aLine );
    5899           0 :             aLine.append( "\n" );
    5900           0 :         }
    5901             :     }
    5902           0 :     if( m_aContext.Tagged && m_aContext.Version > PDFWriter::PDF_1_3 )
    5903             :     {
    5904           0 :         aLine.append( "/MarkInfo<</Marked true>>\n" );
    5905             :     }
    5906           0 :     if( m_aWidgets.size() > 0 )
    5907             :     {
    5908           0 :         aLine.append( "/AcroForm<</Fields[\n" );
    5909           0 :         int nWidgets = m_aWidgets.size();
    5910           0 :         int nOut = 0;
    5911           0 :         for( int j = 0; j < nWidgets; j++ )
    5912             :         {
    5913             :             // output only root fields
    5914           0 :             if( m_aWidgets[j].m_nParent < 1 )
    5915             :             {
    5916           0 :                 aLine.append( m_aWidgets[j].m_nObject );
    5917           0 :                 aLine.append( (nOut++ % 5)==4 ? " 0 R\n" : " 0 R " );
    5918             :             }
    5919             :         }
    5920           0 :         aLine.append( "\n]" );
    5921             : 
    5922             : #if !defined(ANDROID) && !defined(IOS)
    5923           0 :         if (m_nSignatureObject != -1)
    5924           0 :             aLine.append( "/SigFlags 3");
    5925             : #endif
    5926             : 
    5927           0 :         aLine.append( "/DR " );
    5928           0 :         aLine.append( getResourceDictObj() );
    5929           0 :         aLine.append( " 0 R" );
    5930             :         // /NeedAppearances must not be used if PDF is signed
    5931           0 :         if( m_bIsPDF_A1
    5932             : #if !defined(ANDROID) && !defined(IOS)
    5933           0 :             || ( m_nSignatureObject != -1 )
    5934             : #endif
    5935             :             )
    5936           0 :             aLine.append( ">>\n" );
    5937             :         else
    5938           0 :             aLine.append( "/NeedAppearances true>>\n" );
    5939             :     }
    5940             : 
    5941             : //--->i59651
    5942             :     //check if there is a Metadata object
    5943           0 :     if( nOutputIntentObject )
    5944             :     {
    5945           0 :         aLine.append("/OutputIntents[");
    5946           0 :         aLine.append( nOutputIntentObject );
    5947           0 :         aLine.append( " 0 R]" );
    5948             :     }
    5949             : 
    5950           0 :     if( nMetadataObject )
    5951             :     {
    5952           0 :         aLine.append("/Metadata ");
    5953           0 :         aLine.append( nMetadataObject );
    5954           0 :         aLine.append( " 0 R" );
    5955             :     }
    5956             : //<----
    5957             :     aLine.append( ">>\n"
    5958           0 :                   "endobj\n\n" );
    5959           0 :     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
    5960             : 
    5961           0 :     return true;
    5962             : }
    5963             : 
    5964             : #if !defined(ANDROID) && !defined(IOS)
    5965             : 
    5966           0 : bool PDFWriterImpl::emitSignature()
    5967             : {
    5968           0 :     if( !updateObject( m_nSignatureObject ) )
    5969           0 :         return false;
    5970             : 
    5971           0 :     OStringBuffer aLine( 0x5000 );
    5972           0 :     aLine.append( m_nSignatureObject );
    5973           0 :     aLine.append( " 0 obj\n" );
    5974           0 :     aLine.append("<</Contents <" );
    5975             : 
    5976           0 :     sal_uInt64 nOffset = ~0U;
    5977           0 :     CHECK_RETURN( (osl::File::E_None == m_aFile.getPos(nOffset) ) );
    5978             : 
    5979           0 :     m_nSignatureContentOffset = nOffset + aLine.getLength();
    5980             : 
    5981             :     // reserve some space for the PKCS#7 object
    5982           0 :     OStringBuffer aContentFiller( MAX_SIGNATURE_CONTENT_LENGTH );
    5983           0 :     comphelper::string::padToLength(aContentFiller, MAX_SIGNATURE_CONTENT_LENGTH, '0');
    5984           0 :     aLine.append( aContentFiller.makeStringAndClear() );
    5985           0 :     aLine.append( ">\n/Type/Sig/SubFilter/adbe.pkcs7.detached");
    5986             : 
    5987           0 :     if( !m_aContext.DocumentInfo.Author.isEmpty() )
    5988             :     {
    5989           0 :         aLine.append( "/Name" );
    5990           0 :         appendUnicodeTextStringEncrypt( m_aContext.DocumentInfo.Author, m_nSignatureObject, aLine );
    5991             :     }
    5992             : 
    5993           0 :     aLine.append( " /M ");
    5994           0 :     appendLiteralStringEncrypt( m_aCreationDateString, m_nSignatureObject, aLine );
    5995             : 
    5996           0 :     aLine.append( " /ByteRange [ 0 ");
    5997           0 :     aLine.append( m_nSignatureContentOffset - 1, 10 );
    5998           0 :     aLine.append( " " );
    5999           0 :     aLine.append( m_nSignatureContentOffset + MAX_SIGNATURE_CONTENT_LENGTH + 1, 10 );
    6000           0 :     aLine.append( " " );
    6001             : 
    6002           0 :     m_nSignatureLastByteRangeNoOffset = nOffset + aLine.getLength();
    6003             : 
    6004             :     // mark the last ByteRange no and add some space. Now, we don't know
    6005             :     // how many bytes we need for this ByteRange value
    6006             :     // The real value will be overwritten in the finalizeSignature method
    6007           0 :     OStringBuffer aByteRangeFiller( 100  );
    6008           0 :     comphelper::string::padToLength(aByteRangeFiller, 100, ' ');
    6009           0 :     aLine.append( aByteRangeFiller.makeStringAndClear() );
    6010           0 :     aLine.append("  /Filter/Adobe.PPKMS");
    6011             : 
    6012             :     //emit reason, location and contactinfo
    6013           0 :     if ( !m_aContext.SignReason.isEmpty() )
    6014             :     {
    6015           0 :         aLine.append("/Reason");
    6016           0 :         appendUnicodeTextStringEncrypt( m_aContext.SignReason, m_nSignatureObject, aLine );
    6017             :     }
    6018             : 
    6019           0 :     if ( !m_aContext.SignLocation.isEmpty() )
    6020             :     {
    6021           0 :         aLine.append("/Location");
    6022           0 :         appendUnicodeTextStringEncrypt( m_aContext.SignLocation, m_nSignatureObject, aLine );
    6023             :     }
    6024             : 
    6025           0 :     if ( !m_aContext.SignContact.isEmpty() )
    6026             :     {
    6027           0 :         aLine.append("/ContactInfo");
    6028           0 :         appendUnicodeTextStringEncrypt( m_aContext.SignContact, m_nSignatureObject, aLine );
    6029             :     }
    6030             : 
    6031           0 :     aLine.append(" >>\nendobj\n\n" );
    6032             : 
    6033           0 :     if (!writeBuffer( aLine.getStr(), aLine.getLength() ))
    6034           0 :         return false;
    6035             : 
    6036           0 :     return true;
    6037             : }
    6038             : 
    6039             : #if !defined(ANDROID) && !defined(IOS) && !defined(_WIN32)
    6040             : 
    6041             : namespace {
    6042             : #if 0
    6043             : }
    6044             : #endif
    6045             : 
    6046           0 : char *PDFSigningPKCS7PasswordCallback(PK11SlotInfo * /*slot*/, PRBool /*retry*/, void *arg)
    6047             : {
    6048           0 :     return PL_strdup(static_cast<char *>(arg));
    6049             : }
    6050             : 
    6051             : class HashContextScope {
    6052             :     HASHContext *mpPtr;
    6053             : public:
    6054           0 :     explicit HashContextScope(HASHContext *pPtr) : mpPtr(pPtr) {}
    6055           0 :     ~HashContextScope() { clear(); }
    6056           0 :     void clear() { if (mpPtr) { HASH_Destroy(mpPtr); } mpPtr = NULL; }
    6057           0 :     HASHContext *get() { return mpPtr; }
    6058             : };
    6059             : 
    6060             : // ASN.1 used in the (much simpler) time stamp request. From RFC3161
    6061             : // and other sources.
    6062             : 
    6063             : /*
    6064             : AlgorithmIdentifier  ::=  SEQUENCE  {
    6065             :      algorithm  OBJECT IDENTIFIER,
    6066             :      parameters ANY DEFINED BY algorithm OPTIONAL  }
    6067             :                    -- contains a value of the type
    6068             :                    -- registered for use with the
    6069             :                    -- algorithm object identifier value
    6070             : 
    6071             : MessageImprint ::= SEQUENCE  {
    6072             :     hashAlgorithm AlgorithmIdentifier,
    6073             :     hashedMessage OCTET STRING  }
    6074             : */
    6075             : 
    6076             : typedef struct {
    6077             :     SECAlgorithmID hashAlgorithm;
    6078             :     SECItem hashedMessage;
    6079             : } MessageImprint;
    6080             : 
    6081             : /*
    6082             : Extension  ::=  SEQUENCE  {
    6083             :     extnID    OBJECT IDENTIFIER,
    6084             :     critical  BOOLEAN DEFAULT FALSE,
    6085             :     extnValue OCTET STRING  }
    6086             : */
    6087             : 
    6088             : typedef struct {
    6089             :     SECItem extnID;
    6090             :     SECItem critical;
    6091             :     SECItem extnValue;
    6092             : } Extension;
    6093             : 
    6094             : /*
    6095             : Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
    6096             : */
    6097             : 
    6098             : /*
    6099             : TSAPolicyId ::= OBJECT IDENTIFIER
    6100             : 
    6101             : TimeStampReq ::= SEQUENCE  {
    6102             :     version            INTEGER  { v1(1) },
    6103             :     messageImprint     MessageImprint,
    6104             :     --a hash algorithm OID and the hash value of the data to be
    6105             :     --time-stamped
    6106             :     reqPolicy          TSAPolicyId         OPTIONAL,
    6107             :     nonce              INTEGER             OPTIONAL,
    6108             :     certReq            BOOLEAN             DEFAULT FALSE,
    6109             :     extensions     [0] IMPLICIT Extensions OPTIONAL  }
    6110             : */
    6111             : 
    6112             : typedef struct {
    6113             :     SECItem version;
    6114             :     MessageImprint messageImprint;
    6115             :     SECItem reqPolicy;
    6116             :     SECItem nonce;
    6117             :     SECItem certReq;
    6118             :     Extension *extensions;
    6119             : } TimeStampReq;
    6120             : 
    6121             : // (Partial) ASN.1 for the time stamp responce. Very complicated. Pulled
    6122             : // together from varuous RFCs.
    6123             : 
    6124             : /*
    6125             : Accuracy ::= SEQUENCE {
    6126             :     seconds     INTEGER          OPTIONAL,
    6127             :     millis  [0] INTEGER (1..999) OPTIONAL,
    6128             :     micros  [1] INTEGER (1..999) OPTIONAL  }
    6129             : 
    6130             : PKIStatus ::= INTEGER {
    6131             :     granted                (0),
    6132             :     -- when the PKIStatus contains the value zero a TimeStampToken, as requested, is present.
    6133             :     grantedWithMods        (1),
    6134             :      -- when the PKIStatus contains the value one a TimeStampToken, with modifications, is present.
    6135             :     rejection              (2),
    6136             :     waiting                (3),
    6137             :     revocationWarning      (4),
    6138             :      -- this message contains a warning that a revocation is
    6139             :      -- imminent
    6140             :     revocationNotification (5)
    6141             :      -- notification that a revocation has occurred
    6142             : }
    6143             : 
    6144             : PKIFreeText ::= SEQUENCE SIZE (1..MAX) OF UTF8String
    6145             :     -- text encoded as UTF-8 String [RFC3629] (note: each
    6146             :     -- UTF8String MAY include an [RFC3066] language tag
    6147             :     -- to indicate the language of the contained text
    6148             :     -- see [RFC2482] for details)
    6149             : 
    6150             : PKIFailureInfo ::= BIT STRING {
    6151             :     badAlg               (0),
    6152             :       -- unrecognized or unsupported Algorithm Identifier
    6153             :     badRequest           (2),
    6154             :       -- transaction not permitted or supported
    6155             :     badDataFormat        (5),
    6156             :       -- the data submitted has the wrong format
    6157             :     timeNotAvailable    (14),
    6158             :       -- the TSA's time source is not available
    6159             :     unacceptedPolicy    (15),
    6160             :       -- the requested TSA policy is not supported by the TSA.
    6161             :     unacceptedExtension (16),
    6162             :       -- the requested extension is not supported by the TSA.
    6163             :     addInfoNotAvailable (17),
    6164             :       -- the additional information requested could not be understood
    6165             :       -- or is not available
    6166             :     systemFailure       (25)
    6167             :       -- the request cannot be handled due to system failure
    6168             : }
    6169             : 
    6170             : PKIStatusInfo ::= SEQUENCE {
    6171             :     status       PKIStatus,
    6172             :     statusString PKIFreeText    OPTIONAL,
    6173             :     failInfo     PKIFailureInfo OPTIONAL  }
    6174             : 
    6175             : ContentType ::= OBJECT IDENTIFIER
    6176             : 
    6177             : ContentInfo ::= SEQUENCE {
    6178             :     contentType     ContentType,
    6179             :     content     [0] EXPLICIT ANY DEFINED BY contentType }
    6180             : 
    6181             : CMSVersion ::= INTEGER { v0(0), v1(1), v2(2), v3(3), v4(4), v5(5) }
    6182             : 
    6183             : DigestAlgorithmIdentifier ::= AlgorithmIdentifier
    6184             : 
    6185             : DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier
    6186             : 
    6187             : ContentType ::= OBJECT IDENTIFIER
    6188             : 
    6189             : EncapsulatedContentInfo ::= SEQUENCE {
    6190             :     eContentType     ContentType,
    6191             :     eContent     [0] EXPLICIT OCTET STRING OPTIONAL }
    6192             : 
    6193             : OtherCertificateFormat ::= SEQUENCE {
    6194             :     otherCertFormat OBJECT IDENTIFIER,
    6195             :     otherCert       ANY DEFINED BY otherCertFormat }
    6196             : 
    6197             : CertificateChoices ::= CHOICE {
    6198             :     certificate             Certificate,
    6199             :     extendedCertificate [0] IMPLICIT ExtendedCertificate, -- Obsolete
    6200             :     v1AttrCert          [1] IMPLICIT AttributeCertificateV1,       -- Obsolete
    6201             :     v2AttrCert          [2] IMPLICIT AttributeCertificateV2,
    6202             :     other               [3] IMPLICIT OtherCertificateFormat }
    6203             : 
    6204             : CertificateSet ::= SET OF CertificateChoices
    6205             : 
    6206             : CertificateList  ::=  SEQUENCE  {
    6207             :     tbsCertList        TBSCertList,
    6208             :     signatureAlgorithm AlgorithmIdentifier,
    6209             :     signatureValue     BIT STRING  }
    6210             : 
    6211             : TBSCertList  ::=  SEQUENCE  {
    6212             :     version                 Version OPTIONAL,
    6213             :                                   -- if present, MUST be v2
    6214             :     signature               AlgorithmIdentifier,
    6215             :     issuer                  Name,
    6216             :     thisUpdate              Time,
    6217             :     nextUpdate              Time OPTIONAL,
    6218             :     revokedCertificates     SEQUENCE OF SEQUENCE  {
    6219             :         userCertificate         CertificateSerialNumber,
    6220             :         revocationDate          Time,
    6221             :         crlEntryExtensions      Extensions OPTIONAL
    6222             :                                    -- if present, version MUST be v2
    6223             :                             }  OPTIONAL,
    6224             :     crlExtensions       [0] EXPLICIT Extensions OPTIONAL
    6225             :                                    -- if present, version MUST be v2
    6226             :                             }
    6227             : 
    6228             : OtherRevocationInfoFormat ::= SEQUENCE {
    6229             :   otherRevInfoFormat OBJECT IDENTIFIER,
    6230             :   otherRevInfo ANY DEFINED BY otherRevInfoFormat }
    6231             : 
    6232             : RevocationInfoChoice ::= CHOICE {
    6233             :     crl       CertificateList,
    6234             :     other [1] IMPLICIT OtherRevocationInfoFormat }
    6235             : 
    6236             : RevocationInfoChoices ::= SET OF RevocationInfoChoice
    6237             : 
    6238             : SignerIdentifier ::= CHOICE {
    6239             :     issuerAndSerialNumber IssuerAndSerialNumber,
    6240             :     subjectKeyIdentifier [0] SubjectKeyIdentifier }
    6241             : 
    6242             : AttributeValue ::= ANY
    6243             : 
    6244             : Attribute ::= SEQUENCE {
    6245             :     attrType OBJECT IDENTIFIER,
    6246             :     attrValues SET OF AttributeValue }
    6247             : 
    6248             : SignedAttributes ::= SET SIZE (1..MAX) OF Attribute
    6249             : 
    6250             : SignatureValue ::= OCTET STRING
    6251             : 
    6252             : UnsignedAttributes ::= SET SIZE (1..MAX) OF Attribute
    6253             : 
    6254             : SignerInfo ::= SEQUENCE {
    6255             :     version CMSVersion,
    6256             :     sid SignerIdentifier,
    6257             :     digestAlgorithm DigestAlgorithmIdentifier,
    6258             :     signedAttrs [0] IMPLICIT SignedAttributes OPTIONAL,
    6259             :     signatureAlgorithm SignatureAlgorithmIdentifier,
    6260             :     signature SignatureValue,
    6261             :     unsignedAttrs [1] IMPLICIT UnsignedAttributes OPTIONAL }
    6262             : 
    6263             : SignerInfos ::= SET OF SignerInfo
    6264             : 
    6265             : SignedData ::= SEQUENCE {
    6266             :     version                       CMSVersion,
    6267             :     digestAlgorithms              DigestAlgorithmIdentifiers,
    6268             :     encapContentInfo              EncapsulatedContentInfo,
    6269             :     certificates     [0] IMPLICIT CertificateSet              OPTIONAL,
    6270             :     crls             [1] IMPLICIT RevocationInfoChoices       OPTIONAL,
    6271             :     signerInfos                   SignerInfos }
    6272             : 
    6273             : TimeStampToken ::= ContentInfo
    6274             :     -- contentType is id-signedData as defined in [CMS]
    6275             :     -- content is SignedData as defined in([CMS])
    6276             :     -- eContentType within SignedData is id-ct-TSTInfo
    6277             :     -- eContent within SignedData is TSTInfo
    6278             : 
    6279             : TSTInfo ::= SEQUENCE  {
    6280             :     version            INTEGER  { v1(1) },
    6281             :     policy             TSAPolicyId,
    6282             :     messageImprint     MessageImprint,
    6283             :       -- MUST have the same value as the similar field in
    6284             :       -- TimeStampReq
    6285             :     serialNumber       INTEGER,
    6286             :      -- Time-Stamping users MUST be ready to accommodate integers
    6287             :      -- up to 160 bits.
    6288             :     genTime            GeneralizedTime,
    6289             :     accuracy           Accuracy            OPTIONAL,
    6290             :     ordering           BOOLEAN             DEFAULT FALSE,
    6291             :     nonce              INTEGER             OPTIONAL,
    6292             :       -- MUST be present if the similar field was present
    6293             :       -- in TimeStampReq.  In that case it MUST have the same value.
    6294             :     tsa            [0] GeneralName         OPTIONAL,
    6295             :     extensions     [1] IMPLICIT Extensions OPTIONAL   }
    6296             : 
    6297             : TimeStampResp ::= SEQUENCE  {
    6298             :      status         PKIStatusInfo,
    6299             :      timeStampToken TimeStampToken OPTIONAL  }
    6300             : */
    6301             : 
    6302             : const SEC_ASN1Template MessageImprint_Template[] =
    6303             : {
    6304             :     { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(MessageImprint) },
    6305             :     { SEC_ASN1_INLINE, offsetof(MessageImprint, hashAlgorithm), SECOID_AlgorithmIDTemplate, 0 },
    6306             :     { SEC_ASN1_OCTET_STRING, offsetof(MessageImprint, hashedMessage), 0, 0 },
    6307             :     { 0, 0, 0, 0 }
    6308             : };
    6309             : 
    6310             : const SEC_ASN1Template Extension_Template[] =
    6311             : {
    6312             :     { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(Extension) },
    6313             :     { SEC_ASN1_OBJECT_ID, offsetof(Extension, extnID), 0, 0 },
    6314             :     { SEC_ASN1_BOOLEAN, offsetof(Extension, critical), 0, 0 },
    6315             :     { SEC_ASN1_OCTET_STRING, offsetof(Extension, extnValue), 0, 0 },
    6316             :     { 0, 0, 0, 0 }
    6317             : };
    6318             : 
    6319             : const SEC_ASN1Template Extensions_Template[] =
    6320             : {
    6321             :     { SEC_ASN1_SEQUENCE_OF, 0, Extension_Template, 0 }
    6322             : };
    6323             : 
    6324             : const SEC_ASN1Template TimeStampReq_Template[] =
    6325             : {
    6326             :     { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(TimeStampReq) },
    6327             :     { SEC_ASN1_INTEGER, offsetof(TimeStampReq, version), 0, 0 },
    6328             :     { SEC_ASN1_INLINE, offsetof(TimeStampReq, messageImprint), MessageImprint_Template, 0 },
    6329             :     { SEC_ASN1_OBJECT_ID | SEC_ASN1_OPTIONAL, offsetof(TimeStampReq, reqPolicy), 0, 0 },
    6330             :     { SEC_ASN1_INTEGER | SEC_ASN1_OPTIONAL, offsetof(TimeStampReq, nonce), 0, 0 },
    6331             :     { SEC_ASN1_BOOLEAN | SEC_ASN1_OPTIONAL, offsetof(TimeStampReq, certReq), 0, 0 },
    6332             :     { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | 0, offsetof(TimeStampReq, extensions), Extensions_Template, 0 },
    6333             :     { 0, 0, 0, 0 }
    6334             : };
    6335             : 
    6336             : typedef struct {
    6337             :     SECItem status;
    6338             :     SECItem statusString;
    6339             :     SECItem failInfo;
    6340             : } PKIStatusInfo;
    6341             : 
    6342             : const SEC_ASN1Template PKIStatusInfo_Template[] =
    6343             : {
    6344             :     { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(PKIStatusInfo) },
    6345             :     { SEC_ASN1_INTEGER, offsetof(PKIStatusInfo, status), 0, 0 },
    6346             :     { SEC_ASN1_CONSTRUCTED | SEC_ASN1_SEQUENCE | SEC_ASN1_OPTIONAL, offsetof(PKIStatusInfo, statusString), 0, 0 },
    6347             :     { SEC_ASN1_BIT_STRING | SEC_ASN1_OPTIONAL, offsetof(PKIStatusInfo, failInfo), 0, 0 },
    6348             :     { 0, 0, 0, 0 }
    6349             : };
    6350             : 
    6351             : const SEC_ASN1Template Any_Template[] =
    6352             : {
    6353             :     { SEC_ASN1_ANY, 0, NULL, sizeof(SECItem) }
    6354             : };
    6355             : 
    6356             : typedef struct {
    6357             :     PKIStatusInfo status;
    6358             :     SECItem timeStampToken;
    6359             : } TimeStampResp;
    6360             : 
    6361             : const SEC_ASN1Template TimeStampResp_Template[] =
    6362             : {
    6363             :     { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(TimeStampResp) },
    6364             :     { SEC_ASN1_INLINE, offsetof(TimeStampResp, status), PKIStatusInfo_Template, 0 },
    6365             :     { SEC_ASN1_ANY | SEC_ASN1_OPTIONAL, offsetof(TimeStampResp, timeStampToken), Any_Template, 0 },
    6366             :     { 0, 0, 0, 0 }
    6367             : };
    6368             : 
    6369             : /* Will see if these are needed or not
    6370             : typedef struct {
    6371             :     SECItem seconds;
    6372             :     SECItem millis;
    6373             :     SECItem micros;
    6374             : } Accuracy;
    6375             : 
    6376             : const SEC_ASN1Template Integer_Template[] =
    6377             : {
    6378             :     { SEC_ASN1_INTEGER, 0, NULL, sizeof(SECItem) }
    6379             : };
    6380             : 
    6381             : const SEC_ASN1Template Accuracy_Template[] =
    6382             : {
    6383             :     { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(Accuracy) },
    6384             :     { SEC_ASN1_INTEGER | SEC_ASN1_OPTIONAL, offsetof(Accuracy, seconds), 0, 0 },
    6385             :     { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | 0, offsetof(Accuracy, millis), Integer_Template, 0 },
    6386             :     { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | 1, offsetof(Accuracy, micros), Integer_Template, 0 },
    6387             :     { 0, 0, 0, 0 }
    6388             : };
    6389             : */
    6390             : 
    6391           0 : size_t AppendToBuffer(char *ptr, size_t size, size_t nmemb, void *userdata)
    6392             : {
    6393           0 :     OStringBuffer *pBuffer = static_cast<OStringBuffer*>(userdata);
    6394           0 :     pBuffer->append(ptr, size*nmemb);
    6395             : 
    6396           0 :     return size*nmemb;
    6397             : }
    6398             : 
    6399           0 : OUString PKIStatusToString(int n)
    6400             : {
    6401           0 :     switch (n)
    6402             :     {
    6403           0 :     case 0: return OUString("granted");
    6404           0 :     case 1: return OUString("grantedWithMods");
    6405           0 :     case 2: return OUString("rejection");
    6406           0 :     case 3: return OUString("waiting");
    6407           0 :     case 4: return OUString("revocationWarning");
    6408           0 :     case 5: return OUString("revocationNotification");
    6409           0 :     default: return "unknown (" + OUString::number(n) + ")";
    6410             :     }
    6411             : }
    6412             : 
    6413           0 : OUString PKIStatusInfoToString(const PKIStatusInfo& rStatusInfo)
    6414             : {
    6415           0 :     OUString result;
    6416             : 
    6417           0 :     result += "{status=";
    6418           0 :     if (rStatusInfo.status.len == 1)
    6419           0 :         result += PKIStatusToString(rStatusInfo.status.data[0]);
    6420             :     else
    6421           0 :         result += "unknown (len=" + OUString::number(rStatusInfo.status.len);
    6422             : 
    6423             :     // FIXME: Perhaps look at rStatusInfo.statusString.data but note
    6424             :     // that we of course can't assume it contains proper UTF-8. After
    6425             :     // all, it is data from an external source. Also, RFC3161 claims
    6426             :     // it should be a SEQUENCE (1..MAX) OF UTF8String, but another
    6427             :     // source claimed it would be a single UTF8String, hmm?
    6428             : 
    6429             :     // FIXME: Worth it to decode failInfo to cleartext, probably not at least as long as this is only for a SAL_INFO
    6430             : 
    6431           0 :     result += "}";
    6432             : 
    6433           0 :     return result;
    6434             : }
    6435             : 
    6436             : // SEC_StringToOID() and NSS_CMSSignerInfo_AddUnauthAttr() are
    6437             : // not exported from libsmime, so copy them here. Sigh.
    6438             : 
    6439             : SECStatus
    6440           0 : my_SEC_StringToOID(PLArenaPool *pool, SECItem *to, const char *from, PRUint32 len)
    6441             : {
    6442           0 :     PRUint32 decimal_numbers = 0;
    6443           0 :     PRUint32 result_bytes = 0;
    6444             :     SECStatus rv;
    6445             :     PRUint8 result[1024];
    6446             : 
    6447             :     static const PRUint32 max_decimal = (0xffffffff / 10);
    6448             :     static const char OIDstring[] = {"OID."};
    6449             : 
    6450           0 :     if (!from || !to) {
    6451           0 :         PORT_SetError(SEC_ERROR_INVALID_ARGS);
    6452           0 :     return SECFailure;
    6453             :     }
    6454           0 :     if (!len) {
    6455           0 :         len = PL_strlen(from);
    6456             :     }
    6457           0 :     if (len >= 4 && !PL_strncasecmp(from, OIDstring, 4)) {
    6458           0 :         from += 4; /* skip leading "OID." if present */
    6459           0 :     len  -= 4;
    6460             :     }
    6461           0 :     if (!len) {
    6462             : bad_data:
    6463           0 :         PORT_SetError(SEC_ERROR_BAD_DATA);
    6464           0 :     return SECFailure;
    6465             :     }
    6466           0 :     do {
    6467           0 :     PRUint32 decimal = 0;
    6468           0 :         while (len > 0 && isdigit(*from)) {
    6469           0 :         PRUint32 addend = (*from++ - '0');
    6470           0 :         --len;
    6471           0 :         if (decimal > max_decimal)  /* overflow */
    6472           0 :             goto bad_data;
    6473           0 :         decimal = (decimal * 10) + addend;
    6474           0 :         if (decimal < addend)   /* overflow */
    6475           0 :         goto bad_data;
    6476             :     }
    6477           0 :     if (len != 0 && *from != '.') {
    6478           0 :         goto bad_data;
    6479             :     }
    6480           0 :     if (decimal_numbers == 0) {
    6481           0 :         if (decimal > 2)
    6482           0 :             goto bad_data;
    6483           0 :         result[0] = decimal * 40;
    6484           0 :         result_bytes = 1;
    6485           0 :     } else if (decimal_numbers == 1) {
    6486           0 :         if (decimal > 40)
    6487           0 :             goto bad_data;
    6488           0 :         result[0] += decimal;
    6489             :     } else {
    6490             :         /* encode the decimal number,  */
    6491             :         PRUint8 * rp;
    6492           0 :         PRUint32 num_bytes = 0;
    6493           0 :         PRUint32 tmp = decimal;
    6494           0 :         while (tmp) {
    6495           0 :             num_bytes++;
    6496           0 :         tmp >>= 7;
    6497             :         }
    6498           0 :         if (!num_bytes )
    6499           0 :             ++num_bytes;  /* use one byte for a zero value */
    6500           0 :         if (num_bytes + result_bytes > sizeof result)
    6501           0 :             goto bad_data;
    6502           0 :         tmp = num_bytes;
    6503           0 :         rp = result + result_bytes - 1;
    6504           0 :         rp[tmp] = (PRUint8)(decimal & 0x7f);
    6505           0 :         decimal >>= 7;
    6506           0 :         while (--tmp > 0) {
    6507           0 :         rp[tmp] = (PRUint8)(decimal | 0x80);
    6508           0 :         decimal >>= 7;
    6509             :         }
    6510           0 :         result_bytes += num_bytes;
    6511             :     }
    6512           0 :     ++decimal_numbers;
    6513           0 :     if (len > 0) { /* skip trailing '.' */
    6514           0 :         ++from;
    6515           0 :         --len;
    6516             :     }
    6517             :     } while (len > 0);
    6518             :     /* now result contains result_bytes of data */
    6519           0 :     if (to->data && to->len >= result_bytes) {
    6520           0 :         PORT_Memcpy(to->data, result, to->len = result_bytes);
    6521           0 :     rv = SECSuccess;
    6522             :     } else {
    6523           0 :         SECItem result_item = {siBuffer, NULL, 0 };
    6524           0 :     result_item.data = result;
    6525           0 :     result_item.len  = result_bytes;
    6526           0 :     rv = SECITEM_CopyItem(pool, to, &result_item);
    6527             :     }
    6528           0 :     return rv;
    6529             : }
    6530             : 
    6531             : NSSCMSAttribute *
    6532           0 : my_NSS_CMSAttributeArray_FindAttrByOidTag(NSSCMSAttribute **attrs, SECOidTag oidtag, PRBool only)
    6533             : {
    6534             :     SECOidData *oid;
    6535             :     NSSCMSAttribute *attr1, *attr2;
    6536             : 
    6537           0 :     if (attrs == NULL)
    6538           0 :         return NULL;
    6539             : 
    6540           0 :     oid = SECOID_FindOIDByTag(oidtag);
    6541           0 :     if (oid == NULL)
    6542           0 :         return NULL;
    6543             : 
    6544           0 :     while ((attr1 = *attrs++) != NULL) {
    6545           0 :     if (attr1->type.len == oid->oid.len && PORT_Memcmp (attr1->type.data,
    6546             :                                 oid->oid.data,
    6547           0 :                                 oid->oid.len) == 0)
    6548           0 :         break;
    6549             :     }
    6550             : 
    6551           0 :     if (attr1 == NULL)
    6552           0 :         return NULL;
    6553             : 
    6554           0 :     if (!only)
    6555           0 :         return attr1;
    6556             : 
    6557           0 :     while ((attr2 = *attrs++) != NULL) {
    6558           0 :     if (attr2->type.len == oid->oid.len && PORT_Memcmp (attr2->type.data,
    6559             :                                 oid->oid.data,
    6560           0 :                                 oid->oid.len) == 0)
    6561           0 :         break;
    6562             :     }
    6563             : 
    6564           0 :     if (attr2 != NULL)
    6565           0 :         return NULL;
    6566             : 
    6567           0 :     return attr1;
    6568             : }
    6569             : 
    6570             : SECStatus
    6571           0 : my_NSS_CMSArray_Add(PLArenaPool *poolp, void ***array, void *obj)
    6572             : {
    6573             :     void **p;
    6574             :     int n;
    6575             :     void **dest;
    6576             : 
    6577             :     PORT_Assert(array != NULL);
    6578           0 :     if (array == NULL)
    6579           0 :         return SECFailure;
    6580             : 
    6581           0 :     if (*array == NULL) {
    6582           0 :     dest = static_cast<void **>(PORT_ArenaAlloc(poolp, 2 * sizeof(void *)));
    6583           0 :     n = 0;
    6584             :     } else {
    6585           0 :     n = 0; p = *array;
    6586           0 :     while (*p++)
    6587           0 :         n++;
    6588             :     dest = static_cast<void **>(PORT_ArenaGrow (poolp,
    6589             :                   *array,
    6590           0 :                   (n + 1) * sizeof(void *),
    6591           0 :                   (n + 2) * sizeof(void *)));
    6592             :     }
    6593             : 
    6594           0 :     if (dest == NULL)
    6595           0 :         return SECFailure;
    6596             : 
    6597           0 :     dest[n] = obj;
    6598           0 :     dest[n+1] = NULL;
    6599           0 :     *array = dest;
    6600           0 :     return SECSuccess;
    6601             : }
    6602             : 
    6603             : SECOidTag
    6604           0 : my_NSS_CMSAttribute_GetType(NSSCMSAttribute *attr)
    6605             : {
    6606             :     SECOidData *typetag;
    6607             : 
    6608           0 :     typetag = SECOID_FindOID(&(attr->type));
    6609           0 :     if (typetag == NULL)
    6610           0 :         return SEC_OID_UNKNOWN;
    6611             : 
    6612           0 :     return typetag->offset;
    6613             : }
    6614             : 
    6615             : SECStatus
    6616           0 : my_NSS_CMSAttributeArray_AddAttr(PLArenaPool *poolp, NSSCMSAttribute ***attrs, NSSCMSAttribute *attr)
    6617             : {
    6618             :     NSSCMSAttribute *oattr;
    6619             :     void *mark;
    6620             :     SECOidTag type;
    6621             : 
    6622           0 :     mark = PORT_ArenaMark(poolp);
    6623             : 
    6624             :     /* find oidtag of attr */
    6625           0 :     type = my_NSS_CMSAttribute_GetType(attr);
    6626             : 
    6627             :     /* see if we have one already */
    6628           0 :     oattr = my_NSS_CMSAttributeArray_FindAttrByOidTag(*attrs, type, PR_FALSE);
    6629             :     PORT_Assert (oattr == NULL);
    6630           0 :     if (oattr != NULL)
    6631           0 :         goto loser; /* XXX or would it be better to replace it? */
    6632             : 
    6633             :     /* no, shove it in */
    6634           0 :     if (my_NSS_CMSArray_Add(poolp, reinterpret_cast<void ***>(attrs), static_cast<void *>(attr)) != SECSuccess)
    6635           0 :         goto loser;
    6636             : 
    6637           0 :     PORT_ArenaUnmark(poolp, mark);
    6638           0 :     return SECSuccess;
    6639             : 
    6640             : loser:
    6641           0 :     PORT_ArenaRelease(poolp, mark);
    6642           0 :     return SECFailure;
    6643             : }
    6644             : 
    6645             : SECStatus
    6646           0 : my_NSS_CMSSignerInfo_AddUnauthAttr(NSSCMSSignerInfo *signerinfo, NSSCMSAttribute *attr)
    6647             : {
    6648           0 :     return my_NSS_CMSAttributeArray_AddAttr(signerinfo->cmsg->poolp, &(signerinfo->unAuthAttr), attr);
    6649             : }
    6650             : 
    6651           0 : NSSCMSMessage *CreateCMSMessage(PRTime time,
    6652             :                                 NSSCMSSignedData **cms_sd,
    6653             :                                 NSSCMSSignerInfo **cms_signer,
    6654             :                                 CERTCertificate *cert,
    6655             :                                 SECItem *digest)
    6656             : {
    6657           0 :     NSSCMSMessage *result = NSS_CMSMessage_Create(NULL);
    6658           0 :     if (!result)
    6659             :     {
    6660             :         SAL_WARN("vcl.pdfwriter", "NSS_CMSMessage_Create failed");
    6661           0 :         return NULL;
    6662             :     }
    6663             : 
    6664           0 :     *cms_sd = NSS_CMSSignedData_Create(result);
    6665           0 :     if (!*cms_sd)
    6666             :     {
    6667             :         SAL_WARN("vcl.pdfwriter", "NSS_CMSSignedData_Create failed");
    6668           0 :         NSS_CMSMessage_Destroy(result);
    6669           0 :         return NULL;
    6670             :     }
    6671             : 
    6672           0 :     NSSCMSContentInfo *cms_cinfo = NSS_CMSMessage_GetContentInfo(result);
    6673           0 :     if (NSS_CMSContentInfo_SetContent_SignedData(result, cms_cinfo, *cms_sd) != SECSuccess)
    6674             :     {
    6675             :         SAL_WARN("vcl.pdfwriter", "NSS_CMSContentInfo_SetContent_SignedData failed");
    6676           0 :         NSS_CMSSignedData_Destroy(*cms_sd);
    6677           0 :         NSS_CMSMessage_Destroy(result);
    6678           0 :         return NULL;
    6679             :     }
    6680             : 
    6681           0 :     cms_cinfo = NSS_CMSSignedData_GetContentInfo(*cms_sd);
    6682             : 
    6683             :     // Attach NULL data as detached data
    6684           0 :     if (NSS_CMSContentInfo_SetContent_Data(result, cms_cinfo, NULL, PR_TRUE) != SECSuccess)
    6685             :     {
    6686             :         SAL_WARN("vcl.pdfwriter", "NSS_CMSContentInfo_SetContent_Data failed");
    6687           0 :         NSS_CMSSignedData_Destroy(*cms_sd);
    6688           0 :         NSS_CMSMessage_Destroy(result);
    6689           0 :         return NULL;
    6690             :     }
    6691             : 
    6692           0 :     *cms_signer = NSS_CMSSignerInfo_Create(result, cert, SEC_OID_SHA1);
    6693           0 :     if (!*cms_signer)
    6694             :     {
    6695             :         SAL_WARN("vcl.pdfwriter", "NSS_CMSSignerInfo_Create failed");
    6696           0 :         NSS_CMSSignedData_Destroy(*cms_sd);
    6697           0 :         NSS_CMSMessage_Destroy(result);
    6698           0 :         return NULL;
    6699             :     }
    6700             : 
    6701           0 :     if (NSS_CMSSignerInfo_AddSigningTime(*cms_signer, time) != SECSuccess)
    6702             :     {
    6703             :         SAL_WARN("vcl.pdfwriter", "NSS_CMSSignerInfo_AddSigningTime failed");
    6704           0 :         NSS_CMSSignedData_Destroy(*cms_sd);
    6705           0 :         NSS_CMSMessage_Destroy(result);
    6706           0 :         return NULL;
    6707             :     }
    6708             : 
    6709           0 :     if (NSS_CMSSignerInfo_IncludeCerts(*cms_signer, NSSCMSCM_CertChain, certUsageEmailSigner) != SECSuccess)
    6710             :     {
    6711             :         SAL_WARN("vcl.pdfwriter", "NSS_CMSSignerInfo_IncludeCerts failed");
    6712           0 :         NSS_CMSSignedData_Destroy(*cms_sd);
    6713           0 :         NSS_CMSMessage_Destroy(result);
    6714           0 :         return NULL;
    6715             :     }
    6716             : 
    6717           0 :     if (NSS_CMSSignedData_AddCertificate(*cms_sd, cert) != SECSuccess)
    6718             :     {
    6719             :         SAL_WARN("vcl.pdfwriter", "NSS_CMSSignedData_AddCertificate failed");
    6720           0 :         NSS_CMSSignedData_Destroy(*cms_sd);
    6721           0 :         NSS_CMSMessage_Destroy(result);
    6722           0 :         return NULL;
    6723             :     }
    6724             : 
    6725           0 :     if (NSS_CMSSignedData_AddSignerInfo(*cms_sd, *cms_signer) != SECSuccess)
    6726             :     {
    6727             :         SAL_WARN("vcl.pdfwriter", "NSS_CMSSignedData_AddSignerInfo failed");
    6728           0 :         NSS_CMSSignedData_Destroy(*cms_sd);
    6729           0 :         NSS_CMSMessage_Destroy(result);
    6730           0 :         return NULL;
    6731             :     }
    6732             : 
    6733           0 :     if (NSS_CMSSignedData_SetDigestValue(*cms_sd, SEC_OID_SHA1, digest) != SECSuccess)
    6734             :     {
    6735             :         SAL_WARN("vcl.pdfwriter", "NSS_CMSSignedData_SetDigestValue failed");
    6736           0 :         NSS_CMSSignedData_Destroy(*cms_sd);
    6737           0 :         NSS_CMSMessage_Destroy(result);
    6738           0 :         return NULL;
    6739             :     }
    6740             : 
    6741           0 :     return result;
    6742             : }
    6743             : 
    6744             : #if 0
    6745             : {
    6746             : #endif
    6747             : } // anonymous namespace
    6748             : 
    6749             : #endif // !defined(ANDROID) && !defined(IOS) && !defined(_WIN32)
    6750             : 
    6751             : #ifdef _WIN32
    6752             : 
    6753             : typedef BOOL (WINAPI *PointerTo_CryptRetrieveTimeStamp)(LPCWSTR wszUrl,
    6754             :                                                         DWORD dwRetrievalFlags,
    6755             :                                                         DWORD dwTimeout,
    6756             :                                                         LPCSTR pszHashId,
    6757             :                                                         const CRYPT_TIMESTAMP_PARA *pPara,
    6758             :                                                         const BYTE *pbData,
    6759             :                                                         DWORD cbData,
    6760             :                                                         PCRYPT_TIMESTAMP_CONTEXT *ppTsContext,
    6761             :                                                         PCCERT_CONTEXT *ppTsSigner,
    6762             :                                                         HCERTSTORE phStore);
    6763             : 
    6764             : namespace {
    6765             : 
    6766             : OUString WindowsError(DWORD nErrorCode)
    6767             : {
    6768             :     LPWSTR pMsgBuf;
    6769             : 
    6770             :     if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
    6771             :                        NULL,
    6772             :                        nErrorCode,
    6773             :                        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
    6774             :                        (LPWSTR)&pMsgBuf,
    6775             :                        0,
    6776             :                        NULL) == 0)
    6777             :         return OUString::number(nErrorCode, 16);
    6778             : 
    6779             :     if (pMsgBuf[wcslen(pMsgBuf)-1] == '\n')
    6780             :         pMsgBuf[wcslen(pMsgBuf)-1] = '\0';
    6781             : 
    6782             :     OUString result(pMsgBuf);
    6783             : 
    6784             :     LocalFree(pMsgBuf);
    6785             : 
    6786             :     return result;
    6787             : }
    6788             : 
    6789             : }
    6790             : 
    6791             : #endif
    6792             : 
    6793           0 : bool PDFWriterImpl::finalizeSignature()
    6794             : {
    6795             : 
    6796           0 :     if (!m_aContext.SignCertificate.is())
    6797           0 :         return false;
    6798             : 
    6799             :     // 1- calculate last ByteRange value
    6800           0 :     sal_uInt64 nOffset = ~0U;
    6801           0 :     CHECK_RETURN( (osl::File::E_None == m_aFile.getPos(nOffset) ) );
    6802             : 
    6803           0 :     sal_Int64 nLastByteRangeNo = nOffset - (m_nSignatureContentOffset + MAX_SIGNATURE_CONTENT_LENGTH + 1);
    6804             : 
    6805             :     // 2- overwrite the value to the m_nSignatureLastByteRangeNoOffset position
    6806           0 :     sal_uInt64 nWritten = 0;
    6807           0 :     CHECK_RETURN( (osl::File::E_None == m_aFile.setPos(osl_Pos_Absolut, m_nSignatureLastByteRangeNoOffset) ) );
    6808           0 :     OStringBuffer aByteRangeNo( 256 );
    6809           0 :     aByteRangeNo.append( nLastByteRangeNo, 10);
    6810           0 :     aByteRangeNo.append( " ]" );
    6811             : 
    6812           0 :     if (m_aFile.write(aByteRangeNo.getStr(), aByteRangeNo.getLength(), nWritten) != osl::File::E_None)
    6813             :     {
    6814           0 :         CHECK_RETURN( (osl::File::E_None == m_aFile.setPos(osl_Pos_Absolut, nOffset)) );
    6815           0 :         return false;
    6816             :     }
    6817             : 
    6818             :     // 3- create the PKCS#7 object using NSS
    6819           0 :     com::sun::star::uno::Sequence< sal_Int8 > derEncoded = m_aContext.SignCertificate->getEncoded();
    6820             : 
    6821           0 :     if (!derEncoded.hasElements())
    6822           0 :         return false;
    6823             : 
    6824           0 :     sal_Int8* n_derArray = derEncoded.getArray();
    6825           0 :     sal_Int32 n_derLength = derEncoded.getLength();
    6826             : 
    6827             : #ifndef _WIN32
    6828             : 
    6829           0 :     CERTCertificate *cert = CERT_DecodeCertFromPackage(reinterpret_cast<char *>(n_derArray), n_derLength);
    6830             : 
    6831           0 :     if (!cert)
    6832             :     {
    6833             :         SAL_WARN("vcl.pdfwriter", "CERT_DecodeCertFromPackage failed");
    6834           0 :         return false;
    6835             :     }
    6836             : 
    6837             :     // Prepare buffer and calculate PDF file digest
    6838           0 :     CHECK_RETURN( (osl::File::E_None == m_aFile.setPos(osl_Pos_Absolut, 0)) );
    6839             : 
    6840           0 :     HashContextScope hc(HASH_Create(HASH_AlgSHA1));
    6841           0 :     if (!hc.get())
    6842             :     {
    6843             :         SAL_WARN("vcl.pdfwriter", "HASH_Create failed");
    6844           0 :         return false;
    6845             :     }
    6846             : 
    6847           0 :     HASH_Begin(hc.get());
    6848             : 
    6849           0 :     boost::scoped_array<char> buffer(new char[m_nSignatureContentOffset + 1]);
    6850             :     sal_uInt64 bytesRead;
    6851             : 
    6852             :     //FIXME: Check if SHA1 is calculated from the correct byterange
    6853           0 :     CHECK_RETURN( (osl::File::E_None == m_aFile.read(buffer.get(), m_nSignatureContentOffset - 1 , bytesRead)) );
    6854           0 :     if (bytesRead != (sal_uInt64)m_nSignatureContentOffset - 1)
    6855             :         SAL_WARN("vcl.pdfwriter", "First buffer read failed");
    6856             : 
    6857           0 :     HASH_Update(hc.get(), reinterpret_cast<const unsigned char*>(buffer.get()), bytesRead);
    6858             : 
    6859           0 :     CHECK_RETURN( (osl::File::E_None == m_aFile.setPos(osl_Pos_Absolut, m_nSignatureContentOffset + MAX_SIGNATURE_CONTENT_LENGTH + 1)) );
    6860           0 :     buffer.reset(new char[nLastByteRangeNo + 1]);
    6861           0 :     CHECK_RETURN( (osl::File::E_None == m_aFile.read(buffer.get(), nLastByteRangeNo, bytesRead)) );
    6862           0 :     if (bytesRead != (sal_uInt64) nLastByteRangeNo)
    6863             :         SAL_WARN("vcl.pdfwriter", "Second buffer read failed");
    6864             : 
    6865           0 :     HASH_Update(hc.get(), reinterpret_cast<const unsigned char*>(buffer.get()), bytesRead);
    6866             : 
    6867             :     SECItem digest;
    6868             :     unsigned char hash[SHA1_LENGTH];
    6869           0 :     digest.data = hash;
    6870           0 :     HASH_End(hc.get(), digest.data, &digest.len, SHA1_LENGTH);
    6871           0 :     hc.clear();
    6872             : 
    6873             : #ifdef DBG_UTIL
    6874             :     {
    6875             :         FILE *out = fopen("PDFWRITER.hash.data", "wb");
    6876             :         fwrite(hash, SHA1_LENGTH, 1, out);
    6877             :         fclose(out);
    6878             :     }
    6879             : #endif
    6880             : 
    6881           0 :     PRTime now = PR_Now();
    6882             :     NSSCMSSignedData *cms_sd;
    6883             :     NSSCMSSignerInfo *cms_signer;
    6884           0 :     NSSCMSMessage *cms_msg = CreateCMSMessage(now, &cms_sd, &cms_signer, cert, &digest);
    6885           0 :     if (!cms_msg)
    6886           0 :         return false;
    6887             : 
    6888           0 :     char *pass(strdup(OUStringToOString( m_aContext.SignPassword, RTL_TEXTENCODING_UTF8 ).getStr()));
    6889             : 
    6890             :     TimeStampReq src;
    6891           0 :     OStringBuffer response_buffer;
    6892             :     TimeStampResp response;
    6893             :     SECItem response_item;
    6894             :     NSSCMSAttribute timestamp;
    6895             :     SECItem values[2];
    6896             :     SECItem *valuesp[2];
    6897           0 :     valuesp[0] = values;
    6898           0 :     valuesp[1] = NULL;
    6899             :     SECOidData typetag;
    6900             : 
    6901           0 :     if( !m_aContext.SignTSA.isEmpty() )
    6902             :     {
    6903             :         // Create another CMS message with the same contents as cms_msg, because it doesn't seem
    6904             :         // possible to encode a message twice (once to get something to timestamp, and then after
    6905             :         // adding the timestamp attribute).
    6906             : 
    6907             :         NSSCMSSignedData *ts_cms_sd;
    6908             :         NSSCMSSignerInfo *ts_cms_signer;
    6909           0 :         NSSCMSMessage *ts_cms_msg = CreateCMSMessage(now, &ts_cms_sd, &ts_cms_signer, cert, &digest);
    6910           0 :         if (!ts_cms_msg)
    6911             :         {
    6912           0 :             free(pass);
    6913           0 :             return false;
    6914             :         }
    6915             : 
    6916             :         SECItem ts_cms_output;
    6917           0 :         ts_cms_output.data = 0;
    6918           0 :         ts_cms_output.len = 0;
    6919           0 :         PLArenaPool *ts_arena = PORT_NewArena(10000);
    6920             :         NSSCMSEncoderContext *ts_cms_ecx;
    6921           0 :         ts_cms_ecx = NSS_CMSEncoder_Start(ts_cms_msg, NULL, NULL, &ts_cms_output, ts_arena, PDFSigningPKCS7PasswordCallback, pass, NULL, NULL, NULL, NULL);
    6922             : 
    6923           0 :         if (NSS_CMSEncoder_Finish(ts_cms_ecx) != SECSuccess)
    6924             :         {
    6925             :             SAL_WARN("vcl.pdfwriter", "NSS_CMSEncoder_Finish failed");
    6926           0 :             free(pass);
    6927           0 :             return false;
    6928             :         }
    6929             : 
    6930             :         // I have compared the ts_cms_output produced here with the cms_output produced below, with
    6931             :         // the DONTCALLADDUNAUTHATTR env var set (i.e. without actually calling
    6932             :         // my_NSS_CMSSignerInfo_AddUnauthAttr()), and they are identical.
    6933             : 
    6934             : #ifdef DBG_UTIL
    6935             :         {
    6936             :             FILE *out = fopen("PDFWRITER.ts_cms.data", "wb");
    6937             :             fwrite(ts_cms_output.data, ts_cms_output.len, 1, out);
    6938             :             fclose(out);
    6939             :         }
    6940             : #endif
    6941             : 
    6942           0 :         HashContextScope ts_hc(HASH_Create(HASH_AlgSHA1));
    6943           0 :         if (!ts_hc.get())
    6944             :         {
    6945             :             SAL_WARN("vcl.pdfwriter", "HASH_Create failed");
    6946           0 :             free(pass);
    6947           0 :             return false;
    6948             :         }
    6949             : 
    6950           0 :         HASH_Begin(ts_hc.get());
    6951           0 :         HASH_Update(ts_hc.get(), ts_cms_signer->encDigest.data, ts_cms_signer->encDigest.len);
    6952             :         SECItem ts_digest;
    6953             :         unsigned char ts_hash[SHA1_LENGTH];
    6954           0 :         ts_digest.type = siBuffer;
    6955           0 :         ts_digest.data = ts_hash;
    6956           0 :         HASH_End(ts_hc.get(), ts_digest.data, &ts_digest.len, SHA1_LENGTH);
    6957           0 :         ts_hc.clear();
    6958             : 
    6959             : #ifdef DBG_UTIL
    6960             :         {
    6961             :             FILE *out = fopen("PDFWRITER.ts_hash.data", "wb");
    6962             :             fwrite(ts_hash, SHA1_LENGTH, 1, out);
    6963             :             fclose(out);
    6964             :         }
    6965             : #endif
    6966             : 
    6967           0 :         unsigned char cOne = 1;
    6968           0 :         src.version.type = siUnsignedInteger;
    6969           0 :         src.version.data = &cOne;
    6970           0 :         src.version.len = sizeof(cOne);
    6971             : 
    6972           0 :         src.messageImprint.hashAlgorithm.algorithm.data = NULL;
    6973           0 :         src.messageImprint.hashAlgorithm.parameters.data = NULL;
    6974           0 :         SECOID_SetAlgorithmID(NULL, &src.messageImprint.hashAlgorithm, SEC_OID_SHA1, NULL);
    6975           0 :         src.messageImprint.hashedMessage = ts_digest;
    6976             : 
    6977           0 :         src.reqPolicy.type = siBuffer;
    6978           0 :         src.reqPolicy.data = NULL;
    6979           0 :         src.reqPolicy.len = 0;
    6980             : 
    6981           0 :         unsigned int nNonce = comphelper::rng::uniform_uint_distribution(0, SAL_MAX_UINT32);
    6982           0 :         src.nonce.type = siUnsignedInteger;
    6983           0 :         src.nonce.data = reinterpret_cast<unsigned char*>(&nNonce);
    6984           0 :         src.nonce.len = sizeof(nNonce);
    6985             : 
    6986           0 :         src.certReq.type = siUnsignedInteger;
    6987           0 :         src.certReq.data = &cOne;
    6988           0 :         src.certReq.len = sizeof(cOne);
    6989             : 
    6990           0 :         src.extensions = NULL;
    6991             : 
    6992           0 :         SECItem* timestamp_request = SEC_ASN1EncodeItem(NULL, NULL, &src, TimeStampReq_Template);
    6993           0 :         if (timestamp_request == NULL)
    6994             :         {
    6995             :             SAL_WARN("vcl.pdfwriter", "SEC_ASN1EncodeItem failed");
    6996           0 :             free(pass);
    6997           0 :             return false;
    6998             :         }
    6999             : 
    7000           0 :         if (timestamp_request->data == NULL)
    7001             :         {
    7002             :             SAL_WARN("vcl.pdfwriter", "SEC_ASN1EncodeItem succeeded but got NULL data");
    7003           0 :             free(pass);
    7004           0 :             SECITEM_FreeItem(timestamp_request, PR_TRUE);
    7005           0 :             return false;
    7006             :         }
    7007             : 
    7008             :         SAL_INFO("vcl.pdfwriter", "request length=" << timestamp_request->len);
    7009             : 
    7010             : #ifdef DBG_UTIL
    7011             :         {
    7012             :             FILE *out = fopen("PDFWRITER.timestampreq.data", "wb");
    7013             :             fwrite(timestamp_request->data, timestamp_request->len, 1, out);
    7014             :             fclose(out);
    7015             :         }
    7016             : #endif
    7017             : 
    7018             :         // Send time stamp request to TSA server, receive response
    7019             : 
    7020           0 :         CURL* curl = curl_easy_init();
    7021             :         CURLcode rc;
    7022           0 :         struct curl_slist* slist = NULL;
    7023             : 
    7024           0 :         if (!curl)
    7025             :         {
    7026             :             SAL_WARN("vcl.pdfwriter", "curl_easy_init failed");
    7027           0 :             free(pass);
    7028           0 :             SECITEM_FreeItem(timestamp_request, PR_TRUE);
    7029           0 :             return false;
    7030             :         }
    7031             : 
    7032             :         SAL_INFO("vcl.pdfwriter", "Setting curl to verbose: " << (curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L) == CURLE_OK ? "OK" : "FAIL"));
    7033             : 
    7034           0 :         if ((rc = curl_easy_setopt(curl, CURLOPT_URL, OUStringToOString(m_aContext.SignTSA, RTL_TEXTENCODING_UTF8).getStr())) != CURLE_OK)
    7035             :         {
    7036             :             SAL_WARN("vcl.pdfwriter", "curl_easy_setopt(CURLOPT_URL) failed: " << curl_easy_strerror(rc));
    7037           0 :             free(pass);
    7038           0 :             curl_easy_cleanup(curl);
    7039           0 :             SECITEM_FreeItem(timestamp_request, PR_TRUE);
    7040           0 :             return false;
    7041             :         }
    7042             : 
    7043           0 :         slist = curl_slist_append(slist, "Content-Type: application/timestamp-query");
    7044           0 :         slist = curl_slist_append(slist, "Accept: application/timestamp-reply");
    7045             : 
    7046           0 :         if ((rc = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist)) != CURLE_OK)
    7047             :         {
    7048             :             SAL_WARN("vcl.pdfwriter", "curl_easy_setopt(CURLOPT_HTTPHEADER) failed: " << curl_easy_strerror(rc));
    7049           0 :             free(pass);
    7050           0 :             curl_slist_free_all(slist);
    7051           0 :             curl_easy_cleanup(curl);
    7052           0 :             SECITEM_FreeItem(timestamp_request, PR_TRUE);
    7053           0 :             return false;
    7054             :         }
    7055             : 
    7056           0 :         if ((rc = curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, static_cast<long>(timestamp_request->len))) != CURLE_OK ||
    7057           0 :             (rc = curl_easy_setopt(curl, CURLOPT_POSTFIELDS, timestamp_request->data)) != CURLE_OK)
    7058             :         {
    7059             :             SAL_WARN("vcl.pdfwriter", "curl_easy_setopt(CURLOPT_POSTFIELDSIZE or CURLOPT_POSTFIELDS) failed: " << curl_easy_strerror(rc));
    7060           0 :             free(pass);
    7061           0 :             curl_easy_cleanup(curl);
    7062           0 :             SECITEM_FreeItem(timestamp_request, PR_TRUE);
    7063           0 :             return false;
    7064             :         }
    7065             : 
    7066           0 :         if ((rc = curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_buffer)) != CURLE_OK ||
    7067             :             (rc = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, AppendToBuffer)) != CURLE_OK)
    7068             :         {
    7069             :             SAL_WARN("vcl.pdfwriter", "curl_easy_setopt(CURLOPT_WRITEDATA or CURLOPT_WRITEFUNCTION) failed: " << curl_easy_strerror(rc));
    7070           0 :             free(pass);
    7071           0 :             curl_easy_cleanup(curl);
    7072           0 :             SECITEM_FreeItem(timestamp_request, PR_TRUE);
    7073           0 :             return false;
    7074             :         }
    7075             : 
    7076           0 :         if ((rc = curl_easy_setopt(curl, CURLOPT_POST, 1l)) != CURLE_OK)
    7077             :         {
    7078             :             SAL_WARN("vcl.pdfwriter", "curl_easy_setopt(CURLOPT_POST) failed: " << curl_easy_strerror(rc));
    7079           0 :             free(pass);
    7080           0 :             curl_easy_cleanup(curl);
    7081           0 :             SECITEM_FreeItem(timestamp_request, PR_TRUE);
    7082           0 :             return false;
    7083             :         }
    7084             : 
    7085             :         char error_buffer[CURL_ERROR_SIZE];
    7086           0 :         if ((rc = curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error_buffer)) != CURLE_OK)
    7087             :         {
    7088             :             SAL_WARN("vcl.pdfwriter", "curl_easy_setopt(CURLOPT_ERRORBUFFER) failed: " << curl_easy_strerror(rc));
    7089           0 :             free(pass);
    7090           0 :             curl_easy_cleanup(curl);
    7091           0 :             SECITEM_FreeItem(timestamp_request, PR_TRUE);
    7092           0 :             return false;
    7093             :         }
    7094             : 
    7095             :         // Use a ten second timeout
    7096           0 :         if ((rc = curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10l)) != CURLE_OK ||
    7097             :             (rc = curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10l)) != CURLE_OK)
    7098             :         {
    7099             :             SAL_WARN("vcl.pdfwriter", "curl_easy_setopt(CURLOPT_TIMEOUT or CURLOPT_CONNECTTIMEOUT) failed: " << curl_easy_strerror(rc));
    7100           0 :             free(pass);
    7101           0 :             curl_easy_cleanup(curl);
    7102           0 :             SECITEM_FreeItem(timestamp_request, PR_TRUE);
    7103           0 :             return false;
    7104             :         }
    7105             : 
    7106           0 :         if (curl_easy_perform(curl) != CURLE_OK)
    7107             :         {
    7108             :             SAL_WARN("vcl.pdfwriter", "curl_easy_perform failed: " << error_buffer);
    7109           0 :             free(pass);
    7110           0 :             curl_easy_cleanup(curl);
    7111           0 :             SECITEM_FreeItem(timestamp_request, PR_TRUE);
    7112           0 :             return false;
    7113             :         }
    7114             : 
    7115             :         SAL_INFO("vcl.pdfwriter", "PDF signing: got response, length=" << response_buffer.getLength());
    7116             : 
    7117             : #ifdef DBG_UTIL
    7118             :         {
    7119             :             FILE *out = fopen("PDFWRITER.reply.data", "wb");
    7120             :             fwrite(response_buffer.getStr(), response_buffer.getLength(), 1, out);
    7121             :             fclose(out);
    7122             :         }
    7123             : #endif
    7124             : 
    7125           0 :         curl_slist_free_all(slist);
    7126           0 :         curl_easy_cleanup(curl);
    7127           0 :         SECITEM_FreeItem(timestamp_request, PR_TRUE);
    7128             : 
    7129           0 :         memset(&response, 0, sizeof(response));
    7130             : 
    7131           0 :         response_item.type = siBuffer;
    7132           0 :         response_item.data = reinterpret_cast<unsigned char*>(const_cast<char*>(response_buffer.getStr()));
    7133           0 :         response_item.len = response_buffer.getLength();
    7134             : 
    7135           0 :         if (SEC_ASN1DecodeItem(NULL, &response, TimeStampResp_Template, &response_item) != SECSuccess)
    7136             :         {
    7137             :             SAL_WARN("vcl.pdfwriter", "SEC_ASN1DecodeItem failed");
    7138           0 :             free(pass);
    7139           0 :             return false;
    7140             :         }
    7141             : 
    7142             :         SAL_INFO("vcl.pdfwriter", "TimeStampResp received and decoded, status=" << PKIStatusInfoToString(response.status));
    7143             : 
    7144           0 :         if (response.status.status.len != 1 ||
    7145           0 :             (response.status.status.data[0] != 0 && response.status.status.data[0] != 1))
    7146             :         {
    7147             :             SAL_WARN("vcl.pdfwriter", "Timestamp request was not granted");
    7148           0 :             free(pass);
    7149           0 :             return false;
    7150             :         }
    7151             : 
    7152             :         // timestamp.type filled in below
    7153             : 
    7154             :         // Not sure if we actually need two entries in the values array, now when valuesp is an
    7155             :         // array too, the pointer to the values array followed by a null pointer. But I don't feel
    7156             :         // like experimenting.
    7157           0 :         values[0] = response.timeStampToken;
    7158           0 :         values[1].type = siBuffer;
    7159           0 :         values[1].data = NULL;
    7160           0 :         values[1].len = 0;
    7161             : 
    7162           0 :         timestamp.values = valuesp;
    7163             : 
    7164           0 :         typetag.oid.data = NULL;
    7165             :         // id-aa-timeStampToken OBJECT IDENTIFIER ::= { iso(1)
    7166             :         // member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-9(9)
    7167             :         // smime(16) aa(2) 14 }
    7168           0 :         if (my_SEC_StringToOID(NULL, &typetag.oid, "1.2.840.113549.1.9.16.2.14", 0) != SECSuccess)
    7169             :         {
    7170             :             SAL_WARN("vcl.pdfwriter", "SEC_StringToOID failed");
    7171           0 :             free(pass);
    7172           0 :             return false;
    7173             :         }
    7174           0 :         typetag.offset = SEC_OID_UNKNOWN; // ???
    7175           0 :         typetag.desc = "id-aa-timeStampToken";
    7176           0 :         typetag.mechanism = CKM_SHA_1; // ???
    7177           0 :         typetag.supportedExtension = UNSUPPORTED_CERT_EXTENSION; // ???
    7178           0 :         timestamp.typeTag = &typetag;
    7179             : 
    7180           0 :         timestamp.type = typetag.oid; // ???
    7181             : 
    7182           0 :         timestamp.encoded = PR_TRUE; // ???
    7183             : 
    7184             : #ifdef DBG_UTIL
    7185             :         if (getenv("DONTCALLADDUNAUTHATTR"))
    7186             :             ;
    7187             :         else
    7188             : #endif
    7189           0 :         if (my_NSS_CMSSignerInfo_AddUnauthAttr(cms_signer, &timestamp) != SECSuccess)
    7190             :         {
    7191             :             SAL_WARN("vcl.pdfwriter", "NSS_CMSSignerInfo_AddUnauthAttr failed");
    7192           0 :             free(pass);
    7193           0 :             return false;
    7194           0 :         }
    7195             :     }
    7196             : 
    7197             :     SECItem cms_output;
    7198           0 :     cms_output.data = 0;
    7199           0 :     cms_output.len = 0;
    7200           0 :     PLArenaPool *arena = PORT_NewArena(10000);
    7201             :     NSSCMSEncoderContext *cms_ecx;
    7202             : 
    7203             :     // Possibly it would work to even just pass NULL for the password callback function and its
    7204             :     // argument here. After all, at least with the hardware token and associated software I tested
    7205             :     // with, the software itself pops up a dialog asking for the PIN (password). But I am not going
    7206             :     // to test it and risk locking up my token...
    7207             : 
    7208           0 :     cms_ecx = NSS_CMSEncoder_Start(cms_msg, NULL, NULL, &cms_output, arena, PDFSigningPKCS7PasswordCallback, pass, NULL, NULL, NULL, NULL);
    7209             : 
    7210           0 :     if (!cms_ecx)
    7211             :     {
    7212             :         SAL_WARN("vcl.pdfwriter", "NSS_CMSEncoder_Start failed");
    7213           0 :         free(pass);
    7214           0 :         return false;
    7215             :     }
    7216             : 
    7217           0 :     if (NSS_CMSEncoder_Finish(cms_ecx) != SECSuccess)
    7218             :     {
    7219             :         SAL_WARN("vcl.pdfwriter", "NSS_CMSEncoder_Finish failed");
    7220           0 :         free(pass);
    7221           0 :         return false;
    7222             :     }
    7223             : 
    7224           0 :     free(pass);
    7225             : 
    7226             : #ifdef DBG_UTIL
    7227             :     {
    7228             :         FILE *out = fopen("PDFWRITER.cms.data", "wb");
    7229             :         fwrite(cms_output.data, cms_output.len, 1, out);
    7230             :         fclose(out);
    7231             :     }
    7232             : #endif
    7233             : 
    7234           0 :     if (cms_output.len*2 > MAX_SIGNATURE_CONTENT_LENGTH)
    7235             :     {
    7236             :         SAL_WARN("vcl.pdfwriter", "Signature requires more space (" << cms_output.len*2 << ") than we reserved (" << MAX_SIGNATURE_CONTENT_LENGTH << ")");
    7237           0 :         NSS_CMSMessage_Destroy(cms_msg);
    7238           0 :         return false;
    7239             :     }
    7240             : 
    7241           0 :     OStringBuffer cms_hexbuffer;
    7242             : 
    7243           0 :     for (unsigned int i = 0; i < cms_output.len ; i++)
    7244           0 :         appendHex(cms_output.data[i], cms_hexbuffer);
    7245             : 
    7246             :     assert(cms_hexbuffer.getLength() <= MAX_SIGNATURE_CONTENT_LENGTH);
    7247             : 
    7248             :     // Set file pointer to the m_nSignatureContentOffset, we're ready to overwrite PKCS7 object
    7249           0 :     nWritten = 0;
    7250           0 :     CHECK_RETURN( (osl::File::E_None == m_aFile.setPos(osl_Pos_Absolut, m_nSignatureContentOffset)) );
    7251           0 :     m_aFile.write(cms_hexbuffer.getStr(), cms_hexbuffer.getLength(), nWritten);
    7252             : 
    7253           0 :     NSS_CMSMessage_Destroy(cms_msg);
    7254             : 
    7255           0 :     CHECK_RETURN( (osl::File::E_None == m_aFile.setPos(osl_Pos_Absolut, nOffset)) );
    7256           0 :     return true;
    7257             : 
    7258             : #else
    7259             : 
    7260             :     // Prepare buffer and calculate PDF file digest
    7261             :     CHECK_RETURN( (osl::File::E_None == m_aFile.setPos(osl_Pos_Absolut, 0)) );
    7262             : 
    7263             :     boost::scoped_array<char> buffer1(new char[m_nSignatureContentOffset - 1]);
    7264             :     sal_uInt64 bytesRead1;
    7265             : 
    7266             :     if (osl::File::E_None != m_aFile.read(buffer1.get(), m_nSignatureContentOffset - 1 , bytesRead1) ||
    7267             :         bytesRead1 != (sal_uInt64)m_nSignatureContentOffset - 1)
    7268             :     {
    7269             :         SAL_WARN("vcl.pdfwriter", "First buffer read failed");
    7270             :         return false;
    7271             :     }
    7272             : 
    7273             :     boost::scoped_array<char> buffer2(new char[nLastByteRangeNo]);
    7274             :     sal_uInt64 bytesRead2;
    7275             : 
    7276             :     if (osl::File::E_None != m_aFile.setPos(osl_Pos_Absolut, m_nSignatureContentOffset + MAX_SIGNATURE_CONTENT_LENGTH + 1) ||
    7277             :         osl::File::E_None != m_aFile.read(buffer2.get(), nLastByteRangeNo, bytesRead2) ||
    7278             :         bytesRead2 != (sal_uInt64) nLastByteRangeNo)
    7279             :     {
    7280             :         SAL_WARN("vcl.pdfwriter", "Second buffer read failed");
    7281             :         return false;
    7282             :     }
    7283             : 
    7284             :     OString pass = OUStringToOString( m_aContext.SignPassword, RTL_TEXTENCODING_UTF8 );
    7285             : 
    7286             :     PCCERT_CONTEXT pCertContext = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, reinterpret_cast<const BYTE*>(n_derArray), n_derLength);
    7287             :     if (pCertContext == NULL)
    7288             :     {
    7289             :         SAL_WARN("vcl.pdfwriter", "CertCreateCertificateContext failed: " << WindowsError(GetLastError()));
    7290             :         return false;
    7291             :     }
    7292             : 
    7293             :     CRYPT_SIGN_MESSAGE_PARA aPara;
    7294             : 
    7295             :     memset(&aPara, 0, sizeof(aPara));
    7296             :     aPara.cbSize = sizeof(aPara);
    7297             :     aPara.dwMsgEncodingType = PKCS_7_ASN_ENCODING | X509_ASN_ENCODING;
    7298             :     aPara.pSigningCert = pCertContext;
    7299             :     aPara.HashAlgorithm.pszObjId = szOID_RSA_SHA1RSA;
    7300             :     aPara.HashAlgorithm.Parameters.cbData = 0;
    7301             :     aPara.cMsgCert = 1;
    7302             :     aPara.rgpMsgCert = &pCertContext;
    7303             : 
    7304             :     HCRYPTPROV hCryptProv;
    7305             :     DWORD nKeySpec;
    7306             :     BOOL bFreeNeeded;
    7307             : 
    7308             :     if (!CryptAcquireCertificatePrivateKey(pCertContext,
    7309             :                                            CRYPT_ACQUIRE_CACHE_FLAG,
    7310             :                                            NULL,
    7311             :                                            &hCryptProv,
    7312             :                                            &nKeySpec,
    7313             :                                            &bFreeNeeded))
    7314             :     {
    7315             :         SAL_WARN("vcl.pdfwriter", "CryptAcquireCertificatePrivateKey failed: " << WindowsError(GetLastError()));
    7316             :         CertFreeCertificateContext(pCertContext);
    7317             :         return false;
    7318             :     }
    7319             :     assert(!bFreeNeeded);
    7320             : 
    7321             :     CMSG_SIGNER_ENCODE_INFO aSignerInfo;
    7322             : 
    7323             :     memset(&aSignerInfo, 0, sizeof(aSignerInfo));
    7324             :     aSignerInfo.cbSize = sizeof(aSignerInfo);
    7325             :     aSignerInfo.pCertInfo = pCertContext->pCertInfo;
    7326             :     aSignerInfo.hCryptProv = hCryptProv;
    7327             :     aSignerInfo.dwKeySpec = nKeySpec;
    7328             :     aSignerInfo.HashAlgorithm.pszObjId = szOID_RSA_SHA1RSA;
    7329             :     aSignerInfo.HashAlgorithm.Parameters.cbData = 0;
    7330             : 
    7331             :     CMSG_SIGNED_ENCODE_INFO aSignedInfo;
    7332             :     memset(&aSignedInfo, 0, sizeof(aSignedInfo));
    7333             :     aSignedInfo.cbSize = sizeof(aSignedInfo);
    7334             :     aSignedInfo.cSigners = 1;
    7335             :     aSignedInfo.rgSigners = &aSignerInfo;
    7336             : 
    7337             :     CERT_BLOB aCertBlob;
    7338             : 
    7339             :     aCertBlob.cbData = pCertContext->cbCertEncoded;
    7340             :     aCertBlob.pbData = pCertContext->pbCertEncoded;
    7341             : 
    7342             :     aSignedInfo.cCertEncoded = 1;
    7343             :     aSignedInfo.rgCertEncoded = &aCertBlob;
    7344             : 
    7345             :     HCRYPTMSG hMsg;
    7346             :     if (!(hMsg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
    7347             :                                       CMSG_DETACHED_FLAG,
    7348             :                                       CMSG_SIGNED,
    7349             :                                       &aSignedInfo,
    7350             :                                       NULL,
    7351             :                                       NULL)))
    7352             :     {
    7353             :         SAL_WARN("vcl.pdfwriter", "CryptMsgOpenToEncode failed: " << WindowsError(GetLastError()));
    7354             :         CertFreeCertificateContext(pCertContext);
    7355             :         return false;
    7356             :     }
    7357             : 
    7358             :     if (!CryptMsgUpdate(hMsg, (const BYTE *)buffer1.get(), bytesRead1, FALSE) ||
    7359             :         !CryptMsgUpdate(hMsg, (const BYTE *)buffer2.get(), bytesRead2, TRUE))
    7360             :     {
    7361             :         SAL_WARN("vcl.pdfwriter", "CryptMsgUpdate failed: " << WindowsError(GetLastError()));
    7362             :         CryptMsgClose(hMsg);
    7363             :         CertFreeCertificateContext(pCertContext);
    7364             :         return false;
    7365             :     }
    7366             : 
    7367             :     PCRYPT_TIMESTAMP_CONTEXT pTsContext = NULL;
    7368             : 
    7369             :     if( !m_aContext.SignTSA.isEmpty() )
    7370             :     {
    7371             :         PointerTo_CryptRetrieveTimeStamp crts = (PointerTo_CryptRetrieveTimeStamp) GetProcAddress(LoadLibrary("crypt32.dll"), "CryptRetrieveTimeStamp");
    7372             :         if (!crts)
    7373             :         {
    7374             :             SAL_WARN("vcl.pdfwriter", "Could not find the CryptRetrieveTimeStamp function in crypt32.dll: " << WindowsError(GetLastError()));
    7375             :             CryptMsgClose(hMsg);
    7376             :             CertFreeCertificateContext(pCertContext);
    7377             :             return false;
    7378             :         }
    7379             : 
    7380             :         HCRYPTMSG hDecodedMsg;
    7381             :         if (!(hDecodedMsg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
    7382             :                                                  CMSG_DETACHED_FLAG,
    7383             :                                                  CMSG_SIGNED,
    7384             :                                                  NULL,
    7385             :                                                  NULL,
    7386             :                                                  NULL)))
    7387             :         {
    7388             :             SAL_WARN("vcl.pdfwriter", "CryptMsgOpenToDecode failed: " << WindowsError(GetLastError()));
    7389             :             CryptMsgClose(hMsg);
    7390             :             CertFreeCertificateContext(pCertContext);
    7391             :             return false;
    7392             :         }
    7393             : 
    7394             :         DWORD nTsSigLen = 0;
    7395             : 
    7396             :         if (!CryptMsgGetParam(hMsg, CMSG_BARE_CONTENT_PARAM, 0, NULL, &nTsSigLen))
    7397             :         {
    7398             :             SAL_WARN("vcl.pdfwriter", "CryptMsgGetParam(CMSG_BARE_CONTENT_PARAM) failed: " << WindowsError(GetLastError()));
    7399             :             CryptMsgClose(hDecodedMsg);
    7400             :             CryptMsgClose(hMsg);
    7401             :             CertFreeCertificateContext(pCertContext);
    7402             :             return false;
    7403             :         }
    7404             : 
    7405             :         SAL_INFO("vcl.pdfwriter", "nTsSigLen=" << nTsSigLen);
    7406             : 
    7407             :         boost::scoped_array<BYTE> pTsSig(new BYTE[nTsSigLen]);
    7408             : 
    7409             :         if (!CryptMsgGetParam(hMsg, CMSG_BARE_CONTENT_PARAM, 0, pTsSig.get(), &nTsSigLen))
    7410             :         {
    7411             :             SAL_WARN("vcl.pdfwriter", "CryptMsgGetParam(CMSG_BARE_CONTENT_PARAM) failed: " << WindowsError(GetLastError()));
    7412             :             CryptMsgClose(hDecodedMsg);
    7413             :             CryptMsgClose(hMsg);
    7414             :             CertFreeCertificateContext(pCertContext);
    7415             :             return false;
    7416             :         }
    7417             : 
    7418             :         if (!CryptMsgUpdate(hDecodedMsg, pTsSig.get(), nTsSigLen, TRUE))
    7419             :         {
    7420             :             SAL_WARN("vcl.pdfwriter", "CryptMsgUpdate failed: " << WindowsError(GetLastError()));
    7421             :             CryptMsgClose(hDecodedMsg);
    7422             :             CryptMsgClose(hMsg);
    7423             :             CertFreeCertificateContext(pCertContext);
    7424             :             return false;
    7425             :         }
    7426             : 
    7427             :         DWORD nDecodedSignerInfoLen = 0;
    7428             :         if (!CryptMsgGetParam(hDecodedMsg, CMSG_SIGNER_INFO_PARAM, 0, NULL, &nDecodedSignerInfoLen))
    7429             :         {
    7430             :             SAL_WARN("vcl.pdfwriter", "CryptMsgGetParam(CMSG_SIGNER_INFO_PARAM) failed: " << WindowsError(GetLastError()));
    7431             :             CryptMsgClose(hDecodedMsg);
    7432             :             CryptMsgClose(hMsg);
    7433             :             CertFreeCertificateContext(pCertContext);
    7434             :             return false;
    7435             :         }
    7436             : 
    7437             :         boost::scoped_array<BYTE> pDecodedSignerInfoBuf(new BYTE[nDecodedSignerInfoLen]);
    7438             : 
    7439             :         if (!CryptMsgGetParam(hDecodedMsg, CMSG_SIGNER_INFO_PARAM, 0, pDecodedSignerInfoBuf.get(), &nDecodedSignerInfoLen))
    7440             :         {
    7441             :             SAL_WARN("vcl.pdfwriter", "CryptMsgGetParam(CMSG_SIGNER_INFO_PARAM) failed: " << WindowsError(GetLastError()));
    7442             :             CryptMsgClose(hDecodedMsg);
    7443             :             CryptMsgClose(hMsg);
    7444             :             CertFreeCertificateContext(pCertContext);
    7445             :             return false;
    7446             :         }
    7447             : 
    7448             :         CMSG_SIGNER_INFO *pDecodedSignerInfo = (CMSG_SIGNER_INFO *) pDecodedSignerInfoBuf.get();
    7449             : 
    7450             :         CRYPT_TIMESTAMP_PARA aTsPara;
    7451             :         unsigned int nNonce = comphelper::rng::uniform_uint_distribution(0, SAL_MAX_UINT32);
    7452             : 
    7453             :         aTsPara.pszTSAPolicyId = NULL;
    7454             :         aTsPara.fRequestCerts = TRUE;
    7455             :         aTsPara.Nonce.cbData = sizeof(nNonce);
    7456             :         aTsPara.Nonce.pbData = (BYTE *)&nNonce;
    7457             :         aTsPara.cExtension = 0;
    7458             :         aTsPara.rgExtension = NULL;
    7459             : 
    7460             :         if (!(*crts)(m_aContext.SignTSA.getStr(),
    7461             :                      0,
    7462             :                      10000,
    7463             :                      szOID_NIST_sha256,
    7464             :                      &aTsPara,
    7465             :                      pDecodedSignerInfo->EncryptedHash.pbData,
    7466             :                      pDecodedSignerInfo->EncryptedHash.cbData,
    7467             :                      &pTsContext,
    7468             :                      NULL,
    7469             :                      NULL))
    7470             :         {
    7471             :             SAL_WARN("vcl.pdfwriter", "CryptRetrieveTimeStamp failed: " << WindowsError(GetLastError()));
    7472             :             CryptMsgClose(hDecodedMsg);
    7473             :             CryptMsgClose(hMsg);
    7474             :             CertFreeCertificateContext(pCertContext);
    7475             :             return false;
    7476             :         }
    7477             : 
    7478             :         SAL_INFO("vcl.pdfwriter", "Time stamp size is " << pTsContext->cbEncoded << " bytes");
    7479             : 
    7480             : #ifdef DBG_UTIL
    7481             :         {
    7482             :             FILE *out = fopen("PDFWRITER.tstoken.data", "wb");
    7483             :             fwrite(pTsContext->pbEncoded, pTsContext->cbEncoded, 1, out);
    7484             :             fclose(out);
    7485             :         }
    7486             : #endif
    7487             : 
    7488             :         // I tried to use CryptMsgControl() with CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR to add the
    7489             :         // timestamp, but that failed with "The parameter is incorrect". Probably it is too late to
    7490             :         // modify the message once its data has already been encoded as part of the
    7491             :         // CryptMsgGetParam() with CMSG_BARE_CONTENT_PARAM above. So close the message and re-do its
    7492             :         // creation steps, but now with an amended aSignerInfo.
    7493             : 
    7494             :         CRYPT_INTEGER_BLOB aTimestampBlob;
    7495             :         aTimestampBlob.cbData = pTsContext->cbEncoded;
    7496             :         aTimestampBlob.pbData = pTsContext->pbEncoded;
    7497             : 
    7498             :         CRYPT_ATTRIBUTE aTimestampAttribute;
    7499             :         aTimestampAttribute.pszObjId = "1.2.840.113549.1.9.16.2.14";
    7500             :         aTimestampAttribute.cValue = 1;
    7501             :         aTimestampAttribute.rgValue = &aTimestampBlob;
    7502             : 
    7503             :         aSignerInfo.cUnauthAttr = 1;
    7504             :         aSignerInfo.rgUnauthAttr = &aTimestampAttribute;
    7505             : 
    7506             :         CryptMsgClose(hMsg);
    7507             : 
    7508             :         if (!(hMsg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
    7509             :                                           CMSG_DETACHED_FLAG,
    7510             :                                           CMSG_SIGNED,
    7511             :                                           &aSignedInfo,
    7512             :                                           NULL,
    7513             :                                           NULL)) ||
    7514             :             !CryptMsgUpdate(hMsg, (const BYTE *)buffer1.get(), bytesRead1, FALSE) ||
    7515             :             !CryptMsgUpdate(hMsg, (const BYTE *)buffer2.get(), bytesRead2, TRUE))
    7516             :         {
    7517             :             SAL_WARN("vcl.pdfwriter", "Re-creating the message failed: " << WindowsError(GetLastError()));
    7518             :             CryptMemFree(pTsContext);
    7519             :             CryptMsgClose(hDecodedMsg);
    7520             :             CryptMsgClose(hMsg);
    7521             :             CertFreeCertificateContext(pCertContext);
    7522             :             return false;
    7523             :         }
    7524             : 
    7525             :         CryptMsgClose(hDecodedMsg);
    7526             :     }
    7527             : 
    7528             :     DWORD nSigLen = 0;
    7529             : 
    7530             :     if (!CryptMsgGetParam(hMsg, CMSG_CONTENT_PARAM, 0, NULL, &nSigLen))
    7531             :     {
    7532             :         SAL_WARN("vcl.pdfwriter", "CryptMsgGetParam(CMSG_CONTENT_PARAM) failed: " << WindowsError(GetLastError()));
    7533             :         if (pTsContext)
    7534             :             CryptMemFree(pTsContext);
    7535             :         CryptMsgClose(hMsg);
    7536             :         CertFreeCertificateContext(pCertContext);
    7537             :         return false;
    7538             :     }
    7539             : 
    7540             :     if (nSigLen*2 > MAX_SIGNATURE_CONTENT_LENGTH)
    7541             :     {
    7542             :         SAL_WARN("vcl.pdfwriter", "Signature requires more space (" << nSigLen*2 << ") than we reserved (" << MAX_SIGNATURE_CONTENT_LENGTH << ")");
    7543             :         if (pTsContext)
    7544             :             CryptMemFree(pTsContext);
    7545             :         CryptMsgClose(hMsg);
    7546             :         CertFreeCertificateContext(pCertContext);
    7547             :         return false;
    7548             :     }
    7549             : 
    7550             :     SAL_INFO("vcl.pdfwriter", "Signature size is " << nSigLen << " bytes");
    7551             :     boost::scoped_array<BYTE> pSig(new BYTE[nSigLen]);
    7552             : 
    7553             :     if (!CryptMsgGetParam(hMsg, CMSG_CONTENT_PARAM, 0, pSig.get(), &nSigLen))
    7554             :     {
    7555             :         SAL_WARN("vcl.pdfwriter", "CryptMsgGetParam(CMSG_CONTENT_PARAM) failed: " << WindowsError(GetLastError()));
    7556             :         if (pTsContext)
    7557             :             CryptMemFree(pTsContext);
    7558             :         CryptMsgClose(hMsg);
    7559             :         CertFreeCertificateContext(pCertContext);
    7560             :         return false;
    7561             :     }
    7562             : 
    7563             : #ifdef DBG_UTIL
    7564             :     {
    7565             :         FILE *out = fopen("PDFWRITER.signature.data", "wb");
    7566             :         fwrite(pSig.get(), nSigLen, 1, out);
    7567             :         fclose(out);
    7568             :     }
    7569             : #endif
    7570             : 
    7571             :     // Release resources
    7572             :     if (pTsContext)
    7573             :         CryptMemFree(pTsContext);
    7574             :     CryptMsgClose(hMsg);
    7575             :     CertFreeCertificateContext(pCertContext);
    7576             : 
    7577             :     OStringBuffer cms_hexbuffer;
    7578             : 
    7579             :     for (unsigned int i = 0; i < nSigLen ; i++)
    7580             :         appendHex(pSig[i], cms_hexbuffer);
    7581             : 
    7582             :     // Set file pointer to the m_nSignatureContentOffset, we're ready to overwrite PKCS7 object
    7583             :     nWritten = 0;
    7584             :     CHECK_RETURN( (osl::File::E_None == m_aFile.setPos(osl_Pos_Absolut, m_nSignatureContentOffset)) );
    7585             :     m_aFile.write(cms_hexbuffer.getStr(), cms_hexbuffer.getLength(), nWritten);
    7586             : 
    7587             :     CHECK_RETURN( (osl::File::E_None == m_aFile.setPos(osl_Pos_Absolut, nOffset)) );
    7588             : 
    7589             :     return true;
    7590             : #endif
    7591             : }
    7592             : 
    7593             : #endif
    7594             : 
    7595           0 : sal_Int32 PDFWriterImpl::emitInfoDict( )
    7596             : {
    7597           0 :     sal_Int32 nObject = createObject();
    7598             : 
    7599           0 :     if( updateObject( nObject ) )
    7600             :     {
    7601           0 :         OStringBuffer aLine( 1024 );
    7602           0 :         aLine.append( nObject );
    7603             :         aLine.append( " 0 obj\n"
    7604           0 :                       "<<" );
    7605           0 :         if( !m_aContext.DocumentInfo.Title.isEmpty() )
    7606             :         {
    7607           0 :             aLine.append( "/Title" );
    7608           0 :             appendUnicodeTextStringEncrypt( m_aContext.DocumentInfo.Title, nObject, aLine );
    7609           0 :             aLine.append( "\n" );
    7610             :         }
    7611           0 :         if( !m_aContext.DocumentInfo.Author.isEmpty() )
    7612             :         {
    7613           0 :             aLine.append( "/Author" );
    7614           0 :             appendUnicodeTextStringEncrypt( m_aContext.DocumentInfo.Author, nObject, aLine );
    7615           0 :             aLine.append( "\n" );
    7616             :         }
    7617           0 :         if( !m_aContext.DocumentInfo.Subject.isEmpty() )
    7618             :         {
    7619           0 :             aLine.append( "/Subject" );
    7620           0 :             appendUnicodeTextStringEncrypt( m_aContext.DocumentInfo.Subject, nObject, aLine );
    7621           0 :             aLine.append( "\n" );
    7622             :         }
    7623           0 :         if( !m_aContext.DocumentInfo.Keywords.isEmpty() )
    7624             :         {
    7625           0 :             aLine.append( "/Keywords" );
    7626           0 :             appendUnicodeTextStringEncrypt( m_aContext.DocumentInfo.Keywords, nObject, aLine );
    7627           0 :             aLine.append( "\n" );
    7628             :         }
    7629           0 :         if( !m_aContext.DocumentInfo.Creator.isEmpty() )
    7630             :         {
    7631           0 :             aLine.append( "/Creator" );
    7632           0 :             appendUnicodeTextStringEncrypt( m_aContext.DocumentInfo.Creator, nObject, aLine );
    7633           0 :             aLine.append( "\n" );
    7634             :         }
    7635           0 :         if( !m_aContext.DocumentInfo.Producer.isEmpty() )
    7636             :         {
    7637           0 :             aLine.append( "/Producer" );
    7638           0 :             appendUnicodeTextStringEncrypt( m_aContext.DocumentInfo.Producer, nObject, aLine );
    7639           0 :             aLine.append( "\n" );
    7640             :         }
    7641             : 
    7642           0 :          aLine.append( "/CreationDate" );
    7643           0 :          appendLiteralStringEncrypt( m_aCreationDateString, nObject, aLine );
    7644           0 :         aLine.append( ">>\nendobj\n\n" );
    7645           0 :         if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) )
    7646           0 :             nObject = 0;
    7647             :     }
    7648             :     else
    7649           0 :         nObject = 0;
    7650             : 
    7651           0 :     return nObject;
    7652             : }
    7653             : 
    7654             : //--->i56629
    7655             : // Part of this function may be shared with method appendDest.
    7656           0 : sal_Int32 PDFWriterImpl::emitNamedDestinations()
    7657             : {
    7658           0 :     sal_Int32  nCount = m_aNamedDests.size();
    7659           0 :     if( nCount <= 0 )
    7660           0 :         return 0;//define internal error
    7661             : 
    7662             :     //get the object number for all the destinations
    7663           0 :     sal_Int32 nObject = createObject();
    7664             : 
    7665           0 :     if( updateObject( nObject ) )
    7666             :     {
    7667             :         //emit the dictionary
    7668           0 :         OStringBuffer aLine( 1024 );
    7669           0 :         aLine.append( nObject );
    7670             :         aLine.append( " 0 obj\n"
    7671           0 :                       "<<" );
    7672             : 
    7673             :         sal_Int32  nDestID;
    7674           0 :         for( nDestID = 0; nDestID < nCount; nDestID++ )
    7675             :         {
    7676           0 :             const PDFNamedDest& rDest   = m_aNamedDests[ nDestID ];
    7677             :             // In order to correctly function both under an Internet browser and
    7678             :             // directly with a reader (provided the reader has the feature) we
    7679             :             // need to set the name of the destination the same way it will be encoded
    7680             :             // in an Internet link
    7681             :             INetURLObject aLocalURL(
    7682           0 :                 OUString( "http://ahost.ax"  ) ); //dummy location, won't be used
    7683           0 :             aLocalURL.SetMark( rDest.m_aDestName );
    7684             : 
    7685           0 :             const OUString aName   = aLocalURL.GetMark( INetURLObject::NO_DECODE ); //same coding as
    7686             :             // in link creation ( see PDFWriterImpl::emitLinkAnnotations )
    7687           0 :             const PDFPage& rDestPage    = m_aPages[ rDest.m_nPage ];
    7688             : 
    7689           0 :             aLine.append( '/' );
    7690           0 :             appendDestinationName( aName, aLine ); // this conversion must be done when forming the link to target ( see in emitCatalog )
    7691           0 :             aLine.append( '[' ); // the '[' can be emitted immediately, because the appendDestinationName function
    7692             :                                  //maps the preceding character properly
    7693           0 :             aLine.append( rDestPage.m_nPageObject );
    7694           0 :             aLine.append( " 0 R" );
    7695             : 
    7696           0 :             switch( rDest.m_eType )
    7697             :             {
    7698             :             case PDFWriter::XYZ:
    7699             :             default:
    7700           0 :                 aLine.append( "/XYZ " );
    7701           0 :                 appendFixedInt( rDest.m_aRect.Left(), aLine );
    7702           0 :                 aLine.append( ' ' );
    7703           0 :                 appendFixedInt( rDest.m_aRect.Bottom(), aLine );
    7704           0 :                 aLine.append( " 0" );
    7705           0 :                 break;
    7706             :             case PDFWriter::Fit:
    7707           0 :                 aLine.append( "/Fit" );
    7708           0 :                 break;
    7709             :             case PDFWriter::FitRectangle:
    7710           0 :                 aLine.append( "/FitR " );
    7711           0 :                 appendFixedInt( rDest.m_aRect.Left(), aLine );
    7712           0 :                 aLine.append( ' ' );
    7713           0 :                 appendFixedInt( rDest.m_aRect.Top(), aLine );
    7714           0 :                 aLine.append( ' ' );
    7715           0 :                 appendFixedInt( rDest.m_aRect.Right(), aLine );
    7716           0 :                 aLine.append( ' ' );
    7717           0 :                 appendFixedInt( rDest.m_aRect.Bottom(), aLine );
    7718           0 :                 break;
    7719             :             case PDFWriter::FitHorizontal:
    7720           0 :                 aLine.append( "/FitH " );
    7721           0 :                 appendFixedInt( rDest.m_aRect.Bottom(), aLine );
    7722           0 :                 break;
    7723             :             case PDFWriter::FitVertical:
    7724           0 :                 aLine.append( "/FitV " );
    7725           0 :                 appendFixedInt( rDest.m_aRect.Left(), aLine );
    7726           0 :                 break;
    7727             :             case PDFWriter::FitPageBoundingBox:
    7728           0 :                 aLine.append( "/FitB" );
    7729           0 :                 break;
    7730             :             case PDFWriter::FitPageBoundingBoxHorizontal:
    7731           0 :                 aLine.append( "/FitBH " );
    7732           0 :                 appendFixedInt( rDest.m_aRect.Bottom(), aLine );
    7733           0 :                 break;
    7734             :             case PDFWriter::FitPageBoundingBoxVertical:
    7735           0 :                 aLine.append( "/FitBV " );
    7736           0 :                 appendFixedInt( rDest.m_aRect.Left(), aLine );
    7737           0 :                 break;
    7738             :             }
    7739           0 :             aLine.append( "]\n" );
    7740           0 :         }
    7741             : 
    7742             :         //close
    7743           0 :         aLine.append( ">>\nendobj\n\n" );
    7744           0 :         if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) )
    7745           0 :             nObject = 0;
    7746             :     }
    7747             :     else
    7748           0 :         nObject = 0;
    7749             : 
    7750           0 :     return nObject;
    7751             : }
    7752             : //<--- i56629
    7753             : 
    7754             : //--->i59651
    7755             : // emits the output intent dictionary
    7756           0 : sal_Int32 PDFWriterImpl::emitOutputIntent()
    7757             : {
    7758           0 :     if( !m_bIsPDF_A1 )
    7759           0 :         return 0;
    7760             : 
    7761             :     //emit the sRGB standard profile, in ICC format, in a stream, per IEC61966-2.1
    7762             : 
    7763           0 :     OStringBuffer aLine( 1024 );
    7764           0 :     sal_Int32 nICCObject = createObject();
    7765           0 :     sal_Int32 nStreamLengthObject = createObject();
    7766             : 
    7767           0 :     aLine.append( nICCObject );
    7768             : // sRGB has 3 colors, hence /N 3 below (PDF 1.4 table 4.16)
    7769           0 :     aLine.append( " 0 obj\n<</N 3/Length " );
    7770           0 :     aLine.append( nStreamLengthObject );
    7771           0 :     aLine.append( " 0 R" );
    7772             : #ifndef DEBUG_DISABLE_PDFCOMPRESSION
    7773           0 :     aLine.append( "/Filter/FlateDecode" );
    7774             : #endif
    7775           0 :     aLine.append( ">>\nstream\n" );
    7776           0 :     if ( !updateObject( nICCObject ) ) return 0;
    7777           0 :     if ( !writeBuffer( aLine.getStr(), aLine.getLength() ) ) return 0;
    7778             :     //get file position
    7779           0 :     sal_uInt64 nBeginStreamPos = 0;
    7780           0 :     m_aFile.getPos(nBeginStreamPos);
    7781           0 :     beginCompression();
    7782           0 :     checkAndEnableStreamEncryption( nICCObject );
    7783           0 :     cmsHPROFILE hProfile = cmsCreate_sRGBProfile();
    7784             :     //force ICC profile version 2.1
    7785           0 :     cmsSetProfileVersion(hProfile, 2.1);
    7786           0 :     cmsUInt32Number nBytesNeeded = 0;
    7787           0 :     cmsSaveProfileToMem(hProfile, NULL, &nBytesNeeded);
    7788           0 :     if (!nBytesNeeded)
    7789           0 :       return 0;
    7790           0 :     std::vector<unsigned char> xBuffer(nBytesNeeded);
    7791           0 :     cmsSaveProfileToMem(hProfile, &xBuffer[0], &nBytesNeeded);
    7792           0 :     cmsCloseProfile(hProfile);
    7793           0 :     bool written = writeBuffer( &xBuffer[0], (sal_Int32) xBuffer.size() );
    7794           0 :     disableStreamEncryption();
    7795           0 :     endCompression();
    7796           0 :     sal_uInt64 nEndStreamPos = 0;
    7797           0 :     m_aFile.getPos(nEndStreamPos);
    7798             : 
    7799           0 :     if( !written )
    7800           0 :         return 0;
    7801           0 :     if( ! writeBuffer( "\nendstream\nendobj\n\n", 19 ) )
    7802           0 :         return 0 ;
    7803           0 :     aLine.setLength( 0 );
    7804             : 
    7805             :     //emit the stream length   object
    7806           0 :     if ( !updateObject( nStreamLengthObject ) ) return 0;
    7807           0 :     aLine.setLength( 0 );
    7808           0 :     aLine.append( nStreamLengthObject );
    7809           0 :     aLine.append( " 0 obj\n" );
    7810           0 :     aLine.append( (sal_Int64)(nEndStreamPos-nBeginStreamPos) );
    7811           0 :     aLine.append( "\nendobj\n\n" );
    7812           0 :     if ( !writeBuffer( aLine.getStr(), aLine.getLength() ) ) return 0;
    7813           0 :     aLine.setLength( 0 );
    7814             : 
    7815             :     //emit the OutputIntent dictionary
    7816           0 :     sal_Int32 nOIObject = createObject();
    7817           0 :     if ( !updateObject( nOIObject ) ) return 0;
    7818           0 :     aLine.append( nOIObject );
    7819             :     aLine.append( " 0 obj\n"
    7820           0 :                   "<</Type/OutputIntent/S/GTS_PDFA1/OutputConditionIdentifier");
    7821             : 
    7822           0 :     OUString aComment( "sRGB IEC61966-2.1"  );
    7823           0 :     appendLiteralStringEncrypt( aComment ,nOIObject, aLine );
    7824           0 :     aLine.append("/DestOutputProfile ");
    7825           0 :     aLine.append( nICCObject );
    7826           0 :     aLine.append( " 0 R>>\nendobj\n\n" );;
    7827           0 :     if ( !writeBuffer( aLine.getStr(), aLine.getLength() ) ) return 0;
    7828             : 
    7829           0 :     return nOIObject;
    7830             : }
    7831             : 
    7832             : // formats the string for the XML stream
    7833           0 : static void escapeStringXML( const OUString& rStr, OUString &rValue)
    7834             : {
    7835           0 :     const sal_Unicode* pUni = rStr.getStr();
    7836           0 :     int nLen = rStr.getLength();
    7837           0 :     for( ; nLen; nLen--, pUni++ )
    7838             :     {
    7839           0 :         switch( *pUni )
    7840             :         {
    7841             :         case sal_Unicode('&'):
    7842           0 :             rValue += "&amp;";
    7843           0 :         break;
    7844             :         case sal_Unicode('<'):
    7845           0 :             rValue += "&lt;";
    7846           0 :         break;
    7847             :         case sal_Unicode('>'):
    7848           0 :             rValue += "&gt;";
    7849           0 :         break;
    7850             :         case sal_Unicode('\''):
    7851           0 :             rValue += "&apos;";
    7852           0 :         break;
    7853             :         case sal_Unicode('"'):
    7854           0 :             rValue += "&quot;";
    7855           0 :         break;
    7856             :         default:
    7857           0 :             rValue += OUString( *pUni );
    7858           0 :             break;
    7859             :         }
    7860             :     }
    7861           0 : }
    7862             : 
    7863             : // emits the document metadata
    7864           0 : sal_Int32 PDFWriterImpl::emitDocumentMetadata()
    7865             : {
    7866           0 :     if( !m_bIsPDF_A1 )
    7867           0 :         return 0;
    7868             : 
    7869             :     //get the object number for all the destinations
    7870           0 :     sal_Int32 nObject = createObject();
    7871             : 
    7872           0 :     if( updateObject( nObject ) )
    7873             :     {
    7874             :         // the following string are written in UTF-8 unicode
    7875           0 :         OStringBuffer aMetadataStream( 8192 );
    7876             : 
    7877           0 :         aMetadataStream.append( "<?xpacket begin=\"" );
    7878             :         // these lines write Unicode "zero width non-breaking space character" (U+FEFF)
    7879             :         // (aka byte-order mark ) used as a byte-order marker.
    7880           0 :         aMetadataStream.append( OUStringToOString( OUString( sal_Unicode( 0xFEFF ) ), RTL_TEXTENCODING_UTF8 ) );
    7881           0 :         aMetadataStream.append( "\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>\n" );
    7882           0 :         aMetadataStream.append( "<x:xmpmeta xmlns:x=\"adobe:ns:meta/\">\n" );
    7883           0 :         aMetadataStream.append( " <rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n" );
    7884             :         //PDF/A part ( ISO 19005-1:2005 - 6.7.11 )
    7885           0 :         aMetadataStream.append( "  <rdf:Description rdf:about=\"\"\n" );
    7886           0 :         aMetadataStream.append( "      xmlns:pdfaid=\"http://www.aiim.org/pdfa/ns/id/\">\n" );
    7887           0 :         aMetadataStream.append( "   <pdfaid:part>1</pdfaid:part>\n" );
    7888           0 :         aMetadataStream.append( "   <pdfaid:conformance>A</pdfaid:conformance>\n" );
    7889           0 :         aMetadataStream.append( "  </rdf:Description>\n" );
    7890             :         //... Dublin Core properties go here
    7891           0 :         if( !m_aContext.DocumentInfo.Title.isEmpty() ||
    7892           0 :             !m_aContext.DocumentInfo.Author.isEmpty() ||
    7893           0 :             !m_aContext.DocumentInfo.Subject.isEmpty() )
    7894             :         {
    7895           0 :             aMetadataStream.append( "  <rdf:Description rdf:about=\"\"\n" );
    7896           0 :             aMetadataStream.append( "      xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n" );
    7897           0 :             if( !m_aContext.DocumentInfo.Title.isEmpty() )
    7898             :             {
    7899             :                 // this is according to PDF/A-1, technical corrigendum 1 (2007-04-01)
    7900           0 :                 aMetadataStream.append( "   <dc:title>\n" );
    7901           0 :                 aMetadataStream.append( "    <rdf:Alt>\n" );
    7902           0 :                 aMetadataStream.append( "     <rdf:li xml:lang=\"x-default\">" );
    7903           0 :                 OUString aTitle;
    7904           0 :                 escapeStringXML( m_aContext.DocumentInfo.Title, aTitle );
    7905           0 :                 aMetadataStream.append( OUStringToOString( aTitle, RTL_TEXTENCODING_UTF8 )  );
    7906           0 :                 aMetadataStream.append( "</rdf:li>\n" );
    7907           0 :                 aMetadataStream.append( "    </rdf:Alt>\n" );
    7908           0 :                 aMetadataStream.append( "   </dc:title>\n" );
    7909             :             }
    7910           0 :             if( !m_aContext.DocumentInfo.Author.isEmpty() )
    7911             :             {
    7912           0 :                 aMetadataStream.append( "   <dc:creator>\n" );
    7913           0 :                 aMetadataStream.append( "    <rdf:Seq>\n" );
    7914           0 :                 aMetadataStream.append( "     <rdf:li>" );
    7915           0 :                 OUString aAuthor;
    7916           0 :                 escapeStringXML( m_aContext.DocumentInfo.Author, aAuthor );
    7917           0 :                 aMetadataStream.append( OUStringToOString( aAuthor , RTL_TEXTENCODING_UTF8 )  );
    7918           0 :                 aMetadataStream.append( "</rdf:li>\n" );
    7919           0 :                 aMetadataStream.append( "    </rdf:Seq>\n" );
    7920           0 :                 aMetadataStream.append( "   </dc:creator>\n" );
    7921             :             }
    7922           0 :             if( !m_aContext.DocumentInfo.Subject.isEmpty() )
    7923             :             {
    7924             :                 // this is according to PDF/A-1, technical corrigendum 1 (2007-04-01)
    7925           0 :                 aMetadataStream.append( "   <dc:description>\n" );
    7926           0 :                 aMetadataStream.append( "    <rdf:Alt>\n" );
    7927           0 :                 aMetadataStream.append( "     <rdf:li xml:lang=\"x-default\">" );
    7928           0 :                 OUString aSubject;
    7929           0 :                 escapeStringXML( m_aContext.DocumentInfo.Subject, aSubject );
    7930           0 :                 aMetadataStream.append( OUStringToOString( aSubject , RTL_TEXTENCODING_UTF8 )  );
    7931           0 :                 aMetadataStream.append( "</rdf:li>\n" );
    7932           0 :                 aMetadataStream.append( "    </rdf:Alt>\n" );
    7933           0 :                 aMetadataStream.append( "   </dc:description>\n" );
    7934             :             }
    7935           0 :             aMetadataStream.append( "  </rdf:Description>\n" );
    7936             :         }
    7937             : 
    7938             :         //... PDF properties go here
    7939           0 :         if( !m_aContext.DocumentInfo.Producer.isEmpty() ||
    7940           0 :             !m_aContext.DocumentInfo.Keywords.isEmpty() )
    7941             :         {
    7942           0 :             aMetadataStream.append( "  <rdf:Description rdf:about=\"\"\n" );
    7943           0 :             aMetadataStream.append( "     xmlns:pdf=\"http://ns.adobe.com/pdf/1.3/\">\n" );
    7944           0 :             if( !m_aContext.DocumentInfo.Producer.isEmpty() )
    7945             :             {
    7946           0 :                 aMetadataStream.append( "   <pdf:Producer>" );
    7947           0 :                 OUString aProducer;
    7948           0 :                 escapeStringXML( m_aContext.DocumentInfo.Producer, aProducer );
    7949           0 :                 aMetadataStream.append( OUStringToOString( aProducer , RTL_TEXTENCODING_UTF8 )  );
    7950           0 :                 aMetadataStream.append( "</pdf:Producer>\n" );
    7951             :             }
    7952           0 :             if( !m_aContext.DocumentInfo.Keywords.isEmpty() )
    7953             :             {
    7954           0 :                 aMetadataStream.append( "   <pdf:Keywords>" );
    7955           0 :                 OUString aKeywords;
    7956           0 :                 escapeStringXML( m_aContext.DocumentInfo.Keywords, aKeywords );
    7957           0 :                 aMetadataStream.append( OUStringToOString( aKeywords , RTL_TEXTENCODING_UTF8 )  );
    7958           0 :                 aMetadataStream.append( "</pdf:Keywords>\n" );
    7959             :             }
    7960           0 :             aMetadataStream.append( "  </rdf:Description>\n" );
    7961             :         }
    7962             : 
    7963           0 :         aMetadataStream.append( "  <rdf:Description rdf:about=\"\"\n" );
    7964           0 :         aMetadataStream.append( "    xmlns:xmp=\"http://ns.adobe.com/xap/1.0/\">\n" );
    7965           0 :         if( !m_aContext.DocumentInfo.Creator.isEmpty() )
    7966             :         {
    7967           0 :             aMetadataStream.append( "   <xmp:CreatorTool>" );
    7968           0 :             OUString aCreator;
    7969           0 :             escapeStringXML( m_aContext.DocumentInfo.Creator, aCreator );
    7970           0 :             aMetadataStream.append( OUStringToOString( aCreator , RTL_TEXTENCODING_UTF8 )  );
    7971           0 :             aMetadataStream.append( "</xmp:CreatorTool>\n" );
    7972             :         }
    7973             :         //creation date
    7974           0 :         aMetadataStream.append( "   <xmp:CreateDate>" );
    7975           0 :         aMetadataStream.append( m_aCreationMetaDateString );
    7976           0 :         aMetadataStream.append( "</xmp:CreateDate>\n" );
    7977             : 
    7978           0 :         aMetadataStream.append( "  </rdf:Description>\n" );
    7979           0 :         aMetadataStream.append( " </rdf:RDF>\n" );
    7980           0 :         aMetadataStream.append( "</x:xmpmeta>\n" );
    7981             : 
    7982             :         //add the padding
    7983           0 :         for( sal_Int32 nSpaces = 1; nSpaces <= 2100; nSpaces++ )
    7984             :         {
    7985           0 :             aMetadataStream.append( " " );
    7986           0 :             if( nSpaces % 100 == 0 )
    7987           0 :                 aMetadataStream.append( "\n" );
    7988             :         }
    7989             : 
    7990           0 :         aMetadataStream.append( "<?xpacket end=\"w\"?>\n" );
    7991             : 
    7992           0 :         OStringBuffer aMetadataObj( 1024 );
    7993             : 
    7994           0 :         aMetadataObj.append( nObject );
    7995           0 :         aMetadataObj.append( " 0 obj\n" );
    7996             : 
    7997           0 :         aMetadataObj.append( "<</Type/Metadata/Subtype/XML/Length " );
    7998             : 
    7999           0 :         aMetadataObj.append( (sal_Int32) aMetadataStream.getLength() );
    8000           0 :         aMetadataObj.append( ">>\nstream\n" );
    8001           0 :         if ( !writeBuffer( aMetadataObj.getStr(), aMetadataObj.getLength() ) )
    8002           0 :             return 0;
    8003             :         //emit the stream
    8004           0 :         if ( !writeBuffer( aMetadataStream.getStr(), aMetadataStream.getLength() ) )
    8005           0 :             return 0;
    8006             : 
    8007           0 :         aMetadataObj.setLength( 0 );
    8008           0 :         aMetadataObj.append( "\nendstream\nendobj\n\n" );
    8009           0 :         if( ! writeBuffer( aMetadataObj.getStr(), aMetadataObj.getLength() ) )
    8010           0 :             nObject = 0;
    8011             :     }
    8012             :     else
    8013           0 :         nObject = 0;
    8014             : 
    8015           0 :     return nObject;
    8016             : }
    8017             : //<---i59651
    8018             : 
    8019           0 : bool PDFWriterImpl::emitTrailer()
    8020             : {
    8021             :     // emit doc info
    8022           0 :     sal_Int32 nDocInfoObject = emitInfoDict( );
    8023             : 
    8024           0 :     sal_Int32 nSecObject = 0;
    8025             : 
    8026           0 :     if( m_aContext.Encryption.Encrypt() )
    8027             :     {
    8028             :         //emit the security information
    8029             :         //must be emitted as indirect dictionary object, since
    8030             :         //Acrobat Reader 5 works only with this kind of implementation
    8031           0 :         nSecObject = createObject();
    8032             : 
    8033           0 :         if( updateObject( nSecObject ) )
    8034             :         {
    8035           0 :             OStringBuffer aLineS( 1024 );
    8036           0 :             aLineS.append( nSecObject );
    8037             :             aLineS.append( " 0 obj\n"
    8038           0 :                            "<</Filter/Standard/V " );
    8039             :             // check the version
    8040           0 :             if( m_aContext.Encryption.Security128bit )
    8041           0 :                 aLineS.append( "2/Length 128/R 3" );
    8042             :             else
    8043           0 :                 aLineS.append( "1/R 2" );
    8044             : 
    8045             :             // emit the owner password, must not be encrypted
    8046           0 :             aLineS.append( "/O(" );
    8047           0 :             appendLiteralString( reinterpret_cast<char*>(&m_aContext.Encryption.OValue[0]), sal_Int32(m_aContext.Encryption.OValue.size()), aLineS );
    8048           0 :             aLineS.append( ")/U(" );
    8049           0 :             appendLiteralString( reinterpret_cast<char*>(&m_aContext.Encryption.UValue[0]), sal_Int32(m_aContext.Encryption.UValue.size()), aLineS );
    8050           0 :             aLineS.append( ")/P " );// the permission set
    8051           0 :             aLineS.append( m_nAccessPermissions );
    8052           0 :             aLineS.append( ">>\nendobj\n\n" );
    8053           0 :             if( !writeBuffer( aLineS.getStr(), aLineS.getLength() ) )
    8054           0 :                 nSecObject = 0;
    8055             :         }
    8056             :         else
    8057           0 :             nSecObject = 0;
    8058             :     }
    8059             :     // emit xref table
    8060             :     // remember start
    8061           0 :     sal_uInt64 nXRefOffset = 0;
    8062           0 :     CHECK_RETURN( (osl::File::E_None == m_aFile.getPos(nXRefOffset )) );
    8063           0 :     CHECK_RETURN( writeBuffer( "xref\n", 5 ) );
    8064             : 
    8065           0 :     sal_Int32 nObjects = m_aObjects.size();
    8066           0 :     OStringBuffer aLine;
    8067           0 :     aLine.append( "0 " );
    8068           0 :     aLine.append( (sal_Int32)(nObjects+1) );
    8069           0 :     aLine.append( "\n" );
    8070           0 :     aLine.append( "0000000000 65535 f \n" );
    8071           0 :     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
    8072             : 
    8073           0 :     for( sal_Int32 i = 0; i < nObjects; i++ )
    8074             :     {
    8075           0 :         aLine.setLength( 0 );
    8076           0 :         OString aOffset = OString::number( m_aObjects[i] );
    8077           0 :         for( sal_Int32 j = 0; j < (10-aOffset.getLength()); j++ )
    8078           0 :             aLine.append( '0' );
    8079           0 :         aLine.append( aOffset );
    8080           0 :         aLine.append( " 00000 n \n" );
    8081             :         DBG_ASSERT( aLine.getLength() == 20, "invalid xref entry" );
    8082           0 :         CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
    8083           0 :     }
    8084             : 
    8085             :     // prepare document checksum
    8086           0 :     OStringBuffer aDocChecksum( 2*RTL_DIGEST_LENGTH_MD5+1 );
    8087           0 :     if( m_aDocDigest )
    8088             :     {
    8089             :         sal_uInt8 nMD5Sum[ RTL_DIGEST_LENGTH_MD5 ];
    8090           0 :         rtl_digest_getMD5( m_aDocDigest, nMD5Sum, sizeof(nMD5Sum) );
    8091           0 :         for( unsigned int i = 0; i < RTL_DIGEST_LENGTH_MD5; i++ )
    8092           0 :             appendHex( nMD5Sum[i], aDocChecksum );
    8093             :     }
    8094             :     // document id set in setDocInfo method
    8095             :     // emit trailer
    8096           0 :     aLine.setLength( 0 );
    8097             :     aLine.append( "trailer\n"
    8098           0 :                   "<</Size " );
    8099           0 :     aLine.append( (sal_Int32)(nObjects+1) );
    8100           0 :     aLine.append( "/Root " );
    8101           0 :     aLine.append( m_nCatalogObject );
    8102           0 :     aLine.append( " 0 R\n" );
    8103           0 :     if( nSecObject )
    8104             :     {
    8105           0 :         aLine.append( "/Encrypt ");
    8106           0 :         aLine.append( nSecObject );
    8107           0 :         aLine.append( " 0 R\n" );
    8108             :     }
    8109           0 :     if( nDocInfoObject )
    8110             :     {
    8111           0 :         aLine.append( "/Info " );
    8112           0 :         aLine.append( nDocInfoObject );
    8113           0 :         aLine.append( " 0 R\n" );
    8114             :     }
    8115           0 :     if( ! m_aContext.Encryption.DocumentIdentifier.empty() )
    8116             :     {
    8117           0 :         aLine.append( "/ID [ <" );
    8118           0 :         for( std::vector< sal_uInt8 >::const_iterator it = m_aContext.Encryption.DocumentIdentifier.begin();
    8119           0 :              it != m_aContext.Encryption.DocumentIdentifier.end(); ++it )
    8120             :         {
    8121           0 :             appendHex( sal_Int8(*it), aLine );
    8122             :         }
    8123             :         aLine.append( ">\n"
    8124           0 :                       "<" );
    8125           0 :         for( std::vector< sal_uInt8 >::const_iterator it = m_aContext.Encryption.DocumentIdentifier.begin();
    8126           0 :              it != m_aContext.Encryption.DocumentIdentifier.end(); ++it )
    8127             :         {
    8128           0 :             appendHex( sal_Int8(*it), aLine );
    8129             :         }
    8130           0 :         aLine.append( "> ]\n" );
    8131             :     }
    8132           0 :     if( !aDocChecksum.isEmpty() )
    8133             :     {
    8134           0 :         aLine.append( "/DocChecksum /" );
    8135           0 :         aLine.append( aDocChecksum.makeStringAndClear() );
    8136           0 :         aLine.append( "\n" );
    8137             :     }
    8138           0 :     if( m_aAdditionalStreams.size() > 0 )
    8139             :     {
    8140           0 :         aLine.append( "/AdditionalStreams [" );
    8141           0 :         for( size_t i = 0; i < m_aAdditionalStreams.size(); i++ )
    8142             :         {
    8143           0 :             aLine.append( "/" );
    8144           0 :             appendName( m_aAdditionalStreams[i].m_aMimeType, aLine );
    8145           0 :             aLine.append( " " );
    8146           0 :             aLine.append( m_aAdditionalStreams[i].m_nStreamObject );
    8147           0 :             aLine.append( " 0 R\n" );
    8148             :         }
    8149           0 :         aLine.append( "]\n" );
    8150             :     }
    8151             :     aLine.append( ">>\n"
    8152           0 :                   "startxref\n" );
    8153           0 :     aLine.append( (sal_Int64)nXRefOffset );
    8154             :     aLine.append( "\n"
    8155           0 :                   "%%EOF\n" );
    8156           0 :     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
    8157             : 
    8158           0 :     return true;
    8159             : }
    8160             : 
    8161             : struct AnnotationSortEntry
    8162             : {
    8163             :     sal_Int32 nTabOrder;
    8164             :     sal_Int32 nObject;
    8165             :     sal_Int32 nWidgetIndex;
    8166             : 
    8167           0 :     AnnotationSortEntry( sal_Int32 nTab, sal_Int32 nObj, sal_Int32 nI ) :
    8168             :         nTabOrder( nTab ),
    8169             :         nObject( nObj ),
    8170           0 :         nWidgetIndex( nI )
    8171           0 :     {}
    8172             : };
    8173             : 
    8174           0 : struct AnnotSortContainer
    8175             : {
    8176             :     std::set< sal_Int32 >               aObjects;
    8177             :     std::vector< AnnotationSortEntry >    aSortedAnnots;
    8178             : };
    8179             : 
    8180             : struct AnnotSorterLess
    8181             : {
    8182             :     std::vector< PDFWriterImpl::PDFWidget >& m_rWidgets;
    8183             : 
    8184           0 :     explicit AnnotSorterLess( std::vector< PDFWriterImpl::PDFWidget >& rWidgets ) : m_rWidgets( rWidgets ) {}
    8185             : 
    8186           0 :     bool operator()( const AnnotationSortEntry& rLeft, const AnnotationSortEntry& rRight )
    8187             :     {
    8188           0 :         if( rLeft.nTabOrder < rRight.nTabOrder )
    8189           0 :             return true;
    8190           0 :         if( rRight.nTabOrder < rLeft.nTabOrder )
    8191           0 :             return false;
    8192           0 :         if( rLeft.nWidgetIndex < 0 && rRight.nWidgetIndex < 0 )
    8193           0 :             return false;
    8194           0 :         if( rRight.nWidgetIndex < 0 )
    8195           0 :             return true;
    8196           0 :         if( rLeft.nWidgetIndex < 0 )
    8197           0 :             return false;
    8198             :         // remember: widget rects are in PDF coordinates, so they are ordered down up
    8199           0 :         if( m_rWidgets[ rLeft.nWidgetIndex ].m_aRect.Top() >
    8200           0 :             m_rWidgets[ rRight.nWidgetIndex ].m_aRect.Top() )
    8201           0 :             return true;
    8202           0 :         if( m_rWidgets[ rRight.nWidgetIndex ].m_aRect.Top() >
    8203           0 :             m_rWidgets[ rLeft.nWidgetIndex ].m_aRect.Top() )
    8204           0 :             return false;
    8205           0 :         if( m_rWidgets[ rLeft.nWidgetIndex ].m_aRect.Left() <
    8206           0 :             m_rWidgets[ rRight.nWidgetIndex ].m_aRect.Left() )
    8207           0 :             return true;
    8208           0 :         return false;
    8209             :     }
    8210             : };
    8211             : 
    8212           0 : void PDFWriterImpl::sortWidgets()
    8213             : {
    8214             :     // sort widget annotations on each page as per their
    8215             :     // TabOrder attribute
    8216           0 :     std::unordered_map< sal_Int32, AnnotSortContainer > sorted;
    8217           0 :     int nWidgets = m_aWidgets.size();
    8218           0 :     for( int nW = 0; nW < nWidgets; nW++ )
    8219             :     {
    8220           0 :         const PDFWidget& rWidget = m_aWidgets[nW];
    8221           0 :         if( rWidget.m_nPage >= 0 )
    8222             :         {
    8223           0 :             AnnotSortContainer& rCont = sorted[ rWidget.m_nPage ];
    8224             :             // optimize vector allocation
    8225           0 :             if( rCont.aSortedAnnots.empty() )
    8226           0 :                 rCont.aSortedAnnots.reserve( m_aPages[ rWidget.m_nPage ].m_aAnnotations.size() );
    8227             :             // insert widget to tab sorter
    8228             :             // RadioButtons are not page annotations, only their individual check boxes are
    8229           0 :             if( rWidget.m_eType != PDFWriter::RadioButton )
    8230             :             {
    8231           0 :                 rCont.aObjects.insert( rWidget.m_nObject );
    8232           0 :                 rCont.aSortedAnnots.push_back( AnnotationSortEntry( rWidget.m_nTabOrder, rWidget.m_nObject, nW ) );
    8233             :             }
    8234             :         }
    8235             :     }
    8236           0 :     for( std::unordered_map< sal_Int32, AnnotSortContainer >::iterator it = sorted.begin(); it != sorted.end(); ++it )
    8237             :     {
    8238             :         // append entries for non widget annotations
    8239           0 :         PDFPage& rPage = m_aPages[ it->first ];
    8240           0 :         unsigned int nAnnots = rPage.m_aAnnotations.size();
    8241           0 :         for( unsigned int nA = 0; nA < nAnnots; nA++ )
    8242           0 :             if( it->second.aObjects.find( rPage.m_aAnnotations[nA] ) == it->second.aObjects.end())
    8243           0 :                 it->second.aSortedAnnots.push_back( AnnotationSortEntry( 10000, rPage.m_aAnnotations[nA], -1 ) );
    8244             : 
    8245           0 :         AnnotSorterLess aLess( m_aWidgets );
    8246           0 :         std::stable_sort( it->second.aSortedAnnots.begin(), it->second.aSortedAnnots.end(), aLess );
    8247             :         // sanity check
    8248           0 :         if( it->second.aSortedAnnots.size() == nAnnots)
    8249             :         {
    8250           0 :             for( unsigned int nA = 0; nA < nAnnots; nA++ )
    8251           0 :                 rPage.m_aAnnotations[nA] = it->second.aSortedAnnots[nA].nObject;
    8252             :         }
    8253             :         else
    8254             :         {
    8255             :             DBG_ASSERT( false, "wrong number of sorted annotations" );
    8256             :             #if OSL_DEBUG_LEVEL > 0
    8257             :             fprintf( stderr, "PDFWriterImpl::sortWidgets(): wrong number of sorted assertions on page nr %ld\n"
    8258             :                      "    %ld sorted and %ld unsorted\n", (long int)it->first, (long int)it->second.aSortedAnnots.size(), (long int)nAnnots );
    8259             :             #endif
    8260             :         }
    8261           0 :     }
    8262             : 
    8263             :     // FIXME: implement tab order in structure tree for PDF 1.5
    8264           0 : }
    8265             : 
    8266             : namespace vcl {
    8267             : class PDFStreamIf :
    8268             :         public cppu::WeakImplHelper1< com::sun::star::io::XOutputStream >
    8269             : {
    8270             :     PDFWriterImpl*  m_pWriter;
    8271             :     bool            m_bWrite;
    8272             :     public:
    8273           0 :     explicit PDFStreamIf( PDFWriterImpl* pWriter ) : m_pWriter( pWriter ), m_bWrite( true ) {}
    8274             :     virtual ~PDFStreamIf();
    8275             : 
    8276             :     virtual void SAL_CALL writeBytes( const com::sun::star::uno::Sequence< sal_Int8 >& aData ) throw(std::exception) SAL_OVERRIDE;
    8277             :     virtual void SAL_CALL flush() throw(std::exception) SAL_OVERRIDE;
    8278             :     virtual void SAL_CALL closeOutput() throw(std::exception) SAL_OVERRIDE;
    8279             : };
    8280             : }
    8281             : 
    8282           0 : PDFStreamIf::~PDFStreamIf()
    8283             : {
    8284           0 : }
    8285             : 
    8286           0 : void SAL_CALL  PDFStreamIf::writeBytes( const com::sun::star::uno::Sequence< sal_Int8 >& aData ) throw(std::exception)
    8287             : {
    8288           0 :     if( m_bWrite && aData.getLength() )
    8289             :     {
    8290           0 :         sal_Int32 nBytes = aData.getLength();
    8291           0 :         m_pWriter->writeBuffer( aData.getConstArray(), nBytes );
    8292             :     }
    8293           0 : }
    8294             : 
    8295           0 : void SAL_CALL PDFStreamIf::flush() throw(std::exception)
    8296             : {
    8297           0 : }
    8298             : 
    8299           0 : void SAL_CALL PDFStreamIf::closeOutput() throw(std::exception)
    8300             : {
    8301           0 :     m_bWrite = false;
    8302           0 : }
    8303             : 
    8304           0 : bool PDFWriterImpl::emitAdditionalStreams()
    8305             : {
    8306           0 :     unsigned int nStreams = m_aAdditionalStreams.size();
    8307           0 :     for( unsigned int i = 0; i < nStreams; i++ )
    8308             :     {
    8309           0 :         PDFAddStream& rStream = m_aAdditionalStreams[i];
    8310           0 :         rStream.m_nStreamObject = createObject();
    8311           0 :         sal_Int32 nSizeObject = createObject();
    8312             : 
    8313           0 :         if( ! updateObject( rStream.m_nStreamObject ) )
    8314           0 :             return false;
    8315             : 
    8316           0 :         OStringBuffer aLine;
    8317           0 :         aLine.append( rStream.m_nStreamObject );
    8318           0 :         aLine.append( " 0 obj\n<</Length " );
    8319           0 :         aLine.append( nSizeObject );
    8320           0 :         aLine.append( " 0 R" );
    8321           0 :         if( rStream.m_bCompress )
    8322           0 :             aLine.append( "/Filter/FlateDecode" );
    8323           0 :         aLine.append( ">>\nstream\n" );
    8324           0 :         if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) )
    8325           0 :             return false;
    8326           0 :         sal_uInt64 nBeginStreamPos = 0, nEndStreamPos = 0;
    8327           0 :         if( osl::File::E_None != m_aFile.getPos(nBeginStreamPos) )
    8328             :         {
    8329           0 :             m_aFile.close();
    8330           0 :             m_bOpen = false;
    8331             :         }
    8332           0 :         if( rStream.m_bCompress )
    8333           0 :             beginCompression();
    8334             : 
    8335           0 :         checkAndEnableStreamEncryption( rStream.m_nStreamObject );
    8336           0 :         com::sun::star::uno::Reference< com::sun::star::io::XOutputStream > xStream( new PDFStreamIf( this ) );
    8337             :         assert(rStream.m_pStream);
    8338           0 :         if (!rStream.m_pStream)
    8339           0 :             return false;
    8340           0 :         rStream.m_pStream->write( xStream );
    8341           0 :         xStream.clear();
    8342           0 :         delete rStream.m_pStream;
    8343           0 :         rStream.m_pStream = NULL;
    8344           0 :         disableStreamEncryption();
    8345             : 
    8346           0 :         if( rStream.m_bCompress )
    8347           0 :             endCompression();
    8348             : 
    8349           0 :         if (osl::File::E_None != m_aFile.getPos(nEndStreamPos))
    8350             :         {
    8351           0 :             m_aFile.close();
    8352           0 :             m_bOpen = false;
    8353           0 :             return false;
    8354             :         }
    8355           0 :         if( ! writeBuffer( "\nendstream\nendobj\n\n", 19 ) )
    8356           0 :             return false ;
    8357             :         // emit stream length object
    8358           0 :         if( ! updateObject( nSizeObject ) )
    8359           0 :             return false;
    8360           0 :         aLine.setLength( 0 );
    8361           0 :         aLine.append( nSizeObject );
    8362           0 :         aLine.append( " 0 obj\n" );
    8363           0 :         aLine.append( (sal_Int64)(nEndStreamPos-nBeginStreamPos) );
    8364           0 :         aLine.append( "\nendobj\n\n" );
    8365           0 :         if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) )
    8366           0 :             return false;
    8367           0 :     }
    8368           0 :     return true;
    8369             : }
    8370             : 
    8371           0 : bool PDFWriterImpl::emit()
    8372             : {
    8373           0 :     endPage();
    8374             : 
    8375             :     // resort structure tree and annotations if necessary
    8376             :     // needed for widget tab order
    8377           0 :     sortWidgets();
    8378             : 
    8379             : #if !defined(ANDROID) && !defined(IOS)
    8380           0 :     if( m_aContext.SignPDF )
    8381             :     {
    8382             :         // sign the document
    8383           0 :         PDFWriter::SignatureWidget aSignature;
    8384           0 :         aSignature.Name = "Signature1";
    8385           0 :         createControl( aSignature, 0 );
    8386             :     }
    8387             : #endif
    8388             : 
    8389             :     // emit additional streams
    8390           0 :     CHECK_RETURN( emitAdditionalStreams() );
    8391             : 
    8392             :     // emit catalog
    8393           0 :     CHECK_RETURN( emitCatalog() );
    8394             : 
    8395             : #if !defined(ANDROID) && !defined(IOS)
    8396           0 :     if (m_nSignatureObject != -1) // if document is signed, emit sigdict
    8397             :     {
    8398           0 :         if( !emitSignature() )
    8399             :         {
    8400           0 :             m_aErrors.insert( PDFWriter::Error_Signature_Failed );
    8401           0 :             return false;
    8402             :         }
    8403             :     }
    8404             : #endif
    8405             : 
    8406             :     // emit trailer
    8407           0 :     CHECK_RETURN( emitTrailer() );
    8408             : 
    8409             : #if !defined(ANDROID) && !defined(IOS)
    8410           0 :     if (m_nSignatureObject != -1) // finalize the signature
    8411             :     {
    8412           0 :         if( !finalizeSignature() )
    8413             :         {
    8414           0 :             m_aErrors.insert( PDFWriter::Error_Signature_Failed );
    8415           0 :             return false;
    8416             :         }
    8417             :     }
    8418             : #endif
    8419             : 
    8420           0 :     m_aFile.close();
    8421           0 :     m_bOpen = false;
    8422             : 
    8423           0 :     return true;
    8424             : }
    8425             : 
    8426             : 
    8427           0 : sal_Int32 PDFWriterImpl::getSystemFont( const vcl::Font& i_rFont )
    8428             : {
    8429           0 :     getReferenceDevice()->Push();
    8430           0 :     getReferenceDevice()->SetFont( i_rFont );
    8431           0 :     getReferenceDevice()->ImplNewFont();
    8432             : 
    8433           0 :     const PhysicalFontFace* pDevFont = m_pReferenceDevice->mpFontEntry->maFontSelData.mpFontData;
    8434           0 :     sal_Int32 nFontID = 0;
    8435           0 :     FontEmbedData::iterator it = m_aSystemFonts.find( pDevFont );
    8436           0 :     if( it != m_aSystemFonts.end() )
    8437           0 :         nFontID = it->second.m_nNormalFontID;
    8438             :     else
    8439             :     {
    8440           0 :         nFontID = m_nNextFID++;
    8441           0 :         m_aSystemFonts[ pDevFont ] = EmbedFont();
    8442           0 :         m_aSystemFonts[ pDevFont ].m_nNormalFontID = nFontID;
    8443             :     }
    8444             : 
    8445           0 :     getReferenceDevice()->Pop();
    8446           0 :     getReferenceDevice()->ImplNewFont();
    8447             : 
    8448           0 :     return nFontID;
    8449             : }
    8450             : 
    8451           0 : bool PDFWriterImpl::registerGlyphs( int nGlyphs,
    8452             :                                     sal_GlyphId* pGlyphs,
    8453             :                                     sal_Int32* pGlyphWidths,
    8454             :                                     sal_Ucs* pUnicodes,
    8455             :                                     sal_Int32* pUnicodesPerGlyph,
    8456             :                                     sal_uInt8* pMappedGlyphs,
    8457             :                                     sal_Int32* pMappedFontObjects,
    8458             :                                     const PhysicalFontFace* pFallbackFonts[] )
    8459             : {
    8460           0 :     SalGraphics *pGraphics = m_pReferenceDevice->GetGraphics();
    8461             : 
    8462           0 :     if (!pGraphics)
    8463           0 :         return false;
    8464             : 
    8465           0 :     const PhysicalFontFace* pDevFont = m_pReferenceDevice->mpFontEntry->maFontSelData.mpFontData;
    8466           0 :     sal_Ucs* pCurUnicode = pUnicodes;
    8467           0 :     for( int i = 0; i < nGlyphs; pCurUnicode += pUnicodesPerGlyph[i] , i++ )
    8468             :     {
    8469           0 :         const int nFontGlyphId = pGlyphs[i] & (GF_IDXMASK | GF_ISCHAR | GF_GSUB);
    8470           0 :         const PhysicalFontFace* pCurrentFont = pFallbackFonts[i] ? pFallbackFonts[i] : pDevFont;
    8471             : 
    8472           0 :         if( pCurrentFont->mbSubsettable )
    8473             :         {
    8474           0 :             FontSubset& rSubset = m_aSubsets[ pCurrentFont ];
    8475             :             // search for font specific glyphID
    8476           0 :             FontMapping::iterator it = rSubset.m_aMapping.find( nFontGlyphId );
    8477           0 :             if( it != rSubset.m_aMapping.end() )
    8478             :             {
    8479           0 :                 pMappedFontObjects[i] = it->second.m_nFontID;
    8480           0 :                 pMappedGlyphs[i] = it->second.m_nSubsetGlyphID;
    8481             :             }
    8482             :             else
    8483             :             {
    8484             :                 // create new subset if necessary
    8485           0 :                 if( rSubset.m_aSubsets.empty()
    8486           0 :                 || (rSubset.m_aSubsets.back().m_aMapping.size() > 254) )
    8487             :                 {
    8488           0 :                     rSubset.m_aSubsets.push_back( FontEmit( m_nNextFID++ ) );
    8489             :                 }
    8490             : 
    8491             :                 // copy font id
    8492           0 :                 pMappedFontObjects[i] = rSubset.m_aSubsets.back().m_nFontID;
    8493             :                 // create new glyph in subset
    8494           0 :                 sal_uInt8 nNewId = sal::static_int_cast<sal_uInt8>(rSubset.m_aSubsets.back().m_aMapping.size()+1);
    8495           0 :                 pMappedGlyphs[i] = nNewId;
    8496             : 
    8497             :                 // add new glyph to emitted font subset
    8498           0 :                 GlyphEmit& rNewGlyphEmit = rSubset.m_aSubsets.back().m_aMapping[ nFontGlyphId ];
    8499           0 :                 rNewGlyphEmit.setGlyphId( nNewId );
    8500           0 :                 for( sal_Int32 n = 0; n < pUnicodesPerGlyph[i]; n++ )
    8501           0 :                     rNewGlyphEmit.addCode( pCurUnicode[n] );
    8502             : 
    8503             :                 // add new glyph to font mapping
    8504           0 :                 Glyph& rNewGlyph = rSubset.m_aMapping[ nFontGlyphId ];
    8505           0 :                 rNewGlyph.m_nFontID = pMappedFontObjects[i];
    8506           0 :                 rNewGlyph.m_nSubsetGlyphID = nNewId;
    8507             :             }
    8508           0 :             if (!getReferenceDevice()->AcquireGraphics())
    8509           0 :                 return false;
    8510           0 :             const bool bVertical = ((pGlyphs[i] & GF_ROTMASK) != 0);
    8511           0 :             pGlyphWidths[i] = m_aFontCache.getGlyphWidth( pCurrentFont,
    8512             :                                                           nFontGlyphId,
    8513             :                                                           bVertical,
    8514           0 :                                                           pGraphics );
    8515             :         }
    8516           0 :         else if( pCurrentFont->IsEmbeddable() )
    8517             :         {
    8518           0 :             sal_Int32 nFontID = 0;
    8519           0 :             FontEmbedData::iterator it = m_aEmbeddedFonts.find( pCurrentFont );
    8520           0 :             if( it != m_aEmbeddedFonts.end() )
    8521           0 :                 nFontID = it->second.m_nNormalFontID;
    8522             :             else
    8523             :             {
    8524           0 :                 nFontID = m_nNextFID++;
    8525           0 :                 m_aEmbeddedFonts[ pCurrentFont ] = EmbedFont();
    8526           0 :                 m_aEmbeddedFonts[ pCurrentFont ].m_nNormalFontID = nFontID;
    8527             :             }
    8528           0 :             EmbedFont& rEmbedFont = m_aEmbeddedFonts[pCurrentFont];
    8529             : 
    8530           0 :             const Ucs2SIntMap* pEncoding = NULL;
    8531           0 :             const Ucs2OStrMap* pNonEncoded = NULL;
    8532           0 :             if (!getReferenceDevice()->AcquireGraphics())
    8533           0 :                 return false;
    8534           0 :             pEncoding = pGraphics->GetFontEncodingVector( pCurrentFont, &pNonEncoded, 0);
    8535             : 
    8536           0 :             Ucs2SIntMap::const_iterator enc_it;
    8537           0 :             Ucs2OStrMap::const_iterator nonenc_it;
    8538             : 
    8539           0 :             sal_Int32 nCurFontID = nFontID;
    8540           0 :             sal_Ucs cChar = *pCurUnicode;
    8541           0 :             if( pEncoding )
    8542             :             {
    8543           0 :                 enc_it = pEncoding->find( cChar );
    8544           0 :                 if( enc_it != pEncoding->end() && enc_it->second > 0 )
    8545             :                 {
    8546             :                     DBG_ASSERT( (enc_it->second & 0xffffff00) == 0, "Invalid character code" );
    8547           0 :                     cChar = (sal_Ucs)enc_it->second;
    8548             :                 }
    8549           0 :                 else if( (enc_it == pEncoding->end() || enc_it->second == -1) &&
    8550           0 :                          pNonEncoded &&
    8551           0 :                          (nonenc_it = pNonEncoded->find( cChar )) != pNonEncoded->end() )
    8552             :                 {
    8553           0 :                     nCurFontID = 0;
    8554             :                     // find non encoded glyph
    8555           0 :                     for( std::list< EmbedEncoding >::iterator nec_it = rEmbedFont.m_aExtendedEncodings.begin(); nec_it != rEmbedFont.m_aExtendedEncodings.end(); ++nec_it )
    8556             :                     {
    8557           0 :                         if( nec_it->m_aCMap.find( cChar ) != nec_it->m_aCMap.end() )
    8558             :                         {
    8559           0 :                             nCurFontID = nec_it->m_nFontID;
    8560           0 :                             cChar = (sal_Ucs)nec_it->m_aCMap[ cChar ];
    8561           0 :                             break;
    8562             :                         }
    8563             :                     }
    8564           0 :                     if( nCurFontID == 0 ) // new nonencoded glyph
    8565             :                     {
    8566           0 :                         if( rEmbedFont.m_aExtendedEncodings.empty() || rEmbedFont.m_aExtendedEncodings.back().m_aEncVector.size() == 255 )
    8567             :                         {
    8568           0 :                             rEmbedFont.m_aExtendedEncodings.push_back( EmbedEncoding() );
    8569           0 :                             rEmbedFont.m_aExtendedEncodings.back().m_nFontID = m_nNextFID++;
    8570             :                         }
    8571           0 :                         EmbedEncoding& rEncoding = rEmbedFont.m_aExtendedEncodings.back();
    8572           0 :                         rEncoding.m_aEncVector.push_back( EmbedCode() );
    8573           0 :                         rEncoding.m_aEncVector.back().m_aUnicode = cChar;
    8574           0 :                         rEncoding.m_aEncVector.back().m_aName = nonenc_it->second;
    8575           0 :                         rEncoding.m_aCMap[ cChar ] = (sal_Int8)(rEncoding.m_aEncVector.size()-1);
    8576           0 :                         nCurFontID = rEncoding.m_nFontID;
    8577           0 :                         cChar = (sal_Ucs)rEncoding.m_aCMap[ cChar ];
    8578             :                     }
    8579             :                 }
    8580             :                 else
    8581           0 :                     pEncoding = NULL;
    8582             :             }
    8583           0 :             if( ! pEncoding )
    8584             :             {
    8585           0 :                 if( cChar & 0xff00 )
    8586             :                 {
    8587             :                     // some characters can be used by conversion
    8588           0 :                     if( cChar >= 0xf000 && cChar <= 0xf0ff ) // symbol encoding in private use area
    8589           0 :                         cChar -= 0xf000;
    8590             :                     else
    8591             :                     {
    8592           0 :                         OString aChar(&cChar, 1, RTL_TEXTENCODING_MS_1252);
    8593           0 :                         cChar = ((sal_Ucs)aChar[0]) & 0x00ff;
    8594             :                     }
    8595             :                 }
    8596             :             }
    8597             : 
    8598           0 :             pMappedGlyphs[ i ] = (sal_Int8)cChar;
    8599           0 :             pMappedFontObjects[ i ] = nCurFontID;
    8600           0 :             pGlyphWidths[ i ] = m_aFontCache.getGlyphWidth( pCurrentFont,
    8601             :                                                             (pEncoding ? *pCurUnicode : cChar) | GF_ISCHAR,
    8602             :                                                             false,
    8603           0 :                                                             pGraphics );
    8604             :         }
    8605             :     }
    8606           0 :     return true;
    8607             : }
    8608             : 
    8609           0 : void PDFWriterImpl::drawRelief( SalLayout& rLayout, const OUString& rText, bool bTextLines )
    8610             : {
    8611           0 :     push( PushFlags::ALL );
    8612             : 
    8613           0 :     FontRelief eRelief = m_aCurrentPDFState.m_aFont.GetRelief();
    8614             : 
    8615           0 :     Color aTextColor = m_aCurrentPDFState.m_aFont.GetColor();
    8616           0 :     Color aTextLineColor = m_aCurrentPDFState.m_aTextLineColor;
    8617           0 :     Color aOverlineColor = m_aCurrentPDFState.m_aOverlineColor;
    8618           0 :     Color aReliefColor( COL_LIGHTGRAY );
    8619           0 :     if( aTextColor == COL_BLACK )
    8620           0 :         aTextColor = Color( COL_WHITE );
    8621           0 :     if( aTextLineColor == COL_BLACK )
    8622           0 :         aTextLineColor = Color( COL_WHITE );
    8623           0 :     if( aOverlineColor == COL_BLACK )
    8624           0 :         aOverlineColor = Color( COL_WHITE );
    8625           0 :     if( aTextColor == COL_WHITE )
    8626           0 :         aReliefColor = Color( COL_BLACK );
    8627             : 
    8628           0 :     Font aSetFont = m_aCurrentPDFState.m_aFont;
    8629           0 :     aSetFont.SetRelief( RELIEF_NONE );
    8630           0 :     aSetFont.SetShadow( false );
    8631             : 
    8632           0 :     aSetFont.SetColor( aReliefColor );
    8633           0 :     setTextLineColor( aReliefColor );
    8634           0 :     setOverlineColor( aReliefColor );
    8635           0 :     setFont( aSetFont );
    8636           0 :     long nOff = 1 + getReferenceDevice()->mnDPIX/300;
    8637           0 :     if( eRelief == RELIEF_ENGRAVED )
    8638           0 :         nOff = -nOff;
    8639             : 
    8640           0 :     rLayout.DrawOffset() += Point( nOff, nOff );
    8641           0 :     updateGraphicsState();
    8642           0 :     drawLayout( rLayout, rText, bTextLines );
    8643             : 
    8644           0 :     rLayout.DrawOffset() -= Point( nOff, nOff );
    8645           0 :     setTextLineColor( aTextLineColor );
    8646           0 :     setOverlineColor( aOverlineColor );
    8647           0 :     aSetFont.SetColor( aTextColor );
    8648           0 :     setFont( aSetFont );
    8649           0 :     updateGraphicsState();
    8650           0 :     drawLayout( rLayout, rText, bTextLines );
    8651             : 
    8652             :     // clean up the mess
    8653           0 :     pop();
    8654           0 : }
    8655             : 
    8656           0 : void PDFWriterImpl::drawShadow( SalLayout& rLayout, const OUString& rText, bool bTextLines )
    8657             : {
    8658           0 :     Font aSaveFont = m_aCurrentPDFState.m_aFont;
    8659           0 :     Color aSaveTextLineColor = m_aCurrentPDFState.m_aTextLineColor;
    8660           0 :     Color aSaveOverlineColor = m_aCurrentPDFState.m_aOverlineColor;
    8661             : 
    8662           0 :     Font& rFont = m_aCurrentPDFState.m_aFont;
    8663           0 :     if( rFont.GetColor() == Color( COL_BLACK ) || rFont.GetColor().GetLuminance() < 8 )
    8664           0 :         rFont.SetColor( Color( COL_LIGHTGRAY ) );
    8665             :     else
    8666           0 :         rFont.SetColor( Color( COL_BLACK ) );
    8667           0 :     rFont.SetShadow( false );
    8668           0 :     rFont.SetOutline( false );
    8669           0 :     setFont( rFont );
    8670           0 :     setTextLineColor( rFont.GetColor() );
    8671           0 :     setOverlineColor( rFont.GetColor() );
    8672           0 :     updateGraphicsState();
    8673             : 
    8674           0 :     long nOff = 1 + ((m_pReferenceDevice->mpFontEntry->mnLineHeight-24)/24);
    8675           0 :     if( rFont.IsOutline() )
    8676           0 :         nOff++;
    8677           0 :     rLayout.DrawBase() += Point( nOff, nOff );
    8678           0 :     drawLayout( rLayout, rText, bTextLines );
    8679           0 :     rLayout.DrawBase() -= Point( nOff, nOff );
    8680             : 
    8681           0 :     setFont( aSaveFont );
    8682           0 :     setTextLineColor( aSaveTextLineColor );
    8683           0 :     setOverlineColor( aSaveOverlineColor );
    8684           0 :     updateGraphicsState();
    8685           0 : }
    8686             : 
    8687           0 : void PDFWriterImpl::drawVerticalGlyphs(
    8688             :         const std::vector<PDFWriterImpl::PDFGlyph>& rGlyphs,
    8689             :         OStringBuffer& rLine,
    8690             :         const Point& rAlignOffset,
    8691             :         const Matrix3& rRotScale,
    8692             :         double fAngle,
    8693             :         double fXScale,
    8694             :         double fSkew,
    8695             :         sal_Int32 nFontHeight )
    8696             : {
    8697           0 :     long nXOffset = 0;
    8698           0 :     Point aCurPos( rGlyphs[0].m_aPos );
    8699           0 :     aCurPos = m_pReferenceDevice->PixelToLogic( aCurPos );
    8700           0 :     aCurPos += rAlignOffset;
    8701           0 :     for( size_t i = 0; i < rGlyphs.size(); i++ )
    8702             :     {
    8703             :         // have to emit each glyph on its own
    8704           0 :         double fDeltaAngle = 0.0;
    8705           0 :         double fYScale = 1.0;
    8706           0 :         double fTempXScale = fXScale;
    8707           0 :         double fSkewB = fSkew;
    8708           0 :         double fSkewA = 0.0;
    8709             : 
    8710           0 :         Point aDeltaPos;
    8711           0 :         if( ( rGlyphs[i].m_nGlyphId & GF_ROTMASK ) == GF_ROTL )
    8712             :         {
    8713           0 :             fDeltaAngle = M_PI/2.0;
    8714           0 :             aDeltaPos.X() = m_pReferenceDevice->GetFontMetric().GetAscent();
    8715           0 :             aDeltaPos.Y() = (int)((double)m_pReferenceDevice->GetFontMetric().GetDescent() * fXScale);
    8716           0 :             fYScale = fXScale;
    8717           0 :             fTempXScale = 1.0;
    8718           0 :             fSkewA = -fSkewB;
    8719           0 :             fSkewB = 0.0;
    8720             :         }
    8721           0 :         else if( ( rGlyphs[i].m_nGlyphId & GF_ROTMASK ) == GF_ROTR )
    8722             :         {
    8723           0 :             fDeltaAngle = -M_PI/2.0;
    8724           0 :             aDeltaPos.X() = (int)((double)m_pReferenceDevice->GetFontMetric().GetDescent()*fXScale);
    8725           0 :             aDeltaPos.Y() = -m_pReferenceDevice->GetFontMetric().GetAscent();
    8726           0 :             fYScale = fXScale;
    8727           0 :             fTempXScale = 1.0;
    8728           0 :             fSkewA = fSkewB;
    8729           0 :             fSkewB = 0.0;
    8730             :         }
    8731           0 :         aDeltaPos += (m_pReferenceDevice->PixelToLogic( Point( (int)((double)nXOffset/fXScale), 0 ) ) - m_pReferenceDevice->PixelToLogic( Point() ) );
    8732           0 :         if( i < rGlyphs.size()-1 )
    8733             :         // #i120627# the text on the Y axis is reversed when export ppt file to PDF format
    8734             :         {
    8735           0 :             long nOffsetX = rGlyphs[i+1].m_aPos.X() - rGlyphs[i].m_aPos.X();
    8736           0 :             long nOffsetY = rGlyphs[i+1].m_aPos.Y() - rGlyphs[i].m_aPos.Y();
    8737           0 :             nXOffset += (int)sqrt(double(nOffsetX*nOffsetX + nOffsetY*nOffsetY));
    8738             :         }
    8739           0 :         if( ! rGlyphs[i].m_nGlyphId )
    8740           0 :             continue;
    8741             : 
    8742           0 :         aDeltaPos = rRotScale.transform( aDeltaPos );
    8743             : 
    8744           0 :         Matrix3 aMat;
    8745           0 :         if( fSkewB != 0.0 || fSkewA != 0.0 )
    8746           0 :             aMat.skew( fSkewA, fSkewB );
    8747           0 :         aMat.scale( fTempXScale, fYScale );
    8748           0 :         aMat.rotate( fAngle+fDeltaAngle );
    8749           0 :         aMat.translate( aCurPos.X()+aDeltaPos.X(), aCurPos.Y()+aDeltaPos.Y() );
    8750           0 :         aMat.append( m_aPages.back(), rLine );
    8751           0 :         rLine.append( " Tm" );
    8752           0 :         if( i == 0 || rGlyphs[i-1].m_nMappedFontId != rGlyphs[i].m_nMappedFontId )
    8753             :         {
    8754           0 :             rLine.append( " /F" );
    8755           0 :             rLine.append( rGlyphs[i].m_nMappedFontId );
    8756           0 :             rLine.append( ' ' );
    8757           0 :             m_aPages.back().appendMappedLength( nFontHeight, rLine, true );
    8758           0 :             rLine.append( " Tf" );
    8759             :         }
    8760           0 :         rLine.append( "<" );
    8761           0 :         appendHex( rGlyphs[i].m_nMappedGlyphId, rLine );
    8762           0 :         rLine.append( ">Tj\n" );
    8763           0 :     }
    8764           0 : }
    8765             : 
    8766           0 : void PDFWriterImpl::drawHorizontalGlyphs(
    8767             :         const std::vector<PDFWriterImpl::PDFGlyph>& rGlyphs,
    8768             :         OStringBuffer& rLine,
    8769             :         const Point& rAlignOffset,
    8770             :         double fAngle,
    8771             :         double fXScale,
    8772             :         double fSkew,
    8773             :         sal_Int32 nFontHeight,
    8774             :         sal_Int32 nPixelFontHeight
    8775             :         )
    8776             : {
    8777             :     // horizontal (= normal) case
    8778             : 
    8779             :     // fill in  run end indices
    8780             :     // end is marked by index of the first glyph of the next run
    8781             :     // a run is marked by same mapped font id and same Y position
    8782           0 :     std::vector< sal_uInt32 > aRunEnds;
    8783           0 :     aRunEnds.reserve( rGlyphs.size() );
    8784           0 :     for( size_t i = 1; i < rGlyphs.size(); i++ )
    8785             :     {
    8786           0 :         if( rGlyphs[i].m_nMappedFontId != rGlyphs[i-1].m_nMappedFontId ||
    8787           0 :             rGlyphs[i].m_aPos.Y() != rGlyphs[i-1].m_aPos.Y() )
    8788             :         {
    8789           0 :             aRunEnds.push_back(i);
    8790             :         }
    8791             :     }
    8792             :     // last run ends at last glyph
    8793           0 :     aRunEnds.push_back( rGlyphs.size() );
    8794             : 
    8795             :     // loop over runs of the same font
    8796           0 :     sal_uInt32 nBeginRun = 0;
    8797           0 :     for( size_t nRun = 0; nRun < aRunEnds.size(); nRun++ )
    8798             :     {
    8799             :         // setup text matrix
    8800           0 :         Point aCurPos = rGlyphs[nBeginRun].m_aPos;
    8801             :         // back transformation to current coordinate system
    8802           0 :         aCurPos = m_pReferenceDevice->PixelToLogic( aCurPos );
    8803           0 :         aCurPos += rAlignOffset;
    8804             :         // the first run can be set with "Td" operator
    8805             :         // subsequent use of that operator would move
    8806             :         // the texline matrix relative to what was set before
    8807             :         // making use of that would drive us into rounding issues
    8808           0 :         Matrix3 aMat;
    8809           0 :         if( nRun == 0 && fAngle == 0.0 && fXScale == 1.0 && fSkew == 0.0 )
    8810             :         {
    8811           0 :             m_aPages.back().appendPoint( aCurPos, rLine, false );
    8812           0 :             rLine.append( " Td " );
    8813             :         }
    8814             :         else
    8815             :         {
    8816           0 :             if( fSkew != 0.0 )
    8817           0 :                 aMat.skew( 0.0, fSkew );
    8818           0 :             aMat.scale( fXScale, 1.0 );
    8819           0 :             aMat.rotate( fAngle );
    8820           0 :             aMat.translate( aCurPos.X(), aCurPos.Y() );
    8821           0 :             aMat.append( m_aPages.back(), rLine );
    8822           0 :             rLine.append( " Tm\n" );
    8823             :         }
    8824             :         // set up correct font
    8825           0 :         rLine.append( "/F" );
    8826           0 :         rLine.append( rGlyphs[nBeginRun].m_nMappedFontId );
    8827           0 :         rLine.append( ' ' );
    8828           0 :         m_aPages.back().appendMappedLength( nFontHeight, rLine, true );
    8829           0 :         rLine.append( " Tf" );
    8830             : 
    8831             :         // output glyphs using Tj or TJ
    8832           0 :         OStringBuffer aKernedLine( 256 ), aUnkernedLine( 256 );
    8833           0 :         aKernedLine.append( "[<" );
    8834           0 :         aUnkernedLine.append( '<' );
    8835           0 :         appendHex( rGlyphs[nBeginRun].m_nMappedGlyphId, aKernedLine );
    8836           0 :         appendHex( rGlyphs[nBeginRun].m_nMappedGlyphId, aUnkernedLine );
    8837             : 
    8838           0 :         aMat.invert();
    8839           0 :         bool bNeedKern = false;
    8840           0 :         for( sal_uInt32 nPos = nBeginRun+1; nPos < aRunEnds[nRun]; nPos++ )
    8841             :         {
    8842           0 :             appendHex( rGlyphs[nPos].m_nMappedGlyphId, aUnkernedLine );
    8843             :             // check if default glyph positioning is sufficient
    8844           0 :             const Point aThisPos = aMat.transform( rGlyphs[nPos].m_aPos );
    8845           0 :             const Point aPrevPos = aMat.transform( rGlyphs[nPos-1].m_aPos );
    8846           0 :             double fAdvance = aThisPos.X() - aPrevPos.X();
    8847           0 :             fAdvance *= 1000.0 / nPixelFontHeight;
    8848           0 :             const sal_Int32 nAdjustment = (sal_Int32)(rGlyphs[nPos-1].m_nNativeWidth - fAdvance + 0.5);
    8849           0 :             if( nAdjustment != 0 )
    8850             :             {
    8851             :                 // apply individual glyph positioning
    8852           0 :                 bNeedKern = true;
    8853           0 :                 aKernedLine.append( ">" );
    8854           0 :                 aKernedLine.append( nAdjustment );
    8855           0 :                 aKernedLine.append( "<" );
    8856             :             }
    8857           0 :             appendHex( rGlyphs[nPos].m_nMappedGlyphId, aKernedLine );
    8858             :         }
    8859           0 :         aKernedLine.append( ">]TJ\n" );
    8860           0 :         aUnkernedLine.append( ">Tj\n" );
    8861             :         rLine.append(
    8862           0 :             (bNeedKern ? aKernedLine : aUnkernedLine).makeStringAndClear() );
    8863             : 
    8864             :         // set beginning of next run
    8865           0 :         nBeginRun = aRunEnds[nRun];
    8866           0 :     }
    8867           0 : }
    8868             : 
    8869           0 : void PDFWriterImpl::drawLayout( SalLayout& rLayout, const OUString& rText, bool bTextLines )
    8870             : {
    8871             :     // relief takes precedence over shadow (see outdev3.cxx)
    8872           0 :     if(  m_aCurrentPDFState.m_aFont.GetRelief() != RELIEF_NONE )
    8873             :     {
    8874           0 :         drawRelief( rLayout, rText, bTextLines );
    8875           0 :         return;
    8876             :     }
    8877           0 :     else if( m_aCurrentPDFState.m_aFont.IsShadow() )
    8878           0 :         drawShadow( rLayout, rText, bTextLines );
    8879             : 
    8880           0 :     OStringBuffer aLine( 512 );
    8881             : 
    8882           0 :     const int nMaxGlyphs = 256;
    8883             : 
    8884             :     sal_GlyphId pGlyphs[nMaxGlyphs];
    8885             :     sal_Int32 pGlyphWidths[nMaxGlyphs];
    8886             :     sal_uInt8 pMappedGlyphs[nMaxGlyphs];
    8887             :     sal_Int32 pMappedFontObjects[nMaxGlyphs];
    8888           0 :     std::vector<sal_Ucs> aUnicodes;
    8889           0 :     aUnicodes.reserve( nMaxGlyphs );
    8890             :     sal_Int32 pUnicodesPerGlyph[nMaxGlyphs];
    8891             :     int pCharPosAry[nMaxGlyphs];
    8892             :     DeviceCoordinate nAdvanceWidths[nMaxGlyphs];
    8893           0 :     const PhysicalFontFace* pFallbackFonts[nMaxGlyphs] = { NULL };
    8894           0 :     bool bVertical = m_aCurrentPDFState.m_aFont.IsVertical();
    8895             :     int nGlyphs;
    8896           0 :     int nIndex = 0;
    8897           0 :     int nMinCharPos = 0, nMaxCharPos = rText.getLength()-1;
    8898           0 :     double fXScale = 1.0;
    8899           0 :     double fSkew = 0.0;
    8900           0 :     sal_Int32 nPixelFontHeight = m_pReferenceDevice->mpFontEntry->maFontSelData.mnHeight;
    8901           0 :     TextAlign eAlign = m_aCurrentPDFState.m_aFont.GetAlign();
    8902             : 
    8903             :     // transform font height back to current units
    8904             :     // note: the layout calculates in outdevs device pixel !!
    8905           0 :     sal_Int32 nFontHeight = m_pReferenceDevice->ImplDevicePixelToLogicHeight( nPixelFontHeight );
    8906           0 :     if( m_aCurrentPDFState.m_aFont.GetWidth() )
    8907             :     {
    8908           0 :         Font aFont( m_aCurrentPDFState.m_aFont );
    8909           0 :         aFont.SetWidth( 0 );
    8910           0 :         FontMetric aMetric = m_pReferenceDevice->GetFontMetric( aFont );
    8911           0 :         if( aMetric.GetWidth() != m_aCurrentPDFState.m_aFont.GetWidth() )
    8912             :         {
    8913             :             fXScale =
    8914           0 :                 (double)m_aCurrentPDFState.m_aFont.GetWidth() /
    8915           0 :                 (double)aMetric.GetWidth();
    8916             :         }
    8917             :         // force state before GetFontMetric
    8918           0 :         m_pReferenceDevice->ImplNewFont();
    8919             :     }
    8920             : 
    8921             :     // perform artificial italics if necessary
    8922           0 :     if( ( m_aCurrentPDFState.m_aFont.GetItalic() == ITALIC_NORMAL ||
    8923           0 :           m_aCurrentPDFState.m_aFont.GetItalic() == ITALIC_OBLIQUE ) &&
    8924           0 :         !( m_pReferenceDevice->mpFontEntry->maFontSelData.mpFontData->GetSlant() == ITALIC_NORMAL ||
    8925           0 :            m_pReferenceDevice->mpFontEntry->maFontSelData.mpFontData->GetSlant() == ITALIC_OBLIQUE )
    8926             :         )
    8927             :     {
    8928           0 :         fSkew = M_PI/12.0;
    8929             :     }
    8930             : 
    8931             :     // if the mapmode is distorted we need to adjust for that also
    8932           0 :     if( m_aCurrentPDFState.m_aMapMode.GetScaleX() != m_aCurrentPDFState.m_aMapMode.GetScaleY() )
    8933             :     {
    8934           0 :         fXScale *= double(m_aCurrentPDFState.m_aMapMode.GetScaleX()) / double(m_aCurrentPDFState.m_aMapMode.GetScaleY());
    8935             :     }
    8936             : 
    8937           0 :     int nAngle = m_aCurrentPDFState.m_aFont.GetOrientation();
    8938             :     // normalize angles
    8939           0 :     while( nAngle < 0 )
    8940           0 :         nAngle += 3600;
    8941           0 :     nAngle = nAngle % 3600;
    8942           0 :     double fAngle = (double)nAngle * M_PI / 1800.0;
    8943             : 
    8944           0 :     Matrix3 aRotScale;
    8945           0 :     aRotScale.scale( fXScale, 1.0 );
    8946           0 :     if( fAngle != 0.0 )
    8947           0 :         aRotScale.rotate( -fAngle );
    8948             : 
    8949           0 :     bool bPop = false;
    8950           0 :     bool bABold = false;
    8951             :     // artificial bold necessary ?
    8952           0 :     if( m_pReferenceDevice->mpFontEntry->maFontSelData.mpFontData->GetWeight() <= WEIGHT_MEDIUM &&
    8953           0 :         m_pReferenceDevice->mpFontEntry->maFontSelData.GetWeight() > WEIGHT_MEDIUM )
    8954             :     {
    8955           0 :         if( ! bPop )
    8956           0 :             aLine.append( "q " );
    8957           0 :         bPop = true;
    8958           0 :         bABold = true;
    8959             :     }
    8960             :     // setup text colors (if necessary)
    8961           0 :     Color aStrokeColor( COL_TRANSPARENT );
    8962           0 :     Color aNonStrokeColor( COL_TRANSPARENT );
    8963             : 
    8964           0 :     if( m_aCurrentPDFState.m_aFont.IsOutline() )
    8965             :     {
    8966           0 :         aStrokeColor = m_aCurrentPDFState.m_aFont.GetColor();
    8967           0 :         aNonStrokeColor = Color( COL_WHITE );
    8968             :     }
    8969             :     else
    8970           0 :         aNonStrokeColor = m_aCurrentPDFState.m_aFont.GetColor();
    8971           0 :     if( bABold )
    8972           0 :         aStrokeColor = m_aCurrentPDFState.m_aFont.GetColor();
    8973             : 
    8974           0 :     if( aStrokeColor != Color( COL_TRANSPARENT ) && aStrokeColor != m_aCurrentPDFState.m_aLineColor )
    8975             :     {
    8976           0 :         if( ! bPop )
    8977           0 :             aLine.append( "q " );
    8978           0 :         bPop = true;
    8979           0 :         appendStrokingColor( aStrokeColor, aLine );
    8980           0 :         aLine.append( "\n" );
    8981             :     }
    8982           0 :     if( aNonStrokeColor != Color( COL_TRANSPARENT ) && aNonStrokeColor != m_aCurrentPDFState.m_aFillColor )
    8983             :     {
    8984           0 :         if( ! bPop )
    8985           0 :             aLine.append( "q " );
    8986           0 :         bPop = true;
    8987           0 :         appendNonStrokingColor( aNonStrokeColor, aLine );
    8988           0 :         aLine.append( "\n" );
    8989             :     }
    8990             : 
    8991             :     // begin text object
    8992           0 :     aLine.append( "BT\n" );
    8993             :     // outline attribute ?
    8994           0 :     if( m_aCurrentPDFState.m_aFont.IsOutline() || bABold )
    8995             :     {
    8996             :         // set correct text mode, set stroke width
    8997           0 :         aLine.append( "2 Tr " ); // fill, then stroke
    8998             : 
    8999           0 :         if( m_aCurrentPDFState.m_aFont.IsOutline() )
    9000             :         {
    9001             :             // unclear what to do in case of outline and artificial bold
    9002             :             // for the time being outline wins
    9003           0 :             aLine.append( "0.25 w \n" );
    9004             :         }
    9005             :         else
    9006             :         {
    9007           0 :             double fW = (double)m_aCurrentPDFState.m_aFont.GetHeight() / 30.0;
    9008           0 :             m_aPages.back().appendMappedLength( fW, aLine );
    9009           0 :             aLine.append ( " w\n" );
    9010             :         }
    9011             :     }
    9012             : 
    9013           0 :     FontMetric aRefDevFontMetric = m_pReferenceDevice->GetFontMetric();
    9014             : 
    9015             :     // collect the glyphs into a single array
    9016           0 :     const int nTmpMaxGlyphs = rLayout.GetOrientation() ? 1 : nMaxGlyphs; // #i97991# temporary workaround for #i87686#
    9017           0 :     std::vector< PDFGlyph > aGlyphs;
    9018           0 :     aGlyphs.reserve( nTmpMaxGlyphs );
    9019             :     // first get all the glyphs and register them; coordinates still in Pixel
    9020           0 :     Point aGNGlyphPos;
    9021           0 :     while( (nGlyphs = rLayout.GetNextGlyphs( nTmpMaxGlyphs, pGlyphs, aGNGlyphPos, nIndex, nAdvanceWidths, pCharPosAry, pFallbackFonts )) != 0 )
    9022             :     {
    9023           0 :         aUnicodes.clear();
    9024           0 :         for( int i = 0; i < nGlyphs; i++ )
    9025             :         {
    9026             :             // default case: 1 glyph is one unicode
    9027           0 :             pUnicodesPerGlyph[i] = 1;
    9028           0 :             if( (pGlyphs[i] & GF_ISCHAR) )
    9029             :             {
    9030           0 :                 aUnicodes.push_back( static_cast<sal_Ucs>(pGlyphs[i] & GF_IDXMASK) );
    9031             :             }
    9032           0 :             else if( pCharPosAry[i] >= nMinCharPos && pCharPosAry[i] <= nMaxCharPos )
    9033             :             {
    9034           0 :                 int nChars = 1;
    9035           0 :                 aUnicodes.push_back( rText[ pCharPosAry[i] ] );
    9036           0 :                 pUnicodesPerGlyph[i] = 1;
    9037             :                 // try to handle ligatures and such
    9038           0 :                 if( i < nGlyphs-1 )
    9039             :                 {
    9040           0 :                     nChars = pCharPosAry[i+1] - pCharPosAry[i];
    9041             :                     // #i115618# fix for simple RTL+CTL cases
    9042             :                     // TODO: sanitize for RTL ligatures, more complex CTL, etc.
    9043           0 :                     if( nChars < 0 )
    9044           0 :                         nChars = -nChars;
    9045           0 :                     else if( nChars == 0 )
    9046           0 :                         nChars = 1;
    9047           0 :                     pUnicodesPerGlyph[i] = nChars;
    9048           0 :                     for( int n = 1; n < nChars; n++ )
    9049           0 :                         aUnicodes.push_back( rText[ pCharPosAry[i] + n ] );
    9050             :                 }
    9051             :                 // #i36691# hack that is needed because currently the pGlyphs[]
    9052             :                 // argument is ignored for embeddable fonts and so the layout
    9053             :                 // engine's glyph work is ignored (i.e. char mirroring)
    9054             :                 // TODO: a real solution would be to map the layout engine's
    9055             :                 // glyphid (i.e. FreeType's synthetic glyphid for a Type1 font)
    9056             :                 // back to unicode and then to embeddable font's encoding
    9057           0 :                 if( (getReferenceDevice()->GetLayoutMode() & TEXT_LAYOUT_BIDI_RTL) != TEXT_LAYOUT_DEFAULT )
    9058             :                 {
    9059           0 :                     size_t nI = aUnicodes.size()-1;
    9060           0 :                     for( int n = 0; n < nChars; n++, nI-- )
    9061           0 :                         aUnicodes[nI] = static_cast<sal_Ucs>(GetMirroredChar(aUnicodes[nI]));
    9062           0 :                 }
    9063             :             }
    9064             :             else
    9065           0 :                 aUnicodes.push_back( 0 );
    9066             :             // note: in case of ctl one character may result
    9067             :             // in multiple glyphs. The current SalLayout
    9068             :             // implementations set -1 then to indicate that no direct
    9069             :             // mapping is possible
    9070             :         }
    9071             : 
    9072           0 :         registerGlyphs( nGlyphs, pGlyphs, pGlyphWidths, &aUnicodes[0], pUnicodesPerGlyph, pMappedGlyphs, pMappedFontObjects, pFallbackFonts );
    9073             : 
    9074           0 :         for( int i = 0; i < nGlyphs; i++ )
    9075             :         {
    9076             :             aGlyphs.push_back( PDFGlyph( aGNGlyphPos,
    9077             :                                          pGlyphWidths[i],
    9078           0 :                                          pGlyphs[i],
    9079             :                                          pMappedFontObjects[i],
    9080           0 :                                          pMappedGlyphs[i] ) );
    9081           0 :             if( bVertical )
    9082           0 :                 aGNGlyphPos.Y() += nAdvanceWidths[i]/rLayout.GetUnitsPerPixel();
    9083             :             else
    9084           0 :                 aGNGlyphPos.X() += nAdvanceWidths[i]/rLayout.GetUnitsPerPixel();
    9085             :         }
    9086             :     }
    9087             : 
    9088           0 :     Point aAlignOffset;
    9089           0 :     if ( eAlign == ALIGN_BOTTOM )
    9090           0 :         aAlignOffset.Y() -= aRefDevFontMetric.GetDescent();
    9091           0 :     else if ( eAlign == ALIGN_TOP )
    9092           0 :         aAlignOffset.Y() += aRefDevFontMetric.GetAscent();
    9093           0 :     if( aAlignOffset.X() || aAlignOffset.Y() )
    9094           0 :         aAlignOffset = aRotScale.transform( aAlignOffset );
    9095             : 
    9096             :     /* #159153# do not emit an empty glyph vector; this can happen if e.g. the original
    9097             :        string contained only on of the UTF16 BOMs
    9098             :     */
    9099           0 :     if( ! aGlyphs.empty() )
    9100             :     {
    9101           0 :         if( bVertical )
    9102           0 :             drawVerticalGlyphs( aGlyphs, aLine, aAlignOffset, aRotScale, fAngle, fXScale, fSkew, nFontHeight );
    9103             :         else
    9104           0 :             drawHorizontalGlyphs( aGlyphs, aLine, aAlignOffset, fAngle, fXScale, fSkew, nFontHeight, nPixelFontHeight );
    9105             :     }
    9106             : 
    9107             :     // end textobject
    9108           0 :     aLine.append( "ET\n" );
    9109           0 :     if( bPop )
    9110           0 :         aLine.append( "Q\n" );
    9111             : 
    9112           0 :     writeBuffer( aLine.getStr(), aLine.getLength() );
    9113             : 
    9114             :     // draw eventual textlines
    9115           0 :     FontStrikeout eStrikeout = m_aCurrentPDFState.m_aFont.GetStrikeout();
    9116           0 :     FontUnderline eUnderline = m_aCurrentPDFState.m_aFont.GetUnderline();
    9117           0 :     FontUnderline eOverline  = m_aCurrentPDFState.m_aFont.GetOverline();
    9118           0 :     if( bTextLines &&
    9119             :         (
    9120           0 :          ( eUnderline != UNDERLINE_NONE && eUnderline != UNDERLINE_DONTKNOW ) ||
    9121           0 :          ( eOverline  != UNDERLINE_NONE && eOverline  != UNDERLINE_DONTKNOW ) ||
    9122           0 :          ( eStrikeout != STRIKEOUT_NONE && eStrikeout != STRIKEOUT_DONTKNOW )
    9123             :          )
    9124             :         )
    9125             :     {
    9126           0 :         bool bUnderlineAbove = OutputDevice::ImplIsUnderlineAbove( m_aCurrentPDFState.m_aFont );
    9127           0 :         if( m_aCurrentPDFState.m_aFont.IsWordLineMode() )
    9128             :         {
    9129           0 :             Point aPos, aStartPt;
    9130           0 :             sal_Int32 nWidth = 0;
    9131           0 :             DeviceCoordinate nAdvance = 0;
    9132           0 :             for( int nStart = 0;;)
    9133             :             {
    9134             :                 sal_GlyphId aGlyphId;
    9135           0 :                 if( !rLayout.GetNextGlyphs( 1, &aGlyphId, aPos, nStart, &nAdvance ) )
    9136           0 :                     break;
    9137             : 
    9138           0 :                 if( !SalLayout::IsSpacingGlyph( aGlyphId ) )
    9139             :                 {
    9140           0 :                     if( !nWidth )
    9141           0 :                         aStartPt = aPos;
    9142             : 
    9143           0 :                     nWidth += nAdvance;
    9144             :                 }
    9145           0 :                 else if( nWidth > 0 )
    9146             :                 {
    9147           0 :                     drawTextLine( m_pReferenceDevice->PixelToLogic( aStartPt ),
    9148             :                                   m_pReferenceDevice->ImplDevicePixelToLogicWidth( nWidth ),
    9149           0 :                                   eStrikeout, eUnderline, eOverline, bUnderlineAbove );
    9150           0 :                     nWidth = 0;
    9151             :                 }
    9152           0 :             }
    9153             : 
    9154           0 :             if( nWidth > 0 )
    9155             :             {
    9156           0 :                 drawTextLine( m_pReferenceDevice->PixelToLogic( aStartPt ),
    9157             :                               m_pReferenceDevice->ImplDevicePixelToLogicWidth( nWidth ),
    9158           0 :                               eStrikeout, eUnderline, eOverline, bUnderlineAbove );
    9159             :             }
    9160             :         }
    9161             :         else
    9162             :         {
    9163           0 :             Point aStartPt = rLayout.GetDrawPosition();
    9164           0 :             int nWidth = rLayout.GetTextWidth() / rLayout.GetUnitsPerPixel();
    9165           0 :             drawTextLine( m_pReferenceDevice->PixelToLogic( aStartPt ),
    9166             :                           m_pReferenceDevice->ImplDevicePixelToLogicWidth( nWidth ),
    9167           0 :                           eStrikeout, eUnderline, eOverline, bUnderlineAbove );
    9168             :         }
    9169             :     }
    9170             : 
    9171             :     // write eventual emphasis marks
    9172           0 :     if( m_aCurrentPDFState.m_aFont.GetEmphasisMark() & EMPHASISMARK_STYLE )
    9173             :     {
    9174           0 :         tools::PolyPolygon             aEmphPoly;
    9175           0 :         Rectangle               aEmphRect1;
    9176           0 :         Rectangle               aEmphRect2;
    9177             :         long                    nEmphYOff;
    9178             :         long                    nEmphWidth;
    9179             :         long                    nEmphHeight;
    9180             :         bool                    bEmphPolyLine;
    9181             :         FontEmphasisMark        nEmphMark;
    9182             : 
    9183           0 :         push( PushFlags::ALL );
    9184             : 
    9185           0 :         aLine.setLength( 0 );
    9186           0 :         aLine.append( "q\n" );
    9187             : 
    9188           0 :         nEmphMark = OutputDevice::ImplGetEmphasisMarkStyle( m_aCurrentPDFState.m_aFont );
    9189           0 :         if ( nEmphMark & EMPHASISMARK_POS_BELOW )
    9190           0 :             nEmphHeight = m_pReferenceDevice->mnEmphasisDescent;
    9191             :         else
    9192           0 :             nEmphHeight = m_pReferenceDevice->mnEmphasisAscent;
    9193             :         m_pReferenceDevice->ImplGetEmphasisMark( aEmphPoly,
    9194             :                                                  bEmphPolyLine,
    9195             :                                                  aEmphRect1,
    9196             :                                                  aEmphRect2,
    9197             :                                                  nEmphYOff,
    9198             :                                                  nEmphWidth,
    9199             :                                                  nEmphMark,
    9200             :                                                  m_pReferenceDevice->ImplDevicePixelToLogicWidth(nEmphHeight),
    9201           0 :                                                  m_pReferenceDevice->mpFontEntry->mnOrientation );
    9202           0 :         if ( bEmphPolyLine )
    9203             :         {
    9204           0 :             setLineColor( m_aCurrentPDFState.m_aFont.GetColor() );
    9205           0 :             setFillColor( Color( COL_TRANSPARENT ) );
    9206             :         }
    9207             :         else
    9208             :         {
    9209           0 :             setFillColor( m_aCurrentPDFState.m_aFont.GetColor() );
    9210           0 :             setLineColor( Color( COL_TRANSPARENT ) );
    9211             :         }
    9212           0 :         writeBuffer( aLine.getStr(), aLine.getLength() );
    9213             : 
    9214           0 :         Point aOffset = Point(0,0);
    9215             : 
    9216           0 :         if ( nEmphMark & EMPHASISMARK_POS_BELOW )
    9217           0 :             aOffset.Y() += m_pReferenceDevice->mpFontEntry->maMetric.mnDescent + nEmphYOff;
    9218             :         else
    9219           0 :             aOffset.Y() -= m_pReferenceDevice->mpFontEntry->maMetric.mnAscent + nEmphYOff;
    9220             : 
    9221           0 :         long nEmphWidth2     = nEmphWidth / 2;
    9222           0 :         long nEmphHeight2    = nEmphHeight / 2;
    9223           0 :         aOffset += Point( nEmphWidth2, nEmphHeight2 );
    9224             : 
    9225           0 :         if ( eAlign == ALIGN_BOTTOM )
    9226           0 :             aOffset.Y() -= m_pReferenceDevice->mpFontEntry->maMetric.mnDescent;
    9227           0 :         else if ( eAlign == ALIGN_TOP )
    9228           0 :             aOffset.Y() += m_pReferenceDevice->mpFontEntry->maMetric.mnAscent;
    9229             : 
    9230           0 :         for( int nStart = 0;;)
    9231             :         {
    9232           0 :             Point aPos;
    9233             :             sal_GlyphId aGlyphId;
    9234             :             DeviceCoordinate nAdvance;
    9235           0 :             if( !rLayout.GetNextGlyphs( 1, &aGlyphId, aPos, nStart, &nAdvance ) )
    9236           0 :                 break;
    9237             : 
    9238           0 :             if( !SalLayout::IsSpacingGlyph( aGlyphId ) )
    9239             :             {
    9240           0 :                 Point aAdjOffset = aOffset;
    9241           0 :                 aAdjOffset.X() += (nAdvance - nEmphWidth) / 2;
    9242           0 :                 aAdjOffset = aRotScale.transform( aAdjOffset );
    9243             : 
    9244           0 :                 aAdjOffset -= Point( nEmphWidth2, nEmphHeight2 );
    9245             : 
    9246           0 :                 aPos += aAdjOffset;
    9247           0 :                 aPos = m_pReferenceDevice->PixelToLogic( aPos );
    9248           0 :                 drawEmphasisMark( aPos.X(), aPos.Y(),
    9249             :                                   aEmphPoly, bEmphPolyLine,
    9250           0 :                                   aEmphRect1, aEmphRect2 );
    9251             :             }
    9252           0 :         }
    9253             : 
    9254           0 :         writeBuffer( "Q\n", 2 );
    9255           0 :         pop();
    9256           0 :     }
    9257             : }
    9258             : 
    9259           0 : void PDFWriterImpl::drawEmphasisMark( long nX, long nY,
    9260             :                                       const tools::PolyPolygon& rPolyPoly, bool bPolyLine,
    9261             :                                       const Rectangle& rRect1, const Rectangle& rRect2 )
    9262             : {
    9263             :     // TODO: pass nWidth as width of this mark
    9264             :     // long nWidth = 0;
    9265             : 
    9266           0 :     if ( rPolyPoly.Count() )
    9267             :     {
    9268           0 :         if ( bPolyLine )
    9269             :         {
    9270           0 :             Polygon aPoly = rPolyPoly.GetObject( 0 );
    9271           0 :             aPoly.Move( nX, nY );
    9272           0 :             drawPolyLine( aPoly );
    9273             :         }
    9274             :         else
    9275             :         {
    9276           0 :             tools::PolyPolygon aPolyPoly = rPolyPoly;
    9277           0 :             aPolyPoly.Move( nX, nY );
    9278           0 :             drawPolyPolygon( aPolyPoly );
    9279             :         }
    9280             :     }
    9281             : 
    9282           0 :     if ( !rRect1.IsEmpty() )
    9283             :     {
    9284           0 :         Rectangle aRect( Point( nX+rRect1.Left(),
    9285           0 :                                 nY+rRect1.Top() ), rRect1.GetSize() );
    9286           0 :         drawRectangle( aRect );
    9287             :     }
    9288             : 
    9289           0 :     if ( !rRect2.IsEmpty() )
    9290             :     {
    9291           0 :         Rectangle aRect( Point( nX+rRect2.Left(),
    9292           0 :                                 nY+rRect2.Top() ), rRect2.GetSize() );
    9293             : 
    9294           0 :         drawRectangle( aRect );
    9295             :     }
    9296           0 : }
    9297             : 
    9298           0 : void PDFWriterImpl::drawText( const Point& rPos, const OUString& rText, sal_Int32 nIndex, sal_Int32 nLen, bool bTextLines )
    9299             : {
    9300           0 :     MARK( "drawText" );
    9301             : 
    9302           0 :     updateGraphicsState();
    9303             : 
    9304             :     // get a layout from the OuputDevice's SalGraphics
    9305             :     // this also enforces font substitution and sets the font on SalGraphics
    9306           0 :     SalLayout* pLayout = m_pReferenceDevice->ImplLayout( rText, nIndex, nLen, rPos );
    9307           0 :     if( pLayout )
    9308             :     {
    9309           0 :         drawLayout( *pLayout, rText, bTextLines );
    9310           0 :         pLayout->Release();
    9311             :     }
    9312           0 : }
    9313             : 
    9314           0 : void PDFWriterImpl::drawTextArray( const Point& rPos, const OUString& rText, const long* pDXArray, sal_Int32 nIndex, sal_Int32 nLen, bool bTextLines )
    9315             : {
    9316           0 :     MARK( "drawText with array" );
    9317             : 
    9318           0 :     updateGraphicsState();
    9319             : 
    9320             :     // get a layout from the OuputDevice's SalGraphics
    9321             :     // this also enforces font substitution and sets the font on SalGraphics
    9322           0 :     SalLayout* pLayout = m_pReferenceDevice->ImplLayout( rText, nIndex, nLen, rPos, 0, pDXArray );
    9323           0 :     if( pLayout )
    9324             :     {
    9325           0 :         drawLayout( *pLayout, rText, bTextLines );
    9326           0 :         pLayout->Release();
    9327             :     }
    9328           0 : }
    9329             : 
    9330           0 : void PDFWriterImpl::drawStretchText( const Point& rPos, sal_uLong nWidth, const OUString& rText, sal_Int32 nIndex, sal_Int32 nLen, bool bTextLines )
    9331             : {
    9332           0 :     MARK( "drawStretchText" );
    9333             : 
    9334           0 :     updateGraphicsState();
    9335             : 
    9336             :     // get a layout from the OuputDevice's SalGraphics
    9337             :     // this also enforces font substitution and sets the font on SalGraphics
    9338           0 :     SalLayout* pLayout = m_pReferenceDevice->ImplLayout( rText, nIndex, nLen, rPos, nWidth );
    9339           0 :     if( pLayout )
    9340             :     {
    9341           0 :         drawLayout( *pLayout, rText, bTextLines );
    9342           0 :         pLayout->Release();
    9343             :     }
    9344           0 : }
    9345             : 
    9346           0 : void PDFWriterImpl::drawText( const Rectangle& rRect, const OUString& rOrigStr, DrawTextFlags nStyle, bool bTextLines )
    9347             : {
    9348           0 :     long        nWidth          = rRect.GetWidth();
    9349           0 :     long        nHeight         = rRect.GetHeight();
    9350             : 
    9351           0 :     if ( nWidth <= 0 || nHeight <= 0 )
    9352           0 :         return;
    9353             : 
    9354           0 :     MARK( "drawText with rectangle" );
    9355             : 
    9356           0 :     updateGraphicsState();
    9357             : 
    9358             :     // clip with rectangle
    9359           0 :     OStringBuffer aLine;
    9360           0 :     aLine.append( "q " );
    9361           0 :     m_aPages.back().appendRect( rRect, aLine );
    9362           0 :     aLine.append( " W* n\n" );
    9363           0 :     writeBuffer( aLine.getStr(), aLine.getLength() );
    9364             : 
    9365             :     // if disabled text is needed, put in here
    9366             : 
    9367           0 :     Point       aPos            = rRect.TopLeft();
    9368             : 
    9369           0 :     long        nTextHeight     = m_pReferenceDevice->GetTextHeight();
    9370           0 :     sal_Int32   nMnemonicPos    = -1;
    9371             : 
    9372           0 :     OUString aStr = rOrigStr;
    9373           0 :     if ( nStyle & DrawTextFlags::Mnemonic )
    9374           0 :         aStr = OutputDevice::GetNonMnemonicString( aStr, nMnemonicPos );
    9375             : 
    9376             :     // multiline text
    9377           0 :     if ( nStyle & DrawTextFlags::MultiLine )
    9378             :     {
    9379           0 :         OUString           aLastLine;
    9380           0 :         ImplMultiTextLineInfo   aMultiLineInfo;
    9381             :         ImplTextLineInfo*       pLineInfo;
    9382             :         sal_Int32               i;
    9383             :         sal_Int32               nLines;
    9384             :         sal_Int32               nFormatLines;
    9385             : 
    9386           0 :         if ( nTextHeight )
    9387             :         {
    9388           0 :             vcl::DefaultTextLayout aLayout( *m_pReferenceDevice );
    9389           0 :             OutputDevice::ImplGetTextLines( aMultiLineInfo, nWidth, aStr, nStyle, aLayout );
    9390           0 :             nLines = nHeight/nTextHeight;
    9391           0 :             nFormatLines = aMultiLineInfo.Count();
    9392           0 :             if ( !nLines )
    9393           0 :                 nLines = 1;
    9394           0 :             if ( nFormatLines > nLines )
    9395             :             {
    9396           0 :                 if ( nStyle & DrawTextFlags::EndEllipsis )
    9397             :                 {
    9398             :                     // handle last line
    9399           0 :                     nFormatLines = nLines-1;
    9400             : 
    9401           0 :                     pLineInfo = aMultiLineInfo.GetLine( nFormatLines );
    9402           0 :                     aLastLine = convertLineEnd(aStr.copy(pLineInfo->GetIndex()), LINEEND_LF);
    9403             :                     // replace line feed by space
    9404           0 :                     aLastLine = aLastLine.replace('\n', ' ');
    9405           0 :                     aLastLine = m_pReferenceDevice->GetEllipsisString( aLastLine, nWidth, nStyle );
    9406           0 :                     nStyle &= ~DrawTextFlags(DrawTextFlags::VCenter | DrawTextFlags::Bottom);
    9407           0 :                     nStyle |= DrawTextFlags::Top;
    9408             :                 }
    9409             :             }
    9410             : 
    9411             :             // vertical alignment
    9412           0 :             if ( nStyle & DrawTextFlags::Bottom )
    9413           0 :                 aPos.Y() += nHeight-(nFormatLines*nTextHeight);
    9414           0 :             else if ( nStyle & DrawTextFlags::VCenter )
    9415           0 :                 aPos.Y() += (nHeight-(nFormatLines*nTextHeight))/2;
    9416             : 
    9417             :             // draw all lines excluding the last
    9418           0 :             for ( i = 0; i < nFormatLines; i++ )
    9419             :             {
    9420           0 :                 pLineInfo = aMultiLineInfo.GetLine( i );
    9421           0 :                 if ( nStyle & DrawTextFlags::Right )
    9422           0 :                     aPos.X() += nWidth-pLineInfo->GetWidth();
    9423           0 :                 else if ( nStyle & DrawTextFlags::Center )
    9424           0 :                     aPos.X() += (nWidth-pLineInfo->GetWidth())/2;
    9425           0 :                 sal_Int32 nIndex = pLineInfo->GetIndex();
    9426           0 :                 sal_Int32 nLineLen = pLineInfo->GetLen();
    9427           0 :                 drawText( aPos, aStr, nIndex, nLineLen, bTextLines );
    9428             :                 // mnemonics should not appear in documents,
    9429             :                 // if the need arises, put them in here
    9430           0 :                 aPos.Y() += nTextHeight;
    9431           0 :                 aPos.X() = rRect.Left();
    9432             :             }
    9433             : 
    9434             :             // output last line left adjusted since it was shortened
    9435           0 :             if (!aLastLine.isEmpty())
    9436           0 :                 drawText( aPos, aLastLine, 0, aLastLine.getLength(), bTextLines );
    9437           0 :         }
    9438             :     }
    9439             :     else
    9440             :     {
    9441           0 :         long nTextWidth = m_pReferenceDevice->GetTextWidth( aStr );
    9442             : 
    9443             :         // Evt. Text kuerzen
    9444           0 :         if ( nTextWidth > nWidth )
    9445             :         {
    9446           0 :             if ( nStyle & (DrawTextFlags::EndEllipsis | DrawTextFlags::PathEllipsis | DrawTextFlags::NewsEllipsis) )
    9447             :             {
    9448           0 :                 aStr = m_pReferenceDevice->GetEllipsisString( aStr, nWidth, nStyle );
    9449           0 :                 nStyle &= ~DrawTextFlags(DrawTextFlags::Center | DrawTextFlags::Right);
    9450           0 :                 nStyle |= DrawTextFlags::Left;
    9451           0 :                 nTextWidth = m_pReferenceDevice->GetTextWidth( aStr );
    9452             :             }
    9453             :         }
    9454             : 
    9455             :         // vertical alignment
    9456           0 :         if ( nStyle & DrawTextFlags::Right )
    9457           0 :             aPos.X() += nWidth-nTextWidth;
    9458           0 :         else if ( nStyle & DrawTextFlags::Center )
    9459           0 :             aPos.X() += (nWidth-nTextWidth)/2;
    9460             : 
    9461           0 :         if ( nStyle & DrawTextFlags::Bottom )
    9462           0 :             aPos.Y() += nHeight-nTextHeight;
    9463           0 :         else if ( nStyle & DrawTextFlags::VCenter )
    9464           0 :             aPos.Y() += (nHeight-nTextHeight)/2;
    9465             : 
    9466             :         // mnemonics should be inserted here if the need arises
    9467             : 
    9468             :         // draw the actual text
    9469           0 :         drawText( aPos, aStr, 0, aStr.getLength(), bTextLines );
    9470             :     }
    9471             : 
    9472             :     // reset clip region to original value
    9473           0 :     aLine.setLength( 0 );
    9474           0 :     aLine.append( "Q\n" );
    9475           0 :     writeBuffer( aLine.getStr(), aLine.getLength() );
    9476             : }
    9477             : 
    9478           0 : void PDFWriterImpl::drawLine( const Point& rStart, const Point& rStop )
    9479             : {
    9480           0 :     MARK( "drawLine" );
    9481             : 
    9482           0 :     updateGraphicsState();
    9483             : 
    9484           0 :     if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) )
    9485           0 :         return;
    9486             : 
    9487           0 :     OStringBuffer aLine;
    9488           0 :     m_aPages.back().appendPoint( rStart, aLine );
    9489           0 :     aLine.append( " m " );
    9490           0 :     m_aPages.back().appendPoint( rStop, aLine );
    9491           0 :     aLine.append( " l S\n" );
    9492             : 
    9493           0 :     writeBuffer( aLine.getStr(), aLine.getLength() );
    9494             : }
    9495             : 
    9496           0 : void PDFWriterImpl::drawLine( const Point& rStart, const Point& rStop, const LineInfo& rInfo )
    9497             : {
    9498           0 :     MARK( "drawLine with LineInfo" );
    9499           0 :     updateGraphicsState();
    9500             : 
    9501           0 :     if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) )
    9502           0 :         return;
    9503             : 
    9504           0 :     if( rInfo.GetStyle() == LINE_SOLID && rInfo.GetWidth() < 2 )
    9505             :     {
    9506           0 :         drawLine( rStart, rStop );
    9507           0 :         return;
    9508             :     }
    9509             : 
    9510           0 :     OStringBuffer aLine;
    9511             : 
    9512           0 :     aLine.append( "q " );
    9513           0 :     if( m_aPages.back().appendLineInfo( rInfo, aLine ) )
    9514             :     {
    9515           0 :         m_aPages.back().appendPoint( rStart, aLine );
    9516           0 :         aLine.append( " m " );
    9517           0 :         m_aPages.back().appendPoint( rStop, aLine );
    9518           0 :         aLine.append( " l S Q\n" );
    9519             : 
    9520           0 :         writeBuffer( aLine.getStr(), aLine.getLength() );
    9521             :     }
    9522             :     else
    9523             :     {
    9524           0 :         PDFWriter::ExtLineInfo aInfo;
    9525           0 :         convertLineInfoToExtLineInfo( rInfo, aInfo );
    9526           0 :         Point aPolyPoints[2] = { rStart, rStop };
    9527           0 :         Polygon aPoly( 2, aPolyPoints );
    9528           0 :         drawPolyLine( aPoly, aInfo );
    9529           0 :     }
    9530             : }
    9531             : 
    9532             : #define HCONV( x ) m_pReferenceDevice->ImplDevicePixelToLogicHeight( x )
    9533             : 
    9534           0 : void PDFWriterImpl::drawWaveTextLine( OStringBuffer& aLine, long nWidth, FontUnderline eTextLine, Color aColor, bool bIsAbove )
    9535             : {
    9536             :     // note: units in pFontEntry are ref device pixel
    9537           0 :     ImplFontEntry*  pFontEntry = m_pReferenceDevice->mpFontEntry;
    9538           0 :     long            nLineHeight = 0;
    9539           0 :     long            nLinePos = 0;
    9540             : 
    9541           0 :     appendStrokingColor( aColor, aLine );
    9542           0 :     aLine.append( "\n" );
    9543             : 
    9544           0 :     if ( bIsAbove )
    9545             :     {
    9546           0 :         if ( !pFontEntry->maMetric.mnAboveWUnderlineSize )
    9547           0 :             m_pReferenceDevice->ImplInitAboveTextLineSize();
    9548           0 :         nLineHeight = HCONV( pFontEntry->maMetric.mnAboveWUnderlineSize );
    9549           0 :         nLinePos = HCONV( pFontEntry->maMetric.mnAboveWUnderlineOffset );
    9550             :     }
    9551             :     else
    9552             :     {
    9553           0 :         if ( !pFontEntry->maMetric.mnWUnderlineSize )
    9554           0 :             m_pReferenceDevice->ImplInitTextLineSize();
    9555           0 :         nLineHeight = HCONV( pFontEntry->maMetric.mnWUnderlineSize );
    9556           0 :         nLinePos = HCONV( pFontEntry->maMetric.mnWUnderlineOffset );
    9557             :     }
    9558           0 :     if ( (eTextLine == UNDERLINE_SMALLWAVE) && (nLineHeight > 3) )
    9559           0 :         nLineHeight = 3;
    9560             : 
    9561           0 :     long nLineWidth = getReferenceDevice()->mnDPIX/450;
    9562           0 :     if ( ! nLineWidth )
    9563           0 :         nLineWidth = 1;
    9564             : 
    9565           0 :     if ( eTextLine == UNDERLINE_BOLDWAVE )
    9566           0 :         nLineWidth = 3*nLineWidth;
    9567             : 
    9568           0 :     m_aPages.back().appendMappedLength( (sal_Int32)nLineWidth, aLine );
    9569           0 :     aLine.append( " w " );
    9570             : 
    9571           0 :     if ( eTextLine == UNDERLINE_DOUBLEWAVE )
    9572             :     {
    9573           0 :         long nOrgLineHeight = nLineHeight;
    9574           0 :         nLineHeight /= 3;
    9575           0 :         if ( nLineHeight < 2 )
    9576             :         {
    9577           0 :             if ( nOrgLineHeight > 1 )
    9578           0 :                 nLineHeight = 2;
    9579             :             else
    9580           0 :                 nLineHeight = 1;
    9581             :         }
    9582           0 :         long nLineDY = nOrgLineHeight-(nLineHeight*2);
    9583           0 :         if ( nLineDY < nLineWidth )
    9584           0 :             nLineDY = nLineWidth;
    9585           0 :         long nLineDY2 = nLineDY/2;
    9586           0 :         if ( !nLineDY2 )
    9587           0 :             nLineDY2 = 1;
    9588             : 
    9589           0 :         nLinePos -= nLineWidth-nLineDY2;
    9590             : 
    9591           0 :         m_aPages.back().appendWaveLine( nWidth, -nLinePos, 2*nLineHeight, aLine );
    9592             : 
    9593           0 :         nLinePos += nLineWidth+nLineDY;
    9594           0 :         m_aPages.back().appendWaveLine( nWidth, -nLinePos, 2*nLineHeight, aLine );
    9595             :     }
    9596             :     else
    9597             :     {
    9598           0 :         if ( eTextLine != UNDERLINE_BOLDWAVE )
    9599           0 :             nLinePos -= nLineWidth/2;
    9600           0 :         m_aPages.back().appendWaveLine( nWidth, -nLinePos, nLineHeight, aLine );
    9601             :     }
    9602           0 : }
    9603             : 
    9604           0 : void PDFWriterImpl::drawStraightTextLine( OStringBuffer& aLine, long nWidth, FontUnderline eTextLine, Color aColor, bool bIsAbove )
    9605             : {
    9606             :     // note: units in pFontEntry are ref device pixel
    9607           0 :     ImplFontEntry*  pFontEntry = m_pReferenceDevice->mpFontEntry;
    9608           0 :     long            nLineHeight = 0;
    9609           0 :     long            nLinePos  = 0;
    9610           0 :     long            nLinePos2 = 0;
    9611             : 
    9612           0 :     if ( eTextLine > UNDERLINE_BOLDWAVE )
    9613           0 :         eTextLine = UNDERLINE_SINGLE;
    9614             : 
    9615           0 :     switch ( eTextLine )
    9616             :     {
    9617             :         case UNDERLINE_SINGLE:
    9618             :         case UNDERLINE_DOTTED:
    9619             :         case UNDERLINE_DASH:
    9620             :         case UNDERLINE_LONGDASH:
    9621             :         case UNDERLINE_DASHDOT:
    9622             :         case UNDERLINE_DASHDOTDOT:
    9623           0 :             if ( bIsAbove )
    9624             :             {
    9625           0 :                 if ( !pFontEntry->maMetric.mnAboveUnderlineSize )
    9626           0 :                     m_pReferenceDevice->ImplInitAboveTextLineSize();
    9627           0 :                 nLineHeight = HCONV( pFontEntry->maMetric.mnAboveUnderlineSize );
    9628           0 :                 nLinePos    = HCONV( pFontEntry->maMetric.mnAboveUnderlineOffset );
    9629             :             }
    9630             :             else
    9631             :             {
    9632           0 :                 if ( !pFontEntry->maMetric.mnUnderlineSize )
    9633           0 :                     m_pReferenceDevice->ImplInitTextLineSize();
    9634           0 :                 nLineHeight = HCONV( pFontEntry->maMetric.mnUnderlineSize );
    9635           0 :                 nLinePos    = HCONV( pFontEntry->maMetric.mnUnderlineOffset );
    9636             :             }
    9637           0 :             break;
    9638             :         case UNDERLINE_BOLD:
    9639             :         case UNDERLINE_BOLDDOTTED:
    9640             :         case UNDERLINE_BOLDDASH:
    9641             :         case UNDERLINE_BOLDLONGDASH:
    9642             :         case UNDERLINE_BOLDDASHDOT:
    9643             :         case UNDERLINE_BOLDDASHDOTDOT:
    9644           0 :             if ( bIsAbove )
    9645             :             {
    9646           0 :                 if ( !pFontEntry->maMetric.mnAboveBUnderlineSize )
    9647           0 :                     m_pReferenceDevice->ImplInitAboveTextLineSize();
    9648           0 :                 nLineHeight = HCONV( pFontEntry->maMetric.mnAboveBUnderlineSize );
    9649           0 :                 nLinePos    = HCONV( pFontEntry->maMetric.mnAboveBUnderlineOffset );
    9650             :             }
    9651             :             else
    9652             :             {
    9653           0 :                 if ( !pFontEntry->maMetric.mnBUnderlineSize )
    9654           0 :                     m_pReferenceDevice->ImplInitTextLineSize();
    9655           0 :                 nLineHeight = HCONV( pFontEntry->maMetric.mnBUnderlineSize );
    9656           0 :                 nLinePos    = HCONV( pFontEntry->maMetric.mnBUnderlineOffset );
    9657           0 :                 nLinePos += nLineHeight/2;
    9658             :             }
    9659           0 :             break;
    9660             :         case UNDERLINE_DOUBLE:
    9661           0 :             if ( bIsAbove )
    9662             :             {
    9663           0 :                 if ( !pFontEntry->maMetric.mnAboveDUnderlineSize )
    9664           0 :                     m_pReferenceDevice->ImplInitAboveTextLineSize();
    9665           0 :                 nLineHeight = HCONV( pFontEntry->maMetric.mnAboveDUnderlineSize );
    9666           0 :                 nLinePos    = HCONV( pFontEntry->maMetric.mnAboveDUnderlineOffset1 );
    9667           0 :                 nLinePos2   = HCONV( pFontEntry->maMetric.mnAboveDUnderlineOffset2 );
    9668             :             }
    9669             :             else
    9670             :             {
    9671           0 :                 if ( !pFontEntry->maMetric.mnDUnderlineSize )
    9672           0 :                     m_pReferenceDevice->ImplInitTextLineSize();
    9673           0 :                 nLineHeight = HCONV( pFontEntry->maMetric.mnDUnderlineSize );
    9674           0 :                 nLinePos    = HCONV( pFontEntry->maMetric.mnDUnderlineOffset1 );
    9675           0 :                 nLinePos2   = HCONV( pFontEntry->maMetric.mnDUnderlineOffset2 );
    9676             :             }
    9677           0 :             break;
    9678             :         default:
    9679           0 :             break;
    9680             :     }
    9681             : 
    9682           0 :     if ( nLineHeight )
    9683             :     {
    9684           0 :         m_aPages.back().appendMappedLength( (sal_Int32)nLineHeight, aLine, true );
    9685           0 :         aLine.append( " w " );
    9686           0 :         appendStrokingColor( aColor, aLine );
    9687           0 :         aLine.append( "\n" );
    9688             : 
    9689           0 :         switch ( eTextLine )
    9690             :         {
    9691             :             case UNDERLINE_DOTTED:
    9692             :             case UNDERLINE_BOLDDOTTED:
    9693           0 :                 aLine.append( "[ " );
    9694           0 :                 m_aPages.back().appendMappedLength( (sal_Int32)nLineHeight, aLine, false );
    9695           0 :                 aLine.append( " ] 0 d\n" );
    9696           0 :                 break;
    9697             :             case UNDERLINE_DASH:
    9698             :             case UNDERLINE_LONGDASH:
    9699             :             case UNDERLINE_BOLDDASH:
    9700             :             case UNDERLINE_BOLDLONGDASH:
    9701             :                 {
    9702           0 :                     sal_Int32 nDashLength = 4*nLineHeight;
    9703           0 :                     sal_Int32 nVoidLength = 2*nLineHeight;
    9704           0 :                     if ( ( eTextLine == UNDERLINE_LONGDASH ) || ( eTextLine == UNDERLINE_BOLDLONGDASH ) )
    9705           0 :                         nDashLength = 8*nLineHeight;
    9706             : 
    9707           0 :                     aLine.append( "[ " );
    9708           0 :                     m_aPages.back().appendMappedLength( nDashLength, aLine, false );
    9709           0 :                     aLine.append( ' ' );
    9710           0 :                     m_aPages.back().appendMappedLength( nVoidLength, aLine, false );
    9711           0 :                     aLine.append( " ] 0 d\n" );
    9712             :                 }
    9713           0 :                 break;
    9714             :             case UNDERLINE_DASHDOT:
    9715             :             case UNDERLINE_BOLDDASHDOT:
    9716             :                 {
    9717           0 :                     sal_Int32 nDashLength = 4*nLineHeight;
    9718           0 :                     sal_Int32 nVoidLength = 2*nLineHeight;
    9719           0 :                     aLine.append( "[ " );
    9720           0 :                     m_aPages.back().appendMappedLength( nDashLength, aLine, false );
    9721           0 :                     aLine.append( ' ' );
    9722           0 :                     m_aPages.back().appendMappedLength( nVoidLength, aLine, false );
    9723           0 :                     aLine.append( ' ' );
    9724           0 :                     m_aPages.back().appendMappedLength( (sal_Int32)nLineHeight, aLine, false );
    9725           0 :                     aLine.append( ' ' );
    9726           0 :                     m_aPages.back().appendMappedLength( nVoidLength, aLine, false );
    9727           0 :                     aLine.append( " ] 0 d\n" );
    9728             :                 }
    9729           0 :                 break;
    9730             :             case UNDERLINE_DASHDOTDOT:
    9731             :             case UNDERLINE_BOLDDASHDOTDOT:
    9732             :                 {
    9733           0 :                     sal_Int32 nDashLength = 4*nLineHeight;
    9734           0 :                     sal_Int32 nVoidLength = 2*nLineHeight;
    9735           0 :                     aLine.append( "[ " );
    9736           0 :                     m_aPages.back().appendMappedLength( nDashLength, aLine, false );
    9737           0 :                     aLine.append( ' ' );
    9738           0 :                     m_aPages.back().appendMappedLength( nVoidLength, aLine, false );
    9739           0 :                     aLine.append( ' ' );
    9740           0 :                     m_aPages.back().appendMappedLength( (sal_Int32)nLineHeight, aLine, false );
    9741           0 :                     aLine.append( ' ' );
    9742           0 :                     m_aPages.back().appendMappedLength( nVoidLength, aLine, false );
    9743           0 :                     aLine.append( ' ' );
    9744           0 :                     m_aPages.back().appendMappedLength( (sal_Int32)nLineHeight, aLine, false );
    9745           0 :                     aLine.append( ' ' );
    9746           0 :                     m_aPages.back().appendMappedLength( nVoidLength, aLine, false );
    9747           0 :                     aLine.append( " ] 0 d\n" );
    9748             :                 }
    9749           0 :                 break;
    9750             :             default:
    9751           0 :                 break;
    9752             :         }
    9753             : 
    9754           0 :         aLine.append( "0 " );
    9755           0 :         m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos), aLine, true );
    9756           0 :         aLine.append( " m " );
    9757           0 :         m_aPages.back().appendMappedLength( (sal_Int32)nWidth, aLine, false );
    9758           0 :         aLine.append( ' ' );
    9759           0 :         m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos), aLine, true );
    9760           0 :         aLine.append( " l S\n" );
    9761           0 :         if ( eTextLine == UNDERLINE_DOUBLE )
    9762             :         {
    9763           0 :             aLine.append( "0 " );
    9764           0 :             m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos2-nLineHeight), aLine, true );
    9765           0 :             aLine.append( " m " );
    9766           0 :             m_aPages.back().appendMappedLength( (sal_Int32)nWidth, aLine, false );
    9767           0 :             aLine.append( ' ' );
    9768           0 :             m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos2-nLineHeight), aLine, true );
    9769           0 :             aLine.append( " l S\n" );
    9770             :         }
    9771             :     }
    9772           0 : }
    9773             : 
    9774           0 : void PDFWriterImpl::drawStrikeoutLine( OStringBuffer& aLine, long nWidth, FontStrikeout eStrikeout, Color aColor )
    9775             : {
    9776             :     // note: units in pFontEntry are ref device pixel
    9777           0 :     ImplFontEntry*  pFontEntry = m_pReferenceDevice->mpFontEntry;
    9778           0 :     long            nLineHeight = 0;
    9779           0 :     long            nLinePos  = 0;
    9780           0 :     long            nLinePos2 = 0;
    9781             : 
    9782           0 :     if ( eStrikeout > STRIKEOUT_X )
    9783           0 :         eStrikeout = STRIKEOUT_SINGLE;
    9784             : 
    9785           0 :     switch ( eStrikeout )
    9786             :     {
    9787             :         case STRIKEOUT_SINGLE:
    9788           0 :             if ( !pFontEntry->maMetric.mnStrikeoutSize )
    9789           0 :                 m_pReferenceDevice->ImplInitTextLineSize();
    9790           0 :             nLineHeight = HCONV( pFontEntry->maMetric.mnStrikeoutSize );
    9791           0 :             nLinePos    = HCONV( pFontEntry->maMetric.mnStrikeoutOffset );
    9792           0 :             break;
    9793             :         case STRIKEOUT_BOLD:
    9794           0 :             if ( !pFontEntry->maMetric.mnBStrikeoutSize )
    9795           0 :                 m_pReferenceDevice->ImplInitTextLineSize();
    9796           0 :             nLineHeight = HCONV( pFontEntry->maMetric.mnBStrikeoutSize );
    9797           0 :             nLinePos    = HCONV( pFontEntry->maMetric.mnBStrikeoutOffset );
    9798           0 :             break;
    9799             :         case STRIKEOUT_DOUBLE:
    9800           0 :             if ( !pFontEntry->maMetric.mnDStrikeoutSize )
    9801           0 :                 m_pReferenceDevice->ImplInitTextLineSize();
    9802           0 :             nLineHeight = HCONV( pFontEntry->maMetric.mnDStrikeoutSize );
    9803           0 :             nLinePos    = HCONV( pFontEntry->maMetric.mnDStrikeoutOffset1 );
    9804           0 :             nLinePos2   = HCONV( pFontEntry->maMetric.mnDStrikeoutOffset2 );
    9805           0 :             break;
    9806             :         default:
    9807           0 :             break;
    9808             :     }
    9809             : 
    9810           0 :     if ( nLineHeight )
    9811             :     {
    9812           0 :         m_aPages.back().appendMappedLength( (sal_Int32)nLineHeight, aLine, true );
    9813           0 :         aLine.append( " w " );
    9814           0 :         appendStrokingColor( aColor, aLine );
    9815           0 :         aLine.append( "\n" );
    9816             : 
    9817           0 :         aLine.append( "0 " );
    9818           0 :         m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos), aLine, true );
    9819           0 :         aLine.append( " m " );
    9820           0 :         m_aPages.back().appendMappedLength( (sal_Int32)nWidth, aLine, true );
    9821           0 :         aLine.append( ' ' );
    9822           0 :         m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos), aLine, true );
    9823           0 :         aLine.append( " l S\n" );
    9824             : 
    9825           0 :         if ( eStrikeout == STRIKEOUT_DOUBLE )
    9826             :         {
    9827           0 :             aLine.append( "0 " );
    9828           0 :             m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos2-nLineHeight), aLine, true );
    9829           0 :             aLine.append( " m " );
    9830           0 :             m_aPages.back().appendMappedLength( (sal_Int32)nWidth, aLine, true );
    9831           0 :             aLine.append( ' ' );
    9832           0 :             m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos2-nLineHeight), aLine, true );
    9833           0 :             aLine.append( " l S\n" );
    9834             :         }
    9835             :     }
    9836           0 : }
    9837             : 
    9838           0 : void PDFWriterImpl::drawStrikeoutChar( const Point& rPos, long nWidth, FontStrikeout eStrikeout )
    9839             : {
    9840             :     //See qadevOOo/testdocs/StrikeThrough.odt for examples if you need
    9841             :     //to tweak this
    9842             : 
    9843           0 :     OUString aStrikeoutChar = eStrikeout == STRIKEOUT_SLASH ? OUString( "/" ) : OUString( "X" );
    9844           0 :     OUString aStrikeout = aStrikeoutChar;
    9845           0 :     while( m_pReferenceDevice->GetTextWidth( aStrikeout ) < nWidth )
    9846           0 :         aStrikeout += aStrikeout;
    9847             : 
    9848             :     // do not get broader than nWidth modulo 1 character
    9849           0 :     while( m_pReferenceDevice->GetTextWidth( aStrikeout ) >= nWidth )
    9850           0 :         aStrikeout = aStrikeout.replaceAt( 0, 1, "" );
    9851           0 :     aStrikeout += aStrikeoutChar;
    9852           0 :     bool bShadow = m_aCurrentPDFState.m_aFont.IsShadow();
    9853           0 :     if ( bShadow )
    9854             :     {
    9855           0 :         Font aFont = m_aCurrentPDFState.m_aFont;
    9856           0 :         aFont.SetShadow( false );
    9857           0 :         setFont( aFont );
    9858           0 :         updateGraphicsState();
    9859             :     }
    9860             : 
    9861             :     // strikeout string is left aligned non-CTL text
    9862           0 :     ComplexTextLayoutMode nOrigTLM = m_pReferenceDevice->GetLayoutMode();
    9863           0 :     m_pReferenceDevice->SetLayoutMode( TEXT_LAYOUT_BIDI_STRONG|TEXT_LAYOUT_COMPLEX_DISABLED );
    9864             : 
    9865           0 :     push( PushFlags::CLIPREGION );
    9866           0 :     FontMetric aRefDevFontMetric = m_pReferenceDevice->GetFontMetric();
    9867           0 :     Rectangle aRect;
    9868           0 :     aRect.Left() = rPos.X();
    9869           0 :     aRect.Right() = aRect.Left()+nWidth;
    9870           0 :     aRect.Bottom() = rPos.Y()+aRefDevFontMetric.GetDescent();
    9871           0 :     aRect.Top() = rPos.Y()-aRefDevFontMetric.GetAscent();
    9872             : 
    9873           0 :     ImplFontEntry* pFontEntry = m_pReferenceDevice->mpFontEntry;
    9874           0 :     if (pFontEntry->mnOrientation)
    9875             :     {
    9876           0 :         Polygon aPoly( aRect );
    9877           0 :         aPoly.Rotate( rPos, pFontEntry->mnOrientation);
    9878           0 :         aRect = aPoly.GetBoundRect();
    9879             :     }
    9880             : 
    9881           0 :     intersectClipRegion( aRect );
    9882           0 :     drawText( rPos, aStrikeout, 0, aStrikeout.getLength(), false );
    9883           0 :     pop();
    9884             : 
    9885           0 :     m_pReferenceDevice->SetLayoutMode( nOrigTLM );
    9886             : 
    9887           0 :     if ( bShadow )
    9888             :     {
    9889           0 :         Font aFont = m_aCurrentPDFState.m_aFont;
    9890           0 :         aFont.SetShadow( true );
    9891           0 :         setFont( aFont );
    9892           0 :         updateGraphicsState();
    9893           0 :     }
    9894           0 : }
    9895             : 
    9896           0 : void PDFWriterImpl::drawTextLine( const Point& rPos, long nWidth, FontStrikeout eStrikeout, FontUnderline eUnderline, FontUnderline eOverline, bool bUnderlineAbove )
    9897             : {
    9898           0 :     if ( !nWidth ||
    9899           0 :          ( ((eStrikeout == STRIKEOUT_NONE)||(eStrikeout == STRIKEOUT_DONTKNOW)) &&
    9900           0 :            ((eUnderline == UNDERLINE_NONE)||(eUnderline == UNDERLINE_DONTKNOW)) &&
    9901           0 :            ((eOverline  == UNDERLINE_NONE)||(eOverline  == UNDERLINE_DONTKNOW)) ) )
    9902           0 :         return;
    9903             : 
    9904           0 :     MARK( "drawTextLine" );
    9905           0 :     updateGraphicsState();
    9906             : 
    9907             :     // note: units in pFontEntry are ref device pixel
    9908           0 :     ImplFontEntry*  pFontEntry = m_pReferenceDevice->mpFontEntry;
    9909           0 :     Color           aUnderlineColor = m_aCurrentPDFState.m_aTextLineColor;
    9910           0 :     Color           aOverlineColor  = m_aCurrentPDFState.m_aOverlineColor;
    9911           0 :     Color           aStrikeoutColor = m_aCurrentPDFState.m_aFont.GetColor();
    9912           0 :     bool            bStrikeoutDone = false;
    9913           0 :     bool            bUnderlineDone = false;
    9914           0 :     bool            bOverlineDone  = false;
    9915             : 
    9916           0 :     if ( (eStrikeout == STRIKEOUT_SLASH) || (eStrikeout == STRIKEOUT_X) )
    9917             :     {
    9918           0 :         drawStrikeoutChar( rPos, nWidth, eStrikeout );
    9919           0 :         bStrikeoutDone = true;
    9920             :     }
    9921             : 
    9922           0 :     Point aPos( rPos );
    9923           0 :     TextAlign eAlign = m_aCurrentPDFState.m_aFont.GetAlign();
    9924           0 :     if( eAlign == ALIGN_TOP )
    9925           0 :         aPos.Y() += HCONV( pFontEntry->maMetric.mnAscent );
    9926           0 :     else if( eAlign == ALIGN_BOTTOM )
    9927           0 :         aPos.Y() -= HCONV( pFontEntry->maMetric.mnDescent );
    9928             : 
    9929           0 :     OStringBuffer aLine( 512 );
    9930             :     // save GS
    9931           0 :     aLine.append( "q " );
    9932             : 
    9933             :     // rotate and translate matrix
    9934           0 :     double fAngle = (double)m_aCurrentPDFState.m_aFont.GetOrientation() * M_PI / 1800.0;
    9935           0 :     Matrix3 aMat;
    9936           0 :     aMat.rotate( fAngle );
    9937           0 :     aMat.translate( aPos.X(), aPos.Y() );
    9938           0 :     aMat.append( m_aPages.back(), aLine );
    9939           0 :     aLine.append( " cm\n" );
    9940             : 
    9941           0 :     if ( aUnderlineColor.GetTransparency() != 0 )
    9942           0 :         aUnderlineColor = aStrikeoutColor;
    9943             : 
    9944           0 :     if ( (eUnderline == UNDERLINE_SMALLWAVE) ||
    9945           0 :          (eUnderline == UNDERLINE_WAVE) ||
    9946           0 :          (eUnderline == UNDERLINE_DOUBLEWAVE) ||
    9947             :          (eUnderline == UNDERLINE_BOLDWAVE) )
    9948             :     {
    9949           0 :         drawWaveTextLine( aLine, nWidth, eUnderline, aUnderlineColor, bUnderlineAbove );
    9950           0 :         bUnderlineDone = true;
    9951             :     }
    9952             : 
    9953           0 :     if ( (eOverline == UNDERLINE_SMALLWAVE) ||
    9954           0 :          (eOverline == UNDERLINE_WAVE) ||
    9955           0 :          (eOverline == UNDERLINE_DOUBLEWAVE) ||
    9956             :          (eOverline == UNDERLINE_BOLDWAVE) )
    9957             :     {
    9958           0 :         drawWaveTextLine( aLine, nWidth, eOverline, aOverlineColor, true );
    9959           0 :         bOverlineDone = true;
    9960             :     }
    9961             : 
    9962           0 :     if ( !bUnderlineDone )
    9963             :     {
    9964           0 :         drawStraightTextLine( aLine, nWidth, eUnderline, aUnderlineColor, bUnderlineAbove );
    9965             :     }
    9966             : 
    9967           0 :     if ( !bOverlineDone )
    9968             :     {
    9969           0 :         drawStraightTextLine( aLine, nWidth, eOverline, aOverlineColor, true );
    9970             :     }
    9971             : 
    9972           0 :     if ( !bStrikeoutDone )
    9973             :     {
    9974           0 :         drawStrikeoutLine( aLine, nWidth, eStrikeout, aStrikeoutColor );
    9975             :     }
    9976             : 
    9977           0 :     aLine.append( "Q\n" );
    9978           0 :     writeBuffer( aLine.getStr(), aLine.getLength() );
    9979             : }
    9980             : 
    9981           0 : void PDFWriterImpl::drawPolygon( const Polygon& rPoly )
    9982             : {
    9983           0 :     MARK( "drawPolygon" );
    9984             : 
    9985           0 :     updateGraphicsState();
    9986             : 
    9987           0 :     if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) &&
    9988           0 :         m_aGraphicsStack.front().m_aFillColor == Color( COL_TRANSPARENT ) )
    9989           0 :         return;
    9990             : 
    9991           0 :     int nPoints = rPoly.GetSize();
    9992           0 :     OStringBuffer aLine( 20 * nPoints );
    9993           0 :     m_aPages.back().appendPolygon( rPoly, aLine );
    9994           0 :     if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) &&
    9995           0 :         m_aGraphicsStack.front().m_aFillColor != Color( COL_TRANSPARENT ) )
    9996           0 :         aLine.append( "B*\n" );
    9997           0 :     else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
    9998           0 :         aLine.append( "S\n" );
    9999             :     else
   10000           0 :         aLine.append( "f*\n" );
   10001             : 
   10002           0 :     writeBuffer( aLine.getStr(), aLine.getLength() );
   10003             : }
   10004             : 
   10005           0 : void PDFWriterImpl::drawPolyPolygon( const tools::PolyPolygon& rPolyPoly )
   10006             : {
   10007           0 :     MARK( "drawPolyPolygon" );
   10008             : 
   10009           0 :     updateGraphicsState();
   10010             : 
   10011           0 :     if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) &&
   10012           0 :         m_aGraphicsStack.front().m_aFillColor == Color( COL_TRANSPARENT ) )
   10013           0 :         return;
   10014             : 
   10015           0 :     int nPolygons = rPolyPoly.Count();
   10016             : 
   10017           0 :     OStringBuffer aLine( 40 * nPolygons );
   10018           0 :     m_aPages.back().appendPolyPolygon( rPolyPoly, aLine );
   10019           0 :     if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) &&
   10020           0 :         m_aGraphicsStack.front().m_aFillColor != Color( COL_TRANSPARENT ) )
   10021           0 :         aLine.append( "B*\n" );
   10022           0 :     else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
   10023           0 :         aLine.append( "S\n" );
   10024             :     else
   10025           0 :         aLine.append( "f*\n" );
   10026             : 
   10027           0 :     writeBuffer( aLine.getStr(), aLine.getLength() );
   10028             : }
   10029             : 
   10030           0 : void PDFWriterImpl::drawTransparent( const tools::PolyPolygon& rPolyPoly, sal_uInt32 nTransparentPercent )
   10031             : {
   10032             :     DBG_ASSERT( nTransparentPercent <= 100, "invalid alpha value" );
   10033           0 :     nTransparentPercent = nTransparentPercent % 100;
   10034             : 
   10035           0 :     MARK( "drawTransparent" );
   10036             : 
   10037           0 :     updateGraphicsState();
   10038             : 
   10039           0 :     if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) &&
   10040           0 :         m_aGraphicsStack.front().m_aFillColor == Color( COL_TRANSPARENT ) )
   10041           0 :         return;
   10042             : 
   10043           0 :     if( m_bIsPDF_A1 || m_aContext.Version < PDFWriter::PDF_1_4 )
   10044             :     {
   10045             :         m_aErrors.insert( m_bIsPDF_A1 ?
   10046             :                           PDFWriter::Warning_Transparency_Omitted_PDFA :
   10047           0 :                           PDFWriter::Warning_Transparency_Omitted_PDF13 );
   10048             : 
   10049           0 :         drawPolyPolygon( rPolyPoly );
   10050           0 :         return;
   10051             :     }
   10052             : 
   10053             :     // create XObject
   10054           0 :     m_aTransparentObjects.push_back( TransparencyEmit() );
   10055             :     // FIXME: polygons with beziers may yield incorrect bound rect
   10056           0 :     m_aTransparentObjects.back().m_aBoundRect     = rPolyPoly.GetBoundRect();
   10057             :     // convert rectangle to default user space
   10058           0 :     m_aPages.back().convertRect( m_aTransparentObjects.back().m_aBoundRect );
   10059           0 :     m_aTransparentObjects.back().m_nObject          = createObject();
   10060           0 :     m_aTransparentObjects.back().m_nExtGStateObject = createObject();
   10061           0 :     m_aTransparentObjects.back().m_fAlpha           = (double)(100-nTransparentPercent) / 100.0;
   10062           0 :     m_aTransparentObjects.back().m_pContentStream   = new SvMemoryStream( 256, 256 );
   10063             :     // create XObject's content stream
   10064           0 :     OStringBuffer aContent( 256 );
   10065           0 :     m_aPages.back().appendPolyPolygon( rPolyPoly, aContent );
   10066           0 :     if( m_aCurrentPDFState.m_aLineColor != Color( COL_TRANSPARENT ) &&
   10067           0 :         m_aCurrentPDFState.m_aFillColor != Color( COL_TRANSPARENT ) )
   10068           0 :         aContent.append( " B*\n" );
   10069           0 :     else if( m_aCurrentPDFState.m_aLineColor != Color( COL_TRANSPARENT ) )
   10070           0 :         aContent.append( " S\n" );
   10071             :     else
   10072           0 :         aContent.append( " f*\n" );
   10073           0 :     m_aTransparentObjects.back().m_pContentStream->Write( aContent.getStr(), aContent.getLength() );
   10074             : 
   10075           0 :     OStringBuffer aObjName( 16 );
   10076           0 :     aObjName.append( "Tr" );
   10077           0 :     aObjName.append( m_aTransparentObjects.back().m_nObject );
   10078           0 :     OString aTrName( aObjName.makeStringAndClear() );
   10079           0 :     aObjName.append( "EGS" );
   10080           0 :     aObjName.append( m_aTransparentObjects.back().m_nExtGStateObject );
   10081           0 :     OString aExtName( aObjName.makeStringAndClear() );
   10082             : 
   10083           0 :     OStringBuffer aLine( 80 );
   10084             :     // insert XObject
   10085           0 :     aLine.append( "q /" );
   10086           0 :     aLine.append( aExtName );
   10087           0 :     aLine.append( " gs /" );
   10088           0 :     aLine.append( aTrName );
   10089           0 :     aLine.append( " Do Q\n" );
   10090           0 :     writeBuffer( aLine.getStr(), aLine.getLength() );
   10091             : 
   10092           0 :     pushResource( ResXObject, aTrName, m_aTransparentObjects.back().m_nObject );
   10093           0 :     pushResource( ResExtGState, aExtName, m_aTransparentObjects.back().m_nExtGStateObject );
   10094             : }
   10095             : 
   10096           0 : void PDFWriterImpl::pushResource( ResourceKind eKind, const OString& rResource, sal_Int32 nObject )
   10097             : {
   10098           0 :     if( nObject >= 0 )
   10099             :     {
   10100           0 :         switch( eKind )
   10101             :         {
   10102             :             case ResXObject:
   10103           0 :                 m_aGlobalResourceDict.m_aXObjects[ rResource ] = nObject;
   10104           0 :                 if( ! m_aOutputStreams.empty() )
   10105           0 :                     m_aOutputStreams.front().m_aResourceDict.m_aXObjects[ rResource ] = nObject;
   10106           0 :                 break;
   10107             :             case ResExtGState:
   10108           0 :                 m_aGlobalResourceDict.m_aExtGStates[ rResource ] = nObject;
   10109           0 :                 if( ! m_aOutputStreams.empty() )
   10110           0 :                     m_aOutputStreams.front().m_aResourceDict.m_aExtGStates[ rResource ] = nObject;
   10111           0 :                 break;
   10112             :             case ResShading:
   10113           0 :                 m_aGlobalResourceDict.m_aShadings[ rResource ] = nObject;
   10114           0 :                 if( ! m_aOutputStreams.empty() )
   10115           0 :                     m_aOutputStreams.front().m_aResourceDict.m_aShadings[ rResource ] = nObject;
   10116           0 :                 break;
   10117             :             case ResPattern:
   10118           0 :                 m_aGlobalResourceDict.m_aPatterns[ rResource ] = nObject;
   10119           0 :                 if( ! m_aOutputStreams.empty() )
   10120           0 :                     m_aOutputStreams.front().m_aResourceDict.m_aPatterns[ rResource ] = nObject;
   10121           0 :                 break;
   10122             :         }
   10123             :     }
   10124           0 : }
   10125             : 
   10126           0 : void PDFWriterImpl::beginRedirect( SvStream* pStream, const Rectangle& rTargetRect )
   10127             : {
   10128           0 :     push( PushFlags::ALL );
   10129             : 
   10130             :     // force reemitting clip region inside the new stream, and
   10131             :     // prevent emitting an unbalanced "Q" at the start
   10132           0 :     clearClipRegion();
   10133             :     // this is needed to point m_aCurrentPDFState at the pushed state
   10134             :     // ... but it's pointless to actually write into the "outer" stream here!
   10135           0 :     updateGraphicsState(NOWRITE);
   10136             : 
   10137           0 :     m_aOutputStreams.push_front( StreamRedirect() );
   10138           0 :     m_aOutputStreams.front().m_pStream = pStream;
   10139           0 :     m_aOutputStreams.front().m_aMapMode = m_aMapMode;
   10140             : 
   10141           0 :     if( !rTargetRect.IsEmpty() )
   10142             :     {
   10143           0 :         m_aOutputStreams.front().m_aTargetRect =
   10144           0 :             lcl_convert( m_aGraphicsStack.front().m_aMapMode,
   10145             :                          m_aMapMode,
   10146             :                          getReferenceDevice(),
   10147           0 :                          rTargetRect );
   10148           0 :         Point aDelta = m_aOutputStreams.front().m_aTargetRect.BottomLeft();
   10149           0 :         long nPageHeight = pointToPixel(m_aPages[m_nCurrentPage].getHeight());
   10150           0 :         aDelta.Y() = -(nPageHeight - m_aOutputStreams.front().m_aTargetRect.Bottom());
   10151           0 :         m_aMapMode.SetOrigin( m_aMapMode.GetOrigin() + aDelta );
   10152             :     }
   10153             : 
   10154             :     // setup graphics state for independent object stream
   10155             : 
   10156             :     // force reemitting colors
   10157           0 :     m_aCurrentPDFState.m_aLineColor = Color( COL_TRANSPARENT );
   10158           0 :     m_aCurrentPDFState.m_aFillColor = Color( COL_TRANSPARENT );
   10159           0 : }
   10160             : 
   10161           0 : SvStream* PDFWriterImpl::endRedirect()
   10162             : {
   10163           0 :     SvStream* pStream = NULL;
   10164           0 :     if( ! m_aOutputStreams.empty() )
   10165             :     {
   10166           0 :         pStream     = m_aOutputStreams.front().m_pStream;
   10167           0 :         m_aMapMode  = m_aOutputStreams.front().m_aMapMode;
   10168           0 :         m_aOutputStreams.pop_front();
   10169             :     }
   10170             : 
   10171           0 :     pop();
   10172             : 
   10173           0 :     m_aCurrentPDFState.m_aLineColor = Color( COL_TRANSPARENT );
   10174           0 :     m_aCurrentPDFState.m_aFillColor = Color( COL_TRANSPARENT );
   10175             : 
   10176             :     // needed after pop() to set m_aCurrentPDFState
   10177           0 :     updateGraphicsState(NOWRITE);
   10178             : 
   10179           0 :     return pStream;
   10180             : }
   10181             : 
   10182           0 : void PDFWriterImpl::beginTransparencyGroup()
   10183             : {
   10184           0 :     updateGraphicsState();
   10185           0 :     if( m_aContext.Version >= PDFWriter::PDF_1_4 )
   10186           0 :         beginRedirect( new SvMemoryStream( 1024, 1024 ), Rectangle() );
   10187           0 : }
   10188             : 
   10189           0 : void PDFWriterImpl::endTransparencyGroup( const Rectangle& rBoundingBox, sal_uInt32 nTransparentPercent )
   10190             : {
   10191             :     DBG_ASSERT( nTransparentPercent <= 100, "invalid alpha value" );
   10192           0 :     nTransparentPercent = nTransparentPercent % 100;
   10193             : 
   10194           0 :     if( m_aContext.Version >= PDFWriter::PDF_1_4 )
   10195             :     {
   10196             :         // create XObject
   10197           0 :         m_aTransparentObjects.push_back( TransparencyEmit() );
   10198           0 :         m_aTransparentObjects.back().m_aBoundRect   = rBoundingBox;
   10199             :         // convert rectangle to default user space
   10200           0 :         m_aPages.back().convertRect( m_aTransparentObjects.back().m_aBoundRect );
   10201           0 :         m_aTransparentObjects.back().m_nObject      = createObject();
   10202           0 :         m_aTransparentObjects.back().m_fAlpha       = (double)(100-nTransparentPercent) / 100.0;
   10203             :         // get XObject's content stream
   10204           0 :         m_aTransparentObjects.back().m_pContentStream = static_cast<SvMemoryStream*>(endRedirect());
   10205           0 :         m_aTransparentObjects.back().m_nExtGStateObject = createObject();
   10206             : 
   10207           0 :         OStringBuffer aObjName( 16 );
   10208           0 :         aObjName.append( "Tr" );
   10209           0 :         aObjName.append( m_aTransparentObjects.back().m_nObject );
   10210           0 :         OString aTrName( aObjName.makeStringAndClear() );
   10211           0 :         aObjName.append( "EGS" );
   10212           0 :         aObjName.append( m_aTransparentObjects.back().m_nExtGStateObject );
   10213           0 :         OString aExtName( aObjName.makeStringAndClear() );
   10214             : 
   10215           0 :         OStringBuffer aLine( 80 );
   10216             :         // insert XObject
   10217           0 :         aLine.append( "q /" );
   10218           0 :         aLine.append( aExtName );
   10219           0 :         aLine.append( " gs /" );
   10220           0 :         aLine.append( aTrName );
   10221           0 :         aLine.append( " Do Q\n" );
   10222           0 :         writeBuffer( aLine.getStr(), aLine.getLength() );
   10223             : 
   10224           0 :         pushResource( ResXObject, aTrName, m_aTransparentObjects.back().m_nObject );
   10225           0 :         pushResource( ResExtGState, aExtName, m_aTransparentObjects.back().m_nExtGStateObject );
   10226             :     }
   10227           0 : }
   10228             : 
   10229           0 : void PDFWriterImpl::drawRectangle( const Rectangle& rRect )
   10230             : {
   10231           0 :     MARK( "drawRectangle" );
   10232             : 
   10233           0 :     updateGraphicsState();
   10234             : 
   10235           0 :     if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) &&
   10236           0 :         m_aGraphicsStack.front().m_aFillColor == Color( COL_TRANSPARENT ) )
   10237           0 :         return;
   10238             : 
   10239           0 :     OStringBuffer aLine( 40 );
   10240           0 :     m_aPages.back().appendRect( rRect, aLine );
   10241             : 
   10242           0 :     if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) &&
   10243           0 :         m_aGraphicsStack.front().m_aFillColor != Color( COL_TRANSPARENT ) )
   10244           0 :         aLine.append( " B*\n" );
   10245           0 :     else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
   10246           0 :         aLine.append( " S\n" );
   10247             :     else
   10248           0 :         aLine.append( " f*\n" );
   10249             : 
   10250           0 :     writeBuffer( aLine.getStr(), aLine.getLength() );
   10251             : }
   10252             : 
   10253           0 : void PDFWriterImpl::drawRectangle( const Rectangle& rRect, sal_uInt32 nHorzRound, sal_uInt32 nVertRound )
   10254             : {
   10255           0 :     MARK( "drawRectangle with rounded edges" );
   10256             : 
   10257           0 :     if( !nHorzRound && !nVertRound )
   10258           0 :         drawRectangle( rRect );
   10259             : 
   10260           0 :     updateGraphicsState();
   10261             : 
   10262           0 :     if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) &&
   10263           0 :         m_aGraphicsStack.front().m_aFillColor == Color( COL_TRANSPARENT ) )
   10264           0 :         return;
   10265             : 
   10266           0 :     if( nHorzRound > (sal_uInt32)rRect.GetWidth()/2 )
   10267           0 :         nHorzRound = rRect.GetWidth()/2;
   10268           0 :     if( nVertRound > (sal_uInt32)rRect.GetHeight()/2 )
   10269           0 :         nVertRound = rRect.GetHeight()/2;
   10270             : 
   10271           0 :     Point aPoints[16];
   10272           0 :     const double kappa = 0.5522847498;
   10273           0 :     const sal_uInt32 kx = (sal_uInt32)((kappa*(double)nHorzRound)+0.5);
   10274           0 :     const sal_uInt32 ky = (sal_uInt32)((kappa*(double)nVertRound)+0.5);
   10275             : 
   10276           0 :     aPoints[1]  = Point( rRect.TopLeft().X() + nHorzRound, rRect.TopLeft().Y() );
   10277           0 :     aPoints[0]  = Point( aPoints[1].X() - kx, aPoints[1].Y() );
   10278           0 :     aPoints[2]  = Point( rRect.TopRight().X()+1 - nHorzRound, aPoints[1].Y() );
   10279           0 :     aPoints[3]  = Point( aPoints[2].X()+kx, aPoints[2].Y() );
   10280             : 
   10281           0 :     aPoints[5]  = Point( rRect.TopRight().X()+1, rRect.TopRight().Y()+nVertRound );
   10282           0 :     aPoints[4]  = Point( aPoints[5].X(), aPoints[5].Y()-ky );
   10283           0 :     aPoints[6]  = Point( aPoints[5].X(), rRect.BottomRight().Y()+1 - nVertRound );
   10284           0 :     aPoints[7]  = Point( aPoints[6].X(), aPoints[6].Y()+ky );
   10285             : 
   10286           0 :     aPoints[9]  = Point( rRect.BottomRight().X()+1-nHorzRound, rRect.BottomRight().Y()+1 );
   10287           0 :     aPoints[8]  = Point( aPoints[9].X()+kx, aPoints[9].Y() );
   10288           0 :     aPoints[10] = Point( rRect.BottomLeft().X() + nHorzRound, aPoints[9].Y() );
   10289           0 :     aPoints[11] = Point( aPoints[10].X()-kx, aPoints[10].Y() );
   10290             : 
   10291           0 :     aPoints[13] = Point( rRect.BottomLeft().X(), rRect.BottomLeft().Y()+1-nVertRound );
   10292           0 :     aPoints[12] = Point( aPoints[13].X(), aPoints[13].Y()+ky );
   10293           0 :     aPoints[14] = Point( rRect.TopLeft().X(), rRect.TopLeft().Y()+nVertRound );
   10294           0 :     aPoints[15] = Point( aPoints[14].X(), aPoints[14].Y()-ky );
   10295             : 
   10296           0 :     OStringBuffer aLine( 80 );
   10297           0 :     m_aPages.back().appendPoint( aPoints[1], aLine );
   10298           0 :     aLine.append( " m " );
   10299           0 :     m_aPages.back().appendPoint( aPoints[2], aLine );
   10300           0 :     aLine.append( " l " );
   10301           0 :     m_aPages.back().appendPoint( aPoints[3], aLine );
   10302           0 :     aLine.append( ' ' );
   10303           0 :     m_aPages.back().appendPoint( aPoints[4], aLine );
   10304           0 :     aLine.append( ' ' );
   10305           0 :     m_aPages.back().appendPoint( aPoints[5], aLine );
   10306           0 :     aLine.append( " c\n" );
   10307           0 :     m_aPages.back().appendPoint( aPoints[6], aLine );
   10308           0 :     aLine.append( " l " );
   10309           0 :     m_aPages.back().appendPoint( aPoints[7], aLine );
   10310           0 :     aLine.append( ' ' );
   10311           0 :     m_aPages.back().appendPoint( aPoints[8], aLine );
   10312           0 :     aLine.append( ' ' );
   10313           0 :     m_aPages.back().appendPoint( aPoints[9], aLine );
   10314           0 :     aLine.append( " c\n" );
   10315           0 :     m_aPages.back().appendPoint( aPoints[10], aLine );
   10316           0 :     aLine.append( " l " );
   10317           0 :     m_aPages.back().appendPoint( aPoints[11], aLine );
   10318           0 :     aLine.append( ' ' );
   10319           0 :     m_aPages.back().appendPoint( aPoints[12], aLine );
   10320           0 :     aLine.append( ' ' );
   10321           0 :     m_aPages.back().appendPoint( aPoints[13], aLine );
   10322           0 :     aLine.append( " c\n" );
   10323           0 :     m_aPages.back().appendPoint( aPoints[14], aLine );
   10324           0 :     aLine.append( " l " );
   10325           0 :     m_aPages.back().appendPoint( aPoints[15], aLine );
   10326           0 :     aLine.append( ' ' );
   10327           0 :     m_aPages.back().appendPoint( aPoints[0], aLine );
   10328           0 :     aLine.append( ' ' );
   10329           0 :     m_aPages.back().appendPoint( aPoints[1], aLine );
   10330           0 :     aLine.append( " c " );
   10331             : 
   10332           0 :     if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) &&
   10333           0 :         m_aGraphicsStack.front().m_aFillColor != Color( COL_TRANSPARENT ) )
   10334           0 :         aLine.append( "b*\n" );
   10335           0 :     else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
   10336           0 :         aLine.append( "s\n" );
   10337             :     else
   10338           0 :         aLine.append( "f*\n" );
   10339             : 
   10340           0 :     writeBuffer( aLine.getStr(), aLine.getLength() );
   10341             : }
   10342             : 
   10343           0 : void PDFWriterImpl::drawEllipse( const Rectangle& rRect )
   10344             : {
   10345           0 :     MARK( "drawEllipse" );
   10346             : 
   10347           0 :     updateGraphicsState();
   10348             : 
   10349           0 :     if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) &&
   10350           0 :         m_aGraphicsStack.front().m_aFillColor == Color( COL_TRANSPARENT ) )
   10351           0 :         return;
   10352             : 
   10353           0 :     Point aPoints[12];
   10354           0 :     const double kappa = 0.5522847498;
   10355           0 :     const sal_uInt32 kx = (sal_uInt32)((kappa*(double)rRect.GetWidth()/2.0)+0.5);
   10356           0 :     const sal_uInt32 ky = (sal_uInt32)((kappa*(double)rRect.GetHeight()/2.0)+0.5);
   10357             : 
   10358           0 :     aPoints[1]  = Point( rRect.TopLeft().X() + rRect.GetWidth()/2, rRect.TopLeft().Y() );
   10359           0 :     aPoints[0]  = Point( aPoints[1].X() - kx, aPoints[1].Y() );
   10360           0 :     aPoints[2]  = Point( aPoints[1].X() + kx, aPoints[1].Y() );
   10361             : 
   10362           0 :     aPoints[4]  = Point( rRect.TopRight().X()+1, rRect.TopRight().Y() + rRect.GetHeight()/2 );
   10363           0 :     aPoints[3]  = Point( aPoints[4].X(), aPoints[4].Y() - ky );
   10364           0 :     aPoints[5]  = Point( aPoints[4].X(), aPoints[4].Y() + ky );
   10365             : 
   10366           0 :     aPoints[7]  = Point( rRect.BottomLeft().X() + rRect.GetWidth()/2, rRect.BottomLeft().Y()+1 );
   10367           0 :     aPoints[6]  = Point( aPoints[7].X() + kx, aPoints[7].Y() );
   10368           0 :     aPoints[8]  = Point( aPoints[7].X() - kx, aPoints[7].Y() );
   10369             : 
   10370           0 :     aPoints[10] = Point( rRect.TopLeft().X(), rRect.TopLeft().Y() + rRect.GetHeight()/2 );
   10371           0 :     aPoints[9]  = Point( aPoints[10].X(), aPoints[10].Y() + ky );
   10372           0 :     aPoints[11] = Point( aPoints[10].X(), aPoints[10].Y() - ky );
   10373             : 
   10374           0 :     OStringBuffer aLine( 80 );
   10375           0 :     m_aPages.back().appendPoint( aPoints[1], aLine );
   10376           0 :     aLine.append( " m " );
   10377           0 :     m_aPages.back().appendPoint( aPoints[2], aLine );
   10378           0 :     aLine.append( ' ' );
   10379           0 :     m_aPages.back().appendPoint( aPoints[3], aLine );
   10380           0 :     aLine.append( ' ' );
   10381           0 :     m_aPages.back().appendPoint( aPoints[4], aLine );
   10382           0 :     aLine.append( " c\n" );
   10383           0 :     m_aPages.back().appendPoint( aPoints[5], aLine );
   10384           0 :     aLine.append( ' ' );
   10385           0 :     m_aPages.back().appendPoint( aPoints[6], aLine );
   10386           0 :     aLine.append( ' ' );
   10387           0 :     m_aPages.back().appendPoint( aPoints[7], aLine );
   10388           0 :     aLine.append( " c\n" );
   10389           0 :     m_aPages.back().appendPoint( aPoints[8], aLine );
   10390           0 :     aLine.append( ' ' );
   10391           0 :     m_aPages.back().appendPoint( aPoints[9], aLine );
   10392           0 :     aLine.append( ' ' );
   10393           0 :     m_aPages.back().appendPoint( aPoints[10], aLine );
   10394           0 :     aLine.append( " c\n" );
   10395           0 :     m_aPages.back().appendPoint( aPoints[11], aLine );
   10396           0 :     aLine.append( ' ' );
   10397           0 :     m_aPages.back().appendPoint( aPoints[0], aLine );
   10398           0 :     aLine.append( ' ' );
   10399           0 :     m_aPages.back().appendPoint( aPoints[1], aLine );
   10400           0 :     aLine.append( " c " );
   10401             : 
   10402           0 :     if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) &&
   10403           0 :         m_aGraphicsStack.front().m_aFillColor != Color( COL_TRANSPARENT ) )
   10404           0 :         aLine.append( "b*\n" );
   10405           0 :     else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
   10406           0 :         aLine.append( "s\n" );
   10407             :     else
   10408           0 :         aLine.append( "f*\n" );
   10409             : 
   10410           0 :     writeBuffer( aLine.getStr(), aLine.getLength() );
   10411             : }
   10412             : 
   10413           0 : static double calcAngle( const Rectangle& rRect, const Point& rPoint )
   10414             : {
   10415           0 :     Point aOrigin((rRect.Left()+rRect.Right()+1)/2,
   10416           0 :                   (rRect.Top()+rRect.Bottom()+1)/2);
   10417           0 :     Point aPoint = rPoint - aOrigin;
   10418             : 
   10419           0 :     double fX = (double)aPoint.X();
   10420           0 :     double fY = (double)-aPoint.Y();
   10421             : 
   10422           0 :     if ((rRect.GetHeight() == 0) || (rRect.GetWidth() == 0))
   10423           0 :         throw o3tl::divide_by_zero();
   10424             : 
   10425           0 :     if( rRect.GetWidth() > rRect.GetHeight() )
   10426           0 :         fY = fY*((double)rRect.GetWidth()/(double)rRect.GetHeight());
   10427           0 :     else if( rRect.GetHeight() > rRect.GetWidth() )
   10428           0 :         fX = fX*((double)rRect.GetHeight()/(double)rRect.GetWidth());
   10429           0 :     return atan2( fY, fX );
   10430             : }
   10431             : 
   10432           0 : void PDFWriterImpl::drawArc( const Rectangle& rRect, const Point& rStart, const Point& rStop, bool bWithPie, bool bWithChord )
   10433             : {
   10434           0 :     MARK( "drawArc" );
   10435             : 
   10436           0 :     updateGraphicsState();
   10437             : 
   10438           0 :     if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) &&
   10439           0 :         m_aGraphicsStack.front().m_aFillColor == Color( COL_TRANSPARENT ) )
   10440           0 :         return;
   10441             : 
   10442             :     // calculate start and stop angles
   10443           0 :     const double fStartAngle = calcAngle( rRect, rStart );
   10444           0 :     double fStopAngle  = calcAngle( rRect, rStop );
   10445           0 :     while( fStopAngle < fStartAngle )
   10446           0 :         fStopAngle += 2.0*M_PI;
   10447           0 :     const int nFragments = (int)((fStopAngle-fStartAngle)/(M_PI/2.0))+1;
   10448           0 :     const double fFragmentDelta = (fStopAngle-fStartAngle)/(double)nFragments;
   10449           0 :     const double kappa = fabs( 4.0 * (1.0-cos(fFragmentDelta/2.0))/sin(fFragmentDelta/2.0) / 3.0);
   10450           0 :     const double halfWidth = (double)rRect.GetWidth()/2.0;
   10451           0 :     const double halfHeight = (double)rRect.GetHeight()/2.0;
   10452             : 
   10453           0 :     const Point aCenter( (rRect.Left()+rRect.Right()+1)/2,
   10454           0 :                          (rRect.Top()+rRect.Bottom()+1)/2 );
   10455             : 
   10456           0 :     OStringBuffer aLine( 30*nFragments );
   10457           0 :     Point aPoint( (int)(halfWidth * cos(fStartAngle) ),
   10458           0 :                   -(int)(halfHeight * sin(fStartAngle) ) );
   10459           0 :     aPoint += aCenter;
   10460           0 :     m_aPages.back().appendPoint( aPoint, aLine );
   10461           0 :     aLine.append( " m " );
   10462           0 :     if( !basegfx::fTools::equal(fStartAngle, fStopAngle) )
   10463             :     {
   10464           0 :         for( int i = 0; i < nFragments; i++ )
   10465             :         {
   10466           0 :             const double fStartFragment = fStartAngle + (double)i*fFragmentDelta;
   10467           0 :             const double fStopFragment = fStartFragment + fFragmentDelta;
   10468           0 :             aPoint = Point( (int)(halfWidth * (cos(fStartFragment) - kappa*sin(fStartFragment) ) ),
   10469           0 :                             -(int)(halfHeight * (sin(fStartFragment) + kappa*cos(fStartFragment) ) ) );
   10470           0 :             aPoint += aCenter;
   10471           0 :             m_aPages.back().appendPoint( aPoint, aLine );
   10472           0 :             aLine.append( ' ' );
   10473             : 
   10474           0 :             aPoint = Point( (int)(halfWidth * (cos(fStopFragment) + kappa*sin(fStopFragment) ) ),
   10475           0 :                             -(int)(halfHeight * (sin(fStopFragment) - kappa*cos(fStopFragment) ) ) );
   10476           0 :             aPoint += aCenter;
   10477           0 :             m_aPages.back().appendPoint( aPoint, aLine );
   10478           0 :             aLine.append( ' ' );
   10479             : 
   10480           0 :             aPoint = Point( (int)(halfWidth * cos(fStopFragment) ),
   10481           0 :                             -(int)(halfHeight * sin(fStopFragment) ) );
   10482           0 :             aPoint += aCenter;
   10483           0 :             m_aPages.back().appendPoint( aPoint, aLine );
   10484           0 :             aLine.append( " c\n" );
   10485             :         }
   10486             :     }
   10487           0 :     if( bWithChord || bWithPie )
   10488             :     {
   10489           0 :         if( bWithPie )
   10490             :         {
   10491           0 :             m_aPages.back().appendPoint( aCenter, aLine );
   10492           0 :             aLine.append( " l " );
   10493             :         }
   10494           0 :         aLine.append( "h " );
   10495             :     }
   10496           0 :     if( ! bWithChord && ! bWithPie )
   10497           0 :         aLine.append( "S\n" );
   10498           0 :     else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) &&
   10499           0 :         m_aGraphicsStack.front().m_aFillColor != Color( COL_TRANSPARENT ) )
   10500           0 :         aLine.append( "B*\n" );
   10501           0 :     else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
   10502           0 :         aLine.append( "S\n" );
   10503             :     else
   10504           0 :         aLine.append( "f*\n" );
   10505             : 
   10506           0 :     writeBuffer( aLine.getStr(), aLine.getLength() );
   10507             : }
   10508             : 
   10509           0 : void PDFWriterImpl::drawPolyLine( const Polygon& rPoly )
   10510             : {
   10511           0 :     MARK( "drawPolyLine" );
   10512             : 
   10513           0 :     sal_uInt16 nPoints = rPoly.GetSize();
   10514           0 :     if( nPoints < 2 )
   10515           0 :         return;
   10516             : 
   10517           0 :     updateGraphicsState();
   10518             : 
   10519           0 :     if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) )
   10520           0 :         return;
   10521             : 
   10522           0 :     OStringBuffer aLine( 20 * nPoints );
   10523           0 :     m_aPages.back().appendPolygon( rPoly, aLine, rPoly[0] == rPoly[nPoints-1] );
   10524           0 :     aLine.append( "S\n" );
   10525             : 
   10526           0 :     writeBuffer( aLine.getStr(), aLine.getLength() );
   10527             : }
   10528             : 
   10529           0 : void PDFWriterImpl::drawPolyLine( const Polygon& rPoly, const LineInfo& rInfo )
   10530             : {
   10531           0 :     MARK( "drawPolyLine with LineInfo" );
   10532             : 
   10533           0 :     updateGraphicsState();
   10534             : 
   10535           0 :     if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) )
   10536           0 :         return;
   10537             : 
   10538           0 :     OStringBuffer aLine;
   10539           0 :     aLine.append( "q " );
   10540           0 :     if( m_aPages.back().appendLineInfo( rInfo, aLine ) )
   10541             :     {
   10542           0 :         writeBuffer( aLine.getStr(), aLine.getLength() );
   10543           0 :         drawPolyLine( rPoly );
   10544           0 :         writeBuffer( "Q\n", 2 );
   10545             :     }
   10546             :     else
   10547             :     {
   10548           0 :         PDFWriter::ExtLineInfo aInfo;
   10549           0 :         convertLineInfoToExtLineInfo( rInfo, aInfo );
   10550           0 :         drawPolyLine( rPoly, aInfo );
   10551           0 :     }
   10552             : }
   10553             : 
   10554           0 : void PDFWriterImpl::convertLineInfoToExtLineInfo( const LineInfo& rIn, PDFWriter::ExtLineInfo& rOut )
   10555             : {
   10556             :     DBG_ASSERT( rIn.GetStyle() == LINE_DASH, "invalid conversion" );
   10557           0 :     rOut.m_fLineWidth           = rIn.GetWidth();
   10558           0 :     rOut.m_fTransparency        = 0.0;
   10559           0 :     rOut.m_eCap                 = PDFWriter::capButt;
   10560           0 :     rOut.m_eJoin                = PDFWriter::joinMiter;
   10561           0 :     rOut.m_fMiterLimit          = 10;
   10562           0 :     rOut.m_aDashArray.clear();
   10563             : 
   10564             :     // add DashDot to DashArray
   10565           0 :     const int nDashes   = rIn.GetDashCount();
   10566           0 :     const int nDashLen  = rIn.GetDashLen();
   10567           0 :     const int nDistance = rIn.GetDistance();
   10568             : 
   10569           0 :     for( int n  = 0; n < nDashes; n++ )
   10570             :     {
   10571           0 :         rOut.m_aDashArray.push_back( nDashLen );
   10572           0 :         rOut.m_aDashArray.push_back( nDistance );
   10573             :     }
   10574           0 :     const int nDots   = rIn.GetDotCount();
   10575           0 :     const int nDotLen = rIn.GetDotLen();
   10576             : 
   10577           0 :     for( int n  = 0; n < nDots; n++ )
   10578             :     {
   10579           0 :         rOut.m_aDashArray.push_back( nDotLen );
   10580           0 :         rOut.m_aDashArray.push_back( nDistance );
   10581             :     }
   10582             : 
   10583             :     // add LineJoin
   10584           0 :     switch(rIn.GetLineJoin())
   10585             :     {
   10586             :         case basegfx::B2DLineJoin::Bevel :
   10587             :         {
   10588           0 :             rOut.m_eJoin = PDFWriter::joinBevel;
   10589           0 :             break;
   10590             :         }
   10591             :         default : // basegfx::B2DLineJoin::NONE :
   10592             :         // Pdf has no 'none' lineJoin, default is miter
   10593             :         case basegfx::B2DLineJoin::Middle :
   10594             :         case basegfx::B2DLineJoin::Miter :
   10595             :         {
   10596           0 :             rOut.m_eJoin = PDFWriter::joinMiter;
   10597           0 :             break;
   10598             :         }
   10599             :         case basegfx::B2DLineJoin::Round :
   10600             :         {
   10601           0 :             rOut.m_eJoin = PDFWriter::joinRound;
   10602           0 :             break;
   10603             :         }
   10604             :     }
   10605             : 
   10606             :     // add LineCap
   10607           0 :     switch(rIn.GetLineCap())
   10608             :     {
   10609             :         default: /* com::sun::star::drawing::LineCap_BUTT */
   10610             :         {
   10611           0 :             rOut.m_eCap = PDFWriter::capButt;
   10612           0 :             break;
   10613             :         }
   10614             :         case com::sun::star::drawing::LineCap_ROUND:
   10615             :         {
   10616           0 :             rOut.m_eCap = PDFWriter::capRound;
   10617           0 :             break;
   10618             :         }
   10619             :         case com::sun::star::drawing::LineCap_SQUARE:
   10620             :         {
   10621           0 :             rOut.m_eCap = PDFWriter::capSquare;
   10622           0 :             break;
   10623             :         }
   10624             :     }
   10625           0 : }
   10626             : 
   10627           0 : void PDFWriterImpl::drawPolyLine( const Polygon& rPoly, const PDFWriter::ExtLineInfo& rInfo )
   10628             : {
   10629           0 :     MARK( "drawPolyLine with ExtLineInfo" );
   10630             : 
   10631           0 :     updateGraphicsState();
   10632             : 
   10633           0 :     if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) )
   10634           0 :         return;
   10635             : 
   10636           0 :     if( rInfo.m_fTransparency >= 1.0 )
   10637           0 :         return;
   10638             : 
   10639           0 :     if( rInfo.m_fTransparency != 0.0 )
   10640           0 :         beginTransparencyGroup();
   10641             : 
   10642           0 :     OStringBuffer aLine;
   10643           0 :     aLine.append( "q " );
   10644           0 :     m_aPages.back().appendMappedLength( rInfo.m_fLineWidth, aLine );
   10645           0 :     aLine.append( " w" );
   10646           0 :     if( rInfo.m_aDashArray.size() < 10 ) // implmentation limit of acrobat reader
   10647             :     {
   10648           0 :         switch( rInfo.m_eCap )
   10649             :         {
   10650             :             default:
   10651           0 :             case PDFWriter::capButt:   aLine.append( " 0 J" );break;
   10652           0 :             case PDFWriter::capRound:  aLine.append( " 1 J" );break;
   10653           0 :             case PDFWriter::capSquare: aLine.append( " 2 J" );break;
   10654             :         }
   10655           0 :         switch( rInfo.m_eJoin )
   10656             :         {
   10657             :             default:
   10658             :             case PDFWriter::joinMiter:
   10659             :             {
   10660           0 :                 double fLimit = rInfo.m_fMiterLimit;
   10661           0 :                 if( rInfo.m_fLineWidth < rInfo.m_fMiterLimit )
   10662           0 :                     fLimit = fLimit / rInfo.m_fLineWidth;
   10663           0 :                 if( fLimit < 1.0 )
   10664           0 :                     fLimit = 1.0;
   10665           0 :                 aLine.append( " 0 j " );
   10666           0 :                 appendDouble( fLimit, aLine );
   10667           0 :                 aLine.append( " M" );
   10668             :             }
   10669           0 :             break;
   10670           0 :             case PDFWriter::joinRound:  aLine.append( " 1 j" );break;
   10671           0 :             case PDFWriter::joinBevel:  aLine.append( " 2 j" );break;
   10672             :         }
   10673           0 :         if( rInfo.m_aDashArray.size() > 0 )
   10674             :         {
   10675           0 :             aLine.append( " [ " );
   10676           0 :             for( std::vector<double>::const_iterator it = rInfo.m_aDashArray.begin();
   10677           0 :                  it != rInfo.m_aDashArray.end(); ++it )
   10678             :             {
   10679           0 :                 m_aPages.back().appendMappedLength( *it, aLine );
   10680           0 :                 aLine.append( ' ' );
   10681             :             }
   10682           0 :             aLine.append( "] 0 d" );
   10683             :         }
   10684           0 :         aLine.append( "\n" );
   10685           0 :         writeBuffer( aLine.getStr(), aLine.getLength() );
   10686           0 :         drawPolyLine( rPoly );
   10687             :     }
   10688             :     else
   10689             :     {
   10690           0 :         basegfx::B2DPolygon aPoly(rPoly.getB2DPolygon());
   10691           0 :         basegfx::B2DPolyPolygon aPolyPoly;
   10692             : 
   10693           0 :         basegfx::tools::applyLineDashing(aPoly, rInfo.m_aDashArray, &aPolyPoly);
   10694             : 
   10695             :         // Old applyLineDashing subdivided the polygon. New one will create bezier curve segments.
   10696             :         // To mimic old behaviour, apply subdivide here. If beziers shall be written (better quality)
   10697             :         // this line needs to be removed and the loop below adapted accordingly
   10698           0 :         aPolyPoly = basegfx::tools::adaptiveSubdivideByAngle(aPolyPoly);
   10699             : 
   10700           0 :         const sal_uInt32 nPolygonCount(aPolyPoly.count());
   10701             : 
   10702           0 :         for( sal_uInt32 nPoly = 0; nPoly < nPolygonCount; nPoly++ )
   10703             :         {
   10704           0 :             aLine.append( (nPoly != 0 && (nPoly & 7) == 0) ? "\n" : " " );
   10705           0 :             aPoly = aPolyPoly.getB2DPolygon( nPoly );
   10706           0 :             const sal_uInt32 nPointCount(aPoly.count());
   10707             : 
   10708           0 :             if(nPointCount)
   10709             :             {
   10710           0 :                 const sal_uInt32 nEdgeCount(aPoly.isClosed() ? nPointCount : nPointCount - 1);
   10711           0 :                 basegfx::B2DPoint aCurrent(aPoly.getB2DPoint(0));
   10712             : 
   10713           0 :                 for(sal_uInt32 a(0); a < nEdgeCount; a++)
   10714             :                 {
   10715           0 :                     if( a > 0 )
   10716           0 :                         aLine.append( " " );
   10717           0 :                     const sal_uInt32 nNextIndex((a + 1) % nPointCount);
   10718           0 :                     const basegfx::B2DPoint aNext(aPoly.getB2DPoint(nNextIndex));
   10719             : 
   10720           0 :                     m_aPages.back().appendPoint( Point( FRound(aCurrent.getX()),
   10721             :                                                         FRound(aCurrent.getY()) ),
   10722           0 :                                                  aLine );
   10723           0 :                     aLine.append( " m " );
   10724           0 :                     m_aPages.back().appendPoint( Point( FRound(aNext.getX()),
   10725             :                                                         FRound(aNext.getY()) ),
   10726           0 :                                                  aLine );
   10727           0 :                     aLine.append( " l" );
   10728             : 
   10729             :                     // prepare next edge
   10730           0 :                     aCurrent = aNext;
   10731           0 :                 }
   10732             :             }
   10733             :         }
   10734           0 :         aLine.append( " S " );
   10735           0 :         writeBuffer( aLine.getStr(), aLine.getLength() );
   10736             :     }
   10737           0 :     writeBuffer( "Q\n", 2 );
   10738             : 
   10739           0 :     if( rInfo.m_fTransparency != 0.0 )
   10740             :     {
   10741             :         // FIXME: actually this may be incorrect with bezier polygons
   10742           0 :         Rectangle aBoundRect( rPoly.GetBoundRect() );
   10743             :         // avoid clipping with thick lines
   10744           0 :         if( rInfo.m_fLineWidth > 0.0 )
   10745             :         {
   10746           0 :             sal_Int32 nLW = sal_Int32(rInfo.m_fLineWidth);
   10747           0 :             aBoundRect.Top()    -= nLW;
   10748           0 :             aBoundRect.Left()   -= nLW;
   10749           0 :             aBoundRect.Right()  += nLW;
   10750           0 :             aBoundRect.Bottom() += nLW;
   10751             :         }
   10752           0 :         endTransparencyGroup( aBoundRect, (sal_uInt16)(100.0*rInfo.m_fTransparency) );
   10753           0 :     }
   10754             : }
   10755             : 
   10756           0 : void PDFWriterImpl::drawPixel( const Point& rPoint, const Color& rColor )
   10757             : {
   10758           0 :     MARK( "drawPixel" );
   10759             : 
   10760           0 :     Color aColor = ( rColor == Color( COL_TRANSPARENT ) ? m_aGraphicsStack.front().m_aLineColor : rColor );
   10761             : 
   10762           0 :     if( aColor == Color( COL_TRANSPARENT ) )
   10763           0 :         return;
   10764             : 
   10765             :     // pixels are drawn in line color, so have to set
   10766             :     // the nonstroking color to line color
   10767           0 :     Color aOldFillColor = m_aGraphicsStack.front().m_aFillColor;
   10768           0 :     setFillColor( aColor );
   10769             : 
   10770           0 :     updateGraphicsState();
   10771             : 
   10772           0 :     OStringBuffer aLine( 20 );
   10773           0 :     m_aPages.back().appendPoint( rPoint, aLine );
   10774           0 :     aLine.append( ' ' );
   10775           0 :     appendDouble( 1.0/double(getReferenceDevice()->GetDPIX()), aLine );
   10776           0 :     aLine.append( ' ' );
   10777           0 :     appendDouble( 1.0/double(getReferenceDevice()->GetDPIY()), aLine );
   10778           0 :     aLine.append( " re f\n" );
   10779           0 :     writeBuffer( aLine.getStr(), aLine.getLength() );
   10780             : 
   10781           0 :     setFillColor( aOldFillColor );
   10782             : }
   10783             : 
   10784             : class AccessReleaser
   10785             : {
   10786             :     BitmapReadAccess* m_pAccess;
   10787             : public:
   10788           0 :     explicit AccessReleaser( BitmapReadAccess* pAccess ) : m_pAccess( pAccess ){}
   10789           0 :     ~AccessReleaser() { delete m_pAccess; }
   10790             : };
   10791             : 
   10792           0 : bool PDFWriterImpl::writeTransparentObject( TransparencyEmit& rObject )
   10793             : {
   10794           0 :     CHECK_RETURN( updateObject( rObject.m_nObject ) );
   10795             : 
   10796           0 :     bool bFlateFilter = compressStream( rObject.m_pContentStream );
   10797           0 :     rObject.m_pContentStream->Seek( STREAM_SEEK_TO_END );
   10798           0 :     sal_uLong nSize = rObject.m_pContentStream->Tell();
   10799           0 :     rObject.m_pContentStream->Seek( STREAM_SEEK_TO_BEGIN );
   10800             :     #if OSL_DEBUG_LEVEL > 1
   10801             :     emitComment( "PDFWriterImpl::writeTransparentObject" );
   10802             :     #endif
   10803           0 :     OStringBuffer aLine( 512 );
   10804           0 :     CHECK_RETURN( updateObject( rObject.m_nObject ) );
   10805           0 :     aLine.append( rObject.m_nObject );
   10806             :     aLine.append( " 0 obj\n"
   10807             :                   "<</Type/XObject\n"
   10808             :                   "/Subtype/Form\n"
   10809           0 :                   "/BBox[ " );
   10810           0 :     appendFixedInt( rObject.m_aBoundRect.Left(), aLine );
   10811           0 :     aLine.append( ' ' );
   10812           0 :     appendFixedInt( rObject.m_aBoundRect.Top(), aLine );
   10813           0 :     aLine.append( ' ' );
   10814           0 :     appendFixedInt( rObject.m_aBoundRect.Right(), aLine );
   10815           0 :     aLine.append( ' ' );
   10816           0 :     appendFixedInt( rObject.m_aBoundRect.Bottom()+1, aLine );
   10817           0 :     aLine.append( " ]\n" );
   10818           0 :     if( ! rObject.m_pSoftMaskStream )
   10819             :     {
   10820           0 :         if( ! m_bIsPDF_A1 )
   10821             :         {
   10822           0 :             aLine.append( "/Group<</S/Transparency/CS/DeviceRGB/K true>>\n" );
   10823             :         }
   10824             :     }
   10825             :     /* #i42884# the PDF reference recommends that each Form XObject
   10826             :     *  should have a resource dict; alas if that is the same object
   10827             :     *  as the one of the page it triggers an endless recursion in
   10828             :     *  acroread 5 (6 and up have that fixed). Since we have only one
   10829             :     *  resource dict anyway, let's use the one from the page by NOT
   10830             :     *  emitting a Resources entry.
   10831             :     */
   10832             : 
   10833           0 :     aLine.append( "/Length " );
   10834           0 :     aLine.append( (sal_Int32)(nSize) );
   10835           0 :     aLine.append( "\n" );
   10836           0 :     if( bFlateFilter )
   10837           0 :         aLine.append( "/Filter/FlateDecode\n" );
   10838             :     aLine.append( ">>\n"
   10839           0 :                   "stream\n" );
   10840           0 :     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
   10841           0 :     checkAndEnableStreamEncryption( rObject.m_nObject );
   10842           0 :     CHECK_RETURN( writeBuffer( rObject.m_pContentStream->GetData(), nSize ) );
   10843           0 :     disableStreamEncryption();
   10844           0 :     aLine.setLength( 0 );
   10845             :     aLine.append( "\n"
   10846             :                   "endstream\n"
   10847           0 :                   "endobj\n\n" );
   10848           0 :     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
   10849             : 
   10850             :     // write ExtGState dict for this XObject
   10851           0 :     aLine.setLength( 0 );
   10852           0 :     aLine.append( rObject.m_nExtGStateObject );
   10853             :     aLine.append( " 0 obj\n"
   10854           0 :                   "<<" );
   10855           0 :     if( ! rObject.m_pSoftMaskStream )
   10856             :     {
   10857             : //i59651
   10858           0 :         if( m_bIsPDF_A1 )
   10859             :         {
   10860           0 :             aLine.append( "/CA 1.0/ca 1.0" );
   10861           0 :             m_aErrors.insert( PDFWriter::Warning_Transparency_Omitted_PDFA );
   10862             :         }
   10863             :         else
   10864             :         {
   10865           0 :             aLine.append(  "/CA " );
   10866           0 :             appendDouble( rObject.m_fAlpha, aLine );
   10867             :             aLine.append( "\n"
   10868           0 :                           "   /ca " );
   10869           0 :             appendDouble( rObject.m_fAlpha, aLine );
   10870             :         }
   10871           0 :         aLine.append( "\n" );
   10872             :     }
   10873             :     else
   10874             :     {
   10875           0 :         if( m_bIsPDF_A1 )
   10876             :         {
   10877           0 :             aLine.append( "/SMask/None" );
   10878           0 :             m_aErrors.insert( PDFWriter::Warning_Transparency_Omitted_PDFA );
   10879             :         }
   10880             :         else
   10881             :         {
   10882           0 :             rObject.m_pSoftMaskStream->Seek( STREAM_SEEK_TO_END );
   10883           0 :             sal_Int32 nMaskSize = (sal_Int32)rObject.m_pSoftMaskStream->Tell();
   10884           0 :             rObject.m_pSoftMaskStream->Seek( STREAM_SEEK_TO_BEGIN );
   10885           0 :             sal_Int32 nMaskObject = createObject();
   10886           0 :             aLine.append( "/SMask<</Type/Mask/S/Luminosity/G " );
   10887           0 :             aLine.append( nMaskObject );
   10888           0 :             aLine.append( " 0 R>>\n" );
   10889             : 
   10890           0 :             OStringBuffer aMask;
   10891           0 :             aMask.append( nMaskObject );
   10892             :             aMask.append( " 0 obj\n"
   10893             :                           "<</Type/XObject\n"
   10894             :                           "/Subtype/Form\n"
   10895           0 :                           "/BBox[" );
   10896           0 :             appendFixedInt( rObject.m_aBoundRect.Left(), aMask );
   10897           0 :             aMask.append( ' ' );
   10898           0 :             appendFixedInt( rObject.m_aBoundRect.Top(), aMask );
   10899           0 :             aMask.append( ' ' );
   10900           0 :             appendFixedInt( rObject.m_aBoundRect.Right(), aMask );
   10901           0 :             aMask.append( ' ' );
   10902           0 :             appendFixedInt( rObject.m_aBoundRect.Bottom()+1, aMask );
   10903           0 :             aMask.append( "]\n" );
   10904             : 
   10905             :             /* #i42884# see above */
   10906           0 :             aMask.append( "/Group<</S/Transparency/CS/DeviceRGB>>\n" );
   10907           0 :             aMask.append( "/Length " );
   10908           0 :             aMask.append( nMaskSize );
   10909             :             aMask.append( ">>\n"
   10910           0 :                           "stream\n" );
   10911           0 :             CHECK_RETURN( updateObject( nMaskObject ) );
   10912           0 :             checkAndEnableStreamEncryption(  nMaskObject );
   10913           0 :             CHECK_RETURN( writeBuffer( aMask.getStr(), aMask.getLength() ) );
   10914           0 :             CHECK_RETURN( writeBuffer( rObject.m_pSoftMaskStream->GetData(), nMaskSize ) );
   10915           0 :             disableStreamEncryption();
   10916           0 :             aMask.setLength( 0 );
   10917             :             aMask.append( "\nendstream\n"
   10918           0 :                           "endobj\n\n" );
   10919           0 :             CHECK_RETURN( writeBuffer( aMask.getStr(), aMask.getLength() ) );
   10920             :         }
   10921             :     }
   10922             :     aLine.append( ">>\n"
   10923           0 :                   "endobj\n\n" );
   10924           0 :     CHECK_RETURN( updateObject( rObject.m_nExtGStateObject ) );
   10925           0 :     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
   10926             : 
   10927           0 :     return true;
   10928             : }
   10929             : 
   10930           0 : bool PDFWriterImpl::writeGradientFunction( GradientEmit& rObject )
   10931             : {
   10932             :     // LO internal gradient -> PDF shading type:
   10933             :     //  * GradientStyle_LINEAR: axial shading, using sampled-function with 2 samples
   10934             :     //                          [t=0:colorStart, t=1:colorEnd]
   10935             :     //  * GradientStyle_AXIAL: axial shading, using sampled-function with 3 samples
   10936             :     //                          [t=0:colorEnd, t=0.5:colorStart, t=1:colorEnd]
   10937             :     //  * other styles: function shading with aSize.Width() * aSize.Height() samples
   10938           0 :     sal_Int32 nFunctionObject = createObject();
   10939           0 :     CHECK_RETURN( updateObject( nFunctionObject ) );
   10940             : 
   10941           0 :     ScopedVclPtrInstance< VirtualDevice > aDev;
   10942           0 :     aDev->SetOutputSizePixel( rObject.m_aSize );
   10943           0 :     aDev->SetMapMode( MapMode( MAP_PIXEL ) );
   10944           0 :     if( m_aContext.ColorMode == PDFWriter::DrawGreyscale )
   10945           0 :         aDev->SetDrawMode( aDev->GetDrawMode() |
   10946             :                           ( DrawModeFlags::GrayLine | DrawModeFlags::GrayFill | DrawModeFlags::GrayText |
   10947           0 :                             DrawModeFlags::GrayBitmap | DrawModeFlags::GrayGradient ) );
   10948           0 :     aDev->DrawGradient( Rectangle( Point( 0, 0 ), rObject.m_aSize ), rObject.m_aGradient );
   10949             : 
   10950           0 :     Bitmap aSample = aDev->GetBitmap( Point( 0, 0 ), rObject.m_aSize );
   10951           0 :     BitmapReadAccess* pAccess = aSample.AcquireReadAccess();
   10952           0 :     AccessReleaser aReleaser( pAccess );
   10953             : 
   10954           0 :     Size aSize = aSample.GetSizePixel();
   10955             : 
   10956           0 :     sal_Int32 nStreamLengthObject = createObject();
   10957             :     #if OSL_DEBUG_LEVEL > 1
   10958             :     emitComment( "PDFWriterImpl::writeGradientFunction" );
   10959             :     #endif
   10960           0 :     OStringBuffer aLine( 120 );
   10961           0 :     aLine.append( nFunctionObject );
   10962             :     aLine.append( " 0 obj\n"
   10963           0 :                   "<</FunctionType 0\n");
   10964           0 :     switch (rObject.m_aGradient.GetStyle())
   10965             :     {
   10966             :         case GradientStyle_LINEAR:
   10967             :         case GradientStyle_AXIAL:
   10968           0 :             aLine.append("/Domain[ 0 1]\n");
   10969           0 :             break;
   10970             :         default:
   10971           0 :             aLine.append("/Domain[ 0 1 0 1]\n");
   10972             :     }
   10973           0 :     aLine.append("/Size[ " );
   10974           0 :     switch (rObject.m_aGradient.GetStyle())
   10975             :     {
   10976             :         case GradientStyle_LINEAR:
   10977           0 :             aLine.append('2');
   10978           0 :             break;
   10979             :         case GradientStyle_AXIAL:
   10980           0 :             aLine.append('3');
   10981           0 :             break;
   10982             :         default:
   10983           0 :             aLine.append( (sal_Int32)aSize.Width() );
   10984           0 :             aLine.append( ' ' );
   10985           0 :             aLine.append( (sal_Int32)aSize.Height() );
   10986             :     }
   10987             :     aLine.append( " ]\n"
   10988             :                   "/BitsPerSample 8\n"
   10989             :                   "/Range[ 0 1 0 1 0 1 ]\n"
   10990             :                   "/Order 3\n"
   10991           0 :                   "/Length " );
   10992           0 :     aLine.append( nStreamLengthObject );
   10993             :     aLine.append( " 0 R\n"
   10994             : #ifndef DEBUG_DISABLE_PDFCOMPRESSION
   10995             :                   "/Filter/FlateDecode"
   10996             : #endif
   10997             :                   ">>\n"
   10998           0 :                   "stream\n" );
   10999           0 :     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
   11000             : 
   11001           0 :     sal_uInt64 nStartStreamPos = 0;
   11002           0 :     CHECK_RETURN( (osl::File::E_None == m_aFile.getPos(nStartStreamPos)) );
   11003             : 
   11004           0 :     checkAndEnableStreamEncryption( nFunctionObject );
   11005           0 :     beginCompression();
   11006             :     sal_uInt8 aCol[3];
   11007           0 :     switch (rObject.m_aGradient.GetStyle())
   11008             :     {
   11009             :         case GradientStyle_AXIAL:
   11010           0 :             aCol[0] = rObject.m_aGradient.GetEndColor().GetRed();
   11011           0 :             aCol[1] = rObject.m_aGradient.GetEndColor().GetGreen();
   11012           0 :             aCol[2] = rObject.m_aGradient.GetEndColor().GetBlue();
   11013           0 :             CHECK_RETURN( writeBuffer( aCol, 3 ) );
   11014             :             // fall-through
   11015             :         case GradientStyle_LINEAR:
   11016             :         {
   11017           0 :             aCol[0] = rObject.m_aGradient.GetStartColor().GetRed();
   11018           0 :             aCol[1] = rObject.m_aGradient.GetStartColor().GetGreen();
   11019           0 :             aCol[2] = rObject.m_aGradient.GetStartColor().GetBlue();
   11020           0 :             CHECK_RETURN( writeBuffer( aCol, 3 ) );
   11021             : 
   11022           0 :             aCol[0] = rObject.m_aGradient.GetEndColor().GetRed();
   11023           0 :             aCol[1] = rObject.m_aGradient.GetEndColor().GetGreen();
   11024           0 :             aCol[2] = rObject.m_aGradient.GetEndColor().GetBlue();
   11025           0 :             CHECK_RETURN( writeBuffer( aCol, 3 ) );
   11026           0 :             break;
   11027             :         }
   11028             :         default:
   11029           0 :             for( int y = aSize.Height()-1; y >= 0; y-- )
   11030             :             {
   11031           0 :                 for( long x = 0; x < aSize.Width(); x++ )
   11032             :                 {
   11033           0 :                     BitmapColor aColor = pAccess->GetColor( y, x );
   11034           0 :                     aCol[0] = aColor.GetRed();
   11035           0 :                     aCol[1] = aColor.GetGreen();
   11036           0 :                     aCol[2] = aColor.GetBlue();
   11037           0 :                     CHECK_RETURN( writeBuffer( aCol, 3 ) );
   11038           0 :                 }
   11039             :             }
   11040             :     }
   11041           0 :     endCompression();
   11042           0 :     disableStreamEncryption();
   11043             : 
   11044           0 :     sal_uInt64 nEndStreamPos = 0;
   11045           0 :     CHECK_RETURN( (osl::File::E_None == m_aFile.getPos(nEndStreamPos)) );
   11046             : 
   11047           0 :     aLine.setLength( 0 );
   11048           0 :     aLine.append( "\nendstream\nendobj\n\n" );
   11049           0 :     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
   11050             : 
   11051             :     // write stream length
   11052           0 :     CHECK_RETURN( updateObject( nStreamLengthObject ) );
   11053           0 :     aLine.setLength( 0 );
   11054           0 :     aLine.append( nStreamLengthObject );
   11055           0 :     aLine.append( " 0 obj\n" );
   11056           0 :     aLine.append( (sal_Int64)(nEndStreamPos-nStartStreamPos) );
   11057           0 :     aLine.append( "\nendobj\n\n" );
   11058           0 :     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
   11059             : 
   11060           0 :     CHECK_RETURN( updateObject( rObject.m_nObject ) );
   11061           0 :     aLine.setLength( 0 );
   11062           0 :     aLine.append( rObject.m_nObject );
   11063           0 :     aLine.append( " 0 obj\n");
   11064           0 :     switch (rObject.m_aGradient.GetStyle())
   11065             :     {
   11066             :         case GradientStyle_LINEAR:
   11067             :         case GradientStyle_AXIAL:
   11068           0 :             aLine.append("<</ShadingType 2\n");
   11069           0 :             break;
   11070             :         default:
   11071           0 :             aLine.append("<</ShadingType 1\n");
   11072             :     }
   11073             :     aLine.append("/ColorSpace/DeviceRGB\n"
   11074           0 :                   "/AntiAlias true\n");
   11075             : 
   11076             :     // Determination of shading axis
   11077             :     // See: OutputDevice::ImplDrawLinearGradient for reference
   11078           0 :     Rectangle aRect;
   11079           0 :     aRect.Left() = aRect.Top() = 0;
   11080           0 :     aRect.Right() = aSize.Width();
   11081           0 :     aRect.Bottom() = aSize.Height();
   11082             : 
   11083           0 :     Rectangle aBoundRect;
   11084           0 :     Point     aCenter;
   11085           0 :     sal_uInt16    nAngle = rObject.m_aGradient.GetAngle() % 3600;
   11086           0 :     rObject.m_aGradient.GetBoundRect( aRect, aBoundRect, aCenter );
   11087             : 
   11088           0 :     const bool bLinear = (rObject.m_aGradient.GetStyle() == GradientStyle_LINEAR);
   11089           0 :     double fBorder = aBoundRect.GetHeight() * rObject.m_aGradient.GetBorder() / 100.0;
   11090           0 :     if ( !bLinear )
   11091             :     {
   11092           0 :         fBorder /= 2.0;
   11093             :     }
   11094             : 
   11095           0 :     aBoundRect.Bottom() -= fBorder;
   11096           0 :     if (!bLinear)
   11097             :     {
   11098           0 :         aBoundRect.Top() += fBorder;
   11099             :     }
   11100             : 
   11101           0 :     switch (rObject.m_aGradient.GetStyle())
   11102             :     {
   11103             :         case GradientStyle_LINEAR:
   11104             :         case GradientStyle_AXIAL:
   11105             :         {
   11106             :             aLine.append("/Domain[ 0 1 ]\n"
   11107           0 :                     "/Coords[ " );
   11108           0 :             Polygon     aPoly( 2 );
   11109           0 :             aPoly[0] = aBoundRect.BottomCenter();
   11110           0 :             aPoly[1] = aBoundRect.TopCenter();
   11111           0 :             aPoly.Rotate( aCenter, 3600 - nAngle );
   11112             : 
   11113           0 :             aLine.append( (sal_Int32) aPoly[0].X() );
   11114           0 :             aLine.append( " " );
   11115           0 :             aLine.append( (sal_Int32) aPoly[0].Y() );
   11116           0 :             aLine.append( " " );
   11117           0 :             aLine.append( (sal_Int32) aPoly[1].X());
   11118           0 :             aLine.append( " ");
   11119           0 :             aLine.append( (sal_Int32) aPoly[1].Y());
   11120           0 :             aLine.append( " ]\n");
   11121           0 :             aLine.append("/Extend [true true]\n");
   11122           0 :             break;
   11123             :         }
   11124             :         default:
   11125             :             aLine.append("/Domain[ 0 1 0 1 ]\n"
   11126           0 :                     "/Matrix[ " );
   11127           0 :             aLine.append( (sal_Int32)aSize.Width() );
   11128           0 :             aLine.append( " 0 0 " );
   11129           0 :             aLine.append( (sal_Int32)aSize.Height() );
   11130           0 :             aLine.append( " 0 0 ]\n");
   11131             :     }
   11132           0 :     aLine.append("/Function " );
   11133           0 :     aLine.append( nFunctionObject );
   11134             :     aLine.append( " 0 R\n"
   11135             :                   ">>\n"
   11136           0 :                   "endobj\n\n" );
   11137           0 :     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
   11138             : 
   11139           0 :     return true;
   11140             : }
   11141             : 
   11142           0 : bool PDFWriterImpl::writeJPG( JPGEmit& rObject )
   11143             : {
   11144           0 :     CHECK_RETURN( rObject.m_pStream );
   11145           0 :     CHECK_RETURN( updateObject( rObject.m_nObject ) );
   11146             : 
   11147           0 :     sal_Int32 nLength = 0;
   11148           0 :     rObject.m_pStream->Seek( STREAM_SEEK_TO_END );
   11149           0 :     nLength = rObject.m_pStream->Tell();
   11150           0 :     rObject.m_pStream->Seek( STREAM_SEEK_TO_BEGIN );
   11151             : 
   11152           0 :     sal_Int32 nMaskObject = 0;
   11153           0 :     if( !!rObject.m_aMask )
   11154             :     {
   11155           0 :         if( rObject.m_aMask.GetBitCount() == 1 ||
   11156           0 :             ( rObject.m_aMask.GetBitCount() == 8 && m_aContext.Version >= PDFWriter::PDF_1_4 && !m_bIsPDF_A1 )//i59651
   11157             :             )
   11158             :         {
   11159           0 :             nMaskObject = createObject();
   11160             :         }
   11161           0 :         else if( m_bIsPDF_A1 )
   11162           0 :             m_aErrors.insert( PDFWriter::Warning_Transparency_Omitted_PDFA );
   11163           0 :         else if( m_aContext.Version < PDFWriter::PDF_1_4 )
   11164           0 :             m_aErrors.insert( PDFWriter::Warning_Transparency_Omitted_PDF13 );
   11165             : 
   11166             :     }
   11167             :     #if OSL_DEBUG_LEVEL > 1
   11168             :     emitComment( "PDFWriterImpl::writeJPG" );
   11169             :     #endif
   11170             : 
   11171           0 :     OStringBuffer aLine(200);
   11172           0 :     aLine.append( rObject.m_nObject );
   11173             :     aLine.append( " 0 obj\n"
   11174           0 :                   "<</Type/XObject/Subtype/Image/Width " );
   11175           0 :     aLine.append( (sal_Int32)rObject.m_aID.m_aPixelSize.Width() );
   11176           0 :     aLine.append( " /Height " );
   11177           0 :     aLine.append( (sal_Int32)rObject.m_aID.m_aPixelSize.Height() );
   11178           0 :     aLine.append( " /BitsPerComponent 8 " );
   11179           0 :     if( rObject.m_bTrueColor )
   11180           0 :         aLine.append( "/ColorSpace/DeviceRGB" );
   11181             :     else
   11182           0 :         aLine.append( "/ColorSpace/DeviceGray" );
   11183           0 :     aLine.append( "/Filter/DCTDecode/Length " );
   11184           0 :     aLine.append( nLength );
   11185           0 :     if( nMaskObject )
   11186             :     {
   11187           0 :         aLine.append( rObject.m_aMask.GetBitCount() == 1 ? " /Mask " : " /SMask " );
   11188           0 :         aLine.append( nMaskObject );
   11189           0 :         aLine.append( " 0 R " );
   11190             :     }
   11191           0 :     aLine.append( ">>\nstream\n" );
   11192           0 :     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
   11193             : 
   11194           0 :     checkAndEnableStreamEncryption( rObject.m_nObject );
   11195           0 :     CHECK_RETURN( writeBuffer( rObject.m_pStream->GetData(), nLength ) );
   11196           0 :     disableStreamEncryption();
   11197             : 
   11198           0 :     aLine.setLength( 0 );
   11199           0 :     aLine.append( "\nendstream\nendobj\n\n" );
   11200           0 :     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
   11201             : 
   11202           0 :     if( nMaskObject )
   11203             :     {
   11204           0 :         BitmapEmit aEmit;
   11205           0 :         aEmit.m_nObject = nMaskObject;
   11206           0 :         if( rObject.m_aMask.GetBitCount() == 1 )
   11207           0 :             aEmit.m_aBitmap = BitmapEx( rObject.m_aMask, rObject.m_aMask );
   11208           0 :         else if( rObject.m_aMask.GetBitCount() == 8 )
   11209           0 :             aEmit.m_aBitmap = BitmapEx( rObject.m_aMask, AlphaMask( rObject.m_aMask ) );
   11210           0 :         writeBitmapObject( aEmit, true );
   11211             :     }
   11212             : 
   11213           0 :     return true;
   11214             : }
   11215             : 
   11216           0 : bool PDFWriterImpl::writeBitmapObject( BitmapEmit& rObject, bool bMask )
   11217             : {
   11218           0 :     CHECK_RETURN( updateObject( rObject.m_nObject ) );
   11219             : 
   11220           0 :     Bitmap  aBitmap;
   11221           0 :     Color   aTransparentColor( COL_TRANSPARENT );
   11222           0 :     bool    bWriteMask = false;
   11223           0 :     if( ! bMask )
   11224             :     {
   11225           0 :         aBitmap = rObject.m_aBitmap.GetBitmap();
   11226           0 :         if( rObject.m_aBitmap.IsAlpha() )
   11227             :         {
   11228           0 :             if( m_aContext.Version >= PDFWriter::PDF_1_4 )
   11229           0 :                 bWriteMask = true;
   11230             :             // else draw without alpha channel
   11231             :         }
   11232             :         else
   11233             :         {
   11234           0 :             switch( rObject.m_aBitmap.GetTransparentType() )
   11235             :             {
   11236             :                 case TRANSPARENT_NONE:
   11237             :                     // comes from drawMask function
   11238           0 :                     if( aBitmap.GetBitCount() == 1 && rObject.m_bDrawMask )
   11239           0 :                         bMask = true;
   11240           0 :                     break;
   11241             :                 case TRANSPARENT_COLOR:
   11242           0 :                     aTransparentColor = rObject.m_aBitmap.GetTransparentColor();
   11243           0 :                     break;
   11244             :                 case TRANSPARENT_BITMAP:
   11245           0 :                     bWriteMask = true;
   11246           0 :                     break;
   11247             :             }
   11248             :         }
   11249             :     }
   11250             :     else
   11251             :     {
   11252           0 :         if( m_aContext.Version < PDFWriter::PDF_1_4 || ! rObject.m_aBitmap.IsAlpha() )
   11253             :         {
   11254           0 :             aBitmap = rObject.m_aBitmap.GetMask();
   11255           0 :             aBitmap.Convert( BMP_CONVERSION_1BIT_THRESHOLD );
   11256             :             DBG_ASSERT( aBitmap.GetBitCount() == 1, "mask conversion failed" );
   11257             :         }
   11258           0 :         else if( aBitmap.GetBitCount() != 8 )
   11259             :         {
   11260           0 :             aBitmap = rObject.m_aBitmap.GetAlpha().GetBitmap();
   11261           0 :             aBitmap.Convert( BMP_CONVERSION_8BIT_GREYS );
   11262             :             DBG_ASSERT( aBitmap.GetBitCount() == 8, "alpha mask conversion failed" );
   11263             :         }
   11264             :     }
   11265             : 
   11266           0 :     BitmapReadAccess* pAccess = aBitmap.AcquireReadAccess();
   11267           0 :     AccessReleaser aReleaser( pAccess );
   11268             : 
   11269             :     bool bTrueColor;
   11270             :     sal_Int32 nBitsPerComponent;
   11271           0 :     switch( aBitmap.GetBitCount() )
   11272             :     {
   11273             :         case 1:
   11274             :         case 2:
   11275             :         case 4:
   11276             :         case 8:
   11277           0 :             bTrueColor = false;
   11278           0 :             nBitsPerComponent = aBitmap.GetBitCount();
   11279           0 :             break;
   11280             :         default:
   11281           0 :             bTrueColor = true;
   11282           0 :             nBitsPerComponent = 8;
   11283           0 :             break;
   11284             :     }
   11285             : 
   11286           0 :     sal_Int32 nStreamLengthObject   = createObject();
   11287           0 :     sal_Int32 nMaskObject           = 0;
   11288             : 
   11289             :     #if OSL_DEBUG_LEVEL > 1
   11290             :     emitComment( "PDFWriterImpl::writeBitmapObject" );
   11291             :     #endif
   11292           0 :     OStringBuffer aLine(1024);
   11293           0 :     aLine.append( rObject.m_nObject );
   11294             :     aLine.append( " 0 obj\n"
   11295           0 :                   "<</Type/XObject/Subtype/Image/Width " );
   11296           0 :     aLine.append( (sal_Int32)aBitmap.GetSizePixel().Width() );
   11297           0 :     aLine.append( "/Height " );
   11298           0 :     aLine.append( (sal_Int32)aBitmap.GetSizePixel().Height() );
   11299           0 :     aLine.append( "/BitsPerComponent " );
   11300           0 :     aLine.append( nBitsPerComponent );
   11301           0 :     aLine.append( "/Length " );
   11302           0 :     aLine.append( nStreamLengthObject );
   11303           0 :     aLine.append( " 0 R\n" );
   11304             : #ifndef DEBUG_DISABLE_PDFCOMPRESSION
   11305           0 :     if( nBitsPerComponent != 1 )
   11306             :     {
   11307           0 :         aLine.append( "/Filter/FlateDecode" );
   11308             :     }
   11309             :     else
   11310             :     {
   11311           0 :         aLine.append( "/Filter/CCITTFaxDecode/DecodeParms<</K -1/BlackIs1 true/Columns " );
   11312           0 :         aLine.append( (sal_Int32)aBitmap.GetSizePixel().Width() );
   11313           0 :         aLine.append( ">>\n" );
   11314             :     }
   11315             : #endif
   11316           0 :     if( ! bMask )
   11317             :     {
   11318           0 :         aLine.append( "/ColorSpace" );
   11319           0 :         if( bTrueColor )
   11320           0 :             aLine.append( "/DeviceRGB\n" );
   11321           0 :         else if( aBitmap.HasGreyPalette() )
   11322             :         {
   11323           0 :             aLine.append( "/DeviceGray\n" );
   11324           0 :             if( aBitmap.GetBitCount() == 1 )
   11325             :             {
   11326             :                 // #i47395# 1 bit bitmaps occasionally have an inverted grey palette
   11327           0 :                 sal_Int32 nBlackIndex = pAccess->GetBestPaletteIndex( BitmapColor( Color( COL_BLACK ) ) );
   11328             :                 DBG_ASSERT( nBlackIndex == 0 || nBlackIndex == 1, "wrong black index" );
   11329           0 :                 if( nBlackIndex == 1 )
   11330           0 :                     aLine.append( "/Decode[1 0]\n" );
   11331             :             }
   11332             :         }
   11333             :         else
   11334             :         {
   11335           0 :             aLine.append( "[ /Indexed/DeviceRGB " );
   11336           0 :             aLine.append( (sal_Int32)(pAccess->GetPaletteEntryCount()-1) );
   11337           0 :             aLine.append( "\n<" );
   11338           0 :             if( m_aContext.Encryption.Encrypt() )
   11339             :             {
   11340           0 :                 enableStringEncryption( rObject.m_nObject );
   11341             :                 //check encryption buffer size
   11342           0 :                 if( checkEncryptionBufferSize( pAccess->GetPaletteEntryCount()*3 ) )
   11343             :                 {
   11344           0 :                     int nChar = 0;
   11345             :                     //fill the encryption buffer
   11346           0 :                     for( sal_uInt16 i = 0; i < pAccess->GetPaletteEntryCount(); i++ )
   11347             :                     {
   11348           0 :                         const BitmapColor& rColor = pAccess->GetPaletteColor( i );
   11349           0 :                         m_pEncryptionBuffer[nChar++] = rColor.GetRed();
   11350           0 :                         m_pEncryptionBuffer[nChar++] = rColor.GetGreen();
   11351           0 :                         m_pEncryptionBuffer[nChar++] = rColor.GetBlue();
   11352             :                     }
   11353             :                     //encrypt the colorspace lookup table
   11354           0 :                     rtl_cipher_encodeARCFOUR( m_aCipher, m_pEncryptionBuffer, nChar, m_pEncryptionBuffer, nChar );
   11355             :                     //now queue the data for output
   11356           0 :                     nChar = 0;
   11357           0 :                     for( sal_uInt16 i = 0; i < pAccess->GetPaletteEntryCount(); i++ )
   11358             :                     {
   11359           0 :                         appendHex(m_pEncryptionBuffer[nChar++], aLine );
   11360           0 :                         appendHex(m_pEncryptionBuffer[nChar++], aLine );
   11361           0 :                         appendHex(m_pEncryptionBuffer[nChar++], aLine );
   11362             :                     }
   11363             :                 }
   11364             :             }
   11365             :             else //no encryption requested (PDF/A-1a program flow drops here)
   11366             :             {
   11367           0 :                 for( sal_uInt16 i = 0; i < pAccess->GetPaletteEntryCount(); i++ )
   11368             :                 {
   11369           0 :                     const BitmapColor& rColor = pAccess->GetPaletteColor( i );
   11370           0 :                     appendHex( rColor.GetRed(), aLine );
   11371           0 :                     appendHex( rColor.GetGreen(), aLine );
   11372           0 :                     appendHex( rColor.GetBlue(), aLine );
   11373             :                 }
   11374             :             }
   11375           0 :             aLine.append( ">\n]\n" );
   11376             :         }
   11377             :     }
   11378             :     else
   11379             :     {
   11380           0 :         if( aBitmap.GetBitCount() == 1 )
   11381             :         {
   11382           0 :             aLine.append( "/ImageMask true\n" );
   11383           0 :             sal_Int32 nBlackIndex = pAccess->GetBestPaletteIndex( BitmapColor( Color( COL_BLACK ) ) );
   11384             :             DBG_ASSERT( nBlackIndex == 0 || nBlackIndex == 1, "wrong black index" );
   11385           0 :             if( nBlackIndex )
   11386           0 :                 aLine.append( "/Decode[ 1 0 ]\n" );
   11387             :             else
   11388           0 :                 aLine.append( "/Decode[ 0 1 ]\n" );
   11389             :         }
   11390           0 :         else if( aBitmap.GetBitCount() == 8 )
   11391             :         {
   11392             :             aLine.append( "/ColorSpace/DeviceGray\n"
   11393           0 :                           "/Decode [ 1 0 ]\n" );
   11394             :         }
   11395             :     }
   11396             : 
   11397           0 :     if( ! bMask && m_aContext.Version > PDFWriter::PDF_1_2 && !m_bIsPDF_A1 )//i59651
   11398             :     {
   11399           0 :         if( bWriteMask )
   11400             :         {
   11401           0 :             nMaskObject = createObject();
   11402           0 :             if( rObject.m_aBitmap.IsAlpha() && m_aContext.Version > PDFWriter::PDF_1_3 )
   11403           0 :                 aLine.append( "/SMask " );
   11404             :             else
   11405           0 :                 aLine.append( "/Mask " );
   11406           0 :             aLine.append( nMaskObject );
   11407           0 :             aLine.append( " 0 R\n" );
   11408             :         }
   11409           0 :         else if( aTransparentColor != Color( COL_TRANSPARENT ) )
   11410             :         {
   11411           0 :             aLine.append( "/Mask[ " );
   11412           0 :             if( bTrueColor )
   11413             :             {
   11414           0 :                 aLine.append( (sal_Int32)aTransparentColor.GetRed() );
   11415           0 :                 aLine.append( ' ' );
   11416           0 :                 aLine.append( (sal_Int32)aTransparentColor.GetRed() );
   11417           0 :                 aLine.append( ' ' );
   11418           0 :                 aLine.append( (sal_Int32)aTransparentColor.GetGreen() );
   11419           0 :                 aLine.append( ' ' );
   11420           0 :                 aLine.append( (sal_Int32)aTransparentColor.GetGreen() );
   11421           0 :                 aLine.append( ' ' );
   11422           0 :                 aLine.append( (sal_Int32)aTransparentColor.GetBlue() );
   11423           0 :                 aLine.append( ' ' );
   11424           0 :                 aLine.append( (sal_Int32)aTransparentColor.GetBlue() );
   11425             :             }
   11426             :             else
   11427             :             {
   11428           0 :                 sal_Int32 nIndex = pAccess->GetBestPaletteIndex( BitmapColor( aTransparentColor ) );
   11429           0 :                 aLine.append( nIndex );
   11430             :             }
   11431           0 :             aLine.append( " ]\n" );
   11432           0 :         }
   11433             :     }
   11434           0 :     else if( m_bIsPDF_A1 && (bWriteMask || aTransparentColor != Color( COL_TRANSPARENT )) )
   11435           0 :         m_aErrors.insert( PDFWriter::Warning_Transparency_Omitted_PDFA );
   11436             : 
   11437             :     aLine.append( ">>\n"
   11438           0 :                   "stream\n" );
   11439           0 :     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
   11440           0 :     sal_uInt64 nStartPos = 0;
   11441           0 :     CHECK_RETURN( (osl::File::E_None == m_aFile.getPos(nStartPos)) );
   11442             : 
   11443           0 :     checkAndEnableStreamEncryption( rObject.m_nObject );
   11444             : #ifndef DEBUG_DISABLE_PDFCOMPRESSION
   11445           0 :     if( nBitsPerComponent == 1 )
   11446             :     {
   11447           0 :         writeG4Stream( pAccess );
   11448             :     }
   11449             :     else
   11450             : #endif
   11451             :     {
   11452           0 :         beginCompression();
   11453           0 :         if( ! bTrueColor || pAccess->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB )
   11454             :         {
   11455           0 :             const int nScanLineBytes = 1 + ( pAccess->GetBitCount() * ( pAccess->Width() - 1 ) / 8U );
   11456             : 
   11457           0 :             for( long i = 0; i < pAccess->Height(); i++ )
   11458             :             {
   11459           0 :                 CHECK_RETURN( writeBuffer( pAccess->GetScanline( i ), nScanLineBytes ) );
   11460             :             }
   11461             :         }
   11462             :         else
   11463             :         {
   11464           0 :             const int nScanLineBytes = pAccess->Width()*3;
   11465           0 :             boost::shared_array<sal_uInt8> pCol( new sal_uInt8[ nScanLineBytes ] );
   11466           0 :             for( long y = 0; y < pAccess->Height(); y++ )
   11467             :             {
   11468           0 :                 for( long x = 0; x < pAccess->Width(); x++ )
   11469             :                 {
   11470           0 :                     BitmapColor aColor = pAccess->GetColor( y, x );
   11471           0 :                     pCol[3*x+0] = aColor.GetRed();
   11472           0 :                     pCol[3*x+1] = aColor.GetGreen();
   11473           0 :                     pCol[3*x+2] = aColor.GetBlue();
   11474           0 :                 }
   11475           0 :                 CHECK_RETURN( writeBuffer( pCol.get(), nScanLineBytes ) );
   11476           0 :             }
   11477             :         }
   11478           0 :         endCompression();
   11479             :     }
   11480           0 :     disableStreamEncryption();
   11481             : 
   11482           0 :     sal_uInt64 nEndPos = 0;
   11483           0 :     CHECK_RETURN( (osl::File::E_None == m_aFile.getPos(nEndPos)) );
   11484           0 :     aLine.setLength( 0 );
   11485           0 :     aLine.append( "\nendstream\nendobj\n\n" );
   11486           0 :     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
   11487           0 :     CHECK_RETURN( updateObject( nStreamLengthObject ) );
   11488           0 :     aLine.setLength( 0 );
   11489           0 :     aLine.append( nStreamLengthObject );
   11490           0 :     aLine.append( " 0 obj\n" );
   11491           0 :     aLine.append( (sal_Int64)(nEndPos-nStartPos) );
   11492           0 :     aLine.append( "\nendobj\n\n" );
   11493           0 :     CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
   11494             : 
   11495           0 :     if( nMaskObject )
   11496             :     {
   11497           0 :         BitmapEmit aEmit;
   11498           0 :         aEmit.m_nObject             = nMaskObject;
   11499           0 :         aEmit.m_aBitmap             = rObject.m_aBitmap;
   11500           0 :         return writeBitmapObject( aEmit, true );
   11501             :     }
   11502             : 
   11503           0 :     return true;
   11504             : }
   11505             : 
   11506           0 : void PDFWriterImpl::drawJPGBitmap( SvStream& rDCTData, bool bIsTrueColor, const Size& rSizePixel, const Rectangle& rTargetArea, const Bitmap& rMask )
   11507             : {
   11508           0 :     MARK( "drawJPGBitmap" );
   11509             : 
   11510           0 :     OStringBuffer aLine( 80 );
   11511           0 :     updateGraphicsState();
   11512             : 
   11513             :     // #i40055# sanity check
   11514           0 :     if( ! (rTargetArea.GetWidth() && rTargetArea.GetHeight() ) )
   11515           0 :         return;
   11516           0 :     if( ! (rSizePixel.Width() && rSizePixel.Height()) )
   11517           0 :         return;
   11518             : 
   11519           0 :     rDCTData.Seek( 0 );
   11520           0 :     if( bIsTrueColor && m_aContext.ColorMode == PDFWriter::DrawGreyscale )
   11521             :     {
   11522             :         // need to convert to grayscale;
   11523             :         // load stream to bitmap and draw the bitmap instead
   11524           0 :         Graphic aGraphic;
   11525           0 :         GraphicConverter::Import( rDCTData, aGraphic, ConvertDataFormat::JPG );
   11526           0 :         Bitmap aBmp( aGraphic.GetBitmap() );
   11527           0 :         if( !!rMask && rMask.GetSizePixel() == aBmp.GetSizePixel() )
   11528             :         {
   11529           0 :             BitmapEx aBmpEx( aBmp, rMask );
   11530           0 :             drawBitmap( rTargetArea.TopLeft(), rTargetArea.GetSize(), aBmpEx );
   11531             :         }
   11532             :         else
   11533           0 :             drawBitmap( rTargetArea.TopLeft(), rTargetArea.GetSize(), aBmp );
   11534           0 :         return;
   11535             :     }
   11536             : 
   11537           0 :     SvMemoryStream* pStream = new SvMemoryStream;
   11538           0 :     pStream->WriteStream( rDCTData );
   11539           0 :     pStream->Seek( STREAM_SEEK_TO_END );
   11540             : 
   11541           0 :     BitmapID aID;
   11542           0 :     aID.m_aPixelSize    = rSizePixel;
   11543           0 :     aID.m_nSize         = pStream->Tell();
   11544           0 :     pStream->Seek( STREAM_SEEK_TO_BEGIN );
   11545           0 :     aID.m_nChecksum     = rtl_crc32( 0, pStream->GetData(), aID.m_nSize );
   11546           0 :     if( ! rMask.IsEmpty() )
   11547           0 :         aID.m_nMaskChecksum = rMask.GetChecksum();
   11548             : 
   11549           0 :     std::list< JPGEmit >::const_iterator it;
   11550           0 :     for( it = m_aJPGs.begin(); it != m_aJPGs.end() && ! (aID == it->m_aID); ++it )
   11551             :         ;
   11552           0 :     if( it == m_aJPGs.end() )
   11553             :     {
   11554           0 :         m_aJPGs.push_front( JPGEmit() );
   11555           0 :         JPGEmit& rEmit = m_aJPGs.front();
   11556           0 :         rEmit.m_nObject     = createObject();
   11557           0 :         rEmit.m_aID         = aID;
   11558           0 :         rEmit.m_pStream     = pStream;
   11559           0 :         rEmit.m_bTrueColor  = bIsTrueColor;
   11560           0 :         if( !! rMask && rMask.GetSizePixel() == rSizePixel )
   11561           0 :             rEmit.m_aMask   = rMask;
   11562             : 
   11563           0 :         it = m_aJPGs.begin();
   11564             :     }
   11565             :     else
   11566           0 :         delete pStream;
   11567             : 
   11568           0 :     aLine.append( "q " );
   11569           0 :     sal_Int32 nCheckWidth = 0;
   11570           0 :     m_aPages.back().appendMappedLength( (sal_Int32)rTargetArea.GetWidth(), aLine, false, &nCheckWidth );
   11571           0 :     aLine.append( " 0 0 " );
   11572           0 :     sal_Int32 nCheckHeight = 0;
   11573           0 :     m_aPages.back().appendMappedLength( (sal_Int32)rTargetArea.GetHeight(), aLine, true, &nCheckHeight );
   11574           0 :     aLine.append( ' ' );
   11575           0 :     m_aPages.back().appendPoint( rTargetArea.BottomLeft(), aLine );
   11576           0 :     aLine.append( " cm\n/Im" );
   11577           0 :     aLine.append( it->m_nObject );
   11578           0 :     aLine.append( " Do Q\n" );
   11579           0 :     if( nCheckWidth == 0 || nCheckHeight == 0 )
   11580             :     {
   11581             :         // #i97512# avoid invalid current matrix
   11582           0 :         aLine.setLength( 0 );
   11583           0 :         aLine.append( "\n%jpeg image /Im" );
   11584           0 :         aLine.append( it->m_nObject );
   11585           0 :         aLine.append( " scaled to zero size, omitted\n" );
   11586             :     }
   11587           0 :     writeBuffer( aLine.getStr(), aLine.getLength() );
   11588             : 
   11589           0 :     OStringBuffer aObjName( 16 );
   11590           0 :     aObjName.append( "Im" );
   11591           0 :     aObjName.append( it->m_nObject );
   11592           0 :     pushResource( ResXObject, aObjName.makeStringAndClear(), it->m_nObject );
   11593             : 
   11594             : }
   11595             : 
   11596           0 : void PDFWriterImpl::drawBitmap( const Point& rDestPoint, const Size& rDestSize, const BitmapEmit& rBitmap, const Color& rFillColor )
   11597             : {
   11598           0 :     OStringBuffer aLine( 80 );
   11599           0 :     updateGraphicsState();
   11600             : 
   11601           0 :     aLine.append( "q " );
   11602           0 :     if( rFillColor != Color( COL_TRANSPARENT ) )
   11603             :     {
   11604           0 :         appendNonStrokingColor( rFillColor, aLine );
   11605           0 :         aLine.append( ' ' );
   11606             :     }
   11607           0 :     sal_Int32 nCheckWidth = 0;
   11608           0 :     m_aPages.back().appendMappedLength( (sal_Int32)rDestSize.Width(), aLine, false, &nCheckWidth );
   11609           0 :     aLine.append( " 0 0 " );
   11610           0 :     sal_Int32 nCheckHeight = 0;
   11611           0 :     m_aPages.back().appendMappedLength( (sal_Int32)rDestSize.Height(), aLine, true, &nCheckHeight );
   11612           0 :     aLine.append( ' ' );
   11613           0 :     m_aPages.back().appendPoint( rDestPoint + Point( 0, rDestSize.Height()-1 ), aLine );
   11614           0 :     aLine.append( " cm\n/Im" );
   11615           0 :     aLine.append( rBitmap.m_nObject );
   11616           0 :     aLine.append( " Do Q\n" );
   11617           0 :     if( nCheckWidth == 0 || nCheckHeight == 0 )
   11618             :     {
   11619             :         // #i97512# avoid invalid current matrix
   11620           0 :         aLine.setLength( 0 );
   11621           0 :         aLine.append( "\n%bitmap image /Im" );
   11622           0 :         aLine.append( rBitmap.m_nObject );
   11623           0 :         aLine.append( " scaled to zero size, omitted\n" );
   11624             :     }
   11625           0 :     writeBuffer( aLine.getStr(), aLine.getLength() );
   11626           0 : }
   11627             : 
   11628           0 : const PDFWriterImpl::BitmapEmit& PDFWriterImpl::createBitmapEmit( const BitmapEx& i_rBitmap, bool bDrawMask )
   11629             : {
   11630           0 :     BitmapEx aBitmap( i_rBitmap );
   11631           0 :     if( m_aContext.ColorMode == PDFWriter::DrawGreyscale )
   11632             :     {
   11633           0 :         BmpConversion eConv = BMP_CONVERSION_8BIT_GREYS;
   11634           0 :         int nDepth = aBitmap.GetBitmap().GetBitCount();
   11635           0 :         if( nDepth <= 4 )
   11636           0 :             eConv = BMP_CONVERSION_4BIT_GREYS;
   11637           0 :         if( nDepth > 1 )
   11638           0 :             aBitmap.Convert( eConv );
   11639             :     }
   11640           0 :     BitmapID aID;
   11641           0 :     aID.m_aPixelSize        = aBitmap.GetSizePixel();
   11642           0 :     aID.m_nSize             = aBitmap.GetBitCount();
   11643           0 :     aID.m_nChecksum         = aBitmap.GetBitmap().GetChecksum();
   11644           0 :     aID.m_nMaskChecksum     = 0;
   11645           0 :     if( aBitmap.IsAlpha() )
   11646           0 :         aID.m_nMaskChecksum = aBitmap.GetAlpha().GetChecksum();
   11647             :     else
   11648             :     {
   11649           0 :         Bitmap aMask = aBitmap.GetMask();
   11650           0 :         if( ! aMask.IsEmpty() )
   11651           0 :             aID.m_nMaskChecksum = aMask.GetChecksum();
   11652             :     }
   11653           0 :     std::list< BitmapEmit >::const_iterator it;
   11654           0 :     for( it = m_aBitmaps.begin(); it != m_aBitmaps.end(); ++it )
   11655             :     {
   11656           0 :         if( aID == it->m_aID )
   11657           0 :             break;
   11658             :     }
   11659           0 :     if( it == m_aBitmaps.end() )
   11660             :     {
   11661           0 :         m_aBitmaps.push_front( BitmapEmit() );
   11662           0 :         m_aBitmaps.front().m_aID        = aID;
   11663           0 :         m_aBitmaps.front().m_aBitmap    = aBitmap;
   11664           0 :         m_aBitmaps.front().m_nObject    = createObject();
   11665           0 :         m_aBitmaps.front().m_bDrawMask  = bDrawMask;
   11666           0 :         it = m_aBitmaps.begin();
   11667             :     }
   11668             : 
   11669           0 :     OStringBuffer aObjName( 16 );
   11670           0 :     aObjName.append( "Im" );
   11671           0 :     aObjName.append( it->m_nObject );
   11672           0 :     pushResource( ResXObject, aObjName.makeStringAndClear(), it->m_nObject );
   11673             : 
   11674           0 :     return *it;
   11675             : }
   11676             : 
   11677           0 : void PDFWriterImpl::drawBitmap( const Point& rDestPoint, const Size& rDestSize, const Bitmap& rBitmap )
   11678             : {
   11679           0 :     MARK( "drawBitmap (Bitmap)" );
   11680             : 
   11681             :     // #i40055# sanity check
   11682           0 :     if( ! (rDestSize.Width() && rDestSize.Height()) )
   11683           0 :         return;
   11684             : 
   11685           0 :     const BitmapEmit& rEmit = createBitmapEmit( BitmapEx( rBitmap ) );
   11686           0 :     drawBitmap( rDestPoint, rDestSize, rEmit, Color( COL_TRANSPARENT ) );
   11687             : }
   11688             : 
   11689           0 : void PDFWriterImpl::drawBitmap( const Point& rDestPoint, const Size& rDestSize, const BitmapEx& rBitmap )
   11690             : {
   11691           0 :     MARK( "drawBitmap (BitmapEx)" );
   11692             : 
   11693             :     // #i40055# sanity check
   11694           0 :     if( ! (rDestSize.Width() && rDestSize.Height()) )
   11695           0 :         return;
   11696             : 
   11697           0 :     const BitmapEmit& rEmit = createBitmapEmit( rBitmap );
   11698           0 :     drawBitmap( rDestPoint, rDestSize, rEmit, Color( COL_TRANSPARENT ) );
   11699             : }
   11700             : 
   11701           0 : sal_Int32 PDFWriterImpl::createGradient( const Gradient& rGradient, const Size& rSize )
   11702             : {
   11703           0 :     Size aPtSize( lcl_convert( m_aGraphicsStack.front().m_aMapMode,
   11704             :                                MapMode( MAP_POINT ),
   11705             :                                getReferenceDevice(),
   11706           0 :                                rSize ) );
   11707             :     // check if we already have this gradient
   11708           0 :     std::list<GradientEmit>::iterator it;
   11709             :     // rounding to point will generally lose some pixels
   11710             :     // round up to point boundary
   11711           0 :     aPtSize.Width()++;
   11712           0 :     aPtSize.Height()++;
   11713           0 :     for( it = m_aGradients.begin(); it != m_aGradients.end(); ++it )
   11714             :     {
   11715           0 :         if( it->m_aGradient == rGradient )
   11716             :         {
   11717           0 :             if( it->m_aSize == aPtSize )
   11718           0 :                 break;
   11719             :         }
   11720             :     }
   11721           0 :     if( it == m_aGradients.end() )
   11722             :     {
   11723           0 :         m_aGradients.push_front( GradientEmit() );
   11724           0 :         m_aGradients.front().m_aGradient    = rGradient;
   11725           0 :         m_aGradients.front().m_nObject      = createObject();
   11726           0 :         m_aGradients.front().m_aSize        = aPtSize;
   11727           0 :         it = m_aGradients.begin();
   11728             :     }
   11729             : 
   11730           0 :     OStringBuffer aObjName( 16 );
   11731           0 :     aObjName.append( 'P' );
   11732           0 :     aObjName.append( it->m_nObject );
   11733           0 :     pushResource( ResShading, aObjName.makeStringAndClear(), it->m_nObject );
   11734             : 
   11735           0 :     return it->m_nObject;
   11736             : }
   11737             : 
   11738           0 : void PDFWriterImpl::drawGradient( const Rectangle& rRect, const Gradient& rGradient )
   11739             : {
   11740           0 :     MARK( "drawGradient (Rectangle)" );
   11741             : 
   11742           0 :     if( m_aContext.Version == PDFWriter::PDF_1_2 )
   11743             :     {
   11744           0 :         drawRectangle( rRect );
   11745           0 :         return;
   11746             :     }
   11747             : 
   11748           0 :     sal_Int32 nGradient = createGradient( rGradient, rRect.GetSize() );
   11749             : 
   11750           0 :     Point aTranslate( rRect.BottomLeft() );
   11751           0 :     aTranslate += Point( 0, 1 );
   11752             : 
   11753           0 :     updateGraphicsState();
   11754             : 
   11755           0 :     OStringBuffer aLine( 80 );
   11756           0 :     aLine.append( "q 1 0 0 1 " );
   11757           0 :     m_aPages.back().appendPoint( aTranslate, aLine );
   11758           0 :     aLine.append( " cm " );
   11759             :     // if a stroke is appended reset the clip region before stroke
   11760           0 :     if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
   11761           0 :         aLine.append( "q " );
   11762           0 :     aLine.append( "0 0 " );
   11763           0 :     m_aPages.back().appendMappedLength( (sal_Int32)rRect.GetWidth(), aLine, false );
   11764           0 :     aLine.append( ' ' );
   11765           0 :     m_aPages.back().appendMappedLength( (sal_Int32)rRect.GetHeight(), aLine, true );
   11766           0 :     aLine.append( " re W n\n" );
   11767             : 
   11768           0 :     aLine.append( "/P" );
   11769           0 :     aLine.append( nGradient );
   11770           0 :     aLine.append( " sh " );
   11771           0 :     if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
   11772             :     {
   11773           0 :         aLine.append( "Q 0 0 " );
   11774           0 :         m_aPages.back().appendMappedLength( (sal_Int32)rRect.GetWidth(), aLine, false );
   11775           0 :         aLine.append( ' ' );
   11776           0 :         m_aPages.back().appendMappedLength( (sal_Int32)rRect.GetHeight(), aLine, true );
   11777           0 :         aLine.append( " re S " );
   11778             :     }
   11779           0 :     aLine.append( "Q\n" );
   11780           0 :     writeBuffer( aLine.getStr(), aLine.getLength() );
   11781             : }
   11782             : 
   11783           0 : void PDFWriterImpl::drawHatch( const tools::PolyPolygon& rPolyPoly, const Hatch& rHatch )
   11784             : {
   11785           0 :     MARK( "drawHatch" );
   11786             : 
   11787           0 :     updateGraphicsState();
   11788             : 
   11789           0 :     if( rPolyPoly.Count() )
   11790             :     {
   11791           0 :         tools::PolyPolygon     aPolyPoly( rPolyPoly );
   11792             : 
   11793           0 :         aPolyPoly.Optimize( PolyOptimizeFlags::NO_SAME );
   11794           0 :         push( PushFlags::LINECOLOR );
   11795           0 :         setLineColor( rHatch.GetColor() );
   11796           0 :         getReferenceDevice()->DrawHatch( aPolyPoly, rHatch, false );
   11797           0 :         pop();
   11798             :     }
   11799           0 : }
   11800             : 
   11801           0 : void PDFWriterImpl::drawWallpaper( const Rectangle& rRect, const Wallpaper& rWall )
   11802             : {
   11803           0 :     MARK( "drawWallpaper" );
   11804             : 
   11805           0 :     bool bDrawColor         = false;
   11806           0 :     bool bDrawGradient      = false;
   11807           0 :     bool bDrawBitmap        = false;
   11808             : 
   11809           0 :     BitmapEx aBitmap;
   11810           0 :     Point aBmpPos = rRect.TopLeft();
   11811           0 :     Size aBmpSize;
   11812           0 :     if( rWall.IsBitmap() )
   11813             :     {
   11814           0 :         aBitmap = rWall.GetBitmap();
   11815           0 :         aBmpSize = lcl_convert( aBitmap.GetPrefMapMode(),
   11816           0 :                                 getMapMode(),
   11817             :                                 getReferenceDevice(),
   11818           0 :                                 aBitmap.GetPrefSize() );
   11819           0 :         Rectangle aRect( rRect );
   11820           0 :         if( rWall.IsRect() )
   11821             :         {
   11822           0 :             aRect = rWall.GetRect();
   11823           0 :             aBmpPos = aRect.TopLeft();
   11824           0 :             aBmpSize = aRect.GetSize();
   11825             :         }
   11826           0 :         if( rWall.GetStyle() != WALLPAPER_SCALE )
   11827             :         {
   11828           0 :             if( rWall.GetStyle() != WALLPAPER_TILE )
   11829             :             {
   11830           0 :                 bDrawBitmap     = true;
   11831           0 :                 if( rWall.IsGradient() )
   11832           0 :                     bDrawGradient = true;
   11833             :                 else
   11834           0 :                     bDrawColor = true;
   11835           0 :                 switch( rWall.GetStyle() )
   11836             :                 {
   11837             :                     case WALLPAPER_TOPLEFT:
   11838           0 :                         break;
   11839             :                     case WALLPAPER_TOP:
   11840           0 :                         aBmpPos.X() += (aRect.GetWidth()-aBmpSize.Width())/2;
   11841           0 :                         break;
   11842             :                     case WALLPAPER_LEFT:
   11843           0 :                         aBmpPos.Y() += (aRect.GetHeight()-aBmpSize.Height())/2;
   11844           0 :                         break;
   11845             :                     case WALLPAPER_TOPRIGHT:
   11846           0 :                         aBmpPos.X() += aRect.GetWidth()-aBmpSize.Width();
   11847           0 :                         break;
   11848             :                     case WALLPAPER_CENTER:
   11849           0 :                         aBmpPos.X() += (aRect.GetWidth()-aBmpSize.Width())/2;
   11850           0 :                         aBmpPos.Y() += (aRect.GetHeight()-aBmpSize.Height())/2;
   11851           0 :                         break;
   11852             :                     case WALLPAPER_RIGHT:
   11853           0 :                         aBmpPos.X() += aRect.GetWidth()-aBmpSize.Width();
   11854           0 :                         aBmpPos.Y() += (aRect.GetHeight()-aBmpSize.Height())/2;
   11855           0 :                         break;
   11856             :                     case WALLPAPER_BOTTOMLEFT:
   11857           0 :                         aBmpPos.Y() += aRect.GetHeight()-aBmpSize.Height();
   11858           0 :                         break;
   11859             :                     case WALLPAPER_BOTTOM:
   11860           0 :                         aBmpPos.X() += (aRect.GetWidth()-aBmpSize.Width())/2;
   11861           0 :                         aBmpPos.Y() += aRect.GetHeight()-aBmpSize.Height();
   11862           0 :                         break;
   11863             :                     case WALLPAPER_BOTTOMRIGHT:
   11864           0 :                         aBmpPos.X() += aRect.GetWidth()-aBmpSize.Width();
   11865           0 :                         aBmpPos.Y() += aRect.GetHeight()-aBmpSize.Height();
   11866           0 :                         break;
   11867             :                     default: ;
   11868             :                 }
   11869             :             }
   11870             :             else
   11871             :             {
   11872             :                 // push the bitmap
   11873           0 :                 const BitmapEmit& rEmit = createBitmapEmit( BitmapEx( aBitmap ) );
   11874             : 
   11875             :                 // convert to page coordinates; this needs to be done here
   11876             :                 // since the emit does not know the page anymore
   11877           0 :                 Rectangle aConvertRect( aBmpPos, aBmpSize );
   11878           0 :                 m_aPages.back().convertRect( aConvertRect );
   11879             : 
   11880           0 :                 OStringBuffer aNameBuf(16);
   11881           0 :                 aNameBuf.append( "Im" );
   11882           0 :                 aNameBuf.append( rEmit.m_nObject );
   11883           0 :                 OString aImageName( aNameBuf.makeStringAndClear() );
   11884             : 
   11885             :                 // push the pattern
   11886           0 :                 OStringBuffer aTilingStream( 32 );
   11887           0 :                 appendFixedInt( aConvertRect.GetWidth(), aTilingStream );
   11888           0 :                 aTilingStream.append( " 0 0 " );
   11889           0 :                 appendFixedInt( aConvertRect.GetHeight(), aTilingStream );
   11890           0 :                 aTilingStream.append( " 0 0 cm\n/" );
   11891           0 :                 aTilingStream.append( aImageName );
   11892           0 :                 aTilingStream.append( " Do\n" );
   11893             : 
   11894           0 :                 m_aTilings.push_back( TilingEmit() );
   11895           0 :                 m_aTilings.back().m_nObject         = createObject();
   11896           0 :                 m_aTilings.back().m_aRectangle      = Rectangle( Point( 0, 0 ), aConvertRect.GetSize() );
   11897           0 :                 m_aTilings.back().m_pTilingStream   = new SvMemoryStream();
   11898           0 :                 m_aTilings.back().m_pTilingStream->Write( aTilingStream.getStr(), aTilingStream.getLength() );
   11899             :                 // phase the tiling so wallpaper begins on upper left
   11900           0 :                 if ((aConvertRect.GetWidth() == 0) || (aConvertRect.GetHeight() == 0))
   11901           0 :                     throw o3tl::divide_by_zero();
   11902           0 :                 m_aTilings.back().m_aTransform.matrix[2] = double(aConvertRect.Left() % aConvertRect.GetWidth()) / fDivisor;
   11903           0 :                 m_aTilings.back().m_aTransform.matrix[5] = double(aConvertRect.Top() % aConvertRect.GetHeight()) / fDivisor;
   11904           0 :                 m_aTilings.back().m_aResources.m_aXObjects[aImageName] = rEmit.m_nObject;
   11905             : 
   11906           0 :                 updateGraphicsState();
   11907             : 
   11908           0 :                 OStringBuffer aObjName( 16 );
   11909           0 :                 aObjName.append( 'P' );
   11910           0 :                 aObjName.append( m_aTilings.back().m_nObject );
   11911           0 :                 OString aPatternName( aObjName.makeStringAndClear() );
   11912           0 :                 pushResource( ResPattern, aPatternName, m_aTilings.back().m_nObject );
   11913             : 
   11914             :                 // fill a rRect with the pattern
   11915           0 :                 OStringBuffer aLine( 100 );
   11916           0 :                 aLine.append( "q /Pattern cs /" );
   11917           0 :                 aLine.append( aPatternName );
   11918           0 :                 aLine.append( " scn " );
   11919           0 :                 m_aPages.back().appendRect( rRect, aLine );
   11920           0 :                 aLine.append( " f Q\n" );
   11921           0 :                 writeBuffer( aLine.getStr(), aLine.getLength() );
   11922             :             }
   11923             :         }
   11924             :         else
   11925             :         {
   11926           0 :             aBmpPos     = aRect.TopLeft();
   11927           0 :             aBmpSize    = aRect.GetSize();
   11928           0 :             bDrawBitmap = true;
   11929             :         }
   11930             : 
   11931           0 :         if( aBitmap.IsTransparent() )
   11932             :         {
   11933           0 :             if( rWall.IsGradient() )
   11934           0 :                 bDrawGradient = true;
   11935             :             else
   11936           0 :                 bDrawColor = true;
   11937             :         }
   11938             :     }
   11939           0 :     else if( rWall.IsGradient() )
   11940           0 :         bDrawGradient = true;
   11941             :     else
   11942           0 :         bDrawColor = true;
   11943             : 
   11944           0 :     if( bDrawGradient )
   11945             :     {
   11946           0 :         drawGradient( rRect, rWall.GetGradient() );
   11947             :     }
   11948           0 :     if( bDrawColor )
   11949             :     {
   11950           0 :         Color aOldLineColor = m_aGraphicsStack.front().m_aLineColor;
   11951           0 :         Color aOldFillColor = m_aGraphicsStack.front().m_aFillColor;
   11952           0 :         setLineColor( Color( COL_TRANSPARENT ) );
   11953           0 :         setFillColor( rWall.GetColor() );
   11954           0 :         drawRectangle( rRect );
   11955           0 :         setLineColor( aOldLineColor );
   11956           0 :         setFillColor( aOldFillColor );
   11957             :     }
   11958           0 :     if( bDrawBitmap )
   11959             :     {
   11960             :         // set temporary clip region since aBmpPos and aBmpSize
   11961             :         // may be outside rRect
   11962           0 :         OStringBuffer aLine( 20 );
   11963           0 :         aLine.append( "q " );
   11964           0 :         m_aPages.back().appendRect( rRect, aLine );
   11965           0 :         aLine.append( " W n\n" );
   11966           0 :         writeBuffer( aLine.getStr(), aLine.getLength() );
   11967           0 :         drawBitmap( aBmpPos, aBmpSize, aBitmap );
   11968           0 :         writeBuffer( "Q\n", 2 );
   11969           0 :     }
   11970           0 : }
   11971             : 
   11972           0 : void PDFWriterImpl::updateGraphicsState(Mode const mode)
   11973             : {
   11974           0 :     OStringBuffer aLine( 256 );
   11975           0 :     GraphicsState& rNewState = m_aGraphicsStack.front();
   11976             :     // first set clip region since it might invalidate everything else
   11977             : 
   11978           0 :     if( (rNewState.m_nUpdateFlags & GraphicsState::updateClipRegion) )
   11979             :     {
   11980           0 :         rNewState.m_nUpdateFlags &= ~GraphicsState::updateClipRegion;
   11981             : 
   11982           0 :         if( m_aCurrentPDFState.m_bClipRegion != rNewState.m_bClipRegion ||
   11983           0 :             ( rNewState.m_bClipRegion && m_aCurrentPDFState.m_aClipRegion != rNewState.m_aClipRegion ) )
   11984             :         {
   11985           0 :             if( m_aCurrentPDFState.m_bClipRegion && m_aCurrentPDFState.m_aClipRegion.count() )
   11986             :             {
   11987           0 :                 aLine.append( "Q " );
   11988             :                 // invalidate everything but the clip region
   11989           0 :                 m_aCurrentPDFState = GraphicsState();
   11990           0 :                 rNewState.m_nUpdateFlags = sal::static_int_cast<sal_uInt16>(~GraphicsState::updateClipRegion);
   11991             :             }
   11992           0 :             if( rNewState.m_bClipRegion && rNewState.m_aClipRegion.count() )
   11993             :             {
   11994             :                 // clip region is always stored in private PDF mapmode
   11995           0 :                 MapMode aNewMapMode = rNewState.m_aMapMode;
   11996           0 :                 rNewState.m_aMapMode = m_aMapMode;
   11997           0 :                 getReferenceDevice()->SetMapMode( rNewState.m_aMapMode );
   11998           0 :                 m_aCurrentPDFState.m_aMapMode = rNewState.m_aMapMode;
   11999             : 
   12000           0 :                 aLine.append( "q " );
   12001           0 :                 m_aPages.back().appendPolyPolygon( rNewState.m_aClipRegion, aLine );
   12002           0 :                 aLine.append( "W* n\n" );
   12003           0 :                 rNewState.m_aMapMode = aNewMapMode;
   12004           0 :                 getReferenceDevice()->SetMapMode( rNewState.m_aMapMode );
   12005           0 :                 m_aCurrentPDFState.m_aMapMode = rNewState.m_aMapMode;
   12006             :             }
   12007             :         }
   12008             :     }
   12009             : 
   12010           0 :     if( (rNewState.m_nUpdateFlags & GraphicsState::updateMapMode) )
   12011             :     {
   12012           0 :         rNewState.m_nUpdateFlags &= ~GraphicsState::updateMapMode;
   12013           0 :         getReferenceDevice()->SetMapMode( rNewState.m_aMapMode );
   12014             :     }
   12015             : 
   12016           0 :     if( (rNewState.m_nUpdateFlags & GraphicsState::updateFont) )
   12017             :     {
   12018           0 :         rNewState.m_nUpdateFlags &= ~GraphicsState::updateFont;
   12019           0 :         getReferenceDevice()->SetFont( rNewState.m_aFont );
   12020           0 :         getReferenceDevice()->ImplNewFont();
   12021             :     }
   12022             : 
   12023           0 :     if( (rNewState.m_nUpdateFlags & GraphicsState::updateLayoutMode) )
   12024             :     {
   12025           0 :         rNewState.m_nUpdateFlags &= ~GraphicsState::updateLayoutMode;
   12026           0 :         getReferenceDevice()->SetLayoutMode( rNewState.m_nLayoutMode );
   12027             :     }
   12028             : 
   12029           0 :     if( (rNewState.m_nUpdateFlags & GraphicsState::updateDigitLanguage) )
   12030             :     {
   12031           0 :         rNewState.m_nUpdateFlags &= ~GraphicsState::updateDigitLanguage;
   12032           0 :         getReferenceDevice()->SetDigitLanguage( rNewState.m_aDigitLanguage );
   12033             :     }
   12034             : 
   12035           0 :     if( (rNewState.m_nUpdateFlags & GraphicsState::updateLineColor) )
   12036             :     {
   12037           0 :         rNewState.m_nUpdateFlags &= ~GraphicsState::updateLineColor;
   12038           0 :         if( m_aCurrentPDFState.m_aLineColor != rNewState.m_aLineColor &&
   12039           0 :             rNewState.m_aLineColor != Color( COL_TRANSPARENT ) )
   12040             :         {
   12041           0 :             appendStrokingColor( rNewState.m_aLineColor, aLine );
   12042           0 :             aLine.append( "\n" );
   12043             :         }
   12044             :     }
   12045             : 
   12046           0 :     if( (rNewState.m_nUpdateFlags & GraphicsState::updateFillColor) )
   12047             :     {
   12048           0 :         rNewState.m_nUpdateFlags &= ~GraphicsState::updateFillColor;
   12049           0 :         if( m_aCurrentPDFState.m_aFillColor != rNewState.m_aFillColor &&
   12050           0 :             rNewState.m_aFillColor != Color( COL_TRANSPARENT ) )
   12051             :         {
   12052           0 :             appendNonStrokingColor( rNewState.m_aFillColor, aLine );
   12053           0 :             aLine.append( "\n" );
   12054             :         }
   12055             :     }
   12056             : 
   12057           0 :     if( (rNewState.m_nUpdateFlags & GraphicsState::updateTransparentPercent) )
   12058             :     {
   12059           0 :         rNewState.m_nUpdateFlags &= ~GraphicsState::updateTransparentPercent;
   12060           0 :         if( m_aContext.Version >= PDFWriter::PDF_1_4 && m_aCurrentPDFState.m_nTransparentPercent != rNewState.m_nTransparentPercent )
   12061             :         {
   12062             :             // TODO: switch extended graphicsstate
   12063             :         }
   12064             :     }
   12065             : 
   12066             :     // everything is up to date now
   12067           0 :     m_aCurrentPDFState = m_aGraphicsStack.front();
   12068           0 :     if ((mode != NOWRITE) &&  !aLine.isEmpty())
   12069           0 :         writeBuffer( aLine.getStr(), aLine.getLength() );
   12070           0 : }
   12071             : 
   12072             : /* #i47544# imitate OutputDevice behaviour:
   12073             : *  if a font with a nontransparent color is set, it overwrites the current
   12074             : *  text color. OTOH setting the text color will overwrite the color of the font.
   12075             : */
   12076           0 : void PDFWriterImpl::setFont( const vcl::Font& rFont )
   12077             : {
   12078           0 :     Color aColor = rFont.GetColor();
   12079           0 :     if( aColor == Color( COL_TRANSPARENT ) )
   12080           0 :         aColor = m_aGraphicsStack.front().m_aFont.GetColor();
   12081           0 :     m_aGraphicsStack.front().m_aFont = rFont;
   12082           0 :     m_aGraphicsStack.front().m_aFont.SetColor( aColor );
   12083           0 :     m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsState::updateFont;
   12084           0 : }
   12085             : 
   12086           0 : void PDFWriterImpl::push( PushFlags nFlags )
   12087             : {
   12088             :     OSL_ENSURE( !m_aGraphicsStack.empty(), "invalid graphics stack" );
   12089           0 :     m_aGraphicsStack.push_front( m_aGraphicsStack.front() );
   12090           0 :     m_aGraphicsStack.front().m_nFlags = nFlags;
   12091           0 : }
   12092             : 
   12093           0 : void PDFWriterImpl::pop()
   12094             : {
   12095             :     OSL_ENSURE( m_aGraphicsStack.size() > 1, "pop without push" );
   12096           0 :     if( m_aGraphicsStack.size() < 2 )
   12097           0 :         return;
   12098             : 
   12099           0 :     GraphicsState aState = m_aGraphicsStack.front();
   12100           0 :     m_aGraphicsStack.pop_front();
   12101           0 :     GraphicsState& rOld = m_aGraphicsStack.front();
   12102             : 
   12103             :     // move those parameters back that were not pushed
   12104             :     // in the first place
   12105           0 :     if( ! (aState.m_nFlags & PushFlags::LINECOLOR) )
   12106           0 :         setLineColor( aState.m_aLineColor );
   12107           0 :     if( ! (aState.m_nFlags & PushFlags::FILLCOLOR) )
   12108           0 :         setFillColor( aState.m_aFillColor );
   12109           0 :     if( ! (aState.m_nFlags & PushFlags::FONT) )
   12110           0 :         setFont( aState.m_aFont );
   12111           0 :     if( ! (aState.m_nFlags & PushFlags::TEXTCOLOR) )
   12112           0 :         setTextColor( aState.m_aFont.GetColor() );
   12113           0 :     if( ! (aState.m_nFlags & PushFlags::MAPMODE) )
   12114           0 :         setMapMode( aState.m_aMapMode );
   12115           0 :     if( ! (aState.m_nFlags & PushFlags::CLIPREGION) )
   12116             :     {
   12117             :         // do not use setClipRegion here
   12118             :         // it would convert again assuming the current mapmode
   12119           0 :         rOld.m_aClipRegion = aState.m_aClipRegion;
   12120           0 :         rOld.m_bClipRegion = aState.m_bClipRegion;
   12121             :     }
   12122           0 :     if( ! (aState.m_nFlags & PushFlags::TEXTLINECOLOR ) )
   12123           0 :         setTextLineColor( aState.m_aTextLineColor );
   12124           0 :     if( ! (aState.m_nFlags & PushFlags::OVERLINECOLOR ) )
   12125           0 :         setOverlineColor( aState.m_aOverlineColor );
   12126           0 :     if( ! (aState.m_nFlags & PushFlags::TEXTALIGN ) )
   12127           0 :         setTextAlign( aState.m_aFont.GetAlign() );
   12128           0 :     if( ! (aState.m_nFlags & PushFlags::TEXTFILLCOLOR) )
   12129           0 :         setTextFillColor( aState.m_aFont.GetFillColor() );
   12130           0 :     if( ! (aState.m_nFlags & PushFlags::REFPOINT) )
   12131             :     {
   12132             :         // what ?
   12133             :     }
   12134             :     // invalidate graphics state
   12135           0 :     m_aGraphicsStack.front().m_nUpdateFlags = sal::static_int_cast<sal_uInt16>(~0U);
   12136             : }
   12137             : 
   12138           0 : void PDFWriterImpl::setMapMode( const MapMode& rMapMode )
   12139             : {
   12140           0 :     m_aGraphicsStack.front().m_aMapMode = rMapMode;
   12141           0 :     getReferenceDevice()->SetMapMode( rMapMode );
   12142           0 :     m_aCurrentPDFState.m_aMapMode = rMapMode;
   12143           0 : }
   12144             : 
   12145           0 : void PDFWriterImpl::setClipRegion( const basegfx::B2DPolyPolygon& rRegion )
   12146             : {
   12147           0 :     basegfx::B2DPolyPolygon aRegion = getReferenceDevice()->LogicToPixel( rRegion, m_aGraphicsStack.front().m_aMapMode );
   12148           0 :     aRegion = getReferenceDevice()->PixelToLogic( aRegion, m_aMapMode );
   12149           0 :     m_aGraphicsStack.front().m_aClipRegion = aRegion;
   12150           0 :     m_aGraphicsStack.front().m_bClipRegion = true;
   12151           0 :     m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsState::updateClipRegion;
   12152           0 : }
   12153             : 
   12154           0 : void PDFWriterImpl::moveClipRegion( sal_Int32 nX, sal_Int32 nY )
   12155             : {
   12156           0 :     if( m_aGraphicsStack.front().m_bClipRegion && m_aGraphicsStack.front().m_aClipRegion.count() )
   12157             :     {
   12158           0 :         Point aPoint( lcl_convert( m_aGraphicsStack.front().m_aMapMode,
   12159             :                                    m_aMapMode,
   12160             :                                    getReferenceDevice(),
   12161           0 :                                    Point( nX, nY ) ) );
   12162           0 :         aPoint -= lcl_convert( m_aGraphicsStack.front().m_aMapMode,
   12163             :                                m_aMapMode,
   12164             :                                getReferenceDevice(),
   12165           0 :                                Point() );
   12166           0 :         basegfx::B2DHomMatrix aMat;
   12167           0 :         aMat.translate( aPoint.X(), aPoint.Y() );
   12168           0 :         m_aGraphicsStack.front().m_aClipRegion.transform( aMat );
   12169           0 :         m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsState::updateClipRegion;
   12170             :     }
   12171           0 : }
   12172             : 
   12173           0 : bool PDFWriterImpl::intersectClipRegion( const Rectangle& rRect )
   12174             : {
   12175             :     basegfx::B2DPolyPolygon aRect( basegfx::tools::createPolygonFromRect(
   12176           0 :         basegfx::B2DRectangle( rRect.Left(), rRect.Top(), rRect.Right(), rRect.Bottom() ) ) );
   12177           0 :     return intersectClipRegion( aRect );
   12178             : }
   12179             : 
   12180           0 : bool PDFWriterImpl::intersectClipRegion( const basegfx::B2DPolyPolygon& rRegion )
   12181             : {
   12182           0 :     basegfx::B2DPolyPolygon aRegion( getReferenceDevice()->LogicToPixel( rRegion, m_aGraphicsStack.front().m_aMapMode ) );
   12183           0 :     aRegion = getReferenceDevice()->PixelToLogic( aRegion, m_aMapMode );
   12184           0 :     m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsState::updateClipRegion;
   12185           0 :     if( m_aGraphicsStack.front().m_bClipRegion )
   12186             :     {
   12187           0 :         basegfx::B2DPolyPolygon aOld( basegfx::tools::prepareForPolygonOperation( m_aGraphicsStack.front().m_aClipRegion ) );
   12188           0 :         aRegion = basegfx::tools::prepareForPolygonOperation( aRegion );
   12189           0 :         m_aGraphicsStack.front().m_aClipRegion = basegfx::tools::solvePolygonOperationAnd( aOld, aRegion );
   12190             :     }
   12191             :     else
   12192             :     {
   12193           0 :         m_aGraphicsStack.front().m_aClipRegion = aRegion;
   12194           0 :         m_aGraphicsStack.front().m_bClipRegion = true;
   12195             :     }
   12196           0 :     return true;
   12197             : }
   12198             : 
   12199           0 : void PDFWriterImpl::createNote( const Rectangle& rRect, const PDFNote& rNote, sal_Int32 nPageNr )
   12200             : {
   12201           0 :     if( nPageNr < 0 )
   12202           0 :         nPageNr = m_nCurrentPage;
   12203             : 
   12204           0 :     if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() )
   12205           0 :         return;
   12206             : 
   12207           0 :     m_aNotes.push_back( PDFNoteEntry() );
   12208           0 :     m_aNotes.back().m_nObject       = createObject();
   12209           0 :     m_aNotes.back().m_aContents     = rNote;
   12210           0 :     m_aNotes.back().m_aRect         = rRect;
   12211             :     // convert to default user space now, since the mapmode may change
   12212           0 :     m_aPages[nPageNr].convertRect( m_aNotes.back().m_aRect );
   12213             : 
   12214             :     // insert note to page's annotation list
   12215           0 :     m_aPages[ nPageNr ].m_aAnnotations.push_back( m_aNotes.back().m_nObject );
   12216             : }
   12217             : 
   12218           0 : sal_Int32 PDFWriterImpl::createLink( const Rectangle& rRect, sal_Int32 nPageNr )
   12219             : {
   12220           0 :     if( nPageNr < 0 )
   12221           0 :         nPageNr = m_nCurrentPage;
   12222             : 
   12223           0 :     if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() )
   12224           0 :         return -1;
   12225             : 
   12226           0 :     sal_Int32 nRet = m_aLinks.size();
   12227             : 
   12228           0 :     m_aLinks.push_back( PDFLink() );
   12229           0 :     m_aLinks.back().m_nObject   = createObject();
   12230           0 :     m_aLinks.back().m_nPage     = nPageNr;
   12231           0 :     m_aLinks.back().m_aRect     = rRect;
   12232             :     // convert to default user space now, since the mapmode may change
   12233           0 :     m_aPages[nPageNr].convertRect( m_aLinks.back().m_aRect );
   12234             : 
   12235             :     // insert link to page's annotation list
   12236           0 :     m_aPages[ nPageNr ].m_aAnnotations.push_back( m_aLinks.back().m_nObject );
   12237             : 
   12238           0 :     return nRet;
   12239             : }
   12240             : 
   12241             : //--->i56629
   12242           0 : sal_Int32 PDFWriterImpl::createNamedDest( const OUString& sDestName, const Rectangle& rRect, sal_Int32 nPageNr, PDFWriter::DestAreaType eType )
   12243             : {
   12244           0 :     if( nPageNr < 0 )
   12245           0 :         nPageNr = m_nCurrentPage;
   12246             : 
   12247           0 :     if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() )
   12248           0 :         return -1;
   12249             : 
   12250           0 :     sal_Int32 nRet = m_aNamedDests.size();
   12251             : 
   12252           0 :     m_aNamedDests.push_back( PDFNamedDest() );
   12253           0 :     m_aNamedDests.back().m_aDestName = sDestName;
   12254           0 :     m_aNamedDests.back().m_nPage = nPageNr;
   12255           0 :     m_aNamedDests.back().m_eType = eType;
   12256           0 :     m_aNamedDests.back().m_aRect = rRect;
   12257             :     // convert to default user space now, since the mapmode may change
   12258           0 :     m_aPages[nPageNr].convertRect( m_aNamedDests.back().m_aRect );
   12259             : 
   12260           0 :     return nRet;
   12261             : }
   12262             : //<---i56629
   12263             : 
   12264           0 : sal_Int32 PDFWriterImpl::createDest( const Rectangle& rRect, sal_Int32 nPageNr, PDFWriter::DestAreaType eType )
   12265             : {
   12266           0 :     if( nPageNr < 0 )
   12267           0 :         nPageNr = m_nCurrentPage;
   12268             : 
   12269           0 :     if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() )
   12270           0 :         return -1;
   12271             : 
   12272           0 :     sal_Int32 nRet = m_aDests.size();
   12273             : 
   12274           0 :     m_aDests.push_back( PDFDest() );
   12275           0 :     m_aDests.back().m_nPage = nPageNr;
   12276           0 :     m_aDests.back().m_eType = eType;
   12277           0 :     m_aDests.back().m_aRect = rRect;
   12278             :     // convert to default user space now, since the mapmode may change
   12279           0 :     m_aPages[nPageNr].convertRect( m_aDests.back().m_aRect );
   12280             : 
   12281           0 :     return nRet;
   12282             : }
   12283             : 
   12284           0 : sal_Int32 PDFWriterImpl::registerDestReference( sal_Int32 nDestId, const Rectangle& rRect, sal_Int32 nPageNr, PDFWriter::DestAreaType eType )
   12285             : {
   12286           0 :     return m_aDestinationIdTranslation[ nDestId ] = createDest( rRect, nPageNr, eType );
   12287             : }
   12288             : 
   12289           0 : sal_Int32 PDFWriterImpl::setLinkDest( sal_Int32 nLinkId, sal_Int32 nDestId )
   12290             : {
   12291           0 :     if( nLinkId < 0 || nLinkId >= (sal_Int32)m_aLinks.size() )
   12292           0 :         return -1;
   12293           0 :     if( nDestId < 0 || nDestId >= (sal_Int32)m_aDests.size() )
   12294           0 :         return -2;
   12295             : 
   12296           0 :     m_aLinks[ nLinkId ].m_nDest = nDestId;
   12297             : 
   12298           0 :     return 0;
   12299             : }
   12300             : 
   12301           0 : sal_Int32 PDFWriterImpl::setLinkURL( sal_Int32 nLinkId, const OUString& rURL )
   12302             : {
   12303           0 :     if( nLinkId < 0 || nLinkId >= (sal_Int32)m_aLinks.size() )
   12304           0 :         return -1;
   12305             : 
   12306           0 :     m_aLinks[ nLinkId ].m_nDest = -1;
   12307             : 
   12308             :     using namespace ::com::sun::star;
   12309             : 
   12310           0 :     if (!m_xTrans.is())
   12311             :     {
   12312           0 :         uno::Reference< uno::XComponentContext > xContext( comphelper::getProcessComponentContext() );
   12313           0 :         m_xTrans = util::URLTransformer::create(xContext);;
   12314             :     }
   12315             : 
   12316           0 :     util::URL aURL;
   12317           0 :     aURL.Complete = rURL;
   12318             : 
   12319           0 :     m_xTrans->parseStrict( aURL );
   12320             : 
   12321           0 :     m_aLinks[ nLinkId ].m_aURL  = aURL.Complete;
   12322             : 
   12323           0 :     return 0;
   12324             : }
   12325             : 
   12326           0 : void PDFWriterImpl::setLinkPropertyId( sal_Int32 nLinkId, sal_Int32 nPropertyId )
   12327             : {
   12328           0 :     m_aLinkPropertyMap[ nPropertyId ] = nLinkId;
   12329           0 : }
   12330             : 
   12331           0 : sal_Int32 PDFWriterImpl::createOutlineItem( sal_Int32 nParent, const OUString& rText, sal_Int32 nDestID )
   12332             : {
   12333             :     // create new item
   12334           0 :     sal_Int32 nNewItem = m_aOutline.size();
   12335           0 :     m_aOutline.push_back( PDFOutlineEntry() );
   12336             : 
   12337             :     // set item attributes
   12338           0 :     setOutlineItemParent( nNewItem, nParent );
   12339           0 :     setOutlineItemText( nNewItem, rText );
   12340           0 :     setOutlineItemDest( nNewItem, nDestID );
   12341             : 
   12342           0 :     return nNewItem;
   12343             : }
   12344             : 
   12345           0 : sal_Int32 PDFWriterImpl::setOutlineItemParent( sal_Int32 nItem, sal_Int32 nNewParent )
   12346             : {
   12347           0 :     if( nItem < 1 || nItem >= (sal_Int32)m_aOutline.size() )
   12348           0 :         return -1;
   12349             : 
   12350           0 :     int nRet = 0;
   12351             : 
   12352           0 :     if( nNewParent < 0 || nNewParent >= (sal_Int32)m_aOutline.size() || nNewParent == nItem )
   12353             :     {
   12354           0 :         nNewParent = 0;
   12355           0 :         nRet = -2;
   12356             :     }
   12357             :     // remove item from previous parent
   12358           0 :     sal_Int32 nParentID = m_aOutline[ nItem ].m_nParentID;
   12359           0 :     if( nParentID >= 0 && nParentID < (sal_Int32)m_aOutline.size() )
   12360             :     {
   12361           0 :         PDFOutlineEntry& rParent = m_aOutline[ nParentID ];
   12362             : 
   12363           0 :         for( std::vector<sal_Int32>::iterator it = rParent.m_aChildren.begin();
   12364           0 :              it != rParent.m_aChildren.end(); ++it )
   12365             :         {
   12366           0 :             if( *it == nItem )
   12367             :             {
   12368           0 :                 rParent.m_aChildren.erase( it );
   12369           0 :                 break;
   12370             :             }
   12371             :         }
   12372             :     }
   12373             : 
   12374             :     // insert item to new parent's list of children
   12375           0 :     m_aOutline[ nNewParent ].m_aChildren.push_back( nItem );
   12376             : 
   12377           0 :     return nRet;
   12378             : }
   12379             : 
   12380           0 : sal_Int32 PDFWriterImpl::setOutlineItemText( sal_Int32 nItem, const OUString& rText )
   12381             : {
   12382           0 :     if( nItem < 1 || nItem >= (sal_Int32)m_aOutline.size() )
   12383           0 :         return -1;
   12384             : 
   12385           0 :     m_aOutline[ nItem ].m_aTitle = psp::WhitespaceToSpace( rText );
   12386           0 :     return 0;
   12387             : }
   12388             : 
   12389           0 : sal_Int32 PDFWriterImpl::setOutlineItemDest( sal_Int32 nItem, sal_Int32 nDestID )
   12390             : {
   12391           0 :     if( nItem < 1 || nItem >= (sal_Int32)m_aOutline.size() ) // item does not exist
   12392           0 :         return -1;
   12393           0 :     if( nDestID < 0 || nDestID >= (sal_Int32)m_aDests.size() ) // dest does not exist
   12394           0 :         return -2;
   12395           0 :     m_aOutline[nItem].m_nDestID = nDestID;
   12396           0 :     return 0;
   12397             : }
   12398             : 
   12399           0 : const sal_Char* PDFWriterImpl::getStructureTag( PDFWriter::StructElement eType )
   12400             : {
   12401           0 :     static std::map< PDFWriter::StructElement, const char* > aTagStrings;
   12402           0 :     if( aTagStrings.empty() )
   12403             :     {
   12404           0 :         aTagStrings[ PDFWriter::NonStructElement] = "NonStruct";
   12405           0 :         aTagStrings[ PDFWriter::Document ]      = "Document";
   12406           0 :         aTagStrings[ PDFWriter::Part ]          = "Part";
   12407           0 :         aTagStrings[ PDFWriter::Article ]       = "Art";
   12408           0 :         aTagStrings[ PDFWriter::Section ]       = "Sect";
   12409           0 :         aTagStrings[ PDFWriter::Division ]      = "Div";
   12410           0 :         aTagStrings[ PDFWriter::BlockQuote ]    = "BlockQuote";
   12411           0 :         aTagStrings[ PDFWriter::Caption ]       = "Caption";
   12412           0 :         aTagStrings[ PDFWriter::TOC ]           = "TOC";
   12413           0 :         aTagStrings[ PDFWriter::TOCI ]          = "TOCI";
   12414           0 :         aTagStrings[ PDFWriter::Index ]         = "Index";
   12415           0 :         aTagStrings[ PDFWriter::Paragraph ]     = "P";
   12416           0 :         aTagStrings[ PDFWriter::Heading ]       = "H";
   12417           0 :         aTagStrings[ PDFWriter::H1 ]            = "H1";
   12418           0 :         aTagStrings[ PDFWriter::H2 ]            = "H2";
   12419           0 :         aTagStrings[ PDFWriter::H3 ]            = "H3";
   12420           0 :         aTagStrings[ PDFWriter::H4 ]            = "H4";
   12421           0 :         aTagStrings[ PDFWriter::H5 ]            = "H5";
   12422           0 :         aTagStrings[ PDFWriter::H6 ]            = "H6";
   12423           0 :         aTagStrings[ PDFWriter::List ]          = "L";
   12424           0 :         aTagStrings[ PDFWriter::ListItem ]      = "LI";
   12425           0 :         aTagStrings[ PDFWriter::LILabel ]       = "Lbl";
   12426           0 :         aTagStrings[ PDFWriter::LIBody ]        = "LBody";
   12427           0 :         aTagStrings[ PDFWriter::Table ]         = "Table";
   12428           0 :         aTagStrings[ PDFWriter::TableRow ]      = "TR";
   12429           0 :         aTagStrings[ PDFWriter::TableHeader ]   = "TH";
   12430           0 :         aTagStrings[ PDFWriter::TableData ]     = "TD";
   12431           0 :         aTagStrings[ PDFWriter::Span ]          = "Span";
   12432           0 :         aTagStrings[ PDFWriter::Quote ]         = "Quote";
   12433           0 :         aTagStrings[ PDFWriter::Note ]          = "Note";
   12434           0 :         aTagStrings[ PDFWriter::Reference ]     = "Reference";
   12435           0 :         aTagStrings[ PDFWriter::BibEntry ]      = "BibEntry";
   12436           0 :         aTagStrings[ PDFWriter::Code ]          = "Code";
   12437           0 :         aTagStrings[ PDFWriter::Link ]          = "Link";
   12438           0 :         aTagStrings[ PDFWriter::Figure ]        = "Figure";
   12439           0 :         aTagStrings[ PDFWriter::Formula ]       = "Formula";
   12440           0 :         aTagStrings[ PDFWriter::Form ]          = "Form";
   12441             :     }
   12442             : 
   12443           0 :     std::map< PDFWriter::StructElement, const char* >::const_iterator it = aTagStrings.find( eType );
   12444             : 
   12445           0 :     return it != aTagStrings.end() ? it->second : "Div";
   12446             : }
   12447             : 
   12448           0 : void PDFWriterImpl::beginStructureElementMCSeq()
   12449             : {
   12450           0 :     if( m_bEmitStructure &&
   12451           0 :         m_nCurrentStructElement > 0 && // StructTreeRoot
   12452           0 :         ! m_aStructure[ m_nCurrentStructElement ].m_bOpenMCSeq // already opened sequence
   12453             :         )
   12454             :     {
   12455           0 :         PDFStructureElement& rEle = m_aStructure[ m_nCurrentStructElement ];
   12456           0 :         OStringBuffer aLine( 128 );
   12457           0 :         sal_Int32 nMCID = m_aPages[ m_nCurrentPage ].m_aMCIDParents.size();
   12458           0 :         aLine.append( "/" );
   12459           0 :         if( !rEle.m_aAlias.isEmpty() )
   12460           0 :             aLine.append( rEle.m_aAlias );
   12461             :         else
   12462           0 :             aLine.append( getStructureTag( rEle.m_eType ) );
   12463           0 :         aLine.append( "<</MCID " );
   12464           0 :         aLine.append( nMCID );
   12465           0 :         aLine.append( ">>BDC\n" );
   12466           0 :         writeBuffer( aLine.getStr(), aLine.getLength() );
   12467             : 
   12468             :         // update the element's content list
   12469             : #if OSL_DEBUG_LEVEL > 1
   12470             :         fprintf( stderr, "beginning marked content id %" SAL_PRIdINT32 " on page object %" SAL_PRIdINT32 ", structure first page = %" SAL_PRIdINT32 "\n",
   12471             :                  nMCID,
   12472             :                  m_aPages[ m_nCurrentPage ].m_nPageObject,
   12473             :                  rEle.m_nFirstPageObject );
   12474             : #endif
   12475           0 :         rEle.m_aKids.push_back( PDFStructureElementKid( nMCID, m_aPages[m_nCurrentPage].m_nPageObject ) );
   12476             :         // update the page's mcid parent list
   12477           0 :         m_aPages[ m_nCurrentPage ].m_aMCIDParents.push_back( rEle.m_nObject );
   12478             :         // mark element MC sequence as open
   12479           0 :         rEle.m_bOpenMCSeq = true;
   12480             :     }
   12481             :     // handle artifacts
   12482           0 :     else if( ! m_bEmitStructure && m_aContext.Tagged &&
   12483           0 :                m_nCurrentStructElement > 0 &&
   12484           0 :                m_aStructure[ m_nCurrentStructElement ].m_eType == PDFWriter::NonStructElement &&
   12485           0 :              ! m_aStructure[ m_nCurrentStructElement ].m_bOpenMCSeq // already opened sequence
   12486             :              )
   12487             :     {
   12488           0 :         OStringBuffer aLine( 128 );
   12489           0 :         aLine.append( "/Artifact BMC\n" );
   12490           0 :         writeBuffer( aLine.getStr(), aLine.getLength() );
   12491             :         // mark element MC sequence as open
   12492           0 :         m_aStructure[ m_nCurrentStructElement ].m_bOpenMCSeq = true;
   12493             :     }
   12494           0 : }
   12495             : 
   12496           0 : void PDFWriterImpl::endStructureElementMCSeq()
   12497             : {
   12498           0 :     if( m_nCurrentStructElement > 0 && // StructTreeRoot
   12499           0 :         ( m_bEmitStructure || m_aStructure[ m_nCurrentStructElement ].m_eType == PDFWriter::NonStructElement ) &&
   12500           0 :         m_aStructure[ m_nCurrentStructElement ].m_bOpenMCSeq // must have an opened MC sequence
   12501             :         )
   12502             :     {
   12503           0 :         writeBuffer( "EMC\n", 4 );
   12504           0 :         m_aStructure[ m_nCurrentStructElement ].m_bOpenMCSeq = false;
   12505             :     }
   12506           0 : }
   12507             : 
   12508           0 : bool PDFWriterImpl::checkEmitStructure()
   12509             : {
   12510           0 :     bool bEmit = false;
   12511           0 :     if( m_aContext.Tagged )
   12512             :     {
   12513           0 :         bEmit = true;
   12514           0 :         sal_Int32 nEle = m_nCurrentStructElement;
   12515           0 :         while( nEle > 0 && nEle < sal_Int32(m_aStructure.size()) )
   12516             :         {
   12517           0 :             if( m_aStructure[ nEle ].m_eType == PDFWriter::NonStructElement )
   12518             :             {
   12519           0 :                 bEmit = false;
   12520           0 :                 break;
   12521             :             }
   12522           0 :             nEle = m_aStructure[ nEle ].m_nParentElement;
   12523             :         }
   12524             :     }
   12525           0 :     return bEmit;
   12526             : }
   12527             : 
   12528           0 : sal_Int32 PDFWriterImpl::beginStructureElement( PDFWriter::StructElement eType, const OUString& rAlias )
   12529             : {
   12530           0 :     if( m_nCurrentPage < 0 )
   12531           0 :         return -1;
   12532             : 
   12533           0 :     if( ! m_aContext.Tagged )
   12534           0 :         return -1;
   12535             : 
   12536             :     // close eventual current MC sequence
   12537           0 :     endStructureElementMCSeq();
   12538             : 
   12539           0 :     if( m_nCurrentStructElement == 0 &&
   12540           0 :         eType != PDFWriter::Document && eType != PDFWriter::NonStructElement )
   12541             :     {
   12542             :         // struct tree root hit, but not beginning document
   12543             :         // this might happen with setCurrentStructureElement
   12544             :         // silently insert structure into document again if one properly exists
   12545           0 :         if( ! m_aStructure[ 0 ].m_aChildren.empty() )
   12546             :         {
   12547           0 :             PDFWriter::StructElement childType = PDFWriter::NonStructElement;
   12548           0 :             sal_Int32 nNewCurElement = 0;
   12549           0 :             const std::list< sal_Int32 >& rRootChildren = m_aStructure[0].m_aChildren;
   12550           0 :             for( std::list< sal_Int32 >::const_iterator it = rRootChildren.begin();
   12551           0 :                  childType != PDFWriter::Document && it != rRootChildren.end(); ++it )
   12552             :             {
   12553           0 :                 nNewCurElement = *it;
   12554           0 :                 childType = m_aStructure[ nNewCurElement ].m_eType;
   12555             :             }
   12556           0 :             if( childType == PDFWriter::Document )
   12557             :             {
   12558           0 :                 m_nCurrentStructElement = nNewCurElement;
   12559             :                 DBG_ASSERT( false, "Structure element inserted to StructTreeRoot that is not a document" );
   12560             :             }
   12561             :             else {
   12562             :                 OSL_FAIL( "document structure in disorder !" );
   12563             :             }
   12564             :         }
   12565             :         else {
   12566             :             OSL_FAIL( "PDF document structure MUST be contained in a Document element" );
   12567             :         }
   12568             :     }
   12569             : 
   12570           0 :     sal_Int32 nNewId = sal_Int32(m_aStructure.size());
   12571           0 :     m_aStructure.push_back( PDFStructureElement() );
   12572           0 :     PDFStructureElement& rEle = m_aStructure.back();
   12573           0 :     rEle.m_eType            = eType;
   12574           0 :     rEle.m_nOwnElement      = nNewId;
   12575           0 :     rEle.m_nParentElement   = m_nCurrentStructElement;
   12576           0 :     rEle.m_nFirstPageObject = m_aPages[ m_nCurrentPage ].m_nPageObject;
   12577           0 :     m_aStructure[ m_nCurrentStructElement ].m_aChildren.push_back( nNewId );
   12578           0 :     m_nCurrentStructElement = nNewId;
   12579             : 
   12580             :     // handle alias names
   12581           0 :     if( !rAlias.isEmpty() && eType != PDFWriter::NonStructElement )
   12582             :     {
   12583           0 :         OStringBuffer aNameBuf( rAlias.getLength() );
   12584           0 :         appendName( rAlias, aNameBuf );
   12585           0 :         OString aAliasName( aNameBuf.makeStringAndClear() );
   12586           0 :         rEle.m_aAlias = aAliasName;
   12587           0 :         m_aRoleMap[ aAliasName ] = getStructureTag( eType );
   12588             :     }
   12589             : 
   12590             : #if OSL_DEBUG_LEVEL > 1
   12591             :     OStringBuffer aLine( "beginStructureElement " );
   12592             :     aLine.append( m_nCurrentStructElement );
   12593             :     aLine.append( ": " );
   12594             :     aLine.append( getStructureTag( eType ) );
   12595             :     if( !rEle.m_aAlias.isEmpty() )
   12596             :     {
   12597             :         aLine.append( " aliased as \"" );
   12598             :         aLine.append( rEle.m_aAlias );
   12599             :         aLine.append( '\"' );
   12600             :     }
   12601             :     emitComment( aLine.getStr() );
   12602             : #endif
   12603             : 
   12604             :     // check whether to emit structure henceforth
   12605           0 :     m_bEmitStructure = checkEmitStructure();
   12606             : 
   12607           0 :     if( m_bEmitStructure ) // don't create nonexistant objects
   12608             :     {
   12609           0 :         rEle.m_nObject      = createObject();
   12610             :         // update parent's kids list
   12611           0 :         m_aStructure[ rEle.m_nParentElement ].m_aKids.push_back(PDFStructureElementKid(rEle.m_nObject));
   12612             :     }
   12613           0 :     return nNewId;
   12614             : }
   12615             : 
   12616           0 : void PDFWriterImpl::endStructureElement()
   12617             : {
   12618           0 :     if( m_nCurrentPage < 0 )
   12619           0 :         return;
   12620             : 
   12621           0 :     if( ! m_aContext.Tagged )
   12622           0 :         return;
   12623             : 
   12624           0 :     if( m_nCurrentStructElement == 0 )
   12625             :     {
   12626             :         // hit the struct tree root, that means there is an endStructureElement
   12627             :         // without corresponding beginStructureElement
   12628           0 :         return;
   12629             :     }
   12630             : 
   12631             :     // end the marked content sequence
   12632           0 :     endStructureElementMCSeq();
   12633             : 
   12634             : #if OSL_DEBUG_LEVEL > 1
   12635             :     OStringBuffer aLine( "endStructureElement " );
   12636             :     aLine.append( m_nCurrentStructElement );
   12637             :     aLine.append( ": " );
   12638             :     aLine.append( getStructureTag( m_aStructure[ m_nCurrentStructElement ].m_eType ) );
   12639             :     if( !m_aStructure[ m_nCurrentStructElement ].m_aAlias.isEmpty() )
   12640             :     {
   12641             :         aLine.append( " aliased as \"" );
   12642             :         aLine.append( m_aStructure[ m_nCurrentStructElement ].m_aAlias );
   12643             :         aLine.append( '\"' );
   12644             :     }
   12645             : #endif
   12646             : 
   12647             :     // "end" the structure element, the parent becomes current element
   12648           0 :     m_nCurrentStructElement = m_aStructure[ m_nCurrentStructElement ].m_nParentElement;
   12649             : 
   12650             :     // check whether to emit structure henceforth
   12651           0 :     m_bEmitStructure = checkEmitStructure();
   12652             : 
   12653             : #if OSL_DEBUG_LEVEL > 1
   12654             :     if( m_bEmitStructure )
   12655             :         emitComment( aLine.getStr() );
   12656             : #endif
   12657             : }
   12658             : 
   12659             : //---> i94258
   12660             : /*
   12661             :  * This function adds an internal structure list container to overcome the 8191 elements array limitation
   12662             :  * in kids element emission.
   12663             :  * Recursive function
   12664             :  *
   12665             :  */
   12666           0 : void PDFWriterImpl::addInternalStructureContainer( PDFStructureElement& rEle )
   12667             : {
   12668           0 :     if( rEle.m_eType == PDFWriter::NonStructElement &&
   12669           0 :         rEle.m_nOwnElement != rEle.m_nParentElement )
   12670           0 :         return;
   12671             : 
   12672           0 :     for( std::list< sal_Int32 >::const_iterator it = rEle.m_aChildren.begin(); it != rEle.m_aChildren.end(); ++it )
   12673             :     {
   12674           0 :         if( *it > 0 && *it < sal_Int32(m_aStructure.size()) )
   12675             :         {
   12676           0 :             PDFStructureElement& rChild = m_aStructure[ *it ];
   12677           0 :             if( rChild.m_eType != PDFWriter::NonStructElement )
   12678             :             {
   12679             :                 //triggered when a child of the rEle element is found
   12680           0 :                 if( rChild.m_nParentElement == rEle.m_nOwnElement )
   12681           0 :                     addInternalStructureContainer( rChild );//examine the child
   12682             :                 else
   12683             :                 {
   12684             :                     OSL_FAIL( "PDFWriterImpl::addInternalStructureContainer: invalid child structure element" );
   12685             : #if OSL_DEBUG_LEVEL > 1
   12686             :                     fprintf( stderr, "PDFWriterImpl::addInternalStructureContainer: invalid child structure elemnt with id %" SAL_PRIdINT32 "\n", *it );
   12687             : #endif
   12688             :                 }
   12689             :             }
   12690             :         }
   12691             :         else
   12692             :         {
   12693             :             OSL_FAIL( "PDFWriterImpl::emitStructure: invalid child structure id" );
   12694             : #if OSL_DEBUG_LEVEL > 1
   12695             :             fprintf( stderr, "PDFWriterImpl::addInternalStructureContainer: invalid child structure id %" SAL_PRIdINT32 "\n", *it );
   12696             : #endif
   12697             :         }
   12698             :     }
   12699             : 
   12700           0 :     if( rEle.m_nOwnElement != rEle.m_nParentElement )
   12701             :     {
   12702           0 :         if( !rEle.m_aKids.empty() )
   12703             :         {
   12704           0 :             if( rEle.m_aKids.size() > ncMaxPDFArraySize ) {
   12705             :                 //then we need to add the containers for the kids elements
   12706             :                 // a list to be used for the new kid element
   12707           0 :                 std::list< PDFStructureElementKid > aNewKids;
   12708           0 :                 std::list< sal_Int32 > aNewChildren;
   12709             : 
   12710             :                 // add Div in RoleMap, in case no one else did (TODO: is it needed? Is it dangerous?)
   12711           0 :                 OStringBuffer aNameBuf( "Div" );
   12712           0 :                 OString aAliasName( aNameBuf.makeStringAndClear() );
   12713           0 :                 m_aRoleMap[ aAliasName ] = getStructureTag( PDFWriter::Division );
   12714             : 
   12715           0 :                 while( rEle.m_aKids.size() > ncMaxPDFArraySize )
   12716             :                 {
   12717           0 :                     sal_Int32 nCurrentStructElement = rEle.m_nOwnElement;
   12718           0 :                     sal_Int32 nNewId = sal_Int32(m_aStructure.size());
   12719           0 :                     m_aStructure.push_back( PDFStructureElement() );
   12720           0 :                     PDFStructureElement& rEleNew = m_aStructure.back();
   12721           0 :                     rEleNew.m_aAlias            = aAliasName;
   12722           0 :                     rEleNew.m_eType             = PDFWriter::Division; // a new Div type container
   12723           0 :                     rEleNew.m_nOwnElement       = nNewId;
   12724           0 :                     rEleNew.m_nParentElement    = nCurrentStructElement;
   12725             :                     //inherit the same page as the first child to be reparented
   12726           0 :                     rEleNew.m_nFirstPageObject  = m_aStructure[ rEle.m_aChildren.front() ].m_nFirstPageObject;
   12727           0 :                     rEleNew.m_nObject           = createObject();//assign a PDF object number
   12728             :                     //add the object to the kid list of the parent
   12729           0 :                     aNewKids.push_back( PDFStructureElementKid( rEleNew.m_nObject ) );
   12730           0 :                     aNewChildren.push_back( nNewId );
   12731             : 
   12732           0 :                     std::list< sal_Int32 >::iterator aChildEndIt( rEle.m_aChildren.begin() );
   12733           0 :                     std::list< PDFStructureElementKid >::iterator aKidEndIt( rEle.m_aKids.begin() );
   12734           0 :                     advance( aChildEndIt, ncMaxPDFArraySize );
   12735           0 :                     advance( aKidEndIt, ncMaxPDFArraySize );
   12736             : 
   12737             :                     rEleNew.m_aKids.splice( rEleNew.m_aKids.begin(),
   12738             :                                             rEle.m_aKids,
   12739             :                                             rEle.m_aKids.begin(),
   12740           0 :                                             aKidEndIt );
   12741             :                     rEleNew.m_aChildren.splice( rEleNew.m_aChildren.begin(),
   12742             :                                                 rEle.m_aChildren,
   12743             :                                                 rEle.m_aChildren.begin(),
   12744           0 :                                                 aChildEndIt );
   12745             :                     // set the kid's new parent
   12746           0 :                     for( std::list< sal_Int32 >::const_iterator it = rEleNew.m_aChildren.begin();
   12747           0 :                          it != rEleNew.m_aChildren.end(); ++it )
   12748             :                     {
   12749           0 :                         m_aStructure[ *it ].m_nParentElement = nNewId;
   12750             :                     }
   12751             :                 }
   12752             :                 //finally add the new kids resulting from the container added
   12753           0 :                 rEle.m_aKids.insert( rEle.m_aKids.begin(), aNewKids.begin(), aNewKids.end() );
   12754           0 :                 rEle.m_aChildren.insert( rEle.m_aChildren.begin(), aNewChildren.begin(), aNewChildren.end() );
   12755             :             }
   12756             :         }
   12757             :     }
   12758             : }
   12759             : //<--- i94258
   12760             : 
   12761           0 : bool PDFWriterImpl::setCurrentStructureElement( sal_Int32 nEle )
   12762             : {
   12763           0 :     bool bSuccess = false;
   12764             : 
   12765           0 :     if( m_aContext.Tagged && nEle >= 0 && nEle < sal_Int32(m_aStructure.size()) )
   12766             :     {
   12767             :         // end eventual previous marked content sequence
   12768           0 :         endStructureElementMCSeq();
   12769             : 
   12770           0 :         m_nCurrentStructElement = nEle;
   12771           0 :         m_bEmitStructure = checkEmitStructure();
   12772             : #if OSL_DEBUG_LEVEL > 1
   12773             :         OStringBuffer aLine( "setCurrentStructureElement " );
   12774             :         aLine.append( m_nCurrentStructElement );
   12775             :         aLine.append( ": " );
   12776             :         aLine.append( getStructureTag( m_aStructure[ m_nCurrentStructElement ].m_eType ) );
   12777             :         if( !m_aStructure[ m_nCurrentStructElement ].m_aAlias.isEmpty() )
   12778             :         {
   12779             :             aLine.append( " aliased as \"" );
   12780             :             aLine.append( m_aStructure[ m_nCurrentStructElement ].m_aAlias );
   12781             :             aLine.append( '\"' );
   12782             :         }
   12783             :         if( ! m_bEmitStructure )
   12784             :             aLine.append( " (inside NonStruct)" );
   12785             :         emitComment( aLine.getStr() );
   12786             : #endif
   12787           0 :         bSuccess = true;
   12788             :     }
   12789             : 
   12790           0 :     return bSuccess;
   12791             : }
   12792             : 
   12793           0 : bool PDFWriterImpl::setStructureAttribute( enum PDFWriter::StructAttribute eAttr, enum PDFWriter::StructAttributeValue eVal )
   12794             : {
   12795           0 :     if( !m_aContext.Tagged )
   12796           0 :         return false;
   12797             : 
   12798           0 :     bool bInsert = false;
   12799           0 :     if( m_nCurrentStructElement > 0 && m_bEmitStructure )
   12800             :     {
   12801           0 :         PDFWriter::StructElement eType = m_aStructure[ m_nCurrentStructElement ].m_eType;
   12802           0 :         switch( eAttr )
   12803             :         {
   12804             :             case PDFWriter::Placement:
   12805           0 :                 if( eVal == PDFWriter::Block        ||
   12806           0 :                     eVal == PDFWriter::Inline       ||
   12807           0 :                     eVal == PDFWriter::Before       ||
   12808           0 :                     eVal == PDFWriter::Start        ||
   12809             :                     eVal == PDFWriter::End )
   12810           0 :                     bInsert = true;
   12811           0 :                 break;
   12812             :             case PDFWriter::WritingMode:
   12813           0 :                 if( eVal == PDFWriter::LrTb         ||
   12814           0 :                     eVal == PDFWriter::RlTb         ||
   12815             :                     eVal == PDFWriter::TbRl )
   12816             :                 {
   12817           0 :                     bInsert = true;
   12818             :                 }
   12819           0 :                 break;
   12820             :             case PDFWriter::TextAlign:
   12821           0 :                 if( eVal == PDFWriter::Start        ||
   12822           0 :                     eVal == PDFWriter::Center       ||
   12823           0 :                     eVal == PDFWriter::End          ||
   12824             :                     eVal == PDFWriter::Justify )
   12825             :                 {
   12826           0 :                     if( eType == PDFWriter::Paragraph   ||
   12827           0 :                         eType == PDFWriter::Heading     ||
   12828           0 :                         eType == PDFWriter::H1          ||
   12829           0 :                         eType == PDFWriter::H2          ||
   12830           0 :                         eType == PDFWriter::H3          ||
   12831           0 :                         eType == PDFWriter::H4          ||
   12832           0 :                         eType == PDFWriter::H5          ||
   12833           0 :                         eType == PDFWriter::H6          ||
   12834           0 :                         eType == PDFWriter::List        ||
   12835           0 :                         eType == PDFWriter::ListItem    ||
   12836           0 :                         eType == PDFWriter::LILabel     ||
   12837           0 :                         eType == PDFWriter::LIBody      ||
   12838           0 :                         eType == PDFWriter::Table       ||
   12839           0 :                         eType == PDFWriter::TableRow    ||
   12840           0 :                         eType == PDFWriter::TableHeader ||
   12841             :                         eType == PDFWriter::TableData )
   12842             :                     {
   12843           0 :                         bInsert = true;
   12844             :                     }
   12845             :                 }
   12846           0 :                 break;
   12847             :             case PDFWriter::Width:
   12848             :             case PDFWriter::Height:
   12849           0 :                 if( eVal == PDFWriter::Auto )
   12850             :                 {
   12851           0 :                     if( eType == PDFWriter::Figure      ||
   12852           0 :                         eType == PDFWriter::Formula     ||
   12853           0 :                         eType == PDFWriter::Form        ||
   12854           0 :                         eType == PDFWriter::Table       ||
   12855           0 :                         eType == PDFWriter::TableHeader ||
   12856             :                         eType == PDFWriter::TableData )
   12857             :                     {
   12858           0 :                         bInsert = true;
   12859             :                     }
   12860             :                 }
   12861           0 :                 break;
   12862             :             case PDFWriter::BlockAlign:
   12863           0 :                 if( eVal == PDFWriter::Before       ||
   12864           0 :                     eVal == PDFWriter::Middle       ||
   12865           0 :                     eVal == PDFWriter::After        ||
   12866             :                     eVal == PDFWriter::Justify )
   12867             :                 {
   12868           0 :                     if( eType == PDFWriter::TableHeader ||
   12869             :                         eType == PDFWriter::TableData )
   12870             :                     {
   12871           0 :                         bInsert = true;
   12872             :                     }
   12873             :                 }
   12874           0 :                 break;
   12875             :             case PDFWriter::InlineAlign:
   12876           0 :                 if( eVal == PDFWriter::Start        ||
   12877           0 :                     eVal == PDFWriter::Center       ||
   12878             :                     eVal == PDFWriter::End )
   12879             :                 {
   12880           0 :                     if( eType == PDFWriter::TableHeader ||
   12881             :                         eType == PDFWriter::TableData )
   12882             :                     {
   12883           0 :                         bInsert = true;
   12884             :                     }
   12885             :                 }
   12886           0 :                 break;
   12887             :             case PDFWriter::LineHeight:
   12888           0 :                 if( eVal == PDFWriter::Normal       ||
   12889             :                     eVal == PDFWriter::Auto )
   12890             :                 {
   12891             :                     // only for ILSE and BLSE
   12892           0 :                     if( eType == PDFWriter::Paragraph   ||
   12893           0 :                         eType == PDFWriter::Heading     ||
   12894           0 :                         eType == PDFWriter::H1          ||
   12895           0 :                         eType == PDFWriter::H2          ||
   12896           0 :                         eType == PDFWriter::H3          ||
   12897           0 :                         eType == PDFWriter::H4          ||
   12898           0 :                         eType == PDFWriter::H5          ||
   12899           0 :                         eType == PDFWriter::H6          ||
   12900           0 :                         eType == PDFWriter::List        ||
   12901           0 :                         eType == PDFWriter::ListItem    ||
   12902           0 :                         eType == PDFWriter::LILabel     ||
   12903           0 :                         eType == PDFWriter::LIBody      ||
   12904           0 :                         eType == PDFWriter::Table       ||
   12905           0 :                         eType == PDFWriter::TableRow    ||
   12906           0 :                         eType == PDFWriter::TableHeader ||
   12907           0 :                         eType == PDFWriter::TableData   ||
   12908           0 :                         eType == PDFWriter::Span        ||
   12909           0 :                         eType == PDFWriter::Quote       ||
   12910           0 :                         eType == PDFWriter::Note        ||
   12911           0 :                         eType == PDFWriter::Reference   ||
   12912           0 :                         eType == PDFWriter::BibEntry    ||
   12913           0 :                         eType == PDFWriter::Code        ||
   12914             :                         eType == PDFWriter::Link )
   12915             :                     {
   12916           0 :                         bInsert = true;
   12917             :                     }
   12918             :                 }
   12919           0 :                 break;
   12920             :             case PDFWriter::TextDecorationType:
   12921           0 :                 if( eVal == PDFWriter::NONE         ||
   12922           0 :                     eVal == PDFWriter::Underline    ||
   12923           0 :                     eVal == PDFWriter::Overline     ||
   12924             :                     eVal == PDFWriter::LineThrough )
   12925             :                 {
   12926             :                     // only for ILSE and BLSE
   12927           0 :                     if( eType == PDFWriter::Paragraph   ||
   12928           0 :                         eType == PDFWriter::Heading     ||
   12929           0 :                         eType == PDFWriter::H1          ||
   12930           0 :                         eType == PDFWriter::H2          ||
   12931           0 :                         eType == PDFWriter::H3          ||
   12932           0 :                         eType == PDFWriter::H4          ||
   12933           0 :                         eType == PDFWriter::H5          ||
   12934           0 :                         eType == PDFWriter::H6          ||
   12935           0 :                         eType == PDFWriter::List        ||
   12936           0 :                         eType == PDFWriter::ListItem    ||
   12937           0 :                         eType == PDFWriter::LILabel     ||
   12938           0 :                         eType == PDFWriter::LIBody      ||
   12939           0 :                         eType == PDFWriter::Table       ||
   12940           0 :                         eType == PDFWriter::TableRow    ||
   12941           0 :                         eType == PDFWriter::TableHeader ||
   12942           0 :                         eType == PDFWriter::TableData   ||
   12943           0 :                         eType == PDFWriter::Span        ||
   12944           0 :                         eType == PDFWriter::Quote       ||
   12945           0 :                         eType == PDFWriter::Note        ||
   12946           0 :                         eType == PDFWriter::Reference   ||
   12947           0 :                         eType == PDFWriter::BibEntry    ||
   12948           0 :                         eType == PDFWriter::Code        ||
   12949             :                         eType == PDFWriter::Link )
   12950             :                     {
   12951           0 :                         bInsert = true;
   12952             :                     }
   12953             :                 }
   12954           0 :                 break;
   12955             :             case PDFWriter::ListNumbering:
   12956           0 :                 if( eVal == PDFWriter::NONE         ||
   12957           0 :                     eVal == PDFWriter::Disc         ||
   12958           0 :                     eVal == PDFWriter::Circle       ||
   12959           0 :                     eVal == PDFWriter::Square       ||
   12960           0 :                     eVal == PDFWriter::Decimal      ||
   12961           0 :                     eVal == PDFWriter::UpperRoman   ||
   12962           0 :                     eVal == PDFWriter::LowerRoman   ||
   12963           0 :                     eVal == PDFWriter::UpperAlpha   ||
   12964             :                     eVal == PDFWriter::LowerAlpha )
   12965             :                 {
   12966           0 :                     if( eType == PDFWriter::List )
   12967           0 :                         bInsert = true;
   12968             :                 }
   12969           0 :                 break;
   12970           0 :             default: break;
   12971             :         }
   12972             :     }
   12973             : 
   12974           0 :     if( bInsert )
   12975           0 :         m_aStructure[ m_nCurrentStructElement ].m_aAttributes[ eAttr ] = PDFStructureAttribute( eVal );
   12976             : #if OSL_DEBUG_LEVEL > 1
   12977             :     else if( m_nCurrentStructElement > 0 && m_bEmitStructure )
   12978             :         fprintf( stderr, "rejecting setStructureAttribute( %s, %s ) on %s (%s) element\n",
   12979             :                  getAttributeTag( eAttr ),
   12980             :                  getAttributeValueTag( eVal ),
   12981             :                  getStructureTag( m_aStructure[ m_nCurrentStructElement ].m_eType ),
   12982             :                  m_aStructure[ m_nCurrentStructElement ].m_aAlias.getStr()
   12983             :                  );
   12984             : #endif
   12985             : 
   12986           0 :     return bInsert;
   12987             : }
   12988             : 
   12989           0 : bool PDFWriterImpl::setStructureAttributeNumerical( enum PDFWriter::StructAttribute eAttr, sal_Int32 nValue )
   12990             : {
   12991           0 :     if( ! m_aContext.Tagged )
   12992           0 :         return false;
   12993             : 
   12994           0 :     bool bInsert = false;
   12995           0 :     if( m_nCurrentStructElement > 0 && m_bEmitStructure )
   12996             :     {
   12997           0 :         if( eAttr == PDFWriter::Language )
   12998             :         {
   12999           0 :             m_aStructure[ m_nCurrentStructElement ].m_aLocale = LanguageTag( (LanguageType)nValue ).getLocale();
   13000           0 :             return true;
   13001             :         }
   13002             : 
   13003           0 :         PDFWriter::StructElement eType = m_aStructure[ m_nCurrentStructElement ].m_eType;
   13004           0 :         switch( eAttr )
   13005             :         {
   13006             :             case PDFWriter::SpaceBefore:
   13007             :             case PDFWriter::SpaceAfter:
   13008             :             case PDFWriter::StartIndent:
   13009             :             case PDFWriter::EndIndent:
   13010             :                 // just for BLSE
   13011           0 :                 if( eType == PDFWriter::Paragraph   ||
   13012           0 :                     eType == PDFWriter::Heading     ||
   13013           0 :                     eType == PDFWriter::H1          ||
   13014           0 :                     eType == PDFWriter::H2          ||
   13015           0 :                     eType == PDFWriter::H3          ||
   13016           0 :                     eType == PDFWriter::H4          ||
   13017           0 :                     eType == PDFWriter::H5          ||
   13018           0 :                     eType == PDFWriter::H6          ||
   13019           0 :                     eType == PDFWriter::List        ||
   13020           0 :                     eType == PDFWriter::ListItem    ||
   13021           0 :                     eType == PDFWriter::LILabel     ||
   13022           0 :                     eType == PDFWriter::LIBody      ||
   13023           0 :                     eType == PDFWriter::Table       ||
   13024           0 :                     eType == PDFWriter::TableRow    ||
   13025           0 :                     eType == PDFWriter::TableHeader ||
   13026             :                     eType == PDFWriter::TableData )
   13027             :                 {
   13028           0 :                     bInsert = true;
   13029             :                 }
   13030           0 :                 break;
   13031             :             case PDFWriter::TextIndent:
   13032             :                 // paragraph like BLSE and additional elements
   13033           0 :                 if( eType == PDFWriter::Paragraph   ||
   13034           0 :                     eType == PDFWriter::Heading     ||
   13035           0 :                     eType == PDFWriter::H1          ||
   13036           0 :                     eType == PDFWriter::H2          ||
   13037           0 :                     eType == PDFWriter::H3          ||
   13038           0 :                     eType == PDFWriter::H4          ||
   13039           0 :                     eType == PDFWriter::H5          ||
   13040           0 :                     eType == PDFWriter::H6          ||
   13041           0 :                     eType == PDFWriter::LILabel     ||
   13042           0 :                     eType == PDFWriter::LIBody      ||
   13043           0 :                     eType == PDFWriter::TableHeader ||
   13044             :                     eType == PDFWriter::TableData )
   13045             :                 {
   13046           0 :                     bInsert = true;
   13047             :                 }
   13048           0 :                 break;
   13049             :             case PDFWriter::Width:
   13050             :             case PDFWriter::Height:
   13051           0 :                 if( eType == PDFWriter::Figure      ||
   13052           0 :                     eType == PDFWriter::Formula     ||
   13053           0 :                     eType == PDFWriter::Form        ||
   13054           0 :                     eType == PDFWriter::Table       ||
   13055           0 :                     eType == PDFWriter::TableHeader ||
   13056             :                     eType == PDFWriter::TableData )
   13057             :                 {
   13058           0 :                     bInsert = true;
   13059             :                 }
   13060           0 :                 break;
   13061             :             case PDFWriter::LineHeight:
   13062             :             case PDFWriter::BaselineShift:
   13063             :                 // only for ILSE and BLSE
   13064           0 :                 if( eType == PDFWriter::Paragraph   ||
   13065           0 :                     eType == PDFWriter::Heading     ||
   13066           0 :                     eType == PDFWriter::H1          ||
   13067           0 :                     eType == PDFWriter::H2          ||
   13068           0 :                     eType == PDFWriter::H3          ||
   13069           0 :                     eType == PDFWriter::H4          ||
   13070           0 :                     eType == PDFWriter::H5          ||
   13071           0 :                     eType == PDFWriter::H6          ||
   13072           0 :                     eType == PDFWriter::List        ||
   13073           0 :                     eType == PDFWriter::ListItem    ||
   13074           0 :                     eType == PDFWriter::LILabel     ||
   13075           0 :                     eType == PDFWriter::LIBody      ||
   13076           0 :                     eType == PDFWriter::Table       ||
   13077           0 :                     eType == PDFWriter::TableRow    ||
   13078           0 :                     eType == PDFWriter::TableHeader ||
   13079           0 :                     eType == PDFWriter::TableData   ||
   13080           0 :                     eType == PDFWriter::Span        ||
   13081           0 :                     eType == PDFWriter::Quote       ||
   13082           0 :                     eType == PDFWriter::Note        ||
   13083           0 :                     eType == PDFWriter::Reference   ||
   13084           0 :                     eType == PDFWriter::BibEntry    ||
   13085           0 :                     eType == PDFWriter::Code        ||
   13086             :                     eType == PDFWriter::Link )
   13087             :                 {
   13088           0 :                         bInsert = true;
   13089             :                 }
   13090           0 :                 break;
   13091             :             case PDFWriter::RowSpan:
   13092             :             case PDFWriter::ColSpan:
   13093             :                 // only for table cells
   13094           0 :                 if( eType == PDFWriter::TableHeader ||
   13095             :                     eType == PDFWriter::TableData )
   13096             :                 {
   13097           0 :                     bInsert = true;
   13098             :                 }
   13099           0 :                 break;
   13100             :             case PDFWriter::LinkAnnotation:
   13101           0 :                 if( eType == PDFWriter::Link )
   13102           0 :                     bInsert = true;
   13103           0 :                 break;
   13104           0 :             default: break;
   13105             :         }
   13106             :     }
   13107             : 
   13108           0 :     if( bInsert )
   13109           0 :         m_aStructure[ m_nCurrentStructElement ].m_aAttributes[ eAttr ] = PDFStructureAttribute( nValue );
   13110             : #if OSL_DEBUG_LEVEL > 1
   13111             :     else if( m_nCurrentStructElement > 0 && m_bEmitStructure )
   13112             :         fprintf( stderr, "rejecting setStructureAttributeNumerical( %s, %d ) on %s (%s) element\n",
   13113             :                  getAttributeTag( eAttr ),
   13114             :                  (int)nValue,
   13115             :                  getStructureTag( m_aStructure[ m_nCurrentStructElement ].m_eType ),
   13116             :                  m_aStructure[ m_nCurrentStructElement ].m_aAlias.getStr() );
   13117             : #endif
   13118             : 
   13119           0 :     return bInsert;
   13120             : }
   13121             : 
   13122           0 : void PDFWriterImpl::setStructureBoundingBox( const Rectangle& rRect )
   13123             : {
   13124           0 :     sal_Int32 nPageNr = m_nCurrentPage;
   13125           0 :     if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() || !m_aContext.Tagged )
   13126           0 :         return;
   13127             : 
   13128           0 :     if( m_nCurrentStructElement > 0 && m_bEmitStructure )
   13129             :     {
   13130           0 :         PDFWriter::StructElement eType = m_aStructure[ m_nCurrentStructElement ].m_eType;
   13131           0 :         if( eType == PDFWriter::Figure      ||
   13132           0 :             eType == PDFWriter::Formula     ||
   13133           0 :             eType == PDFWriter::Form        ||
   13134             :             eType == PDFWriter::Table )
   13135             :         {
   13136           0 :             m_aStructure[ m_nCurrentStructElement ].m_aBBox = rRect;
   13137             :             // convert to default user space now, since the mapmode may change
   13138           0 :             m_aPages[nPageNr].convertRect( m_aStructure[ m_nCurrentStructElement ].m_aBBox );
   13139             :         }
   13140             :     }
   13141             : }
   13142             : 
   13143           0 : void PDFWriterImpl::setActualText( const OUString& rText )
   13144             : {
   13145           0 :     if( m_aContext.Tagged && m_nCurrentStructElement > 0 && m_bEmitStructure )
   13146             :     {
   13147           0 :         m_aStructure[ m_nCurrentStructElement ].m_aActualText = rText;
   13148             :     }
   13149           0 : }
   13150             : 
   13151           0 : void PDFWriterImpl::setAlternateText( const OUString& rText )
   13152             : {
   13153           0 :     if( m_aContext.Tagged && m_nCurrentStructElement > 0 && m_bEmitStructure )
   13154             :     {
   13155           0 :         m_aStructure[ m_nCurrentStructElement ].m_aAltText = rText;
   13156             :     }
   13157           0 : }
   13158             : 
   13159           0 : void PDFWriterImpl::setAutoAdvanceTime( sal_uInt32 nSeconds, sal_Int32 nPageNr )
   13160             : {
   13161           0 :     if( nPageNr < 0 )
   13162           0 :         nPageNr = m_nCurrentPage;
   13163             : 
   13164           0 :     if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() )
   13165           0 :         return;
   13166             : 
   13167           0 :     m_aPages[ nPageNr ].m_nDuration = nSeconds;
   13168             : }
   13169             : 
   13170           0 : void PDFWriterImpl::setPageTransition( PDFWriter::PageTransition eType, sal_uInt32 nMilliSec, sal_Int32 nPageNr )
   13171             : {
   13172           0 :     if( nPageNr < 0 )
   13173           0 :         nPageNr = m_nCurrentPage;
   13174             : 
   13175           0 :     if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() )
   13176           0 :         return;
   13177             : 
   13178           0 :     m_aPages[ nPageNr ].m_eTransition   = eType;
   13179           0 :     m_aPages[ nPageNr ].m_nTransTime    = nMilliSec;
   13180             : }
   13181             : 
   13182           0 : void PDFWriterImpl::ensureUniqueRadioOnValues()
   13183             : {
   13184             :     // loop over radio groups
   13185           0 :     for( std::map<sal_Int32,sal_Int32>::const_iterator group = m_aRadioGroupWidgets.begin();
   13186           0 :          group != m_aRadioGroupWidgets.end(); ++group )
   13187             :     {
   13188           0 :         PDFWidget& rGroupWidget = m_aWidgets[ group->second ];
   13189             :         // check whether all kids have a unique OnValue
   13190           0 :         std::unordered_map< OUString, sal_Int32, OUStringHash > aOnValues;
   13191           0 :         int nChildren = rGroupWidget.m_aKidsIndex.size();
   13192           0 :         bool bIsUnique = true;
   13193           0 :         for( int nKid = 0; nKid < nChildren && bIsUnique; nKid++ )
   13194             :         {
   13195           0 :             int nKidIndex = rGroupWidget.m_aKidsIndex[nKid];
   13196           0 :             const OUString& rVal = m_aWidgets[nKidIndex].m_aOnValue;
   13197             :             #if OSL_DEBUG_LEVEL > 1
   13198             :             fprintf( stderr, "OnValue: %s\n", OUStringToOString( rVal, RTL_TEXTENCODING_UTF8 ).getStr() );
   13199             :             #endif
   13200           0 :             if( aOnValues.find( rVal ) == aOnValues.end() )
   13201             :             {
   13202           0 :                 aOnValues[ rVal ] = 1;
   13203             :             }
   13204             :             else
   13205             :             {
   13206           0 :                 bIsUnique = false;
   13207             :             }
   13208             :         }
   13209           0 :         if( ! bIsUnique )
   13210             :         {
   13211             :             #if OSL_DEBUG_LEVEL > 1
   13212             :             fprintf( stderr, "enforcing unique OnValues\n" );
   13213             :             #endif
   13214             :             // make unique by using ascending OnValues
   13215           0 :             for( int nKid = 0; nKid < nChildren; nKid++ )
   13216             :             {
   13217           0 :                 int nKidIndex = rGroupWidget.m_aKidsIndex[nKid];
   13218           0 :                 PDFWidget& rKid = m_aWidgets[nKidIndex];
   13219           0 :                 rKid.m_aOnValue = OUString::number( nKid+1 );
   13220           0 :                 if( rKid.m_aValue != "Off" )
   13221           0 :                     rKid.m_aValue = rKid.m_aOnValue;
   13222             :             }
   13223             :         }
   13224             :         // finally move the "Yes" appearance to the OnValue appearance
   13225           0 :         for( int nKid = 0; nKid < nChildren; nKid++ )
   13226             :         {
   13227           0 :             int nKidIndex = rGroupWidget.m_aKidsIndex[nKid];
   13228           0 :             PDFWidget& rKid = m_aWidgets[nKidIndex];
   13229           0 :             PDFAppearanceMap::iterator app_it = rKid.m_aAppearances.find( "N" );
   13230           0 :             if( app_it != rKid.m_aAppearances.end() )
   13231             :             {
   13232           0 :                 PDFAppearanceStreams::iterator stream_it = app_it->second.find( "Yes" );
   13233           0 :                 if( stream_it != app_it->second.end() )
   13234             :                 {
   13235           0 :                     SvMemoryStream* pStream = stream_it->second;
   13236           0 :                     app_it->second.erase( stream_it );
   13237           0 :                     OStringBuffer aBuf( rKid.m_aOnValue.getLength()*2 );
   13238           0 :                     appendName( rKid.m_aOnValue, aBuf );
   13239           0 :                     (app_it->second)[ aBuf.makeStringAndClear() ] = pStream;
   13240             :                 }
   13241             :                 #if OSL_DEBUG_LEVEL > 1
   13242             :                 else
   13243             :                     fprintf( stderr, "error: RadioButton without \"Yes\" stream\n" );
   13244             :                 #endif
   13245             :             }
   13246             :             // update selected radio button
   13247           0 :             if( rKid.m_aValue != "Off" )
   13248             :             {
   13249           0 :                 rGroupWidget.m_aValue = rKid.m_aValue;
   13250             :             }
   13251             :         }
   13252           0 :     }
   13253           0 : }
   13254             : 
   13255           0 : sal_Int32 PDFWriterImpl::findRadioGroupWidget( const PDFWriter::RadioButtonWidget& rBtn )
   13256             : {
   13257           0 :     sal_Int32 nRadioGroupWidget = -1;
   13258             : 
   13259           0 :     std::map< sal_Int32, sal_Int32 >::const_iterator it = m_aRadioGroupWidgets.find( rBtn.RadioGroup );
   13260             : 
   13261           0 :     if( it == m_aRadioGroupWidgets.end() )
   13262             :     {
   13263           0 :         m_aRadioGroupWidgets[ rBtn.RadioGroup ] = nRadioGroupWidget =
   13264           0 :             sal_Int32(m_aWidgets.size());
   13265             : 
   13266             :         // new group, insert the radiobutton
   13267           0 :         m_aWidgets.push_back( PDFWidget() );
   13268           0 :         m_aWidgets.back().m_nObject     = createObject();
   13269           0 :         m_aWidgets.back().m_nPage       = m_nCurrentPage;
   13270           0 :         m_aWidgets.back().m_eType       = PDFWriter::RadioButton;
   13271           0 :         m_aWidgets.back().m_nRadioGroup = rBtn.RadioGroup;
   13272           0 :         m_aWidgets.back().m_nFlags |= 0x0000C000;   // NoToggleToOff and Radio bits
   13273             : 
   13274           0 :         createWidgetFieldName( sal_Int32(m_aWidgets.size()-1), rBtn );
   13275             :     }
   13276             :     else
   13277           0 :         nRadioGroupWidget = it->second;
   13278             : 
   13279           0 :     return nRadioGroupWidget;
   13280             : }
   13281             : 
   13282           0 : sal_Int32 PDFWriterImpl::createControl( const PDFWriter::AnyWidget& rControl, sal_Int32 nPageNr )
   13283             : {
   13284           0 :     if( nPageNr < 0 )
   13285           0 :         nPageNr = m_nCurrentPage;
   13286             : 
   13287           0 :     if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() )
   13288           0 :         return -1;
   13289             : 
   13290           0 :     bool sigHidden(true);
   13291           0 :     sal_Int32 nNewWidget = m_aWidgets.size();
   13292           0 :     m_aWidgets.push_back( PDFWidget() );
   13293             : 
   13294           0 :     m_aWidgets.back().m_nObject         = createObject();
   13295           0 :     m_aWidgets.back().m_aRect           = rControl.Location;
   13296           0 :     m_aWidgets.back().m_nPage           = nPageNr;
   13297           0 :     m_aWidgets.back().m_eType           = rControl.getType();
   13298             : 
   13299           0 :     sal_Int32 nRadioGroupWidget = -1;
   13300             :     // for unknown reasons the radio buttons of a radio group must not have a
   13301             :     // field name, else the buttons are in fact check boxes -
   13302             :     // that is multiple buttons of the radio group can be selected
   13303           0 :     if( rControl.getType() == PDFWriter::RadioButton )
   13304           0 :         nRadioGroupWidget = findRadioGroupWidget( static_cast<const PDFWriter::RadioButtonWidget&>(rControl) );
   13305             :     else
   13306             :     {
   13307           0 :         createWidgetFieldName( nNewWidget, rControl );
   13308             :     }
   13309             : 
   13310             :     // caution: m_aWidgets must not be changed after here or rNewWidget may be invalid
   13311           0 :     PDFWidget& rNewWidget           = m_aWidgets[nNewWidget];
   13312           0 :     rNewWidget.m_aDescription       = rControl.Description;
   13313           0 :     rNewWidget.m_aText              = rControl.Text;
   13314           0 :     rNewWidget.m_nTextStyle         = rControl.TextStyle &
   13315             :         (  DrawTextFlags::Left | DrawTextFlags::Center | DrawTextFlags::Right | DrawTextFlags::Top |
   13316             :            DrawTextFlags::VCenter | DrawTextFlags::Bottom |
   13317           0 :            DrawTextFlags::MultiLine | DrawTextFlags::WordBreak  );
   13318           0 :     rNewWidget.m_nTabOrder          = rControl.TabOrder;
   13319             : 
   13320             :     // various properties are set via the flags (/Ff) property of the field dict
   13321           0 :     if( rControl.ReadOnly )
   13322           0 :         rNewWidget.m_nFlags |= 1;
   13323           0 :     if( rControl.getType() == PDFWriter::PushButton )
   13324             :     {
   13325           0 :         const PDFWriter::PushButtonWidget& rBtn = static_cast<const PDFWriter::PushButtonWidget&>(rControl);
   13326           0 :         if( rNewWidget.m_nTextStyle == DrawTextFlags::NONE )
   13327           0 :             rNewWidget.m_nTextStyle =
   13328             :                 DrawTextFlags::Center | DrawTextFlags::VCenter |
   13329           0 :                 DrawTextFlags::MultiLine | DrawTextFlags::WordBreak;
   13330             : 
   13331           0 :         rNewWidget.m_nFlags |= 0x00010000;
   13332           0 :         if( !rBtn.URL.isEmpty() )
   13333           0 :             rNewWidget.m_aListEntries.push_back( rBtn.URL );
   13334           0 :         rNewWidget.m_bSubmit    = rBtn.Submit;
   13335           0 :         rNewWidget.m_bSubmitGet = rBtn.SubmitGet;
   13336           0 :         rNewWidget.m_nDest      = rBtn.Dest;
   13337           0 :         createDefaultPushButtonAppearance( rNewWidget, rBtn );
   13338             :     }
   13339           0 :     else if( rControl.getType() == PDFWriter::RadioButton )
   13340             :     {
   13341           0 :         const PDFWriter::RadioButtonWidget& rBtn = static_cast<const PDFWriter::RadioButtonWidget&>(rControl);
   13342           0 :         if( rNewWidget.m_nTextStyle == DrawTextFlags::NONE )
   13343           0 :             rNewWidget.m_nTextStyle =
   13344           0 :                 DrawTextFlags::VCenter | DrawTextFlags::MultiLine | DrawTextFlags::WordBreak;
   13345             :         /*  PDF sees a RadioButton group as one radio button with
   13346             :          *  children which are in turn check boxes
   13347             :          *
   13348             :          *  so we need to create a radio button on demand for a new group
   13349             :          *  and insert a checkbox for each RadioButtonWidget as its child
   13350             :          */
   13351           0 :         rNewWidget.m_eType          = PDFWriter::CheckBox;
   13352           0 :         rNewWidget.m_nRadioGroup    = rBtn.RadioGroup;
   13353             : 
   13354             :         DBG_ASSERT( nRadioGroupWidget >= 0 && nRadioGroupWidget < (sal_Int32)m_aWidgets.size(), "no radio group parent" );
   13355             : 
   13356           0 :         PDFWidget& rRadioButton = m_aWidgets[nRadioGroupWidget];
   13357           0 :         rRadioButton.m_aKids.push_back( rNewWidget.m_nObject );
   13358           0 :         rRadioButton.m_aKidsIndex.push_back( nNewWidget );
   13359           0 :         rNewWidget.m_nParent = rRadioButton.m_nObject;
   13360             : 
   13361           0 :         rNewWidget.m_aValue     = "Off";
   13362           0 :         rNewWidget.m_aOnValue   = rBtn.OnValue;
   13363           0 :         if( rRadioButton.m_aValue.isEmpty() && rBtn.Selected )
   13364             :         {
   13365           0 :             rNewWidget.m_aValue     = rNewWidget.m_aOnValue;
   13366           0 :             rRadioButton.m_aValue   = rNewWidget.m_aOnValue;
   13367             :         }
   13368           0 :         createDefaultRadioButtonAppearance( rNewWidget, rBtn );
   13369             : 
   13370             :         // union rect of radio group
   13371           0 :         Rectangle aRect = rNewWidget.m_aRect;
   13372           0 :         m_aPages[ nPageNr ].convertRect( aRect );
   13373           0 :         rRadioButton.m_aRect.Union( aRect );
   13374             :     }
   13375           0 :     else if( rControl.getType() == PDFWriter::CheckBox )
   13376             :     {
   13377           0 :         const PDFWriter::CheckBoxWidget& rBox = static_cast<const PDFWriter::CheckBoxWidget&>(rControl);
   13378           0 :         if( rNewWidget.m_nTextStyle == DrawTextFlags::NONE )
   13379           0 :             rNewWidget.m_nTextStyle =
   13380           0 :                 DrawTextFlags::VCenter | DrawTextFlags::MultiLine | DrawTextFlags::WordBreak;
   13381             : 
   13382           0 :         rNewWidget.m_aValue = rBox.Checked ? OUString("Yes") : OUString("Off" );
   13383             :         // create default appearance before m_aRect gets transformed
   13384           0 :         createDefaultCheckBoxAppearance( rNewWidget, rBox );
   13385             :     }
   13386           0 :     else if( rControl.getType() == PDFWriter::ListBox )
   13387             :     {
   13388           0 :         if( rNewWidget.m_nTextStyle == DrawTextFlags::NONE )
   13389           0 :             rNewWidget.m_nTextStyle = DrawTextFlags::VCenter;
   13390             : 
   13391           0 :         const PDFWriter::ListBoxWidget& rLstBox = static_cast<const PDFWriter::ListBoxWidget&>(rControl);
   13392           0 :         rNewWidget.m_aListEntries     = rLstBox.Entries;
   13393           0 :         rNewWidget.m_aSelectedEntries = rLstBox.SelectedEntries;
   13394           0 :         rNewWidget.m_aValue           = rLstBox.Text;
   13395           0 :         if( rLstBox.DropDown )
   13396           0 :             rNewWidget.m_nFlags |= 0x00020000;
   13397           0 :         if( rLstBox.Sort )
   13398           0 :             rNewWidget.m_nFlags |= 0x00080000;
   13399           0 :         if( rLstBox.MultiSelect && !rLstBox.DropDown && (int)m_aContext.Version > (int)PDFWriter::PDF_1_3 )
   13400           0 :             rNewWidget.m_nFlags |= 0x00200000;
   13401             : 
   13402           0 :         createDefaultListBoxAppearance( rNewWidget, rLstBox );
   13403             :     }
   13404           0 :     else if( rControl.getType() == PDFWriter::ComboBox )
   13405             :     {
   13406           0 :         if( rNewWidget.m_nTextStyle == DrawTextFlags::NONE )
   13407           0 :             rNewWidget.m_nTextStyle = DrawTextFlags::VCenter;
   13408             : 
   13409           0 :         const PDFWriter::ComboBoxWidget& rBox = static_cast<const PDFWriter::ComboBoxWidget&>(rControl);
   13410           0 :         rNewWidget.m_aValue         = rBox.Text;
   13411           0 :         rNewWidget.m_aListEntries   = rBox.Entries;
   13412           0 :         rNewWidget.m_nFlags |= 0x00060000; // combo and edit flag
   13413           0 :         if( rBox.Sort )
   13414           0 :             rNewWidget.m_nFlags |= 0x00080000;
   13415             : 
   13416           0 :         PDFWriter::ListBoxWidget aLBox;
   13417           0 :         aLBox.Name              = rBox.Name;
   13418           0 :         aLBox.Description       = rBox.Description;
   13419           0 :         aLBox.Text              = rBox.Text;
   13420           0 :         aLBox.TextStyle         = rBox.TextStyle;
   13421           0 :         aLBox.ReadOnly          = rBox.ReadOnly;
   13422           0 :         aLBox.Border            = rBox.Border;
   13423           0 :         aLBox.BorderColor       = rBox.BorderColor;
   13424           0 :         aLBox.Background        = rBox.Background;
   13425           0 :         aLBox.BackgroundColor   = rBox.BackgroundColor;
   13426           0 :         aLBox.TextFont          = rBox.TextFont;
   13427           0 :         aLBox.TextColor         = rBox.TextColor;
   13428           0 :         aLBox.DropDown          = true;
   13429           0 :         aLBox.Sort              = rBox.Sort;
   13430           0 :         aLBox.MultiSelect       = false;
   13431           0 :         aLBox.Entries           = rBox.Entries;
   13432             : 
   13433           0 :         createDefaultListBoxAppearance( rNewWidget, aLBox );
   13434             :     }
   13435           0 :     else if( rControl.getType() == PDFWriter::Edit )
   13436             :     {
   13437           0 :         if( rNewWidget.m_nTextStyle == DrawTextFlags::NONE )
   13438           0 :             rNewWidget.m_nTextStyle = DrawTextFlags::Left | DrawTextFlags::VCenter;
   13439             : 
   13440           0 :         const PDFWriter::EditWidget& rEdit = static_cast<const  PDFWriter::EditWidget&>(rControl);
   13441           0 :         if( rEdit.MultiLine )
   13442             :         {
   13443           0 :             rNewWidget.m_nFlags |= 0x00001000;
   13444           0 :             rNewWidget.m_nTextStyle |= DrawTextFlags::MultiLine | DrawTextFlags::WordBreak;
   13445             :         }
   13446           0 :         if( rEdit.Password )
   13447           0 :             rNewWidget.m_nFlags |= 0x00002000;
   13448           0 :         if( rEdit.FileSelect && m_aContext.Version > PDFWriter::PDF_1_3 )
   13449           0 :             rNewWidget.m_nFlags |= 0x00100000;
   13450           0 :         rNewWidget.m_nMaxLen = rEdit.MaxLen;
   13451           0 :         rNewWidget.m_aValue = rEdit.Text;
   13452             : 
   13453           0 :         createDefaultEditAppearance( rNewWidget, rEdit );
   13454             :     }
   13455             : #if !defined(ANDROID) && !defined(IOS)
   13456           0 :     else if( rControl.getType() == PDFWriter::Signature)
   13457             :     {
   13458           0 :         const PDFWriter::SignatureWidget& rSig = static_cast<const PDFWriter::SignatureWidget&>(rControl);
   13459           0 :         sigHidden = rSig.SigHidden;
   13460             : 
   13461           0 :         if ( sigHidden )
   13462           0 :             rNewWidget.m_aRect = Rectangle(0, 0, 0, 0);
   13463             : 
   13464           0 :         m_nSignatureObject = createObject();
   13465           0 :         rNewWidget.m_aValue = OUString::number( m_nSignatureObject );
   13466           0 :         rNewWidget.m_aValue += " 0 R";
   13467             :         // let's add a fake appearance
   13468           0 :         rNewWidget.m_aAppearances[ "N" ][ "Standard" ] = new SvMemoryStream();
   13469             :     }
   13470             : #endif
   13471             : 
   13472             :     // if control is a hidden signature, do not convert coordinates since we
   13473             :     // need /Rect [ 0 0 0 0 ]
   13474           0 :     if ( ! ( ( rControl.getType() == PDFWriter::Signature ) && ( sigHidden ) ) )
   13475             :     {
   13476             :         // convert to default user space now, since the mapmode may change
   13477             :         // note: create default appearances before m_aRect gets transformed
   13478           0 :         m_aPages[ nPageNr ].convertRect( rNewWidget.m_aRect );
   13479             :     }
   13480             : 
   13481             :     // insert widget to page's annotation list
   13482           0 :     m_aPages[ nPageNr ].m_aAnnotations.push_back( rNewWidget.m_nObject );
   13483             : 
   13484             :     // mark page as having widgets
   13485           0 :     m_aPages[ nPageNr ].m_bHasWidgets = true;
   13486             : 
   13487           0 :     return nNewWidget;
   13488             : }
   13489             : 
   13490           0 : void PDFWriterImpl::addStream( const OUString& rMimeType, PDFOutputStream* pStream, bool bCompress )
   13491             : {
   13492           0 :     if( pStream )
   13493             :     {
   13494           0 :         m_aAdditionalStreams.push_back( PDFAddStream() );
   13495           0 :         PDFAddStream& rStream = m_aAdditionalStreams.back();
   13496           0 :         rStream.m_aMimeType = !rMimeType.isEmpty()
   13497             :                               ? OUString( rMimeType )
   13498           0 :                               : OUString( "application/octet-stream"  );
   13499           0 :         rStream.m_pStream = pStream;
   13500           0 :         rStream.m_bCompress = bCompress;
   13501             :     }
   13502         801 : }
   13503             : 
   13504             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11