19f62ea84SAndrew Rist /************************************************************** 2cdf0e10cSrcweir * 39f62ea84SAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one 49f62ea84SAndrew Rist * or more contributor license agreements. See the NOTICE file 59f62ea84SAndrew Rist * distributed with this work for additional information 69f62ea84SAndrew Rist * regarding copyright ownership. The ASF licenses this file 79f62ea84SAndrew Rist * to you under the Apache License, Version 2.0 (the 89f62ea84SAndrew Rist * "License"); you may not use this file except in compliance 99f62ea84SAndrew Rist * with the License. You may obtain a copy of the License at 10cdf0e10cSrcweir * 119f62ea84SAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 12cdf0e10cSrcweir * 139f62ea84SAndrew Rist * Unless required by applicable law or agreed to in writing, 149f62ea84SAndrew Rist * software distributed under the License is distributed on an 159f62ea84SAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 169f62ea84SAndrew Rist * KIND, either express or implied. See the License for the 179f62ea84SAndrew Rist * specific language governing permissions and limitations 189f62ea84SAndrew Rist * under the License. 19cdf0e10cSrcweir * 209f62ea84SAndrew Rist *************************************************************/ 219f62ea84SAndrew Rist 229f62ea84SAndrew Rist 23cdf0e10cSrcweir 24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove 25cdf0e10cSrcweir #include "precompiled_vcl.hxx" 26cdf0e10cSrcweir 27cdf0e10cSrcweir #define _USE_MATH_DEFINES 28cdf0e10cSrcweir #include <math.h> 29cdf0e10cSrcweir #include <algorithm> 30cdf0e10cSrcweir 31cdf0e10cSrcweir #include <tools/urlobj.hxx> 32cdf0e10cSrcweir 33cdf0e10cSrcweir #include <pdfwriter_impl.hxx> 34cdf0e10cSrcweir 35cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygon.hxx> 36cdf0e10cSrcweir #include <basegfx/polygon/b2dpolypolygon.hxx> 37cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygontools.hxx> 38cdf0e10cSrcweir #include <basegfx/polygon/b2dpolypolygontools.hxx> 39cdf0e10cSrcweir #include <basegfx/polygon/b2dpolypolygoncutter.hxx> 40cdf0e10cSrcweir #include <basegfx/matrix/b2dhommatrix.hxx> 41cdf0e10cSrcweir 42cdf0e10cSrcweir #include <osl/thread.h> 43cdf0e10cSrcweir #include <osl/file.h> 44cdf0e10cSrcweir 45cdf0e10cSrcweir #include <rtl/crc.h> 46cdf0e10cSrcweir #include <rtl/digest.h> 47cdf0e10cSrcweir #include <rtl/ustrbuf.hxx> 48cdf0e10cSrcweir 49cdf0e10cSrcweir #include <tools/debug.hxx> 50cdf0e10cSrcweir #include <tools/zcodec.hxx> 51cdf0e10cSrcweir #include <tools/stream.hxx> 52cdf0e10cSrcweir 53cdf0e10cSrcweir #include <i18npool/mslangid.hxx> 54cdf0e10cSrcweir 55cdf0e10cSrcweir #include <vcl/virdev.hxx> 56cdf0e10cSrcweir #include <vcl/bmpacc.hxx> 57cdf0e10cSrcweir #include <vcl/bitmapex.hxx> 58cdf0e10cSrcweir #include <vcl/image.hxx> 59cdf0e10cSrcweir #include <vcl/metric.hxx> 60cdf0e10cSrcweir #include <vcl/svapp.hxx> 61cdf0e10cSrcweir #include <vcl/lineinfo.hxx> 62cdf0e10cSrcweir #include "vcl/cvtgrf.hxx" 63cdf0e10cSrcweir #include "vcl/strhelper.hxx" 64cdf0e10cSrcweir 65cdf0e10cSrcweir #include <fontsubset.hxx> 66cdf0e10cSrcweir #include <outdev.h> 67cdf0e10cSrcweir #include <sallayout.hxx> 68cdf0e10cSrcweir #include <textlayout.hxx> 69cdf0e10cSrcweir #include <salgdi.hxx> 70cdf0e10cSrcweir 71cdf0e10cSrcweir #include <icc/sRGB-IEC61966-2.1.hxx> 72cdf0e10cSrcweir 73cdf0e10cSrcweir #include <comphelper/processfactory.hxx> 74cdf0e10cSrcweir 75cdf0e10cSrcweir #include <com/sun/star/lang/XMultiServiceFactory.hpp> 76cdf0e10cSrcweir #include <com/sun/star/util/URL.hpp> 77cdf0e10cSrcweir 78cdf0e10cSrcweir #include "cppuhelper/implbase1.hxx" 79cdf0e10cSrcweir 80cdf0e10cSrcweir using namespace vcl; 81cdf0e10cSrcweir using namespace rtl; 82cdf0e10cSrcweir 83cdf0e10cSrcweir #if (OSL_DEBUG_LEVEL < 2) 84cdf0e10cSrcweir #define COMPRESS_PAGES 85cdf0e10cSrcweir #else 86cdf0e10cSrcweir #define DEBUG_DISABLE_PDFCOMPRESSION // also do not compress streams 87cdf0e10cSrcweir #endif 88cdf0e10cSrcweir 89cdf0e10cSrcweir #ifdef DO_TEST_PDF 90cdf0e10cSrcweir class PDFTestOutputStream : public PDFOutputStream 91cdf0e10cSrcweir { 92cdf0e10cSrcweir public: 93cdf0e10cSrcweir virtual ~PDFTestOutputStream(); 94cdf0e10cSrcweir virtual void write( const com::sun::star::uno::Reference< com::sun::star::io::XOutputStream >& xStream ); 95cdf0e10cSrcweir }; 96cdf0e10cSrcweir 97cdf0e10cSrcweir PDFTestOutputStream::~PDFTestOutputStream() 98cdf0e10cSrcweir { 99cdf0e10cSrcweir } 100cdf0e10cSrcweir 101cdf0e10cSrcweir void PDFTestOutputStream::write( const com::sun::star::uno::Reference< com::sun::star::io::XOutputStream >& xStream ) 102cdf0e10cSrcweir { 103cdf0e10cSrcweir OString aStr( "lalala\ntest\ntest\ntest" ); 104cdf0e10cSrcweir com::sun::star::uno::Sequence< sal_Int8 > aData( aStr.getLength() ); 105cdf0e10cSrcweir rtl_copyMemory( aData.getArray(), aStr.getStr(), aStr.getLength() ); 106cdf0e10cSrcweir xStream->writeBytes( aData ); 107cdf0e10cSrcweir } 108cdf0e10cSrcweir 109cdf0e10cSrcweir // this test code cannot be used to test PDF/A-1 because it forces 110cdf0e10cSrcweir // control item (widgets) to bypass the structure controlling 111cdf0e10cSrcweir // the embedding of such elements in actual run 112cdf0e10cSrcweir void doTestCode() 113cdf0e10cSrcweir { 114cdf0e10cSrcweir static const char* pHome = getenv( "HOME" ); 115cdf0e10cSrcweir rtl::OUString aTestFile( RTL_CONSTASCII_USTRINGPARAM( "file://" ) ); 116cdf0e10cSrcweir aTestFile += rtl::OUString( pHome, strlen( pHome ), RTL_TEXTENCODING_MS_1252 ); 117cdf0e10cSrcweir aTestFile += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/pdf_export_test.pdf" ) ); 118cdf0e10cSrcweir 119cdf0e10cSrcweir PDFWriter::PDFWriterContext aContext; 120cdf0e10cSrcweir aContext.URL = aTestFile; 121cdf0e10cSrcweir aContext.Version = PDFWriter::PDF_1_4; 122cdf0e10cSrcweir aContext.Tagged = true; 123cdf0e10cSrcweir aContext.InitialPage = 2; 124cdf0e10cSrcweir aContext.DocumentInfo.Title = OUString( RTL_CONSTASCII_USTRINGPARAM( "PDF export test document" ) ); 125cdf0e10cSrcweir aContext.DocumentInfo.Producer = OUString( RTL_CONSTASCII_USTRINGPARAM( "VCL" ) ); 126cdf0e10cSrcweir 127cdf0e10cSrcweir PDFWriter aWriter( aContext ); 128cdf0e10cSrcweir aWriter.NewPage( 595, 842 ); 129cdf0e10cSrcweir aWriter.BeginStructureElement( PDFWriter::Document ); 130cdf0e10cSrcweir // set duration of 3 sec for first page 131cdf0e10cSrcweir aWriter.SetAutoAdvanceTime( 3 ); 132cdf0e10cSrcweir aWriter.SetMapMode( MapMode( MAP_100TH_MM ) ); 133cdf0e10cSrcweir 134cdf0e10cSrcweir aWriter.SetFillColor( Color( COL_LIGHTRED ) ); 135cdf0e10cSrcweir aWriter.SetLineColor( Color( COL_LIGHTGREEN ) ); 136cdf0e10cSrcweir aWriter.DrawRect( Rectangle( Point( 2000, 200 ), Size( 8000, 3000 ) ), 5000, 2000 ); 137cdf0e10cSrcweir 138cdf0e10cSrcweir aWriter.SetFont( Font( String( RTL_CONSTASCII_USTRINGPARAM( "Times" ) ), Size( 0, 500 ) ) ); 139cdf0e10cSrcweir aWriter.SetTextColor( Color( COL_BLACK ) ); 140cdf0e10cSrcweir aWriter.SetLineColor( Color( COL_BLACK ) ); 141cdf0e10cSrcweir aWriter.SetFillColor( Color( COL_LIGHTBLUE ) ); 142cdf0e10cSrcweir 143cdf0e10cSrcweir Rectangle aRect( Point( 5000, 5000 ), Size( 6000, 3000 ) ); 144cdf0e10cSrcweir aWriter.DrawRect( aRect ); 145cdf0e10cSrcweir aWriter.DrawText( aRect, String( RTL_CONSTASCII_USTRINGPARAM( "Link annot 1" ) ) ); 146cdf0e10cSrcweir sal_Int32 nFirstLink = aWriter.CreateLink( aRect ); 147cdf0e10cSrcweir PDFNote aNote; 148cdf0e10cSrcweir aNote.Title = String( RTL_CONSTASCII_USTRINGPARAM( "A small test note" ) ); 149cdf0e10cSrcweir aNote.Contents = String( RTL_CONSTASCII_USTRINGPARAM( "There is no business like show business like no business i know. Everything about it is appealing." ) ); 150cdf0e10cSrcweir aWriter.CreateNote( Rectangle( Point( aRect.Right(), aRect.Top() ), Size( 6000, 3000 ) ), aNote ); 151cdf0e10cSrcweir 152cdf0e10cSrcweir Rectangle aTargetRect( Point( 3000, 23000 ), Size( 12000, 6000 ) ); 153cdf0e10cSrcweir aWriter.SetFillColor( Color( COL_LIGHTGREEN ) ); 154cdf0e10cSrcweir aWriter.DrawRect( aTargetRect ); 155cdf0e10cSrcweir aWriter.DrawText( aTargetRect, String( RTL_CONSTASCII_USTRINGPARAM( "Dest second link" ) ) ); 156cdf0e10cSrcweir sal_Int32 nSecondDest = aWriter.CreateDest( aTargetRect ); 157cdf0e10cSrcweir 158cdf0e10cSrcweir aWriter.BeginStructureElement( PDFWriter::Section ); 159cdf0e10cSrcweir aWriter.BeginStructureElement( PDFWriter::Heading ); 160cdf0e10cSrcweir aWriter.DrawText( Point(4500, 9000), String( RTL_CONSTASCII_USTRINGPARAM( "A small structure test" ) ) ); 161cdf0e10cSrcweir aWriter.EndStructureElement(); 162cdf0e10cSrcweir aWriter.BeginStructureElement( PDFWriter::Paragraph ); 163cdf0e10cSrcweir aWriter.SetStructureAttribute( PDFWriter::WritingMode, PDFWriter::LrTb ); 164cdf0e10cSrcweir aWriter.SetStructureAttribute( PDFWriter::TextDecorationType, PDFWriter::Underline ); 165cdf0e10cSrcweir aWriter.DrawText( Rectangle( Point( 4500, 10000 ), Size( 12000, 6000 ) ), 166cdf0e10cSrcweir String( RTL_CONSTASCII_USTRINGPARAM( "It was the best of PDF, it was the worst of PDF ... or so. This is a pretty nonsensical text to denote a paragraph. I suggest you stop reading it. Because if you read on you might get bored. So continue on your on risk. Hey, you're still here ? Why do you continue to read this as it is of no use at all ? OK, it's your time, but still... . Woah, i even get bored writing this, so let's end this here and now." ) ), 167cdf0e10cSrcweir TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK 168cdf0e10cSrcweir ); 169cdf0e10cSrcweir aWriter.SetActualText( String( RTL_CONSTASCII_USTRINGPARAM( "It was the best of PDF, it was the worst of PDF ... or so. This is a pretty nonsensical text to denote a paragraph. I suggest you stop reading it. Because if you read on you might get bored. So continue on your on risk. Hey, you're still here ? Why do you continue to read this as it is of no use at all ? OK, it's your time, but still... . Woah, i even get bored writing this, so let's end this here and now." ) ) ); 170cdf0e10cSrcweir aWriter.SetAlternateText( String( RTL_CONSTASCII_USTRINGPARAM( "This paragraph contains some lengthy nonsense to test structural element emission of PDFWriter." ) ) ); 171cdf0e10cSrcweir aWriter.EndStructureElement(); 172cdf0e10cSrcweir sal_Int32 nLongPara = aWriter.BeginStructureElement( PDFWriter::Paragraph ); 173cdf0e10cSrcweir aWriter.SetStructureAttribute( PDFWriter::WritingMode, PDFWriter::LrTb ); 174cdf0e10cSrcweir aWriter.DrawText( Rectangle( Point( 4500, 19000 ), Size( 12000, 1000 ) ), 175cdf0e10cSrcweir String( RTL_CONSTASCII_USTRINGPARAM( "This paragraph is nothing special either but ends on the next page structurewise" ) ), 176cdf0e10cSrcweir TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK 177cdf0e10cSrcweir ); 178cdf0e10cSrcweir 179cdf0e10cSrcweir aWriter.NewPage( 595, 842 ); 180cdf0e10cSrcweir // test AddStream interface 181cdf0e10cSrcweir aWriter.AddStream( String( RTL_CONSTASCII_USTRINGPARAM( "text/plain" ) ), new PDFTestOutputStream(), true ); 182cdf0e10cSrcweir // set transitional mode 183cdf0e10cSrcweir aWriter.SetPageTransition( PDFWriter::WipeRightToLeft, 1500 ); 184cdf0e10cSrcweir aWriter.SetMapMode( MapMode( MAP_100TH_MM ) ); 185cdf0e10cSrcweir aWriter.SetTextColor( Color( COL_BLACK ) ); 186cdf0e10cSrcweir aWriter.SetFont( Font( String( RTL_CONSTASCII_USTRINGPARAM( "Times" ) ), Size( 0, 500 ) ) ); 187cdf0e10cSrcweir aWriter.DrawText( Rectangle( Point( 4500, 1500 ), Size( 12000, 3000 ) ), 188cdf0e10cSrcweir String( RTL_CONSTASCII_USTRINGPARAM( "Here's where all things come to an end ... well at least the paragaph from the last page." ) ), 189cdf0e10cSrcweir TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK 190cdf0e10cSrcweir ); 191cdf0e10cSrcweir aWriter.EndStructureElement(); 192cdf0e10cSrcweir 193cdf0e10cSrcweir aWriter.SetFillColor( Color( COL_LIGHTBLUE ) ); 194cdf0e10cSrcweir // disable structure 195cdf0e10cSrcweir aWriter.BeginStructureElement( PDFWriter::NonStructElement ); 196cdf0e10cSrcweir aWriter.DrawRect( aRect ); 197cdf0e10cSrcweir aWriter.BeginStructureElement( PDFWriter::Paragraph ); 198cdf0e10cSrcweir aWriter.DrawText( aRect, String( RTL_CONSTASCII_USTRINGPARAM( "Link annot 2" ) ) ); 199cdf0e10cSrcweir sal_Int32 nSecondLink = aWriter.CreateLink( aRect ); 200cdf0e10cSrcweir 201cdf0e10cSrcweir aWriter.SetFillColor( Color( COL_LIGHTGREEN ) ); 202cdf0e10cSrcweir aWriter.BeginStructureElement( PDFWriter::ListItem ); 203cdf0e10cSrcweir aWriter.DrawRect( aTargetRect ); 204cdf0e10cSrcweir aWriter.DrawText( aTargetRect, String( RTL_CONSTASCII_USTRINGPARAM( "Dest first link" ) ) ); 205cdf0e10cSrcweir sal_Int32 nFirstDest = aWriter.CreateDest( aTargetRect ); 206cdf0e10cSrcweir // enable structure 207cdf0e10cSrcweir aWriter.EndStructureElement(); 208cdf0e10cSrcweir // add something to the long paragraph as an afterthought 209cdf0e10cSrcweir sal_Int32 nSaveStruct = aWriter.GetCurrentStructureElement(); 210cdf0e10cSrcweir aWriter.SetCurrentStructureElement( nLongPara ); 211cdf0e10cSrcweir aWriter.DrawText( Rectangle( Point( 4500,4500 ), Size( 12000, 1000 ) ), 212cdf0e10cSrcweir String( RTL_CONSTASCII_USTRINGPARAM( "Add something to the longish paragraph above." ) ), 213cdf0e10cSrcweir TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK ); 214cdf0e10cSrcweir aWriter.SetCurrentStructureElement( nSaveStruct ); 215cdf0e10cSrcweir aWriter.EndStructureElement(); 216cdf0e10cSrcweir aWriter.EndStructureElement(); 217cdf0e10cSrcweir aWriter.BeginStructureElement( PDFWriter::Figure ); 218cdf0e10cSrcweir aWriter.BeginStructureElement( PDFWriter::Caption ); 219cdf0e10cSrcweir aWriter.DrawText( Point( 4500, 9000 ), String( RTL_CONSTASCII_USTRINGPARAM( "Some drawing stuff inside the structure" ) ) ); 220cdf0e10cSrcweir aWriter.EndStructureElement(); 221cdf0e10cSrcweir 222cdf0e10cSrcweir // test clipping 223cdf0e10cSrcweir basegfx::B2DPolyPolygon aClip; 224cdf0e10cSrcweir basegfx::B2DPolygon aClipPoly; 225cdf0e10cSrcweir aClipPoly.append( basegfx::B2DPoint( 8250, 9600 ) ); 226cdf0e10cSrcweir aClipPoly.append( basegfx::B2DPoint( 16500, 11100 ) ); 227cdf0e10cSrcweir aClipPoly.append( basegfx::B2DPoint( 8250, 12600 ) ); 228cdf0e10cSrcweir aClipPoly.append( basegfx::B2DPoint( 4500, 11100 ) ); 229cdf0e10cSrcweir aClipPoly.setClosed( true ); 230cdf0e10cSrcweir //aClipPoly.flip(); 231cdf0e10cSrcweir aClip.append( aClipPoly ); 232cdf0e10cSrcweir 233cdf0e10cSrcweir aWriter.Push( PUSH_CLIPREGION | PUSH_FILLCOLOR ); 234cdf0e10cSrcweir aWriter.SetClipRegion( aClip ); 235cdf0e10cSrcweir aWriter.DrawEllipse( Rectangle( Point( 4500, 9600 ), Size( 12000, 3000 ) ) ); 236cdf0e10cSrcweir aWriter.MoveClipRegion( 1000, 500 ); 237cdf0e10cSrcweir aWriter.SetFillColor( Color( COL_RED ) ); 238cdf0e10cSrcweir aWriter.DrawEllipse( Rectangle( Point( 4500, 9600 ), Size( 12000, 3000 ) ) ); 239cdf0e10cSrcweir aWriter.Pop(); 240cdf0e10cSrcweir // test transparency 241cdf0e10cSrcweir // draw background 242cdf0e10cSrcweir Rectangle aTranspRect( Point( 7500, 13500 ), Size( 9000, 6000 ) ); 243cdf0e10cSrcweir aWriter.SetFillColor( Color( COL_LIGHTRED ) ); 244cdf0e10cSrcweir aWriter.DrawRect( aTranspRect ); 245cdf0e10cSrcweir aWriter.BeginTransparencyGroup(); 246cdf0e10cSrcweir 247cdf0e10cSrcweir aWriter.SetFillColor( Color( COL_LIGHTGREEN ) ); 248cdf0e10cSrcweir aWriter.DrawEllipse( aTranspRect ); 249cdf0e10cSrcweir aWriter.SetTextColor( Color( COL_LIGHTBLUE ) ); 250cdf0e10cSrcweir aWriter.DrawText( aTranspRect, 251cdf0e10cSrcweir String( RTL_CONSTASCII_USTRINGPARAM( "Some transparent text" ) ), 252cdf0e10cSrcweir TEXT_DRAW_CENTER | TEXT_DRAW_VCENTER | TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK ); 253cdf0e10cSrcweir 254cdf0e10cSrcweir aWriter.EndTransparencyGroup( aTranspRect, 50 ); 255cdf0e10cSrcweir 256cdf0e10cSrcweir // prepare an alpha mask 257cdf0e10cSrcweir Bitmap aTransMask( Size( 256, 256 ), 8, &Bitmap::GetGreyPalette( 256 ) ); 258cdf0e10cSrcweir BitmapWriteAccess* pAcc = aTransMask.AcquireWriteAccess(); 259cdf0e10cSrcweir for( int nX = 0; nX < 256; nX++ ) 260cdf0e10cSrcweir for( int nY = 0; nY < 256; nY++ ) 261cdf0e10cSrcweir pAcc->SetPixel( nX, nY, BitmapColor( (sal_uInt8)((nX+nY)/2) ) ); 262cdf0e10cSrcweir aTransMask.ReleaseAccess( pAcc ); 263cdf0e10cSrcweir aTransMask.SetPrefMapMode( MAP_MM ); 264cdf0e10cSrcweir aTransMask.SetPrefSize( Size( 10, 10 ) ); 265cdf0e10cSrcweir 266cdf0e10cSrcweir aWriter.DrawBitmap( Point( 600, 13500 ), Size( 3000, 3000 ), aTransMask ); 267cdf0e10cSrcweir 268cdf0e10cSrcweir aTranspRect = Rectangle( Point( 4200, 13500 ), Size( 3000, 3000 ) ); 269cdf0e10cSrcweir aWriter.SetFillColor( Color( COL_LIGHTRED ) ); 270cdf0e10cSrcweir aWriter.DrawRect( aTranspRect ); 271cdf0e10cSrcweir aWriter.SetFillColor( Color( COL_LIGHTGREEN ) ); 272cdf0e10cSrcweir aWriter.DrawEllipse( aTranspRect ); 273cdf0e10cSrcweir aWriter.SetTextColor( Color( COL_LIGHTBLUE ) ); 274cdf0e10cSrcweir aWriter.DrawText( aTranspRect, 275cdf0e10cSrcweir String( RTL_CONSTASCII_USTRINGPARAM( "Some transparent text" ) ), 276cdf0e10cSrcweir TEXT_DRAW_CENTER | TEXT_DRAW_VCENTER | TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK ); 277cdf0e10cSrcweir aTranspRect = Rectangle( Point( 1500, 16500 ), Size( 4800, 3000 ) ); 278cdf0e10cSrcweir aWriter.SetFillColor( Color( COL_LIGHTRED ) ); 279cdf0e10cSrcweir aWriter.DrawRect( aTranspRect ); 280cdf0e10cSrcweir aWriter.BeginTransparencyGroup(); 281cdf0e10cSrcweir aWriter.SetFillColor( Color( COL_LIGHTGREEN ) ); 282cdf0e10cSrcweir aWriter.DrawEllipse( aTranspRect ); 283cdf0e10cSrcweir aWriter.SetTextColor( Color( COL_LIGHTBLUE ) ); 284cdf0e10cSrcweir aWriter.DrawText( aTranspRect, 285cdf0e10cSrcweir String( RTL_CONSTASCII_USTRINGPARAM( "Some transparent text" ) ), 286cdf0e10cSrcweir TEXT_DRAW_CENTER | TEXT_DRAW_VCENTER | TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK ); 287cdf0e10cSrcweir aWriter.EndTransparencyGroup( aTranspRect, aTransMask ); 288cdf0e10cSrcweir 289cdf0e10cSrcweir Bitmap aImageBmp( Size( 256, 256 ), 24 ); 290cdf0e10cSrcweir pAcc = aImageBmp.AcquireWriteAccess(); 291cdf0e10cSrcweir pAcc->SetFillColor( Color( 0xff, 0, 0xff ) ); 292cdf0e10cSrcweir pAcc->FillRect( Rectangle( Point( 0, 0 ), Size( 256, 256 ) ) ); 293cdf0e10cSrcweir aImageBmp.ReleaseAccess( pAcc ); 294cdf0e10cSrcweir BitmapEx aBmpEx( aImageBmp, AlphaMask( aTransMask ) ); 295cdf0e10cSrcweir aWriter.DrawBitmapEx( Point( 1500, 19500 ), Size( 4800, 3000 ), aBmpEx ); 296cdf0e10cSrcweir 297cdf0e10cSrcweir 298cdf0e10cSrcweir aWriter.EndStructureElement(); 299cdf0e10cSrcweir aWriter.EndStructureElement(); 300cdf0e10cSrcweir 301cdf0e10cSrcweir LineInfo aLI( LINE_DASH, 3 ); 302cdf0e10cSrcweir aLI.SetDashCount( 2 ); 303cdf0e10cSrcweir aLI.SetDashLen( 50 ); 304cdf0e10cSrcweir aLI.SetDotCount( 2 ); 305cdf0e10cSrcweir aLI.SetDotLen( 25 ); 306cdf0e10cSrcweir aLI.SetDistance( 15 ); 307cdf0e10cSrcweir Point aLIPoints[] = { Point( 4000, 10000 ), 308cdf0e10cSrcweir Point( 8000, 12000 ), 309cdf0e10cSrcweir Point( 3000, 19000 ) }; 310cdf0e10cSrcweir Polygon aLIPoly( 3, aLIPoints ); 311cdf0e10cSrcweir aWriter.SetLineColor( Color( COL_BLUE ) ); 312cdf0e10cSrcweir aWriter.SetFillColor(); 313cdf0e10cSrcweir aWriter.DrawPolyLine( aLIPoly, aLI ); 314cdf0e10cSrcweir 315cdf0e10cSrcweir aLI.SetDashCount( 4 ); 316cdf0e10cSrcweir aLIPoly.Move( 1000, 1000 ); 317cdf0e10cSrcweir aWriter.DrawPolyLine( aLIPoly, aLI ); 318cdf0e10cSrcweir 319cdf0e10cSrcweir aWriter.NewPage( 595, 842 ); 320cdf0e10cSrcweir aWriter.SetMapMode( MapMode( MAP_100TH_MM ) ); 321cdf0e10cSrcweir Wallpaper aWall( aTransMask ); 322cdf0e10cSrcweir aWall.SetStyle( WALLPAPER_TILE ); 323cdf0e10cSrcweir aWriter.DrawWallpaper( Rectangle( Point( 4400, 4200 ), Size( 10200, 6300 ) ), aWall ); 324cdf0e10cSrcweir 325cdf0e10cSrcweir aWriter.Push( PUSH_ALL ); 326cdf0e10cSrcweir aWriter.BeginPattern(Rectangle(Point(0,0),Size(2000,1000))); 327cdf0e10cSrcweir aWriter.SetFillColor( Color( COL_RED ) ); 328cdf0e10cSrcweir aWriter.SetLineColor( Color( COL_LIGHTBLUE ) ); 329cdf0e10cSrcweir Point aFillPoints[] = { Point( 1000, 0 ), 330cdf0e10cSrcweir Point( 0, 1000 ), 331cdf0e10cSrcweir Point( 2000, 1000 ) }; 332cdf0e10cSrcweir aWriter.DrawPolygon( Polygon( 3, aFillPoints ) ); 333cdf0e10cSrcweir aWriter.DrawBitmap( Point( 200, 200 ), Size( 1600, 600 ), aTransMask ); 334cdf0e10cSrcweir aWriter.DrawText( Rectangle( Point( 200, 200 ), Size( 1600, 600 ) ), String( RTL_CONSTASCII_USTRINGPARAM( "Pattern" ) ) ); 335cdf0e10cSrcweir sal_Int32 nPattern = aWriter.EndPattern( SvtGraphicFill::Transform() ); 336cdf0e10cSrcweir aWriter.Pop(); 337cdf0e10cSrcweir Rectangle aPolyRect( Point( 3800, 11200 ), Size( 10200, 6300 ) ); 338cdf0e10cSrcweir aWriter.DrawPolyPolygon( PolyPolygon( Polygon( aPolyRect ) ), nPattern, true ); 339cdf0e10cSrcweir aWriter.SetFillColor(); 340cdf0e10cSrcweir aWriter.SetLineColor( Color( COL_LIGHTBLUE ) ); 341cdf0e10cSrcweir aWriter.DrawRect( aPolyRect ); 342cdf0e10cSrcweir 343cdf0e10cSrcweir aWriter.NewPage( 595, 842 ); 344cdf0e10cSrcweir aWriter.SetMapMode( MapMode( MAP_100TH_MM ) ); 345cdf0e10cSrcweir aWriter.SetFont( Font( String( RTL_CONSTASCII_USTRINGPARAM( "Times" ) ), Size( 0, 500 ) ) ); 346cdf0e10cSrcweir aWriter.SetTextColor( Color( COL_BLACK ) ); 347cdf0e10cSrcweir aRect = Rectangle( Point( 4500, 6000 ), Size( 6000, 1500 ) ); 348cdf0e10cSrcweir aWriter.DrawRect( aRect ); 349cdf0e10cSrcweir aWriter.DrawText( aRect, String( RTL_CONSTASCII_USTRINGPARAM( "www.heise.de" ) ) ); 350cdf0e10cSrcweir sal_Int32 nURILink = aWriter.CreateLink( aRect ); 351cdf0e10cSrcweir aWriter.SetLinkURL( nURILink, OUString( RTL_CONSTASCII_USTRINGPARAM( "http://www.heise.de" ) ) ); 352cdf0e10cSrcweir 353cdf0e10cSrcweir aWriter.SetLinkDest( nFirstLink, nFirstDest ); 354cdf0e10cSrcweir aWriter.SetLinkDest( nSecondLink, nSecondDest ); 355cdf0e10cSrcweir 356cdf0e10cSrcweir // include a button 357cdf0e10cSrcweir PDFWriter::PushButtonWidget aBtn; 358cdf0e10cSrcweir aBtn.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "testButton" ) ); 359cdf0e10cSrcweir aBtn.Description = OUString( RTL_CONSTASCII_USTRINGPARAM( "A test button" ) ); 360cdf0e10cSrcweir aBtn.Text = OUString( RTL_CONSTASCII_USTRINGPARAM( "hit me" ) ); 361cdf0e10cSrcweir aBtn.Location = Rectangle( Point( 4500, 9000 ), Size( 4500, 3000 ) ); 362cdf0e10cSrcweir aBtn.Border = aBtn.Background = true; 363cdf0e10cSrcweir aWriter.CreateControl( aBtn ); 364cdf0e10cSrcweir 365cdf0e10cSrcweir // include a uri button 366cdf0e10cSrcweir PDFWriter::PushButtonWidget aUriBtn; 367cdf0e10cSrcweir aUriBtn.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "wwwButton" ) ); 368cdf0e10cSrcweir aUriBtn.Description = OUString( RTL_CONSTASCII_USTRINGPARAM( "A URI button" ) ); 369cdf0e10cSrcweir aUriBtn.Text = OUString( RTL_CONSTASCII_USTRINGPARAM( "to www" ) ); 370cdf0e10cSrcweir aUriBtn.Location = Rectangle( Point( 9500, 9000 ), Size( 4500, 3000 ) ); 371cdf0e10cSrcweir aUriBtn.Border = aUriBtn.Background = true; 372cdf0e10cSrcweir aUriBtn.URL = OUString( RTL_CONSTASCII_USTRINGPARAM( "http://www.heise.de" ) ); 373cdf0e10cSrcweir aWriter.CreateControl( aUriBtn ); 374cdf0e10cSrcweir 375cdf0e10cSrcweir // include a dest button 376cdf0e10cSrcweir PDFWriter::PushButtonWidget aDstBtn; 377cdf0e10cSrcweir aDstBtn.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "destButton" ) ); 378cdf0e10cSrcweir aDstBtn.Description = OUString( RTL_CONSTASCII_USTRINGPARAM( "A Dest button" ) ); 379cdf0e10cSrcweir aDstBtn.Text = OUString( RTL_CONSTASCII_USTRINGPARAM( "to paragraph" ) ); 380cdf0e10cSrcweir aDstBtn.Location = Rectangle( Point( 14500, 9000 ), Size( 4500, 3000 ) ); 381cdf0e10cSrcweir aDstBtn.Border = aDstBtn.Background = true; 382cdf0e10cSrcweir aDstBtn.Dest = nFirstDest; 383cdf0e10cSrcweir aWriter.CreateControl( aDstBtn ); 384cdf0e10cSrcweir 385cdf0e10cSrcweir PDFWriter::CheckBoxWidget aCBox; 386cdf0e10cSrcweir aCBox.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "textCheckBox" ) ); 387cdf0e10cSrcweir aCBox.Description = OUString( RTL_CONSTASCII_USTRINGPARAM( "A test check box" ) ); 388cdf0e10cSrcweir aCBox.Text = OUString( RTL_CONSTASCII_USTRINGPARAM( "check me" ) ); 389cdf0e10cSrcweir aCBox.Location = Rectangle( Point( 4500, 13500 ), Size( 3000, 750 ) ); 390cdf0e10cSrcweir aCBox.Checked = true; 391cdf0e10cSrcweir aCBox.Border = aCBox.Background = false; 392cdf0e10cSrcweir aWriter.CreateControl( aCBox ); 393cdf0e10cSrcweir 394cdf0e10cSrcweir PDFWriter::CheckBoxWidget aCBox2; 395cdf0e10cSrcweir aCBox2.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "textCheckBox2" ) ); 396cdf0e10cSrcweir aCBox2.Description = OUString( RTL_CONSTASCII_USTRINGPARAM( "Another test check box" ) ); 397cdf0e10cSrcweir aCBox2.Text = OUString( RTL_CONSTASCII_USTRINGPARAM( "check me right" ) ); 398cdf0e10cSrcweir aCBox2.Location = Rectangle( Point( 4500, 14250 ), Size( 3000, 750 ) ); 399cdf0e10cSrcweir aCBox2.Checked = true; 400cdf0e10cSrcweir aCBox2.Border = aCBox2.Background = false; 401cdf0e10cSrcweir aCBox2.ButtonIsLeft = false; 402cdf0e10cSrcweir aWriter.CreateControl( aCBox2 ); 403cdf0e10cSrcweir 404cdf0e10cSrcweir PDFWriter::RadioButtonWidget aRB1; 405cdf0e10cSrcweir aRB1.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "rb1_1" ) ); 406cdf0e10cSrcweir aRB1.Description = OUString( RTL_CONSTASCII_USTRINGPARAM( "radio 1 button 1" ) ); 407cdf0e10cSrcweir aRB1.Text = OUString( RTL_CONSTASCII_USTRINGPARAM( "Despair" ) ); 408cdf0e10cSrcweir aRB1.Location = Rectangle( Point( 4500, 15000 ), Size( 6000, 1000 ) ); 409cdf0e10cSrcweir aRB1.Selected = true; 410cdf0e10cSrcweir aRB1.RadioGroup = 1; 411cdf0e10cSrcweir aRB1.Border = aRB1.Background = true; 412cdf0e10cSrcweir aRB1.ButtonIsLeft = false; 413cdf0e10cSrcweir aRB1.BorderColor = Color( COL_LIGHTGREEN ); 414cdf0e10cSrcweir aRB1.BackgroundColor = Color( COL_LIGHTBLUE ); 415cdf0e10cSrcweir aRB1.TextColor = Color( COL_LIGHTRED ); 416cdf0e10cSrcweir aRB1.TextFont = Font( String( RTL_CONSTASCII_USTRINGPARAM( "Courier" ) ), Size( 0, 800 ) ); 417cdf0e10cSrcweir aWriter.CreateControl( aRB1 ); 418cdf0e10cSrcweir 419cdf0e10cSrcweir PDFWriter::RadioButtonWidget aRB2; 420cdf0e10cSrcweir aRB2.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "rb2_1" ) ); 421cdf0e10cSrcweir aRB2.Description = OUString( RTL_CONSTASCII_USTRINGPARAM( "radio 2 button 1" ) ); 422cdf0e10cSrcweir aRB2.Text = OUString( RTL_CONSTASCII_USTRINGPARAM( "Joy" ) ); 423cdf0e10cSrcweir aRB2.Location = Rectangle( Point( 10500, 15000 ), Size( 3000, 1000 ) ); 424cdf0e10cSrcweir aRB2.Selected = true; 425cdf0e10cSrcweir aRB2.RadioGroup = 2; 426cdf0e10cSrcweir aWriter.CreateControl( aRB2 ); 427cdf0e10cSrcweir 428cdf0e10cSrcweir PDFWriter::RadioButtonWidget aRB3; 429cdf0e10cSrcweir aRB3.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "rb1_2" ) ); 430cdf0e10cSrcweir aRB3.Description = OUString( RTL_CONSTASCII_USTRINGPARAM( "radio 1 button 2" ) ); 431cdf0e10cSrcweir aRB3.Text = OUString( RTL_CONSTASCII_USTRINGPARAM( "Desperation" ) ); 432cdf0e10cSrcweir aRB3.Location = Rectangle( Point( 4500, 16000 ), Size( 3000, 1000 ) ); 433cdf0e10cSrcweir aRB3.Selected = true; 434cdf0e10cSrcweir aRB3.RadioGroup = 1; 435cdf0e10cSrcweir aWriter.CreateControl( aRB3 ); 436cdf0e10cSrcweir 437cdf0e10cSrcweir PDFWriter::EditWidget aEditBox; 438cdf0e10cSrcweir aEditBox.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "testEdit" ) ); 439cdf0e10cSrcweir aEditBox.Description = OUString( RTL_CONSTASCII_USTRINGPARAM( "A test edit field" ) ); 440cdf0e10cSrcweir aEditBox.Text = OUString( RTL_CONSTASCII_USTRINGPARAM( "A little test text" ) ); 441cdf0e10cSrcweir aEditBox.TextStyle = TEXT_DRAW_LEFT | TEXT_DRAW_VCENTER; 442cdf0e10cSrcweir aEditBox.Location = Rectangle( Point( 10000, 18000 ), Size( 5000, 1500 ) ); 443cdf0e10cSrcweir aEditBox.MaxLen = 100; 444cdf0e10cSrcweir aEditBox.Border = aEditBox.Background = true; 445cdf0e10cSrcweir aEditBox.BorderColor = Color( COL_BLACK ); 446cdf0e10cSrcweir aWriter.CreateControl( aEditBox ); 447cdf0e10cSrcweir 448cdf0e10cSrcweir // normal list box 449cdf0e10cSrcweir PDFWriter::ListBoxWidget aLstBox; 450cdf0e10cSrcweir aLstBox.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "testListBox" ) ); 451cdf0e10cSrcweir aLstBox.Text = OUString( RTL_CONSTASCII_USTRINGPARAM( "One" ) ); 452cdf0e10cSrcweir aLstBox.Description = OUString( RTL_CONSTASCII_USTRINGPARAM( "select me" ) ); 453cdf0e10cSrcweir aLstBox.Location = Rectangle( Point( 4500, 18000 ), Size( 3000, 1500 ) ); 454cdf0e10cSrcweir aLstBox.Sort = true; 455cdf0e10cSrcweir aLstBox.MultiSelect = true; 456cdf0e10cSrcweir aLstBox.Border = aLstBox.Background = true; 457cdf0e10cSrcweir aLstBox.BorderColor = Color( COL_BLACK ); 458cdf0e10cSrcweir aLstBox.Entries.push_back( OUString( RTL_CONSTASCII_USTRINGPARAM( "One" ) ) ); 459cdf0e10cSrcweir aLstBox.Entries.push_back( OUString( RTL_CONSTASCII_USTRINGPARAM( "Two" ) ) ); 460cdf0e10cSrcweir aLstBox.Entries.push_back( OUString( RTL_CONSTASCII_USTRINGPARAM( "Three" ) ) ); 461cdf0e10cSrcweir aLstBox.Entries.push_back( OUString( RTL_CONSTASCII_USTRINGPARAM( "Four" ) ) ); 462cdf0e10cSrcweir aLstBox.SelectedEntries.push_back( 1 ); 463cdf0e10cSrcweir aLstBox.SelectedEntries.push_back( 2 ); 464cdf0e10cSrcweir aWriter.CreateControl( aLstBox ); 465cdf0e10cSrcweir 466cdf0e10cSrcweir // dropdown list box 467cdf0e10cSrcweir aLstBox.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "testDropDownListBox" ) ); 468cdf0e10cSrcweir aLstBox.DropDown = true; 469cdf0e10cSrcweir aLstBox.Location = Rectangle( Point( 4500, 19500 ), Size( 3000, 500 ) ); 470cdf0e10cSrcweir aWriter.CreateControl( aLstBox ); 471cdf0e10cSrcweir 472cdf0e10cSrcweir // combo box 473cdf0e10cSrcweir PDFWriter::ComboBoxWidget aComboBox; 474cdf0e10cSrcweir aComboBox.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "testComboBox" ) ); 475cdf0e10cSrcweir aComboBox.Text = OUString( RTL_CONSTASCII_USTRINGPARAM( "test a combobox" ) ); 476cdf0e10cSrcweir aComboBox.Entries.push_back( OUString( RTL_CONSTASCII_USTRINGPARAM( "Larry" ) ) ); 477cdf0e10cSrcweir aComboBox.Entries.push_back( OUString( RTL_CONSTASCII_USTRINGPARAM( "Curly" ) ) ); 478cdf0e10cSrcweir aComboBox.Entries.push_back( OUString( RTL_CONSTASCII_USTRINGPARAM( "Moe" ) ) ); 479cdf0e10cSrcweir aComboBox.Location = Rectangle( Point( 4500, 20000 ), Size( 3000, 500 ) ); 480cdf0e10cSrcweir aWriter.CreateControl( aComboBox ); 481cdf0e10cSrcweir 482cdf0e10cSrcweir // test outlines 483cdf0e10cSrcweir sal_Int32 nPage1OL = aWriter.CreateOutlineItem(); 484cdf0e10cSrcweir aWriter.SetOutlineItemText( nPage1OL, OUString( RTL_CONSTASCII_USTRINGPARAM( "Page 1" ) ) ); 485cdf0e10cSrcweir aWriter.SetOutlineItemDest( nPage1OL, nSecondDest ); 486cdf0e10cSrcweir aWriter.CreateOutlineItem( nPage1OL, OUString( RTL_CONSTASCII_USTRINGPARAM( "Dest 2" ) ), nSecondDest ); 487cdf0e10cSrcweir aWriter.CreateOutlineItem( nPage1OL, OUString( RTL_CONSTASCII_USTRINGPARAM( "Dest 2 revisited" ) ), nSecondDest ); 488cdf0e10cSrcweir aWriter.CreateOutlineItem( nPage1OL, OUString( RTL_CONSTASCII_USTRINGPARAM( "Dest 2 again" ) ), nSecondDest ); 489cdf0e10cSrcweir sal_Int32 nPage2OL = aWriter.CreateOutlineItem(); 490cdf0e10cSrcweir aWriter.SetOutlineItemText( nPage2OL, OUString( RTL_CONSTASCII_USTRINGPARAM( "Page 2" ) ) ); 491cdf0e10cSrcweir aWriter.CreateOutlineItem( nPage2OL, OUString( RTL_CONSTASCII_USTRINGPARAM( "Dest 1" ) ), nFirstDest ); 492cdf0e10cSrcweir 493cdf0e10cSrcweir aWriter.EndStructureElement(); // close document 494cdf0e10cSrcweir aWriter.Emit(); 495cdf0e10cSrcweir } 496cdf0e10cSrcweir #endif 497cdf0e10cSrcweir 498cdf0e10cSrcweir static const sal_Int32 nLog10Divisor = 1; 499cdf0e10cSrcweir static const double fDivisor = 10.0; 500cdf0e10cSrcweir 501cdf0e10cSrcweir static inline double pixelToPoint( sal_Int32 px ) { return double(px)/fDivisor; } 502cdf0e10cSrcweir static inline double pixelToPoint( double px ) { return px/fDivisor; } 503cdf0e10cSrcweir static inline sal_Int32 pointToPixel( double pt ) { return sal_Int32(pt*fDivisor); } 504cdf0e10cSrcweir 505cdf0e10cSrcweir const sal_uInt8 PDFWriterImpl::s_nPadString[32] = 506cdf0e10cSrcweir { 507cdf0e10cSrcweir 0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08, 508cdf0e10cSrcweir 0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80, 0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A 509cdf0e10cSrcweir }; 510cdf0e10cSrcweir 511cdf0e10cSrcweir static void appendHex( sal_Int8 nInt, OStringBuffer& rBuffer ) 512cdf0e10cSrcweir { 513cdf0e10cSrcweir static const sal_Char pHexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', 514cdf0e10cSrcweir '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; 515cdf0e10cSrcweir rBuffer.append( pHexDigits[ (nInt >> 4) & 15 ] ); 516cdf0e10cSrcweir rBuffer.append( pHexDigits[ nInt & 15 ] ); 517cdf0e10cSrcweir } 518cdf0e10cSrcweir 519cdf0e10cSrcweir static void appendName( const OUString& rStr, OStringBuffer& rBuffer ) 520cdf0e10cSrcweir { 521cdf0e10cSrcweir // FIXME i59651 add a check for max length of 127 chars? Per PDF spec 1.4, appendix C.1 522cdf0e10cSrcweir // I guess than when reading the #xx sequence it will count for a single character. 523cdf0e10cSrcweir OString aStr( OUStringToOString( rStr, RTL_TEXTENCODING_UTF8 ) ); 524cdf0e10cSrcweir const sal_Char* pStr = aStr.getStr(); 525cdf0e10cSrcweir int nLen = aStr.getLength(); 526cdf0e10cSrcweir for( int i = 0; i < nLen; i++ ) 527cdf0e10cSrcweir { 528cdf0e10cSrcweir /* #i16920# PDF recommendation: output UTF8, any byte 529cdf0e10cSrcweir * outside the interval [33(=ASCII'!');126(=ASCII'~')] 530cdf0e10cSrcweir * should be escaped hexadecimal 531cdf0e10cSrcweir * for the sake of ghostscript which also reads PDF 532cdf0e10cSrcweir * but has a narrower acceptance rate we only pass 533cdf0e10cSrcweir * alphanumerics and '-' literally. 534cdf0e10cSrcweir */ 535cdf0e10cSrcweir if( (pStr[i] >= 'A' && pStr[i] <= 'Z' ) || 536cdf0e10cSrcweir (pStr[i] >= 'a' && pStr[i] <= 'z' ) || 537cdf0e10cSrcweir (pStr[i] >= '0' && pStr[i] <= '9' ) || 538cdf0e10cSrcweir pStr[i] == '-' ) 539cdf0e10cSrcweir { 540cdf0e10cSrcweir rBuffer.append( pStr[i] ); 541cdf0e10cSrcweir } 542cdf0e10cSrcweir else 543cdf0e10cSrcweir { 544cdf0e10cSrcweir rBuffer.append( '#' ); 545cdf0e10cSrcweir appendHex( (sal_Int8)pStr[i], rBuffer ); 546cdf0e10cSrcweir } 547cdf0e10cSrcweir } 548cdf0e10cSrcweir } 549cdf0e10cSrcweir 550cdf0e10cSrcweir static void appendName( const sal_Char* pStr, OStringBuffer& rBuffer ) 551cdf0e10cSrcweir { 552cdf0e10cSrcweir //FIXME i59651 see above 553cdf0e10cSrcweir while( pStr && *pStr ) 554cdf0e10cSrcweir { 555cdf0e10cSrcweir if( (*pStr >= 'A' && *pStr <= 'Z' ) || 556cdf0e10cSrcweir (*pStr >= 'a' && *pStr <= 'z' ) || 557cdf0e10cSrcweir (*pStr >= '0' && *pStr <= '9' ) || 558cdf0e10cSrcweir *pStr == '-' ) 559cdf0e10cSrcweir { 560cdf0e10cSrcweir rBuffer.append( *pStr ); 561cdf0e10cSrcweir } 562cdf0e10cSrcweir else 563cdf0e10cSrcweir { 564cdf0e10cSrcweir rBuffer.append( '#' ); 565cdf0e10cSrcweir appendHex( (sal_Int8)*pStr, rBuffer ); 566cdf0e10cSrcweir } 567cdf0e10cSrcweir pStr++; 568cdf0e10cSrcweir } 569cdf0e10cSrcweir } 570cdf0e10cSrcweir 571cdf0e10cSrcweir //used only to emit encoded passwords 572cdf0e10cSrcweir static void appendLiteralString( const sal_Char* pStr, sal_Int32 nLength, OStringBuffer& rBuffer ) 573cdf0e10cSrcweir { 574cdf0e10cSrcweir while( nLength ) 575cdf0e10cSrcweir { 576cdf0e10cSrcweir switch( *pStr ) 577cdf0e10cSrcweir { 578cdf0e10cSrcweir case '\n' : 579cdf0e10cSrcweir rBuffer.append( "\\n" ); 580cdf0e10cSrcweir break; 581cdf0e10cSrcweir case '\r' : 582cdf0e10cSrcweir rBuffer.append( "\\r" ); 583cdf0e10cSrcweir break; 584cdf0e10cSrcweir case '\t' : 585cdf0e10cSrcweir rBuffer.append( "\\t" ); 586cdf0e10cSrcweir break; 587cdf0e10cSrcweir case '\b' : 588cdf0e10cSrcweir rBuffer.append( "\\b" ); 589cdf0e10cSrcweir break; 590cdf0e10cSrcweir case '\f' : 591cdf0e10cSrcweir rBuffer.append( "\\f" ); 592cdf0e10cSrcweir break; 593cdf0e10cSrcweir case '(' : 594cdf0e10cSrcweir case ')' : 595cdf0e10cSrcweir case '\\' : 596cdf0e10cSrcweir rBuffer.append( "\\" ); 597cdf0e10cSrcweir rBuffer.append( (sal_Char) *pStr ); 598cdf0e10cSrcweir break; 599cdf0e10cSrcweir default: 600cdf0e10cSrcweir rBuffer.append( (sal_Char) *pStr ); 601cdf0e10cSrcweir break; 602cdf0e10cSrcweir } 603cdf0e10cSrcweir pStr++; 604cdf0e10cSrcweir nLength--; 605cdf0e10cSrcweir } 606cdf0e10cSrcweir } 607cdf0e10cSrcweir 608cdf0e10cSrcweir /**--->i56629 609cdf0e10cSrcweir * Convert a string before using it. 610cdf0e10cSrcweir * 611cdf0e10cSrcweir * This string conversion function is needed because the destination name 612cdf0e10cSrcweir * in a PDF file seen through an Internet browser should be 613cdf0e10cSrcweir * specially crafted, in order to be used directly by the browser. 614cdf0e10cSrcweir * In this way the fragment part of a hyperlink to a PDF file (e.g. something 615cdf0e10cSrcweir * as 'test1/test2/a-file.pdf#thefragment) will be (hopefully) interpreted by the 616cdf0e10cSrcweir * PDF reader (currently only Adobe Reader plug-in seems to be working that way) called 617cdf0e10cSrcweir * from inside the Internet browser as: 'open the file test1/test2/a-file.pdf 618cdf0e10cSrcweir * and go to named destination thefragment using default zoom'. 619cdf0e10cSrcweir * The conversion is needed because in case of a fragment in the form: Slide%201 620cdf0e10cSrcweir * (meaning Slide 1) as it is converted obeying the Inet rules, it will become Slide25201 621cdf0e10cSrcweir * using this conversion, in both the generated named destinations, fragment and GoToR 622cdf0e10cSrcweir * destination. 623cdf0e10cSrcweir * 624cdf0e10cSrcweir * The names for destinations are name objects and so they don't need to be encrypted 625cdf0e10cSrcweir * even though they expose the content of PDF file (e.g. guessing the PDF content from the 626cdf0e10cSrcweir * destination name). 627cdf0e10cSrcweir * 628cdf0e10cSrcweir * Fhurter limitation: it is advisable to use standard ASCII characters for 629cdf0e10cSrcweir * OOo bookmarks. 630cdf0e10cSrcweir */ 631cdf0e10cSrcweir static void appendDestinationName( const rtl::OUString& rString, OStringBuffer& rBuffer ) 632cdf0e10cSrcweir { 633cdf0e10cSrcweir const sal_Unicode* pStr = rString.getStr(); 634cdf0e10cSrcweir sal_Int32 nLen = rString.getLength(); 635cdf0e10cSrcweir for( int i = 0; i < nLen; i++ ) 636cdf0e10cSrcweir { 637cdf0e10cSrcweir sal_Unicode aChar = pStr[i]; 638cdf0e10cSrcweir if( (aChar >= '0' && aChar <= '9' ) || 639cdf0e10cSrcweir (aChar >= 'a' && aChar <= 'z' ) || 640cdf0e10cSrcweir (aChar >= 'A' && aChar <= 'Z' ) || 641cdf0e10cSrcweir aChar == '-' ) 642cdf0e10cSrcweir { 643cdf0e10cSrcweir rBuffer.append((sal_Char)aChar); 644cdf0e10cSrcweir } 645cdf0e10cSrcweir else 646cdf0e10cSrcweir { 647cdf0e10cSrcweir sal_Int8 aValueHigh = sal_Int8(aChar >> 8); 648cdf0e10cSrcweir if(aValueHigh > 0) 649cdf0e10cSrcweir appendHex( aValueHigh, rBuffer ); 650cdf0e10cSrcweir appendHex( (sal_Int8)(aChar & 255 ), rBuffer ); 651cdf0e10cSrcweir } 652cdf0e10cSrcweir } 653cdf0e10cSrcweir } 654cdf0e10cSrcweir //<--- i56629 655cdf0e10cSrcweir 656cdf0e10cSrcweir static void appendUnicodeTextString( const rtl::OUString& rString, OStringBuffer& rBuffer ) 657cdf0e10cSrcweir { 658cdf0e10cSrcweir rBuffer.append( "FEFF" ); 659cdf0e10cSrcweir const sal_Unicode* pStr = rString.getStr(); 660cdf0e10cSrcweir sal_Int32 nLen = rString.getLength(); 661cdf0e10cSrcweir for( int i = 0; i < nLen; i++ ) 662cdf0e10cSrcweir { 663cdf0e10cSrcweir sal_Unicode aChar = pStr[i]; 664cdf0e10cSrcweir appendHex( (sal_Int8)(aChar >> 8), rBuffer ); 665cdf0e10cSrcweir appendHex( (sal_Int8)(aChar & 255 ), rBuffer ); 666cdf0e10cSrcweir } 667cdf0e10cSrcweir } 668cdf0e10cSrcweir 669cdf0e10cSrcweir void PDFWriterImpl::createWidgetFieldName( sal_Int32 i_nWidgetIndex, const PDFWriter::AnyWidget& i_rControl ) 670cdf0e10cSrcweir { 671cdf0e10cSrcweir /* #i80258# previously we use appendName here 672cdf0e10cSrcweir however we need a slightly different coding scheme than the normal 673cdf0e10cSrcweir name encoding for field names 674cdf0e10cSrcweir */ 675cdf0e10cSrcweir const OUString& rName = (m_aContext.Version > PDFWriter::PDF_1_2) ? i_rControl.Name : i_rControl.Text; 676cdf0e10cSrcweir OString aStr( OUStringToOString( rName, RTL_TEXTENCODING_UTF8 ) ); 677cdf0e10cSrcweir const sal_Char* pStr = aStr.getStr(); 678cdf0e10cSrcweir int nLen = aStr.getLength(); 679cdf0e10cSrcweir 680cdf0e10cSrcweir OStringBuffer aBuffer( rName.getLength()+64 ); 681cdf0e10cSrcweir for( int i = 0; i < nLen; i++ ) 682cdf0e10cSrcweir { 683cdf0e10cSrcweir /* #i16920# PDF recommendation: output UTF8, any byte 684cdf0e10cSrcweir * outside the interval [32(=ASCII' ');126(=ASCII'~')] 685cdf0e10cSrcweir * should be escaped hexadecimal 686cdf0e10cSrcweir */ 687cdf0e10cSrcweir if( (pStr[i] >= 32 && pStr[i] <= 126 ) ) 688cdf0e10cSrcweir aBuffer.append( pStr[i] ); 689cdf0e10cSrcweir else 690cdf0e10cSrcweir { 691cdf0e10cSrcweir aBuffer.append( '#' ); 692cdf0e10cSrcweir appendHex( (sal_Int8)pStr[i], aBuffer ); 693cdf0e10cSrcweir } 694cdf0e10cSrcweir } 695cdf0e10cSrcweir 696cdf0e10cSrcweir OString aFullName( aBuffer.makeStringAndClear() ); 697cdf0e10cSrcweir 698cdf0e10cSrcweir /* #i82785# create hierarchical fields down to the for each dot in i_rName */ 699cdf0e10cSrcweir sal_Int32 nTokenIndex = 0, nLastTokenIndex = 0; 700cdf0e10cSrcweir OString aPartialName; 701cdf0e10cSrcweir OString aDomain; 702cdf0e10cSrcweir do 703cdf0e10cSrcweir { 704cdf0e10cSrcweir nLastTokenIndex = nTokenIndex; 705cdf0e10cSrcweir aPartialName = aFullName.getToken( 0, '.', nTokenIndex ); 706cdf0e10cSrcweir if( nTokenIndex != -1 ) 707cdf0e10cSrcweir { 708cdf0e10cSrcweir // find or create a hierarchical field 709cdf0e10cSrcweir // first find the fully qualified name up to this field 710cdf0e10cSrcweir aDomain = aFullName.copy( 0, nTokenIndex-1 ); 711cdf0e10cSrcweir std::hash_map< rtl::OString, sal_Int32, rtl::OStringHash >::const_iterator it = m_aFieldNameMap.find( aDomain ); 712cdf0e10cSrcweir if( it == m_aFieldNameMap.end() ) 713cdf0e10cSrcweir { 714cdf0e10cSrcweir // create new hierarchy field 715cdf0e10cSrcweir sal_Int32 nNewWidget = m_aWidgets.size(); 716cdf0e10cSrcweir m_aWidgets.push_back( PDFWidget() ); 717cdf0e10cSrcweir m_aWidgets[nNewWidget].m_nObject = createObject(); 718cdf0e10cSrcweir m_aWidgets[nNewWidget].m_eType = PDFWriter::Hierarchy; 719cdf0e10cSrcweir m_aWidgets[nNewWidget].m_aName = aPartialName; 720cdf0e10cSrcweir m_aWidgets[i_nWidgetIndex].m_nParent = m_aWidgets[nNewWidget].m_nObject; 721cdf0e10cSrcweir m_aFieldNameMap[aDomain] = nNewWidget; 722cdf0e10cSrcweir m_aWidgets[i_nWidgetIndex].m_nParent = m_aWidgets[nNewWidget].m_nObject; 723cdf0e10cSrcweir if( nLastTokenIndex > 0 ) 724cdf0e10cSrcweir { 725cdf0e10cSrcweir // this field is not a root field and 726cdf0e10cSrcweir // needs to be inserted to its parent 727cdf0e10cSrcweir OString aParentDomain( aDomain.copy( 0, nLastTokenIndex-1 ) ); 728cdf0e10cSrcweir it = m_aFieldNameMap.find( aParentDomain ); 729cdf0e10cSrcweir OSL_ENSURE( it != m_aFieldNameMap.end(), "field name not found" ); 730cdf0e10cSrcweir if( it != m_aFieldNameMap.end() ) 731cdf0e10cSrcweir { 732cdf0e10cSrcweir OSL_ENSURE( it->second < sal_Int32(m_aWidgets.size()), "invalid field number entry" ); 733cdf0e10cSrcweir if( it->second < sal_Int32(m_aWidgets.size()) ) 734cdf0e10cSrcweir { 735cdf0e10cSrcweir PDFWidget& rParentField( m_aWidgets[it->second] ); 736cdf0e10cSrcweir rParentField.m_aKids.push_back( m_aWidgets[nNewWidget].m_nObject ); 737cdf0e10cSrcweir rParentField.m_aKidsIndex.push_back( nNewWidget ); 738cdf0e10cSrcweir m_aWidgets[nNewWidget].m_nParent = rParentField.m_nObject; 739cdf0e10cSrcweir } 740cdf0e10cSrcweir } 741cdf0e10cSrcweir } 742cdf0e10cSrcweir } 743cdf0e10cSrcweir else if( m_aWidgets[it->second].m_eType != PDFWriter::Hierarchy ) 744cdf0e10cSrcweir { 745cdf0e10cSrcweir // this is invalid, someone tries to have a terminal field as parent 746cdf0e10cSrcweir // example: a button with the name foo.bar exists and 747cdf0e10cSrcweir // another button is named foo.bar.no 748cdf0e10cSrcweir // workaround: put the second terminal field as much up in the hierarchy as 749cdf0e10cSrcweir // necessary to have a non-terminal field as parent (or none at all) 750cdf0e10cSrcweir // since it->second already is terminal, we just need to use its parent 751cdf0e10cSrcweir aDomain = OString(); 752cdf0e10cSrcweir aPartialName = aFullName.copy( aFullName.lastIndexOf( '.' )+1 ); 753cdf0e10cSrcweir if( nLastTokenIndex > 0 ) 754cdf0e10cSrcweir { 755cdf0e10cSrcweir aDomain = aFullName.copy( 0, nLastTokenIndex-1 ); 756cdf0e10cSrcweir OStringBuffer aBuf( aDomain.getLength() + 1 + aPartialName.getLength() ); 757cdf0e10cSrcweir aBuf.append( aDomain ); 758cdf0e10cSrcweir aBuf.append( '.' ); 759cdf0e10cSrcweir aBuf.append( aPartialName ); 760cdf0e10cSrcweir aFullName = aBuf.makeStringAndClear(); 761cdf0e10cSrcweir } 762cdf0e10cSrcweir else 763cdf0e10cSrcweir aFullName = aPartialName; 764cdf0e10cSrcweir break; 765cdf0e10cSrcweir } 766cdf0e10cSrcweir } 767cdf0e10cSrcweir } while( nTokenIndex != -1 ); 768cdf0e10cSrcweir 769cdf0e10cSrcweir // insert widget into its hierarchy field 770cdf0e10cSrcweir if( aDomain.getLength() ) 771cdf0e10cSrcweir { 772cdf0e10cSrcweir std::hash_map< rtl::OString, sal_Int32, rtl::OStringHash >::const_iterator it = m_aFieldNameMap.find( aDomain ); 773cdf0e10cSrcweir if( it != m_aFieldNameMap.end() ) 774cdf0e10cSrcweir { 775cdf0e10cSrcweir OSL_ENSURE( it->second >= 0 && it->second < sal_Int32( m_aWidgets.size() ), "invalid field index" ); 776cdf0e10cSrcweir if( it->second >= 0 && it->second < sal_Int32(m_aWidgets.size()) ) 777cdf0e10cSrcweir { 778cdf0e10cSrcweir m_aWidgets[i_nWidgetIndex].m_nParent = m_aWidgets[it->second].m_nObject; 779cdf0e10cSrcweir m_aWidgets[it->second].m_aKids.push_back( m_aWidgets[i_nWidgetIndex].m_nObject); 780cdf0e10cSrcweir m_aWidgets[it->second].m_aKidsIndex.push_back( i_nWidgetIndex ); 781cdf0e10cSrcweir } 782cdf0e10cSrcweir } 783cdf0e10cSrcweir } 784cdf0e10cSrcweir 785cdf0e10cSrcweir if( aPartialName.getLength() == 0 ) 786cdf0e10cSrcweir { 787cdf0e10cSrcweir // how funny, an empty field name 788cdf0e10cSrcweir if( i_rControl.getType() == PDFWriter::RadioButton ) 789cdf0e10cSrcweir { 790cdf0e10cSrcweir aPartialName = "RadioGroup"; 791cdf0e10cSrcweir aPartialName += OString::valueOf( static_cast<const PDFWriter::RadioButtonWidget&>(i_rControl).RadioGroup ); 792cdf0e10cSrcweir } 793cdf0e10cSrcweir else 794cdf0e10cSrcweir aPartialName = OString( "Widget" ); 795cdf0e10cSrcweir } 796cdf0e10cSrcweir 797cdf0e10cSrcweir if( ! m_aContext.AllowDuplicateFieldNames ) 798cdf0e10cSrcweir { 799cdf0e10cSrcweir std::hash_map<OString, sal_Int32, OStringHash>::iterator it = m_aFieldNameMap.find( aFullName ); 800cdf0e10cSrcweir 801cdf0e10cSrcweir if( it != m_aFieldNameMap.end() ) // not unique 802cdf0e10cSrcweir { 803cdf0e10cSrcweir std::hash_map< OString, sal_Int32, OStringHash >::const_iterator check_it; 804cdf0e10cSrcweir OString aTry; 805cdf0e10cSrcweir sal_Int32 nTry = 2; 806cdf0e10cSrcweir do 807cdf0e10cSrcweir { 808cdf0e10cSrcweir OStringBuffer aUnique( aFullName.getLength() + 16 ); 809cdf0e10cSrcweir aUnique.append( aFullName ); 810cdf0e10cSrcweir aUnique.append( '_' ); 811cdf0e10cSrcweir aUnique.append( nTry++ ); 812cdf0e10cSrcweir aTry = aUnique.makeStringAndClear(); 813cdf0e10cSrcweir check_it = m_aFieldNameMap.find( aTry ); 814cdf0e10cSrcweir } while( check_it != m_aFieldNameMap.end() ); 815cdf0e10cSrcweir aFullName = aTry; 816cdf0e10cSrcweir m_aFieldNameMap[ aFullName ] = i_nWidgetIndex; 817cdf0e10cSrcweir aPartialName = aFullName.copy( aFullName.lastIndexOf( '.' )+1 ); 818cdf0e10cSrcweir } 819cdf0e10cSrcweir else 820cdf0e10cSrcweir m_aFieldNameMap[ aFullName ] = i_nWidgetIndex; 821cdf0e10cSrcweir } 822cdf0e10cSrcweir 823cdf0e10cSrcweir // finally 824cdf0e10cSrcweir m_aWidgets[i_nWidgetIndex].m_aName = aPartialName; 825cdf0e10cSrcweir } 826cdf0e10cSrcweir 827cdf0e10cSrcweir static void appendFixedInt( sal_Int32 nValue, OStringBuffer& rBuffer, sal_Int32 nPrecision = nLog10Divisor ) 828cdf0e10cSrcweir { 829cdf0e10cSrcweir if( nValue < 0 ) 830cdf0e10cSrcweir { 831cdf0e10cSrcweir rBuffer.append( '-' ); 832cdf0e10cSrcweir nValue = -nValue; 833cdf0e10cSrcweir } 834cdf0e10cSrcweir sal_Int32 nFactor = 1, nDiv = nPrecision; 835cdf0e10cSrcweir while( nDiv-- ) 836cdf0e10cSrcweir nFactor *= 10; 837cdf0e10cSrcweir 838cdf0e10cSrcweir sal_Int32 nInt = nValue / nFactor; 839cdf0e10cSrcweir rBuffer.append( nInt ); 840cdf0e10cSrcweir if( nFactor > 1 ) 841cdf0e10cSrcweir { 842cdf0e10cSrcweir sal_Int32 nDecimal = nValue % nFactor; 843cdf0e10cSrcweir if( nDecimal ) 844cdf0e10cSrcweir { 845cdf0e10cSrcweir rBuffer.append( '.' ); 846cdf0e10cSrcweir // omit trailing zeros 847cdf0e10cSrcweir while( (nDecimal % 10) == 0 ) 848cdf0e10cSrcweir nDecimal /= 10; 849cdf0e10cSrcweir rBuffer.append( nDecimal ); 850cdf0e10cSrcweir } 851cdf0e10cSrcweir } 852cdf0e10cSrcweir } 853cdf0e10cSrcweir 854cdf0e10cSrcweir 855cdf0e10cSrcweir // appends a double. PDF does not accept exponential format, only fixed point 856cdf0e10cSrcweir static void appendDouble( double fValue, OStringBuffer& rBuffer, sal_Int32 nPrecision = 5 ) 857cdf0e10cSrcweir { 858cdf0e10cSrcweir bool bNeg = false; 859cdf0e10cSrcweir if( fValue < 0.0 ) 860cdf0e10cSrcweir { 861cdf0e10cSrcweir bNeg = true; 862cdf0e10cSrcweir fValue=-fValue; 863cdf0e10cSrcweir } 864cdf0e10cSrcweir 865cdf0e10cSrcweir sal_Int64 nInt = (sal_Int64)fValue; 866cdf0e10cSrcweir fValue -= (double)nInt; 867cdf0e10cSrcweir // optimizing hardware may lead to a value of 1.0 after the subtraction 868cdf0e10cSrcweir if( fValue == 1.0 || log10( 1.0-fValue ) <= -nPrecision ) 869cdf0e10cSrcweir { 870cdf0e10cSrcweir nInt++; 871cdf0e10cSrcweir fValue = 0.0; 872cdf0e10cSrcweir } 873cdf0e10cSrcweir sal_Int64 nFrac = 0; 874cdf0e10cSrcweir if( fValue ) 875cdf0e10cSrcweir { 876cdf0e10cSrcweir fValue *= pow( 10.0, (double)nPrecision ); 877cdf0e10cSrcweir nFrac = (sal_Int64)fValue; 878cdf0e10cSrcweir } 879cdf0e10cSrcweir if( bNeg && ( nInt || nFrac ) ) 880cdf0e10cSrcweir rBuffer.append( '-' ); 881cdf0e10cSrcweir rBuffer.append( nInt ); 882cdf0e10cSrcweir if( nFrac ) 883cdf0e10cSrcweir { 884cdf0e10cSrcweir int i; 885cdf0e10cSrcweir rBuffer.append( '.' ); 886cdf0e10cSrcweir sal_Int64 nBound = (sal_Int64)(pow( 10.0, nPrecision - 1.0 )+0.5); 887cdf0e10cSrcweir for ( i = 0; ( i < nPrecision ) && nFrac; i++ ) 888cdf0e10cSrcweir { 889cdf0e10cSrcweir sal_Int64 nNumb = nFrac / nBound; 890cdf0e10cSrcweir nFrac -= nNumb * nBound; 891cdf0e10cSrcweir rBuffer.append( nNumb ); 892cdf0e10cSrcweir nBound /= 10; 893cdf0e10cSrcweir } 894cdf0e10cSrcweir } 895cdf0e10cSrcweir } 896cdf0e10cSrcweir 897cdf0e10cSrcweir 898cdf0e10cSrcweir static void appendColor( const Color& rColor, OStringBuffer& rBuffer, bool bConvertToGrey = false ) 899cdf0e10cSrcweir { 900cdf0e10cSrcweir 901cdf0e10cSrcweir if( rColor != Color( COL_TRANSPARENT ) ) 902cdf0e10cSrcweir { 903cdf0e10cSrcweir if( bConvertToGrey ) 904cdf0e10cSrcweir { 905cdf0e10cSrcweir sal_uInt8 cByte = rColor.GetLuminance(); 906cdf0e10cSrcweir appendDouble( (double)cByte / 255.0, rBuffer ); 907cdf0e10cSrcweir } 908cdf0e10cSrcweir else 909cdf0e10cSrcweir { 910cdf0e10cSrcweir appendDouble( (double)rColor.GetRed() / 255.0, rBuffer ); 911cdf0e10cSrcweir rBuffer.append( ' ' ); 912cdf0e10cSrcweir appendDouble( (double)rColor.GetGreen() / 255.0, rBuffer ); 913cdf0e10cSrcweir rBuffer.append( ' ' ); 914cdf0e10cSrcweir appendDouble( (double)rColor.GetBlue() / 255.0, rBuffer ); 915cdf0e10cSrcweir } 916cdf0e10cSrcweir } 917cdf0e10cSrcweir } 918cdf0e10cSrcweir 919cdf0e10cSrcweir void PDFWriterImpl::appendStrokingColor( const Color& rColor, OStringBuffer& rBuffer ) 920cdf0e10cSrcweir { 921cdf0e10cSrcweir if( rColor != Color( COL_TRANSPARENT ) ) 922cdf0e10cSrcweir { 923cdf0e10cSrcweir bool bGrey = m_aContext.ColorMode == PDFWriter::DrawGreyscale; 924cdf0e10cSrcweir appendColor( rColor, rBuffer, bGrey ); 925cdf0e10cSrcweir rBuffer.append( bGrey ? " G" : " RG" ); 926cdf0e10cSrcweir } 927cdf0e10cSrcweir } 928cdf0e10cSrcweir 929cdf0e10cSrcweir void PDFWriterImpl::appendNonStrokingColor( const Color& rColor, OStringBuffer& rBuffer ) 930cdf0e10cSrcweir { 931cdf0e10cSrcweir if( rColor != Color( COL_TRANSPARENT ) ) 932cdf0e10cSrcweir { 933cdf0e10cSrcweir bool bGrey = m_aContext.ColorMode == PDFWriter::DrawGreyscale; 934cdf0e10cSrcweir appendColor( rColor, rBuffer, bGrey ); 935cdf0e10cSrcweir rBuffer.append( bGrey ? " g" : " rg" ); 936cdf0e10cSrcweir } 937cdf0e10cSrcweir } 938cdf0e10cSrcweir 939cdf0e10cSrcweir // matrix helper class 940cdf0e10cSrcweir // TODO: use basegfx matrix class instead or derive from it 941cdf0e10cSrcweir namespace vcl // TODO: use anonymous namespace to keep this class local 942cdf0e10cSrcweir { 943cdf0e10cSrcweir /* for sparse matrices of the form (2D linear transformations) 944cdf0e10cSrcweir * f[0] f[1] 0 945cdf0e10cSrcweir * f[2] f[3] 0 946cdf0e10cSrcweir * f[4] f[5] 1 947cdf0e10cSrcweir */ 948cdf0e10cSrcweir class Matrix3 949cdf0e10cSrcweir { 950cdf0e10cSrcweir double f[6]; 951cdf0e10cSrcweir 952cdf0e10cSrcweir void set( double *pn ) { for( int i = 0 ; i < 6; i++ ) f[i] = pn[i]; } 953cdf0e10cSrcweir public: 954cdf0e10cSrcweir Matrix3(); 955cdf0e10cSrcweir ~Matrix3() {} 956cdf0e10cSrcweir 957cdf0e10cSrcweir void skew( double alpha, double beta ); 958cdf0e10cSrcweir void scale( double sx, double sy ); 959cdf0e10cSrcweir void rotate( double angle ); 960cdf0e10cSrcweir void translate( double tx, double ty ); 961cdf0e10cSrcweir bool invert(); 962cdf0e10cSrcweir 963cdf0e10cSrcweir void append( PDFWriterImpl::PDFPage& rPage, OStringBuffer& rBuffer, Point* pBack = NULL ); 964cdf0e10cSrcweir 965cdf0e10cSrcweir Point transform( const Point& rPoint ) const; 966cdf0e10cSrcweir }; 967cdf0e10cSrcweir } 968cdf0e10cSrcweir 969cdf0e10cSrcweir Matrix3::Matrix3() 970cdf0e10cSrcweir { 971cdf0e10cSrcweir // initialize to unity 972cdf0e10cSrcweir f[0] = 1.0; 973cdf0e10cSrcweir f[1] = 0.0; 974cdf0e10cSrcweir f[2] = 0.0; 975cdf0e10cSrcweir f[3] = 1.0; 976cdf0e10cSrcweir f[4] = 0.0; 977cdf0e10cSrcweir f[5] = 0.0; 978cdf0e10cSrcweir } 979cdf0e10cSrcweir 980cdf0e10cSrcweir Point Matrix3::transform( const Point& rOrig ) const 981cdf0e10cSrcweir { 982cdf0e10cSrcweir double x = (double)rOrig.X(), y = (double)rOrig.Y(); 983cdf0e10cSrcweir return Point( (int)(x*f[0] + y*f[2] + f[4]), (int)(x*f[1] + y*f[3] + f[5]) ); 984cdf0e10cSrcweir } 985cdf0e10cSrcweir 986cdf0e10cSrcweir void Matrix3::skew( double alpha, double beta ) 987cdf0e10cSrcweir { 988cdf0e10cSrcweir double fn[6]; 989cdf0e10cSrcweir double tb = tan( beta ); 990cdf0e10cSrcweir fn[0] = f[0] + f[2]*tb; 991cdf0e10cSrcweir fn[1] = f[1]; 992cdf0e10cSrcweir fn[2] = f[2] + f[3]*tb; 993cdf0e10cSrcweir fn[3] = f[3]; 994cdf0e10cSrcweir fn[4] = f[4] + f[5]*tb; 995cdf0e10cSrcweir fn[5] = f[5]; 996cdf0e10cSrcweir if( alpha != 0.0 ) 997cdf0e10cSrcweir { 998cdf0e10cSrcweir double ta = tan( alpha ); 999cdf0e10cSrcweir fn[1] += f[0]*ta; 1000cdf0e10cSrcweir fn[3] += f[2]*ta; 1001cdf0e10cSrcweir fn[5] += f[4]*ta; 1002cdf0e10cSrcweir } 1003cdf0e10cSrcweir set( fn ); 1004cdf0e10cSrcweir } 1005cdf0e10cSrcweir 1006cdf0e10cSrcweir void Matrix3::scale( double sx, double sy ) 1007cdf0e10cSrcweir { 1008cdf0e10cSrcweir double fn[6]; 1009cdf0e10cSrcweir fn[0] = sx*f[0]; 1010cdf0e10cSrcweir fn[1] = sy*f[1]; 1011cdf0e10cSrcweir fn[2] = sx*f[2]; 1012cdf0e10cSrcweir fn[3] = sy*f[3]; 1013cdf0e10cSrcweir fn[4] = sx*f[4]; 1014cdf0e10cSrcweir fn[5] = sy*f[5]; 1015cdf0e10cSrcweir set( fn ); 1016cdf0e10cSrcweir } 1017cdf0e10cSrcweir 1018cdf0e10cSrcweir void Matrix3::rotate( double angle ) 1019cdf0e10cSrcweir { 1020cdf0e10cSrcweir double fn[6]; 1021cdf0e10cSrcweir double fSin = sin(angle); 1022cdf0e10cSrcweir double fCos = cos(angle); 1023cdf0e10cSrcweir fn[0] = f[0]*fCos - f[1]*fSin; 1024cdf0e10cSrcweir fn[1] = f[0]*fSin + f[1]*fCos; 1025cdf0e10cSrcweir fn[2] = f[2]*fCos - f[3]*fSin; 1026cdf0e10cSrcweir fn[3] = f[2]*fSin + f[3]*fCos; 1027cdf0e10cSrcweir fn[4] = f[4]*fCos - f[5]*fSin; 1028cdf0e10cSrcweir fn[5] = f[4]*fSin + f[5]*fCos; 1029cdf0e10cSrcweir set( fn ); 1030cdf0e10cSrcweir } 1031cdf0e10cSrcweir 1032cdf0e10cSrcweir void Matrix3::translate( double tx, double ty ) 1033cdf0e10cSrcweir { 1034cdf0e10cSrcweir f[4] += tx; 1035cdf0e10cSrcweir f[5] += ty; 1036cdf0e10cSrcweir } 1037cdf0e10cSrcweir 1038cdf0e10cSrcweir bool Matrix3::invert() 1039cdf0e10cSrcweir { 1040cdf0e10cSrcweir // short circuit trivial cases 1041cdf0e10cSrcweir if( f[1]==f[2] && f[1]==0.0 && f[0]==f[3] && f[0]==1.0 ) 1042cdf0e10cSrcweir { 1043cdf0e10cSrcweir f[4] = -f[4]; 1044cdf0e10cSrcweir f[5] = -f[5]; 1045cdf0e10cSrcweir return true; 1046cdf0e10cSrcweir } 1047cdf0e10cSrcweir 1048cdf0e10cSrcweir // check determinant 1049cdf0e10cSrcweir const double fDet = f[0]*f[3]-f[1]*f[2]; 1050cdf0e10cSrcweir if( fDet == 0.0 ) 1051cdf0e10cSrcweir return false; 1052cdf0e10cSrcweir 1053cdf0e10cSrcweir // invert the matrix 1054cdf0e10cSrcweir double fn[6]; 1055cdf0e10cSrcweir fn[0] = +f[3] / fDet; 1056cdf0e10cSrcweir fn[1] = -f[1] / fDet; 1057cdf0e10cSrcweir fn[2] = -f[2] / fDet; 1058cdf0e10cSrcweir fn[3] = +f[0] / fDet; 1059cdf0e10cSrcweir 1060cdf0e10cSrcweir // apply inversion to translation 1061cdf0e10cSrcweir fn[4] = -(f[4]*fn[0] + f[5]*fn[2]); 1062cdf0e10cSrcweir fn[5] = -(f[4]*fn[1] + f[5]*fn[3]); 1063cdf0e10cSrcweir 1064cdf0e10cSrcweir set( fn ); 1065cdf0e10cSrcweir return true; 1066cdf0e10cSrcweir } 1067cdf0e10cSrcweir 1068cdf0e10cSrcweir void Matrix3::append( PDFWriterImpl::PDFPage& rPage, OStringBuffer& rBuffer, Point* pBack ) 1069cdf0e10cSrcweir { 1070cdf0e10cSrcweir appendDouble( f[0], rBuffer ); 1071cdf0e10cSrcweir rBuffer.append( ' ' ); 1072cdf0e10cSrcweir appendDouble( f[1], rBuffer ); 1073cdf0e10cSrcweir rBuffer.append( ' ' ); 1074cdf0e10cSrcweir appendDouble( f[2], rBuffer ); 1075cdf0e10cSrcweir rBuffer.append( ' ' ); 1076cdf0e10cSrcweir appendDouble( f[3], rBuffer ); 1077cdf0e10cSrcweir rBuffer.append( ' ' ); 1078cdf0e10cSrcweir rPage.appendPoint( Point( (long)f[4], (long)f[5] ), rBuffer, false, pBack ); 1079cdf0e10cSrcweir } 1080cdf0e10cSrcweir 1081cdf0e10cSrcweir static void appendResourceMap( OStringBuffer& rBuf, const char* pPrefix, const PDFWriterImpl::ResourceMap& rList ) 1082cdf0e10cSrcweir { 1083cdf0e10cSrcweir if( rList.empty() ) 1084cdf0e10cSrcweir return; 1085cdf0e10cSrcweir rBuf.append( '/' ); 1086cdf0e10cSrcweir rBuf.append( pPrefix ); 1087cdf0e10cSrcweir rBuf.append( "<<" ); 1088cdf0e10cSrcweir int ni = 0; 1089cdf0e10cSrcweir for( PDFWriterImpl::ResourceMap::const_iterator it = rList.begin(); it != rList.end(); ++it ) 1090cdf0e10cSrcweir { 1091cdf0e10cSrcweir if( it->first.getLength() && it->second > 0 ) 1092cdf0e10cSrcweir { 1093cdf0e10cSrcweir rBuf.append( '/' ); 1094cdf0e10cSrcweir rBuf.append( it->first ); 1095cdf0e10cSrcweir rBuf.append( ' ' ); 1096cdf0e10cSrcweir rBuf.append( it->second ); 1097cdf0e10cSrcweir rBuf.append( " 0 R" ); 1098cdf0e10cSrcweir if( ((++ni) & 7) == 0 ) 1099cdf0e10cSrcweir rBuf.append( '\n' ); 1100cdf0e10cSrcweir } 1101cdf0e10cSrcweir } 1102cdf0e10cSrcweir rBuf.append( ">>\n" ); 1103cdf0e10cSrcweir } 1104cdf0e10cSrcweir 1105cdf0e10cSrcweir void PDFWriterImpl::ResourceDict::append( OStringBuffer& rBuf, sal_Int32 nFontDictObject ) 1106cdf0e10cSrcweir { 1107cdf0e10cSrcweir rBuf.append( "<</Font " ); 1108cdf0e10cSrcweir rBuf.append( nFontDictObject ); 1109cdf0e10cSrcweir rBuf.append( " 0 R\n" ); 1110cdf0e10cSrcweir appendResourceMap( rBuf, "XObject", m_aXObjects ); 1111cdf0e10cSrcweir appendResourceMap( rBuf, "ExtGState", m_aExtGStates ); 1112cdf0e10cSrcweir appendResourceMap( rBuf, "Shading", m_aShadings ); 1113cdf0e10cSrcweir appendResourceMap( rBuf, "Pattern", m_aPatterns ); 1114cdf0e10cSrcweir rBuf.append( "/ProcSet[/PDF/Text" ); 1115cdf0e10cSrcweir if( !m_aXObjects.empty() ) 1116cdf0e10cSrcweir rBuf.append( "/ImageC/ImageI/ImageB" ); 1117cdf0e10cSrcweir rBuf.append( "]\n>>\n" ); 1118cdf0e10cSrcweir }; 1119cdf0e10cSrcweir 1120cdf0e10cSrcweir PDFWriterImpl::PDFPage::PDFPage( PDFWriterImpl* pWriter, sal_Int32 nPageWidth, sal_Int32 nPageHeight, PDFWriter::Orientation eOrientation ) 1121cdf0e10cSrcweir : 1122cdf0e10cSrcweir m_pWriter( pWriter ), 1123cdf0e10cSrcweir m_nPageWidth( nPageWidth ), 1124cdf0e10cSrcweir m_nPageHeight( nPageHeight ), 1125cdf0e10cSrcweir m_eOrientation( eOrientation ), 1126cdf0e10cSrcweir m_nPageObject( 0 ), // invalid object number 1127cdf0e10cSrcweir m_nPageIndex( -1 ), // invalid index 1128cdf0e10cSrcweir m_nStreamLengthObject( 0 ), 1129cdf0e10cSrcweir m_nBeginStreamPos( 0 ), 1130cdf0e10cSrcweir m_eTransition( PDFWriter::Regular ), 1131cdf0e10cSrcweir m_nTransTime( 0 ), 1132cdf0e10cSrcweir m_nDuration( 0 ), 1133cdf0e10cSrcweir m_bHasWidgets( false ) 1134cdf0e10cSrcweir { 1135cdf0e10cSrcweir // object ref must be only ever updated in emit() 1136cdf0e10cSrcweir m_nPageObject = m_pWriter->createObject(); 1137cdf0e10cSrcweir } 1138cdf0e10cSrcweir 1139cdf0e10cSrcweir PDFWriterImpl::PDFPage::~PDFPage() 1140cdf0e10cSrcweir { 1141cdf0e10cSrcweir } 1142cdf0e10cSrcweir 1143cdf0e10cSrcweir void PDFWriterImpl::PDFPage::beginStream() 1144cdf0e10cSrcweir { 1145cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 1146cdf0e10cSrcweir { 1147cdf0e10cSrcweir OStringBuffer aLine( "PDFWriterImpl::PDFPage::beginStream, +" ); 1148cdf0e10cSrcweir m_pWriter->emitComment( aLine.getStr() ); 1149cdf0e10cSrcweir } 1150cdf0e10cSrcweir #endif 1151cdf0e10cSrcweir m_aStreamObjects.push_back(m_pWriter->createObject()); 1152cdf0e10cSrcweir if( ! m_pWriter->updateObject( m_aStreamObjects.back() ) ) 1153cdf0e10cSrcweir return; 1154cdf0e10cSrcweir 1155cdf0e10cSrcweir m_nStreamLengthObject = m_pWriter->createObject(); 1156cdf0e10cSrcweir // write content stream header 1157cdf0e10cSrcweir OStringBuffer aLine; 1158cdf0e10cSrcweir aLine.append( m_aStreamObjects.back() ); 1159cdf0e10cSrcweir aLine.append( " 0 obj\n<</Length " ); 1160cdf0e10cSrcweir aLine.append( m_nStreamLengthObject ); 1161cdf0e10cSrcweir aLine.append( " 0 R" ); 1162cdf0e10cSrcweir #if defined ( COMPRESS_PAGES ) && !defined ( DEBUG_DISABLE_PDFCOMPRESSION ) 1163cdf0e10cSrcweir aLine.append( "/Filter/FlateDecode" ); 1164cdf0e10cSrcweir #endif 1165cdf0e10cSrcweir aLine.append( ">>\nstream\n" ); 1166cdf0e10cSrcweir if( ! m_pWriter->writeBuffer( aLine.getStr(), aLine.getLength() ) ) 1167cdf0e10cSrcweir return; 1168cdf0e10cSrcweir if( osl_File_E_None != osl_getFilePos( m_pWriter->m_aFile, &m_nBeginStreamPos ) ) 1169cdf0e10cSrcweir { 1170cdf0e10cSrcweir osl_closeFile( m_pWriter->m_aFile ); 1171cdf0e10cSrcweir m_pWriter->m_bOpen = false; 1172cdf0e10cSrcweir } 1173cdf0e10cSrcweir #if defined ( COMPRESS_PAGES ) && !defined ( DEBUG_DISABLE_PDFCOMPRESSION ) 1174cdf0e10cSrcweir m_pWriter->beginCompression(); 1175cdf0e10cSrcweir #endif 1176cdf0e10cSrcweir m_pWriter->checkAndEnableStreamEncryption( m_aStreamObjects.back() ); 1177cdf0e10cSrcweir } 1178cdf0e10cSrcweir 1179cdf0e10cSrcweir void PDFWriterImpl::PDFPage::endStream() 1180cdf0e10cSrcweir { 1181cdf0e10cSrcweir #if defined ( COMPRESS_PAGES ) && !defined ( DEBUG_DISABLE_PDFCOMPRESSION ) 1182cdf0e10cSrcweir m_pWriter->endCompression(); 1183cdf0e10cSrcweir #endif 1184cdf0e10cSrcweir sal_uInt64 nEndStreamPos; 1185cdf0e10cSrcweir if( osl_File_E_None != osl_getFilePos( m_pWriter->m_aFile, &nEndStreamPos ) ) 1186cdf0e10cSrcweir { 1187cdf0e10cSrcweir osl_closeFile( m_pWriter->m_aFile ); 1188cdf0e10cSrcweir m_pWriter->m_bOpen = false; 1189cdf0e10cSrcweir return; 1190cdf0e10cSrcweir } 1191cdf0e10cSrcweir m_pWriter->disableStreamEncryption(); 1192cdf0e10cSrcweir if( ! m_pWriter->writeBuffer( "\nendstream\nendobj\n\n", 19 ) ) 1193cdf0e10cSrcweir return; 1194cdf0e10cSrcweir // emit stream length object 1195cdf0e10cSrcweir if( ! m_pWriter->updateObject( m_nStreamLengthObject ) ) 1196cdf0e10cSrcweir return; 1197cdf0e10cSrcweir OStringBuffer aLine; 1198cdf0e10cSrcweir aLine.append( m_nStreamLengthObject ); 1199cdf0e10cSrcweir aLine.append( " 0 obj\n" ); 1200cdf0e10cSrcweir aLine.append( (sal_Int64)(nEndStreamPos-m_nBeginStreamPos) ); 1201cdf0e10cSrcweir aLine.append( "\nendobj\n\n" ); 1202cdf0e10cSrcweir m_pWriter->writeBuffer( aLine.getStr(), aLine.getLength() ); 1203cdf0e10cSrcweir } 1204cdf0e10cSrcweir 1205cdf0e10cSrcweir bool PDFWriterImpl::PDFPage::emit(sal_Int32 nParentObject ) 1206cdf0e10cSrcweir { 1207cdf0e10cSrcweir // emit page object 1208cdf0e10cSrcweir if( ! m_pWriter->updateObject( m_nPageObject ) ) 1209cdf0e10cSrcweir return false; 1210cdf0e10cSrcweir OStringBuffer aLine; 1211cdf0e10cSrcweir 1212cdf0e10cSrcweir aLine.append( m_nPageObject ); 1213cdf0e10cSrcweir aLine.append( " 0 obj\n" 1214cdf0e10cSrcweir "<</Type/Page/Parent " ); 1215cdf0e10cSrcweir aLine.append( nParentObject ); 1216cdf0e10cSrcweir aLine.append( " 0 R" ); 1217cdf0e10cSrcweir aLine.append( "/Resources " ); 1218cdf0e10cSrcweir aLine.append( m_pWriter->getResourceDictObj() ); 1219cdf0e10cSrcweir aLine.append( " 0 R" ); 1220cdf0e10cSrcweir if( m_nPageWidth && m_nPageHeight ) 1221cdf0e10cSrcweir { 1222cdf0e10cSrcweir aLine.append( "/MediaBox[0 0 " ); 1223cdf0e10cSrcweir aLine.append( m_nPageWidth ); 1224cdf0e10cSrcweir aLine.append( ' ' ); 1225cdf0e10cSrcweir aLine.append( m_nPageHeight ); 1226cdf0e10cSrcweir aLine.append( "]" ); 1227cdf0e10cSrcweir } 1228cdf0e10cSrcweir switch( m_eOrientation ) 1229cdf0e10cSrcweir { 1230cdf0e10cSrcweir case PDFWriter::Landscape: aLine.append( "/Rotate 90\n" );break; 1231cdf0e10cSrcweir case PDFWriter::Seascape: aLine.append( "/Rotate -90\n" );break; 1232cdf0e10cSrcweir case PDFWriter::Portrait: aLine.append( "/Rotate 0\n" );break; 1233cdf0e10cSrcweir 1234cdf0e10cSrcweir case PDFWriter::Inherit: 1235cdf0e10cSrcweir default: 1236cdf0e10cSrcweir break; 1237cdf0e10cSrcweir } 1238cdf0e10cSrcweir int nAnnots = m_aAnnotations.size(); 1239cdf0e10cSrcweir if( nAnnots > 0 ) 1240cdf0e10cSrcweir { 1241cdf0e10cSrcweir aLine.append( "/Annots[\n" ); 1242cdf0e10cSrcweir for( int i = 0; i < nAnnots; i++ ) 1243cdf0e10cSrcweir { 1244cdf0e10cSrcweir aLine.append( m_aAnnotations[i] ); 1245cdf0e10cSrcweir aLine.append( " 0 R" ); 1246cdf0e10cSrcweir aLine.append( ((i+1)%15) ? " " : "\n" ); 1247cdf0e10cSrcweir } 1248cdf0e10cSrcweir aLine.append( "]\n" ); 1249cdf0e10cSrcweir } 1250cdf0e10cSrcweir #if 0 1251cdf0e10cSrcweir // FIXME: implement tab order as Structure Tree 1252cdf0e10cSrcweir if( m_bHasWidgets && m_pWriter->getVersion() >= PDFWriter::PDF_1_5 ) 1253cdf0e10cSrcweir aLine.append( " /Tabs /S\n" ); 1254cdf0e10cSrcweir #endif 1255cdf0e10cSrcweir if( m_aMCIDParents.size() > 0 ) 1256cdf0e10cSrcweir { 1257cdf0e10cSrcweir OStringBuffer aStructParents( 1024 ); 1258cdf0e10cSrcweir aStructParents.append( "[ " ); 1259cdf0e10cSrcweir int nParents = m_aMCIDParents.size(); 1260cdf0e10cSrcweir for( int i = 0; i < nParents; i++ ) 1261cdf0e10cSrcweir { 1262cdf0e10cSrcweir aStructParents.append( m_aMCIDParents[i] ); 1263cdf0e10cSrcweir aStructParents.append( " 0 R" ); 1264cdf0e10cSrcweir aStructParents.append( ((i%10) == 9) ? "\n" : " " ); 1265cdf0e10cSrcweir } 1266cdf0e10cSrcweir aStructParents.append( "]" ); 1267cdf0e10cSrcweir m_pWriter->m_aStructParentTree.push_back( aStructParents.makeStringAndClear() ); 1268cdf0e10cSrcweir 1269cdf0e10cSrcweir aLine.append( "/StructParents " ); 1270cdf0e10cSrcweir aLine.append( sal_Int32(m_pWriter->m_aStructParentTree.size()-1) ); 1271cdf0e10cSrcweir aLine.append( "\n" ); 1272cdf0e10cSrcweir } 1273cdf0e10cSrcweir if( m_nDuration > 0 ) 1274cdf0e10cSrcweir { 1275cdf0e10cSrcweir aLine.append( "/Dur " ); 1276cdf0e10cSrcweir aLine.append( (sal_Int32)m_nDuration ); 1277cdf0e10cSrcweir aLine.append( "\n" ); 1278cdf0e10cSrcweir } 1279cdf0e10cSrcweir if( m_eTransition != PDFWriter::Regular && m_nTransTime > 0 ) 1280cdf0e10cSrcweir { 1281cdf0e10cSrcweir // transition duration 1282cdf0e10cSrcweir aLine.append( "/Trans<</D " ); 1283cdf0e10cSrcweir appendDouble( (double)m_nTransTime/1000.0, aLine, 3 ); 1284cdf0e10cSrcweir aLine.append( "\n" ); 1285cdf0e10cSrcweir const char *pStyle = NULL, *pDm = NULL, *pM = NULL, *pDi = NULL; 1286cdf0e10cSrcweir switch( m_eTransition ) 1287cdf0e10cSrcweir { 1288cdf0e10cSrcweir case PDFWriter::SplitHorizontalInward: 1289cdf0e10cSrcweir pStyle = "Split"; pDm = "H"; pM = "I"; break; 1290cdf0e10cSrcweir case PDFWriter::SplitHorizontalOutward: 1291cdf0e10cSrcweir pStyle = "Split"; pDm = "H"; pM = "O"; break; 1292cdf0e10cSrcweir case PDFWriter::SplitVerticalInward: 1293cdf0e10cSrcweir pStyle = "Split"; pDm = "V"; pM = "I"; break; 1294cdf0e10cSrcweir case PDFWriter::SplitVerticalOutward: 1295cdf0e10cSrcweir pStyle = "Split"; pDm = "V"; pM = "O"; break; 1296cdf0e10cSrcweir case PDFWriter::BlindsHorizontal: 1297cdf0e10cSrcweir pStyle = "Blinds"; pDm = "H"; break; 1298cdf0e10cSrcweir case PDFWriter::BlindsVertical: 1299cdf0e10cSrcweir pStyle = "Blinds"; pDm = "V"; break; 1300cdf0e10cSrcweir case PDFWriter::BoxInward: 1301cdf0e10cSrcweir pStyle = "Box"; pM = "I"; break; 1302cdf0e10cSrcweir case PDFWriter::BoxOutward: 1303cdf0e10cSrcweir pStyle = "Box"; pM = "O"; break; 1304cdf0e10cSrcweir case PDFWriter::WipeLeftToRight: 1305cdf0e10cSrcweir pStyle = "Wipe"; pDi = "0"; break; 1306cdf0e10cSrcweir case PDFWriter::WipeBottomToTop: 1307cdf0e10cSrcweir pStyle = "Wipe"; pDi = "90"; break; 1308cdf0e10cSrcweir case PDFWriter::WipeRightToLeft: 1309cdf0e10cSrcweir pStyle = "Wipe"; pDi = "180"; break; 1310cdf0e10cSrcweir case PDFWriter::WipeTopToBottom: 1311cdf0e10cSrcweir pStyle = "Wipe"; pDi = "270"; break; 1312cdf0e10cSrcweir case PDFWriter::Dissolve: 1313cdf0e10cSrcweir pStyle = "Dissolve"; break; 1314cdf0e10cSrcweir case PDFWriter::GlitterLeftToRight: 1315cdf0e10cSrcweir pStyle = "Glitter"; pDi = "0"; break; 1316cdf0e10cSrcweir case PDFWriter::GlitterTopToBottom: 1317cdf0e10cSrcweir pStyle = "Glitter"; pDi = "270"; break; 1318cdf0e10cSrcweir case PDFWriter::GlitterTopLeftToBottomRight: 1319cdf0e10cSrcweir pStyle = "Glitter"; pDi = "315"; break; 1320cdf0e10cSrcweir case PDFWriter::Regular: 1321cdf0e10cSrcweir break; 1322cdf0e10cSrcweir } 1323cdf0e10cSrcweir // transition style 1324cdf0e10cSrcweir if( pStyle ) 1325cdf0e10cSrcweir { 1326cdf0e10cSrcweir aLine.append( "/S/" ); 1327cdf0e10cSrcweir aLine.append( pStyle ); 1328cdf0e10cSrcweir aLine.append( "\n" ); 1329cdf0e10cSrcweir } 1330cdf0e10cSrcweir if( pDm ) 1331cdf0e10cSrcweir { 1332cdf0e10cSrcweir aLine.append( "/Dm/" ); 1333cdf0e10cSrcweir aLine.append( pDm ); 1334cdf0e10cSrcweir aLine.append( "\n" ); 1335cdf0e10cSrcweir } 1336cdf0e10cSrcweir if( pM ) 1337cdf0e10cSrcweir { 1338cdf0e10cSrcweir aLine.append( "/M/" ); 1339cdf0e10cSrcweir aLine.append( pM ); 1340cdf0e10cSrcweir aLine.append( "\n" ); 1341cdf0e10cSrcweir } 1342cdf0e10cSrcweir if( pDi ) 1343cdf0e10cSrcweir { 1344cdf0e10cSrcweir aLine.append( "/Di " ); 1345cdf0e10cSrcweir aLine.append( pDi ); 1346cdf0e10cSrcweir aLine.append( "\n" ); 1347cdf0e10cSrcweir } 1348cdf0e10cSrcweir aLine.append( ">>\n" ); 1349cdf0e10cSrcweir } 1350cdf0e10cSrcweir if( m_pWriter->getVersion() > PDFWriter::PDF_1_3 && ! m_pWriter->m_bIsPDF_A1 ) 1351cdf0e10cSrcweir { 1352cdf0e10cSrcweir aLine.append( "/Group<</S/Transparency/CS/DeviceRGB/I true>>" ); 1353cdf0e10cSrcweir } 1354cdf0e10cSrcweir aLine.append( "/Contents" ); 1355cdf0e10cSrcweir unsigned int nStreamObjects = m_aStreamObjects.size(); 1356cdf0e10cSrcweir if( nStreamObjects > 1 ) 1357cdf0e10cSrcweir aLine.append( '[' ); 1358cdf0e10cSrcweir for( unsigned int i = 0; i < m_aStreamObjects.size(); i++ ) 1359cdf0e10cSrcweir { 1360cdf0e10cSrcweir aLine.append( ' ' ); 1361cdf0e10cSrcweir aLine.append( m_aStreamObjects[i] ); 1362cdf0e10cSrcweir aLine.append( " 0 R" ); 1363cdf0e10cSrcweir } 1364cdf0e10cSrcweir if( nStreamObjects > 1 ) 1365cdf0e10cSrcweir aLine.append( ']' ); 1366cdf0e10cSrcweir aLine.append( ">>\nendobj\n\n" ); 1367cdf0e10cSrcweir return m_pWriter->writeBuffer( aLine.getStr(), aLine.getLength() ); 1368cdf0e10cSrcweir } 1369cdf0e10cSrcweir 1370cdf0e10cSrcweir namespace vcl 1371cdf0e10cSrcweir { 1372cdf0e10cSrcweir template < class GEOMETRY > 1373cdf0e10cSrcweir GEOMETRY lcl_convert( const MapMode& _rSource, const MapMode& _rDest, OutputDevice* _pPixelConversion, const GEOMETRY& _rObject ) 1374cdf0e10cSrcweir { 1375cdf0e10cSrcweir GEOMETRY aPoint; 1376cdf0e10cSrcweir if ( MAP_PIXEL == _rSource.GetMapUnit() ) 1377cdf0e10cSrcweir { 1378cdf0e10cSrcweir aPoint = _pPixelConversion->PixelToLogic( _rObject, _rDest ); 1379cdf0e10cSrcweir } 1380cdf0e10cSrcweir else 1381cdf0e10cSrcweir { 1382cdf0e10cSrcweir aPoint = OutputDevice::LogicToLogic( _rObject, _rSource, _rDest ); 1383cdf0e10cSrcweir } 1384cdf0e10cSrcweir return aPoint; 1385cdf0e10cSrcweir } 1386cdf0e10cSrcweir } 1387cdf0e10cSrcweir 1388cdf0e10cSrcweir void PDFWriterImpl::PDFPage::appendPoint( const Point& rPoint, OStringBuffer& rBuffer, bool bNeg, Point* pOutPoint ) const 1389cdf0e10cSrcweir { 1390cdf0e10cSrcweir if( pOutPoint ) 1391cdf0e10cSrcweir { 1392cdf0e10cSrcweir Point aPoint( lcl_convert( m_pWriter->m_aGraphicsStack.front().m_aMapMode, 1393cdf0e10cSrcweir m_pWriter->m_aMapMode, 1394cdf0e10cSrcweir m_pWriter->getReferenceDevice(), 1395cdf0e10cSrcweir rPoint ) ); 1396cdf0e10cSrcweir *pOutPoint = aPoint; 1397cdf0e10cSrcweir } 1398cdf0e10cSrcweir 1399cdf0e10cSrcweir Point aPoint( lcl_convert( m_pWriter->m_aGraphicsStack.front().m_aMapMode, 1400cdf0e10cSrcweir m_pWriter->m_aMapMode, 1401cdf0e10cSrcweir m_pWriter->getReferenceDevice(), 1402cdf0e10cSrcweir rPoint ) ); 1403cdf0e10cSrcweir 1404cdf0e10cSrcweir sal_Int32 nValue = aPoint.X(); 1405cdf0e10cSrcweir if( bNeg ) 1406cdf0e10cSrcweir nValue = -nValue; 1407cdf0e10cSrcweir 1408cdf0e10cSrcweir appendFixedInt( nValue, rBuffer ); 1409cdf0e10cSrcweir 1410cdf0e10cSrcweir rBuffer.append( ' ' ); 1411cdf0e10cSrcweir 1412cdf0e10cSrcweir nValue = pointToPixel(getHeight()) - aPoint.Y(); 1413cdf0e10cSrcweir if( bNeg ) 1414cdf0e10cSrcweir nValue = -nValue; 1415cdf0e10cSrcweir 1416cdf0e10cSrcweir appendFixedInt( nValue, rBuffer ); 1417cdf0e10cSrcweir } 1418cdf0e10cSrcweir 1419cdf0e10cSrcweir void PDFWriterImpl::PDFPage::appendPixelPoint( const basegfx::B2DPoint& rPoint, OStringBuffer& rBuffer ) const 1420cdf0e10cSrcweir { 1421cdf0e10cSrcweir double fValue = pixelToPoint(rPoint.getX()); 1422cdf0e10cSrcweir 1423cdf0e10cSrcweir appendDouble( fValue, rBuffer, nLog10Divisor ); 1424cdf0e10cSrcweir 1425cdf0e10cSrcweir rBuffer.append( ' ' ); 1426cdf0e10cSrcweir 1427cdf0e10cSrcweir fValue = double(getHeight()) - pixelToPoint(rPoint.getY()); 1428cdf0e10cSrcweir 1429cdf0e10cSrcweir appendDouble( fValue, rBuffer, nLog10Divisor ); 1430cdf0e10cSrcweir } 1431cdf0e10cSrcweir 1432cdf0e10cSrcweir void PDFWriterImpl::PDFPage::appendRect( const Rectangle& rRect, OStringBuffer& rBuffer ) const 1433cdf0e10cSrcweir { 1434cdf0e10cSrcweir appendPoint( rRect.BottomLeft() + Point( 0, 1 ), rBuffer ); 1435cdf0e10cSrcweir rBuffer.append( ' ' ); 1436cdf0e10cSrcweir appendMappedLength( (sal_Int32)rRect.GetWidth(), rBuffer, false ); 1437cdf0e10cSrcweir rBuffer.append( ' ' ); 1438cdf0e10cSrcweir appendMappedLength( (sal_Int32)rRect.GetHeight(), rBuffer, true ); 1439cdf0e10cSrcweir rBuffer.append( " re" ); 1440cdf0e10cSrcweir } 1441cdf0e10cSrcweir 1442cdf0e10cSrcweir void PDFWriterImpl::PDFPage::convertRect( Rectangle& rRect ) const 1443cdf0e10cSrcweir { 1444cdf0e10cSrcweir Point aLL = lcl_convert( m_pWriter->m_aGraphicsStack.front().m_aMapMode, 1445cdf0e10cSrcweir m_pWriter->m_aMapMode, 1446cdf0e10cSrcweir m_pWriter->getReferenceDevice(), 1447cdf0e10cSrcweir rRect.BottomLeft() + Point( 0, 1 ) 1448cdf0e10cSrcweir ); 1449cdf0e10cSrcweir Size aSize = lcl_convert( m_pWriter->m_aGraphicsStack.front().m_aMapMode, 1450cdf0e10cSrcweir m_pWriter->m_aMapMode, 1451cdf0e10cSrcweir m_pWriter->getReferenceDevice(), 1452cdf0e10cSrcweir rRect.GetSize() ); 1453cdf0e10cSrcweir rRect.Left() = aLL.X(); 1454cdf0e10cSrcweir rRect.Right() = aLL.X() + aSize.Width(); 1455cdf0e10cSrcweir rRect.Top() = pointToPixel(getHeight()) - aLL.Y(); 1456cdf0e10cSrcweir rRect.Bottom() = rRect.Top() + aSize.Height(); 1457cdf0e10cSrcweir } 1458cdf0e10cSrcweir 1459cdf0e10cSrcweir void PDFWriterImpl::PDFPage::appendPolygon( const Polygon& rPoly, OStringBuffer& rBuffer, bool bClose ) const 1460cdf0e10cSrcweir { 1461cdf0e10cSrcweir sal_uInt16 nPoints = rPoly.GetSize(); 1462cdf0e10cSrcweir /* 1463cdf0e10cSrcweir * #108582# applications do weird things 1464cdf0e10cSrcweir */ 1465cdf0e10cSrcweir sal_uInt32 nBufLen = rBuffer.getLength(); 1466cdf0e10cSrcweir if( nPoints > 0 ) 1467cdf0e10cSrcweir { 1468cdf0e10cSrcweir const sal_uInt8* pFlagArray = rPoly.GetConstFlagAry(); 1469cdf0e10cSrcweir appendPoint( rPoly[0], rBuffer ); 1470cdf0e10cSrcweir rBuffer.append( " m\n" ); 1471cdf0e10cSrcweir for( sal_uInt16 i = 1; i < nPoints; i++ ) 1472cdf0e10cSrcweir { 1473cdf0e10cSrcweir if( pFlagArray && pFlagArray[i] == POLY_CONTROL && nPoints-i > 2 ) 1474cdf0e10cSrcweir { 1475cdf0e10cSrcweir // bezier 1476cdf0e10cSrcweir DBG_ASSERT( pFlagArray[i+1] == POLY_CONTROL && pFlagArray[i+2] != POLY_CONTROL, "unexpected sequence of control points" ); 1477cdf0e10cSrcweir appendPoint( rPoly[i], rBuffer ); 1478cdf0e10cSrcweir rBuffer.append( " " ); 1479cdf0e10cSrcweir appendPoint( rPoly[i+1], rBuffer ); 1480cdf0e10cSrcweir rBuffer.append( " " ); 1481cdf0e10cSrcweir appendPoint( rPoly[i+2], rBuffer ); 1482cdf0e10cSrcweir rBuffer.append( " c" ); 1483cdf0e10cSrcweir i += 2; // add additionally consumed points 1484cdf0e10cSrcweir } 1485cdf0e10cSrcweir else 1486cdf0e10cSrcweir { 1487cdf0e10cSrcweir // line 1488cdf0e10cSrcweir appendPoint( rPoly[i], rBuffer ); 1489cdf0e10cSrcweir rBuffer.append( " l" ); 1490cdf0e10cSrcweir } 1491cdf0e10cSrcweir if( (rBuffer.getLength() - nBufLen) > 65 ) 1492cdf0e10cSrcweir { 1493cdf0e10cSrcweir rBuffer.append( "\n" ); 1494cdf0e10cSrcweir nBufLen = rBuffer.getLength(); 1495cdf0e10cSrcweir } 1496cdf0e10cSrcweir else 1497cdf0e10cSrcweir rBuffer.append( " " ); 1498cdf0e10cSrcweir } 1499cdf0e10cSrcweir if( bClose ) 1500cdf0e10cSrcweir rBuffer.append( "h\n" ); 1501cdf0e10cSrcweir } 1502cdf0e10cSrcweir } 1503cdf0e10cSrcweir 1504cdf0e10cSrcweir void PDFWriterImpl::PDFPage::appendPolygon( const basegfx::B2DPolygon& rPoly, OStringBuffer& rBuffer, bool bClose ) const 1505cdf0e10cSrcweir { 1506cdf0e10cSrcweir basegfx::B2DPolygon aPoly( lcl_convert( m_pWriter->m_aGraphicsStack.front().m_aMapMode, 1507cdf0e10cSrcweir m_pWriter->m_aMapMode, 1508cdf0e10cSrcweir m_pWriter->getReferenceDevice(), 1509cdf0e10cSrcweir rPoly ) ); 1510cdf0e10cSrcweir 1511cdf0e10cSrcweir if( basegfx::tools::isRectangle( aPoly ) ) 1512cdf0e10cSrcweir { 1513cdf0e10cSrcweir basegfx::B2DRange aRange( aPoly.getB2DRange() ); 1514cdf0e10cSrcweir basegfx::B2DPoint aBL( aRange.getMinX(), aRange.getMaxY() ); 1515cdf0e10cSrcweir appendPixelPoint( aBL, rBuffer ); 1516cdf0e10cSrcweir rBuffer.append( ' ' ); 1517cdf0e10cSrcweir appendMappedLength( aRange.getWidth(), rBuffer, false, NULL, nLog10Divisor ); 1518cdf0e10cSrcweir rBuffer.append( ' ' ); 1519cdf0e10cSrcweir appendMappedLength( aRange.getHeight(), rBuffer, true, NULL, nLog10Divisor ); 1520cdf0e10cSrcweir rBuffer.append( " re\n" ); 1521cdf0e10cSrcweir return; 1522cdf0e10cSrcweir } 1523cdf0e10cSrcweir sal_uInt32 nPoints = aPoly.count(); 1524cdf0e10cSrcweir if( nPoints > 0 ) 1525cdf0e10cSrcweir { 1526cdf0e10cSrcweir sal_uInt32 nBufLen = rBuffer.getLength(); 1527cdf0e10cSrcweir basegfx::B2DPoint aLastPoint( aPoly.getB2DPoint( 0 ) ); 1528cdf0e10cSrcweir appendPixelPoint( aLastPoint, rBuffer ); 1529cdf0e10cSrcweir rBuffer.append( " m\n" ); 1530cdf0e10cSrcweir for( sal_uInt32 i = 1; i <= nPoints; i++ ) 1531cdf0e10cSrcweir { 1532cdf0e10cSrcweir if( i != nPoints || aPoly.isClosed() ) 1533cdf0e10cSrcweir { 1534cdf0e10cSrcweir sal_uInt32 nCurPoint = i % nPoints; 1535cdf0e10cSrcweir sal_uInt32 nLastPoint = i-1; 1536cdf0e10cSrcweir basegfx::B2DPoint aPoint( aPoly.getB2DPoint( nCurPoint ) ); 1537cdf0e10cSrcweir if( aPoly.isNextControlPointUsed( nLastPoint ) && 1538cdf0e10cSrcweir aPoly.isPrevControlPointUsed( nCurPoint ) ) 1539cdf0e10cSrcweir { 1540cdf0e10cSrcweir appendPixelPoint( aPoly.getNextControlPoint( nLastPoint ), rBuffer ); 1541cdf0e10cSrcweir rBuffer.append( ' ' ); 1542cdf0e10cSrcweir appendPixelPoint( aPoly.getPrevControlPoint( nCurPoint ), rBuffer ); 1543cdf0e10cSrcweir rBuffer.append( ' ' ); 1544cdf0e10cSrcweir appendPixelPoint( aPoint, rBuffer ); 1545cdf0e10cSrcweir rBuffer.append( " c" ); 1546cdf0e10cSrcweir } 1547cdf0e10cSrcweir else if( aPoly.isNextControlPointUsed( nLastPoint ) ) 1548cdf0e10cSrcweir { 1549cdf0e10cSrcweir appendPixelPoint( aPoly.getNextControlPoint( nLastPoint ), rBuffer ); 1550cdf0e10cSrcweir rBuffer.append( ' ' ); 1551cdf0e10cSrcweir appendPixelPoint( aPoint, rBuffer ); 1552cdf0e10cSrcweir rBuffer.append( " y" ); 1553cdf0e10cSrcweir } 1554cdf0e10cSrcweir else if( aPoly.isPrevControlPointUsed( nCurPoint ) ) 1555cdf0e10cSrcweir { 1556cdf0e10cSrcweir appendPixelPoint( aPoly.getPrevControlPoint( nCurPoint ), rBuffer ); 1557cdf0e10cSrcweir rBuffer.append( ' ' ); 1558cdf0e10cSrcweir appendPixelPoint( aPoint, rBuffer ); 1559cdf0e10cSrcweir rBuffer.append( " v" ); 1560cdf0e10cSrcweir } 1561cdf0e10cSrcweir else 1562cdf0e10cSrcweir { 1563cdf0e10cSrcweir appendPixelPoint( aPoint, rBuffer ); 1564cdf0e10cSrcweir rBuffer.append( " l" ); 1565cdf0e10cSrcweir } 1566cdf0e10cSrcweir if( (rBuffer.getLength() - nBufLen) > 65 ) 1567cdf0e10cSrcweir { 1568cdf0e10cSrcweir rBuffer.append( "\n" ); 1569cdf0e10cSrcweir nBufLen = rBuffer.getLength(); 1570cdf0e10cSrcweir } 1571cdf0e10cSrcweir else 1572cdf0e10cSrcweir rBuffer.append( " " ); 1573cdf0e10cSrcweir } 1574cdf0e10cSrcweir } 1575cdf0e10cSrcweir if( bClose ) 1576cdf0e10cSrcweir rBuffer.append( "h\n" ); 1577cdf0e10cSrcweir } 1578cdf0e10cSrcweir } 1579cdf0e10cSrcweir 1580cdf0e10cSrcweir void PDFWriterImpl::PDFPage::appendPolyPolygon( const PolyPolygon& rPolyPoly, OStringBuffer& rBuffer, bool bClose ) const 1581cdf0e10cSrcweir { 1582cdf0e10cSrcweir sal_uInt16 nPolygons = rPolyPoly.Count(); 1583cdf0e10cSrcweir for( sal_uInt16 n = 0; n < nPolygons; n++ ) 1584cdf0e10cSrcweir appendPolygon( rPolyPoly[n], rBuffer, bClose ); 1585cdf0e10cSrcweir } 1586cdf0e10cSrcweir 1587cdf0e10cSrcweir void PDFWriterImpl::PDFPage::appendPolyPolygon( const basegfx::B2DPolyPolygon& rPolyPoly, OStringBuffer& rBuffer, bool bClose ) const 1588cdf0e10cSrcweir { 1589cdf0e10cSrcweir sal_uInt32 nPolygons = rPolyPoly.count(); 1590cdf0e10cSrcweir for( sal_uInt32 n = 0; n < nPolygons; n++ ) 1591cdf0e10cSrcweir appendPolygon( rPolyPoly.getB2DPolygon( n ), rBuffer, bClose ); 1592cdf0e10cSrcweir } 1593cdf0e10cSrcweir 1594cdf0e10cSrcweir void PDFWriterImpl::PDFPage::appendMappedLength( sal_Int32 nLength, OStringBuffer& rBuffer, bool bVertical, sal_Int32* pOutLength ) const 1595cdf0e10cSrcweir { 1596cdf0e10cSrcweir sal_Int32 nValue = nLength; 1597cdf0e10cSrcweir if ( nLength < 0 ) 1598cdf0e10cSrcweir { 1599cdf0e10cSrcweir rBuffer.append( '-' ); 1600cdf0e10cSrcweir nValue = -nLength; 1601cdf0e10cSrcweir } 1602cdf0e10cSrcweir Size aSize( lcl_convert( m_pWriter->m_aGraphicsStack.front().m_aMapMode, 1603cdf0e10cSrcweir m_pWriter->m_aMapMode, 1604cdf0e10cSrcweir m_pWriter->getReferenceDevice(), 1605cdf0e10cSrcweir Size( nValue, nValue ) ) ); 1606cdf0e10cSrcweir nValue = bVertical ? aSize.Height() : aSize.Width(); 1607cdf0e10cSrcweir if( pOutLength ) 1608cdf0e10cSrcweir *pOutLength = ((nLength < 0 ) ? -nValue : nValue); 1609cdf0e10cSrcweir 1610cdf0e10cSrcweir appendFixedInt( nValue, rBuffer, 1 ); 1611cdf0e10cSrcweir } 1612cdf0e10cSrcweir 1613cdf0e10cSrcweir void PDFWriterImpl::PDFPage::appendMappedLength( double fLength, OStringBuffer& rBuffer, bool bVertical, sal_Int32* pOutLength, sal_Int32 nPrecision ) const 1614cdf0e10cSrcweir { 1615cdf0e10cSrcweir Size aSize( lcl_convert( m_pWriter->m_aGraphicsStack.front().m_aMapMode, 1616cdf0e10cSrcweir m_pWriter->m_aMapMode, 1617cdf0e10cSrcweir m_pWriter->getReferenceDevice(), 1618cdf0e10cSrcweir Size( 1000, 1000 ) ) ); 1619cdf0e10cSrcweir if( pOutLength ) 1620cdf0e10cSrcweir *pOutLength = (sal_Int32)(fLength*(double)(bVertical ? aSize.Height() : aSize.Width())/1000.0); 1621cdf0e10cSrcweir fLength *= pixelToPoint((double)(bVertical ? aSize.Height() : aSize.Width()) / 1000.0); 1622cdf0e10cSrcweir appendDouble( fLength, rBuffer, nPrecision ); 1623cdf0e10cSrcweir } 1624cdf0e10cSrcweir 1625cdf0e10cSrcweir bool PDFWriterImpl::PDFPage::appendLineInfo( const LineInfo& rInfo, OStringBuffer& rBuffer ) const 1626cdf0e10cSrcweir { 16275aaf853bSArmin Le Grand if(LINE_DASH == rInfo.GetStyle() && rInfo.GetDashLen() != rInfo.GetDotLen()) 16285aaf853bSArmin Le Grand { 16295aaf853bSArmin Le Grand // dashed and non-degraded case, check for implementation limits of dash array 16305aaf853bSArmin Le Grand // in PDF reader apps (e.g. acroread) 16315aaf853bSArmin Le Grand if(2 * (rInfo.GetDashCount() + rInfo.GetDotCount()) > 10) 16325aaf853bSArmin Le Grand { 16335aaf853bSArmin Le Grand return false; 16345aaf853bSArmin Le Grand } 16355aaf853bSArmin Le Grand } 16365aaf853bSArmin Le Grand 16375aaf853bSArmin Le Grand if(basegfx::B2DLINEJOIN_NONE != rInfo.GetLineJoin()) 16385aaf853bSArmin Le Grand { 16395aaf853bSArmin Le Grand // LineJoin used, ExtLineInfo required 16405aaf853bSArmin Le Grand return false; 16415aaf853bSArmin Le Grand } 16425aaf853bSArmin Le Grand 16435aaf853bSArmin Le Grand if(com::sun::star::drawing::LineCap_BUTT != rInfo.GetLineCap()) 16445aaf853bSArmin Le Grand { 16455aaf853bSArmin Le Grand // LineCap used, ExtLineInfo required 16465aaf853bSArmin Le Grand return false; 16475aaf853bSArmin Le Grand } 16485aaf853bSArmin Le Grand 1649cdf0e10cSrcweir if( rInfo.GetStyle() == LINE_DASH ) 1650cdf0e10cSrcweir { 1651cdf0e10cSrcweir rBuffer.append( "[ " ); 1652cdf0e10cSrcweir if( rInfo.GetDashLen() == rInfo.GetDotLen() ) // degraded case 1653cdf0e10cSrcweir { 1654cdf0e10cSrcweir appendMappedLength( (sal_Int32)rInfo.GetDashLen(), rBuffer ); 1655cdf0e10cSrcweir rBuffer.append( ' ' ); 1656cdf0e10cSrcweir appendMappedLength( (sal_Int32)rInfo.GetDistance(), rBuffer ); 1657cdf0e10cSrcweir rBuffer.append( ' ' ); 1658cdf0e10cSrcweir } 1659cdf0e10cSrcweir else 1660cdf0e10cSrcweir { 1661cdf0e10cSrcweir for( int n = 0; n < rInfo.GetDashCount(); n++ ) 1662cdf0e10cSrcweir { 1663cdf0e10cSrcweir appendMappedLength( (sal_Int32)rInfo.GetDashLen(), rBuffer ); 1664cdf0e10cSrcweir rBuffer.append( ' ' ); 1665cdf0e10cSrcweir appendMappedLength( (sal_Int32)rInfo.GetDistance(), rBuffer ); 1666cdf0e10cSrcweir rBuffer.append( ' ' ); 1667cdf0e10cSrcweir } 1668cdf0e10cSrcweir for( int m = 0; m < rInfo.GetDotCount(); m++ ) 1669cdf0e10cSrcweir { 1670cdf0e10cSrcweir appendMappedLength( (sal_Int32)rInfo.GetDotLen(), rBuffer ); 1671cdf0e10cSrcweir rBuffer.append( ' ' ); 1672cdf0e10cSrcweir appendMappedLength( (sal_Int32)rInfo.GetDistance(), rBuffer ); 1673cdf0e10cSrcweir rBuffer.append( ' ' ); 1674cdf0e10cSrcweir } 1675cdf0e10cSrcweir } 1676cdf0e10cSrcweir rBuffer.append( "] 0 d\n" ); 1677cdf0e10cSrcweir } 16785aaf853bSArmin Le Grand 1679cdf0e10cSrcweir if( rInfo.GetWidth() > 1 ) 1680cdf0e10cSrcweir { 1681cdf0e10cSrcweir appendMappedLength( (sal_Int32)rInfo.GetWidth(), rBuffer ); 1682cdf0e10cSrcweir rBuffer.append( " w\n" ); 1683cdf0e10cSrcweir } 1684cdf0e10cSrcweir else if( rInfo.GetWidth() == 0 ) 1685cdf0e10cSrcweir { 1686cdf0e10cSrcweir // "pixel" line 1687cdf0e10cSrcweir appendDouble( 72.0/double(m_pWriter->getReferenceDevice()->ImplGetDPIX()), rBuffer ); 1688cdf0e10cSrcweir rBuffer.append( " w\n" ); 1689cdf0e10cSrcweir } 16905aaf853bSArmin Le Grand 16915aaf853bSArmin Le Grand return true; 1692cdf0e10cSrcweir } 1693cdf0e10cSrcweir 1694cdf0e10cSrcweir void PDFWriterImpl::PDFPage::appendWaveLine( sal_Int32 nWidth, sal_Int32 nY, sal_Int32 nDelta, OStringBuffer& rBuffer ) const 1695cdf0e10cSrcweir { 1696cdf0e10cSrcweir if( nWidth <= 0 ) 1697cdf0e10cSrcweir return; 1698cdf0e10cSrcweir if( nDelta < 1 ) 1699cdf0e10cSrcweir nDelta = 1; 1700cdf0e10cSrcweir 1701cdf0e10cSrcweir rBuffer.append( "0 " ); 1702cdf0e10cSrcweir appendMappedLength( nY, rBuffer, true ); 1703cdf0e10cSrcweir rBuffer.append( " m\n" ); 1704cdf0e10cSrcweir for( sal_Int32 n = 0; n < nWidth; ) 1705cdf0e10cSrcweir { 1706cdf0e10cSrcweir n += nDelta; 1707cdf0e10cSrcweir appendMappedLength( n, rBuffer, false ); 1708cdf0e10cSrcweir rBuffer.append( ' ' ); 1709cdf0e10cSrcweir appendMappedLength( nDelta+nY, rBuffer, true ); 1710cdf0e10cSrcweir rBuffer.append( ' ' ); 1711cdf0e10cSrcweir n += nDelta; 1712cdf0e10cSrcweir appendMappedLength( n, rBuffer, false ); 1713cdf0e10cSrcweir rBuffer.append( ' ' ); 1714cdf0e10cSrcweir appendMappedLength( nY, rBuffer, true ); 1715cdf0e10cSrcweir rBuffer.append( " v " ); 1716cdf0e10cSrcweir if( n < nWidth ) 1717cdf0e10cSrcweir { 1718cdf0e10cSrcweir n += nDelta; 1719cdf0e10cSrcweir appendMappedLength( n, rBuffer, false ); 1720cdf0e10cSrcweir rBuffer.append( ' ' ); 1721cdf0e10cSrcweir appendMappedLength( nY-nDelta, rBuffer, true ); 1722cdf0e10cSrcweir rBuffer.append( ' ' ); 1723cdf0e10cSrcweir n += nDelta; 1724cdf0e10cSrcweir appendMappedLength( n, rBuffer, false ); 1725cdf0e10cSrcweir rBuffer.append( ' ' ); 1726cdf0e10cSrcweir appendMappedLength( nY, rBuffer, true ); 1727cdf0e10cSrcweir rBuffer.append( " v\n" ); 1728cdf0e10cSrcweir } 1729cdf0e10cSrcweir } 1730cdf0e10cSrcweir rBuffer.append( "S\n" ); 1731cdf0e10cSrcweir } 1732cdf0e10cSrcweir 1733cdf0e10cSrcweir /* 1734cdf0e10cSrcweir * class PDFWriterImpl 1735cdf0e10cSrcweir */ 1736cdf0e10cSrcweir 1737cdf0e10cSrcweir PDFWriterImpl::PDFWriterImpl( const PDFWriter::PDFWriterContext& rContext, 1738cdf0e10cSrcweir const com::sun::star::uno::Reference< com::sun::star::beans::XMaterialHolder >& xEnc, 1739cdf0e10cSrcweir PDFWriter& i_rOuterFace) 1740cdf0e10cSrcweir : 1741cdf0e10cSrcweir m_pReferenceDevice( NULL ), 1742cdf0e10cSrcweir m_aMapMode( MAP_POINT, Point(), Fraction( 1L, pointToPixel(1) ), Fraction( 1L, pointToPixel(1) ) ), 1743cdf0e10cSrcweir m_nCurrentStructElement( 0 ), 1744cdf0e10cSrcweir m_bEmitStructure( true ), 1745cdf0e10cSrcweir m_bNewMCID( false ), 1746cdf0e10cSrcweir m_nCurrentControl( -1 ), 1747cdf0e10cSrcweir m_bEmbedStandardFonts( false ), 1748cdf0e10cSrcweir m_nNextFID( 1 ), 1749cdf0e10cSrcweir m_nInheritedPageWidth( 595 ), // default A4 1750cdf0e10cSrcweir m_nInheritedPageHeight( 842 ), // default A4 1751cdf0e10cSrcweir m_eInheritedOrientation( PDFWriter::Portrait ), 1752cdf0e10cSrcweir m_nCurrentPage( -1 ), 1753cdf0e10cSrcweir m_nResourceDict( -1 ), 1754cdf0e10cSrcweir m_nFontDictObject( -1 ), 1755cdf0e10cSrcweir m_pCodec( NULL ), 1756cdf0e10cSrcweir m_aDocDigest( rtl_digest_createMD5() ), 1757cdf0e10cSrcweir m_aCipher( (rtlCipher)NULL ), 1758cdf0e10cSrcweir m_aDigest( NULL ), 1759cdf0e10cSrcweir m_bEncryptThisStream( false ), 1760cdf0e10cSrcweir m_pEncryptionBuffer( NULL ), 1761cdf0e10cSrcweir m_nEncryptionBufferSize( 0 ), 1762cdf0e10cSrcweir m_bIsPDF_A1( false ), 1763cdf0e10cSrcweir m_rOuterFace( i_rOuterFace ) 1764cdf0e10cSrcweir { 1765cdf0e10cSrcweir #ifdef DO_TEST_PDF 1766cdf0e10cSrcweir static bool bOnce = true; 1767cdf0e10cSrcweir if( bOnce ) 1768cdf0e10cSrcweir { 1769cdf0e10cSrcweir bOnce = false; 1770cdf0e10cSrcweir doTestCode(); 1771cdf0e10cSrcweir } 1772cdf0e10cSrcweir #endif 1773cdf0e10cSrcweir m_aContext = rContext; 1774cdf0e10cSrcweir m_aStructure.push_back( PDFStructureElement() ); 1775cdf0e10cSrcweir m_aStructure[0].m_nOwnElement = 0; 1776cdf0e10cSrcweir m_aStructure[0].m_nParentElement = 0; 1777cdf0e10cSrcweir 1778cdf0e10cSrcweir Font aFont; 1779cdf0e10cSrcweir aFont.SetName( String( RTL_CONSTASCII_USTRINGPARAM( "Times" ) ) ); 1780cdf0e10cSrcweir aFont.SetSize( Size( 0, 12 ) ); 1781cdf0e10cSrcweir 1782cdf0e10cSrcweir GraphicsState aState; 1783cdf0e10cSrcweir aState.m_aMapMode = m_aMapMode; 1784cdf0e10cSrcweir aState.m_aFont = aFont; 1785cdf0e10cSrcweir m_aGraphicsStack.push_front( aState ); 1786cdf0e10cSrcweir 1787cdf0e10cSrcweir oslFileError aError = osl_openFile( m_aContext.URL.pData, &m_aFile, osl_File_OpenFlag_Write | osl_File_OpenFlag_Create ); 1788cdf0e10cSrcweir if( aError != osl_File_E_None ) 1789cdf0e10cSrcweir { 1790cdf0e10cSrcweir if( aError == osl_File_E_EXIST ) 1791cdf0e10cSrcweir { 1792cdf0e10cSrcweir aError = osl_openFile( m_aContext.URL.pData, &m_aFile, osl_File_OpenFlag_Write ); 1793cdf0e10cSrcweir if( aError == osl_File_E_None ) 1794cdf0e10cSrcweir aError = osl_setFileSize( m_aFile, 0 ); 1795cdf0e10cSrcweir } 1796cdf0e10cSrcweir } 1797cdf0e10cSrcweir if( aError != osl_File_E_None ) 1798cdf0e10cSrcweir return; 1799cdf0e10cSrcweir 1800cdf0e10cSrcweir m_bOpen = true; 1801cdf0e10cSrcweir 1802cdf0e10cSrcweir // setup DocInfo 1803cdf0e10cSrcweir setupDocInfo(); 1804cdf0e10cSrcweir 1805cdf0e10cSrcweir /* prepare the cypher engine, can be done in CTOR, free in DTOR */ 1806cdf0e10cSrcweir m_aCipher = rtl_cipher_createARCFOUR( rtl_Cipher_ModeStream ); 1807cdf0e10cSrcweir m_aDigest = rtl_digest_createMD5(); 1808cdf0e10cSrcweir 1809cdf0e10cSrcweir /* the size of the Codec default maximum */ 1810cdf0e10cSrcweir checkEncryptionBufferSize( 0x4000 ); 1811cdf0e10cSrcweir 1812cdf0e10cSrcweir if( xEnc.is() ) 1813cdf0e10cSrcweir prepareEncryption( xEnc ); 1814cdf0e10cSrcweir 1815cdf0e10cSrcweir if( m_aContext.Encryption.Encrypt() ) 1816cdf0e10cSrcweir { 1817cdf0e10cSrcweir // sanity check 1818cdf0e10cSrcweir if( m_aContext.Encryption.OValue.size() != ENCRYPTED_PWD_SIZE || 1819cdf0e10cSrcweir m_aContext.Encryption.UValue.size() != ENCRYPTED_PWD_SIZE || 1820cdf0e10cSrcweir m_aContext.Encryption.EncryptionKey.size() != MAXIMUM_RC4_KEY_LENGTH 1821cdf0e10cSrcweir ) 1822cdf0e10cSrcweir { 1823cdf0e10cSrcweir // the field lengths are invalid ? This was not setup by initEncryption. 1824cdf0e10cSrcweir // do not encrypt after all 1825cdf0e10cSrcweir m_aContext.Encryption.OValue.clear(); 1826cdf0e10cSrcweir m_aContext.Encryption.UValue.clear(); 1827cdf0e10cSrcweir OSL_ENSURE( 0, "encryption data failed sanity check, encryption disabled" ); 1828cdf0e10cSrcweir } 1829cdf0e10cSrcweir else // setup key lengths 1830cdf0e10cSrcweir m_nAccessPermissions = computeAccessPermissions( m_aContext.Encryption, m_nKeyLength, m_nRC4KeyLength ); 1831cdf0e10cSrcweir } 1832cdf0e10cSrcweir 1833cdf0e10cSrcweir // write header 1834cdf0e10cSrcweir OStringBuffer aBuffer( 20 ); 1835cdf0e10cSrcweir aBuffer.append( "%PDF-" ); 1836cdf0e10cSrcweir switch( m_aContext.Version ) 1837cdf0e10cSrcweir { 1838cdf0e10cSrcweir case PDFWriter::PDF_1_2: aBuffer.append( "1.2" );break; 1839cdf0e10cSrcweir case PDFWriter::PDF_1_3: aBuffer.append( "1.3" );break; 1840cdf0e10cSrcweir case PDFWriter::PDF_A_1: 1841cdf0e10cSrcweir default: 1842cdf0e10cSrcweir case PDFWriter::PDF_1_4: aBuffer.append( "1.4" );break; 1843cdf0e10cSrcweir case PDFWriter::PDF_1_5: aBuffer.append( "1.5" );break; 1844cdf0e10cSrcweir } 1845cdf0e10cSrcweir // append something binary as comment (suggested in PDF Reference) 1846cdf0e10cSrcweir aBuffer.append( "\n%äüöß\n" ); 1847cdf0e10cSrcweir if( !writeBuffer( aBuffer.getStr(), aBuffer.getLength() ) ) 1848cdf0e10cSrcweir { 1849cdf0e10cSrcweir osl_closeFile( m_aFile ); 1850cdf0e10cSrcweir m_bOpen = false; 1851cdf0e10cSrcweir return; 1852cdf0e10cSrcweir } 1853cdf0e10cSrcweir 1854cdf0e10cSrcweir // insert outline root 1855cdf0e10cSrcweir m_aOutline.push_back( PDFOutlineEntry() ); 1856cdf0e10cSrcweir 1857cdf0e10cSrcweir m_bIsPDF_A1 = (m_aContext.Version == PDFWriter::PDF_A_1); 1858cdf0e10cSrcweir if( m_bIsPDF_A1 ) 1859cdf0e10cSrcweir m_aContext.Version = PDFWriter::PDF_1_4; //meaning we need PDF 1.4, PDF/A flavour 1860cdf0e10cSrcweir 1861cdf0e10cSrcweir m_bEmbedStandardFonts = m_aContext.EmbedStandardFonts; 1862cdf0e10cSrcweir } 1863cdf0e10cSrcweir 1864cdf0e10cSrcweir PDFWriterImpl::~PDFWriterImpl() 1865cdf0e10cSrcweir { 1866cdf0e10cSrcweir if( m_aDocDigest ) 1867cdf0e10cSrcweir rtl_digest_destroyMD5( m_aDocDigest ); 1868cdf0e10cSrcweir delete static_cast<VirtualDevice*>(m_pReferenceDevice); 1869cdf0e10cSrcweir 1870cdf0e10cSrcweir if( m_aCipher ) 1871cdf0e10cSrcweir rtl_cipher_destroyARCFOUR( m_aCipher ); 1872cdf0e10cSrcweir if( m_aDigest ) 1873cdf0e10cSrcweir rtl_digest_destroyMD5( m_aDigest ); 1874cdf0e10cSrcweir 1875cdf0e10cSrcweir rtl_freeMemory( m_pEncryptionBuffer ); 1876cdf0e10cSrcweir } 1877cdf0e10cSrcweir 1878cdf0e10cSrcweir void PDFWriterImpl::setupDocInfo() 1879cdf0e10cSrcweir { 1880cdf0e10cSrcweir std::vector< sal_uInt8 > aId; 1881cdf0e10cSrcweir computeDocumentIdentifier( aId, m_aContext.DocumentInfo, m_aCreationDateString, m_aCreationMetaDateString ); 1882cdf0e10cSrcweir if( m_aContext.Encryption.DocumentIdentifier.empty() ) 1883cdf0e10cSrcweir m_aContext.Encryption.DocumentIdentifier = aId; 1884cdf0e10cSrcweir } 1885cdf0e10cSrcweir 1886cdf0e10cSrcweir void PDFWriterImpl::computeDocumentIdentifier( std::vector< sal_uInt8 >& o_rIdentifier, 1887cdf0e10cSrcweir const vcl::PDFWriter::PDFDocInfo& i_rDocInfo, 1888cdf0e10cSrcweir rtl::OString& o_rCString1, 1889cdf0e10cSrcweir rtl::OString& o_rCString2 1890cdf0e10cSrcweir ) 1891cdf0e10cSrcweir { 1892cdf0e10cSrcweir o_rIdentifier.clear(); 1893cdf0e10cSrcweir 1894cdf0e10cSrcweir //build the document id 1895cdf0e10cSrcweir rtl::OString aInfoValuesOut; 1896cdf0e10cSrcweir OStringBuffer aID( 1024 ); 1897cdf0e10cSrcweir if( i_rDocInfo.Title.Len() ) 1898cdf0e10cSrcweir appendUnicodeTextString( i_rDocInfo.Title, aID ); 1899cdf0e10cSrcweir if( i_rDocInfo.Author.Len() ) 1900cdf0e10cSrcweir appendUnicodeTextString( i_rDocInfo.Author, aID ); 1901cdf0e10cSrcweir if( i_rDocInfo.Subject.Len() ) 1902cdf0e10cSrcweir appendUnicodeTextString( i_rDocInfo.Subject, aID ); 1903cdf0e10cSrcweir if( i_rDocInfo.Keywords.Len() ) 1904cdf0e10cSrcweir appendUnicodeTextString( i_rDocInfo.Keywords, aID ); 1905cdf0e10cSrcweir if( i_rDocInfo.Creator.Len() ) 1906cdf0e10cSrcweir appendUnicodeTextString( i_rDocInfo.Creator, aID ); 1907cdf0e10cSrcweir if( i_rDocInfo.Producer.Len() ) 1908cdf0e10cSrcweir appendUnicodeTextString( i_rDocInfo.Producer, aID ); 1909cdf0e10cSrcweir 1910cdf0e10cSrcweir TimeValue aTVal, aGMT; 1911cdf0e10cSrcweir oslDateTime aDT; 1912cdf0e10cSrcweir osl_getSystemTime( &aGMT ); 1913cdf0e10cSrcweir osl_getLocalTimeFromSystemTime( &aGMT, &aTVal ); 1914cdf0e10cSrcweir osl_getDateTimeFromTimeValue( &aTVal, &aDT ); 1915cdf0e10cSrcweir rtl::OStringBuffer aCreationDateString(64), aCreationMetaDateString(64); 1916cdf0e10cSrcweir aCreationDateString.append( "D:" ); 1917cdf0e10cSrcweir aCreationDateString.append( (sal_Char)('0' + ((aDT.Year/1000)%10)) ); 1918cdf0e10cSrcweir aCreationDateString.append( (sal_Char)('0' + ((aDT.Year/100)%10)) ); 1919cdf0e10cSrcweir aCreationDateString.append( (sal_Char)('0' + ((aDT.Year/10)%10)) ); 1920cdf0e10cSrcweir aCreationDateString.append( (sal_Char)('0' + ((aDT.Year)%10)) ); 1921cdf0e10cSrcweir aCreationDateString.append( (sal_Char)('0' + ((aDT.Month/10)%10)) ); 1922cdf0e10cSrcweir aCreationDateString.append( (sal_Char)('0' + ((aDT.Month)%10)) ); 1923cdf0e10cSrcweir aCreationDateString.append( (sal_Char)('0' + ((aDT.Day/10)%10)) ); 1924cdf0e10cSrcweir aCreationDateString.append( (sal_Char)('0' + ((aDT.Day)%10)) ); 1925cdf0e10cSrcweir aCreationDateString.append( (sal_Char)('0' + ((aDT.Hours/10)%10)) ); 1926cdf0e10cSrcweir aCreationDateString.append( (sal_Char)('0' + ((aDT.Hours)%10)) ); 1927cdf0e10cSrcweir aCreationDateString.append( (sal_Char)('0' + ((aDT.Minutes/10)%10)) ); 1928cdf0e10cSrcweir aCreationDateString.append( (sal_Char)('0' + ((aDT.Minutes)%10)) ); 1929cdf0e10cSrcweir aCreationDateString.append( (sal_Char)('0' + ((aDT.Seconds/10)%10)) ); 1930cdf0e10cSrcweir aCreationDateString.append( (sal_Char)('0' + ((aDT.Seconds)%10)) ); 1931cdf0e10cSrcweir 1932cdf0e10cSrcweir //--> i59651, we fill the Metadata date string as well, if PDF/A is requested 1933cdf0e10cSrcweir // according to ISO 19005-1:2005 6.7.3 the date is corrected for 1934cdf0e10cSrcweir // local time zone offset UTC only, whereas Acrobat 8 seems 1935cdf0e10cSrcweir // to use the localtime notation only 1936cdf0e10cSrcweir // according to a raccomandation in XMP Specification (Jan 2004, page 75) 1937cdf0e10cSrcweir // the Acrobat way seems the right approach 1938cdf0e10cSrcweir aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Year/1000)%10)) ); 1939cdf0e10cSrcweir aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Year/100)%10)) ); 1940cdf0e10cSrcweir aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Year/10)%10)) ); 1941cdf0e10cSrcweir aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Year)%10)) ); 1942cdf0e10cSrcweir aCreationMetaDateString.append( "-" ); 1943cdf0e10cSrcweir aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Month/10)%10)) ); 1944cdf0e10cSrcweir aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Month)%10)) ); 1945cdf0e10cSrcweir aCreationMetaDateString.append( "-" ); 1946cdf0e10cSrcweir aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Day/10)%10)) ); 1947cdf0e10cSrcweir aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Day)%10)) ); 1948cdf0e10cSrcweir aCreationMetaDateString.append( "T" ); 1949cdf0e10cSrcweir aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Hours/10)%10)) ); 1950cdf0e10cSrcweir aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Hours)%10)) ); 1951cdf0e10cSrcweir aCreationMetaDateString.append( ":" ); 1952cdf0e10cSrcweir aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Minutes/10)%10)) ); 1953cdf0e10cSrcweir aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Minutes)%10)) ); 1954cdf0e10cSrcweir aCreationMetaDateString.append( ":" ); 1955cdf0e10cSrcweir aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Seconds/10)%10)) ); 1956cdf0e10cSrcweir aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Seconds)%10)) ); 1957cdf0e10cSrcweir 1958cdf0e10cSrcweir sal_uInt32 nDelta = 0; 1959cdf0e10cSrcweir if( aGMT.Seconds > aTVal.Seconds ) 1960cdf0e10cSrcweir { 1961cdf0e10cSrcweir aCreationDateString.append( "-" ); 1962cdf0e10cSrcweir nDelta = aGMT.Seconds-aTVal.Seconds; 1963cdf0e10cSrcweir aCreationMetaDateString.append( "-" ); 1964cdf0e10cSrcweir } 1965cdf0e10cSrcweir else if( aGMT.Seconds < aTVal.Seconds ) 1966cdf0e10cSrcweir { 1967cdf0e10cSrcweir aCreationDateString.append( "+" ); 1968cdf0e10cSrcweir nDelta = aTVal.Seconds-aGMT.Seconds; 1969cdf0e10cSrcweir aCreationMetaDateString.append( "+" ); 1970cdf0e10cSrcweir } 1971cdf0e10cSrcweir else 1972cdf0e10cSrcweir { 1973cdf0e10cSrcweir aCreationDateString.append( "Z" ); 1974cdf0e10cSrcweir aCreationMetaDateString.append( "Z" ); 1975cdf0e10cSrcweir 1976cdf0e10cSrcweir } 1977cdf0e10cSrcweir if( nDelta ) 1978cdf0e10cSrcweir { 1979cdf0e10cSrcweir aCreationDateString.append( (sal_Char)('0' + ((nDelta/36000)%10)) ); 1980cdf0e10cSrcweir aCreationDateString.append( (sal_Char)('0' + ((nDelta/3600)%10)) ); 1981cdf0e10cSrcweir aCreationDateString.append( "'" ); 1982cdf0e10cSrcweir aCreationDateString.append( (sal_Char)('0' + ((nDelta/600)%6)) ); 1983cdf0e10cSrcweir aCreationDateString.append( (sal_Char)('0' + ((nDelta/60)%10)) ); 1984cdf0e10cSrcweir 1985cdf0e10cSrcweir aCreationMetaDateString.append( (sal_Char)('0' + ((nDelta/36000)%10)) ); 1986cdf0e10cSrcweir aCreationMetaDateString.append( (sal_Char)('0' + ((nDelta/3600)%10)) ); 1987cdf0e10cSrcweir aCreationMetaDateString.append( ":" ); 1988cdf0e10cSrcweir aCreationMetaDateString.append( (sal_Char)('0' + ((nDelta/600)%6)) ); 1989cdf0e10cSrcweir aCreationMetaDateString.append( (sal_Char)('0' + ((nDelta/60)%10)) ); 1990cdf0e10cSrcweir } 1991cdf0e10cSrcweir aCreationDateString.append( "'" ); 1992cdf0e10cSrcweir aID.append( aCreationDateString.getStr(), aCreationDateString.getLength() ); 1993cdf0e10cSrcweir 1994cdf0e10cSrcweir aInfoValuesOut = aID.makeStringAndClear(); 1995cdf0e10cSrcweir o_rCString1 = aCreationDateString.makeStringAndClear(); 1996cdf0e10cSrcweir o_rCString2 = aCreationMetaDateString.makeStringAndClear(); 1997cdf0e10cSrcweir 1998cdf0e10cSrcweir rtlDigest aDigest = rtl_digest_createMD5(); 1999cdf0e10cSrcweir OSL_ENSURE( aDigest != NULL, "PDFWriterImpl::computeDocumentIdentifier: cannot obtain a digest object !" ); 2000cdf0e10cSrcweir if( aDigest ) 2001cdf0e10cSrcweir { 2002cdf0e10cSrcweir rtlDigestError nError = rtl_digest_updateMD5( aDigest, &aGMT, sizeof( aGMT ) ); 2003cdf0e10cSrcweir if( nError == rtl_Digest_E_None ) 2004cdf0e10cSrcweir nError = rtl_digest_updateMD5( aDigest, aInfoValuesOut.getStr(), aInfoValuesOut.getLength() ); 2005cdf0e10cSrcweir if( nError == rtl_Digest_E_None ) 2006cdf0e10cSrcweir { 2007cdf0e10cSrcweir o_rIdentifier = std::vector< sal_uInt8 >( 16, 0 ); 2008cdf0e10cSrcweir //the binary form of the doc id is needed for encryption stuff 2009cdf0e10cSrcweir rtl_digest_getMD5( aDigest, &o_rIdentifier[0], 16 ); 2010cdf0e10cSrcweir } 2011cdf0e10cSrcweir } 2012cdf0e10cSrcweir } 2013cdf0e10cSrcweir 2014cdf0e10cSrcweir /* i12626 methods */ 2015cdf0e10cSrcweir /* 2016cdf0e10cSrcweir check if the Unicode string must be encrypted or not, perform the requested task, 2017cdf0e10cSrcweir append the string as unicode hex, encrypted if needed 2018cdf0e10cSrcweir */ 2019cdf0e10cSrcweir inline void PDFWriterImpl::appendUnicodeTextStringEncrypt( const rtl::OUString& rInString, const sal_Int32 nInObjectNumber, OStringBuffer& rOutBuffer ) 2020cdf0e10cSrcweir { 2021cdf0e10cSrcweir rOutBuffer.append( "<" ); 2022cdf0e10cSrcweir if( m_aContext.Encryption.Encrypt() ) 2023cdf0e10cSrcweir { 2024cdf0e10cSrcweir const sal_Unicode* pStr = rInString.getStr(); 2025cdf0e10cSrcweir sal_Int32 nLen = rInString.getLength(); 2026cdf0e10cSrcweir //prepare a unicode string, encrypt it 2027cdf0e10cSrcweir if( checkEncryptionBufferSize( nLen*2 ) ) 2028cdf0e10cSrcweir { 2029cdf0e10cSrcweir enableStringEncryption( nInObjectNumber ); 2030cdf0e10cSrcweir register sal_uInt8 *pCopy = m_pEncryptionBuffer; 2031cdf0e10cSrcweir sal_Int32 nChars = 2; 2032cdf0e10cSrcweir *pCopy++ = 0xFE; 2033cdf0e10cSrcweir *pCopy++ = 0xFF; 2034cdf0e10cSrcweir // we need to prepare a byte stream from the unicode string buffer 2035cdf0e10cSrcweir for( register int i = 0; i < nLen; i++ ) 2036cdf0e10cSrcweir { 2037cdf0e10cSrcweir register sal_Unicode aUnChar = pStr[i]; 2038cdf0e10cSrcweir *pCopy++ = (sal_uInt8)( aUnChar >> 8 ); 2039cdf0e10cSrcweir *pCopy++ = (sal_uInt8)( aUnChar & 255 ); 2040cdf0e10cSrcweir nChars += 2; 2041cdf0e10cSrcweir } 2042cdf0e10cSrcweir //encrypt in place 2043cdf0e10cSrcweir rtl_cipher_encodeARCFOUR( m_aCipher, m_pEncryptionBuffer, nChars, m_pEncryptionBuffer, nChars ); 2044cdf0e10cSrcweir //now append, hexadecimal (appendHex), the encrypted result 2045cdf0e10cSrcweir for(register int i = 0; i < nChars; i++) 2046cdf0e10cSrcweir appendHex( m_pEncryptionBuffer[i], rOutBuffer ); 2047cdf0e10cSrcweir } 2048cdf0e10cSrcweir } 2049cdf0e10cSrcweir else 2050cdf0e10cSrcweir appendUnicodeTextString( rInString, rOutBuffer ); 2051cdf0e10cSrcweir rOutBuffer.append( ">" ); 2052cdf0e10cSrcweir } 2053cdf0e10cSrcweir 2054cdf0e10cSrcweir inline void PDFWriterImpl::appendLiteralStringEncrypt( rtl::OStringBuffer& rInString, const sal_Int32 nInObjectNumber, rtl::OStringBuffer& rOutBuffer ) 2055cdf0e10cSrcweir { 2056cdf0e10cSrcweir rOutBuffer.append( "(" ); 2057cdf0e10cSrcweir sal_Int32 nChars = rInString.getLength(); 2058cdf0e10cSrcweir //check for encryption, if ok, encrypt the string, then convert with appndLiteralString 2059cdf0e10cSrcweir if( m_aContext.Encryption.Encrypt() && checkEncryptionBufferSize( nChars ) ) 2060cdf0e10cSrcweir { 2061cdf0e10cSrcweir //encrypt the string in a buffer, then append it 2062cdf0e10cSrcweir enableStringEncryption( nInObjectNumber ); 2063cdf0e10cSrcweir rtl_cipher_encodeARCFOUR( m_aCipher, rInString.getStr(), nChars, m_pEncryptionBuffer, nChars ); 2064cdf0e10cSrcweir appendLiteralString( (const sal_Char*)m_pEncryptionBuffer, nChars, rOutBuffer ); 2065cdf0e10cSrcweir } 2066cdf0e10cSrcweir else 2067cdf0e10cSrcweir appendLiteralString( rInString.getStr(), nChars , rOutBuffer ); 2068cdf0e10cSrcweir rOutBuffer.append( ")" ); 2069cdf0e10cSrcweir } 2070cdf0e10cSrcweir 2071cdf0e10cSrcweir inline void PDFWriterImpl::appendLiteralStringEncrypt( const rtl::OString& rInString, const sal_Int32 nInObjectNumber, rtl::OStringBuffer& rOutBuffer ) 2072cdf0e10cSrcweir { 2073cdf0e10cSrcweir rtl::OStringBuffer aBufferString( rInString ); 2074cdf0e10cSrcweir appendLiteralStringEncrypt( aBufferString, nInObjectNumber, rOutBuffer); 2075cdf0e10cSrcweir } 2076cdf0e10cSrcweir 2077cdf0e10cSrcweir void PDFWriterImpl::appendLiteralStringEncrypt( const rtl::OUString& rInString, const sal_Int32 nInObjectNumber, rtl::OStringBuffer& rOutBuffer, rtl_TextEncoding nEnc ) 2078cdf0e10cSrcweir { 2079cdf0e10cSrcweir rtl::OString aBufferString( rtl::OUStringToOString( rInString, nEnc ) ); 2080cdf0e10cSrcweir sal_Int32 nLen = aBufferString.getLength(); 2081cdf0e10cSrcweir rtl::OStringBuffer aBuf( nLen ); 2082cdf0e10cSrcweir const sal_Char* pT = aBufferString.getStr(); 2083cdf0e10cSrcweir 2084cdf0e10cSrcweir for( sal_Int32 i = 0; i < nLen; i++, pT++ ) 2085cdf0e10cSrcweir { 2086cdf0e10cSrcweir if( (*pT & 0x80) == 0 ) 2087cdf0e10cSrcweir aBuf.append( *pT ); 2088cdf0e10cSrcweir else 2089cdf0e10cSrcweir { 2090cdf0e10cSrcweir aBuf.append( '<' ); 2091cdf0e10cSrcweir appendHex( *pT, aBuf ); 2092cdf0e10cSrcweir aBuf.append( '>' ); 2093cdf0e10cSrcweir } 2094cdf0e10cSrcweir } 2095cdf0e10cSrcweir aBufferString = aBuf.makeStringAndClear(); 2096cdf0e10cSrcweir appendLiteralStringEncrypt( aBufferString, nInObjectNumber, rOutBuffer); 2097cdf0e10cSrcweir } 2098cdf0e10cSrcweir 2099cdf0e10cSrcweir /* end i12626 methods */ 2100cdf0e10cSrcweir 2101cdf0e10cSrcweir void PDFWriterImpl::emitComment( const char* pComment ) 2102cdf0e10cSrcweir { 2103cdf0e10cSrcweir OStringBuffer aLine( 64 ); 2104cdf0e10cSrcweir aLine.append( "% " ); 2105cdf0e10cSrcweir aLine.append( (const sal_Char*)pComment ); 2106cdf0e10cSrcweir aLine.append( "\n" ); 2107cdf0e10cSrcweir writeBuffer( aLine.getStr(), aLine.getLength() ); 2108cdf0e10cSrcweir } 2109cdf0e10cSrcweir 2110cdf0e10cSrcweir bool PDFWriterImpl::compressStream( SvMemoryStream* pStream ) 2111cdf0e10cSrcweir { 2112cdf0e10cSrcweir #ifndef DEBUG_DISABLE_PDFCOMPRESSION 2113cdf0e10cSrcweir pStream->Seek( STREAM_SEEK_TO_END ); 2114cdf0e10cSrcweir sal_uLong nEndPos = pStream->Tell(); 2115cdf0e10cSrcweir pStream->Seek( STREAM_SEEK_TO_BEGIN ); 2116cdf0e10cSrcweir ZCodec* pCodec = new ZCodec( 0x4000, 0x4000 ); 2117cdf0e10cSrcweir SvMemoryStream aStream; 2118cdf0e10cSrcweir pCodec->BeginCompression(); 2119cdf0e10cSrcweir pCodec->Write( aStream, (const sal_uInt8*)pStream->GetData(), nEndPos ); 2120cdf0e10cSrcweir pCodec->EndCompression(); 2121cdf0e10cSrcweir delete pCodec; 2122cdf0e10cSrcweir nEndPos = aStream.Tell(); 2123cdf0e10cSrcweir pStream->Seek( STREAM_SEEK_TO_BEGIN ); 2124cdf0e10cSrcweir aStream.Seek( STREAM_SEEK_TO_BEGIN ); 2125cdf0e10cSrcweir pStream->SetStreamSize( nEndPos ); 2126cdf0e10cSrcweir pStream->Write( aStream.GetData(), nEndPos ); 2127cdf0e10cSrcweir return true; 2128cdf0e10cSrcweir #else 2129cdf0e10cSrcweir (void)pStream; 2130cdf0e10cSrcweir return false; 2131cdf0e10cSrcweir #endif 2132cdf0e10cSrcweir } 2133cdf0e10cSrcweir 2134cdf0e10cSrcweir void PDFWriterImpl::beginCompression() 2135cdf0e10cSrcweir { 2136cdf0e10cSrcweir #ifndef DEBUG_DISABLE_PDFCOMPRESSION 2137cdf0e10cSrcweir m_pCodec = new ZCodec( 0x4000, 0x4000 ); 2138cdf0e10cSrcweir m_pMemStream = new SvMemoryStream(); 2139cdf0e10cSrcweir m_pCodec->BeginCompression(); 2140cdf0e10cSrcweir #endif 2141cdf0e10cSrcweir } 2142cdf0e10cSrcweir 2143cdf0e10cSrcweir void PDFWriterImpl::endCompression() 2144cdf0e10cSrcweir { 2145cdf0e10cSrcweir #ifndef DEBUG_DISABLE_PDFCOMPRESSION 2146cdf0e10cSrcweir if( m_pCodec ) 2147cdf0e10cSrcweir { 2148cdf0e10cSrcweir m_pCodec->EndCompression(); 2149cdf0e10cSrcweir delete m_pCodec; 2150cdf0e10cSrcweir m_pCodec = NULL; 2151cdf0e10cSrcweir sal_uInt64 nLen = m_pMemStream->Tell(); 2152cdf0e10cSrcweir m_pMemStream->Seek( 0 ); 2153cdf0e10cSrcweir writeBuffer( m_pMemStream->GetData(), nLen ); 2154cdf0e10cSrcweir delete m_pMemStream; 2155cdf0e10cSrcweir m_pMemStream = NULL; 2156cdf0e10cSrcweir } 2157cdf0e10cSrcweir #endif 2158cdf0e10cSrcweir } 2159cdf0e10cSrcweir 2160cdf0e10cSrcweir bool PDFWriterImpl::writeBuffer( const void* pBuffer, sal_uInt64 nBytes ) 2161cdf0e10cSrcweir { 2162cdf0e10cSrcweir if( ! m_bOpen ) // we are already down the drain 2163cdf0e10cSrcweir return false; 2164cdf0e10cSrcweir 2165cdf0e10cSrcweir if( ! nBytes ) // huh ? 2166cdf0e10cSrcweir return true; 2167cdf0e10cSrcweir 2168cdf0e10cSrcweir if( m_aOutputStreams.begin() != m_aOutputStreams.end() ) 2169cdf0e10cSrcweir { 2170cdf0e10cSrcweir m_aOutputStreams.front().m_pStream->Seek( STREAM_SEEK_TO_END ); 2171cdf0e10cSrcweir m_aOutputStreams.front().m_pStream->Write( pBuffer, sal::static_int_cast<sal_Size>(nBytes) ); 2172cdf0e10cSrcweir return true; 2173cdf0e10cSrcweir } 2174cdf0e10cSrcweir 2175cdf0e10cSrcweir sal_uInt64 nWritten; 2176cdf0e10cSrcweir if( m_pCodec ) 2177cdf0e10cSrcweir { 2178cdf0e10cSrcweir m_pCodec->Write( *m_pMemStream, static_cast<const sal_uInt8*>(pBuffer), (sal_uLong)nBytes ); 2179cdf0e10cSrcweir nWritten = nBytes; 2180cdf0e10cSrcweir } 2181cdf0e10cSrcweir else 2182cdf0e10cSrcweir { 2183cdf0e10cSrcweir sal_Bool buffOK = sal_True; 2184cdf0e10cSrcweir if( m_bEncryptThisStream ) 2185cdf0e10cSrcweir { 2186cdf0e10cSrcweir /* implement the encryption part of the PDF spec encryption algorithm 3.1 */ 2187cdf0e10cSrcweir if( ( buffOK = checkEncryptionBufferSize( static_cast<sal_Int32>(nBytes) ) ) != sal_False ) 2188cdf0e10cSrcweir rtl_cipher_encodeARCFOUR( m_aCipher, 2189cdf0e10cSrcweir (sal_uInt8*)pBuffer, static_cast<sal_Size>(nBytes), 2190cdf0e10cSrcweir m_pEncryptionBuffer, static_cast<sal_Size>(nBytes) ); 2191cdf0e10cSrcweir } 2192cdf0e10cSrcweir 2193cdf0e10cSrcweir const void* pWriteBuffer = ( m_bEncryptThisStream && buffOK ) ? m_pEncryptionBuffer : pBuffer; 2194cdf0e10cSrcweir if( m_aDocDigest ) 2195cdf0e10cSrcweir rtl_digest_updateMD5( m_aDocDigest, pWriteBuffer, static_cast<sal_uInt32>(nBytes) ); 2196cdf0e10cSrcweir 2197cdf0e10cSrcweir if( osl_writeFile( m_aFile, 2198cdf0e10cSrcweir pWriteBuffer, 2199cdf0e10cSrcweir nBytes, &nWritten ) != osl_File_E_None ) 2200cdf0e10cSrcweir nWritten = 0; 2201cdf0e10cSrcweir 2202cdf0e10cSrcweir if( nWritten != nBytes ) 2203cdf0e10cSrcweir { 2204cdf0e10cSrcweir osl_closeFile( m_aFile ); 2205cdf0e10cSrcweir m_bOpen = false; 2206cdf0e10cSrcweir } 2207cdf0e10cSrcweir } 2208cdf0e10cSrcweir 2209cdf0e10cSrcweir return nWritten == nBytes; 2210cdf0e10cSrcweir } 2211cdf0e10cSrcweir 2212cdf0e10cSrcweir OutputDevice* PDFWriterImpl::getReferenceDevice() 2213cdf0e10cSrcweir { 2214cdf0e10cSrcweir if( ! m_pReferenceDevice ) 2215cdf0e10cSrcweir { 2216cdf0e10cSrcweir VirtualDevice* pVDev = new VirtualDevice( 0 ); 2217cdf0e10cSrcweir 2218cdf0e10cSrcweir m_pReferenceDevice = pVDev; 2219cdf0e10cSrcweir 2220cdf0e10cSrcweir if( m_aContext.DPIx == 0 || m_aContext.DPIy == 0 ) 2221cdf0e10cSrcweir pVDev->SetReferenceDevice( VirtualDevice::REFDEV_MODE_PDF1 ); 2222cdf0e10cSrcweir else 2223cdf0e10cSrcweir pVDev->SetReferenceDevice( m_aContext.DPIx, m_aContext.DPIy ); 2224cdf0e10cSrcweir 2225cdf0e10cSrcweir pVDev->SetOutputSizePixel( Size( 640, 480 ) ); 2226cdf0e10cSrcweir pVDev->SetMapMode( MAP_MM ); 2227cdf0e10cSrcweir 2228cdf0e10cSrcweir m_pReferenceDevice->mpPDFWriter = this; 2229cdf0e10cSrcweir m_pReferenceDevice->ImplUpdateFontData( sal_True ); 2230cdf0e10cSrcweir } 2231cdf0e10cSrcweir return m_pReferenceDevice; 2232cdf0e10cSrcweir } 2233cdf0e10cSrcweir 2234cdf0e10cSrcweir class ImplPdfBuiltinFontData : public ImplFontData 2235cdf0e10cSrcweir { 2236cdf0e10cSrcweir private: 2237cdf0e10cSrcweir const PDFWriterImpl::BuiltinFont& mrBuiltin; 2238cdf0e10cSrcweir 2239cdf0e10cSrcweir public: 2240cdf0e10cSrcweir enum {PDF_FONT_MAGIC = 0xBDFF0A1C }; 2241cdf0e10cSrcweir ImplPdfBuiltinFontData( const PDFWriterImpl::BuiltinFont& ); 2242cdf0e10cSrcweir const PDFWriterImpl::BuiltinFont* GetBuiltinFont() const { return &mrBuiltin; } 2243cdf0e10cSrcweir 2244cdf0e10cSrcweir virtual ImplFontData* Clone() const { return new ImplPdfBuiltinFontData(*this); } 2245cdf0e10cSrcweir virtual ImplFontEntry* CreateFontInstance( ImplFontSelectData& ) const; 2246cdf0e10cSrcweir virtual sal_IntPtr GetFontId() const { return reinterpret_cast<sal_IntPtr>(&mrBuiltin); } 2247cdf0e10cSrcweir }; 2248cdf0e10cSrcweir 2249cdf0e10cSrcweir inline const ImplPdfBuiltinFontData* GetPdfFontData( const ImplFontData* pFontData ) 2250cdf0e10cSrcweir { 2251cdf0e10cSrcweir const ImplPdfBuiltinFontData* pFD = NULL; 2252cdf0e10cSrcweir if( pFontData && pFontData->CheckMagic( ImplPdfBuiltinFontData::PDF_FONT_MAGIC ) ) 2253cdf0e10cSrcweir pFD = static_cast<const ImplPdfBuiltinFontData*>( pFontData ); 2254cdf0e10cSrcweir return pFD; 2255cdf0e10cSrcweir } 2256cdf0e10cSrcweir 2257cdf0e10cSrcweir static ImplDevFontAttributes GetDevFontAttributes( const PDFWriterImpl::BuiltinFont& rBuiltin ) 2258cdf0e10cSrcweir { 2259cdf0e10cSrcweir ImplDevFontAttributes aDFA; 2260cdf0e10cSrcweir aDFA.maName = String::CreateFromAscii( rBuiltin.m_pName ); 2261cdf0e10cSrcweir aDFA.maStyleName = String::CreateFromAscii( rBuiltin.m_pStyleName ); 2262cdf0e10cSrcweir aDFA.meFamily = rBuiltin.m_eFamily; 2263cdf0e10cSrcweir aDFA.mbSymbolFlag = (rBuiltin.m_eCharSet != RTL_TEXTENCODING_MS_1252 ); 2264cdf0e10cSrcweir aDFA.mePitch = rBuiltin.m_ePitch; 2265cdf0e10cSrcweir aDFA.meWeight = rBuiltin.m_eWeight; 2266cdf0e10cSrcweir aDFA.meItalic = rBuiltin.m_eItalic; 2267cdf0e10cSrcweir aDFA.meWidthType = rBuiltin.m_eWidthType; 2268cdf0e10cSrcweir 2269cdf0e10cSrcweir aDFA.mbOrientation = true; 2270cdf0e10cSrcweir aDFA.mbDevice = true; 2271cdf0e10cSrcweir aDFA.mnQuality = 50000; 2272cdf0e10cSrcweir aDFA.mbSubsettable = false; 2273cdf0e10cSrcweir aDFA.mbEmbeddable = false; 2274cdf0e10cSrcweir return aDFA; 2275cdf0e10cSrcweir } 2276cdf0e10cSrcweir 2277cdf0e10cSrcweir ImplPdfBuiltinFontData::ImplPdfBuiltinFontData( const PDFWriterImpl::BuiltinFont& rBuiltin ) 2278cdf0e10cSrcweir : ImplFontData( GetDevFontAttributes(rBuiltin), PDF_FONT_MAGIC ), 2279cdf0e10cSrcweir mrBuiltin( rBuiltin ) 2280cdf0e10cSrcweir {} 2281cdf0e10cSrcweir 2282cdf0e10cSrcweir ImplFontEntry* ImplPdfBuiltinFontData::CreateFontInstance( ImplFontSelectData& rFSD ) const 2283cdf0e10cSrcweir { 2284cdf0e10cSrcweir ImplFontEntry* pEntry = new ImplFontEntry( rFSD ); 2285cdf0e10cSrcweir return pEntry; 2286cdf0e10cSrcweir } 2287cdf0e10cSrcweir 2288cdf0e10cSrcweir ImplDevFontList* PDFWriterImpl::filterDevFontList( ImplDevFontList* pFontList ) 2289cdf0e10cSrcweir { 2290cdf0e10cSrcweir DBG_ASSERT( m_aSubsets.size() == 0, "Fonts changing during PDF generation, document will be invalid" ); 2291cdf0e10cSrcweir ImplDevFontList* pFiltered = pFontList->Clone( true, true ); 2292cdf0e10cSrcweir 2293cdf0e10cSrcweir // append the PDF builtin fonts 2294cdf0e10cSrcweir if( !m_bIsPDF_A1 && !m_bEmbedStandardFonts) 2295cdf0e10cSrcweir for( unsigned int i = 0; i < sizeof(m_aBuiltinFonts)/sizeof(m_aBuiltinFonts[0]); i++ ) 2296cdf0e10cSrcweir { 2297cdf0e10cSrcweir ImplFontData* pNewData = new ImplPdfBuiltinFontData( m_aBuiltinFonts[i] ); 2298cdf0e10cSrcweir pFiltered->Add( pNewData ); 2299cdf0e10cSrcweir } 2300cdf0e10cSrcweir return pFiltered; 2301cdf0e10cSrcweir } 2302cdf0e10cSrcweir 2303cdf0e10cSrcweir bool PDFWriterImpl::isBuiltinFont( const ImplFontData* pFont ) const 2304cdf0e10cSrcweir { 2305cdf0e10cSrcweir const ImplPdfBuiltinFontData* pFD = GetPdfFontData( pFont ); 2306cdf0e10cSrcweir return (pFD != NULL); 2307cdf0e10cSrcweir } 2308cdf0e10cSrcweir 2309cdf0e10cSrcweir void PDFWriterImpl::getFontMetric( ImplFontSelectData* pSelect, ImplFontMetricData* pMetric ) const 2310cdf0e10cSrcweir { 2311cdf0e10cSrcweir const ImplPdfBuiltinFontData* pFD = GetPdfFontData( pSelect->mpFontData ); 2312cdf0e10cSrcweir if( !pFD ) 2313cdf0e10cSrcweir return; 2314cdf0e10cSrcweir const BuiltinFont* pBuiltinFont = pFD->GetBuiltinFont(); 2315cdf0e10cSrcweir 2316cdf0e10cSrcweir pMetric->mnOrientation = sal::static_int_cast<short>(pSelect->mnOrientation); 2317cdf0e10cSrcweir pMetric->meFamily = pBuiltinFont->m_eFamily; 2318cdf0e10cSrcweir pMetric->mePitch = pBuiltinFont->m_ePitch; 2319cdf0e10cSrcweir pMetric->meWeight = pBuiltinFont->m_eWeight; 2320cdf0e10cSrcweir pMetric->meItalic = pBuiltinFont->m_eItalic; 2321cdf0e10cSrcweir pMetric->mbSymbolFlag = pFD->IsSymbolFont(); 2322cdf0e10cSrcweir pMetric->mnWidth = pSelect->mnHeight; 2323cdf0e10cSrcweir pMetric->mnAscent = ( pSelect->mnHeight * +pBuiltinFont->m_nAscent + 500 ) / 1000; 2324cdf0e10cSrcweir pMetric->mnDescent = ( pSelect->mnHeight * -pBuiltinFont->m_nDescent + 500 ) / 1000; 2325cdf0e10cSrcweir pMetric->mnIntLeading = 0; 2326cdf0e10cSrcweir pMetric->mnExtLeading = 0; 2327cdf0e10cSrcweir pMetric->mnSlant = 0; 2328cdf0e10cSrcweir pMetric->mbScalableFont = true; 2329cdf0e10cSrcweir pMetric->mbDevice = true; 2330cdf0e10cSrcweir } 2331cdf0e10cSrcweir 2332cdf0e10cSrcweir // ----------------------------------------------------------------------- 2333cdf0e10cSrcweir 2334cdf0e10cSrcweir namespace vcl { 2335cdf0e10cSrcweir 2336cdf0e10cSrcweir class PDFSalLayout : public GenericSalLayout 2337cdf0e10cSrcweir { 2338cdf0e10cSrcweir PDFWriterImpl& mrPDFWriterImpl; 2339cdf0e10cSrcweir const PDFWriterImpl::BuiltinFont& mrBuiltinFont; 2340cdf0e10cSrcweir bool mbIsSymbolFont; 2341cdf0e10cSrcweir long mnPixelPerEM; 2342cdf0e10cSrcweir String maOrigText; 2343cdf0e10cSrcweir 2344cdf0e10cSrcweir public: 2345cdf0e10cSrcweir PDFSalLayout( PDFWriterImpl&, 2346cdf0e10cSrcweir const PDFWriterImpl::BuiltinFont&, 2347cdf0e10cSrcweir long nPixelPerEM, int nOrientation ); 2348cdf0e10cSrcweir 2349cdf0e10cSrcweir void SetText( const String& rText ) { maOrigText = rText; } 2350cdf0e10cSrcweir virtual bool LayoutText( ImplLayoutArgs& ); 2351cdf0e10cSrcweir virtual void InitFont() const; 2352cdf0e10cSrcweir virtual void DrawText( SalGraphics& ) const; 2353cdf0e10cSrcweir }; 2354cdf0e10cSrcweir 2355cdf0e10cSrcweir } 2356cdf0e10cSrcweir 2357cdf0e10cSrcweir // ----------------------------------------------------------------------- 2358cdf0e10cSrcweir 2359cdf0e10cSrcweir PDFSalLayout::PDFSalLayout( PDFWriterImpl& rPDFWriterImpl, 2360cdf0e10cSrcweir const PDFWriterImpl::BuiltinFont& rBuiltinFont, 2361cdf0e10cSrcweir long nPixelPerEM, int nOrientation ) 2362cdf0e10cSrcweir : mrPDFWriterImpl( rPDFWriterImpl ), 2363cdf0e10cSrcweir mrBuiltinFont( rBuiltinFont ), 2364cdf0e10cSrcweir mnPixelPerEM( nPixelPerEM ) 2365cdf0e10cSrcweir { 2366cdf0e10cSrcweir mbIsSymbolFont = (rBuiltinFont.m_eCharSet != RTL_TEXTENCODING_MS_1252); 2367cdf0e10cSrcweir SetOrientation( nOrientation ); 2368cdf0e10cSrcweir } 2369cdf0e10cSrcweir 2370cdf0e10cSrcweir // ----------------------------------------------------------------------- 2371cdf0e10cSrcweir 2372cdf0e10cSrcweir bool PDFSalLayout::LayoutText( ImplLayoutArgs& rArgs ) 2373cdf0e10cSrcweir { 2374cdf0e10cSrcweir const String aText( rArgs.mpStr+rArgs.mnMinCharPos, sal::static_int_cast<xub_StrLen>(rArgs.mnEndCharPos-rArgs.mnMinCharPos) ); 2375cdf0e10cSrcweir SetText( aText ); 2376cdf0e10cSrcweir SetUnitsPerPixel( 1000 ); 2377cdf0e10cSrcweir 2378cdf0e10cSrcweir rtl_UnicodeToTextConverter aConv = rtl_createTextToUnicodeConverter( mrBuiltinFont.m_eCharSet ); 2379cdf0e10cSrcweir 2380cdf0e10cSrcweir Point aNewPos( 0, 0 ); 2381cdf0e10cSrcweir bool bRightToLeft; 2382cdf0e10cSrcweir for( int nCharPos = -1; rArgs.GetNextPos( &nCharPos, &bRightToLeft ); ) 2383cdf0e10cSrcweir { 2384cdf0e10cSrcweir // TODO: handle unicode surrogates 2385cdf0e10cSrcweir // on the other hand the PDF builtin fonts don't support them anyway 2386cdf0e10cSrcweir sal_Unicode cChar = rArgs.mpStr[ nCharPos ]; 2387cdf0e10cSrcweir if( bRightToLeft ) 2388cdf0e10cSrcweir cChar = static_cast<sal_Unicode>(GetMirroredChar( cChar )); 2389cdf0e10cSrcweir 2390cdf0e10cSrcweir if( 1 ) // TODO: shortcut for ASCII? 2391cdf0e10cSrcweir { 2392cdf0e10cSrcweir sal_Char aBuf[4]; 2393cdf0e10cSrcweir sal_uInt32 nInfo; 2394cdf0e10cSrcweir sal_Size nSrcCvtChars; 2395cdf0e10cSrcweir 2396cdf0e10cSrcweir sal_Size nConv = rtl_convertUnicodeToText( aConv, 2397cdf0e10cSrcweir NULL, 2398cdf0e10cSrcweir &cChar, 1, 2399cdf0e10cSrcweir aBuf, sizeof(aBuf)/sizeof(*aBuf), 2400cdf0e10cSrcweir RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR, 2401cdf0e10cSrcweir &nInfo, &nSrcCvtChars ); 2402cdf0e10cSrcweir // check whether conversion was possible 2403cdf0e10cSrcweir // else fallback font is needed as the standard fonts 2404cdf0e10cSrcweir // are handled via WinAnsi encoding 2405cdf0e10cSrcweir if( nConv > 0 ) 2406cdf0e10cSrcweir cChar = ((sal_Unicode)aBuf[0]) & 0x00ff; 2407cdf0e10cSrcweir } 2408cdf0e10cSrcweir if( cChar & 0xff00 ) 2409cdf0e10cSrcweir { 2410cdf0e10cSrcweir cChar = 0; // NotDef glyph 2411cdf0e10cSrcweir rArgs.NeedFallback( nCharPos, bRightToLeft ); 2412cdf0e10cSrcweir } 2413cdf0e10cSrcweir 2414cdf0e10cSrcweir long nGlyphWidth = (long)mrBuiltinFont.m_aWidths[cChar] * mnPixelPerEM; 2415cdf0e10cSrcweir long nGlyphFlags = 0; // builtin fonts don't have diacritic glyphs 2416cdf0e10cSrcweir if( bRightToLeft ) 2417cdf0e10cSrcweir nGlyphFlags |= GlyphItem::IS_RTL_GLYPH; 2418cdf0e10cSrcweir // TODO: get kerning from builtin fonts 2419cdf0e10cSrcweir GlyphItem aGI( nCharPos, cChar, aNewPos, nGlyphFlags, nGlyphWidth ); 2420cdf0e10cSrcweir AppendGlyph( aGI ); 2421cdf0e10cSrcweir 2422cdf0e10cSrcweir aNewPos.X() += nGlyphWidth; 2423cdf0e10cSrcweir } 2424cdf0e10cSrcweir 2425cdf0e10cSrcweir rtl_destroyUnicodeToTextConverter( aConv ); 2426cdf0e10cSrcweir 2427cdf0e10cSrcweir return true; 2428cdf0e10cSrcweir } 2429cdf0e10cSrcweir 2430cdf0e10cSrcweir // ----------------------------------------------------------------------- 2431cdf0e10cSrcweir 2432cdf0e10cSrcweir void PDFSalLayout::InitFont() const 2433cdf0e10cSrcweir { 2434cdf0e10cSrcweir // TODO: recreate font with all its attributes 2435cdf0e10cSrcweir } 2436cdf0e10cSrcweir 2437cdf0e10cSrcweir // ----------------------------------------------------------------------- 2438cdf0e10cSrcweir 2439cdf0e10cSrcweir void PDFSalLayout::DrawText( SalGraphics& ) const 2440cdf0e10cSrcweir { 2441cdf0e10cSrcweir mrPDFWriterImpl.drawLayout( *const_cast<PDFSalLayout*>(this), maOrigText, true ); 2442cdf0e10cSrcweir } 2443cdf0e10cSrcweir 2444cdf0e10cSrcweir // ----------------------------------------------------------------------- 2445cdf0e10cSrcweir 2446cdf0e10cSrcweir SalLayout* PDFWriterImpl::GetTextLayout( ImplLayoutArgs& rArgs, ImplFontSelectData* pSelect ) 2447cdf0e10cSrcweir { 2448cdf0e10cSrcweir DBG_ASSERT( (pSelect->mpFontData != NULL), 2449cdf0e10cSrcweir "PDFWriterImpl::GetTextLayout mpFontData is NULL" ); 2450cdf0e10cSrcweir 2451cdf0e10cSrcweir const ImplPdfBuiltinFontData* pFD = GetPdfFontData( pSelect->mpFontData ); 2452cdf0e10cSrcweir if( !pFD ) 2453cdf0e10cSrcweir return NULL; 2454cdf0e10cSrcweir const BuiltinFont* pBuiltinFont = pFD->GetBuiltinFont(); 2455cdf0e10cSrcweir 2456cdf0e10cSrcweir long nPixelPerEM = pSelect->mnWidth ? pSelect->mnWidth : pSelect->mnHeight; 2457cdf0e10cSrcweir int nOrientation = pSelect->mnOrientation; 2458cdf0e10cSrcweir PDFSalLayout* pLayout = new PDFSalLayout( *this, *pBuiltinFont, nPixelPerEM, nOrientation ); 2459cdf0e10cSrcweir pLayout->SetText( rArgs.mpStr ); 2460cdf0e10cSrcweir return pLayout; 2461cdf0e10cSrcweir } 2462cdf0e10cSrcweir 2463cdf0e10cSrcweir sal_Int32 PDFWriterImpl::newPage( sal_Int32 nPageWidth, sal_Int32 nPageHeight, PDFWriter::Orientation eOrientation ) 2464cdf0e10cSrcweir { 2465cdf0e10cSrcweir endPage(); 2466cdf0e10cSrcweir m_nCurrentPage = m_aPages.size(); 2467cdf0e10cSrcweir m_aPages.push_back( PDFPage(this, nPageWidth, nPageHeight, eOrientation ) ); 2468cdf0e10cSrcweir m_aPages.back().m_nPageIndex = m_nCurrentPage; 2469cdf0e10cSrcweir m_aPages.back().beginStream(); 2470cdf0e10cSrcweir 2471cdf0e10cSrcweir // setup global graphics state 2472cdf0e10cSrcweir // linewidth is "1 pixel" by default 2473cdf0e10cSrcweir OStringBuffer aBuf( 16 ); 2474cdf0e10cSrcweir appendDouble( 72.0/double(getReferenceDevice()->ImplGetDPIX()), aBuf ); 2475cdf0e10cSrcweir aBuf.append( " w\n" ); 2476cdf0e10cSrcweir writeBuffer( aBuf.getStr(), aBuf.getLength() ); 2477cdf0e10cSrcweir 2478cdf0e10cSrcweir return m_nCurrentPage; 2479cdf0e10cSrcweir } 2480cdf0e10cSrcweir 2481cdf0e10cSrcweir void PDFWriterImpl::endPage() 2482cdf0e10cSrcweir { 2483cdf0e10cSrcweir if( m_aPages.begin() != m_aPages.end() ) 2484cdf0e10cSrcweir { 2485cdf0e10cSrcweir // close eventual MC sequence 2486cdf0e10cSrcweir endStructureElementMCSeq(); 2487cdf0e10cSrcweir 2488cdf0e10cSrcweir // sanity check 2489cdf0e10cSrcweir if( m_aOutputStreams.begin() != m_aOutputStreams.end() ) 2490cdf0e10cSrcweir { 2491cdf0e10cSrcweir DBG_ERROR( "redirection across pages !!!" ); 2492cdf0e10cSrcweir m_aOutputStreams.clear(); // leak ! 2493cdf0e10cSrcweir m_aMapMode.SetOrigin( Point() ); 2494cdf0e10cSrcweir } 2495cdf0e10cSrcweir 2496cdf0e10cSrcweir m_aGraphicsStack.clear(); 2497cdf0e10cSrcweir m_aGraphicsStack.push_back( GraphicsState() ); 2498cdf0e10cSrcweir 2499cdf0e10cSrcweir // this should pop the PDF graphics stack if necessary 2500cdf0e10cSrcweir updateGraphicsState(); 2501cdf0e10cSrcweir 2502cdf0e10cSrcweir m_aPages.back().endStream(); 2503cdf0e10cSrcweir 2504cdf0e10cSrcweir // reset the default font 2505cdf0e10cSrcweir Font aFont; 2506cdf0e10cSrcweir aFont.SetName( String( RTL_CONSTASCII_USTRINGPARAM( "Times" ) ) ); 2507cdf0e10cSrcweir aFont.SetSize( Size( 0, 12 ) ); 2508cdf0e10cSrcweir 2509cdf0e10cSrcweir m_aCurrentPDFState = m_aGraphicsStack.front(); 2510cdf0e10cSrcweir m_aGraphicsStack.front().m_aFont = aFont; 2511cdf0e10cSrcweir 2512cdf0e10cSrcweir for( std::list<BitmapEmit>::iterator it = m_aBitmaps.begin(); 2513cdf0e10cSrcweir it != m_aBitmaps.end(); ++it ) 2514cdf0e10cSrcweir { 2515cdf0e10cSrcweir if( ! it->m_aBitmap.IsEmpty() ) 2516cdf0e10cSrcweir { 2517cdf0e10cSrcweir writeBitmapObject( *it ); 2518cdf0e10cSrcweir it->m_aBitmap = BitmapEx(); 2519cdf0e10cSrcweir } 2520cdf0e10cSrcweir } 2521cdf0e10cSrcweir for( std::list<JPGEmit>::iterator jpeg = m_aJPGs.begin(); jpeg != m_aJPGs.end(); ++jpeg ) 2522cdf0e10cSrcweir { 2523cdf0e10cSrcweir if( jpeg->m_pStream ) 2524cdf0e10cSrcweir { 2525cdf0e10cSrcweir writeJPG( *jpeg ); 2526cdf0e10cSrcweir delete jpeg->m_pStream; 2527cdf0e10cSrcweir jpeg->m_pStream = NULL; 2528cdf0e10cSrcweir jpeg->m_aMask = Bitmap(); 2529cdf0e10cSrcweir } 2530cdf0e10cSrcweir } 2531cdf0e10cSrcweir for( std::list<TransparencyEmit>::iterator t = m_aTransparentObjects.begin(); 2532cdf0e10cSrcweir t != m_aTransparentObjects.end(); ++t ) 2533cdf0e10cSrcweir { 2534cdf0e10cSrcweir if( t->m_pContentStream ) 2535cdf0e10cSrcweir { 2536cdf0e10cSrcweir writeTransparentObject( *t ); 2537cdf0e10cSrcweir delete t->m_pContentStream; 2538cdf0e10cSrcweir t->m_pContentStream = NULL; 2539cdf0e10cSrcweir } 2540cdf0e10cSrcweir } 2541cdf0e10cSrcweir } 2542cdf0e10cSrcweir } 2543cdf0e10cSrcweir 2544cdf0e10cSrcweir sal_Int32 PDFWriterImpl::createObject() 2545cdf0e10cSrcweir { 2546cdf0e10cSrcweir m_aObjects.push_back( ~0U ); 2547cdf0e10cSrcweir return m_aObjects.size(); 2548cdf0e10cSrcweir } 2549cdf0e10cSrcweir 2550cdf0e10cSrcweir bool PDFWriterImpl::updateObject( sal_Int32 n ) 2551cdf0e10cSrcweir { 2552cdf0e10cSrcweir if( ! m_bOpen ) 2553cdf0e10cSrcweir return false; 2554cdf0e10cSrcweir 2555cdf0e10cSrcweir sal_uInt64 nOffset = ~0U; 2556cdf0e10cSrcweir oslFileError aError = osl_getFilePos( m_aFile, &nOffset ); 2557cdf0e10cSrcweir DBG_ASSERT( aError == osl_File_E_None, "could not register object" ); 2558cdf0e10cSrcweir if( aError != osl_File_E_None ) 2559cdf0e10cSrcweir { 2560cdf0e10cSrcweir osl_closeFile( m_aFile ); 2561cdf0e10cSrcweir m_bOpen = false; 2562cdf0e10cSrcweir } 2563cdf0e10cSrcweir m_aObjects[ n-1 ] = nOffset; 2564cdf0e10cSrcweir return aError == osl_File_E_None; 2565cdf0e10cSrcweir } 2566cdf0e10cSrcweir 2567cdf0e10cSrcweir #define CHECK_RETURN( x ) if( !(x) ) return 0 2568cdf0e10cSrcweir 2569cdf0e10cSrcweir sal_Int32 PDFWriterImpl::emitStructParentTree( sal_Int32 nObject ) 2570cdf0e10cSrcweir { 2571cdf0e10cSrcweir if( nObject > 0 ) 2572cdf0e10cSrcweir { 2573cdf0e10cSrcweir OStringBuffer aLine( 1024 ); 2574cdf0e10cSrcweir 2575cdf0e10cSrcweir aLine.append( nObject ); 2576cdf0e10cSrcweir aLine.append( " 0 obj\n" 2577cdf0e10cSrcweir "<</Nums[\n" ); 2578cdf0e10cSrcweir sal_Int32 nTreeItems = m_aStructParentTree.size(); 2579cdf0e10cSrcweir for( sal_Int32 n = 0; n < nTreeItems; n++ ) 2580cdf0e10cSrcweir { 2581cdf0e10cSrcweir aLine.append( n ); 2582cdf0e10cSrcweir aLine.append( ' ' ); 2583cdf0e10cSrcweir aLine.append( m_aStructParentTree[n] ); 2584cdf0e10cSrcweir aLine.append( "\n" ); 2585cdf0e10cSrcweir } 2586cdf0e10cSrcweir aLine.append( "]>>\nendobj\n\n" ); 2587cdf0e10cSrcweir CHECK_RETURN( updateObject( nObject ) ); 2588cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) ); 2589cdf0e10cSrcweir } 2590cdf0e10cSrcweir return nObject; 2591cdf0e10cSrcweir } 2592cdf0e10cSrcweir 2593cdf0e10cSrcweir const sal_Char* PDFWriterImpl::getAttributeTag( PDFWriter::StructAttribute eAttr ) 2594cdf0e10cSrcweir { 2595cdf0e10cSrcweir static std::map< PDFWriter::StructAttribute, const char* > aAttributeStrings; 2596cdf0e10cSrcweir // fill maps once 2597cdf0e10cSrcweir if( aAttributeStrings.empty() ) 2598cdf0e10cSrcweir { 2599cdf0e10cSrcweir aAttributeStrings[ PDFWriter::Placement ] = "Placement"; 2600cdf0e10cSrcweir aAttributeStrings[ PDFWriter::WritingMode ] = "WritingMode"; 2601cdf0e10cSrcweir aAttributeStrings[ PDFWriter::SpaceBefore ] = "SpaceBefore"; 2602cdf0e10cSrcweir aAttributeStrings[ PDFWriter::SpaceAfter ] = "SpaceAfter"; 2603cdf0e10cSrcweir aAttributeStrings[ PDFWriter::StartIndent ] = "StartIndent"; 2604cdf0e10cSrcweir aAttributeStrings[ PDFWriter::EndIndent ] = "EndIndent"; 2605cdf0e10cSrcweir aAttributeStrings[ PDFWriter::TextIndent ] = "TextIndent"; 2606cdf0e10cSrcweir aAttributeStrings[ PDFWriter::TextAlign ] = "TextAlign"; 2607cdf0e10cSrcweir aAttributeStrings[ PDFWriter::Width ] = "Width"; 2608cdf0e10cSrcweir aAttributeStrings[ PDFWriter::Height ] = "Height"; 2609cdf0e10cSrcweir aAttributeStrings[ PDFWriter::BlockAlign ] = "BlockAlign"; 2610cdf0e10cSrcweir aAttributeStrings[ PDFWriter::InlineAlign ] = "InlineAlign"; 2611cdf0e10cSrcweir aAttributeStrings[ PDFWriter::LineHeight ] = "LineHeight"; 2612cdf0e10cSrcweir aAttributeStrings[ PDFWriter::BaselineShift ] = "BaselineShift"; 2613cdf0e10cSrcweir aAttributeStrings[ PDFWriter::TextDecorationType ] = "TextDecorationType"; 2614cdf0e10cSrcweir aAttributeStrings[ PDFWriter::ListNumbering ] = "ListNumbering"; 2615cdf0e10cSrcweir aAttributeStrings[ PDFWriter::RowSpan ] = "RowSpan"; 2616cdf0e10cSrcweir aAttributeStrings[ PDFWriter::ColSpan ] = "ColSpan"; 2617cdf0e10cSrcweir aAttributeStrings[ PDFWriter::LinkAnnotation ] = "LinkAnnotation"; 2618cdf0e10cSrcweir } 2619cdf0e10cSrcweir 2620cdf0e10cSrcweir std::map< PDFWriter::StructAttribute, const char* >::const_iterator it = 2621cdf0e10cSrcweir aAttributeStrings.find( eAttr ); 2622cdf0e10cSrcweir 2623cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 2624cdf0e10cSrcweir if( it == aAttributeStrings.end() ) 2625cdf0e10cSrcweir fprintf( stderr, "invalid PDFWriter::StructAttribute %d\n", eAttr ); 2626cdf0e10cSrcweir #endif 2627cdf0e10cSrcweir 2628cdf0e10cSrcweir return it != aAttributeStrings.end() ? it->second : ""; 2629cdf0e10cSrcweir } 2630cdf0e10cSrcweir 2631cdf0e10cSrcweir const sal_Char* PDFWriterImpl::getAttributeValueTag( PDFWriter::StructAttributeValue eVal ) 2632cdf0e10cSrcweir { 2633cdf0e10cSrcweir static std::map< PDFWriter::StructAttributeValue, const char* > aValueStrings; 2634cdf0e10cSrcweir 2635cdf0e10cSrcweir if( aValueStrings.empty() ) 2636cdf0e10cSrcweir { 2637cdf0e10cSrcweir aValueStrings[ PDFWriter::NONE ] = "None"; 2638cdf0e10cSrcweir aValueStrings[ PDFWriter::Block ] = "Block"; 2639cdf0e10cSrcweir aValueStrings[ PDFWriter::Inline ] = "Inline"; 2640cdf0e10cSrcweir aValueStrings[ PDFWriter::Before ] = "Before"; 2641cdf0e10cSrcweir aValueStrings[ PDFWriter::After ] = "After"; 2642cdf0e10cSrcweir aValueStrings[ PDFWriter::Start ] = "Start"; 2643cdf0e10cSrcweir aValueStrings[ PDFWriter::End ] = "End"; 2644cdf0e10cSrcweir aValueStrings[ PDFWriter::LrTb ] = "LrTb"; 2645cdf0e10cSrcweir aValueStrings[ PDFWriter::RlTb ] = "RlTb"; 2646cdf0e10cSrcweir aValueStrings[ PDFWriter::TbRl ] = "TbRl"; 2647cdf0e10cSrcweir aValueStrings[ PDFWriter::Center ] = "Center"; 2648cdf0e10cSrcweir aValueStrings[ PDFWriter::Justify ] = "Justify"; 2649cdf0e10cSrcweir aValueStrings[ PDFWriter::Auto ] = "Auto"; 2650cdf0e10cSrcweir aValueStrings[ PDFWriter::Middle ] = "Middle"; 2651cdf0e10cSrcweir aValueStrings[ PDFWriter::Normal ] = "Normal"; 2652cdf0e10cSrcweir aValueStrings[ PDFWriter::Underline ] = "Underline"; 2653cdf0e10cSrcweir aValueStrings[ PDFWriter::Overline ] = "Overline"; 2654cdf0e10cSrcweir aValueStrings[ PDFWriter::LineThrough ] = "LineThrough"; 2655cdf0e10cSrcweir aValueStrings[ PDFWriter::Disc ] = "Disc"; 2656cdf0e10cSrcweir aValueStrings[ PDFWriter::Circle ] = "Circle"; 2657cdf0e10cSrcweir aValueStrings[ PDFWriter::Square ] = "Square"; 2658cdf0e10cSrcweir aValueStrings[ PDFWriter::Decimal ] = "Decimal"; 2659cdf0e10cSrcweir aValueStrings[ PDFWriter::UpperRoman ] = "UpperRoman"; 2660cdf0e10cSrcweir aValueStrings[ PDFWriter::LowerRoman ] = "LowerRoman"; 2661cdf0e10cSrcweir aValueStrings[ PDFWriter::UpperAlpha ] = "UpperAlpha"; 2662cdf0e10cSrcweir aValueStrings[ PDFWriter::LowerAlpha ] = "LowerAlpha"; 2663cdf0e10cSrcweir } 2664cdf0e10cSrcweir 2665cdf0e10cSrcweir std::map< PDFWriter::StructAttributeValue, const char* >::const_iterator it = 2666cdf0e10cSrcweir aValueStrings.find( eVal ); 2667cdf0e10cSrcweir 2668cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 2669cdf0e10cSrcweir if( it == aValueStrings.end() ) 2670cdf0e10cSrcweir fprintf( stderr, "invalid PDFWriter::StructAttributeValue %d\n", eVal ); 2671cdf0e10cSrcweir #endif 2672cdf0e10cSrcweir 2673cdf0e10cSrcweir return it != aValueStrings.end() ? it->second : ""; 2674cdf0e10cSrcweir } 2675cdf0e10cSrcweir 2676cdf0e10cSrcweir static void appendStructureAttributeLine( PDFWriter::StructAttribute i_eAttr, const PDFWriterImpl::PDFStructureAttribute& i_rVal, OStringBuffer& o_rLine, bool i_bIsFixedInt ) 2677cdf0e10cSrcweir { 2678cdf0e10cSrcweir o_rLine.append( "/" ); 2679cdf0e10cSrcweir o_rLine.append( PDFWriterImpl::getAttributeTag( i_eAttr ) ); 2680cdf0e10cSrcweir 2681cdf0e10cSrcweir if( i_rVal.eValue != PDFWriter::Invalid ) 2682cdf0e10cSrcweir { 2683cdf0e10cSrcweir o_rLine.append( "/" ); 2684cdf0e10cSrcweir o_rLine.append( PDFWriterImpl::getAttributeValueTag( i_rVal.eValue ) ); 2685cdf0e10cSrcweir } 2686cdf0e10cSrcweir else 2687cdf0e10cSrcweir { 2688cdf0e10cSrcweir // numerical value 2689cdf0e10cSrcweir o_rLine.append( " " ); 2690cdf0e10cSrcweir if( i_bIsFixedInt ) 2691cdf0e10cSrcweir appendFixedInt( i_rVal.nValue, o_rLine ); 2692cdf0e10cSrcweir else 2693cdf0e10cSrcweir o_rLine.append( i_rVal.nValue ); 2694cdf0e10cSrcweir } 2695cdf0e10cSrcweir o_rLine.append( "\n" ); 2696cdf0e10cSrcweir } 2697cdf0e10cSrcweir 2698cdf0e10cSrcweir OString PDFWriterImpl::emitStructureAttributes( PDFStructureElement& i_rEle ) 2699cdf0e10cSrcweir { 2700cdf0e10cSrcweir // create layout, list and table attribute sets 2701cdf0e10cSrcweir OStringBuffer aLayout(256), aList(64), aTable(64); 2702cdf0e10cSrcweir for( PDFStructAttributes::const_iterator it = i_rEle.m_aAttributes.begin(); 2703cdf0e10cSrcweir it != i_rEle.m_aAttributes.end(); ++it ) 2704cdf0e10cSrcweir { 2705cdf0e10cSrcweir if( it->first == PDFWriter::ListNumbering ) 2706cdf0e10cSrcweir appendStructureAttributeLine( it->first, it->second, aList, true ); 2707cdf0e10cSrcweir else if( it->first == PDFWriter::RowSpan || 2708cdf0e10cSrcweir it->first == PDFWriter::ColSpan ) 2709cdf0e10cSrcweir appendStructureAttributeLine( it->first, it->second, aTable, false ); 2710cdf0e10cSrcweir else if( it->first == PDFWriter::LinkAnnotation ) 2711cdf0e10cSrcweir { 2712cdf0e10cSrcweir sal_Int32 nLink = it->second.nValue; 2713cdf0e10cSrcweir std::map< sal_Int32, sal_Int32 >::const_iterator link_it = 2714cdf0e10cSrcweir m_aLinkPropertyMap.find( nLink ); 2715cdf0e10cSrcweir if( link_it != m_aLinkPropertyMap.end() ) 2716cdf0e10cSrcweir nLink = link_it->second; 2717cdf0e10cSrcweir if( nLink >= 0 && nLink < (sal_Int32)m_aLinks.size() ) 2718cdf0e10cSrcweir { 2719cdf0e10cSrcweir // update struct parent of link 2720cdf0e10cSrcweir OStringBuffer aStructParentEntry( 32 ); 2721cdf0e10cSrcweir aStructParentEntry.append( i_rEle.m_nObject ); 2722cdf0e10cSrcweir aStructParentEntry.append( " 0 R" ); 2723cdf0e10cSrcweir m_aStructParentTree.push_back( aStructParentEntry.makeStringAndClear() ); 2724cdf0e10cSrcweir m_aLinks[ nLink ].m_nStructParent = m_aStructParentTree.size()-1; 2725cdf0e10cSrcweir 2726cdf0e10cSrcweir sal_Int32 nRefObject = createObject(); 2727cdf0e10cSrcweir OStringBuffer aRef( 256 ); 2728cdf0e10cSrcweir aRef.append( nRefObject ); 2729cdf0e10cSrcweir aRef.append( " 0 obj\n" 2730cdf0e10cSrcweir "<</Type/OBJR/Obj " ); 2731cdf0e10cSrcweir aRef.append( m_aLinks[ nLink ].m_nObject ); 2732cdf0e10cSrcweir aRef.append( " 0 R>>\n" 2733cdf0e10cSrcweir "endobj\n\n" 2734cdf0e10cSrcweir ); 2735cdf0e10cSrcweir updateObject( nRefObject ); 2736cdf0e10cSrcweir writeBuffer( aRef.getStr(), aRef.getLength() ); 2737cdf0e10cSrcweir 2738cdf0e10cSrcweir i_rEle.m_aKids.push_back( PDFStructureElementKid( nRefObject ) ); 2739cdf0e10cSrcweir } 2740cdf0e10cSrcweir else 2741cdf0e10cSrcweir { 2742cdf0e10cSrcweir DBG_ERROR( "unresolved link id for Link structure" ); 2743cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 2744cdf0e10cSrcweir fprintf( stderr, "unresolved link id %" SAL_PRIdINT32 " for Link structure\n", nLink ); 2745cdf0e10cSrcweir { 2746cdf0e10cSrcweir OStringBuffer aLine( "unresolved link id " ); 2747cdf0e10cSrcweir aLine.append( nLink ); 2748cdf0e10cSrcweir aLine.append( " for Link structure" ); 2749cdf0e10cSrcweir emitComment( aLine.getStr() ); 2750cdf0e10cSrcweir } 2751cdf0e10cSrcweir #endif 2752cdf0e10cSrcweir } 2753cdf0e10cSrcweir } 2754cdf0e10cSrcweir else 2755cdf0e10cSrcweir appendStructureAttributeLine( it->first, it->second, aLayout, true ); 2756cdf0e10cSrcweir } 2757cdf0e10cSrcweir if( ! i_rEle.m_aBBox.IsEmpty() ) 2758cdf0e10cSrcweir { 2759cdf0e10cSrcweir aLayout.append( "/BBox[" ); 2760cdf0e10cSrcweir appendFixedInt( i_rEle.m_aBBox.Left(), aLayout ); 2761cdf0e10cSrcweir aLayout.append( " " ); 2762cdf0e10cSrcweir appendFixedInt( i_rEle.m_aBBox.Top(), aLayout ); 2763cdf0e10cSrcweir aLayout.append( " " ); 2764cdf0e10cSrcweir appendFixedInt( i_rEle.m_aBBox.Right(), aLayout ); 2765cdf0e10cSrcweir aLayout.append( " " ); 2766cdf0e10cSrcweir appendFixedInt( i_rEle.m_aBBox.Bottom(), aLayout ); 2767cdf0e10cSrcweir aLayout.append( "]\n" ); 2768cdf0e10cSrcweir } 2769cdf0e10cSrcweir 2770cdf0e10cSrcweir std::vector< sal_Int32 > aAttribObjects; 2771cdf0e10cSrcweir if( aLayout.getLength() ) 2772cdf0e10cSrcweir { 2773cdf0e10cSrcweir aAttribObjects.push_back( createObject() ); 2774cdf0e10cSrcweir updateObject( aAttribObjects.back() ); 2775cdf0e10cSrcweir OStringBuffer aObj( 64 ); 2776cdf0e10cSrcweir aObj.append( aAttribObjects.back() ); 2777cdf0e10cSrcweir aObj.append( " 0 obj\n" 2778cdf0e10cSrcweir "<</O/Layout\n" ); 2779cdf0e10cSrcweir aLayout.append( ">>\nendobj\n\n" ); 2780cdf0e10cSrcweir writeBuffer( aObj.getStr(), aObj.getLength() ); 2781cdf0e10cSrcweir writeBuffer( aLayout.getStr(), aLayout.getLength() ); 2782cdf0e10cSrcweir } 2783cdf0e10cSrcweir if( aList.getLength() ) 2784cdf0e10cSrcweir { 2785cdf0e10cSrcweir aAttribObjects.push_back( createObject() ); 2786cdf0e10cSrcweir updateObject( aAttribObjects.back() ); 2787cdf0e10cSrcweir OStringBuffer aObj( 64 ); 2788cdf0e10cSrcweir aObj.append( aAttribObjects.back() ); 2789cdf0e10cSrcweir aObj.append( " 0 obj\n" 2790cdf0e10cSrcweir "<</O/List\n" ); 2791cdf0e10cSrcweir aList.append( ">>\nendobj\n\n" ); 2792cdf0e10cSrcweir writeBuffer( aObj.getStr(), aObj.getLength() ); 2793cdf0e10cSrcweir writeBuffer( aList.getStr(), aList.getLength() ); 2794cdf0e10cSrcweir } 2795cdf0e10cSrcweir if( aTable.getLength() ) 2796cdf0e10cSrcweir { 2797cdf0e10cSrcweir aAttribObjects.push_back( createObject() ); 2798cdf0e10cSrcweir updateObject( aAttribObjects.back() ); 2799cdf0e10cSrcweir OStringBuffer aObj( 64 ); 2800cdf0e10cSrcweir aObj.append( aAttribObjects.back() ); 2801cdf0e10cSrcweir aObj.append( " 0 obj\n" 2802cdf0e10cSrcweir "<</O/Table\n" ); 2803cdf0e10cSrcweir aTable.append( ">>\nendobj\n\n" ); 2804cdf0e10cSrcweir writeBuffer( aObj.getStr(), aObj.getLength() ); 2805cdf0e10cSrcweir writeBuffer( aTable.getStr(), aTable.getLength() ); 2806cdf0e10cSrcweir } 2807cdf0e10cSrcweir 2808cdf0e10cSrcweir OStringBuffer aRet( 64 ); 2809cdf0e10cSrcweir if( aAttribObjects.size() > 1 ) 2810cdf0e10cSrcweir aRet.append( " [" ); 2811cdf0e10cSrcweir for( std::vector< sal_Int32 >::const_iterator at_it = aAttribObjects.begin(); 2812cdf0e10cSrcweir at_it != aAttribObjects.end(); ++at_it ) 2813cdf0e10cSrcweir { 2814cdf0e10cSrcweir aRet.append( " " ); 2815cdf0e10cSrcweir aRet.append( *at_it ); 2816cdf0e10cSrcweir aRet.append( " 0 R" ); 2817cdf0e10cSrcweir } 2818cdf0e10cSrcweir if( aAttribObjects.size() > 1 ) 2819cdf0e10cSrcweir aRet.append( " ]" ); 2820cdf0e10cSrcweir return aRet.makeStringAndClear(); 2821cdf0e10cSrcweir } 2822cdf0e10cSrcweir 2823cdf0e10cSrcweir sal_Int32 PDFWriterImpl::emitStructure( PDFStructureElement& rEle ) 2824cdf0e10cSrcweir { 2825cdf0e10cSrcweir if( 2826cdf0e10cSrcweir // do not emit NonStruct and its children 2827cdf0e10cSrcweir rEle.m_eType == PDFWriter::NonStructElement && 2828cdf0e10cSrcweir rEle.m_nOwnElement != rEle.m_nParentElement // but of course emit the struct tree root 2829cdf0e10cSrcweir ) 2830cdf0e10cSrcweir return 0; 2831cdf0e10cSrcweir 2832cdf0e10cSrcweir for( std::list< sal_Int32 >::const_iterator it = rEle.m_aChildren.begin(); it != rEle.m_aChildren.end(); ++it ) 2833cdf0e10cSrcweir { 2834cdf0e10cSrcweir if( *it > 0 && *it < sal_Int32(m_aStructure.size()) ) 2835cdf0e10cSrcweir { 2836cdf0e10cSrcweir PDFStructureElement& rChild = m_aStructure[ *it ]; 2837cdf0e10cSrcweir if( rChild.m_eType != PDFWriter::NonStructElement ) 2838cdf0e10cSrcweir { 2839cdf0e10cSrcweir if( rChild.m_nParentElement == rEle.m_nOwnElement ) 2840cdf0e10cSrcweir emitStructure( rChild ); 2841cdf0e10cSrcweir else 2842cdf0e10cSrcweir { 2843cdf0e10cSrcweir DBG_ERROR( "PDFWriterImpl::emitStructure: invalid child structure element" ); 2844cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 2845cdf0e10cSrcweir fprintf( stderr, "PDFWriterImpl::emitStructure: invalid child structure elemnt with id %" SAL_PRIdINT32 "\n", *it ); 2846cdf0e10cSrcweir #endif 2847cdf0e10cSrcweir } 2848cdf0e10cSrcweir } 2849cdf0e10cSrcweir } 2850cdf0e10cSrcweir else 2851cdf0e10cSrcweir { 2852cdf0e10cSrcweir DBG_ERROR( "PDFWriterImpl::emitStructure: invalid child structure id" ); 2853cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 2854cdf0e10cSrcweir fprintf( stderr, "PDFWriterImpl::emitStructure: invalid child structure id %" SAL_PRIdINT32 "\n", *it ); 2855cdf0e10cSrcweir #endif 2856cdf0e10cSrcweir } 2857cdf0e10cSrcweir } 2858cdf0e10cSrcweir 2859cdf0e10cSrcweir OStringBuffer aLine( 512 ); 2860cdf0e10cSrcweir aLine.append( rEle.m_nObject ); 2861cdf0e10cSrcweir aLine.append( " 0 obj\n" 2862cdf0e10cSrcweir "<</Type" ); 2863cdf0e10cSrcweir sal_Int32 nParentTree = -1; 2864cdf0e10cSrcweir if( rEle.m_nOwnElement == rEle.m_nParentElement ) 2865cdf0e10cSrcweir { 2866cdf0e10cSrcweir nParentTree = createObject(); 2867cdf0e10cSrcweir CHECK_RETURN( nParentTree ); 2868cdf0e10cSrcweir aLine.append( "/StructTreeRoot\n" ); 2869cdf0e10cSrcweir aLine.append( "/ParentTree " ); 2870cdf0e10cSrcweir aLine.append( nParentTree ); 2871cdf0e10cSrcweir aLine.append( " 0 R\n" ); 2872cdf0e10cSrcweir if( ! m_aRoleMap.empty() ) 2873cdf0e10cSrcweir { 2874cdf0e10cSrcweir aLine.append( "/RoleMap<<" ); 2875cdf0e10cSrcweir for( std::hash_map<OString,OString,OStringHash>::const_iterator 2876cdf0e10cSrcweir it = m_aRoleMap.begin(); it != m_aRoleMap.end(); ++it ) 2877cdf0e10cSrcweir { 2878cdf0e10cSrcweir aLine.append( '/' ); 2879cdf0e10cSrcweir aLine.append(it->first); 2880cdf0e10cSrcweir aLine.append( '/' ); 2881cdf0e10cSrcweir aLine.append( it->second ); 2882cdf0e10cSrcweir aLine.append( '\n' ); 2883cdf0e10cSrcweir } 2884cdf0e10cSrcweir aLine.append( ">>\n" ); 2885cdf0e10cSrcweir } 2886cdf0e10cSrcweir } 2887cdf0e10cSrcweir else 2888cdf0e10cSrcweir { 2889cdf0e10cSrcweir aLine.append( "/StructElem\n" 2890cdf0e10cSrcweir "/S/" ); 2891cdf0e10cSrcweir if( rEle.m_aAlias.getLength() > 0 ) 2892cdf0e10cSrcweir aLine.append( rEle.m_aAlias ); 2893cdf0e10cSrcweir else 2894cdf0e10cSrcweir aLine.append( getStructureTag( rEle.m_eType ) ); 2895cdf0e10cSrcweir aLine.append( "\n" 2896cdf0e10cSrcweir "/P " ); 2897cdf0e10cSrcweir aLine.append( m_aStructure[ rEle.m_nParentElement ].m_nObject ); 2898cdf0e10cSrcweir aLine.append( " 0 R\n" 2899cdf0e10cSrcweir "/Pg " ); 2900cdf0e10cSrcweir aLine.append( rEle.m_nFirstPageObject ); 2901cdf0e10cSrcweir aLine.append( " 0 R\n" ); 2902cdf0e10cSrcweir if( rEle.m_aActualText.getLength() ) 2903cdf0e10cSrcweir { 2904cdf0e10cSrcweir aLine.append( "/ActualText" ); 2905cdf0e10cSrcweir appendUnicodeTextStringEncrypt( rEle.m_aActualText, rEle.m_nObject, aLine ); 2906cdf0e10cSrcweir aLine.append( "\n" ); 2907cdf0e10cSrcweir } 2908cdf0e10cSrcweir if( rEle.m_aAltText.getLength() ) 2909cdf0e10cSrcweir { 2910cdf0e10cSrcweir aLine.append( "/Alt" ); 2911cdf0e10cSrcweir appendUnicodeTextStringEncrypt( rEle.m_aAltText, rEle.m_nObject, aLine ); 2912cdf0e10cSrcweir aLine.append( "\n" ); 2913cdf0e10cSrcweir } 2914cdf0e10cSrcweir } 2915cdf0e10cSrcweir if( ! rEle.m_aBBox.IsEmpty() || rEle.m_aAttributes.size() ) 2916cdf0e10cSrcweir { 2917cdf0e10cSrcweir OString aAttribs = emitStructureAttributes( rEle ); 2918cdf0e10cSrcweir if( aAttribs.getLength() ) 2919cdf0e10cSrcweir { 2920cdf0e10cSrcweir aLine.append( "/A" ); 2921cdf0e10cSrcweir aLine.append( aAttribs ); 2922cdf0e10cSrcweir aLine.append( "\n" ); 2923cdf0e10cSrcweir } 2924cdf0e10cSrcweir } 2925cdf0e10cSrcweir if( rEle.m_aLocale.Language.getLength() > 0 ) 2926cdf0e10cSrcweir { 2927cdf0e10cSrcweir OUStringBuffer aLocBuf( 16 ); 2928cdf0e10cSrcweir aLocBuf.append( rEle.m_aLocale.Language.toAsciiLowerCase() ); 2929cdf0e10cSrcweir if( rEle.m_aLocale.Country.getLength() > 0 ) 2930cdf0e10cSrcweir { 2931cdf0e10cSrcweir aLocBuf.append( sal_Unicode('-') ); 2932cdf0e10cSrcweir aLocBuf.append( rEle.m_aLocale.Country ); 2933cdf0e10cSrcweir } 2934cdf0e10cSrcweir aLine.append( "/Lang" ); 2935cdf0e10cSrcweir appendLiteralStringEncrypt( aLocBuf.makeStringAndClear(), rEle.m_nObject, aLine ); 2936cdf0e10cSrcweir aLine.append( "\n" ); 2937cdf0e10cSrcweir } 2938cdf0e10cSrcweir if( ! rEle.m_aKids.empty() ) 2939cdf0e10cSrcweir { 2940cdf0e10cSrcweir unsigned int i = 0; 2941cdf0e10cSrcweir aLine.append( "/K[" ); 2942cdf0e10cSrcweir for( std::list< PDFStructureElementKid >::const_iterator it = 2943cdf0e10cSrcweir rEle.m_aKids.begin(); it != rEle.m_aKids.end(); ++it, i++ ) 2944cdf0e10cSrcweir { 2945cdf0e10cSrcweir if( it->nMCID == -1 ) 2946cdf0e10cSrcweir { 2947cdf0e10cSrcweir aLine.append( it->nObject ); 2948cdf0e10cSrcweir aLine.append( " 0 R" ); 2949cdf0e10cSrcweir aLine.append( ( (i & 15) == 15 ) ? "\n" : " " ); 2950cdf0e10cSrcweir } 2951cdf0e10cSrcweir else 2952cdf0e10cSrcweir { 2953cdf0e10cSrcweir if( it->nObject == rEle.m_nFirstPageObject ) 2954cdf0e10cSrcweir { 2955cdf0e10cSrcweir aLine.append( it->nMCID ); 2956cdf0e10cSrcweir aLine.append( " " ); 2957cdf0e10cSrcweir } 2958cdf0e10cSrcweir else 2959cdf0e10cSrcweir { 2960cdf0e10cSrcweir aLine.append( "<</Type/MCR/Pg " ); 2961cdf0e10cSrcweir aLine.append( it->nObject ); 2962cdf0e10cSrcweir aLine.append( " 0 R /MCID " ); 2963cdf0e10cSrcweir aLine.append( it->nMCID ); 2964cdf0e10cSrcweir aLine.append( ">>\n" ); 2965cdf0e10cSrcweir } 2966cdf0e10cSrcweir } 2967cdf0e10cSrcweir } 2968cdf0e10cSrcweir aLine.append( "]\n" ); 2969cdf0e10cSrcweir } 2970cdf0e10cSrcweir aLine.append( ">>\nendobj\n\n" ); 2971cdf0e10cSrcweir 2972cdf0e10cSrcweir CHECK_RETURN( updateObject( rEle.m_nObject ) ); 2973cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) ); 2974cdf0e10cSrcweir 2975cdf0e10cSrcweir CHECK_RETURN( emitStructParentTree( nParentTree ) ); 2976cdf0e10cSrcweir 2977cdf0e10cSrcweir return rEle.m_nObject; 2978cdf0e10cSrcweir } 2979cdf0e10cSrcweir 2980cdf0e10cSrcweir bool PDFWriterImpl::emitGradients() 2981cdf0e10cSrcweir { 2982cdf0e10cSrcweir for( std::list<GradientEmit>::iterator it = m_aGradients.begin(); 2983cdf0e10cSrcweir it != m_aGradients.end(); ++it ) 2984cdf0e10cSrcweir { 2985cdf0e10cSrcweir CHECK_RETURN( writeGradientFunction( *it ) ); 2986cdf0e10cSrcweir } 2987cdf0e10cSrcweir return true; 2988cdf0e10cSrcweir } 2989cdf0e10cSrcweir 2990cdf0e10cSrcweir bool PDFWriterImpl::emitTilings() 2991cdf0e10cSrcweir { 2992cdf0e10cSrcweir OStringBuffer aTilingObj( 1024 ); 2993cdf0e10cSrcweir 2994cdf0e10cSrcweir for( std::vector<TilingEmit>::iterator it = m_aTilings.begin(); it != m_aTilings.end(); ++it ) 2995cdf0e10cSrcweir { 2996cdf0e10cSrcweir DBG_ASSERT( it->m_pTilingStream, "tiling without stream" ); 2997cdf0e10cSrcweir if( ! it->m_pTilingStream ) 2998cdf0e10cSrcweir continue; 2999cdf0e10cSrcweir 3000cdf0e10cSrcweir aTilingObj.setLength( 0 ); 3001cdf0e10cSrcweir 3002cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 3003cdf0e10cSrcweir emitComment( "PDFWriterImpl::emitTilings" ); 3004cdf0e10cSrcweir #endif 3005cdf0e10cSrcweir 3006cdf0e10cSrcweir sal_Int32 nX = (sal_Int32)it->m_aRectangle.Left(); 3007cdf0e10cSrcweir sal_Int32 nY = (sal_Int32)it->m_aRectangle.Top(); 3008cdf0e10cSrcweir sal_Int32 nW = (sal_Int32)it->m_aRectangle.GetWidth(); 3009cdf0e10cSrcweir sal_Int32 nH = (sal_Int32)it->m_aRectangle.GetHeight(); 3010cdf0e10cSrcweir if( it->m_aCellSize.Width() == 0 ) 3011cdf0e10cSrcweir it->m_aCellSize.Width() = nW; 3012cdf0e10cSrcweir if( it->m_aCellSize.Height() == 0 ) 3013cdf0e10cSrcweir it->m_aCellSize.Height() = nH; 3014cdf0e10cSrcweir 3015cdf0e10cSrcweir bool bDeflate = compressStream( it->m_pTilingStream ); 3016cdf0e10cSrcweir it->m_pTilingStream->Seek( STREAM_SEEK_TO_END ); 3017cdf0e10cSrcweir sal_Size nTilingStreamSize = it->m_pTilingStream->Tell(); 3018cdf0e10cSrcweir it->m_pTilingStream->Seek( STREAM_SEEK_TO_BEGIN ); 3019cdf0e10cSrcweir 3020cdf0e10cSrcweir // write pattern object 3021cdf0e10cSrcweir aTilingObj.append( it->m_nObject ); 3022cdf0e10cSrcweir aTilingObj.append( " 0 obj\n" ); 3023cdf0e10cSrcweir aTilingObj.append( "<</Type/Pattern/PatternType 1\n" 3024cdf0e10cSrcweir "/PaintType 1\n" 3025cdf0e10cSrcweir "/TilingType 2\n" 3026cdf0e10cSrcweir "/BBox[" ); 3027cdf0e10cSrcweir appendFixedInt( nX, aTilingObj ); 3028cdf0e10cSrcweir aTilingObj.append( ' ' ); 3029cdf0e10cSrcweir appendFixedInt( nY, aTilingObj ); 3030cdf0e10cSrcweir aTilingObj.append( ' ' ); 3031cdf0e10cSrcweir appendFixedInt( nX+nW, aTilingObj ); 3032cdf0e10cSrcweir aTilingObj.append( ' ' ); 3033cdf0e10cSrcweir appendFixedInt( nY+nH, aTilingObj ); 3034cdf0e10cSrcweir aTilingObj.append( "]\n" 3035cdf0e10cSrcweir "/XStep " ); 3036cdf0e10cSrcweir appendFixedInt( it->m_aCellSize.Width(), aTilingObj ); 3037cdf0e10cSrcweir aTilingObj.append( "\n" 3038cdf0e10cSrcweir "/YStep " ); 3039cdf0e10cSrcweir appendFixedInt( it->m_aCellSize.Height(), aTilingObj ); 3040cdf0e10cSrcweir aTilingObj.append( "\n" ); 3041cdf0e10cSrcweir if( it->m_aTransform.matrix[0] != 1.0 || 3042cdf0e10cSrcweir it->m_aTransform.matrix[1] != 0.0 || 3043cdf0e10cSrcweir it->m_aTransform.matrix[3] != 0.0 || 3044cdf0e10cSrcweir it->m_aTransform.matrix[4] != 1.0 || 3045cdf0e10cSrcweir it->m_aTransform.matrix[2] != 0.0 || 3046cdf0e10cSrcweir it->m_aTransform.matrix[5] != 0.0 ) 3047cdf0e10cSrcweir { 3048cdf0e10cSrcweir aTilingObj.append( "/Matrix [" ); 3049cdf0e10cSrcweir // TODO: scaling, mirroring on y, etc 3050cdf0e10cSrcweir appendDouble( it->m_aTransform.matrix[0], aTilingObj ); 3051cdf0e10cSrcweir aTilingObj.append( ' ' ); 3052cdf0e10cSrcweir appendDouble( it->m_aTransform.matrix[1], aTilingObj ); 3053cdf0e10cSrcweir aTilingObj.append( ' ' ); 3054cdf0e10cSrcweir appendDouble( it->m_aTransform.matrix[3], aTilingObj ); 3055cdf0e10cSrcweir aTilingObj.append( ' ' ); 3056cdf0e10cSrcweir appendDouble( it->m_aTransform.matrix[4], aTilingObj ); 3057cdf0e10cSrcweir aTilingObj.append( ' ' ); 3058cdf0e10cSrcweir appendDouble( it->m_aTransform.matrix[2], aTilingObj ); 3059cdf0e10cSrcweir aTilingObj.append( ' ' ); 3060cdf0e10cSrcweir appendDouble( it->m_aTransform.matrix[5], aTilingObj ); 3061cdf0e10cSrcweir aTilingObj.append( "]\n" ); 3062cdf0e10cSrcweir } 3063cdf0e10cSrcweir aTilingObj.append( "/Resources" ); 3064cdf0e10cSrcweir it->m_aResources.append( aTilingObj, getFontDictObject() ); 3065cdf0e10cSrcweir if( bDeflate ) 3066cdf0e10cSrcweir aTilingObj.append( "/Filter/FlateDecode" ); 3067cdf0e10cSrcweir aTilingObj.append( "/Length " ); 3068cdf0e10cSrcweir aTilingObj.append( (sal_Int32)nTilingStreamSize ); 3069cdf0e10cSrcweir aTilingObj.append( ">>\nstream\n" ); 3070cdf0e10cSrcweir CHECK_RETURN( updateObject( it->m_nObject ) ); 3071cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aTilingObj.getStr(), aTilingObj.getLength() ) ); 3072cdf0e10cSrcweir checkAndEnableStreamEncryption( it->m_nObject ); 3073cdf0e10cSrcweir nTilingStreamSize = writeBuffer( it->m_pTilingStream->GetData(), nTilingStreamSize ); 3074cdf0e10cSrcweir delete it->m_pTilingStream; 3075cdf0e10cSrcweir it->m_pTilingStream = NULL; 3076cdf0e10cSrcweir if( nTilingStreamSize == 0 ) 3077cdf0e10cSrcweir return false; 3078cdf0e10cSrcweir disableStreamEncryption(); 3079cdf0e10cSrcweir aTilingObj.setLength( 0 ); 3080cdf0e10cSrcweir aTilingObj.append( "\nendstream\nendobj\n\n" ); 3081cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aTilingObj.getStr(), aTilingObj.getLength() ) ); 3082cdf0e10cSrcweir } 3083cdf0e10cSrcweir return true; 3084cdf0e10cSrcweir } 3085cdf0e10cSrcweir 3086cdf0e10cSrcweir sal_Int32 PDFWriterImpl::emitBuiltinFont( const ImplFontData* pFont, sal_Int32 nFontObject ) 3087cdf0e10cSrcweir { 3088cdf0e10cSrcweir const ImplPdfBuiltinFontData* pFD = GetPdfFontData( pFont ); 3089cdf0e10cSrcweir if( !pFD ) 3090cdf0e10cSrcweir return 0; 3091cdf0e10cSrcweir const BuiltinFont* pBuiltinFont = pFD->GetBuiltinFont(); 3092cdf0e10cSrcweir 3093cdf0e10cSrcweir OStringBuffer aLine( 1024 ); 3094cdf0e10cSrcweir 3095cdf0e10cSrcweir if( nFontObject <= 0 ) 3096cdf0e10cSrcweir nFontObject = createObject(); 3097cdf0e10cSrcweir CHECK_RETURN( updateObject( nFontObject ) ); 3098cdf0e10cSrcweir aLine.append( nFontObject ); 3099cdf0e10cSrcweir aLine.append( " 0 obj\n" 3100cdf0e10cSrcweir "<</Type/Font/Subtype/Type1/BaseFont/" ); 3101cdf0e10cSrcweir appendName( pBuiltinFont->m_pPSName, aLine ); 3102cdf0e10cSrcweir aLine.append( "\n" ); 3103cdf0e10cSrcweir if( pBuiltinFont->m_eCharSet == RTL_TEXTENCODING_MS_1252 ) 3104cdf0e10cSrcweir aLine.append( "/Encoding/WinAnsiEncoding\n" ); 3105cdf0e10cSrcweir aLine.append( ">>\nendobj\n\n" ); 3106cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) ); 3107cdf0e10cSrcweir return nFontObject; 3108cdf0e10cSrcweir } 3109cdf0e10cSrcweir 3110cdf0e10cSrcweir std::map< sal_Int32, sal_Int32 > PDFWriterImpl::emitSystemFont( const ImplFontData* pFont, EmbedFont& rEmbed ) 3111cdf0e10cSrcweir { 3112cdf0e10cSrcweir std::map< sal_Int32, sal_Int32 > aRet; 3113cdf0e10cSrcweir if( isBuiltinFont( pFont ) ) 3114cdf0e10cSrcweir { 3115cdf0e10cSrcweir aRet[ rEmbed.m_nNormalFontID ] = emitBuiltinFont( pFont ); 3116cdf0e10cSrcweir return aRet; 3117cdf0e10cSrcweir } 3118cdf0e10cSrcweir 3119cdf0e10cSrcweir sal_Int32 nFontObject = 0; 3120cdf0e10cSrcweir sal_Int32 nFontDescriptor = 0; 3121cdf0e10cSrcweir rtl::OString aSubType( "/Type1" ); 3122cdf0e10cSrcweir FontSubsetInfo aInfo; 3123cdf0e10cSrcweir // fill in dummy values 3124cdf0e10cSrcweir aInfo.m_nAscent = 1000; 3125cdf0e10cSrcweir aInfo.m_nDescent = 200; 3126cdf0e10cSrcweir aInfo.m_nCapHeight = 1000; 3127cdf0e10cSrcweir aInfo.m_aFontBBox = Rectangle( Point( -200, -200 ), Size( 1700, 1700 ) ); 3128cdf0e10cSrcweir aInfo.m_aPSName = pFont->maName; 3129cdf0e10cSrcweir sal_Int32 pWidths[256]; 3130cdf0e10cSrcweir rtl_zeroMemory( pWidths, sizeof(pWidths) ); 3131cdf0e10cSrcweir if( pFont->IsEmbeddable() ) 3132cdf0e10cSrcweir { 3133cdf0e10cSrcweir const unsigned char* pFontData = NULL; 3134cdf0e10cSrcweir long nFontLen = 0; 3135cdf0e10cSrcweir sal_Ucs nEncodedCodes[256]; 3136cdf0e10cSrcweir sal_Int32 pEncWidths[256]; 3137cdf0e10cSrcweir if( (pFontData = (const unsigned char*)m_pReferenceDevice->mpGraphics->GetEmbedFontData( pFont, nEncodedCodes, pEncWidths, aInfo, &nFontLen )) != NULL ) 3138cdf0e10cSrcweir { 3139cdf0e10cSrcweir m_pReferenceDevice->mpGraphics->FreeEmbedFontData( pFontData, nFontLen ); 3140cdf0e10cSrcweir for( int i = 0; i < 256; i++ ) 3141cdf0e10cSrcweir { 3142cdf0e10cSrcweir if( nEncodedCodes[i] >= 32 && nEncodedCodes[i] < 256 ) 3143cdf0e10cSrcweir { 3144cdf0e10cSrcweir pWidths[i] = pEncWidths[ i ]; 3145cdf0e10cSrcweir } 3146cdf0e10cSrcweir } 3147cdf0e10cSrcweir } 3148cdf0e10cSrcweir } 3149cdf0e10cSrcweir else if( pFont->mbSubsettable ) 3150cdf0e10cSrcweir { 3151cdf0e10cSrcweir aSubType = rtl::OString( "/TrueType" ); 3152cdf0e10cSrcweir Int32Vector aGlyphWidths; 3153cdf0e10cSrcweir Ucs2UIntMap aUnicodeMap; 3154cdf0e10cSrcweir m_pReferenceDevice->mpGraphics->GetGlyphWidths( pFont, false, aGlyphWidths, aUnicodeMap ); 3155cdf0e10cSrcweir 3156cdf0e10cSrcweir OUString aTmpName; 3157cdf0e10cSrcweir osl_createTempFile( NULL, NULL, &aTmpName.pData ); 3158cdf0e10cSrcweir sal_Int32 pGlyphIDs[ 256 ]; 3159cdf0e10cSrcweir sal_uInt8 pEncoding[ 256 ]; 3160cdf0e10cSrcweir sal_Ucs pUnicodes[ 256 ]; 3161cdf0e10cSrcweir sal_Int32 pDuWidths[ 256 ]; 3162cdf0e10cSrcweir 3163cdf0e10cSrcweir memset( pGlyphIDs, 0, sizeof( pGlyphIDs ) ); 3164cdf0e10cSrcweir memset( pEncoding, 0, sizeof( pEncoding ) ); 3165cdf0e10cSrcweir memset( pUnicodes, 0, sizeof( pUnicodes ) ); 3166cdf0e10cSrcweir memset( pDuWidths, 0, sizeof( pDuWidths ) ); 3167cdf0e10cSrcweir 3168cdf0e10cSrcweir for( sal_Ucs c = 32; c < 256; c++ ) 3169cdf0e10cSrcweir { 3170cdf0e10cSrcweir pUnicodes[c] = c; 3171cdf0e10cSrcweir pEncoding[c] = c; 3172cdf0e10cSrcweir pGlyphIDs[c] = 0; 3173cdf0e10cSrcweir if( aUnicodeMap.find( c ) != aUnicodeMap.end() ) 3174cdf0e10cSrcweir pWidths[ c ] = aGlyphWidths[ aUnicodeMap[ c ] ]; 3175cdf0e10cSrcweir } 3176cdf0e10cSrcweir 3177cdf0e10cSrcweir m_pReferenceDevice->mpGraphics->CreateFontSubset( aTmpName, pFont, pGlyphIDs, pEncoding, pDuWidths, 256, aInfo ); 3178cdf0e10cSrcweir osl_removeFile( aTmpName.pData ); 3179cdf0e10cSrcweir } 3180cdf0e10cSrcweir else 3181cdf0e10cSrcweir { 3182cdf0e10cSrcweir DBG_ERROR( "system font neither embeddable nor subsettable" ); 3183cdf0e10cSrcweir } 3184cdf0e10cSrcweir 3185cdf0e10cSrcweir // write font descriptor 3186cdf0e10cSrcweir nFontDescriptor = emitFontDescriptor( pFont, aInfo, 0, 0 ); 3187cdf0e10cSrcweir if( nFontDescriptor ) 3188cdf0e10cSrcweir { 3189cdf0e10cSrcweir // write font object 3190cdf0e10cSrcweir sal_Int32 nObject = createObject(); 3191cdf0e10cSrcweir if( updateObject( nObject ) ) 3192cdf0e10cSrcweir { 3193cdf0e10cSrcweir OStringBuffer aLine( 1024 ); 3194cdf0e10cSrcweir aLine.append( nObject ); 3195cdf0e10cSrcweir aLine.append( " 0 obj\n" 3196cdf0e10cSrcweir "<</Type/Font/Subtype" ); 3197cdf0e10cSrcweir aLine.append( aSubType ); 3198cdf0e10cSrcweir aLine.append( "/BaseFont/" ); 3199cdf0e10cSrcweir appendName( aInfo.m_aPSName, aLine ); 3200cdf0e10cSrcweir aLine.append( "\n" ); 3201cdf0e10cSrcweir if( !pFont->mbSymbolFlag ) 3202cdf0e10cSrcweir aLine.append( "/Encoding/WinAnsiEncoding\n" ); 3203cdf0e10cSrcweir aLine.append( "/FirstChar 32 /LastChar 255\n" 3204cdf0e10cSrcweir "/Widths[" ); 3205cdf0e10cSrcweir for( int i = 32; i < 256; i++ ) 3206cdf0e10cSrcweir { 3207cdf0e10cSrcweir aLine.append( pWidths[i] ); 3208cdf0e10cSrcweir aLine.append( ((i&15) == 15) ? "\n" : " " ); 3209cdf0e10cSrcweir } 3210cdf0e10cSrcweir aLine.append( "]\n" 3211cdf0e10cSrcweir "/FontDescriptor " ); 3212cdf0e10cSrcweir aLine.append( nFontDescriptor ); 3213cdf0e10cSrcweir aLine.append( " 0 R>>\n" 3214cdf0e10cSrcweir "endobj\n\n" ); 3215cdf0e10cSrcweir writeBuffer( aLine.getStr(), aLine.getLength() ); 3216cdf0e10cSrcweir 3217cdf0e10cSrcweir nFontObject = nObject; 3218cdf0e10cSrcweir aRet[ rEmbed.m_nNormalFontID ] = nObject; 3219cdf0e10cSrcweir } 3220cdf0e10cSrcweir } 3221cdf0e10cSrcweir 3222cdf0e10cSrcweir return aRet; 3223cdf0e10cSrcweir } 3224cdf0e10cSrcweir 3225cdf0e10cSrcweir typedef int ThreeInts[3]; 3226cdf0e10cSrcweir static bool getPfbSegmentLengths( const unsigned char* pFontBytes, int nByteLen, 3227cdf0e10cSrcweir ThreeInts& rSegmentLengths ) 3228cdf0e10cSrcweir { 3229cdf0e10cSrcweir if( !pFontBytes || (nByteLen < 0) ) 3230cdf0e10cSrcweir return false; 3231cdf0e10cSrcweir const unsigned char* pPtr = pFontBytes; 3232cdf0e10cSrcweir const unsigned char* pEnd = pFontBytes + nByteLen; 3233cdf0e10cSrcweir 3234cdf0e10cSrcweir for( int i = 0; i < 3; ++i) { 3235cdf0e10cSrcweir // read segment1 header 3236cdf0e10cSrcweir if( pPtr+6 >= pEnd ) 3237cdf0e10cSrcweir return false; 3238cdf0e10cSrcweir if( (pPtr[0] != 0x80) || (pPtr[1] >= 0x03) ) 3239cdf0e10cSrcweir return false; 3240cdf0e10cSrcweir const int nLen = (pPtr[5]<<24) + (pPtr[4]<<16) + (pPtr[3]<<8) + pPtr[2]; 3241cdf0e10cSrcweir if( nLen <= 0) 3242cdf0e10cSrcweir return false; 3243cdf0e10cSrcweir rSegmentLengths[i] = nLen; 3244cdf0e10cSrcweir pPtr += nLen + 6; 3245cdf0e10cSrcweir } 3246cdf0e10cSrcweir 3247cdf0e10cSrcweir // read segment-end header 3248cdf0e10cSrcweir if( pPtr+2 >= pEnd ) 3249cdf0e10cSrcweir return false; 3250cdf0e10cSrcweir if( (pPtr[0] != 0x80) || (pPtr[1] != 0x03) ) 3251cdf0e10cSrcweir return false; 3252cdf0e10cSrcweir 3253cdf0e10cSrcweir return true; 3254cdf0e10cSrcweir } 3255cdf0e10cSrcweir 3256cdf0e10cSrcweir struct FontException : public std::exception 3257cdf0e10cSrcweir { 3258cdf0e10cSrcweir }; 3259cdf0e10cSrcweir 3260cdf0e10cSrcweir // TODO: always subset instead of embedding the full font => this method becomes obsolete then 3261cdf0e10cSrcweir std::map< sal_Int32, sal_Int32 > PDFWriterImpl::emitEmbeddedFont( const ImplFontData* pFont, EmbedFont& rEmbed ) 3262cdf0e10cSrcweir { 3263cdf0e10cSrcweir std::map< sal_Int32, sal_Int32 > aRet; 3264cdf0e10cSrcweir if( isBuiltinFont( pFont ) ) 3265cdf0e10cSrcweir { 3266cdf0e10cSrcweir aRet[ rEmbed.m_nNormalFontID ] = emitBuiltinFont( pFont ); 3267cdf0e10cSrcweir return aRet; 3268cdf0e10cSrcweir } 3269cdf0e10cSrcweir 3270cdf0e10cSrcweir sal_Int32 nFontObject = 0; 3271cdf0e10cSrcweir sal_Int32 nStreamObject = 0; 3272cdf0e10cSrcweir sal_Int32 nFontDescriptor = 0; 3273cdf0e10cSrcweir 3274cdf0e10cSrcweir // prepare font encoding 3275cdf0e10cSrcweir const Ucs2SIntMap* pEncoding = m_pReferenceDevice->mpGraphics->GetFontEncodingVector( pFont, NULL ); 3276cdf0e10cSrcweir sal_Int32 nToUnicodeStream = 0; 3277cdf0e10cSrcweir sal_uInt8 nEncoding[256]; 3278cdf0e10cSrcweir sal_Ucs nEncodedCodes[256]; 3279cdf0e10cSrcweir std::vector<sal_Ucs> aUnicodes; 3280cdf0e10cSrcweir aUnicodes.reserve( 256 ); 3281cdf0e10cSrcweir sal_Int32 pUnicodesPerGlyph[256]; 3282cdf0e10cSrcweir sal_Int32 pEncToUnicodeIndex[256]; 3283cdf0e10cSrcweir if( pEncoding ) 3284cdf0e10cSrcweir { 3285cdf0e10cSrcweir rtl_zeroMemory( nEncoding, sizeof(nEncoding) ); 3286cdf0e10cSrcweir rtl_zeroMemory( nEncodedCodes, sizeof(nEncodedCodes) ); 3287cdf0e10cSrcweir rtl_zeroMemory( pUnicodesPerGlyph, sizeof(pUnicodesPerGlyph) ); 3288cdf0e10cSrcweir rtl_zeroMemory( pEncToUnicodeIndex, sizeof(pEncToUnicodeIndex) ); 3289cdf0e10cSrcweir for( Ucs2SIntMap::const_iterator it = pEncoding->begin(); it != pEncoding->end(); ++it ) 3290cdf0e10cSrcweir { 3291cdf0e10cSrcweir if( it->second != -1 ) 3292cdf0e10cSrcweir { 3293cdf0e10cSrcweir sal_Int32 nCode = (sal_Int32)(it->second & 0x000000ff); 3294cdf0e10cSrcweir nEncoding[ nCode ] = static_cast<sal_uInt8>( nCode ); 3295cdf0e10cSrcweir nEncodedCodes[ nCode ] = it->first; 3296cdf0e10cSrcweir pEncToUnicodeIndex[ nCode ] = static_cast<sal_Int32>(aUnicodes.size()); 3297cdf0e10cSrcweir aUnicodes.push_back( it->first ); 3298cdf0e10cSrcweir pUnicodesPerGlyph[ nCode ] = 1; 3299cdf0e10cSrcweir } 3300cdf0e10cSrcweir } 3301cdf0e10cSrcweir } 3302cdf0e10cSrcweir 3303cdf0e10cSrcweir FontSubsetInfo aInfo; 3304cdf0e10cSrcweir sal_Int32 pWidths[256]; 3305cdf0e10cSrcweir const unsigned char* pFontData = NULL; 3306cdf0e10cSrcweir long nFontLen = 0; 3307cdf0e10cSrcweir sal_Int32 nLength1, nLength2; 3308cdf0e10cSrcweir try 3309cdf0e10cSrcweir { 3310cdf0e10cSrcweir if( (pFontData = (const unsigned char*)m_pReferenceDevice->mpGraphics->GetEmbedFontData( pFont, nEncodedCodes, pWidths, aInfo, &nFontLen )) != NULL ) 3311cdf0e10cSrcweir { 3312cdf0e10cSrcweir if( (aInfo.m_nFontType & FontSubsetInfo::ANY_TYPE1) == 0 ) 3313cdf0e10cSrcweir throw FontException(); 3314cdf0e10cSrcweir // see whether it is pfb or pfa; if it is a pfb, fill ranges 3315cdf0e10cSrcweir // of 6 bytes that are not part of the font program 3316cdf0e10cSrcweir std::list< int > aSections; 3317cdf0e10cSrcweir std::list< int >::const_iterator it; 3318cdf0e10cSrcweir int nIndex = 0; 3319cdf0e10cSrcweir while( pFontData[nIndex] == 0x80 && nIndex < nFontLen-1 ) 3320cdf0e10cSrcweir { 3321cdf0e10cSrcweir aSections.push_back( nIndex ); 3322cdf0e10cSrcweir if( pFontData[nIndex+1] == 0x03 ) 3323cdf0e10cSrcweir break; 3324cdf0e10cSrcweir sal_Int32 nBytes = 3325cdf0e10cSrcweir ((sal_Int32)pFontData[nIndex+2]) | 3326cdf0e10cSrcweir ((sal_Int32)pFontData[nIndex+3]) << 8 | 3327cdf0e10cSrcweir ((sal_Int32)pFontData[nIndex+4]) << 16 | 3328cdf0e10cSrcweir ((sal_Int32)pFontData[nIndex+5]) << 24; 3329cdf0e10cSrcweir nIndex += nBytes+6; 3330cdf0e10cSrcweir } 3331cdf0e10cSrcweir 3332cdf0e10cSrcweir // search for eexec 3333cdf0e10cSrcweir // TODO: use getPfbSegmentLengths() if possible to skip the search thingies below 3334cdf0e10cSrcweir nIndex = 0; 3335cdf0e10cSrcweir int nEndAsciiIndex; 3336cdf0e10cSrcweir int nBeginBinaryIndex; 3337cdf0e10cSrcweir int nEndBinaryIndex; 3338cdf0e10cSrcweir do 3339cdf0e10cSrcweir { 3340cdf0e10cSrcweir while( nIndex < nFontLen-4 && 3341cdf0e10cSrcweir ( pFontData[nIndex] != 'e' || 3342cdf0e10cSrcweir pFontData[nIndex+1] != 'e' || 3343cdf0e10cSrcweir pFontData[nIndex+2] != 'x' || 3344cdf0e10cSrcweir pFontData[nIndex+3] != 'e' || 3345cdf0e10cSrcweir pFontData[nIndex+4] != 'c' 3346cdf0e10cSrcweir ) 3347cdf0e10cSrcweir ) 3348cdf0e10cSrcweir nIndex++; 3349cdf0e10cSrcweir // check whether we are in a excluded section 3350cdf0e10cSrcweir for( it = aSections.begin(); it != aSections.end() && (nIndex < *it || nIndex > ((*it) + 5) ); ++it ) 3351cdf0e10cSrcweir ; 3352cdf0e10cSrcweir } while( it != aSections.end() && nIndex < nFontLen-4 ); 3353cdf0e10cSrcweir // this should end the ascii part 3354cdf0e10cSrcweir if( nIndex > nFontLen-5 ) 3355cdf0e10cSrcweir throw FontException(); 3356cdf0e10cSrcweir 3357cdf0e10cSrcweir nEndAsciiIndex = nIndex+4; 3358cdf0e10cSrcweir // now count backwards until we can account for 512 '0' 3359cdf0e10cSrcweir // which is the endmarker of the (hopefully) binary data 3360cdf0e10cSrcweir // do not count the pfb header sections 3361cdf0e10cSrcweir int nFound = 0; 3362cdf0e10cSrcweir nIndex = nFontLen-1; 3363cdf0e10cSrcweir while( nIndex > 0 && nFound < 512 ) 3364cdf0e10cSrcweir { 3365cdf0e10cSrcweir for( it = aSections.begin(); it != aSections.end() && (nIndex < *it || nIndex > ((*it) + 5) ); ++it ) 3366cdf0e10cSrcweir ; 3367cdf0e10cSrcweir if( it == aSections.end() ) 3368cdf0e10cSrcweir { 3369cdf0e10cSrcweir // inside the 512 '0' block there may only be whitespace 3370cdf0e10cSrcweir // according to T1 spec; probably it would be to simple 3371cdf0e10cSrcweir // if all fonts complied 3372cdf0e10cSrcweir if( pFontData[nIndex] == '0' ) 3373cdf0e10cSrcweir nFound++; 3374cdf0e10cSrcweir else if( nFound > 0 && 3375cdf0e10cSrcweir pFontData[nIndex] != '\r' && 3376cdf0e10cSrcweir pFontData[nIndex] != '\t' && 3377cdf0e10cSrcweir pFontData[nIndex] != '\n' && 3378cdf0e10cSrcweir pFontData[nIndex] != ' ' ) 3379cdf0e10cSrcweir break; 3380cdf0e10cSrcweir } 3381cdf0e10cSrcweir nIndex--; 3382cdf0e10cSrcweir } 3383cdf0e10cSrcweir 3384cdf0e10cSrcweir if( nIndex < 1 || nIndex <= nEndAsciiIndex ) 3385cdf0e10cSrcweir throw FontException(); 3386cdf0e10cSrcweir 3387cdf0e10cSrcweir // nLength3 is the rest of the file - excluding any section headers 3388cdf0e10cSrcweir // nIndex now points to the first of the 512 '0' characters marking the 3389cdf0e10cSrcweir // fixed content portion 3390cdf0e10cSrcweir sal_Int32 nLength3 = nFontLen - nIndex; 3391cdf0e10cSrcweir for( it = aSections.begin(); it != aSections.end(); ++it ) 3392cdf0e10cSrcweir { 3393cdf0e10cSrcweir // special case: nIndex inside a section marker 3394457fd29fSEike Rathke if( nIndex >= (*it) && (*it)+6 > nIndex ) 3395457fd29fSEike Rathke nLength3 -= (*it)+6 - nIndex; 3396457fd29fSEike Rathke else if( *it >= nIndex ) 3397cdf0e10cSrcweir { 3398cdf0e10cSrcweir if( *it < nFontLen - 6 ) 3399cdf0e10cSrcweir nLength3 -= 6; 3400cdf0e10cSrcweir else // the last section 0x8003 is only 2 bytes after all 3401cdf0e10cSrcweir nLength3 -= (nFontLen - *it); 3402cdf0e10cSrcweir } 3403cdf0e10cSrcweir } 3404cdf0e10cSrcweir 3405cdf0e10cSrcweir // there may be whitespace to ignore before the 512 '0' 3406cdf0e10cSrcweir while( pFontData[nIndex] == '\r' || pFontData[nIndex] == '\n' ) 3407cdf0e10cSrcweir { 3408cdf0e10cSrcweir nIndex--; 3409cdf0e10cSrcweir for( it = aSections.begin(); it != aSections.end() && (nIndex < *it || nIndex > ((*it) + 5) ); ++it ) 3410cdf0e10cSrcweir ; 3411cdf0e10cSrcweir if( it != aSections.end() ) 3412cdf0e10cSrcweir { 3413cdf0e10cSrcweir nIndex = (*it)-1; 3414cdf0e10cSrcweir break; // this is surely a binary boundary, in ascii case it wouldn't matter 3415cdf0e10cSrcweir } 3416cdf0e10cSrcweir } 3417cdf0e10cSrcweir nEndBinaryIndex = nIndex; 3418cdf0e10cSrcweir 3419cdf0e10cSrcweir // search for beginning of binary section 3420cdf0e10cSrcweir nBeginBinaryIndex = nEndAsciiIndex; 3421cdf0e10cSrcweir do 3422cdf0e10cSrcweir { 3423cdf0e10cSrcweir nBeginBinaryIndex++; 3424cdf0e10cSrcweir for( it = aSections.begin(); it != aSections.end() && (nBeginBinaryIndex < *it || nBeginBinaryIndex > ((*it) + 5) ); ++it ) 3425cdf0e10cSrcweir ; 3426cdf0e10cSrcweir } while( nBeginBinaryIndex < nEndBinaryIndex && 3427cdf0e10cSrcweir ( pFontData[nBeginBinaryIndex] == '\r' || 3428cdf0e10cSrcweir pFontData[nBeginBinaryIndex] == '\n' || 3429cdf0e10cSrcweir it != aSections.end() ) ); 3430cdf0e10cSrcweir 3431cdf0e10cSrcweir // it seems to be vital to copy the exact whitespace between binary data 3432cdf0e10cSrcweir // and eexec, else a invalid font results. so make nEndAsciiIndex 3433cdf0e10cSrcweir // always immediate in front of nBeginBinaryIndex 3434cdf0e10cSrcweir nEndAsciiIndex = nBeginBinaryIndex-1; 3435cdf0e10cSrcweir for( it = aSections.begin(); it != aSections.end() && (nEndAsciiIndex < *it || nEndAsciiIndex > ((*it)+5)); ++it ) 3436cdf0e10cSrcweir ; 3437cdf0e10cSrcweir if( it != aSections.end() ) 3438cdf0e10cSrcweir nEndAsciiIndex = (*it)-1; 3439cdf0e10cSrcweir 3440cdf0e10cSrcweir nLength1 = nEndAsciiIndex+1; // including the last character 3441cdf0e10cSrcweir for( it = aSections.begin(); it != aSections.end() && *it < nEndAsciiIndex; ++it ) 3442cdf0e10cSrcweir nLength1 -= 6; // decrease by pfb section size 3443cdf0e10cSrcweir 3444cdf0e10cSrcweir // if the first four bytes are all ascii hex characters, then binary data 3445cdf0e10cSrcweir // has to be converted to real binary data 3446cdf0e10cSrcweir for( nIndex = 0; nIndex < 4 && 3447cdf0e10cSrcweir ( ( pFontData[ nBeginBinaryIndex+nIndex ] >= '0' && pFontData[ nBeginBinaryIndex+nIndex ] <= '9' ) || 3448cdf0e10cSrcweir ( pFontData[ nBeginBinaryIndex+nIndex ] >= 'a' && pFontData[ nBeginBinaryIndex+nIndex ] <= 'f' ) || 3449cdf0e10cSrcweir ( pFontData[ nBeginBinaryIndex+nIndex ] >= 'A' && pFontData[ nBeginBinaryIndex+nIndex ] <= 'F' ) 3450cdf0e10cSrcweir ); ++nIndex ) 3451cdf0e10cSrcweir ; 3452cdf0e10cSrcweir bool bConvertHexData = true; 3453cdf0e10cSrcweir if( nIndex < 4 ) 3454cdf0e10cSrcweir { 3455cdf0e10cSrcweir bConvertHexData = false; 3456cdf0e10cSrcweir nLength2 = nEndBinaryIndex - nBeginBinaryIndex + 1; // include the last byte 3457cdf0e10cSrcweir for( it = aSections.begin(); it != aSections.end(); ++it ) 3458cdf0e10cSrcweir if( *it > nBeginBinaryIndex && *it < nEndBinaryIndex ) 3459cdf0e10cSrcweir nLength2 -= 6; 3460cdf0e10cSrcweir } 3461cdf0e10cSrcweir else 3462cdf0e10cSrcweir { 3463cdf0e10cSrcweir // count the hex ascii characters to get nLength2 3464cdf0e10cSrcweir nLength2 = 0; 3465cdf0e10cSrcweir int nNextSectionIndex = 0; 3466cdf0e10cSrcweir for( it = aSections.begin(); it != aSections.end() && *it < nBeginBinaryIndex; ++it ) 3467cdf0e10cSrcweir ; 3468cdf0e10cSrcweir if( it != aSections.end() ) 3469cdf0e10cSrcweir nNextSectionIndex = *it; 3470cdf0e10cSrcweir for( nIndex = nBeginBinaryIndex; nIndex <= nEndBinaryIndex; nIndex++ ) 3471cdf0e10cSrcweir { 3472cdf0e10cSrcweir if( nIndex == nNextSectionIndex ) 3473cdf0e10cSrcweir { 3474cdf0e10cSrcweir nIndex += 6; 3475cdf0e10cSrcweir ++it; 3476cdf0e10cSrcweir nNextSectionIndex = (it == aSections.end() ? 0 : *it ); 3477cdf0e10cSrcweir } 3478cdf0e10cSrcweir if( ( pFontData[ nIndex ] >= '0' && pFontData[ nIndex ] <= '9' ) || 3479cdf0e10cSrcweir ( pFontData[ nIndex ] >= 'a' && pFontData[ nIndex ] <= 'f' ) || 3480cdf0e10cSrcweir ( pFontData[ nIndex ] >= 'A' && pFontData[ nIndex ] <= 'F' ) ) 3481cdf0e10cSrcweir nLength2++; 3482cdf0e10cSrcweir } 3483cdf0e10cSrcweir DBG_ASSERT( !(nLength2 & 1), "uneven number of hex chars in binary pfa section" ); 3484cdf0e10cSrcweir nLength2 /= 2; 3485cdf0e10cSrcweir } 3486cdf0e10cSrcweir 3487cdf0e10cSrcweir // now we can actually write the font stream ! 3488cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 3489cdf0e10cSrcweir emitComment( " PDFWriterImpl::emitEmbeddedFont" ); 3490cdf0e10cSrcweir #endif 3491cdf0e10cSrcweir OStringBuffer aLine( 512 ); 3492cdf0e10cSrcweir nStreamObject = createObject(); 3493cdf0e10cSrcweir if( !updateObject(nStreamObject)) 3494cdf0e10cSrcweir throw FontException(); 3495cdf0e10cSrcweir sal_Int32 nStreamLengthObject = createObject(); 3496cdf0e10cSrcweir aLine.append( nStreamObject ); 3497cdf0e10cSrcweir aLine.append( " 0 obj\n" 3498cdf0e10cSrcweir "<</Length " ); 3499cdf0e10cSrcweir aLine.append( nStreamLengthObject ); 3500cdf0e10cSrcweir aLine.append( " 0 R" 3501cdf0e10cSrcweir #ifndef DEBUG_DISABLE_PDFCOMPRESSION 3502cdf0e10cSrcweir "/Filter/FlateDecode" 3503cdf0e10cSrcweir #endif 3504cdf0e10cSrcweir "/Length1 " ); 3505cdf0e10cSrcweir aLine.append( nLength1 ); 3506cdf0e10cSrcweir aLine.append( " /Length2 " ); 3507cdf0e10cSrcweir aLine.append( nLength2 ); 3508cdf0e10cSrcweir aLine.append( " /Length3 "); 3509cdf0e10cSrcweir aLine.append( nLength3 ); 3510cdf0e10cSrcweir aLine.append( ">>\n" 3511cdf0e10cSrcweir "stream\n" ); 3512cdf0e10cSrcweir if( !writeBuffer( aLine.getStr(), aLine.getLength() ) ) 3513cdf0e10cSrcweir throw FontException(); 3514cdf0e10cSrcweir 3515cdf0e10cSrcweir sal_uInt64 nBeginStreamPos = 0; 3516cdf0e10cSrcweir osl_getFilePos( m_aFile, &nBeginStreamPos ); 3517cdf0e10cSrcweir 3518cdf0e10cSrcweir beginCompression(); 3519cdf0e10cSrcweir checkAndEnableStreamEncryption( nStreamObject ); 3520cdf0e10cSrcweir 3521cdf0e10cSrcweir // write ascii section 3522cdf0e10cSrcweir if( aSections.begin() == aSections.end() ) 3523cdf0e10cSrcweir { 3524cdf0e10cSrcweir if( ! writeBuffer( pFontData, nEndAsciiIndex+1 ) ) 3525cdf0e10cSrcweir throw FontException(); 3526cdf0e10cSrcweir } 3527cdf0e10cSrcweir else 3528cdf0e10cSrcweir { 3529cdf0e10cSrcweir // first section always starts at 0 3530cdf0e10cSrcweir it = aSections.begin(); 3531cdf0e10cSrcweir nIndex = (*it)+6; 3532cdf0e10cSrcweir ++it; 3533cdf0e10cSrcweir while( *it < nEndAsciiIndex ) 3534cdf0e10cSrcweir { 3535cdf0e10cSrcweir if( ! writeBuffer( pFontData+nIndex, (*it)-nIndex ) ) 3536cdf0e10cSrcweir throw FontException(); 3537cdf0e10cSrcweir nIndex = (*it)+6; 3538cdf0e10cSrcweir ++it; 3539cdf0e10cSrcweir } 3540cdf0e10cSrcweir // write partial last section 3541cdf0e10cSrcweir if( ! writeBuffer( pFontData+nIndex, nEndAsciiIndex-nIndex+1 ) ) 3542cdf0e10cSrcweir throw FontException(); 3543cdf0e10cSrcweir } 3544cdf0e10cSrcweir 3545cdf0e10cSrcweir // write binary section 3546cdf0e10cSrcweir if( ! bConvertHexData ) 3547cdf0e10cSrcweir { 3548cdf0e10cSrcweir if( aSections.begin() == aSections.end() ) 3549cdf0e10cSrcweir { 3550cdf0e10cSrcweir if( ! writeBuffer( pFontData+nBeginBinaryIndex, nFontLen-nBeginBinaryIndex ) ) 3551cdf0e10cSrcweir throw FontException(); 3552cdf0e10cSrcweir } 3553cdf0e10cSrcweir else 3554cdf0e10cSrcweir { 3555cdf0e10cSrcweir for( it = aSections.begin(); *it < nBeginBinaryIndex; ++it ) 3556cdf0e10cSrcweir ; 3557cdf0e10cSrcweir // write first partial section 3558cdf0e10cSrcweir if( ! writeBuffer( pFontData+nBeginBinaryIndex, (*it) - nBeginBinaryIndex ) ) 3559cdf0e10cSrcweir throw FontException(); 3560cdf0e10cSrcweir // write following sections 3561cdf0e10cSrcweir while( it != aSections.end() ) 3562cdf0e10cSrcweir { 3563cdf0e10cSrcweir nIndex = (*it)+6; 3564cdf0e10cSrcweir ++it; 3565cdf0e10cSrcweir if( nIndex < nFontLen ) // last section marker is usually the EOF which has only 2 bytes 3566cdf0e10cSrcweir { 3567cdf0e10cSrcweir sal_Int32 nSectionLen = (it == aSections.end()) ? nFontLen - nIndex : (*it) - nIndex; 3568cdf0e10cSrcweir if( ! writeBuffer( pFontData+nIndex, nSectionLen ) ) 3569cdf0e10cSrcweir throw FontException(); 3570cdf0e10cSrcweir } 3571cdf0e10cSrcweir } 3572cdf0e10cSrcweir } 3573cdf0e10cSrcweir } 3574cdf0e10cSrcweir else 3575cdf0e10cSrcweir { 3576cdf0e10cSrcweir boost::shared_array<unsigned char> pWriteBuffer( new unsigned char[ nLength2 ] ); 3577cdf0e10cSrcweir rtl_zeroMemory( pWriteBuffer.get(), nLength2 ); 3578cdf0e10cSrcweir int nWriteIndex = 0; 3579cdf0e10cSrcweir 3580cdf0e10cSrcweir int nNextSectionIndex = 0; 3581cdf0e10cSrcweir for( it = aSections.begin(); it != aSections.end() && *it < nBeginBinaryIndex; ++it ) 3582cdf0e10cSrcweir ; 3583cdf0e10cSrcweir if( it != aSections.end() ) 3584cdf0e10cSrcweir nNextSectionIndex = *it; 3585cdf0e10cSrcweir for( nIndex = nBeginBinaryIndex; nIndex <= nEndBinaryIndex; nIndex++ ) 3586cdf0e10cSrcweir { 3587cdf0e10cSrcweir if( nIndex == nNextSectionIndex ) 3588cdf0e10cSrcweir { 3589cdf0e10cSrcweir nIndex += 6; 3590cdf0e10cSrcweir ++it; 3591cdf0e10cSrcweir nNextSectionIndex = (it == aSections.end() ? nFontLen : *it ); 3592cdf0e10cSrcweir } 3593cdf0e10cSrcweir unsigned char cNibble = 0x80; 3594cdf0e10cSrcweir if( pFontData[ nIndex ] >= '0' && pFontData[ nIndex ] <= '9' ) 3595cdf0e10cSrcweir cNibble = pFontData[nIndex] - '0'; 3596cdf0e10cSrcweir else if( pFontData[ nIndex ] >= 'a' && pFontData[ nIndex ] <= 'f' ) 3597cdf0e10cSrcweir cNibble = pFontData[nIndex] - 'a' + 10; 3598cdf0e10cSrcweir else if( pFontData[ nIndex ] >= 'A' && pFontData[ nIndex ] <= 'F' ) 3599cdf0e10cSrcweir cNibble = pFontData[nIndex] - 'A' + 10; 3600cdf0e10cSrcweir if( cNibble != 0x80 ) 3601cdf0e10cSrcweir { 3602cdf0e10cSrcweir if( !(nWriteIndex & 1 ) ) 3603cdf0e10cSrcweir cNibble <<= 4; 3604cdf0e10cSrcweir pWriteBuffer.get()[ nWriteIndex/2 ] |= cNibble; 3605cdf0e10cSrcweir nWriteIndex++; 3606cdf0e10cSrcweir } 3607cdf0e10cSrcweir } 3608cdf0e10cSrcweir if( ! writeBuffer( pWriteBuffer.get(), nLength2 ) ) 3609cdf0e10cSrcweir throw FontException(); 3610cdf0e10cSrcweir if( aSections.empty() ) 3611cdf0e10cSrcweir { 3612cdf0e10cSrcweir if( ! writeBuffer( pFontData+nIndex, nFontLen-nIndex ) ) 3613cdf0e10cSrcweir throw FontException(); 3614cdf0e10cSrcweir } 3615cdf0e10cSrcweir else 3616cdf0e10cSrcweir { 3617cdf0e10cSrcweir // write rest of this section 3618cdf0e10cSrcweir if( nIndex < nNextSectionIndex ) 3619cdf0e10cSrcweir { 3620cdf0e10cSrcweir if( ! writeBuffer( pFontData+nIndex, nNextSectionIndex - nIndex ) ) 3621cdf0e10cSrcweir throw FontException(); 3622cdf0e10cSrcweir } 3623cdf0e10cSrcweir // write following sections 3624cdf0e10cSrcweir while( it != aSections.end() ) 3625cdf0e10cSrcweir { 3626cdf0e10cSrcweir nIndex = (*it)+6; 3627cdf0e10cSrcweir ++it; 3628cdf0e10cSrcweir if( nIndex < nFontLen ) // last section marker is usually the EOF which has only 2 bytes 3629cdf0e10cSrcweir { 3630cdf0e10cSrcweir sal_Int32 nSectionLen = (it == aSections.end()) ? nFontLen - nIndex : (*it) - nIndex; 3631cdf0e10cSrcweir if( ! writeBuffer( pFontData+nIndex, nSectionLen ) ) 3632cdf0e10cSrcweir throw FontException(); 3633cdf0e10cSrcweir } 3634cdf0e10cSrcweir } 3635cdf0e10cSrcweir } 3636cdf0e10cSrcweir } 3637cdf0e10cSrcweir endCompression(); 3638cdf0e10cSrcweir disableStreamEncryption(); 3639cdf0e10cSrcweir 3640cdf0e10cSrcweir 3641cdf0e10cSrcweir sal_uInt64 nEndStreamPos = 0; 3642cdf0e10cSrcweir osl_getFilePos( m_aFile, &nEndStreamPos ); 3643cdf0e10cSrcweir 3644cdf0e10cSrcweir // and finally close the stream 3645cdf0e10cSrcweir aLine.setLength( 0 ); 3646cdf0e10cSrcweir aLine.append( "\nendstream\nendobj\n\n" ); 3647cdf0e10cSrcweir if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) ) 3648cdf0e10cSrcweir throw FontException(); 3649cdf0e10cSrcweir 3650cdf0e10cSrcweir // write stream length object 3651cdf0e10cSrcweir aLine.setLength( 0 ); 3652cdf0e10cSrcweir if( ! updateObject( nStreamLengthObject ) ) 3653cdf0e10cSrcweir throw FontException(); 3654cdf0e10cSrcweir aLine.append( nStreamLengthObject ); 3655cdf0e10cSrcweir aLine.append( " 0 obj\n" ); 3656cdf0e10cSrcweir aLine.append( (sal_Int64)(nEndStreamPos-nBeginStreamPos ) ); 3657cdf0e10cSrcweir aLine.append( "\nendobj\n\n" ); 3658cdf0e10cSrcweir if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) ) 3659cdf0e10cSrcweir throw FontException(); 3660cdf0e10cSrcweir } 3661cdf0e10cSrcweir else 3662cdf0e10cSrcweir { 3663cdf0e10cSrcweir rtl::OStringBuffer aErrorComment( 256 ); 3664cdf0e10cSrcweir aErrorComment.append( "GetEmbedFontData failed for font \"" ); 3665cdf0e10cSrcweir aErrorComment.append( OUStringToOString( pFont->GetFamilyName(), RTL_TEXTENCODING_UTF8 ) ); 3666cdf0e10cSrcweir aErrorComment.append( '\"' ); 3667cdf0e10cSrcweir if( pFont->GetSlant() == ITALIC_NORMAL ) 3668cdf0e10cSrcweir aErrorComment.append( " italic" ); 3669cdf0e10cSrcweir else if( pFont->GetSlant() == ITALIC_OBLIQUE ) 3670cdf0e10cSrcweir aErrorComment.append( " oblique" ); 3671cdf0e10cSrcweir aErrorComment.append( " weight=" ); 3672cdf0e10cSrcweir aErrorComment.append( sal_Int32(pFont->GetWeight()) ); 3673cdf0e10cSrcweir emitComment( aErrorComment.getStr() ); 3674cdf0e10cSrcweir } 3675cdf0e10cSrcweir 3676cdf0e10cSrcweir if( nStreamObject ) 3677cdf0e10cSrcweir // write font descriptor 3678cdf0e10cSrcweir nFontDescriptor = emitFontDescriptor( pFont, aInfo, 0, nStreamObject ); 3679cdf0e10cSrcweir 3680cdf0e10cSrcweir if( nFontDescriptor ) 3681cdf0e10cSrcweir { 3682cdf0e10cSrcweir if( pEncoding ) 3683cdf0e10cSrcweir nToUnicodeStream = createToUnicodeCMap( nEncoding, &aUnicodes[0], pUnicodesPerGlyph, pEncToUnicodeIndex, sizeof(nEncoding)/sizeof(nEncoding[0]) ); 3684cdf0e10cSrcweir 3685cdf0e10cSrcweir // write font object 3686cdf0e10cSrcweir sal_Int32 nObject = createObject(); 3687cdf0e10cSrcweir if( ! updateObject( nObject ) ) 3688cdf0e10cSrcweir throw FontException(); 3689cdf0e10cSrcweir 3690cdf0e10cSrcweir OStringBuffer aLine( 1024 ); 3691cdf0e10cSrcweir aLine.append( nObject ); 3692cdf0e10cSrcweir aLine.append( " 0 obj\n" 3693cdf0e10cSrcweir "<</Type/Font/Subtype/Type1/BaseFont/" ); 3694cdf0e10cSrcweir appendName( aInfo.m_aPSName, aLine ); 3695cdf0e10cSrcweir aLine.append( "\n" ); 3696cdf0e10cSrcweir if( !pFont->mbSymbolFlag && pEncoding == 0 ) 3697cdf0e10cSrcweir aLine.append( "/Encoding/WinAnsiEncoding\n" ); 3698cdf0e10cSrcweir if( nToUnicodeStream ) 3699cdf0e10cSrcweir { 3700cdf0e10cSrcweir aLine.append( "/ToUnicode " ); 3701cdf0e10cSrcweir aLine.append( nToUnicodeStream ); 3702cdf0e10cSrcweir aLine.append( " 0 R\n" ); 3703cdf0e10cSrcweir } 3704cdf0e10cSrcweir aLine.append( "/FirstChar 0 /LastChar 255\n" 3705cdf0e10cSrcweir "/Widths[" ); 3706cdf0e10cSrcweir for( int i = 0; i < 256; i++ ) 3707cdf0e10cSrcweir { 3708cdf0e10cSrcweir aLine.append( pWidths[i] ); 3709cdf0e10cSrcweir aLine.append( ((i&15) == 15) ? "\n" : " " ); 3710cdf0e10cSrcweir } 3711cdf0e10cSrcweir aLine.append( "]\n" 3712cdf0e10cSrcweir "/FontDescriptor " ); 3713cdf0e10cSrcweir aLine.append( nFontDescriptor ); 3714cdf0e10cSrcweir aLine.append( " 0 R>>\n" 3715cdf0e10cSrcweir "endobj\n\n" ); 3716cdf0e10cSrcweir if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) ) 3717cdf0e10cSrcweir throw FontException(); 3718cdf0e10cSrcweir 3719cdf0e10cSrcweir nFontObject = nObject; 3720cdf0e10cSrcweir 3721cdf0e10cSrcweir aRet[ rEmbed.m_nNormalFontID ] = nObject; 3722cdf0e10cSrcweir 3723cdf0e10cSrcweir // write additional encodings 3724cdf0e10cSrcweir for( std::list< EmbedEncoding >::iterator enc_it = rEmbed.m_aExtendedEncodings.begin(); enc_it != rEmbed.m_aExtendedEncodings.end(); ++enc_it ) 3725cdf0e10cSrcweir { 3726cdf0e10cSrcweir sal_Int32 aEncWidths[ 256 ]; 3727cdf0e10cSrcweir // emit encoding dict 3728cdf0e10cSrcweir sal_Int32 nEncObject = createObject(); 3729cdf0e10cSrcweir if( ! updateObject( nEncObject ) ) 3730cdf0e10cSrcweir throw FontException(); 3731cdf0e10cSrcweir 3732cdf0e10cSrcweir OutputDevice* pRef = getReferenceDevice(); 3733cdf0e10cSrcweir pRef->Push( PUSH_FONT | PUSH_MAPMODE ); 3734cdf0e10cSrcweir pRef->SetMapMode( MapMode( MAP_PIXEL ) ); 3735cdf0e10cSrcweir Font aFont( pFont->GetFamilyName(), pFont->GetStyleName(), Size( 0, 1000 ) ); 3736cdf0e10cSrcweir aFont.SetWeight( pFont->GetWeight() ); 3737cdf0e10cSrcweir aFont.SetItalic( pFont->GetSlant() ); 3738cdf0e10cSrcweir aFont.SetPitch( pFont->GetPitch() ); 3739cdf0e10cSrcweir pRef->SetFont( aFont ); 3740cdf0e10cSrcweir pRef->ImplNewFont(); 3741cdf0e10cSrcweir 3742cdf0e10cSrcweir aLine.setLength( 0 ); 3743cdf0e10cSrcweir aLine.append( nEncObject ); 3744cdf0e10cSrcweir aLine.append( " 0 obj\n" 3745cdf0e10cSrcweir "<</Type/Encoding/Differences[ 0\n" ); 3746cdf0e10cSrcweir int nEncoded = 0; 3747cdf0e10cSrcweir aUnicodes.clear(); 3748cdf0e10cSrcweir for( std::vector< EmbedCode >::iterator str_it = enc_it->m_aEncVector.begin(); str_it != enc_it->m_aEncVector.end(); ++str_it ) 3749cdf0e10cSrcweir { 3750cdf0e10cSrcweir String aStr( str_it->m_aUnicode ); 3751cdf0e10cSrcweir aEncWidths[nEncoded] = pRef->GetTextWidth( aStr ); 3752cdf0e10cSrcweir nEncodedCodes[nEncoded] = str_it->m_aUnicode; 3753cdf0e10cSrcweir nEncoding[nEncoded] = sal::static_int_cast<sal_uInt8>(nEncoded); 3754cdf0e10cSrcweir pEncToUnicodeIndex[nEncoded] = static_cast<sal_Int32>(aUnicodes.size()); 3755cdf0e10cSrcweir aUnicodes.push_back( nEncodedCodes[nEncoded] ); 3756cdf0e10cSrcweir pUnicodesPerGlyph[nEncoded] = 1; 3757cdf0e10cSrcweir 3758cdf0e10cSrcweir aLine.append( " /" ); 3759cdf0e10cSrcweir aLine.append( str_it->m_aName ); 3760cdf0e10cSrcweir if( !((++nEncoded) & 15) ) 3761cdf0e10cSrcweir aLine.append( "\n" ); 3762cdf0e10cSrcweir } 3763cdf0e10cSrcweir aLine.append( "]>>\n" 3764cdf0e10cSrcweir "endobj\n\n" ); 3765cdf0e10cSrcweir 3766cdf0e10cSrcweir pRef->Pop(); 3767cdf0e10cSrcweir 3768cdf0e10cSrcweir if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) ) 3769cdf0e10cSrcweir throw FontException(); 3770cdf0e10cSrcweir 3771cdf0e10cSrcweir nToUnicodeStream = createToUnicodeCMap( nEncoding, &aUnicodes[0], pUnicodesPerGlyph, pEncToUnicodeIndex, nEncoded ); 3772cdf0e10cSrcweir 3773cdf0e10cSrcweir nObject = createObject(); 3774cdf0e10cSrcweir if( ! updateObject( nObject ) ) 3775cdf0e10cSrcweir throw FontException(); 3776cdf0e10cSrcweir 3777cdf0e10cSrcweir aLine.setLength( 0 ); 3778cdf0e10cSrcweir aLine.append( nObject ); 3779cdf0e10cSrcweir aLine.append( " 0 obj\n" 3780cdf0e10cSrcweir "<</Type/Font/Subtype/Type1/BaseFont/" ); 3781cdf0e10cSrcweir appendName( aInfo.m_aPSName, aLine ); 3782cdf0e10cSrcweir aLine.append( "\n" ); 3783cdf0e10cSrcweir aLine.append( "/Encoding " ); 3784cdf0e10cSrcweir aLine.append( nEncObject ); 3785cdf0e10cSrcweir aLine.append( " 0 R\n" ); 3786cdf0e10cSrcweir if( nToUnicodeStream ) 3787cdf0e10cSrcweir { 3788cdf0e10cSrcweir aLine.append( "/ToUnicode " ); 3789cdf0e10cSrcweir aLine.append( nToUnicodeStream ); 3790cdf0e10cSrcweir aLine.append( " 0 R\n" ); 3791cdf0e10cSrcweir } 3792cdf0e10cSrcweir aLine.append( "/FirstChar 0\n" 3793cdf0e10cSrcweir "/LastChar " ); 3794cdf0e10cSrcweir aLine.append( (sal_Int32)(nEncoded-1) ); 3795cdf0e10cSrcweir aLine.append( "\n" 3796cdf0e10cSrcweir "/Widths[" ); 3797cdf0e10cSrcweir for( int i = 0; i < nEncoded; i++ ) 3798cdf0e10cSrcweir { 3799cdf0e10cSrcweir aLine.append( aEncWidths[i] ); 3800cdf0e10cSrcweir aLine.append( ((i&15) == 15) ? "\n" : " " ); 3801cdf0e10cSrcweir } 3802cdf0e10cSrcweir aLine.append( " ]\n" 3803cdf0e10cSrcweir "/FontDescriptor " ); 3804cdf0e10cSrcweir aLine.append( nFontDescriptor ); 3805cdf0e10cSrcweir aLine.append( " 0 R>>\n" 3806cdf0e10cSrcweir "endobj\n\n" ); 3807cdf0e10cSrcweir if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) ) 3808cdf0e10cSrcweir throw FontException(); 3809cdf0e10cSrcweir 3810cdf0e10cSrcweir aRet[ enc_it->m_nFontID ] = nObject; 3811cdf0e10cSrcweir } 3812cdf0e10cSrcweir } 3813cdf0e10cSrcweir } 3814cdf0e10cSrcweir catch( FontException& ) 3815cdf0e10cSrcweir { 3816cdf0e10cSrcweir // these do nothing in case there was no compression or encryption ongoing 3817cdf0e10cSrcweir endCompression(); 3818cdf0e10cSrcweir disableStreamEncryption(); 3819cdf0e10cSrcweir } 3820cdf0e10cSrcweir 3821cdf0e10cSrcweir if( pFontData ) 3822cdf0e10cSrcweir m_pReferenceDevice->mpGraphics->FreeEmbedFontData( pFontData, nFontLen ); 3823cdf0e10cSrcweir 3824cdf0e10cSrcweir return aRet; 3825cdf0e10cSrcweir } 3826cdf0e10cSrcweir 3827cdf0e10cSrcweir static void appendSubsetName( int nSubsetID, const OUString& rPSName, OStringBuffer& rBuffer ) 3828cdf0e10cSrcweir { 3829cdf0e10cSrcweir if( nSubsetID ) 3830cdf0e10cSrcweir { 3831cdf0e10cSrcweir for( int i = 0; i < 6; i++ ) 3832cdf0e10cSrcweir { 3833cdf0e10cSrcweir int nOffset = (nSubsetID % 26); 3834cdf0e10cSrcweir nSubsetID /= 26; 3835cdf0e10cSrcweir rBuffer.append( (sal_Char)('A'+nOffset) ); 3836cdf0e10cSrcweir } 3837cdf0e10cSrcweir rBuffer.append( '+' ); 3838cdf0e10cSrcweir } 3839cdf0e10cSrcweir appendName( rPSName, rBuffer ); 3840cdf0e10cSrcweir } 3841cdf0e10cSrcweir 3842cdf0e10cSrcweir sal_Int32 PDFWriterImpl::createToUnicodeCMap( sal_uInt8* pEncoding, 3843cdf0e10cSrcweir sal_Ucs* pUnicodes, 3844cdf0e10cSrcweir sal_Int32* pUnicodesPerGlyph, 3845cdf0e10cSrcweir sal_Int32* pEncToUnicodeIndex, 3846cdf0e10cSrcweir int nGlyphs ) 3847cdf0e10cSrcweir { 3848cdf0e10cSrcweir int nMapped = 0, n = 0; 3849cdf0e10cSrcweir for( n = 0; n < nGlyphs; n++ ) 3850cdf0e10cSrcweir if( pUnicodes[pEncToUnicodeIndex[n]] && pUnicodesPerGlyph[n] ) 3851cdf0e10cSrcweir nMapped++; 3852cdf0e10cSrcweir 3853cdf0e10cSrcweir if( nMapped == 0 ) 3854cdf0e10cSrcweir return 0; 3855cdf0e10cSrcweir 3856cdf0e10cSrcweir sal_Int32 nStream = createObject(); 3857cdf0e10cSrcweir CHECK_RETURN( updateObject( nStream ) ); 3858cdf0e10cSrcweir 3859cdf0e10cSrcweir OStringBuffer aContents( 1024 ); 3860cdf0e10cSrcweir aContents.append( 3861cdf0e10cSrcweir "/CIDInit/ProcSet findresource begin\n" 3862cdf0e10cSrcweir "12 dict begin\n" 3863cdf0e10cSrcweir "begincmap\n" 3864cdf0e10cSrcweir "/CIDSystemInfo<<\n" 3865cdf0e10cSrcweir "/Registry (Adobe)\n" 3866cdf0e10cSrcweir "/Ordering (UCS)\n" 3867cdf0e10cSrcweir "/Supplement 0\n" 3868cdf0e10cSrcweir ">> def\n" 3869cdf0e10cSrcweir "/CMapName/Adobe-Identity-UCS def\n" 3870cdf0e10cSrcweir "/CMapType 2 def\n" 3871cdf0e10cSrcweir "1 begincodespacerange\n" 3872cdf0e10cSrcweir "<00> <FF>\n" 3873cdf0e10cSrcweir "endcodespacerange\n" 3874cdf0e10cSrcweir ); 3875cdf0e10cSrcweir int nCount = 0; 3876cdf0e10cSrcweir for( n = 0; n < nGlyphs; n++ ) 3877cdf0e10cSrcweir { 3878cdf0e10cSrcweir if( pUnicodes[pEncToUnicodeIndex[n]] && pUnicodesPerGlyph[n] ) 3879cdf0e10cSrcweir { 3880cdf0e10cSrcweir if( (nCount % 100) == 0 ) 3881cdf0e10cSrcweir { 3882cdf0e10cSrcweir if( nCount ) 3883cdf0e10cSrcweir aContents.append( "endbfchar\n" ); 3884cdf0e10cSrcweir aContents.append( (sal_Int32)((nMapped-nCount > 100) ? 100 : nMapped-nCount ) ); 3885cdf0e10cSrcweir aContents.append( " beginbfchar\n" ); 3886cdf0e10cSrcweir } 3887cdf0e10cSrcweir aContents.append( '<' ); 3888cdf0e10cSrcweir appendHex( (sal_Int8)pEncoding[n], aContents ); 3889cdf0e10cSrcweir aContents.append( "> <" ); 3890cdf0e10cSrcweir // TODO: handle unicodes>U+FFFF 3891cdf0e10cSrcweir sal_Int32 nIndex = pEncToUnicodeIndex[n]; 3892cdf0e10cSrcweir for( sal_Int32 j = 0; j < pUnicodesPerGlyph[n]; j++ ) 3893cdf0e10cSrcweir { 3894cdf0e10cSrcweir appendHex( (sal_Int8)(pUnicodes[nIndex + j] / 256), aContents ); 3895cdf0e10cSrcweir appendHex( (sal_Int8)(pUnicodes[nIndex + j] & 255), aContents ); 3896cdf0e10cSrcweir } 3897cdf0e10cSrcweir aContents.append( ">\n" ); 3898cdf0e10cSrcweir nCount++; 3899cdf0e10cSrcweir } 3900cdf0e10cSrcweir } 3901cdf0e10cSrcweir aContents.append( "endbfchar\n" 3902cdf0e10cSrcweir "endcmap\n" 3903cdf0e10cSrcweir "CMapName currentdict /CMap defineresource pop\n" 3904cdf0e10cSrcweir "end\n" 3905cdf0e10cSrcweir "end\n" ); 3906cdf0e10cSrcweir #ifndef DEBUG_DISABLE_PDFCOMPRESSION 3907cdf0e10cSrcweir ZCodec* pCodec = new ZCodec( 0x4000, 0x4000 ); 3908cdf0e10cSrcweir SvMemoryStream aStream; 3909cdf0e10cSrcweir pCodec->BeginCompression(); 3910cdf0e10cSrcweir pCodec->Write( aStream, (const sal_uInt8*)aContents.getStr(), aContents.getLength() ); 3911cdf0e10cSrcweir pCodec->EndCompression(); 3912cdf0e10cSrcweir delete pCodec; 3913cdf0e10cSrcweir #endif 3914cdf0e10cSrcweir 3915cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 3916cdf0e10cSrcweir emitComment( "PDFWriterImpl::createToUnicodeCMap" ); 3917cdf0e10cSrcweir #endif 3918cdf0e10cSrcweir OStringBuffer aLine( 40 ); 3919cdf0e10cSrcweir 3920cdf0e10cSrcweir aLine.append( nStream ); 3921cdf0e10cSrcweir aLine.append( " 0 obj\n<</Length " ); 3922cdf0e10cSrcweir #ifndef DEBUG_DISABLE_PDFCOMPRESSION 3923cdf0e10cSrcweir sal_Int32 nLen = (sal_Int32)aStream.Tell(); 3924cdf0e10cSrcweir aStream.Seek( 0 ); 3925cdf0e10cSrcweir aLine.append( nLen ); 3926cdf0e10cSrcweir aLine.append( "/Filter/FlateDecode" ); 3927cdf0e10cSrcweir #else 3928cdf0e10cSrcweir aLine.append( aContents.getLength() ); 3929cdf0e10cSrcweir #endif 3930cdf0e10cSrcweir aLine.append( ">>\nstream\n" ); 3931cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) ); 3932cdf0e10cSrcweir checkAndEnableStreamEncryption( nStream ); 3933cdf0e10cSrcweir #ifndef DEBUG_DISABLE_PDFCOMPRESSION 3934cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aStream.GetData(), nLen ) ); 3935cdf0e10cSrcweir #else 3936cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aContents.getStr(), aContents.getLength() ) ); 3937cdf0e10cSrcweir #endif 3938cdf0e10cSrcweir disableStreamEncryption(); 3939cdf0e10cSrcweir aLine.setLength( 0 ); 3940cdf0e10cSrcweir aLine.append( "\nendstream\n" 3941cdf0e10cSrcweir "endobj\n\n" ); 3942cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) ); 3943cdf0e10cSrcweir return nStream; 3944cdf0e10cSrcweir } 3945cdf0e10cSrcweir 3946cdf0e10cSrcweir sal_Int32 PDFWriterImpl::emitFontDescriptor( const ImplFontData* pFont, FontSubsetInfo& rInfo, sal_Int32 nSubsetID, sal_Int32 nFontStream ) 3947cdf0e10cSrcweir { 3948cdf0e10cSrcweir OStringBuffer aLine( 1024 ); 3949cdf0e10cSrcweir // get font flags, see PDF reference 1.4 p. 358 3950cdf0e10cSrcweir // possibly characters outside Adobe standard encoding 3951cdf0e10cSrcweir // so set Symbolic flag 3952cdf0e10cSrcweir sal_Int32 nFontFlags = (1<<2); 3953cdf0e10cSrcweir if( pFont->GetSlant() == ITALIC_NORMAL || pFont->GetSlant() == ITALIC_OBLIQUE ) 3954cdf0e10cSrcweir nFontFlags |= (1 << 6); 3955cdf0e10cSrcweir if( pFont->GetPitch() == PITCH_FIXED ) 3956cdf0e10cSrcweir nFontFlags |= 1; 3957cdf0e10cSrcweir if( pFont->GetFamilyType() == FAMILY_SCRIPT ) 3958cdf0e10cSrcweir nFontFlags |= (1 << 3); 3959cdf0e10cSrcweir else if( pFont->GetFamilyType() == FAMILY_ROMAN ) 3960cdf0e10cSrcweir nFontFlags |= (1 << 1); 3961cdf0e10cSrcweir 3962cdf0e10cSrcweir sal_Int32 nFontDescriptor = createObject(); 3963cdf0e10cSrcweir CHECK_RETURN( updateObject( nFontDescriptor ) ); 3964cdf0e10cSrcweir aLine.setLength( 0 ); 3965cdf0e10cSrcweir aLine.append( nFontDescriptor ); 3966cdf0e10cSrcweir aLine.append( " 0 obj\n" 3967cdf0e10cSrcweir "<</Type/FontDescriptor/FontName/" ); 3968cdf0e10cSrcweir appendSubsetName( nSubsetID, rInfo.m_aPSName, aLine ); 3969cdf0e10cSrcweir aLine.append( "\n" 3970cdf0e10cSrcweir "/Flags " ); 3971cdf0e10cSrcweir aLine.append( nFontFlags ); 3972cdf0e10cSrcweir aLine.append( "\n" 3973cdf0e10cSrcweir "/FontBBox[" ); 3974cdf0e10cSrcweir // note: Top and Bottom are reversed in VCL and PDF rectangles 3975cdf0e10cSrcweir aLine.append( (sal_Int32)rInfo.m_aFontBBox.TopLeft().X() ); 3976cdf0e10cSrcweir aLine.append( ' ' ); 3977cdf0e10cSrcweir aLine.append( (sal_Int32)rInfo.m_aFontBBox.TopLeft().Y() ); 3978cdf0e10cSrcweir aLine.append( ' ' ); 3979cdf0e10cSrcweir aLine.append( (sal_Int32)rInfo.m_aFontBBox.BottomRight().X() ); 3980cdf0e10cSrcweir aLine.append( ' ' ); 3981cdf0e10cSrcweir aLine.append( (sal_Int32)(rInfo.m_aFontBBox.BottomRight().Y()+1) ); 3982cdf0e10cSrcweir aLine.append( "]/ItalicAngle " ); 3983cdf0e10cSrcweir if( pFont->GetSlant() == ITALIC_OBLIQUE || pFont->GetSlant() == ITALIC_NORMAL ) 3984cdf0e10cSrcweir aLine.append( "-30" ); 3985cdf0e10cSrcweir else 3986cdf0e10cSrcweir aLine.append( "0" ); 3987cdf0e10cSrcweir aLine.append( "\n" 3988cdf0e10cSrcweir "/Ascent " ); 3989cdf0e10cSrcweir aLine.append( (sal_Int32)rInfo.m_nAscent ); 3990cdf0e10cSrcweir aLine.append( "\n" 3991cdf0e10cSrcweir "/Descent " ); 3992cdf0e10cSrcweir aLine.append( (sal_Int32)-rInfo.m_nDescent ); 3993cdf0e10cSrcweir aLine.append( "\n" 3994cdf0e10cSrcweir "/CapHeight " ); 3995cdf0e10cSrcweir aLine.append( (sal_Int32)rInfo.m_nCapHeight ); 3996cdf0e10cSrcweir // According to PDF reference 1.4 StemV is required 3997cdf0e10cSrcweir // seems a tad strange to me, but well ... 3998cdf0e10cSrcweir aLine.append( "\n" 3999cdf0e10cSrcweir "/StemV 80\n" ); 4000cdf0e10cSrcweir if( nFontStream ) 4001cdf0e10cSrcweir { 4002cdf0e10cSrcweir aLine.append( "/FontFile" ); 4003cdf0e10cSrcweir switch( rInfo.m_nFontType ) 4004cdf0e10cSrcweir { 4005cdf0e10cSrcweir case FontSubsetInfo::SFNT_TTF: 4006cdf0e10cSrcweir aLine.append( '2' ); 4007cdf0e10cSrcweir break; 4008cdf0e10cSrcweir case FontSubsetInfo::TYPE1_PFA: 4009cdf0e10cSrcweir case FontSubsetInfo::TYPE1_PFB: 4010cdf0e10cSrcweir case FontSubsetInfo::ANY_TYPE1: 4011cdf0e10cSrcweir break; 4012cdf0e10cSrcweir default: 4013cdf0e10cSrcweir DBG_ERROR( "unknown fonttype in PDF font descriptor" ); 4014cdf0e10cSrcweir return 0; 4015cdf0e10cSrcweir } 4016cdf0e10cSrcweir aLine.append( ' ' ); 4017cdf0e10cSrcweir aLine.append( nFontStream ); 4018cdf0e10cSrcweir aLine.append( " 0 R\n" ); 4019cdf0e10cSrcweir } 4020cdf0e10cSrcweir aLine.append( ">>\n" 4021cdf0e10cSrcweir "endobj\n\n" ); 4022cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) ); 4023cdf0e10cSrcweir 4024cdf0e10cSrcweir return nFontDescriptor; 4025cdf0e10cSrcweir } 4026cdf0e10cSrcweir 4027cdf0e10cSrcweir void PDFWriterImpl::appendBuiltinFontsToDict( OStringBuffer& rDict ) const 4028cdf0e10cSrcweir { 4029cdf0e10cSrcweir for( std::map< sal_Int32, sal_Int32 >::const_iterator it = 4030cdf0e10cSrcweir m_aBuiltinFontToObjectMap.begin(); it != m_aBuiltinFontToObjectMap.end(); ++it ) 4031cdf0e10cSrcweir { 4032cdf0e10cSrcweir rDict.append( m_aBuiltinFonts[it->first].getNameObject() ); 4033cdf0e10cSrcweir rDict.append( ' ' ); 4034cdf0e10cSrcweir rDict.append( it->second ); 4035cdf0e10cSrcweir rDict.append( " 0 R" ); 4036cdf0e10cSrcweir } 4037cdf0e10cSrcweir } 4038cdf0e10cSrcweir 4039cdf0e10cSrcweir bool PDFWriterImpl::emitFonts() 4040cdf0e10cSrcweir { 4041cdf0e10cSrcweir if( ! m_pReferenceDevice->ImplGetGraphics() ) 4042cdf0e10cSrcweir return false; 4043cdf0e10cSrcweir 4044cdf0e10cSrcweir OStringBuffer aLine( 1024 ); 4045cdf0e10cSrcweir 4046cdf0e10cSrcweir std::map< sal_Int32, sal_Int32 > aFontIDToObject; 4047cdf0e10cSrcweir 4048cdf0e10cSrcweir OUString aTmpName; 4049cdf0e10cSrcweir osl_createTempFile( NULL, NULL, &aTmpName.pData ); 4050cdf0e10cSrcweir for( FontSubsetData::iterator it = m_aSubsets.begin(); it != m_aSubsets.end(); ++it ) 4051cdf0e10cSrcweir { 4052cdf0e10cSrcweir for( FontEmitList::iterator lit = it->second.m_aSubsets.begin(); lit != it->second.m_aSubsets.end(); ++lit ) 4053cdf0e10cSrcweir { 4054cdf0e10cSrcweir sal_Int32 pGlyphIDs[ 256 ]; 4055cdf0e10cSrcweir sal_Int32 pWidths[ 256 ]; 4056cdf0e10cSrcweir sal_uInt8 pEncoding[ 256 ]; 4057cdf0e10cSrcweir sal_Int32 pEncToUnicodeIndex[ 256 ]; 4058cdf0e10cSrcweir sal_Int32 pUnicodesPerGlyph[ 256 ]; 4059cdf0e10cSrcweir std::vector<sal_Ucs> aUnicodes; 4060cdf0e10cSrcweir aUnicodes.reserve( 256 ); 4061cdf0e10cSrcweir int nGlyphs = 1; 4062cdf0e10cSrcweir // fill arrays and prepare encoding index map 4063cdf0e10cSrcweir sal_Int32 nToUnicodeStream = 0; 4064cdf0e10cSrcweir 4065cdf0e10cSrcweir rtl_zeroMemory( pGlyphIDs, sizeof( pGlyphIDs ) ); 4066cdf0e10cSrcweir rtl_zeroMemory( pEncoding, sizeof( pEncoding ) ); 4067cdf0e10cSrcweir rtl_zeroMemory( pUnicodesPerGlyph, sizeof( pUnicodesPerGlyph ) ); 4068cdf0e10cSrcweir rtl_zeroMemory( pEncToUnicodeIndex, sizeof( pEncToUnicodeIndex ) ); 4069cdf0e10cSrcweir for( FontEmitMapping::iterator fit = lit->m_aMapping.begin(); fit != lit->m_aMapping.end();++fit ) 4070cdf0e10cSrcweir { 4071cdf0e10cSrcweir sal_uInt8 nEnc = fit->second.getGlyphId(); 4072cdf0e10cSrcweir 4073cdf0e10cSrcweir DBG_ASSERT( pGlyphIDs[nEnc] == 0 && pEncoding[nEnc] == 0, "duplicate glyph" ); 4074cdf0e10cSrcweir DBG_ASSERT( nEnc <= lit->m_aMapping.size(), "invalid glyph encoding" ); 4075cdf0e10cSrcweir 4076cdf0e10cSrcweir pGlyphIDs[ nEnc ] = fit->first; 4077cdf0e10cSrcweir pEncoding[ nEnc ] = nEnc; 4078cdf0e10cSrcweir pEncToUnicodeIndex[ nEnc ] = static_cast<sal_Int32>(aUnicodes.size()); 4079cdf0e10cSrcweir pUnicodesPerGlyph[ nEnc ] = fit->second.countCodes(); 4080cdf0e10cSrcweir for( sal_Int32 n = 0; n < pUnicodesPerGlyph[ nEnc ]; n++ ) 4081cdf0e10cSrcweir aUnicodes.push_back( fit->second.getCode( n ) ); 4082cdf0e10cSrcweir if( fit->second.getCode(0) ) 4083cdf0e10cSrcweir nToUnicodeStream = 1; 4084cdf0e10cSrcweir if( nGlyphs < 256 ) 4085cdf0e10cSrcweir nGlyphs++; 4086cdf0e10cSrcweir else 4087cdf0e10cSrcweir { 4088cdf0e10cSrcweir DBG_ERROR( "too many glyphs for subset" ); 4089cdf0e10cSrcweir } 4090cdf0e10cSrcweir } 4091cdf0e10cSrcweir FontSubsetInfo aSubsetInfo; 4092cdf0e10cSrcweir if( m_pReferenceDevice->mpGraphics->CreateFontSubset( aTmpName, it->first, pGlyphIDs, pEncoding, pWidths, nGlyphs, aSubsetInfo ) ) 4093cdf0e10cSrcweir { 4094cdf0e10cSrcweir // create font stream 4095cdf0e10cSrcweir oslFileHandle aFontFile; 4096cdf0e10cSrcweir CHECK_RETURN( (osl_File_E_None == osl_openFile( aTmpName.pData, &aFontFile, osl_File_OpenFlag_Read ) ) ); 4097cdf0e10cSrcweir // get file size 4098cdf0e10cSrcweir sal_uInt64 nLength1; 4099cdf0e10cSrcweir CHECK_RETURN( (osl_File_E_None == osl_setFilePos( aFontFile, osl_Pos_End, 0 ) ) ); 4100cdf0e10cSrcweir CHECK_RETURN( (osl_File_E_None == osl_getFilePos( aFontFile, &nLength1 ) ) ); 4101cdf0e10cSrcweir CHECK_RETURN( (osl_File_E_None == osl_setFilePos( aFontFile, osl_Pos_Absolut, 0 ) ) ); 4102cdf0e10cSrcweir 4103cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 4104cdf0e10cSrcweir emitComment( "PDFWriterImpl::emitFonts" ); 4105cdf0e10cSrcweir #endif 4106cdf0e10cSrcweir sal_Int32 nFontStream = createObject(); 4107cdf0e10cSrcweir sal_Int32 nStreamLengthObject = createObject(); 4108cdf0e10cSrcweir CHECK_RETURN( updateObject( nFontStream ) ); 4109cdf0e10cSrcweir aLine.setLength( 0 ); 4110cdf0e10cSrcweir aLine.append( nFontStream ); 4111cdf0e10cSrcweir aLine.append( " 0 obj\n" 4112cdf0e10cSrcweir "<</Length " ); 4113cdf0e10cSrcweir aLine.append( (sal_Int32)nStreamLengthObject ); 4114cdf0e10cSrcweir aLine.append( " 0 R" 4115cdf0e10cSrcweir #ifndef DEBUG_DISABLE_PDFCOMPRESSION 4116cdf0e10cSrcweir "/Filter/FlateDecode" 4117cdf0e10cSrcweir #endif 4118cdf0e10cSrcweir "/Length1 " ); 4119cdf0e10cSrcweir 4120cdf0e10cSrcweir sal_uInt64 nStartPos = 0; 4121cdf0e10cSrcweir if( aSubsetInfo.m_nFontType == FontSubsetInfo::SFNT_TTF ) 4122cdf0e10cSrcweir { 4123cdf0e10cSrcweir aLine.append( (sal_Int32)nLength1 ); 4124cdf0e10cSrcweir 4125cdf0e10cSrcweir aLine.append( ">>\n" 4126cdf0e10cSrcweir "stream\n" ); 4127cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) ); 4128cdf0e10cSrcweir CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nStartPos ) ) ); 4129cdf0e10cSrcweir 4130cdf0e10cSrcweir // copy font file 4131cdf0e10cSrcweir beginCompression(); 4132cdf0e10cSrcweir checkAndEnableStreamEncryption( nFontStream ); 4133cdf0e10cSrcweir sal_Bool bEOF = sal_False; 4134cdf0e10cSrcweir do 4135cdf0e10cSrcweir { 4136cdf0e10cSrcweir char buf[8192]; 4137cdf0e10cSrcweir sal_uInt64 nRead; 4138cdf0e10cSrcweir CHECK_RETURN( (osl_File_E_None == osl_readFile( aFontFile, buf, sizeof( buf ), &nRead ) ) ); 4139cdf0e10cSrcweir CHECK_RETURN( writeBuffer( buf, nRead ) ); 4140cdf0e10cSrcweir CHECK_RETURN( (osl_File_E_None == osl_isEndOfFile( aFontFile, &bEOF ) ) ); 4141cdf0e10cSrcweir } while( ! bEOF ); 4142cdf0e10cSrcweir } 4143cdf0e10cSrcweir else if( (aSubsetInfo.m_nFontType & FontSubsetInfo::CFF_FONT) != 0 ) 4144cdf0e10cSrcweir { 4145cdf0e10cSrcweir // TODO: implement 4146cdf0e10cSrcweir DBG_ERROR( "PDFWriterImpl does not support CFF-font subsets yet!" ); 4147cdf0e10cSrcweir } 4148cdf0e10cSrcweir else if( (aSubsetInfo.m_nFontType & FontSubsetInfo::TYPE1_PFB) != 0 ) // TODO: also support PFA? 4149cdf0e10cSrcweir { 4150cdf0e10cSrcweir boost::shared_array<unsigned char> pBuffer( new unsigned char[ nLength1 ] ); 4151cdf0e10cSrcweir 4152cdf0e10cSrcweir sal_uInt64 nBytesRead = 0; 4153cdf0e10cSrcweir CHECK_RETURN( (osl_File_E_None == osl_readFile( aFontFile, pBuffer.get(), nLength1, &nBytesRead ) ) ); 4154cdf0e10cSrcweir DBG_ASSERT( nBytesRead==nLength1, "PDF-FontSubset read incomplete!" ); 4155cdf0e10cSrcweir CHECK_RETURN( (osl_File_E_None == osl_setFilePos( aFontFile, osl_Pos_Absolut, 0 ) ) ); 4156cdf0e10cSrcweir // get the PFB-segment lengths 4157cdf0e10cSrcweir ThreeInts aSegmentLengths = {0,0,0}; 4158cdf0e10cSrcweir getPfbSegmentLengths( pBuffer.get(), (int)nBytesRead, aSegmentLengths ); 4159cdf0e10cSrcweir // the lengths below are mandatory for PDF-exported Type1 fonts 4160cdf0e10cSrcweir // because the PFB segment headers get stripped! WhyOhWhy. 4161cdf0e10cSrcweir aLine.append( (sal_Int32)aSegmentLengths[0] ); 4162cdf0e10cSrcweir aLine.append( "/Length2 " ); 4163cdf0e10cSrcweir aLine.append( (sal_Int32)aSegmentLengths[1] ); 4164cdf0e10cSrcweir aLine.append( "/Length3 " ); 4165cdf0e10cSrcweir aLine.append( (sal_Int32)aSegmentLengths[2] ); 4166cdf0e10cSrcweir 4167cdf0e10cSrcweir aLine.append( ">>\n" 4168cdf0e10cSrcweir "stream\n" ); 4169cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) ); 4170cdf0e10cSrcweir CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nStartPos ) ) ); 4171cdf0e10cSrcweir 4172cdf0e10cSrcweir // emit PFB-sections without section headers 4173cdf0e10cSrcweir beginCompression(); 4174cdf0e10cSrcweir checkAndEnableStreamEncryption( nFontStream ); 4175cdf0e10cSrcweir CHECK_RETURN( writeBuffer( &pBuffer[6], aSegmentLengths[0] ) ); 4176cdf0e10cSrcweir CHECK_RETURN( writeBuffer( &pBuffer[12] + aSegmentLengths[0], aSegmentLengths[1] ) ); 4177cdf0e10cSrcweir CHECK_RETURN( writeBuffer( &pBuffer[18] + aSegmentLengths[0] + aSegmentLengths[1], aSegmentLengths[2] ) ); 4178cdf0e10cSrcweir } 4179cdf0e10cSrcweir else 4180cdf0e10cSrcweir { 4181cdf0e10cSrcweir fprintf( stderr, "PDF: CreateFontSubset result in not yet supported format=%d\n",aSubsetInfo.m_nFontType); 4182cdf0e10cSrcweir aLine.append( "0 >>\nstream\n" ); 4183cdf0e10cSrcweir } 4184cdf0e10cSrcweir 4185cdf0e10cSrcweir endCompression(); 4186cdf0e10cSrcweir disableStreamEncryption(); 4187cdf0e10cSrcweir // close the file 4188cdf0e10cSrcweir osl_closeFile( aFontFile ); 4189cdf0e10cSrcweir 4190cdf0e10cSrcweir sal_uInt64 nEndPos = 0; 4191cdf0e10cSrcweir CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nEndPos ) ) ); 4192cdf0e10cSrcweir // end the stream 4193cdf0e10cSrcweir aLine.setLength( 0 ); 4194cdf0e10cSrcweir aLine.append( "\nendstream\nendobj\n\n" ); 4195cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) ); 4196cdf0e10cSrcweir 4197cdf0e10cSrcweir // emit stream length object 4198cdf0e10cSrcweir CHECK_RETURN( updateObject( nStreamLengthObject ) ); 4199cdf0e10cSrcweir aLine.setLength( 0 ); 4200cdf0e10cSrcweir aLine.append( nStreamLengthObject ); 4201cdf0e10cSrcweir aLine.append( " 0 obj\n" ); 4202cdf0e10cSrcweir aLine.append( (sal_Int64)(nEndPos-nStartPos) ); 4203cdf0e10cSrcweir aLine.append( "\nendobj\n\n" ); 4204cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) ); 4205cdf0e10cSrcweir 4206cdf0e10cSrcweir // write font descriptor 4207cdf0e10cSrcweir sal_Int32 nFontDescriptor = emitFontDescriptor( it->first, aSubsetInfo, lit->m_nFontID, nFontStream ); 4208cdf0e10cSrcweir 4209cdf0e10cSrcweir if( nToUnicodeStream ) 4210cdf0e10cSrcweir nToUnicodeStream = createToUnicodeCMap( pEncoding, &aUnicodes[0], pUnicodesPerGlyph, pEncToUnicodeIndex, nGlyphs ); 4211cdf0e10cSrcweir 4212cdf0e10cSrcweir sal_Int32 nFontObject = createObject(); 4213cdf0e10cSrcweir CHECK_RETURN( updateObject( nFontObject ) ); 4214cdf0e10cSrcweir aLine.setLength( 0 ); 4215cdf0e10cSrcweir aLine.append( nFontObject ); 4216cdf0e10cSrcweir 4217cdf0e10cSrcweir aLine.append( " 0 obj\n" ); 4218cdf0e10cSrcweir aLine.append( ((aSubsetInfo.m_nFontType & FontSubsetInfo::ANY_TYPE1) != 0) ? 4219cdf0e10cSrcweir "<</Type/Font/Subtype/Type1/BaseFont/" : 4220cdf0e10cSrcweir "<</Type/Font/Subtype/TrueType/BaseFont/" ); 4221cdf0e10cSrcweir appendSubsetName( lit->m_nFontID, aSubsetInfo.m_aPSName, aLine ); 4222cdf0e10cSrcweir aLine.append( "\n" 4223cdf0e10cSrcweir "/FirstChar 0\n" 4224cdf0e10cSrcweir "/LastChar " ); 4225cdf0e10cSrcweir aLine.append( (sal_Int32)(nGlyphs-1) ); 4226cdf0e10cSrcweir aLine.append( "\n" 4227cdf0e10cSrcweir "/Widths[" ); 4228cdf0e10cSrcweir for( int i = 0; i < nGlyphs; i++ ) 4229cdf0e10cSrcweir { 4230cdf0e10cSrcweir aLine.append( pWidths[ i ] ); 4231cdf0e10cSrcweir aLine.append( ((i & 15) == 15) ? "\n" : " " ); 4232cdf0e10cSrcweir } 4233cdf0e10cSrcweir aLine.append( "]\n" 4234cdf0e10cSrcweir "/FontDescriptor " ); 4235cdf0e10cSrcweir aLine.append( nFontDescriptor ); 4236cdf0e10cSrcweir aLine.append( " 0 R\n" ); 4237cdf0e10cSrcweir if( nToUnicodeStream ) 4238cdf0e10cSrcweir { 4239cdf0e10cSrcweir aLine.append( "/ToUnicode " ); 4240cdf0e10cSrcweir aLine.append( nToUnicodeStream ); 4241cdf0e10cSrcweir aLine.append( " 0 R\n" ); 4242cdf0e10cSrcweir } 4243cdf0e10cSrcweir aLine.append( ">>\n" 4244cdf0e10cSrcweir "endobj\n\n" ); 4245cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) ); 4246cdf0e10cSrcweir 4247cdf0e10cSrcweir aFontIDToObject[ lit->m_nFontID ] = nFontObject; 4248cdf0e10cSrcweir } 4249cdf0e10cSrcweir else 4250cdf0e10cSrcweir { 4251cdf0e10cSrcweir const ImplFontData* pFont = it->first; 4252cdf0e10cSrcweir rtl::OStringBuffer aErrorComment( 256 ); 4253cdf0e10cSrcweir aErrorComment.append( "CreateFontSubset failed for font \"" ); 4254cdf0e10cSrcweir aErrorComment.append( OUStringToOString( pFont->GetFamilyName(), RTL_TEXTENCODING_UTF8 ) ); 4255cdf0e10cSrcweir aErrorComment.append( '\"' ); 4256cdf0e10cSrcweir if( pFont->GetSlant() == ITALIC_NORMAL ) 4257cdf0e10cSrcweir aErrorComment.append( " italic" ); 4258cdf0e10cSrcweir else if( pFont->GetSlant() == ITALIC_OBLIQUE ) 4259cdf0e10cSrcweir aErrorComment.append( " oblique" ); 4260cdf0e10cSrcweir aErrorComment.append( " weight=" ); 4261cdf0e10cSrcweir aErrorComment.append( sal_Int32(pFont->GetWeight()) ); 4262cdf0e10cSrcweir emitComment( aErrorComment.getStr() ); 4263cdf0e10cSrcweir } 4264cdf0e10cSrcweir } 4265cdf0e10cSrcweir } 4266cdf0e10cSrcweir osl_removeFile( aTmpName.pData ); 4267cdf0e10cSrcweir 4268cdf0e10cSrcweir // emit embedded fonts 4269cdf0e10cSrcweir for( FontEmbedData::iterator eit = m_aEmbeddedFonts.begin(); eit != m_aEmbeddedFonts.end(); ++eit ) 4270cdf0e10cSrcweir { 4271cdf0e10cSrcweir std::map< sal_Int32, sal_Int32 > aObjects = emitEmbeddedFont( eit->first, eit->second ); 4272cdf0e10cSrcweir for( std::map< sal_Int32, sal_Int32 >::iterator fit = aObjects.begin(); fit != aObjects.end(); ++fit ) 4273cdf0e10cSrcweir { 4274cdf0e10cSrcweir CHECK_RETURN( fit->second ); 4275cdf0e10cSrcweir aFontIDToObject[ fit->first ] = fit->second; 4276cdf0e10cSrcweir } 4277cdf0e10cSrcweir } 4278cdf0e10cSrcweir 4279cdf0e10cSrcweir // emit system fonts 4280cdf0e10cSrcweir for( FontEmbedData::iterator sit = m_aSystemFonts.begin(); sit != m_aSystemFonts.end(); ++sit ) 4281cdf0e10cSrcweir { 4282cdf0e10cSrcweir std::map< sal_Int32, sal_Int32 > aObjects = emitSystemFont( sit->first, sit->second ); 4283cdf0e10cSrcweir for( std::map< sal_Int32, sal_Int32 >::iterator fit = aObjects.begin(); fit != aObjects.end(); ++fit ) 4284cdf0e10cSrcweir { 4285cdf0e10cSrcweir CHECK_RETURN( fit->second ); 4286cdf0e10cSrcweir aFontIDToObject[ fit->first ] = fit->second; 4287cdf0e10cSrcweir } 4288cdf0e10cSrcweir } 4289cdf0e10cSrcweir 4290cdf0e10cSrcweir OStringBuffer aFontDict( 1024 ); 4291cdf0e10cSrcweir aFontDict.append( getFontDictObject() ); 4292cdf0e10cSrcweir aFontDict.append( " 0 obj\n" 4293cdf0e10cSrcweir "<<" ); 4294cdf0e10cSrcweir int ni = 0; 4295cdf0e10cSrcweir for( std::map< sal_Int32, sal_Int32 >::iterator mit = aFontIDToObject.begin(); mit != aFontIDToObject.end(); ++mit ) 4296cdf0e10cSrcweir { 4297cdf0e10cSrcweir aFontDict.append( "/F" ); 4298cdf0e10cSrcweir aFontDict.append( mit->first ); 4299cdf0e10cSrcweir aFontDict.append( ' ' ); 4300cdf0e10cSrcweir aFontDict.append( mit->second ); 4301cdf0e10cSrcweir aFontDict.append( " 0 R" ); 4302cdf0e10cSrcweir if( ((++ni) & 7) == 0 ) 4303cdf0e10cSrcweir aFontDict.append( '\n' ); 4304cdf0e10cSrcweir } 4305cdf0e10cSrcweir // emit builtin font for widget apperances / variable text 4306cdf0e10cSrcweir for( std::map< sal_Int32, sal_Int32 >::iterator it = m_aBuiltinFontToObjectMap.begin(); 4307cdf0e10cSrcweir it != m_aBuiltinFontToObjectMap.end(); ++it ) 4308cdf0e10cSrcweir { 4309cdf0e10cSrcweir ImplPdfBuiltinFontData aData(m_aBuiltinFonts[it->first]); 4310cdf0e10cSrcweir it->second = emitBuiltinFont( &aData, it->second ); 4311cdf0e10cSrcweir } 4312cdf0e10cSrcweir appendBuiltinFontsToDict( aFontDict ); 4313cdf0e10cSrcweir aFontDict.append( "\n>>\nendobj\n\n" ); 4314cdf0e10cSrcweir 4315cdf0e10cSrcweir CHECK_RETURN( updateObject( getFontDictObject() ) ); 4316cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aFontDict.getStr(), aFontDict.getLength() ) ); 4317cdf0e10cSrcweir return true; 4318cdf0e10cSrcweir } 4319cdf0e10cSrcweir 4320cdf0e10cSrcweir sal_Int32 PDFWriterImpl::emitResources() 4321cdf0e10cSrcweir { 4322cdf0e10cSrcweir // emit shadings 4323cdf0e10cSrcweir if( ! m_aGradients.empty() ) 4324cdf0e10cSrcweir CHECK_RETURN( emitGradients() ); 4325cdf0e10cSrcweir // emit tilings 4326cdf0e10cSrcweir if( ! m_aTilings.empty() ) 4327cdf0e10cSrcweir CHECK_RETURN( emitTilings() ); 4328cdf0e10cSrcweir 4329cdf0e10cSrcweir // emit font dict 4330cdf0e10cSrcweir CHECK_RETURN( emitFonts() ); 4331cdf0e10cSrcweir 4332cdf0e10cSrcweir // emit Resource dict 4333cdf0e10cSrcweir OStringBuffer aLine( 512 ); 4334cdf0e10cSrcweir sal_Int32 nResourceDict = getResourceDictObj(); 4335cdf0e10cSrcweir CHECK_RETURN( updateObject( nResourceDict ) ); 4336cdf0e10cSrcweir aLine.setLength( 0 ); 4337cdf0e10cSrcweir aLine.append( nResourceDict ); 4338cdf0e10cSrcweir aLine.append( " 0 obj\n" ); 4339cdf0e10cSrcweir m_aGlobalResourceDict.append( aLine, getFontDictObject() ); 4340cdf0e10cSrcweir aLine.append( "endobj\n\n" ); 4341cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) ); 4342cdf0e10cSrcweir return nResourceDict; 4343cdf0e10cSrcweir } 4344cdf0e10cSrcweir 4345cdf0e10cSrcweir sal_Int32 PDFWriterImpl::updateOutlineItemCount( std::vector< sal_Int32 >& rCounts, 4346cdf0e10cSrcweir sal_Int32 nItemLevel, 4347cdf0e10cSrcweir sal_Int32 nCurrentItemId ) 4348cdf0e10cSrcweir { 4349cdf0e10cSrcweir /* The /Count number of an item is 4350cdf0e10cSrcweir positive: the number of visible subitems 4351cdf0e10cSrcweir negative: the negative number of subitems that will become visible if 4352cdf0e10cSrcweir the item gets opened 4353cdf0e10cSrcweir see PDF ref 1.4 p 478 4354cdf0e10cSrcweir */ 4355cdf0e10cSrcweir 4356cdf0e10cSrcweir sal_Int32 nCount = 0; 4357cdf0e10cSrcweir 4358cdf0e10cSrcweir if( m_aContext.OpenBookmarkLevels < 0 || // all levels arevisible 4359cdf0e10cSrcweir m_aContext.OpenBookmarkLevels >= nItemLevel // this level is visible 4360cdf0e10cSrcweir ) 4361cdf0e10cSrcweir { 4362cdf0e10cSrcweir PDFOutlineEntry& rItem = m_aOutline[ nCurrentItemId ]; 4363cdf0e10cSrcweir sal_Int32 nChildren = rItem.m_aChildren.size(); 4364cdf0e10cSrcweir for( sal_Int32 i = 0; i < nChildren; i++ ) 4365cdf0e10cSrcweir nCount += updateOutlineItemCount( rCounts, nItemLevel+1, rItem.m_aChildren[i] ); 4366cdf0e10cSrcweir rCounts[nCurrentItemId] = nCount; 4367cdf0e10cSrcweir // return 1 (this item) + visible sub items 4368cdf0e10cSrcweir if( nCount < 0 ) 4369cdf0e10cSrcweir nCount = 0; 4370cdf0e10cSrcweir nCount++; 4371cdf0e10cSrcweir } 4372cdf0e10cSrcweir else 4373cdf0e10cSrcweir { 4374cdf0e10cSrcweir // this bookmark level is invisible 4375cdf0e10cSrcweir PDFOutlineEntry& rItem = m_aOutline[ nCurrentItemId ]; 4376cdf0e10cSrcweir sal_Int32 nChildren = rItem.m_aChildren.size(); 4377cdf0e10cSrcweir rCounts[ nCurrentItemId ] = -sal_Int32(rItem.m_aChildren.size()); 4378cdf0e10cSrcweir for( sal_Int32 i = 0; i < nChildren; i++ ) 4379cdf0e10cSrcweir updateOutlineItemCount( rCounts, nItemLevel+1, rItem.m_aChildren[i] ); 4380cdf0e10cSrcweir nCount = -1; 4381cdf0e10cSrcweir } 4382cdf0e10cSrcweir 4383cdf0e10cSrcweir return nCount; 4384cdf0e10cSrcweir } 4385cdf0e10cSrcweir 4386cdf0e10cSrcweir sal_Int32 PDFWriterImpl::emitOutline() 4387cdf0e10cSrcweir { 4388cdf0e10cSrcweir int i, nItems = m_aOutline.size(); 4389cdf0e10cSrcweir 4390cdf0e10cSrcweir // do we have an outline at all ? 4391cdf0e10cSrcweir if( nItems < 2 ) 4392cdf0e10cSrcweir return 0; 4393cdf0e10cSrcweir 4394cdf0e10cSrcweir // reserve object numbers for all outline items 4395cdf0e10cSrcweir for( i = 0; i < nItems; ++i ) 4396cdf0e10cSrcweir m_aOutline[i].m_nObject = createObject(); 4397cdf0e10cSrcweir 4398cdf0e10cSrcweir // update all parent, next and prev object ids 4399cdf0e10cSrcweir for( i = 0; i < nItems; ++i ) 4400cdf0e10cSrcweir { 4401cdf0e10cSrcweir PDFOutlineEntry& rItem = m_aOutline[i]; 4402cdf0e10cSrcweir int nChildren = rItem.m_aChildren.size(); 4403cdf0e10cSrcweir 4404cdf0e10cSrcweir if( nChildren ) 4405cdf0e10cSrcweir { 4406cdf0e10cSrcweir for( int n = 0; n < nChildren; ++n ) 4407cdf0e10cSrcweir { 4408cdf0e10cSrcweir PDFOutlineEntry& rChild = m_aOutline[ rItem.m_aChildren[n] ]; 4409cdf0e10cSrcweir 4410cdf0e10cSrcweir rChild.m_nParentObject = rItem.m_nObject; 4411cdf0e10cSrcweir rChild.m_nPrevObject = (n > 0) ? m_aOutline[ rItem.m_aChildren[n-1] ].m_nObject : 0; 4412cdf0e10cSrcweir rChild.m_nNextObject = (n < nChildren-1) ? m_aOutline[ rItem.m_aChildren[n+1] ].m_nObject : 0; 4413cdf0e10cSrcweir } 4414cdf0e10cSrcweir 4415cdf0e10cSrcweir } 4416cdf0e10cSrcweir } 4417cdf0e10cSrcweir 4418cdf0e10cSrcweir // calculate Count entries for all items 4419cdf0e10cSrcweir std::vector< sal_Int32 > aCounts( nItems ); 4420cdf0e10cSrcweir updateOutlineItemCount( aCounts, 0, 0 ); 4421cdf0e10cSrcweir 4422cdf0e10cSrcweir // emit hierarchy 4423cdf0e10cSrcweir for( i = 0; i < nItems; ++i ) 4424cdf0e10cSrcweir { 4425cdf0e10cSrcweir PDFOutlineEntry& rItem = m_aOutline[i]; 4426cdf0e10cSrcweir OStringBuffer aLine( 1024 ); 4427cdf0e10cSrcweir 4428cdf0e10cSrcweir CHECK_RETURN( updateObject( rItem.m_nObject ) ); 4429cdf0e10cSrcweir aLine.append( rItem.m_nObject ); 4430cdf0e10cSrcweir aLine.append( " 0 obj\n" ); 4431cdf0e10cSrcweir aLine.append( "<<" ); 4432cdf0e10cSrcweir // number of visible children (all levels) 4433cdf0e10cSrcweir if( i > 0 || aCounts[0] > 0 ) 4434cdf0e10cSrcweir { 4435cdf0e10cSrcweir aLine.append( "/Count " ); 4436cdf0e10cSrcweir aLine.append( aCounts[i] ); 4437cdf0e10cSrcweir } 4438cdf0e10cSrcweir if( ! rItem.m_aChildren.empty() ) 4439cdf0e10cSrcweir { 4440cdf0e10cSrcweir // children list: First, Last 4441cdf0e10cSrcweir aLine.append( "/First " ); 4442cdf0e10cSrcweir aLine.append( m_aOutline[rItem.m_aChildren.front()].m_nObject ); 4443cdf0e10cSrcweir aLine.append( " 0 R/Last " ); 4444cdf0e10cSrcweir aLine.append( m_aOutline[rItem.m_aChildren.back()].m_nObject ); 4445cdf0e10cSrcweir aLine.append( " 0 R\n" ); 4446cdf0e10cSrcweir } 4447cdf0e10cSrcweir if( i > 0 ) 4448cdf0e10cSrcweir { 4449cdf0e10cSrcweir // Title, Dest, Parent, Prev, Next 4450cdf0e10cSrcweir aLine.append( "/Title" ); 4451cdf0e10cSrcweir appendUnicodeTextStringEncrypt( rItem.m_aTitle, rItem.m_nObject, aLine ); 4452cdf0e10cSrcweir aLine.append( "\n" ); 4453cdf0e10cSrcweir // Dest is not required 4454cdf0e10cSrcweir if( rItem.m_nDestID >= 0 && rItem.m_nDestID < (sal_Int32)m_aDests.size() ) 4455cdf0e10cSrcweir { 4456cdf0e10cSrcweir aLine.append( "/Dest" ); 4457cdf0e10cSrcweir appendDest( rItem.m_nDestID, aLine ); 4458cdf0e10cSrcweir } 4459cdf0e10cSrcweir aLine.append( "/Parent " ); 4460cdf0e10cSrcweir aLine.append( rItem.m_nParentObject ); 4461cdf0e10cSrcweir aLine.append( " 0 R" ); 4462cdf0e10cSrcweir if( rItem.m_nPrevObject ) 4463cdf0e10cSrcweir { 4464cdf0e10cSrcweir aLine.append( "/Prev " ); 4465cdf0e10cSrcweir aLine.append( rItem.m_nPrevObject ); 4466cdf0e10cSrcweir aLine.append( " 0 R" ); 4467cdf0e10cSrcweir } 4468cdf0e10cSrcweir if( rItem.m_nNextObject ) 4469cdf0e10cSrcweir { 4470cdf0e10cSrcweir aLine.append( "/Next " ); 4471cdf0e10cSrcweir aLine.append( rItem.m_nNextObject ); 4472cdf0e10cSrcweir aLine.append( " 0 R" ); 4473cdf0e10cSrcweir } 4474cdf0e10cSrcweir } 4475cdf0e10cSrcweir aLine.append( ">>\nendobj\n\n" ); 4476cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) ); 4477cdf0e10cSrcweir } 4478cdf0e10cSrcweir 4479cdf0e10cSrcweir return m_aOutline[0].m_nObject; 4480cdf0e10cSrcweir } 4481cdf0e10cSrcweir 4482cdf0e10cSrcweir #undef CHECK_RETURN 4483cdf0e10cSrcweir #define CHECK_RETURN( x ) if( !x ) return false 4484cdf0e10cSrcweir 4485cdf0e10cSrcweir bool PDFWriterImpl::appendDest( sal_Int32 nDestID, OStringBuffer& rBuffer ) 4486cdf0e10cSrcweir { 4487cdf0e10cSrcweir if( nDestID < 0 || nDestID >= (sal_Int32)m_aDests.size() ) 4488cdf0e10cSrcweir { 4489cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 4490cdf0e10cSrcweir fprintf( stderr, "ERROR: invalid dest %d requested\n", (int)nDestID ); 4491cdf0e10cSrcweir #endif 4492cdf0e10cSrcweir return false; 4493cdf0e10cSrcweir } 4494cdf0e10cSrcweir 4495cdf0e10cSrcweir 4496cdf0e10cSrcweir const PDFDest& rDest = m_aDests[ nDestID ]; 4497cdf0e10cSrcweir const PDFPage& rDestPage = m_aPages[ rDest.m_nPage ]; 4498cdf0e10cSrcweir 4499cdf0e10cSrcweir rBuffer.append( '[' ); 4500cdf0e10cSrcweir rBuffer.append( rDestPage.m_nPageObject ); 4501cdf0e10cSrcweir rBuffer.append( " 0 R" ); 4502cdf0e10cSrcweir 4503cdf0e10cSrcweir switch( rDest.m_eType ) 4504cdf0e10cSrcweir { 4505cdf0e10cSrcweir case PDFWriter::XYZ: 4506cdf0e10cSrcweir default: 4507cdf0e10cSrcweir rBuffer.append( "/XYZ " ); 4508cdf0e10cSrcweir appendFixedInt( rDest.m_aRect.Left(), rBuffer ); 4509cdf0e10cSrcweir rBuffer.append( ' ' ); 4510cdf0e10cSrcweir appendFixedInt( rDest.m_aRect.Bottom(), rBuffer ); 4511cdf0e10cSrcweir rBuffer.append( " 0" ); 4512cdf0e10cSrcweir break; 4513cdf0e10cSrcweir case PDFWriter::Fit: 4514cdf0e10cSrcweir rBuffer.append( "/Fit" ); 4515cdf0e10cSrcweir break; 4516cdf0e10cSrcweir case PDFWriter::FitRectangle: 4517cdf0e10cSrcweir rBuffer.append( "/FitR " ); 4518cdf0e10cSrcweir appendFixedInt( rDest.m_aRect.Left(), rBuffer ); 4519cdf0e10cSrcweir rBuffer.append( ' ' ); 4520cdf0e10cSrcweir appendFixedInt( rDest.m_aRect.Top(), rBuffer ); 4521cdf0e10cSrcweir rBuffer.append( ' ' ); 4522cdf0e10cSrcweir appendFixedInt( rDest.m_aRect.Right(), rBuffer ); 4523cdf0e10cSrcweir rBuffer.append( ' ' ); 4524cdf0e10cSrcweir appendFixedInt( rDest.m_aRect.Bottom(), rBuffer ); 4525cdf0e10cSrcweir break; 4526cdf0e10cSrcweir case PDFWriter::FitHorizontal: 4527cdf0e10cSrcweir rBuffer.append( "/FitH " ); 4528cdf0e10cSrcweir appendFixedInt( rDest.m_aRect.Bottom(), rBuffer ); 4529cdf0e10cSrcweir break; 4530cdf0e10cSrcweir case PDFWriter::FitVertical: 4531cdf0e10cSrcweir rBuffer.append( "/FitV " ); 4532cdf0e10cSrcweir appendFixedInt( rDest.m_aRect.Left(), rBuffer ); 4533cdf0e10cSrcweir break; 4534cdf0e10cSrcweir case PDFWriter::FitPageBoundingBox: 4535cdf0e10cSrcweir rBuffer.append( "/FitB" ); 4536cdf0e10cSrcweir break; 4537cdf0e10cSrcweir case PDFWriter::FitPageBoundingBoxHorizontal: 4538cdf0e10cSrcweir rBuffer.append( "/FitBH " ); 4539cdf0e10cSrcweir appendFixedInt( rDest.m_aRect.Bottom(), rBuffer ); 4540cdf0e10cSrcweir break; 4541cdf0e10cSrcweir case PDFWriter::FitPageBoundingBoxVertical: 4542cdf0e10cSrcweir rBuffer.append( "/FitBV " ); 4543cdf0e10cSrcweir appendFixedInt( rDest.m_aRect.Left(), rBuffer ); 4544cdf0e10cSrcweir break; 4545cdf0e10cSrcweir } 4546cdf0e10cSrcweir rBuffer.append( ']' ); 4547cdf0e10cSrcweir 4548cdf0e10cSrcweir return true; 4549cdf0e10cSrcweir } 4550cdf0e10cSrcweir 4551cdf0e10cSrcweir bool PDFWriterImpl::emitLinkAnnotations() 4552cdf0e10cSrcweir { 4553cdf0e10cSrcweir int nAnnots = m_aLinks.size(); 4554cdf0e10cSrcweir for( int i = 0; i < nAnnots; i++ ) 4555cdf0e10cSrcweir { 4556cdf0e10cSrcweir const PDFLink& rLink = m_aLinks[i]; 4557cdf0e10cSrcweir if( ! updateObject( rLink.m_nObject ) ) 4558cdf0e10cSrcweir continue; 4559cdf0e10cSrcweir 4560cdf0e10cSrcweir OStringBuffer aLine( 1024 ); 4561cdf0e10cSrcweir aLine.append( rLink.m_nObject ); 4562cdf0e10cSrcweir aLine.append( " 0 obj\n" ); 4563cdf0e10cSrcweir //i59651 key /F set bits Print to 1 rest to 0. We don't set NoZoom NoRotate to 1, since it's a 'should' 4564cdf0e10cSrcweir // see PDF 8.4.2 and ISO 19005-1:2005 6.5.3 4565cdf0e10cSrcweir aLine.append( "<</Type/Annot" ); 4566cdf0e10cSrcweir if( m_bIsPDF_A1 ) 4567cdf0e10cSrcweir aLine.append( "/F 4" ); 4568cdf0e10cSrcweir aLine.append( "/Subtype/Link/Border[0 0 0]/Rect[" ); 4569cdf0e10cSrcweir 4570cdf0e10cSrcweir appendFixedInt( rLink.m_aRect.Left()-7, aLine );//the +7 to have a better shape of the border rectangle 4571cdf0e10cSrcweir aLine.append( ' ' ); 4572cdf0e10cSrcweir appendFixedInt( rLink.m_aRect.Top(), aLine ); 4573cdf0e10cSrcweir aLine.append( ' ' ); 4574cdf0e10cSrcweir appendFixedInt( rLink.m_aRect.Right()+7, aLine );//the +7 to have a better shape of the border rectangle 4575cdf0e10cSrcweir aLine.append( ' ' ); 4576cdf0e10cSrcweir appendFixedInt( rLink.m_aRect.Bottom(), aLine ); 4577cdf0e10cSrcweir aLine.append( "]" ); 4578cdf0e10cSrcweir if( rLink.m_nDest >= 0 ) 4579cdf0e10cSrcweir { 4580cdf0e10cSrcweir aLine.append( "/Dest" ); 4581cdf0e10cSrcweir appendDest( rLink.m_nDest, aLine ); 4582cdf0e10cSrcweir } 4583cdf0e10cSrcweir else 4584cdf0e10cSrcweir { 4585cdf0e10cSrcweir /*--->i56629 4586cdf0e10cSrcweir destination is external to the document, so 4587cdf0e10cSrcweir we check in the following sequence: 4588cdf0e10cSrcweir 4589cdf0e10cSrcweir if target type is neither .pdf, nor .od[tpgs], then 4590cdf0e10cSrcweir check if relative or absolute and act accordingly (use URI or 'launch application' as requested) 4591cdf0e10cSrcweir end processing 4592cdf0e10cSrcweir else if target is .od[tpgs]: then 4593cdf0e10cSrcweir if conversion of type from od[tpgs] to pdf is requested, convert it and this becomes the new target file 4594cdf0e10cSrcweir processing continue 4595cdf0e10cSrcweir 4596cdf0e10cSrcweir if (new)target is .pdf : then 4597cdf0e10cSrcweir if GotToR is requested, then 4598cdf0e10cSrcweir convert the target in GoToR where the fragment of the URI is 4599cdf0e10cSrcweir considered the named destination in the target file, set relative or absolute as requested 4600cdf0e10cSrcweir else strip the fragment from URL and then set URI or 'launch application' as requested 4601cdf0e10cSrcweir */ 4602cdf0e10cSrcweir // 4603cdf0e10cSrcweir // FIXME: check if the decode mechanisms for URL processing throughout this implementation 4604cdf0e10cSrcweir // are the correct one!! 4605cdf0e10cSrcweir // 4606cdf0e10cSrcweir // extract target file type 4607cdf0e10cSrcweir INetURLObject aDocumentURL( m_aContext.BaseURL ); 4608cdf0e10cSrcweir INetURLObject aTargetURL( rLink.m_aURL ); 4609cdf0e10cSrcweir sal_Int32 nChangeFileExtensionToPDF = 0; 4610cdf0e10cSrcweir sal_Int32 nSetGoToRMode = 0; 4611cdf0e10cSrcweir sal_Bool bTargetHasPDFExtension = sal_False; 4612cdf0e10cSrcweir INetProtocol eTargetProtocol = aTargetURL.GetProtocol(); 4613cdf0e10cSrcweir sal_Bool bIsUNCPath = sal_False; 4614cdf0e10cSrcweir // check if the protocol is a known one, or if there is no protocol at all (on target only) 4615cdf0e10cSrcweir // if there is no protocol, make the target relative to the current document directory 4616cdf0e10cSrcweir // getting the needed URL information from the current document path 4617cdf0e10cSrcweir if( eTargetProtocol == INET_PROT_NOT_VALID ) 4618cdf0e10cSrcweir { 4619cdf0e10cSrcweir if( rLink.m_aURL.getLength() > 4 && rLink.m_aURL.compareToAscii( "\\\\\\\\", 4 ) == 0) 4620cdf0e10cSrcweir { 4621cdf0e10cSrcweir bIsUNCPath = sal_True; 4622cdf0e10cSrcweir } 4623cdf0e10cSrcweir else 4624cdf0e10cSrcweir { 4625cdf0e10cSrcweir INetURLObject aNewBase( aDocumentURL );//duplicate document URL 4626cdf0e10cSrcweir aNewBase.removeSegment(); //remove last segment from it, obtaining the base URL of the 4627cdf0e10cSrcweir //target document 4628cdf0e10cSrcweir aNewBase.insertName( rLink.m_aURL ); 4629cdf0e10cSrcweir aTargetURL = aNewBase;//reassign the new target URL 4630cdf0e10cSrcweir //recompute the target protocol, with the new URL 4631cdf0e10cSrcweir //normal URL processing resumes 4632cdf0e10cSrcweir eTargetProtocol = aTargetURL.GetProtocol(); 4633cdf0e10cSrcweir } 4634cdf0e10cSrcweir } 4635cdf0e10cSrcweir 4636cdf0e10cSrcweir rtl::OUString aFileExtension = aTargetURL.GetFileExtension(); 4637cdf0e10cSrcweir 4638cdf0e10cSrcweir // Check if the URL ends in '/': if yes it's a directory, 4639cdf0e10cSrcweir // it will be forced to a URI link. 4640cdf0e10cSrcweir // possibly a malformed URI, leave it as it is, force as URI 4641cdf0e10cSrcweir if( aTargetURL.hasFinalSlash() ) 4642cdf0e10cSrcweir m_aContext.DefaultLinkAction = PDFWriter::URIAction; 4643cdf0e10cSrcweir 4644cdf0e10cSrcweir if( aFileExtension.getLength() > 0 ) 4645cdf0e10cSrcweir { 4646cdf0e10cSrcweir if( m_aContext.ConvertOOoTargetToPDFTarget ) 4647cdf0e10cSrcweir { 4648cdf0e10cSrcweir //examine the file type (.odm .odt. .odp, odg, ods) 4649cdf0e10cSrcweir if( aFileExtension.equalsIgnoreAsciiCase(rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "odm" ) ) ) ) 4650cdf0e10cSrcweir nChangeFileExtensionToPDF++; 4651cdf0e10cSrcweir if( aFileExtension.equalsIgnoreAsciiCase(rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "odt" ) ) ) ) 4652cdf0e10cSrcweir nChangeFileExtensionToPDF++; 4653cdf0e10cSrcweir else if( aFileExtension.equalsIgnoreAsciiCase(rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "odp" ) ) ) ) 4654cdf0e10cSrcweir nChangeFileExtensionToPDF++; 4655cdf0e10cSrcweir else if( aFileExtension.equalsIgnoreAsciiCase(rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "odg" ) ) ) ) 4656cdf0e10cSrcweir nChangeFileExtensionToPDF++; 4657cdf0e10cSrcweir else if( aFileExtension.equalsIgnoreAsciiCase(rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ods" ) ) ) ) 4658cdf0e10cSrcweir nChangeFileExtensionToPDF++; 4659cdf0e10cSrcweir if( nChangeFileExtensionToPDF ) 4660cdf0e10cSrcweir aTargetURL.setExtension(rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "pdf" ) ) ); 4661cdf0e10cSrcweir } 4662cdf0e10cSrcweir //check if extension is pdf, see if GoToR should be forced 4663cdf0e10cSrcweir bTargetHasPDFExtension = aTargetURL.GetFileExtension().equalsIgnoreAsciiCase(rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "pdf" ) ) ); 4664cdf0e10cSrcweir if( m_aContext.ForcePDFAction && bTargetHasPDFExtension ) 4665cdf0e10cSrcweir nSetGoToRMode++; 4666cdf0e10cSrcweir } 4667cdf0e10cSrcweir //prepare the URL, if relative or not 4668cdf0e10cSrcweir INetProtocol eBaseProtocol = aDocumentURL.GetProtocol(); 4669cdf0e10cSrcweir //queue the string common to all types of actions 4670cdf0e10cSrcweir aLine.append( "/A<</Type/Action/S"); 4671cdf0e10cSrcweir if( bIsUNCPath ) // handle Win UNC paths 4672cdf0e10cSrcweir { 4673cdf0e10cSrcweir aLine.append( "/Launch/Win<</F" ); 4674cdf0e10cSrcweir // INetURLObject is not good with UNC paths, use original path 4675cdf0e10cSrcweir appendLiteralStringEncrypt( rLink.m_aURL, rLink.m_nObject, aLine, osl_getThreadTextEncoding() ); 4676cdf0e10cSrcweir aLine.append( ">>" ); 4677cdf0e10cSrcweir } 4678cdf0e10cSrcweir else 4679cdf0e10cSrcweir { 4680cdf0e10cSrcweir bool bSetRelative = false; 4681cdf0e10cSrcweir bool bFileSpec = false; 4682cdf0e10cSrcweir //check if relative file link is requested and if the protocol is 'file://' 4683cdf0e10cSrcweir if( m_aContext.RelFsys && eBaseProtocol == eTargetProtocol && eTargetProtocol == INET_PROT_FILE ) 4684cdf0e10cSrcweir bSetRelative = true; 4685cdf0e10cSrcweir 4686cdf0e10cSrcweir rtl::OUString aFragment = aTargetURL.GetMark( INetURLObject::NO_DECODE /*DECODE_WITH_CHARSET*/ ); //fragment as is, 4687cdf0e10cSrcweir if( nSetGoToRMode == 0 ) 4688cdf0e10cSrcweir { 4689cdf0e10cSrcweir switch( m_aContext.DefaultLinkAction ) 4690cdf0e10cSrcweir { 4691cdf0e10cSrcweir default: 4692cdf0e10cSrcweir case PDFWriter::URIAction : 4693cdf0e10cSrcweir case PDFWriter::URIActionDestination : 4694cdf0e10cSrcweir aLine.append( "/URI/URI" ); 4695cdf0e10cSrcweir break; 4696cdf0e10cSrcweir case PDFWriter::LaunchAction: 4697cdf0e10cSrcweir // now: 4698cdf0e10cSrcweir // if a launch action is requested and the hyperlink target has a fragment 4699cdf0e10cSrcweir // and the target file does not have a pdf extension, or it's not a 'file:://' protocol 4700cdf0e10cSrcweir // then force the uri action on it 4701cdf0e10cSrcweir // This code will permit the correct opening of application on web pages, the one that 4702cdf0e10cSrcweir // normally have fragments (but I may be wrong...) 4703cdf0e10cSrcweir // and will force the use of URI when the protocol is not file:// 4704cdf0e10cSrcweir if( (aFragment.getLength() > 0 && !bTargetHasPDFExtension) || 4705cdf0e10cSrcweir eTargetProtocol != INET_PROT_FILE ) 4706cdf0e10cSrcweir aLine.append( "/URI/URI" ); 4707cdf0e10cSrcweir else 4708cdf0e10cSrcweir { 4709cdf0e10cSrcweir aLine.append( "/Launch/F" ); 4710cdf0e10cSrcweir bFileSpec = true; 4711cdf0e10cSrcweir } 4712cdf0e10cSrcweir break; 4713cdf0e10cSrcweir } 4714cdf0e10cSrcweir } 4715cdf0e10cSrcweir //fragment are encoded in the same way as in the named destination processing 4716cdf0e10cSrcweir if( nSetGoToRMode ) 4717cdf0e10cSrcweir {//add the fragment 4718cdf0e10cSrcweir rtl::OUString aURLNoMark = aTargetURL.GetURLNoMark( INetURLObject::DECODE_WITH_CHARSET ); 4719cdf0e10cSrcweir aLine.append("/GoToR"); 4720cdf0e10cSrcweir aLine.append("/F"); 4721cdf0e10cSrcweir bFileSpec = true; 4722cdf0e10cSrcweir appendLiteralStringEncrypt( bSetRelative ? INetURLObject::GetRelURL( m_aContext.BaseURL, aURLNoMark, 4723cdf0e10cSrcweir INetURLObject::WAS_ENCODED, 4724cdf0e10cSrcweir INetURLObject::DECODE_WITH_CHARSET ) : 4725cdf0e10cSrcweir aURLNoMark, rLink.m_nObject, aLine, osl_getThreadTextEncoding() ); 4726cdf0e10cSrcweir if( aFragment.getLength() > 0 ) 4727cdf0e10cSrcweir { 4728cdf0e10cSrcweir aLine.append("/D/"); 4729cdf0e10cSrcweir appendDestinationName( aFragment , aLine ); 4730cdf0e10cSrcweir } 4731cdf0e10cSrcweir } 4732cdf0e10cSrcweir else 4733cdf0e10cSrcweir { 4734cdf0e10cSrcweir // change the fragment to accomodate the bookmark (only if the file extension is PDF and 4735cdf0e10cSrcweir // the requested action is of the correct type) 4736cdf0e10cSrcweir if(m_aContext.DefaultLinkAction == PDFWriter::URIActionDestination && 4737cdf0e10cSrcweir bTargetHasPDFExtension && aFragment.getLength() > 0 ) 4738cdf0e10cSrcweir { 4739cdf0e10cSrcweir OStringBuffer aLineLoc( 1024 ); 4740cdf0e10cSrcweir appendDestinationName( aFragment , aLineLoc ); 4741cdf0e10cSrcweir //substitute the fragment 4742cdf0e10cSrcweir aTargetURL.SetMark( aLineLoc.getStr() ); 4743cdf0e10cSrcweir } 4744cdf0e10cSrcweir rtl::OUString aURL = aTargetURL.GetMainURL( bFileSpec ? INetURLObject::DECODE_WITH_CHARSET : INetURLObject::NO_DECODE ); 4745cdf0e10cSrcweir // check if we have a URL available, if the string is empty, set it as the original one 4746cdf0e10cSrcweir // if( aURL.getLength() == 0 ) 4747cdf0e10cSrcweir // appendLiteralStringEncrypt( rLink.m_aURL , rLink.m_nObject, aLine ); 4748cdf0e10cSrcweir // else 4749cdf0e10cSrcweir appendLiteralStringEncrypt( bSetRelative ? INetURLObject::GetRelURL( m_aContext.BaseURL, aURL, 4750cdf0e10cSrcweir INetURLObject::WAS_ENCODED, 4751cdf0e10cSrcweir bFileSpec ? INetURLObject::DECODE_WITH_CHARSET : INetURLObject::NO_DECODE 4752cdf0e10cSrcweir ) : 4753cdf0e10cSrcweir aURL , rLink.m_nObject, aLine, osl_getThreadTextEncoding() ); 4754cdf0e10cSrcweir } 4755cdf0e10cSrcweir //<--- i56629 4756cdf0e10cSrcweir } 4757cdf0e10cSrcweir aLine.append( ">>\n" ); 4758cdf0e10cSrcweir } 4759cdf0e10cSrcweir if( rLink.m_nStructParent > 0 ) 4760cdf0e10cSrcweir { 4761cdf0e10cSrcweir aLine.append( "/StructParent " ); 4762cdf0e10cSrcweir aLine.append( rLink.m_nStructParent ); 4763cdf0e10cSrcweir } 4764cdf0e10cSrcweir aLine.append( ">>\nendobj\n\n" ); 4765cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) ); 4766cdf0e10cSrcweir } 4767cdf0e10cSrcweir 4768cdf0e10cSrcweir return true; 4769cdf0e10cSrcweir } 4770cdf0e10cSrcweir 4771cdf0e10cSrcweir bool PDFWriterImpl::emitNoteAnnotations() 4772cdf0e10cSrcweir { 4773cdf0e10cSrcweir // emit note annotations 4774cdf0e10cSrcweir int nAnnots = m_aNotes.size(); 4775cdf0e10cSrcweir for( int i = 0; i < nAnnots; i++ ) 4776cdf0e10cSrcweir { 4777cdf0e10cSrcweir const PDFNoteEntry& rNote = m_aNotes[i]; 4778cdf0e10cSrcweir if( ! updateObject( rNote.m_nObject ) ) 4779cdf0e10cSrcweir return false; 4780cdf0e10cSrcweir 4781cdf0e10cSrcweir OStringBuffer aLine( 1024 ); 4782cdf0e10cSrcweir aLine.append( rNote.m_nObject ); 4783cdf0e10cSrcweir aLine.append( " 0 obj\n" ); 4784cdf0e10cSrcweir //i59651 key /F set bits Print to 1 rest to 0. We don't set NoZoom NoRotate to 1, since it's a 'should' 4785cdf0e10cSrcweir // see PDF 8.4.2 and ISO 19005-1:2005 6.5.3 4786cdf0e10cSrcweir aLine.append( "<</Type/Annot" ); 4787cdf0e10cSrcweir if( m_bIsPDF_A1 ) 4788cdf0e10cSrcweir aLine.append( "/F 4" ); 4789cdf0e10cSrcweir aLine.append( "/Subtype/Text/Rect[" ); 4790cdf0e10cSrcweir 4791cdf0e10cSrcweir appendFixedInt( rNote.m_aRect.Left(), aLine ); 4792cdf0e10cSrcweir aLine.append( ' ' ); 4793cdf0e10cSrcweir appendFixedInt( rNote.m_aRect.Top(), aLine ); 4794cdf0e10cSrcweir aLine.append( ' ' ); 4795cdf0e10cSrcweir appendFixedInt( rNote.m_aRect.Right(), aLine ); 4796cdf0e10cSrcweir aLine.append( ' ' ); 4797cdf0e10cSrcweir appendFixedInt( rNote.m_aRect.Bottom(), aLine ); 4798cdf0e10cSrcweir aLine.append( "]" ); 4799cdf0e10cSrcweir 4800cdf0e10cSrcweir // contents of the note (type text string) 4801cdf0e10cSrcweir aLine.append( "/Contents\n" ); 4802cdf0e10cSrcweir appendUnicodeTextStringEncrypt( rNote.m_aContents.Contents, rNote.m_nObject, aLine ); 4803cdf0e10cSrcweir aLine.append( "\n" ); 4804cdf0e10cSrcweir 4805cdf0e10cSrcweir // optional title 4806cdf0e10cSrcweir if( rNote.m_aContents.Title.Len() ) 4807cdf0e10cSrcweir { 4808cdf0e10cSrcweir aLine.append( "/T" ); 4809cdf0e10cSrcweir appendUnicodeTextStringEncrypt( rNote.m_aContents.Title, rNote.m_nObject, aLine ); 4810cdf0e10cSrcweir aLine.append( "\n" ); 4811cdf0e10cSrcweir } 4812cdf0e10cSrcweir 4813cdf0e10cSrcweir aLine.append( ">>\nendobj\n\n" ); 4814cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) ); 4815cdf0e10cSrcweir } 4816cdf0e10cSrcweir return true; 4817cdf0e10cSrcweir } 4818cdf0e10cSrcweir 4819cdf0e10cSrcweir Font PDFWriterImpl::replaceFont( const Font& rControlFont, const Font& rAppSetFont ) 4820cdf0e10cSrcweir { 4821cdf0e10cSrcweir bool bAdjustSize = false; 4822cdf0e10cSrcweir 4823cdf0e10cSrcweir Font aFont( rControlFont ); 4824cdf0e10cSrcweir if( ! aFont.GetName().Len() ) 4825cdf0e10cSrcweir { 4826cdf0e10cSrcweir aFont = rAppSetFont; 4827cdf0e10cSrcweir if( rControlFont.GetHeight() ) 4828cdf0e10cSrcweir aFont.SetSize( Size( 0, rControlFont.GetHeight() ) ); 4829cdf0e10cSrcweir else 4830cdf0e10cSrcweir bAdjustSize = true; 4831cdf0e10cSrcweir if( rControlFont.GetItalic() != ITALIC_DONTKNOW ) 4832cdf0e10cSrcweir aFont.SetItalic( rControlFont.GetItalic() ); 4833cdf0e10cSrcweir if( rControlFont.GetWeight() != WEIGHT_DONTKNOW ) 4834cdf0e10cSrcweir aFont.SetWeight( rControlFont.GetWeight() ); 4835cdf0e10cSrcweir } 4836cdf0e10cSrcweir else if( ! aFont.GetHeight() ) 4837cdf0e10cSrcweir { 4838cdf0e10cSrcweir aFont.SetSize( rAppSetFont.GetSize() ); 4839cdf0e10cSrcweir bAdjustSize = true; 4840cdf0e10cSrcweir } 4841cdf0e10cSrcweir if( bAdjustSize ) 4842cdf0e10cSrcweir { 4843cdf0e10cSrcweir Size aFontSize = aFont.GetSize(); 4844cdf0e10cSrcweir OutputDevice* pDefDev = Application::GetDefaultDevice(); 4845cdf0e10cSrcweir aFontSize = OutputDevice::LogicToLogic( aFontSize, pDefDev->GetMapMode(), getMapMode() ); 4846cdf0e10cSrcweir aFont.SetSize( aFontSize ); 4847cdf0e10cSrcweir } 4848cdf0e10cSrcweir return aFont; 4849cdf0e10cSrcweir } 4850cdf0e10cSrcweir 4851cdf0e10cSrcweir sal_Int32 PDFWriterImpl::getBestBuiltinFont( const Font& rFont ) 4852cdf0e10cSrcweir { 4853cdf0e10cSrcweir sal_Int32 nBest = 4; // default to Helvetica 4854cdf0e10cSrcweir OUString aFontName( rFont.GetName() ); 4855cdf0e10cSrcweir aFontName = aFontName.toAsciiLowerCase(); 4856cdf0e10cSrcweir 4857cdf0e10cSrcweir if( aFontName.indexOf( OUString( RTL_CONSTASCII_USTRINGPARAM( "times" ) ) ) != -1 ) 4858cdf0e10cSrcweir nBest = 8; 4859cdf0e10cSrcweir else if( aFontName.indexOf( OUString( RTL_CONSTASCII_USTRINGPARAM( "courier" ) ) ) != -1 ) 4860cdf0e10cSrcweir nBest = 0; 4861cdf0e10cSrcweir else if( aFontName.indexOf( OUString( RTL_CONSTASCII_USTRINGPARAM( "dingbats" ) ) ) != -1 ) 4862cdf0e10cSrcweir nBest = 13; 4863cdf0e10cSrcweir else if( aFontName.indexOf( OUString( RTL_CONSTASCII_USTRINGPARAM( "symbol" ) ) ) != -1 ) 4864cdf0e10cSrcweir nBest = 12; 4865cdf0e10cSrcweir if( nBest < 12 ) 4866cdf0e10cSrcweir { 4867cdf0e10cSrcweir if( rFont.GetItalic() == ITALIC_OBLIQUE || rFont.GetItalic() == ITALIC_NORMAL ) 4868cdf0e10cSrcweir nBest += 1; 4869cdf0e10cSrcweir if( rFont.GetWeight() > WEIGHT_MEDIUM ) 4870cdf0e10cSrcweir nBest += 2; 4871cdf0e10cSrcweir } 4872cdf0e10cSrcweir 4873cdf0e10cSrcweir if( m_aBuiltinFontToObjectMap.find( nBest ) == m_aBuiltinFontToObjectMap.end() ) 4874cdf0e10cSrcweir m_aBuiltinFontToObjectMap[ nBest ] = createObject(); 4875cdf0e10cSrcweir 4876cdf0e10cSrcweir return nBest; 4877cdf0e10cSrcweir } 4878cdf0e10cSrcweir 4879cdf0e10cSrcweir static inline const Color& replaceColor( const Color& rCol1, const Color& rCol2 ) 4880cdf0e10cSrcweir { 4881cdf0e10cSrcweir return (rCol1 == Color( COL_TRANSPARENT )) ? rCol2 : rCol1; 4882cdf0e10cSrcweir } 4883cdf0e10cSrcweir 4884cdf0e10cSrcweir void PDFWriterImpl::createDefaultPushButtonAppearance( PDFWidget& rButton, const PDFWriter::PushButtonWidget& rWidget ) 4885cdf0e10cSrcweir { 4886cdf0e10cSrcweir const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings(); 4887cdf0e10cSrcweir 4888cdf0e10cSrcweir // save graphics state 4889cdf0e10cSrcweir push( sal::static_int_cast<sal_uInt16>(~0U) ); 4890cdf0e10cSrcweir 4891cdf0e10cSrcweir // transform relative to control's coordinates since an 4892cdf0e10cSrcweir // appearance stream is a form XObject 4893cdf0e10cSrcweir // this relies on the m_aRect member of rButton NOT already being transformed 4894cdf0e10cSrcweir // to default user space 4895cdf0e10cSrcweir if( rWidget.Background || rWidget.Border ) 4896cdf0e10cSrcweir { 4897cdf0e10cSrcweir setLineColor( rWidget.Border ? replaceColor( rWidget.BorderColor, rSettings.GetLightColor() ) : Color( COL_TRANSPARENT ) ); 4898cdf0e10cSrcweir setFillColor( rWidget.Background ? replaceColor( rWidget.BackgroundColor, rSettings.GetDialogColor() ) : Color( COL_TRANSPARENT ) ); 4899cdf0e10cSrcweir drawRectangle( rWidget.Location ); 4900cdf0e10cSrcweir } 4901cdf0e10cSrcweir // prepare font to use 4902cdf0e10cSrcweir Font aFont = replaceFont( rWidget.TextFont, rSettings.GetPushButtonFont() ); 4903cdf0e10cSrcweir setFont( aFont ); 4904cdf0e10cSrcweir setTextColor( replaceColor( rWidget.TextColor, rSettings.GetButtonTextColor() ) ); 4905cdf0e10cSrcweir 4906cdf0e10cSrcweir drawText( rButton.m_aRect, rButton.m_aText, rButton.m_nTextStyle ); 4907cdf0e10cSrcweir 4908cdf0e10cSrcweir // create DA string while local mapmode is still in place 4909cdf0e10cSrcweir // (that is before endRedirect()) 4910cdf0e10cSrcweir OStringBuffer aDA( 256 ); 4911cdf0e10cSrcweir appendNonStrokingColor( replaceColor( rWidget.TextColor, rSettings.GetButtonTextColor() ), aDA ); 4912cdf0e10cSrcweir Font aDummyFont( String( RTL_CONSTASCII_USTRINGPARAM( "Helvetica" ) ), aFont.GetSize() ); 4913cdf0e10cSrcweir sal_Int32 nDummyBuiltin = getBestBuiltinFont( aDummyFont ); 4914cdf0e10cSrcweir aDA.append( ' ' ); 4915cdf0e10cSrcweir aDA.append( m_aBuiltinFonts[nDummyBuiltin].getNameObject() ); 4916cdf0e10cSrcweir aDA.append( ' ' ); 4917cdf0e10cSrcweir m_aPages[m_nCurrentPage].appendMappedLength( sal_Int32( aFont.GetHeight() ), aDA ); 4918cdf0e10cSrcweir aDA.append( " Tf" ); 4919cdf0e10cSrcweir rButton.m_aDAString = aDA.makeStringAndClear(); 4920cdf0e10cSrcweir 4921cdf0e10cSrcweir pop(); 4922cdf0e10cSrcweir 4923cdf0e10cSrcweir rButton.m_aAppearances[ "N" ][ "Standard" ] = new SvMemoryStream(); 4924cdf0e10cSrcweir 4925cdf0e10cSrcweir /* seems like a bad hack but at least works in both AR5 and 6: 4926cdf0e10cSrcweir we draw the button ourselves and tell AR 4927cdf0e10cSrcweir the button would be totally transparent with no text 4928cdf0e10cSrcweir 4929cdf0e10cSrcweir One would expect that simply setting a normal appearance 4930cdf0e10cSrcweir should suffice, but no, as soon as the user actually presses 4931cdf0e10cSrcweir the button and an action is tied to it (gasp! a button that 4932cdf0e10cSrcweir does something) the appearance gets replaced by some crap that AR 4933cdf0e10cSrcweir creates on the fly even if no DA or MK is given. On AR6 at least 4934cdf0e10cSrcweir the DA and MK work as expected, but on AR5 this creates a region 4935cdf0e10cSrcweir filled with the background color but nor text. Urgh. 4936cdf0e10cSrcweir */ 4937cdf0e10cSrcweir rButton.m_aMKDict = "/BC [] /BG [] /CA"; 4938cdf0e10cSrcweir rButton.m_aMKDictCAString = ""; 4939cdf0e10cSrcweir } 4940cdf0e10cSrcweir 4941cdf0e10cSrcweir Font PDFWriterImpl::drawFieldBorder( PDFWidget& rIntern, 4942cdf0e10cSrcweir const PDFWriter::AnyWidget& rWidget, 4943cdf0e10cSrcweir const StyleSettings& rSettings ) 4944cdf0e10cSrcweir { 4945cdf0e10cSrcweir Font aFont = replaceFont( rWidget.TextFont, rSettings.GetFieldFont() ); 4946cdf0e10cSrcweir 4947cdf0e10cSrcweir if( rWidget.Background || rWidget.Border ) 4948cdf0e10cSrcweir { 4949cdf0e10cSrcweir if( rWidget.Border && rWidget.BorderColor == Color( COL_TRANSPARENT ) ) 4950cdf0e10cSrcweir { 4951cdf0e10cSrcweir sal_Int32 nDelta = getReferenceDevice()->ImplGetDPIX() / 500; 4952cdf0e10cSrcweir if( nDelta < 1 ) 4953cdf0e10cSrcweir nDelta = 1; 4954cdf0e10cSrcweir setLineColor( Color( COL_TRANSPARENT ) ); 4955cdf0e10cSrcweir Rectangle aRect = rIntern.m_aRect; 4956cdf0e10cSrcweir setFillColor( rSettings.GetLightBorderColor() ); 4957cdf0e10cSrcweir drawRectangle( aRect ); 4958cdf0e10cSrcweir aRect.Left() += nDelta; aRect.Top() += nDelta; 4959cdf0e10cSrcweir aRect.Right() -= nDelta; aRect.Bottom() -= nDelta; 4960cdf0e10cSrcweir setFillColor( rSettings.GetFieldColor() ); 4961cdf0e10cSrcweir drawRectangle( aRect ); 4962cdf0e10cSrcweir setFillColor( rSettings.GetLightColor() ); 4963cdf0e10cSrcweir drawRectangle( Rectangle( Point( aRect.Left(), aRect.Bottom()-nDelta ), aRect.BottomRight() ) ); 4964cdf0e10cSrcweir drawRectangle( Rectangle( Point( aRect.Right()-nDelta, aRect.Top() ), aRect.BottomRight() ) ); 4965cdf0e10cSrcweir setFillColor( rSettings.GetDarkShadowColor() ); 4966cdf0e10cSrcweir drawRectangle( Rectangle( aRect.TopLeft(), Point( aRect.Left()+nDelta, aRect.Bottom() ) ) ); 4967cdf0e10cSrcweir drawRectangle( Rectangle( aRect.TopLeft(), Point( aRect.Right(), aRect.Top()+nDelta ) ) ); 4968cdf0e10cSrcweir } 4969cdf0e10cSrcweir else 4970cdf0e10cSrcweir { 4971cdf0e10cSrcweir setLineColor( rWidget.Border ? replaceColor( rWidget.BorderColor, rSettings.GetShadowColor() ) : Color( COL_TRANSPARENT ) ); 4972cdf0e10cSrcweir setFillColor( rWidget.Background ? replaceColor( rWidget.BackgroundColor, rSettings.GetFieldColor() ) : Color( COL_TRANSPARENT ) ); 4973cdf0e10cSrcweir drawRectangle( rIntern.m_aRect ); 4974cdf0e10cSrcweir } 4975cdf0e10cSrcweir 4976cdf0e10cSrcweir if( rWidget.Border ) 4977cdf0e10cSrcweir { 4978cdf0e10cSrcweir // adjust edit area accounting for border 4979cdf0e10cSrcweir sal_Int32 nDelta = aFont.GetHeight()/4; 4980cdf0e10cSrcweir if( nDelta < 1 ) 4981cdf0e10cSrcweir nDelta = 1; 4982cdf0e10cSrcweir rIntern.m_aRect.Left() += nDelta; 4983cdf0e10cSrcweir rIntern.m_aRect.Top() += nDelta; 4984cdf0e10cSrcweir rIntern.m_aRect.Right() -= nDelta; 4985cdf0e10cSrcweir rIntern.m_aRect.Bottom()-= nDelta; 4986cdf0e10cSrcweir } 4987cdf0e10cSrcweir } 4988cdf0e10cSrcweir return aFont; 4989cdf0e10cSrcweir } 4990cdf0e10cSrcweir 4991cdf0e10cSrcweir void PDFWriterImpl::createDefaultEditAppearance( PDFWidget& rEdit, const PDFWriter::EditWidget& rWidget ) 4992cdf0e10cSrcweir { 4993cdf0e10cSrcweir const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings(); 4994cdf0e10cSrcweir SvMemoryStream* pEditStream = new SvMemoryStream( 1024, 1024 ); 4995cdf0e10cSrcweir 4996cdf0e10cSrcweir push( sal::static_int_cast<sal_uInt16>(~0U) ); 4997cdf0e10cSrcweir 4998cdf0e10cSrcweir // prepare font to use, draw field border 4999cdf0e10cSrcweir Font aFont = drawFieldBorder( rEdit, rWidget, rSettings ); 5000cdf0e10cSrcweir sal_Int32 nBest = m_aContext.FieldsUseSystemFonts ? getSystemFont( aFont ): getBestBuiltinFont( aFont ); 5001cdf0e10cSrcweir 5002cdf0e10cSrcweir // prepare DA string 5003cdf0e10cSrcweir OStringBuffer aDA( 32 ); 5004cdf0e10cSrcweir appendNonStrokingColor( replaceColor( rWidget.TextColor, rSettings.GetFieldTextColor() ), aDA ); 5005cdf0e10cSrcweir aDA.append( ' ' ); 5006cdf0e10cSrcweir if( m_aContext.FieldsUseSystemFonts ) 5007cdf0e10cSrcweir { 5008cdf0e10cSrcweir aDA.append( "/F" ); 5009cdf0e10cSrcweir aDA.append( nBest ); 5010cdf0e10cSrcweir 5011cdf0e10cSrcweir OStringBuffer aDR( 32 ); 5012cdf0e10cSrcweir aDR.append( "/Font " ); 5013cdf0e10cSrcweir aDR.append( getFontDictObject() ); 5014cdf0e10cSrcweir aDR.append( " 0 R" ); 5015cdf0e10cSrcweir rEdit.m_aDRDict = aDR.makeStringAndClear(); 5016cdf0e10cSrcweir } 5017cdf0e10cSrcweir else 5018cdf0e10cSrcweir aDA.append( m_aBuiltinFonts[nBest].getNameObject() ); 5019cdf0e10cSrcweir aDA.append( ' ' ); 5020cdf0e10cSrcweir m_aPages[ m_nCurrentPage ].appendMappedLength( sal_Int32( aFont.GetHeight() ), aDA ); 5021cdf0e10cSrcweir aDA.append( " Tf" ); 5022cdf0e10cSrcweir 5023cdf0e10cSrcweir /* create an empty appearance stream, let the viewer create 5024cdf0e10cSrcweir the appearance at runtime. This is because AR5 seems to 5025cdf0e10cSrcweir paint the widget appearance always, and a dynamically created 5026cdf0e10cSrcweir appearance on top of it. AR6 is well behaved in that regard, so 5027cdf0e10cSrcweir that behaviour seems to be a bug. Anyway this empty appearance 5028cdf0e10cSrcweir relies on /NeedAppearances in the AcroForm dictionary set to "true" 5029cdf0e10cSrcweir */ 5030cdf0e10cSrcweir beginRedirect( pEditStream, rEdit.m_aRect ); 5031cdf0e10cSrcweir OStringBuffer aAppearance( 32 ); 5032cdf0e10cSrcweir aAppearance.append( "/Tx BMC\nEMC\n" ); 5033cdf0e10cSrcweir writeBuffer( aAppearance.getStr(), aAppearance.getLength() ); 5034cdf0e10cSrcweir 5035cdf0e10cSrcweir endRedirect(); 5036cdf0e10cSrcweir pop(); 5037cdf0e10cSrcweir 5038cdf0e10cSrcweir rEdit.m_aAppearances[ "N" ][ "Standard" ] = pEditStream; 5039cdf0e10cSrcweir 5040cdf0e10cSrcweir rEdit.m_aDAString = aDA.makeStringAndClear(); 5041cdf0e10cSrcweir } 5042cdf0e10cSrcweir 5043cdf0e10cSrcweir void PDFWriterImpl::createDefaultListBoxAppearance( PDFWidget& rBox, const PDFWriter::ListBoxWidget& rWidget ) 5044cdf0e10cSrcweir { 5045cdf0e10cSrcweir const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings(); 5046cdf0e10cSrcweir SvMemoryStream* pListBoxStream = new SvMemoryStream( 1024, 1024 ); 5047cdf0e10cSrcweir 5048cdf0e10cSrcweir push( sal::static_int_cast<sal_uInt16>(~0U) ); 5049cdf0e10cSrcweir 5050cdf0e10cSrcweir // prepare font to use, draw field border 5051cdf0e10cSrcweir Font aFont = drawFieldBorder( rBox, rWidget, rSettings ); 5052cdf0e10cSrcweir sal_Int32 nBest = m_aContext.FieldsUseSystemFonts ? getSystemFont( aFont ): getBestBuiltinFont( aFont ); 5053cdf0e10cSrcweir 5054cdf0e10cSrcweir beginRedirect( pListBoxStream, rBox.m_aRect ); 5055cdf0e10cSrcweir OStringBuffer aAppearance( 64 ); 5056cdf0e10cSrcweir 5057cdf0e10cSrcweir #if 0 5058cdf0e10cSrcweir if( ! rWidget.DropDown ) 5059cdf0e10cSrcweir { 5060cdf0e10cSrcweir // prepare linewidth for DA string hack, see below 5061cdf0e10cSrcweir Size aFontSize = lcl_convert( m_aGraphicsStack.front().m_aMapMode, 5062cdf0e10cSrcweir m_aMapMode, 5063cdf0e10cSrcweir getReferenceDevice(), 5064cdf0e10cSrcweir Size( 0, aFont.GetHeight() ) ); 5065cdf0e10cSrcweir sal_Int32 nLW = aFontSize.Height() / 40; 5066cdf0e10cSrcweir appendFixedInt( nLW > 0 ? nLW : 1, aAppearance ); 5067cdf0e10cSrcweir aAppearance.append( " w\n" ); 5068cdf0e10cSrcweir writeBuffer( aAppearance.getStr(), aAppearance.getLength() ); 5069cdf0e10cSrcweir aAppearance.setLength( 0 ); 5070cdf0e10cSrcweir } 5071cdf0e10cSrcweir #endif 5072cdf0e10cSrcweir 5073cdf0e10cSrcweir setLineColor( Color( COL_TRANSPARENT ) ); 5074cdf0e10cSrcweir setFillColor( replaceColor( rWidget.BackgroundColor, rSettings.GetFieldColor() ) ); 5075cdf0e10cSrcweir drawRectangle( rBox.m_aRect ); 5076cdf0e10cSrcweir 5077cdf0e10cSrcweir // empty appearance, see createDefaultEditAppearance for reference 5078cdf0e10cSrcweir aAppearance.append( "/Tx BMC\nEMC\n" ); 5079cdf0e10cSrcweir writeBuffer( aAppearance.getStr(), aAppearance.getLength() ); 5080cdf0e10cSrcweir 5081cdf0e10cSrcweir endRedirect(); 5082cdf0e10cSrcweir pop(); 5083cdf0e10cSrcweir 5084cdf0e10cSrcweir rBox.m_aAppearances[ "N" ][ "Standard" ] = pListBoxStream; 5085cdf0e10cSrcweir 5086cdf0e10cSrcweir // prepare DA string 5087cdf0e10cSrcweir OStringBuffer aDA( 256 ); 5088cdf0e10cSrcweir #if 0 5089cdf0e10cSrcweir if( !rWidget.DropDown ) 5090cdf0e10cSrcweir { 5091cdf0e10cSrcweir /* another of AR5's peculiarities: the selected item of a choice 5092cdf0e10cSrcweir field is highlighted using the non stroking color - same as the 5093cdf0e10cSrcweir text color. so workaround that by using text rendering mode 2 5094cdf0e10cSrcweir (fill, then stroke) and set the stroking color 5095cdf0e10cSrcweir */ 5096cdf0e10cSrcweir appendStrokingColor( replaceColor( rWidget.BackgroundColor, rSettings.GetFieldColor() ), aDA ); 5097cdf0e10cSrcweir aDA.append( " 2 Tr " ); 5098cdf0e10cSrcweir } 5099cdf0e10cSrcweir #endif 5100cdf0e10cSrcweir // prepare DA string 5101cdf0e10cSrcweir appendNonStrokingColor( replaceColor( rWidget.TextColor, rSettings.GetFieldTextColor() ), aDA ); 5102cdf0e10cSrcweir aDA.append( ' ' ); 5103cdf0e10cSrcweir if( m_aContext.FieldsUseSystemFonts ) 5104cdf0e10cSrcweir { 5105cdf0e10cSrcweir aDA.append( "/F" ); 5106cdf0e10cSrcweir aDA.append( nBest ); 5107cdf0e10cSrcweir 5108cdf0e10cSrcweir OStringBuffer aDR( 32 ); 5109cdf0e10cSrcweir aDR.append( "/Font " ); 5110cdf0e10cSrcweir aDR.append( getFontDictObject() ); 5111cdf0e10cSrcweir aDR.append( " 0 R" ); 5112cdf0e10cSrcweir rBox.m_aDRDict = aDR.makeStringAndClear(); 5113cdf0e10cSrcweir } 5114cdf0e10cSrcweir else 5115cdf0e10cSrcweir aDA.append( m_aBuiltinFonts[nBest].getNameObject() ); 5116cdf0e10cSrcweir aDA.append( ' ' ); 5117cdf0e10cSrcweir m_aPages[ m_nCurrentPage ].appendMappedLength( sal_Int32( aFont.GetHeight() ), aDA ); 5118cdf0e10cSrcweir aDA.append( " Tf" ); 5119cdf0e10cSrcweir rBox.m_aDAString = aDA.makeStringAndClear(); 5120cdf0e10cSrcweir } 5121cdf0e10cSrcweir 5122cdf0e10cSrcweir void PDFWriterImpl::createDefaultCheckBoxAppearance( PDFWidget& rBox, const PDFWriter::CheckBoxWidget& rWidget ) 5123cdf0e10cSrcweir { 5124cdf0e10cSrcweir const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings(); 5125cdf0e10cSrcweir 5126cdf0e10cSrcweir // save graphics state 5127cdf0e10cSrcweir push( sal::static_int_cast<sal_uInt16>(~0U) ); 5128cdf0e10cSrcweir 5129cdf0e10cSrcweir if( rWidget.Background || rWidget.Border ) 5130cdf0e10cSrcweir { 5131cdf0e10cSrcweir setLineColor( rWidget.Border ? replaceColor( rWidget.BorderColor, rSettings.GetCheckedColor() ) : Color( COL_TRANSPARENT ) ); 5132cdf0e10cSrcweir setFillColor( rWidget.Background ? replaceColor( rWidget.BackgroundColor, rSettings.GetFieldColor() ) : Color( COL_TRANSPARENT ) ); 5133cdf0e10cSrcweir drawRectangle( rBox.m_aRect ); 5134cdf0e10cSrcweir } 5135cdf0e10cSrcweir 5136cdf0e10cSrcweir Font aFont = replaceFont( rWidget.TextFont, rSettings.GetRadioCheckFont() ); 5137cdf0e10cSrcweir setFont( aFont ); 5138cdf0e10cSrcweir Size aFontSize = aFont.GetSize(); 5139cdf0e10cSrcweir if( aFontSize.Height() > rBox.m_aRect.GetHeight() ) 5140cdf0e10cSrcweir aFontSize.Height() = rBox.m_aRect.GetHeight(); 5141cdf0e10cSrcweir sal_Int32 nDelta = aFontSize.Height()/10; 5142cdf0e10cSrcweir if( nDelta < 1 ) 5143cdf0e10cSrcweir nDelta = 1; 5144cdf0e10cSrcweir 5145cdf0e10cSrcweir Rectangle aCheckRect, aTextRect; 5146cdf0e10cSrcweir if( rWidget.ButtonIsLeft ) 5147cdf0e10cSrcweir { 5148cdf0e10cSrcweir aCheckRect.Left() = rBox.m_aRect.Left() + nDelta; 5149cdf0e10cSrcweir aCheckRect.Top() = rBox.m_aRect.Top() + (rBox.m_aRect.GetHeight()-aFontSize.Height())/2; 5150cdf0e10cSrcweir aCheckRect.Right() = aCheckRect.Left() + aFontSize.Height(); 5151cdf0e10cSrcweir aCheckRect.Bottom() = aCheckRect.Top() + aFontSize.Height(); 5152cdf0e10cSrcweir 5153cdf0e10cSrcweir // #i74206# handle small controls without text area 5154cdf0e10cSrcweir while( aCheckRect.GetWidth() > rBox.m_aRect.GetWidth() && aCheckRect.GetWidth() > nDelta ) 5155cdf0e10cSrcweir { 5156cdf0e10cSrcweir aCheckRect.Right() -= nDelta; 5157cdf0e10cSrcweir aCheckRect.Top() += nDelta/2; 5158cdf0e10cSrcweir aCheckRect.Bottom() -= nDelta - (nDelta/2); 5159cdf0e10cSrcweir } 5160cdf0e10cSrcweir 5161cdf0e10cSrcweir aTextRect.Left() = rBox.m_aRect.Left() + aCheckRect.GetWidth()+5*nDelta; 5162cdf0e10cSrcweir aTextRect.Top() = rBox.m_aRect.Top(); 5163cdf0e10cSrcweir aTextRect.Right() = aTextRect.Left() + rBox.m_aRect.GetWidth() - aCheckRect.GetWidth()-6*nDelta; 5164cdf0e10cSrcweir aTextRect.Bottom() = rBox.m_aRect.Bottom(); 5165cdf0e10cSrcweir } 5166cdf0e10cSrcweir else 5167cdf0e10cSrcweir { 5168cdf0e10cSrcweir aCheckRect.Left() = rBox.m_aRect.Right() - nDelta - aFontSize.Height(); 5169cdf0e10cSrcweir aCheckRect.Top() = rBox.m_aRect.Top() + (rBox.m_aRect.GetHeight()-aFontSize.Height())/2; 5170cdf0e10cSrcweir aCheckRect.Right() = aCheckRect.Left() + aFontSize.Height(); 5171cdf0e10cSrcweir aCheckRect.Bottom() = aCheckRect.Top() + aFontSize.Height(); 5172cdf0e10cSrcweir 5173cdf0e10cSrcweir // #i74206# handle small controls without text area 5174cdf0e10cSrcweir while( aCheckRect.GetWidth() > rBox.m_aRect.GetWidth() && aCheckRect.GetWidth() > nDelta ) 5175cdf0e10cSrcweir { 5176cdf0e10cSrcweir aCheckRect.Left() += nDelta; 5177cdf0e10cSrcweir aCheckRect.Top() += nDelta/2; 5178cdf0e10cSrcweir aCheckRect.Bottom() -= nDelta - (nDelta/2); 5179cdf0e10cSrcweir } 5180cdf0e10cSrcweir 5181cdf0e10cSrcweir aTextRect.Left() = rBox.m_aRect.Left(); 5182cdf0e10cSrcweir aTextRect.Top() = rBox.m_aRect.Top(); 5183cdf0e10cSrcweir aTextRect.Right() = aTextRect.Left() + rBox.m_aRect.GetWidth() - aCheckRect.GetWidth()-6*nDelta; 5184cdf0e10cSrcweir aTextRect.Bottom() = rBox.m_aRect.Bottom(); 5185cdf0e10cSrcweir } 5186cdf0e10cSrcweir setLineColor( Color( COL_BLACK ) ); 5187cdf0e10cSrcweir setFillColor( Color( COL_TRANSPARENT ) ); 5188cdf0e10cSrcweir OStringBuffer aLW( 32 ); 5189cdf0e10cSrcweir aLW.append( "q " ); 5190cdf0e10cSrcweir m_aPages[m_nCurrentPage].appendMappedLength( nDelta, aLW ); 5191cdf0e10cSrcweir aLW.append( " w " ); 5192cdf0e10cSrcweir writeBuffer( aLW.getStr(), aLW.getLength() ); 5193cdf0e10cSrcweir drawRectangle( aCheckRect ); 5194cdf0e10cSrcweir writeBuffer( " Q\n", 3 ); 5195cdf0e10cSrcweir setTextColor( replaceColor( rWidget.TextColor, rSettings.GetRadioCheckTextColor() ) ); 5196cdf0e10cSrcweir drawText( aTextRect, rBox.m_aText, rBox.m_nTextStyle ); 5197cdf0e10cSrcweir 5198cdf0e10cSrcweir pop(); 5199cdf0e10cSrcweir 5200cdf0e10cSrcweir OStringBuffer aDA( 256 ); 5201cdf0e10cSrcweir appendNonStrokingColor( replaceColor( rWidget.TextColor, rSettings.GetRadioCheckTextColor() ), aDA ); 5202cdf0e10cSrcweir sal_Int32 nBest = getBestBuiltinFont( Font( String( RTL_CONSTASCII_USTRINGPARAM( "ZapfDingbats" ) ), aFont.GetSize() ) ); 5203cdf0e10cSrcweir aDA.append( ' ' ); 5204cdf0e10cSrcweir aDA.append( m_aBuiltinFonts[nBest].getNameObject() ); 5205cdf0e10cSrcweir aDA.append( " 0 Tf" ); 5206cdf0e10cSrcweir rBox.m_aDAString = aDA.makeStringAndClear(); 5207cdf0e10cSrcweir rBox.m_aMKDict = "/CA"; 5208cdf0e10cSrcweir rBox.m_aMKDictCAString = "8"; 5209cdf0e10cSrcweir rBox.m_aRect = aCheckRect; 5210cdf0e10cSrcweir 5211cdf0e10cSrcweir // create appearance streams 5212cdf0e10cSrcweir sal_Char cMark = '8'; 5213cdf0e10cSrcweir sal_Int32 nCharXOffset = 1000-m_aBuiltinFonts[13].m_aWidths[sal_Int32(cMark)]; 5214cdf0e10cSrcweir nCharXOffset *= aCheckRect.GetHeight(); 5215cdf0e10cSrcweir nCharXOffset /= 2000; 5216cdf0e10cSrcweir sal_Int32 nCharYOffset = 1000- 5217cdf0e10cSrcweir (m_aBuiltinFonts[13].m_nAscent+m_aBuiltinFonts[13].m_nDescent); // descent is negative 5218cdf0e10cSrcweir nCharYOffset *= aCheckRect.GetHeight(); 5219cdf0e10cSrcweir nCharYOffset /= 2000; 5220cdf0e10cSrcweir 5221cdf0e10cSrcweir SvMemoryStream* pCheckStream = new SvMemoryStream( 256, 256 ); 5222cdf0e10cSrcweir beginRedirect( pCheckStream, aCheckRect ); 5223cdf0e10cSrcweir aDA.append( "/Tx BMC\nq BT\n" ); 5224cdf0e10cSrcweir appendNonStrokingColor( replaceColor( rWidget.TextColor, rSettings.GetRadioCheckTextColor() ), aDA ); 5225cdf0e10cSrcweir aDA.append( ' ' ); 5226cdf0e10cSrcweir aDA.append( m_aBuiltinFonts[nBest].getNameObject() ); 5227cdf0e10cSrcweir aDA.append( ' ' ); 5228cdf0e10cSrcweir m_aPages[ m_nCurrentPage ].appendMappedLength( sal_Int32( aCheckRect.GetHeight() ), aDA ); 5229cdf0e10cSrcweir aDA.append( " Tf\n" ); 5230cdf0e10cSrcweir m_aPages[ m_nCurrentPage ].appendMappedLength( nCharXOffset, aDA ); 5231cdf0e10cSrcweir aDA.append( " " ); 5232cdf0e10cSrcweir m_aPages[ m_nCurrentPage ].appendMappedLength( nCharYOffset, aDA ); 5233cdf0e10cSrcweir aDA.append( " Td (" ); 5234cdf0e10cSrcweir aDA.append( cMark ); 5235cdf0e10cSrcweir aDA.append( ") Tj\nET\nQ\nEMC\n" ); 5236cdf0e10cSrcweir writeBuffer( aDA.getStr(), aDA.getLength() ); 5237cdf0e10cSrcweir endRedirect(); 5238cdf0e10cSrcweir rBox.m_aAppearances[ "N" ][ "Yes" ] = pCheckStream; 5239cdf0e10cSrcweir 5240cdf0e10cSrcweir SvMemoryStream* pUncheckStream = new SvMemoryStream( 256, 256 ); 5241cdf0e10cSrcweir beginRedirect( pUncheckStream, aCheckRect ); 5242cdf0e10cSrcweir writeBuffer( "/Tx BMC\nEMC\n", 12 ); 5243cdf0e10cSrcweir endRedirect(); 5244cdf0e10cSrcweir rBox.m_aAppearances[ "N" ][ "Off" ] = pUncheckStream; 5245cdf0e10cSrcweir } 5246cdf0e10cSrcweir 5247cdf0e10cSrcweir void PDFWriterImpl::createDefaultRadioButtonAppearance( PDFWidget& rBox, const PDFWriter::RadioButtonWidget& rWidget ) 5248cdf0e10cSrcweir { 5249cdf0e10cSrcweir const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings(); 5250cdf0e10cSrcweir 5251cdf0e10cSrcweir // save graphics state 5252cdf0e10cSrcweir push( sal::static_int_cast<sal_uInt16>(~0U) ); 5253cdf0e10cSrcweir 5254cdf0e10cSrcweir if( rWidget.Background || rWidget.Border ) 5255cdf0e10cSrcweir { 5256cdf0e10cSrcweir setLineColor( rWidget.Border ? replaceColor( rWidget.BorderColor, rSettings.GetCheckedColor() ) : Color( COL_TRANSPARENT ) ); 5257cdf0e10cSrcweir setFillColor( rWidget.Background ? replaceColor( rWidget.BackgroundColor, rSettings.GetFieldColor() ) : Color( COL_TRANSPARENT ) ); 5258cdf0e10cSrcweir drawRectangle( rBox.m_aRect ); 5259cdf0e10cSrcweir } 5260cdf0e10cSrcweir 5261cdf0e10cSrcweir Font aFont = replaceFont( rWidget.TextFont, rSettings.GetRadioCheckFont() ); 5262cdf0e10cSrcweir setFont( aFont ); 5263cdf0e10cSrcweir Size aFontSize = aFont.GetSize(); 5264cdf0e10cSrcweir if( aFontSize.Height() > rBox.m_aRect.GetHeight() ) 5265cdf0e10cSrcweir aFontSize.Height() = rBox.m_aRect.GetHeight(); 5266cdf0e10cSrcweir sal_Int32 nDelta = aFontSize.Height()/10; 5267cdf0e10cSrcweir if( nDelta < 1 ) 5268cdf0e10cSrcweir nDelta = 1; 5269cdf0e10cSrcweir 5270cdf0e10cSrcweir Rectangle aCheckRect, aTextRect; 5271cdf0e10cSrcweir if( rWidget.ButtonIsLeft ) 5272cdf0e10cSrcweir { 5273cdf0e10cSrcweir aCheckRect.Left() = rBox.m_aRect.Left() + nDelta; 5274cdf0e10cSrcweir aCheckRect.Top() = rBox.m_aRect.Top() + (rBox.m_aRect.GetHeight()-aFontSize.Height())/2; 5275cdf0e10cSrcweir aCheckRect.Right() = aCheckRect.Left() + aFontSize.Height(); 5276cdf0e10cSrcweir aCheckRect.Bottom() = aCheckRect.Top() + aFontSize.Height(); 5277cdf0e10cSrcweir 5278cdf0e10cSrcweir // #i74206# handle small controls without text area 5279cdf0e10cSrcweir while( aCheckRect.GetWidth() > rBox.m_aRect.GetWidth() && aCheckRect.GetWidth() > nDelta ) 5280cdf0e10cSrcweir { 5281cdf0e10cSrcweir aCheckRect.Right() -= nDelta; 5282cdf0e10cSrcweir aCheckRect.Top() += nDelta/2; 5283cdf0e10cSrcweir aCheckRect.Bottom() -= nDelta - (nDelta/2); 5284cdf0e10cSrcweir } 5285cdf0e10cSrcweir 5286cdf0e10cSrcweir aTextRect.Left() = rBox.m_aRect.Left() + aCheckRect.GetWidth()+5*nDelta; 5287cdf0e10cSrcweir aTextRect.Top() = rBox.m_aRect.Top(); 5288cdf0e10cSrcweir aTextRect.Right() = aTextRect.Left() + rBox.m_aRect.GetWidth() - aCheckRect.GetWidth()-6*nDelta; 5289cdf0e10cSrcweir aTextRect.Bottom() = rBox.m_aRect.Bottom(); 5290cdf0e10cSrcweir } 5291cdf0e10cSrcweir else 5292cdf0e10cSrcweir { 5293cdf0e10cSrcweir aCheckRect.Left() = rBox.m_aRect.Right() - nDelta - aFontSize.Height(); 5294cdf0e10cSrcweir aCheckRect.Top() = rBox.m_aRect.Top() + (rBox.m_aRect.GetHeight()-aFontSize.Height())/2; 5295cdf0e10cSrcweir aCheckRect.Right() = aCheckRect.Left() + aFontSize.Height(); 5296cdf0e10cSrcweir aCheckRect.Bottom() = aCheckRect.Top() + aFontSize.Height(); 5297cdf0e10cSrcweir 5298cdf0e10cSrcweir // #i74206# handle small controls without text area 5299cdf0e10cSrcweir while( aCheckRect.GetWidth() > rBox.m_aRect.GetWidth() && aCheckRect.GetWidth() > nDelta ) 5300cdf0e10cSrcweir { 5301cdf0e10cSrcweir aCheckRect.Left() += nDelta; 5302cdf0e10cSrcweir aCheckRect.Top() += nDelta/2; 5303cdf0e10cSrcweir aCheckRect.Bottom() -= nDelta - (nDelta/2); 5304cdf0e10cSrcweir } 5305cdf0e10cSrcweir 5306cdf0e10cSrcweir aTextRect.Left() = rBox.m_aRect.Left(); 5307cdf0e10cSrcweir aTextRect.Top() = rBox.m_aRect.Top(); 5308cdf0e10cSrcweir aTextRect.Right() = aTextRect.Left() + rBox.m_aRect.GetWidth() - aCheckRect.GetWidth()-6*nDelta; 5309cdf0e10cSrcweir aTextRect.Bottom() = rBox.m_aRect.Bottom(); 5310cdf0e10cSrcweir } 5311cdf0e10cSrcweir setLineColor( Color( COL_BLACK ) ); 5312cdf0e10cSrcweir setFillColor( Color( COL_TRANSPARENT ) ); 5313cdf0e10cSrcweir OStringBuffer aLW( 32 ); 5314cdf0e10cSrcweir aLW.append( "q " ); 5315cdf0e10cSrcweir m_aPages[ m_nCurrentPage ].appendMappedLength( nDelta, aLW ); 5316cdf0e10cSrcweir aLW.append( " w " ); 5317cdf0e10cSrcweir writeBuffer( aLW.getStr(), aLW.getLength() ); 5318cdf0e10cSrcweir drawEllipse( aCheckRect ); 5319cdf0e10cSrcweir writeBuffer( " Q\n", 3 ); 5320cdf0e10cSrcweir setTextColor( replaceColor( rWidget.TextColor, rSettings.GetRadioCheckTextColor() ) ); 5321cdf0e10cSrcweir drawText( aTextRect, rBox.m_aText, rBox.m_nTextStyle ); 5322cdf0e10cSrcweir 5323cdf0e10cSrcweir pop(); 5324cdf0e10cSrcweir 5325cdf0e10cSrcweir OStringBuffer aDA( 256 ); 5326cdf0e10cSrcweir appendNonStrokingColor( replaceColor( rWidget.TextColor, rSettings.GetRadioCheckTextColor() ), aDA ); 5327cdf0e10cSrcweir sal_Int32 nBest = getBestBuiltinFont( Font( String( RTL_CONSTASCII_USTRINGPARAM( "ZapfDingbats" ) ), aFont.GetSize() ) ); 5328cdf0e10cSrcweir aDA.append( ' ' ); 5329cdf0e10cSrcweir aDA.append( m_aBuiltinFonts[nBest].getNameObject() ); 5330cdf0e10cSrcweir aDA.append( " 0 Tf" ); 5331cdf0e10cSrcweir rBox.m_aDAString = aDA.makeStringAndClear(); 5332cdf0e10cSrcweir //to encrypt this (el) 5333cdf0e10cSrcweir rBox.m_aMKDict = "/CA"; 5334cdf0e10cSrcweir //after this assignement, to m_aMKDic cannot be added anything 5335cdf0e10cSrcweir rBox.m_aMKDictCAString = "l"; 5336cdf0e10cSrcweir 5337cdf0e10cSrcweir rBox.m_aRect = aCheckRect; 5338cdf0e10cSrcweir 5339cdf0e10cSrcweir // create appearance streams 5340cdf0e10cSrcweir push( sal::static_int_cast<sal_uInt16>(~0U) ); 5341cdf0e10cSrcweir SvMemoryStream* pCheckStream = new SvMemoryStream( 256, 256 ); 5342cdf0e10cSrcweir 5343cdf0e10cSrcweir beginRedirect( pCheckStream, aCheckRect ); 5344cdf0e10cSrcweir aDA.append( "/Tx BMC\nq BT\n" ); 5345cdf0e10cSrcweir appendNonStrokingColor( replaceColor( rWidget.TextColor, rSettings.GetRadioCheckTextColor() ), aDA ); 5346cdf0e10cSrcweir aDA.append( ' ' ); 5347cdf0e10cSrcweir aDA.append( m_aBuiltinFonts[nBest].getNameObject() ); 5348cdf0e10cSrcweir aDA.append( ' ' ); 5349cdf0e10cSrcweir m_aPages[m_nCurrentPage].appendMappedLength( sal_Int32( aCheckRect.GetHeight() ), aDA ); 5350cdf0e10cSrcweir aDA.append( " Tf\n0 0 Td\nET\nQ\n" ); 5351cdf0e10cSrcweir writeBuffer( aDA.getStr(), aDA.getLength() ); 5352cdf0e10cSrcweir setFillColor( replaceColor( rWidget.TextColor, rSettings.GetRadioCheckTextColor() ) ); 5353cdf0e10cSrcweir setLineColor( Color( COL_TRANSPARENT ) ); 5354cdf0e10cSrcweir aCheckRect.Left() += 3*nDelta; 5355cdf0e10cSrcweir aCheckRect.Top() += 3*nDelta; 5356cdf0e10cSrcweir aCheckRect.Bottom() -= 3*nDelta; 5357cdf0e10cSrcweir aCheckRect.Right() -= 3*nDelta; 5358cdf0e10cSrcweir drawEllipse( aCheckRect ); 5359cdf0e10cSrcweir writeBuffer( "\nEMC\n", 5 ); 5360cdf0e10cSrcweir endRedirect(); 5361cdf0e10cSrcweir 5362cdf0e10cSrcweir pop(); 5363cdf0e10cSrcweir rBox.m_aAppearances[ "N" ][ "Yes" ] = pCheckStream; 5364cdf0e10cSrcweir 5365cdf0e10cSrcweir SvMemoryStream* pUncheckStream = new SvMemoryStream( 256, 256 ); 5366cdf0e10cSrcweir beginRedirect( pUncheckStream, aCheckRect ); 5367cdf0e10cSrcweir writeBuffer( "/Tx BMC\nEMC\n", 12 ); 5368cdf0e10cSrcweir endRedirect(); 5369cdf0e10cSrcweir rBox.m_aAppearances[ "N" ][ "Off" ] = pUncheckStream; 5370cdf0e10cSrcweir } 5371cdf0e10cSrcweir 5372cdf0e10cSrcweir bool PDFWriterImpl::emitAppearances( PDFWidget& rWidget, OStringBuffer& rAnnotDict ) 5373cdf0e10cSrcweir { 5374cdf0e10cSrcweir 5375cdf0e10cSrcweir // TODO: check and insert default streams 5376cdf0e10cSrcweir rtl::OString aStandardAppearance; 5377cdf0e10cSrcweir switch( rWidget.m_eType ) 5378cdf0e10cSrcweir { 5379cdf0e10cSrcweir case PDFWriter::CheckBox: 5380cdf0e10cSrcweir aStandardAppearance = OUStringToOString( rWidget.m_aValue, RTL_TEXTENCODING_ASCII_US ); 5381cdf0e10cSrcweir break; 5382cdf0e10cSrcweir default: 5383cdf0e10cSrcweir break; 5384cdf0e10cSrcweir } 5385cdf0e10cSrcweir 5386cdf0e10cSrcweir if( rWidget.m_aAppearances.size() ) 5387cdf0e10cSrcweir { 5388cdf0e10cSrcweir rAnnotDict.append( "/AP<<\n" ); 5389cdf0e10cSrcweir for( PDFAppearanceMap::iterator dict_it = rWidget.m_aAppearances.begin(); dict_it != rWidget.m_aAppearances.end(); ++dict_it ) 5390cdf0e10cSrcweir { 5391cdf0e10cSrcweir rAnnotDict.append( "/" ); 5392cdf0e10cSrcweir rAnnotDict.append( dict_it->first ); 5393cdf0e10cSrcweir bool bUseSubDict = (dict_it->second.size() > 1); 5394cdf0e10cSrcweir rAnnotDict.append( bUseSubDict ? "<<" : " " ); 5395cdf0e10cSrcweir 5396cdf0e10cSrcweir for( PDFAppearanceStreams::const_iterator stream_it = dict_it->second.begin(); 5397cdf0e10cSrcweir stream_it != dict_it->second.end(); ++stream_it ) 5398cdf0e10cSrcweir { 5399cdf0e10cSrcweir SvMemoryStream* pApppearanceStream = stream_it->second; 5400cdf0e10cSrcweir dict_it->second[ stream_it->first ] = NULL; 5401cdf0e10cSrcweir 5402cdf0e10cSrcweir bool bDeflate = compressStream( pApppearanceStream ); 5403cdf0e10cSrcweir 5404cdf0e10cSrcweir pApppearanceStream->Seek( STREAM_SEEK_TO_END ); 5405cdf0e10cSrcweir sal_Int64 nStreamLen = pApppearanceStream->Tell(); 5406cdf0e10cSrcweir pApppearanceStream->Seek( STREAM_SEEK_TO_BEGIN ); 5407cdf0e10cSrcweir sal_Int32 nObject = createObject(); 5408cdf0e10cSrcweir CHECK_RETURN( updateObject( nObject ) ); 5409cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 5410cdf0e10cSrcweir emitComment( "PDFWriterImpl::emitAppearances" ); 5411cdf0e10cSrcweir #endif 5412cdf0e10cSrcweir OStringBuffer aLine; 5413cdf0e10cSrcweir aLine.append( nObject ); 5414cdf0e10cSrcweir 5415cdf0e10cSrcweir aLine.append( " 0 obj\n" 5416cdf0e10cSrcweir "<</Type/XObject\n" 5417cdf0e10cSrcweir "/Subtype/Form\n" 5418cdf0e10cSrcweir "/BBox[0 0 " ); 5419cdf0e10cSrcweir appendFixedInt( rWidget.m_aRect.GetWidth()-1, aLine ); 5420cdf0e10cSrcweir aLine.append( " " ); 5421cdf0e10cSrcweir appendFixedInt( rWidget.m_aRect.GetHeight()-1, aLine ); 5422cdf0e10cSrcweir aLine.append( "]\n" 5423cdf0e10cSrcweir "/Resources " ); 5424cdf0e10cSrcweir aLine.append( getResourceDictObj() ); 5425cdf0e10cSrcweir aLine.append( " 0 R\n" 5426cdf0e10cSrcweir "/Length " ); 5427cdf0e10cSrcweir aLine.append( nStreamLen ); 5428cdf0e10cSrcweir aLine.append( "\n" ); 5429cdf0e10cSrcweir if( bDeflate ) 5430cdf0e10cSrcweir aLine.append( "/Filter/FlateDecode\n" ); 5431cdf0e10cSrcweir aLine.append( ">>\nstream\n" ); 5432cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) ); 5433cdf0e10cSrcweir checkAndEnableStreamEncryption( nObject ); 5434cdf0e10cSrcweir CHECK_RETURN( writeBuffer( pApppearanceStream->GetData(), nStreamLen ) ); 5435cdf0e10cSrcweir disableStreamEncryption(); 5436cdf0e10cSrcweir CHECK_RETURN( writeBuffer( "\nendstream\nendobj\n\n", 19 ) ); 5437cdf0e10cSrcweir 5438cdf0e10cSrcweir if( bUseSubDict ) 5439cdf0e10cSrcweir { 5440cdf0e10cSrcweir rAnnotDict.append( " /" ); 5441cdf0e10cSrcweir rAnnotDict.append( stream_it->first ); 5442cdf0e10cSrcweir rAnnotDict.append( " " ); 5443cdf0e10cSrcweir } 5444cdf0e10cSrcweir rAnnotDict.append( nObject ); 5445cdf0e10cSrcweir rAnnotDict.append( " 0 R" ); 5446cdf0e10cSrcweir 5447cdf0e10cSrcweir delete pApppearanceStream; 5448cdf0e10cSrcweir } 5449cdf0e10cSrcweir 5450cdf0e10cSrcweir rAnnotDict.append( bUseSubDict ? ">>\n" : "\n" ); 5451cdf0e10cSrcweir } 5452cdf0e10cSrcweir rAnnotDict.append( ">>\n" ); 5453cdf0e10cSrcweir if( aStandardAppearance.getLength() ) 5454cdf0e10cSrcweir { 5455cdf0e10cSrcweir rAnnotDict.append( "/AS /" ); 5456cdf0e10cSrcweir rAnnotDict.append( aStandardAppearance ); 5457cdf0e10cSrcweir rAnnotDict.append( "\n" ); 5458cdf0e10cSrcweir } 5459cdf0e10cSrcweir } 5460cdf0e10cSrcweir 5461cdf0e10cSrcweir return true; 5462cdf0e10cSrcweir } 5463cdf0e10cSrcweir 5464cdf0e10cSrcweir bool PDFWriterImpl::emitWidgetAnnotations() 5465cdf0e10cSrcweir { 5466cdf0e10cSrcweir ensureUniqueRadioOnValues(); 5467cdf0e10cSrcweir 5468cdf0e10cSrcweir int nAnnots = m_aWidgets.size(); 5469cdf0e10cSrcweir for( int a = 0; a < nAnnots; a++ ) 5470cdf0e10cSrcweir { 5471cdf0e10cSrcweir PDFWidget& rWidget = m_aWidgets[a]; 5472cdf0e10cSrcweir 5473cdf0e10cSrcweir OStringBuffer aLine( 1024 ); 5474cdf0e10cSrcweir OStringBuffer aValue( 256 ); 5475cdf0e10cSrcweir aLine.append( rWidget.m_nObject ); 5476cdf0e10cSrcweir aLine.append( " 0 obj\n" 5477cdf0e10cSrcweir "<<" ); 5478cdf0e10cSrcweir if( rWidget.m_eType != PDFWriter::Hierarchy ) 5479cdf0e10cSrcweir { 5480cdf0e10cSrcweir // emit widget annotation only for terminal fields 5481cdf0e10cSrcweir if( rWidget.m_aKids.empty() ) 5482cdf0e10cSrcweir { 5483cdf0e10cSrcweir aLine.append( "/Type/Annot/Subtype/Widget/F 4\n" 5484cdf0e10cSrcweir "/Rect[" ); 5485cdf0e10cSrcweir appendFixedInt( rWidget.m_aRect.Left()-1, aLine ); 5486cdf0e10cSrcweir aLine.append( ' ' ); 5487cdf0e10cSrcweir appendFixedInt( rWidget.m_aRect.Top()+1, aLine ); 5488cdf0e10cSrcweir aLine.append( ' ' ); 5489cdf0e10cSrcweir appendFixedInt( rWidget.m_aRect.Right()+1, aLine ); 5490cdf0e10cSrcweir aLine.append( ' ' ); 5491cdf0e10cSrcweir appendFixedInt( rWidget.m_aRect.Bottom()-1, aLine ); 5492cdf0e10cSrcweir aLine.append( "]\n" ); 5493cdf0e10cSrcweir } 5494cdf0e10cSrcweir aLine.append( "/FT/" ); 5495cdf0e10cSrcweir switch( rWidget.m_eType ) 5496cdf0e10cSrcweir { 5497cdf0e10cSrcweir case PDFWriter::RadioButton: 5498cdf0e10cSrcweir case PDFWriter::CheckBox: 5499cdf0e10cSrcweir // for radio buttons only the RadioButton field, not the 5500cdf0e10cSrcweir // CheckBox children should have a value, else acrobat reader 5501cdf0e10cSrcweir // does not always check the right button 5502cdf0e10cSrcweir // of course real check boxes (not belonging to a readio group) 5503cdf0e10cSrcweir // need their values, too 5504cdf0e10cSrcweir if( rWidget.m_eType == PDFWriter::RadioButton || rWidget.m_nRadioGroup < 0 ) 5505cdf0e10cSrcweir { 5506cdf0e10cSrcweir aValue.append( "/" ); 5507cdf0e10cSrcweir // check for radio group with all buttons unpressed 5508cdf0e10cSrcweir if( rWidget.m_aValue.getLength() == 0 ) 5509cdf0e10cSrcweir aValue.append( "Off" ); 5510cdf0e10cSrcweir else 5511cdf0e10cSrcweir appendName( rWidget.m_aValue, aValue ); 5512cdf0e10cSrcweir } 5513cdf0e10cSrcweir case PDFWriter::PushButton: 5514cdf0e10cSrcweir aLine.append( "Btn" ); 5515cdf0e10cSrcweir break; 5516cdf0e10cSrcweir case PDFWriter::ListBox: 5517cdf0e10cSrcweir if( rWidget.m_nFlags & 0x200000 ) // multiselect 5518cdf0e10cSrcweir { 5519cdf0e10cSrcweir aValue.append( "[" ); 5520cdf0e10cSrcweir for( unsigned int i = 0; i < rWidget.m_aSelectedEntries.size(); i++ ) 5521cdf0e10cSrcweir { 5522cdf0e10cSrcweir sal_Int32 nEntry = rWidget.m_aSelectedEntries[i]; 5523cdf0e10cSrcweir if( nEntry >= 0 && nEntry < sal_Int32(rWidget.m_aListEntries.size()) ) 5524cdf0e10cSrcweir appendUnicodeTextStringEncrypt( rWidget.m_aListEntries[ nEntry ], rWidget.m_nObject, aValue ); 5525cdf0e10cSrcweir } 5526cdf0e10cSrcweir aValue.append( "]" ); 5527cdf0e10cSrcweir } 5528cdf0e10cSrcweir else if( rWidget.m_aSelectedEntries.size() > 0 && 5529cdf0e10cSrcweir rWidget.m_aSelectedEntries[0] >= 0 && 5530cdf0e10cSrcweir rWidget.m_aSelectedEntries[0] < sal_Int32(rWidget.m_aListEntries.size()) ) 5531cdf0e10cSrcweir { 5532cdf0e10cSrcweir appendUnicodeTextStringEncrypt( rWidget.m_aListEntries[ rWidget.m_aSelectedEntries[0] ], rWidget.m_nObject, aValue ); 5533cdf0e10cSrcweir } 5534cdf0e10cSrcweir else 5535cdf0e10cSrcweir appendUnicodeTextStringEncrypt( rtl::OUString(), rWidget.m_nObject, aValue ); 5536cdf0e10cSrcweir aLine.append( "Ch" ); 5537cdf0e10cSrcweir break; 5538cdf0e10cSrcweir case PDFWriter::ComboBox: 5539cdf0e10cSrcweir appendUnicodeTextStringEncrypt( rWidget.m_aValue, rWidget.m_nObject, aValue ); 5540cdf0e10cSrcweir aLine.append( "Ch" ); 5541cdf0e10cSrcweir break; 5542cdf0e10cSrcweir case PDFWriter::Edit: 5543cdf0e10cSrcweir aLine.append( "Tx" ); 5544cdf0e10cSrcweir appendUnicodeTextStringEncrypt( rWidget.m_aValue, rWidget.m_nObject, aValue ); 5545cdf0e10cSrcweir break; 5546cdf0e10cSrcweir case PDFWriter::Hierarchy: // make the compiler happy 5547cdf0e10cSrcweir break; 5548cdf0e10cSrcweir } 5549cdf0e10cSrcweir aLine.append( "\n" ); 5550cdf0e10cSrcweir aLine.append( "/P " ); 5551cdf0e10cSrcweir aLine.append( m_aPages[ rWidget.m_nPage ].m_nPageObject ); 5552cdf0e10cSrcweir aLine.append( " 0 R\n" ); 5553cdf0e10cSrcweir } 5554cdf0e10cSrcweir if( rWidget.m_nParent ) 5555cdf0e10cSrcweir { 5556cdf0e10cSrcweir aLine.append( "/Parent " ); 5557cdf0e10cSrcweir aLine.append( rWidget.m_nParent ); 5558cdf0e10cSrcweir aLine.append( " 0 R\n" ); 5559cdf0e10cSrcweir } 5560cdf0e10cSrcweir if( rWidget.m_aKids.size() ) 5561cdf0e10cSrcweir { 5562cdf0e10cSrcweir aLine.append( "/Kids[" ); 5563cdf0e10cSrcweir for( unsigned int i = 0; i < rWidget.m_aKids.size(); i++ ) 5564cdf0e10cSrcweir { 5565cdf0e10cSrcweir aLine.append( rWidget.m_aKids[i] ); 5566cdf0e10cSrcweir aLine.append( " 0 R" ); 5567cdf0e10cSrcweir aLine.append( ( (i&15) == 15 ) ? "\n" : " " ); 5568cdf0e10cSrcweir } 5569cdf0e10cSrcweir aLine.append( "]\n" ); 5570cdf0e10cSrcweir } 5571cdf0e10cSrcweir if( rWidget.m_aName.getLength() ) 5572cdf0e10cSrcweir { 5573cdf0e10cSrcweir aLine.append( "/T" ); 5574cdf0e10cSrcweir appendLiteralStringEncrypt( rWidget.m_aName, rWidget.m_nObject, aLine ); 5575cdf0e10cSrcweir aLine.append( "\n" ); 5576cdf0e10cSrcweir } 5577cdf0e10cSrcweir if( m_aContext.Version > PDFWriter::PDF_1_2 && rWidget.m_aDescription.getLength() ) 5578cdf0e10cSrcweir { 5579cdf0e10cSrcweir // the alternate field name should be unicode able since it is 5580cdf0e10cSrcweir // supposed to be used in UI 5581cdf0e10cSrcweir aLine.append( "/TU" ); 5582cdf0e10cSrcweir appendUnicodeTextStringEncrypt( rWidget.m_aDescription, rWidget.m_nObject, aLine ); 5583cdf0e10cSrcweir aLine.append( "\n" ); 5584cdf0e10cSrcweir } 5585cdf0e10cSrcweir 5586cdf0e10cSrcweir if( rWidget.m_nFlags ) 5587cdf0e10cSrcweir { 5588cdf0e10cSrcweir aLine.append( "/Ff " ); 5589cdf0e10cSrcweir aLine.append( rWidget.m_nFlags ); 5590cdf0e10cSrcweir aLine.append( "\n" ); 5591cdf0e10cSrcweir } 5592cdf0e10cSrcweir if( aValue.getLength() ) 5593cdf0e10cSrcweir { 5594cdf0e10cSrcweir OString aVal = aValue.makeStringAndClear(); 5595cdf0e10cSrcweir aLine.append( "/V " ); 5596cdf0e10cSrcweir aLine.append( aVal ); 5597cdf0e10cSrcweir aLine.append( "\n" 5598cdf0e10cSrcweir "/DV " ); 5599cdf0e10cSrcweir aLine.append( aVal ); 5600cdf0e10cSrcweir aLine.append( "\n" ); 5601cdf0e10cSrcweir } 5602cdf0e10cSrcweir if( rWidget.m_eType == PDFWriter::ListBox || rWidget.m_eType == PDFWriter::ComboBox ) 5603cdf0e10cSrcweir { 5604cdf0e10cSrcweir sal_Int32 nTI = -1; 5605cdf0e10cSrcweir aLine.append( "/Opt[\n" ); 5606cdf0e10cSrcweir sal_Int32 i = 0; 5607cdf0e10cSrcweir for( std::vector< OUString >::const_iterator it = rWidget.m_aListEntries.begin(); it != rWidget.m_aListEntries.end(); ++it, ++i ) 5608cdf0e10cSrcweir { 5609cdf0e10cSrcweir appendUnicodeTextStringEncrypt( *it, rWidget.m_nObject, aLine ); 5610cdf0e10cSrcweir aLine.append( "\n" ); 5611cdf0e10cSrcweir if( *it == rWidget.m_aValue ) 5612cdf0e10cSrcweir nTI = i; 5613cdf0e10cSrcweir } 5614cdf0e10cSrcweir aLine.append( "]\n" ); 5615cdf0e10cSrcweir if( nTI > 0 ) 5616cdf0e10cSrcweir { 5617cdf0e10cSrcweir aLine.append( "/TI " ); 5618cdf0e10cSrcweir aLine.append( nTI ); 5619cdf0e10cSrcweir aLine.append( "\n" ); 5620cdf0e10cSrcweir if( rWidget.m_nFlags & 0x200000 ) // Multiselect 5621cdf0e10cSrcweir { 5622cdf0e10cSrcweir aLine.append( "/I [" ); 5623cdf0e10cSrcweir aLine.append( nTI ); 5624cdf0e10cSrcweir aLine.append( "]\n" ); 5625cdf0e10cSrcweir } 5626cdf0e10cSrcweir } 5627cdf0e10cSrcweir } 5628cdf0e10cSrcweir if( rWidget.m_eType == PDFWriter::Edit && rWidget.m_nMaxLen > 0 ) 5629cdf0e10cSrcweir { 5630cdf0e10cSrcweir aLine.append( "/MaxLen " ); 5631cdf0e10cSrcweir aLine.append( rWidget.m_nMaxLen ); 5632cdf0e10cSrcweir aLine.append( "\n" ); 5633cdf0e10cSrcweir } 5634cdf0e10cSrcweir if( rWidget.m_eType == PDFWriter::PushButton ) 5635cdf0e10cSrcweir { 5636cdf0e10cSrcweir if(!m_bIsPDF_A1) 5637cdf0e10cSrcweir { 5638cdf0e10cSrcweir OStringBuffer aDest; 5639cdf0e10cSrcweir if( rWidget.m_nDest != -1 && appendDest( m_aDestinationIdTranslation[ rWidget.m_nDest ], aDest ) ) 5640cdf0e10cSrcweir { 5641cdf0e10cSrcweir aLine.append( "/AA<</D<</Type/Action/S/GoTo/D " ); 5642cdf0e10cSrcweir aLine.append( aDest.makeStringAndClear() ); 5643cdf0e10cSrcweir aLine.append( ">>>>\n" ); 5644cdf0e10cSrcweir } 5645cdf0e10cSrcweir else if( rWidget.m_aListEntries.empty() ) 5646cdf0e10cSrcweir { 5647cdf0e10cSrcweir // create a reset form action 5648cdf0e10cSrcweir aLine.append( "/AA<</D<</Type/Action/S/ResetForm>>>>\n" ); 5649cdf0e10cSrcweir } 5650cdf0e10cSrcweir else if( rWidget.m_bSubmit ) 5651cdf0e10cSrcweir { 5652cdf0e10cSrcweir // create a submit form action 5653cdf0e10cSrcweir aLine.append( "/AA<</D<</Type/Action/S/SubmitForm/F" ); 5654cdf0e10cSrcweir appendLiteralStringEncrypt( rWidget.m_aListEntries.front(), rWidget.m_nObject, aLine, osl_getThreadTextEncoding() ); 5655cdf0e10cSrcweir aLine.append( "/Flags " ); 5656cdf0e10cSrcweir 5657cdf0e10cSrcweir sal_Int32 nFlags = 0; 5658cdf0e10cSrcweir switch( m_aContext.SubmitFormat ) 5659cdf0e10cSrcweir { 5660cdf0e10cSrcweir case PDFWriter::HTML: 5661cdf0e10cSrcweir nFlags |= 4; 5662cdf0e10cSrcweir break; 5663cdf0e10cSrcweir case PDFWriter::XML: 5664cdf0e10cSrcweir if( m_aContext.Version > PDFWriter::PDF_1_3 ) 5665cdf0e10cSrcweir nFlags |= 32; 5666cdf0e10cSrcweir break; 5667cdf0e10cSrcweir case PDFWriter::PDF: 5668cdf0e10cSrcweir if( m_aContext.Version > PDFWriter::PDF_1_3 ) 5669cdf0e10cSrcweir nFlags |= 256; 5670cdf0e10cSrcweir break; 5671cdf0e10cSrcweir case PDFWriter::FDF: 5672cdf0e10cSrcweir default: 5673cdf0e10cSrcweir break; 5674cdf0e10cSrcweir } 5675cdf0e10cSrcweir if( rWidget.m_bSubmitGet ) 5676cdf0e10cSrcweir nFlags |= 8; 5677cdf0e10cSrcweir aLine.append( nFlags ); 5678cdf0e10cSrcweir aLine.append( ">>>>\n" ); 5679cdf0e10cSrcweir } 5680cdf0e10cSrcweir else 5681cdf0e10cSrcweir { 5682cdf0e10cSrcweir // create a URI action 5683cdf0e10cSrcweir aLine.append( "/AA<</D<</Type/Action/S/URI/URI(" ); 5684cdf0e10cSrcweir aLine.append( OUStringToOString( rWidget.m_aListEntries.front(), RTL_TEXTENCODING_ASCII_US ) ); 5685cdf0e10cSrcweir aLine.append( ")>>>>\n" ); 5686cdf0e10cSrcweir } 5687cdf0e10cSrcweir } 5688cdf0e10cSrcweir else 5689cdf0e10cSrcweir m_aErrors.insert( PDFWriter::Warning_FormAction_Omitted_PDFA ); 5690cdf0e10cSrcweir } 5691cdf0e10cSrcweir if( rWidget.m_aDAString.getLength() ) 5692cdf0e10cSrcweir { 5693cdf0e10cSrcweir if( rWidget.m_aDRDict.getLength() ) 5694cdf0e10cSrcweir { 5695cdf0e10cSrcweir aLine.append( "/DR<<" ); 5696cdf0e10cSrcweir aLine.append( rWidget.m_aDRDict ); 5697cdf0e10cSrcweir aLine.append( ">>\n" ); 5698cdf0e10cSrcweir } 5699cdf0e10cSrcweir else 5700cdf0e10cSrcweir { 5701cdf0e10cSrcweir aLine.append( "/DR<</Font<<" ); 5702cdf0e10cSrcweir appendBuiltinFontsToDict( aLine ); 5703cdf0e10cSrcweir aLine.append( ">>>>\n" ); 5704cdf0e10cSrcweir } 5705cdf0e10cSrcweir aLine.append( "/DA" ); 5706cdf0e10cSrcweir appendLiteralStringEncrypt( rWidget.m_aDAString, rWidget.m_nObject, aLine ); 5707cdf0e10cSrcweir aLine.append( "\n" ); 5708cdf0e10cSrcweir if( rWidget.m_nTextStyle & TEXT_DRAW_CENTER ) 5709cdf0e10cSrcweir aLine.append( "/Q 1\n" ); 5710cdf0e10cSrcweir else if( rWidget.m_nTextStyle & TEXT_DRAW_RIGHT ) 5711cdf0e10cSrcweir aLine.append( "/Q 2\n" ); 5712cdf0e10cSrcweir } 5713cdf0e10cSrcweir // appearance charactristics for terminal fields 5714cdf0e10cSrcweir // which are supposed to have an appearance constructed 5715cdf0e10cSrcweir // by the viewer application 5716cdf0e10cSrcweir if( rWidget.m_aMKDict.getLength() ) 5717cdf0e10cSrcweir { 5718cdf0e10cSrcweir aLine.append( "/MK<<" ); 5719cdf0e10cSrcweir aLine.append( rWidget.m_aMKDict ); 5720cdf0e10cSrcweir //add the CA string, encrypting it 5721cdf0e10cSrcweir appendLiteralStringEncrypt(rWidget.m_aMKDictCAString, rWidget.m_nObject, aLine); 5722cdf0e10cSrcweir aLine.append( ">>\n" ); 5723cdf0e10cSrcweir } 5724cdf0e10cSrcweir 5725cdf0e10cSrcweir CHECK_RETURN( emitAppearances( rWidget, aLine ) ); 5726cdf0e10cSrcweir 5727cdf0e10cSrcweir aLine.append( ">>\n" 5728cdf0e10cSrcweir "endobj\n\n" ); 5729cdf0e10cSrcweir CHECK_RETURN( updateObject( rWidget.m_nObject ) ); 5730cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) ); 5731cdf0e10cSrcweir } 5732cdf0e10cSrcweir return true; 5733cdf0e10cSrcweir } 5734cdf0e10cSrcweir 5735cdf0e10cSrcweir bool PDFWriterImpl::emitAnnotations() 5736cdf0e10cSrcweir { 5737cdf0e10cSrcweir if( m_aPages.size() < 1 ) 5738cdf0e10cSrcweir return false; 5739cdf0e10cSrcweir 5740cdf0e10cSrcweir CHECK_RETURN( emitLinkAnnotations() ); 5741cdf0e10cSrcweir 5742cdf0e10cSrcweir CHECK_RETURN( emitNoteAnnotations() ); 5743cdf0e10cSrcweir 5744cdf0e10cSrcweir CHECK_RETURN( emitWidgetAnnotations() ); 5745cdf0e10cSrcweir 5746cdf0e10cSrcweir return true; 5747cdf0e10cSrcweir } 5748cdf0e10cSrcweir 5749cdf0e10cSrcweir #undef CHECK_RETURN 5750cdf0e10cSrcweir #define CHECK_RETURN( x ) if( !x ) return false 5751cdf0e10cSrcweir 5752cdf0e10cSrcweir bool PDFWriterImpl::emitCatalog() 5753cdf0e10cSrcweir { 5754cdf0e10cSrcweir // build page tree 5755cdf0e10cSrcweir // currently there is only one node that contains all leaves 5756cdf0e10cSrcweir 5757cdf0e10cSrcweir // first create a page tree node id 5758cdf0e10cSrcweir sal_Int32 nTreeNode = createObject(); 5759cdf0e10cSrcweir 5760cdf0e10cSrcweir // emit global resource dictionary (page emit needs it) 5761cdf0e10cSrcweir CHECK_RETURN( emitResources() ); 5762cdf0e10cSrcweir 5763cdf0e10cSrcweir // emit all pages 5764cdf0e10cSrcweir for( std::vector<PDFPage>::iterator it = m_aPages.begin(); it != m_aPages.end(); ++it ) 5765cdf0e10cSrcweir if( ! it->emit( nTreeNode ) ) 5766cdf0e10cSrcweir return false; 5767cdf0e10cSrcweir 5768cdf0e10cSrcweir sal_Int32 nNamedDestinationsDictionary = emitNamedDestinations(); 5769cdf0e10cSrcweir 5770cdf0e10cSrcweir sal_Int32 nOutlineDict = emitOutline(); 5771cdf0e10cSrcweir 5772cdf0e10cSrcweir //emit Output intent i59651 5773cdf0e10cSrcweir sal_Int32 nOutputIntentObject = emitOutputIntent(); 5774cdf0e10cSrcweir 5775cdf0e10cSrcweir //emit metadata 5776cdf0e10cSrcweir sal_Int32 nMetadataObject = emitDocumentMetadata(); 5777cdf0e10cSrcweir 5778cdf0e10cSrcweir sal_Int32 nStructureDict = 0; 5779cdf0e10cSrcweir if(m_aStructure.size() > 1) 5780cdf0e10cSrcweir { 5781cdf0e10cSrcweir ///check if dummy structure containers are needed 5782cdf0e10cSrcweir addInternalStructureContainer(m_aStructure[0]); 5783cdf0e10cSrcweir nStructureDict = m_aStructure[0].m_nObject = createObject(); 5784cdf0e10cSrcweir emitStructure( m_aStructure[ 0 ] ); 5785cdf0e10cSrcweir } 5786cdf0e10cSrcweir 5787cdf0e10cSrcweir // adjust tree node file offset 5788cdf0e10cSrcweir if( ! updateObject( nTreeNode ) ) 5789cdf0e10cSrcweir return false; 5790cdf0e10cSrcweir 5791cdf0e10cSrcweir // emit tree node 5792cdf0e10cSrcweir OStringBuffer aLine( 2048 ); 5793cdf0e10cSrcweir aLine.append( nTreeNode ); 5794cdf0e10cSrcweir aLine.append( " 0 obj\n" ); 5795cdf0e10cSrcweir aLine.append( "<</Type/Pages\n" ); 5796cdf0e10cSrcweir aLine.append( "/Resources " ); 5797cdf0e10cSrcweir aLine.append( getResourceDictObj() ); 5798cdf0e10cSrcweir aLine.append( " 0 R\n" ); 5799cdf0e10cSrcweir 5800cdf0e10cSrcweir switch( m_eInheritedOrientation ) 5801cdf0e10cSrcweir { 5802cdf0e10cSrcweir case PDFWriter::Landscape: aLine.append( "/Rotate 90\n" );break; 5803cdf0e10cSrcweir case PDFWriter::Seascape: aLine.append( "/Rotate -90\n" );break; 5804cdf0e10cSrcweir 5805cdf0e10cSrcweir case PDFWriter::Inherit: // actually Inherit would be a bug, but insignificant 5806cdf0e10cSrcweir case PDFWriter::Portrait: 5807cdf0e10cSrcweir default: 5808cdf0e10cSrcweir break; 5809cdf0e10cSrcweir } 5810cdf0e10cSrcweir sal_Int32 nMediaBoxWidth = 0; 5811cdf0e10cSrcweir sal_Int32 nMediaBoxHeight = 0; 5812cdf0e10cSrcweir if( m_aPages.empty() ) // sanity check, this should not happen 5813cdf0e10cSrcweir { 5814cdf0e10cSrcweir nMediaBoxWidth = m_nInheritedPageWidth; 5815cdf0e10cSrcweir nMediaBoxHeight = m_nInheritedPageHeight; 5816cdf0e10cSrcweir } 5817cdf0e10cSrcweir else 5818cdf0e10cSrcweir { 5819cdf0e10cSrcweir for( std::vector<PDFPage>::const_iterator iter = m_aPages.begin(); iter != m_aPages.end(); ++iter ) 5820cdf0e10cSrcweir { 5821cdf0e10cSrcweir if( iter->m_nPageWidth > nMediaBoxWidth ) 5822cdf0e10cSrcweir nMediaBoxWidth = iter->m_nPageWidth; 5823cdf0e10cSrcweir if( iter->m_nPageHeight > nMediaBoxHeight ) 5824cdf0e10cSrcweir nMediaBoxHeight = iter->m_nPageHeight; 5825cdf0e10cSrcweir } 5826cdf0e10cSrcweir } 5827cdf0e10cSrcweir aLine.append( "/MediaBox[ 0 0 " ); 5828cdf0e10cSrcweir aLine.append( nMediaBoxWidth ); 5829cdf0e10cSrcweir aLine.append( ' ' ); 5830cdf0e10cSrcweir aLine.append( nMediaBoxHeight ); 5831cdf0e10cSrcweir aLine.append( " ]\n" 5832cdf0e10cSrcweir "/Kids[ " ); 5833cdf0e10cSrcweir unsigned int i = 0; 5834cdf0e10cSrcweir for( std::vector<PDFPage>::const_iterator iter = m_aPages.begin(); iter != m_aPages.end(); ++iter, i++ ) 5835cdf0e10cSrcweir { 5836cdf0e10cSrcweir aLine.append( iter->m_nPageObject ); 5837cdf0e10cSrcweir aLine.append( " 0 R" ); 5838cdf0e10cSrcweir aLine.append( ( (i&15) == 15 ) ? "\n" : " " ); 5839cdf0e10cSrcweir } 5840cdf0e10cSrcweir aLine.append( "]\n" 5841cdf0e10cSrcweir "/Count " ); 5842cdf0e10cSrcweir aLine.append( (sal_Int32)m_aPages.size() ); 5843cdf0e10cSrcweir aLine.append( ">>\n" 5844cdf0e10cSrcweir "endobj\n\n" ); 5845cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) ); 5846cdf0e10cSrcweir 5847cdf0e10cSrcweir // emit annotation objects 5848cdf0e10cSrcweir CHECK_RETURN( emitAnnotations() ); 5849cdf0e10cSrcweir 5850cdf0e10cSrcweir // emit Catalog 5851cdf0e10cSrcweir m_nCatalogObject = createObject(); 5852cdf0e10cSrcweir if( ! updateObject( m_nCatalogObject ) ) 5853cdf0e10cSrcweir return false; 5854cdf0e10cSrcweir aLine.setLength( 0 ); 5855cdf0e10cSrcweir aLine.append( m_nCatalogObject ); 5856cdf0e10cSrcweir aLine.append( " 0 obj\n" 5857cdf0e10cSrcweir "<</Type/Catalog/Pages " ); 5858cdf0e10cSrcweir aLine.append( nTreeNode ); 5859cdf0e10cSrcweir aLine.append( " 0 R\n" ); 5860cdf0e10cSrcweir //--->i56629 5861cdf0e10cSrcweir //check if there are named destinations to emit (root must be inside the catalog) 5862cdf0e10cSrcweir if( nNamedDestinationsDictionary ) 5863cdf0e10cSrcweir { 5864cdf0e10cSrcweir aLine.append("/Dests "); 5865cdf0e10cSrcweir aLine.append( nNamedDestinationsDictionary ); 5866cdf0e10cSrcweir aLine.append( " 0 R\n" ); 5867cdf0e10cSrcweir } 5868cdf0e10cSrcweir //<---- 5869cdf0e10cSrcweir if( m_aContext.PageLayout != PDFWriter::DefaultLayout ) 5870cdf0e10cSrcweir switch( m_aContext.PageLayout ) 5871cdf0e10cSrcweir { 5872cdf0e10cSrcweir default : 5873cdf0e10cSrcweir case PDFWriter::SinglePage : 5874cdf0e10cSrcweir aLine.append( "/PageLayout/SinglePage\n" ); 5875cdf0e10cSrcweir break; 5876cdf0e10cSrcweir case PDFWriter::Continuous : 5877cdf0e10cSrcweir aLine.append( "/PageLayout/OneColumn\n" ); 5878cdf0e10cSrcweir break; 5879cdf0e10cSrcweir case PDFWriter::ContinuousFacing : 5880cdf0e10cSrcweir //the flag m_aContext.FirstPageLeft below is used to set the page on the left side 5881cdf0e10cSrcweir aLine.append( "/PageLayout/TwoColumnRight\n" );//odd page on the right side 5882cdf0e10cSrcweir break; 5883cdf0e10cSrcweir } 5884cdf0e10cSrcweir if( m_aContext.PDFDocumentMode != PDFWriter::ModeDefault && !m_aContext.OpenInFullScreenMode ) 5885cdf0e10cSrcweir switch( m_aContext.PDFDocumentMode ) 5886cdf0e10cSrcweir { 5887cdf0e10cSrcweir default : 5888cdf0e10cSrcweir aLine.append( "/PageMode/UseNone\n" ); 5889cdf0e10cSrcweir break; 5890cdf0e10cSrcweir case PDFWriter::UseOutlines : 5891cdf0e10cSrcweir aLine.append( "/PageMode/UseOutlines\n" ); //document is opened with outline pane open 5892cdf0e10cSrcweir break; 5893cdf0e10cSrcweir case PDFWriter::UseThumbs : 5894cdf0e10cSrcweir aLine.append( "/PageMode/UseThumbs\n" ); //document is opened with thumbnails pane open 5895cdf0e10cSrcweir break; 5896cdf0e10cSrcweir } 5897cdf0e10cSrcweir else if( m_aContext.OpenInFullScreenMode ) 5898cdf0e10cSrcweir aLine.append( "/PageMode/FullScreen\n" ); //document is opened full screen 5899cdf0e10cSrcweir 5900cdf0e10cSrcweir OStringBuffer aInitPageRef; 5901cdf0e10cSrcweir if( m_aContext.InitialPage >= 0 && m_aContext.InitialPage < (sal_Int32)m_aPages.size() ) 5902cdf0e10cSrcweir { 5903cdf0e10cSrcweir aInitPageRef.append( m_aPages[m_aContext.InitialPage].m_nPageObject ); 5904cdf0e10cSrcweir aInitPageRef.append( " 0 R" ); 5905cdf0e10cSrcweir } 5906cdf0e10cSrcweir else 5907cdf0e10cSrcweir aInitPageRef.append( "0" ); 5908cdf0e10cSrcweir switch( m_aContext.PDFDocumentAction ) 5909cdf0e10cSrcweir { 5910cdf0e10cSrcweir case PDFWriter::ActionDefault : //do nothing, this is the Acrobat default 5911cdf0e10cSrcweir default: 5912cdf0e10cSrcweir if( aInitPageRef.getLength() > 1 ) 5913cdf0e10cSrcweir { 5914cdf0e10cSrcweir aLine.append( "/OpenAction[" ); 5915cdf0e10cSrcweir aLine.append( aInitPageRef ); 5916cdf0e10cSrcweir aLine.append( " /XYZ null null 0]\n" ); 5917cdf0e10cSrcweir } 5918cdf0e10cSrcweir break; 5919cdf0e10cSrcweir case PDFWriter::FitInWindow : 5920cdf0e10cSrcweir aLine.append( "/OpenAction[" ); 5921cdf0e10cSrcweir aLine.append( aInitPageRef ); 5922cdf0e10cSrcweir aLine.append( " /Fit]\n" ); //Open fit page 5923cdf0e10cSrcweir break; 5924cdf0e10cSrcweir case PDFWriter::FitWidth : 5925cdf0e10cSrcweir aLine.append( "/OpenAction[" ); 5926cdf0e10cSrcweir aLine.append( aInitPageRef ); 5927cdf0e10cSrcweir aLine.append( " /FitH " ); 5928cdf0e10cSrcweir aLine.append( m_nInheritedPageHeight );//Open fit width 5929cdf0e10cSrcweir aLine.append( "]\n" ); 5930cdf0e10cSrcweir break; 5931cdf0e10cSrcweir case PDFWriter::FitVisible : 5932cdf0e10cSrcweir aLine.append( "/OpenAction[" ); 5933cdf0e10cSrcweir aLine.append( aInitPageRef ); 5934cdf0e10cSrcweir aLine.append( " /FitBH " ); 5935cdf0e10cSrcweir aLine.append( m_nInheritedPageHeight );//Open fit visible 5936cdf0e10cSrcweir aLine.append( "]\n" ); 5937cdf0e10cSrcweir break; 5938cdf0e10cSrcweir case PDFWriter::ActionZoom : 5939cdf0e10cSrcweir aLine.append( "/OpenAction[" ); 5940cdf0e10cSrcweir aLine.append( aInitPageRef ); 5941cdf0e10cSrcweir aLine.append( " /XYZ null null " ); 5942cdf0e10cSrcweir if( m_aContext.Zoom >= 50 && m_aContext.Zoom <= 1600 ) 5943cdf0e10cSrcweir aLine.append( (double)m_aContext.Zoom/100.0 ); 5944cdf0e10cSrcweir else 5945cdf0e10cSrcweir aLine.append( "0" ); 5946cdf0e10cSrcweir aLine.append( "]\n" ); 5947cdf0e10cSrcweir break; 5948cdf0e10cSrcweir } 5949cdf0e10cSrcweir // viewer preferences, if we had some, then emit 5950cdf0e10cSrcweir if( m_aContext.HideViewerToolbar || 5951cdf0e10cSrcweir ( m_aContext.Version > PDFWriter::PDF_1_3 && m_aContext.DocumentInfo.Title.Len() && m_aContext.DisplayPDFDocumentTitle ) || 5952cdf0e10cSrcweir m_aContext.HideViewerMenubar || 5953cdf0e10cSrcweir m_aContext.HideViewerWindowControls || m_aContext.FitWindow || 5954cdf0e10cSrcweir m_aContext.CenterWindow || (m_aContext.FirstPageLeft && m_aContext.PageLayout == PDFWriter::ContinuousFacing ) || 5955cdf0e10cSrcweir m_aContext.OpenInFullScreenMode ) 5956cdf0e10cSrcweir { 5957cdf0e10cSrcweir aLine.append( "/ViewerPreferences<<" ); 5958cdf0e10cSrcweir if( m_aContext.HideViewerToolbar ) 5959cdf0e10cSrcweir aLine.append( "/HideToolbar true\n" ); 5960cdf0e10cSrcweir if( m_aContext.HideViewerMenubar ) 5961cdf0e10cSrcweir aLine.append( "/HideMenubar true\n" ); 5962cdf0e10cSrcweir if( m_aContext.HideViewerWindowControls ) 5963cdf0e10cSrcweir aLine.append( "/HideWindowUI true\n" ); 5964cdf0e10cSrcweir if( m_aContext.FitWindow ) 5965cdf0e10cSrcweir aLine.append( "/FitWindow true\n" ); 5966cdf0e10cSrcweir if( m_aContext.CenterWindow ) 5967cdf0e10cSrcweir aLine.append( "/CenterWindow true\n" ); 5968cdf0e10cSrcweir if( m_aContext.Version > PDFWriter::PDF_1_3 && m_aContext.DocumentInfo.Title.Len() && m_aContext.DisplayPDFDocumentTitle ) 5969cdf0e10cSrcweir aLine.append( "/DisplayDocTitle true\n" ); 5970cdf0e10cSrcweir if( m_aContext.FirstPageLeft && m_aContext.PageLayout == PDFWriter::ContinuousFacing ) 5971cdf0e10cSrcweir aLine.append( "/Direction/R2L\n" ); 5972cdf0e10cSrcweir if( m_aContext.OpenInFullScreenMode ) 5973cdf0e10cSrcweir switch( m_aContext.PDFDocumentMode ) 5974cdf0e10cSrcweir { 5975cdf0e10cSrcweir default : 5976cdf0e10cSrcweir case PDFWriter::ModeDefault : 5977cdf0e10cSrcweir aLine.append( "/NonFullScreenPageMode/UseNone\n" ); 5978cdf0e10cSrcweir break; 5979cdf0e10cSrcweir case PDFWriter::UseOutlines : 5980cdf0e10cSrcweir aLine.append( "/NonFullScreenPageMode/UseOutlines\n" ); 5981cdf0e10cSrcweir break; 5982cdf0e10cSrcweir case PDFWriter::UseThumbs : 5983cdf0e10cSrcweir aLine.append( "/NonFullScreenPageMode/UseThumbs\n" ); 5984cdf0e10cSrcweir break; 5985cdf0e10cSrcweir } 5986cdf0e10cSrcweir aLine.append( ">>\n" ); 5987cdf0e10cSrcweir } 5988cdf0e10cSrcweir 5989cdf0e10cSrcweir if( nOutlineDict ) 5990cdf0e10cSrcweir { 5991cdf0e10cSrcweir aLine.append( "/Outlines " ); 5992cdf0e10cSrcweir aLine.append( nOutlineDict ); 5993cdf0e10cSrcweir aLine.append( " 0 R\n" ); 5994cdf0e10cSrcweir } 5995cdf0e10cSrcweir if( nStructureDict ) 5996cdf0e10cSrcweir { 5997cdf0e10cSrcweir aLine.append( "/StructTreeRoot " ); 5998cdf0e10cSrcweir aLine.append( nStructureDict ); 5999cdf0e10cSrcweir aLine.append( " 0 R\n" ); 6000cdf0e10cSrcweir } 6001cdf0e10cSrcweir if( m_aContext.DocumentLocale.Language.getLength() > 0 ) 6002cdf0e10cSrcweir { 6003cdf0e10cSrcweir OUStringBuffer aLocBuf( 16 ); 6004cdf0e10cSrcweir aLocBuf.append( m_aContext.DocumentLocale.Language.toAsciiLowerCase() ); 6005cdf0e10cSrcweir if( m_aContext.DocumentLocale.Country.getLength() > 0 ) 6006cdf0e10cSrcweir { 6007cdf0e10cSrcweir aLocBuf.append( sal_Unicode('-') ); 6008cdf0e10cSrcweir aLocBuf.append( m_aContext.DocumentLocale.Country ); 6009cdf0e10cSrcweir } 6010cdf0e10cSrcweir aLine.append( "/Lang" ); 6011cdf0e10cSrcweir appendLiteralStringEncrypt( aLocBuf.makeStringAndClear(), m_nCatalogObject, aLine ); 6012cdf0e10cSrcweir aLine.append( "\n" ); 6013cdf0e10cSrcweir } 6014cdf0e10cSrcweir if( m_aContext.Tagged && m_aContext.Version > PDFWriter::PDF_1_3 ) 6015cdf0e10cSrcweir { 6016cdf0e10cSrcweir aLine.append( "/MarkInfo<</Marked true>>\n" ); 6017cdf0e10cSrcweir } 6018cdf0e10cSrcweir if( m_aWidgets.size() > 0 ) 6019cdf0e10cSrcweir { 6020cdf0e10cSrcweir aLine.append( "/AcroForm<</Fields[\n" ); 6021cdf0e10cSrcweir int nWidgets = m_aWidgets.size(); 6022cdf0e10cSrcweir int nOut = 0; 6023cdf0e10cSrcweir for( int j = 0; j < nWidgets; j++ ) 6024cdf0e10cSrcweir { 6025cdf0e10cSrcweir // output only root fields 6026cdf0e10cSrcweir if( m_aWidgets[j].m_nParent < 1 ) 6027cdf0e10cSrcweir { 6028cdf0e10cSrcweir aLine.append( m_aWidgets[j].m_nObject ); 6029cdf0e10cSrcweir aLine.append( (nOut++ % 5)==4 ? " 0 R\n" : " 0 R " ); 6030cdf0e10cSrcweir } 6031cdf0e10cSrcweir } 6032cdf0e10cSrcweir aLine.append( "\n]/DR " ); 6033cdf0e10cSrcweir aLine.append( getResourceDictObj() ); 6034cdf0e10cSrcweir aLine.append( " 0 R" ); 6035cdf0e10cSrcweir if( m_bIsPDF_A1 ) 6036cdf0e10cSrcweir aLine.append( ">>\n" ); 6037cdf0e10cSrcweir else 6038cdf0e10cSrcweir aLine.append( "/NeedAppearances true>>\n" ); 6039cdf0e10cSrcweir } 6040cdf0e10cSrcweir //--->i59651 6041cdf0e10cSrcweir //check if there is a Metadata object 6042cdf0e10cSrcweir if( nOutputIntentObject ) 6043cdf0e10cSrcweir { 6044cdf0e10cSrcweir aLine.append("/OutputIntents["); 6045cdf0e10cSrcweir aLine.append( nOutputIntentObject ); 6046cdf0e10cSrcweir aLine.append( " 0 R]" ); 6047cdf0e10cSrcweir } 6048cdf0e10cSrcweir if( nMetadataObject ) 6049cdf0e10cSrcweir { 6050cdf0e10cSrcweir aLine.append("/Metadata "); 6051cdf0e10cSrcweir aLine.append( nMetadataObject ); 6052cdf0e10cSrcweir aLine.append( " 0 R" ); 6053cdf0e10cSrcweir } 6054cdf0e10cSrcweir //<---- 6055cdf0e10cSrcweir aLine.append( ">>\n" 6056cdf0e10cSrcweir "endobj\n\n" ); 6057cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) ); 6058cdf0e10cSrcweir 6059cdf0e10cSrcweir return true; 6060cdf0e10cSrcweir } 6061cdf0e10cSrcweir 6062cdf0e10cSrcweir sal_Int32 PDFWriterImpl::emitInfoDict( ) 6063cdf0e10cSrcweir { 6064cdf0e10cSrcweir sal_Int32 nObject = createObject(); 6065cdf0e10cSrcweir 6066cdf0e10cSrcweir if( updateObject( nObject ) ) 6067cdf0e10cSrcweir { 6068cdf0e10cSrcweir OStringBuffer aLine( 1024 ); 6069cdf0e10cSrcweir aLine.append( nObject ); 6070cdf0e10cSrcweir aLine.append( " 0 obj\n" 6071cdf0e10cSrcweir "<<" ); 6072cdf0e10cSrcweir if( m_aContext.DocumentInfo.Title.Len() ) 6073cdf0e10cSrcweir { 6074cdf0e10cSrcweir aLine.append( "/Title" ); 6075cdf0e10cSrcweir appendUnicodeTextStringEncrypt( m_aContext.DocumentInfo.Title, nObject, aLine ); 6076cdf0e10cSrcweir aLine.append( "\n" ); 6077cdf0e10cSrcweir } 6078cdf0e10cSrcweir if( m_aContext.DocumentInfo.Author.Len() ) 6079cdf0e10cSrcweir { 6080cdf0e10cSrcweir aLine.append( "/Author" ); 6081cdf0e10cSrcweir appendUnicodeTextStringEncrypt( m_aContext.DocumentInfo.Author, nObject, aLine ); 6082cdf0e10cSrcweir aLine.append( "\n" ); 6083cdf0e10cSrcweir } 6084cdf0e10cSrcweir if( m_aContext.DocumentInfo.Subject.Len() ) 6085cdf0e10cSrcweir { 6086cdf0e10cSrcweir aLine.append( "/Subject" ); 6087cdf0e10cSrcweir appendUnicodeTextStringEncrypt( m_aContext.DocumentInfo.Subject, nObject, aLine ); 6088cdf0e10cSrcweir aLine.append( "\n" ); 6089cdf0e10cSrcweir } 6090cdf0e10cSrcweir if( m_aContext.DocumentInfo.Keywords.Len() ) 6091cdf0e10cSrcweir { 6092cdf0e10cSrcweir aLine.append( "/Keywords" ); 6093cdf0e10cSrcweir appendUnicodeTextStringEncrypt( m_aContext.DocumentInfo.Keywords, nObject, aLine ); 6094cdf0e10cSrcweir aLine.append( "\n" ); 6095cdf0e10cSrcweir } 6096cdf0e10cSrcweir if( m_aContext.DocumentInfo.Creator.Len() ) 6097cdf0e10cSrcweir { 6098cdf0e10cSrcweir aLine.append( "/Creator" ); 6099cdf0e10cSrcweir appendUnicodeTextStringEncrypt( m_aContext.DocumentInfo.Creator, nObject, aLine ); 6100cdf0e10cSrcweir aLine.append( "\n" ); 6101cdf0e10cSrcweir } 6102cdf0e10cSrcweir if( m_aContext.DocumentInfo.Producer.Len() ) 6103cdf0e10cSrcweir { 6104cdf0e10cSrcweir aLine.append( "/Producer" ); 6105cdf0e10cSrcweir appendUnicodeTextStringEncrypt( m_aContext.DocumentInfo.Producer, nObject, aLine ); 6106cdf0e10cSrcweir aLine.append( "\n" ); 6107cdf0e10cSrcweir } 6108cdf0e10cSrcweir 6109cdf0e10cSrcweir aLine.append( "/CreationDate" ); 6110cdf0e10cSrcweir appendLiteralStringEncrypt( m_aCreationDateString, nObject, aLine ); 6111cdf0e10cSrcweir aLine.append( ">>\nendobj\n\n" ); 6112cdf0e10cSrcweir if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) ) 6113cdf0e10cSrcweir nObject = 0; 6114cdf0e10cSrcweir } 6115cdf0e10cSrcweir else 6116cdf0e10cSrcweir nObject = 0; 6117cdf0e10cSrcweir 6118cdf0e10cSrcweir return nObject; 6119cdf0e10cSrcweir } 6120cdf0e10cSrcweir 6121cdf0e10cSrcweir //--->i56629 6122cdf0e10cSrcweir // Part of this function may be shared with method appendDest. 6123cdf0e10cSrcweir // 6124cdf0e10cSrcweir sal_Int32 PDFWriterImpl::emitNamedDestinations() 6125cdf0e10cSrcweir { 6126cdf0e10cSrcweir sal_Int32 nCount = m_aNamedDests.size(); 6127cdf0e10cSrcweir if( nCount <= 0 ) 6128cdf0e10cSrcweir return 0;//define internal error 6129cdf0e10cSrcweir 6130cdf0e10cSrcweir //get the object number for all the destinations 6131cdf0e10cSrcweir sal_Int32 nObject = createObject(); 6132cdf0e10cSrcweir 6133cdf0e10cSrcweir if( updateObject( nObject ) ) 6134cdf0e10cSrcweir { 6135cdf0e10cSrcweir //emit the dictionary 6136cdf0e10cSrcweir OStringBuffer aLine( 1024 ); 6137cdf0e10cSrcweir aLine.append( nObject ); 6138cdf0e10cSrcweir aLine.append( " 0 obj\n" 6139cdf0e10cSrcweir "<<" ); 6140cdf0e10cSrcweir 6141cdf0e10cSrcweir sal_Int32 nDestID; 6142cdf0e10cSrcweir for( nDestID = 0; nDestID < nCount; nDestID++ ) 6143cdf0e10cSrcweir { 6144cdf0e10cSrcweir const PDFNamedDest& rDest = m_aNamedDests[ nDestID ]; 6145cdf0e10cSrcweir // In order to correctly function both under an Internet browser and 6146cdf0e10cSrcweir // directly with a reader (provided the reader has the feature) we 6147cdf0e10cSrcweir // need to set the name of the destination the same way it will be encoded 6148cdf0e10cSrcweir // in an Internet link 6149cdf0e10cSrcweir INetURLObject aLocalURL( 6150cdf0e10cSrcweir OUString( RTL_CONSTASCII_USTRINGPARAM( "http://ahost.ax" ) ) ); //dummy location, won't be used 6151cdf0e10cSrcweir aLocalURL.SetMark( rDest.m_aDestName ); 6152cdf0e10cSrcweir 6153cdf0e10cSrcweir const rtl::OUString aName = aLocalURL.GetMark( INetURLObject::NO_DECODE ); //same coding as 6154cdf0e10cSrcweir // in link creation ( see PDFWriterImpl::emitLinkAnnotations ) 6155cdf0e10cSrcweir const PDFPage& rDestPage = m_aPages[ rDest.m_nPage ]; 6156cdf0e10cSrcweir 6157cdf0e10cSrcweir aLine.append( '/' ); 6158cdf0e10cSrcweir appendDestinationName( aName, aLine ); // this conversion must be done when forming the link to target ( see in emitCatalog ) 6159cdf0e10cSrcweir aLine.append( '[' ); // the '[' can be emitted immediately, because the appendDestinationName function 6160cdf0e10cSrcweir //maps the preceeding character properly 6161cdf0e10cSrcweir aLine.append( rDestPage.m_nPageObject ); 6162cdf0e10cSrcweir aLine.append( " 0 R" ); 6163cdf0e10cSrcweir 6164cdf0e10cSrcweir switch( rDest.m_eType ) 6165cdf0e10cSrcweir { 6166cdf0e10cSrcweir case PDFWriter::XYZ: 6167cdf0e10cSrcweir default: 6168cdf0e10cSrcweir aLine.append( "/XYZ " ); 6169cdf0e10cSrcweir appendFixedInt( rDest.m_aRect.Left(), aLine ); 6170cdf0e10cSrcweir aLine.append( ' ' ); 6171cdf0e10cSrcweir appendFixedInt( rDest.m_aRect.Bottom(), aLine ); 6172cdf0e10cSrcweir aLine.append( " 0" ); 6173cdf0e10cSrcweir break; 6174cdf0e10cSrcweir case PDFWriter::Fit: 6175cdf0e10cSrcweir aLine.append( "/Fit" ); 6176cdf0e10cSrcweir break; 6177cdf0e10cSrcweir case PDFWriter::FitRectangle: 6178cdf0e10cSrcweir aLine.append( "/FitR " ); 6179cdf0e10cSrcweir appendFixedInt( rDest.m_aRect.Left(), aLine ); 6180cdf0e10cSrcweir aLine.append( ' ' ); 6181cdf0e10cSrcweir appendFixedInt( rDest.m_aRect.Top(), aLine ); 6182cdf0e10cSrcweir aLine.append( ' ' ); 6183cdf0e10cSrcweir appendFixedInt( rDest.m_aRect.Right(), aLine ); 6184cdf0e10cSrcweir aLine.append( ' ' ); 6185cdf0e10cSrcweir appendFixedInt( rDest.m_aRect.Bottom(), aLine ); 6186cdf0e10cSrcweir break; 6187cdf0e10cSrcweir case PDFWriter::FitHorizontal: 6188cdf0e10cSrcweir aLine.append( "/FitH " ); 6189cdf0e10cSrcweir appendFixedInt( rDest.m_aRect.Bottom(), aLine ); 6190cdf0e10cSrcweir break; 6191cdf0e10cSrcweir case PDFWriter::FitVertical: 6192cdf0e10cSrcweir aLine.append( "/FitV " ); 6193cdf0e10cSrcweir appendFixedInt( rDest.m_aRect.Left(), aLine ); 6194cdf0e10cSrcweir break; 6195cdf0e10cSrcweir case PDFWriter::FitPageBoundingBox: 6196cdf0e10cSrcweir aLine.append( "/FitB" ); 6197cdf0e10cSrcweir break; 6198cdf0e10cSrcweir case PDFWriter::FitPageBoundingBoxHorizontal: 6199cdf0e10cSrcweir aLine.append( "/FitBH " ); 6200cdf0e10cSrcweir appendFixedInt( rDest.m_aRect.Bottom(), aLine ); 6201cdf0e10cSrcweir break; 6202cdf0e10cSrcweir case PDFWriter::FitPageBoundingBoxVertical: 6203cdf0e10cSrcweir aLine.append( "/FitBV " ); 6204cdf0e10cSrcweir appendFixedInt( rDest.m_aRect.Left(), aLine ); 6205cdf0e10cSrcweir break; 6206cdf0e10cSrcweir } 6207cdf0e10cSrcweir aLine.append( "]\n" ); 6208cdf0e10cSrcweir } 6209cdf0e10cSrcweir //close 6210cdf0e10cSrcweir 6211cdf0e10cSrcweir aLine.append( ">>\nendobj\n\n" ); 6212cdf0e10cSrcweir if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) ) 6213cdf0e10cSrcweir nObject = 0; 6214cdf0e10cSrcweir } 6215cdf0e10cSrcweir else 6216cdf0e10cSrcweir nObject = 0; 6217cdf0e10cSrcweir 6218cdf0e10cSrcweir return nObject; 6219cdf0e10cSrcweir } 6220cdf0e10cSrcweir //<--- i56629 6221cdf0e10cSrcweir 6222cdf0e10cSrcweir //--->i59651 6223cdf0e10cSrcweir // emits the output intent dictionary 6224cdf0e10cSrcweir 6225cdf0e10cSrcweir sal_Int32 PDFWriterImpl::emitOutputIntent() 6226cdf0e10cSrcweir { 6227cdf0e10cSrcweir if( !m_bIsPDF_A1 ) 6228cdf0e10cSrcweir return 0; 6229cdf0e10cSrcweir 6230cdf0e10cSrcweir //emit the sRGB standard profile, in ICC format, in a stream, per IEC61966-2.1 6231cdf0e10cSrcweir 6232cdf0e10cSrcweir OStringBuffer aLine( 1024 ); 6233cdf0e10cSrcweir sal_Int32 nICCObject = createObject(); 6234cdf0e10cSrcweir sal_Int32 nStreamLengthObject = createObject(); 6235cdf0e10cSrcweir 6236cdf0e10cSrcweir aLine.append( nICCObject ); 6237cdf0e10cSrcweir // sRGB has 3 colors, hence /N 3 below (PDF 1.4 table 4.16) 6238cdf0e10cSrcweir aLine.append( " 0 obj\n<</N 3/Length " ); 6239cdf0e10cSrcweir aLine.append( nStreamLengthObject ); 6240cdf0e10cSrcweir aLine.append( " 0 R" ); 6241cdf0e10cSrcweir #ifndef DEBUG_DISABLE_PDFCOMPRESSION 6242cdf0e10cSrcweir aLine.append( "/Filter/FlateDecode" ); 6243cdf0e10cSrcweir #endif 6244cdf0e10cSrcweir aLine.append( ">>\nstream\n" ); 6245cdf0e10cSrcweir CHECK_RETURN( updateObject( nICCObject ) ); 6246cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) ); 6247cdf0e10cSrcweir //get file position 6248cdf0e10cSrcweir sal_uInt64 nBeginStreamPos = 0; 6249cdf0e10cSrcweir osl_getFilePos( m_aFile, &nBeginStreamPos ); 6250cdf0e10cSrcweir beginCompression(); 6251cdf0e10cSrcweir checkAndEnableStreamEncryption( nICCObject ); 6252cdf0e10cSrcweir sal_Int32 nStreamSize = writeBuffer( nsRGB_ICC_profile, (sal_Int32) sizeof( nsRGB_ICC_profile ) ); 6253cdf0e10cSrcweir disableStreamEncryption(); 6254cdf0e10cSrcweir endCompression(); 6255cdf0e10cSrcweir sal_uInt64 nEndStreamPos = 0; 6256cdf0e10cSrcweir osl_getFilePos( m_aFile, &nEndStreamPos ); 6257cdf0e10cSrcweir 6258cdf0e10cSrcweir if( nStreamSize == 0 ) 6259cdf0e10cSrcweir return 0; 6260cdf0e10cSrcweir if( ! writeBuffer( "\nendstream\nendobj\n\n", 19 ) ) 6261cdf0e10cSrcweir return 0 ; 6262cdf0e10cSrcweir aLine.setLength( 0 ); 6263cdf0e10cSrcweir 6264cdf0e10cSrcweir //emit the stream length object 6265cdf0e10cSrcweir CHECK_RETURN( updateObject( nStreamLengthObject ) ); 6266cdf0e10cSrcweir aLine.setLength( 0 ); 6267cdf0e10cSrcweir aLine.append( nStreamLengthObject ); 6268cdf0e10cSrcweir aLine.append( " 0 obj\n" ); 6269cdf0e10cSrcweir aLine.append( (sal_Int64)(nEndStreamPos-nBeginStreamPos) ); 6270cdf0e10cSrcweir aLine.append( "\nendobj\n\n" ); 6271cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) ); 6272cdf0e10cSrcweir aLine.setLength( 0 ); 6273cdf0e10cSrcweir 6274cdf0e10cSrcweir //emit the OutputIntent dictionary 6275cdf0e10cSrcweir sal_Int32 nOIObject = createObject(); 6276cdf0e10cSrcweir CHECK_RETURN( updateObject( nOIObject ) ); 6277cdf0e10cSrcweir aLine.append( nOIObject ); 6278cdf0e10cSrcweir aLine.append( " 0 obj\n" 6279cdf0e10cSrcweir "<</Type/OutputIntent/S/GTS_PDFA1/OutputConditionIdentifier"); 6280cdf0e10cSrcweir 6281cdf0e10cSrcweir rtl::OUString aComment( RTL_CONSTASCII_USTRINGPARAM( "sRGB IEC61966-2.1" ) ); 6282cdf0e10cSrcweir appendLiteralStringEncrypt( aComment ,nOIObject, aLine ); 6283cdf0e10cSrcweir aLine.append("/DestOutputProfile "); 6284cdf0e10cSrcweir aLine.append( nICCObject ); 6285cdf0e10cSrcweir aLine.append( " 0 R>>\nendobj\n\n" );; 6286cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) ); 6287cdf0e10cSrcweir 6288cdf0e10cSrcweir return nOIObject; 6289cdf0e10cSrcweir } 6290cdf0e10cSrcweir 6291cdf0e10cSrcweir // formats the string for the XML stream 6292cdf0e10cSrcweir static void escapeStringXML( const rtl::OUString& rStr, rtl::OUString &rValue) 6293cdf0e10cSrcweir { 6294cdf0e10cSrcweir const sal_Unicode* pUni = rStr.getStr(); 6295cdf0e10cSrcweir int nLen = rStr.getLength(); 6296cdf0e10cSrcweir for( ; nLen; nLen--, pUni++ ) 6297cdf0e10cSrcweir { 6298cdf0e10cSrcweir switch( *pUni ) 6299cdf0e10cSrcweir { 6300cdf0e10cSrcweir case sal_Unicode('&'): 6301cdf0e10cSrcweir rValue += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "&" ) ); 6302cdf0e10cSrcweir break; 6303cdf0e10cSrcweir case sal_Unicode('<'): 6304cdf0e10cSrcweir rValue += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "<" ) ); 6305cdf0e10cSrcweir break; 6306cdf0e10cSrcweir case sal_Unicode('>'): 6307cdf0e10cSrcweir rValue += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( ">" ) ); 6308cdf0e10cSrcweir break; 6309cdf0e10cSrcweir case sal_Unicode('\''): 6310cdf0e10cSrcweir rValue += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "'" ) ); 6311cdf0e10cSrcweir break; 6312cdf0e10cSrcweir case sal_Unicode('"'): 6313cdf0e10cSrcweir rValue += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( """ ) ); 6314cdf0e10cSrcweir break; 6315cdf0e10cSrcweir default: 6316cdf0e10cSrcweir rValue += rtl::OUString( *pUni ); 6317cdf0e10cSrcweir break; 6318cdf0e10cSrcweir } 6319cdf0e10cSrcweir } 6320cdf0e10cSrcweir } 6321cdf0e10cSrcweir 6322cdf0e10cSrcweir // emits the document metadata 6323cdf0e10cSrcweir // 6324cdf0e10cSrcweir sal_Int32 PDFWriterImpl::emitDocumentMetadata() 6325cdf0e10cSrcweir { 6326cdf0e10cSrcweir if( !m_bIsPDF_A1 ) 6327cdf0e10cSrcweir return 0; 6328cdf0e10cSrcweir 6329cdf0e10cSrcweir //get the object number for all the destinations 6330cdf0e10cSrcweir sal_Int32 nObject = createObject(); 6331cdf0e10cSrcweir 6332cdf0e10cSrcweir if( updateObject( nObject ) ) 6333cdf0e10cSrcweir { 6334cdf0e10cSrcweir // the following string are written in UTF-8 unicode 6335cdf0e10cSrcweir OStringBuffer aMetadataStream( 8192 ); 6336cdf0e10cSrcweir 6337cdf0e10cSrcweir aMetadataStream.append( "<?xpacket begin=\"" ); 6338cdf0e10cSrcweir // this lines writes Unicode “zero width non-breaking space character” (U+FEFF) (aka byte-order mark ) used 6339cdf0e10cSrcweir // as a byte-order marker. 6340cdf0e10cSrcweir aMetadataStream.append( OUStringToOString( OUString( sal_Unicode( 0xFEFF ) ), RTL_TEXTENCODING_UTF8 ) ); 6341cdf0e10cSrcweir aMetadataStream.append( "\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>\n" ); 6342cdf0e10cSrcweir aMetadataStream.append( "<x:xmpmeta xmlns:x=\"adobe:ns:meta/\">\n" ); 6343cdf0e10cSrcweir aMetadataStream.append( " <rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n" ); 6344cdf0e10cSrcweir //PDF/A part ( ISO 19005-1:2005 - 6.7.11 ) 6345cdf0e10cSrcweir aMetadataStream.append( " <rdf:Description rdf:about=\"\"\n" ); 6346cdf0e10cSrcweir aMetadataStream.append( " xmlns:pdfaid=\"http://www.aiim.org/pdfa/ns/id/\">\n" ); 6347cdf0e10cSrcweir aMetadataStream.append( " <pdfaid:part>1</pdfaid:part>\n" ); 6348cdf0e10cSrcweir aMetadataStream.append( " <pdfaid:conformance>A</pdfaid:conformance>\n" ); 6349cdf0e10cSrcweir aMetadataStream.append( " </rdf:Description>\n" ); 6350cdf0e10cSrcweir //... Dublin Core properties go here 6351cdf0e10cSrcweir if( m_aContext.DocumentInfo.Title.Len() || 6352cdf0e10cSrcweir m_aContext.DocumentInfo.Author.Len() || 6353cdf0e10cSrcweir m_aContext.DocumentInfo.Subject.Len() ) 6354cdf0e10cSrcweir { 6355cdf0e10cSrcweir aMetadataStream.append( " <rdf:Description rdf:about=\"\"\n" ); 6356cdf0e10cSrcweir aMetadataStream.append( " xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n" ); 6357cdf0e10cSrcweir if( m_aContext.DocumentInfo.Title.Len() ) 6358cdf0e10cSrcweir { 6359cdf0e10cSrcweir // this is according to PDF/A-1, technical corrigendum 1 (2007-04-01) 6360cdf0e10cSrcweir aMetadataStream.append( " <dc:title>\n" ); 6361cdf0e10cSrcweir aMetadataStream.append( " <rdf:Alt>\n" ); 6362cdf0e10cSrcweir aMetadataStream.append( " <rdf:li xml:lang=\"x-default\">" ); 6363cdf0e10cSrcweir rtl::OUString aTitle; 6364cdf0e10cSrcweir escapeStringXML( m_aContext.DocumentInfo.Title, aTitle ); 6365cdf0e10cSrcweir aMetadataStream.append( OUStringToOString( aTitle, RTL_TEXTENCODING_UTF8 ) ); 6366cdf0e10cSrcweir aMetadataStream.append( "</rdf:li>\n" ); 6367cdf0e10cSrcweir aMetadataStream.append( " </rdf:Alt>\n" ); 6368cdf0e10cSrcweir aMetadataStream.append( " </dc:title>\n" ); 6369cdf0e10cSrcweir } 6370cdf0e10cSrcweir if( m_aContext.DocumentInfo.Author.Len() ) 6371cdf0e10cSrcweir { 6372cdf0e10cSrcweir aMetadataStream.append( " <dc:creator>\n" ); 6373cdf0e10cSrcweir aMetadataStream.append( " <rdf:Seq>\n" ); 6374cdf0e10cSrcweir aMetadataStream.append( " <rdf:li>" ); 6375cdf0e10cSrcweir rtl::OUString aAuthor; 6376cdf0e10cSrcweir escapeStringXML( m_aContext.DocumentInfo.Author, aAuthor ); 6377cdf0e10cSrcweir aMetadataStream.append( OUStringToOString( aAuthor , RTL_TEXTENCODING_UTF8 ) ); 6378cdf0e10cSrcweir aMetadataStream.append( "</rdf:li>\n" ); 6379cdf0e10cSrcweir aMetadataStream.append( " </rdf:Seq>\n" ); 6380cdf0e10cSrcweir aMetadataStream.append( " </dc:creator>\n" ); 6381cdf0e10cSrcweir } 6382cdf0e10cSrcweir if( m_aContext.DocumentInfo.Subject.Len() ) 6383cdf0e10cSrcweir { 6384cdf0e10cSrcweir // this is according to PDF/A-1, technical corrigendum 1 (2007-04-01) 6385cdf0e10cSrcweir aMetadataStream.append( " <dc:description>\n" ); 6386cdf0e10cSrcweir aMetadataStream.append( " <rdf:Alt>\n" ); 6387cdf0e10cSrcweir aMetadataStream.append( " <rdf:li xml:lang=\"x-default\">" ); 6388cdf0e10cSrcweir rtl::OUString aSubject; 6389cdf0e10cSrcweir escapeStringXML( m_aContext.DocumentInfo.Subject, aSubject ); 6390cdf0e10cSrcweir aMetadataStream.append( OUStringToOString( aSubject , RTL_TEXTENCODING_UTF8 ) ); 6391cdf0e10cSrcweir aMetadataStream.append( "</rdf:li>\n" ); 6392cdf0e10cSrcweir aMetadataStream.append( " </rdf:Alt>\n" ); 6393cdf0e10cSrcweir aMetadataStream.append( " </dc:description>\n" ); 6394cdf0e10cSrcweir } 6395cdf0e10cSrcweir aMetadataStream.append( " </rdf:Description>\n" ); 6396cdf0e10cSrcweir } 6397cdf0e10cSrcweir 6398cdf0e10cSrcweir //... PDF properties go here 6399cdf0e10cSrcweir if( m_aContext.DocumentInfo.Producer.Len() || 6400cdf0e10cSrcweir m_aContext.DocumentInfo.Keywords.Len() ) 6401cdf0e10cSrcweir { 6402cdf0e10cSrcweir aMetadataStream.append( " <rdf:Description rdf:about=\"\"\n" ); 6403cdf0e10cSrcweir aMetadataStream.append( " xmlns:pdf=\"http://ns.adobe.com/pdf/1.3/\">\n" ); 6404cdf0e10cSrcweir if( m_aContext.DocumentInfo.Producer.Len() ) 6405cdf0e10cSrcweir { 6406cdf0e10cSrcweir aMetadataStream.append( " <pdf:Producer>" ); 6407cdf0e10cSrcweir rtl::OUString aProducer; 6408cdf0e10cSrcweir escapeStringXML( m_aContext.DocumentInfo.Producer, aProducer ); 6409cdf0e10cSrcweir aMetadataStream.append( OUStringToOString( aProducer , RTL_TEXTENCODING_UTF8 ) ); 6410cdf0e10cSrcweir aMetadataStream.append( "</pdf:Producer>\n" ); 6411cdf0e10cSrcweir } 6412cdf0e10cSrcweir if( m_aContext.DocumentInfo.Keywords.Len() ) 6413cdf0e10cSrcweir { 6414cdf0e10cSrcweir aMetadataStream.append( " <pdf:Keywords>" ); 6415cdf0e10cSrcweir rtl::OUString aKeywords; 6416cdf0e10cSrcweir escapeStringXML( m_aContext.DocumentInfo.Keywords, aKeywords ); 6417cdf0e10cSrcweir aMetadataStream.append( OUStringToOString( aKeywords , RTL_TEXTENCODING_UTF8 ) ); 6418cdf0e10cSrcweir aMetadataStream.append( "</pdf:Keywords>\n" ); 6419cdf0e10cSrcweir } 6420cdf0e10cSrcweir aMetadataStream.append( " </rdf:Description>\n" ); 6421cdf0e10cSrcweir } 6422cdf0e10cSrcweir 6423cdf0e10cSrcweir aMetadataStream.append( " <rdf:Description rdf:about=\"\"\n" ); 6424cdf0e10cSrcweir aMetadataStream.append( " xmlns:xmp=\"http://ns.adobe.com/xap/1.0/\">\n" ); 6425cdf0e10cSrcweir if( m_aContext.DocumentInfo.Creator.Len() ) 6426cdf0e10cSrcweir { 6427cdf0e10cSrcweir aMetadataStream.append( " <xmp:CreatorTool>" ); 6428cdf0e10cSrcweir rtl::OUString aCreator; 6429cdf0e10cSrcweir escapeStringXML( m_aContext.DocumentInfo.Creator, aCreator ); 6430cdf0e10cSrcweir aMetadataStream.append( OUStringToOString( aCreator , RTL_TEXTENCODING_UTF8 ) ); 6431cdf0e10cSrcweir aMetadataStream.append( "</xmp:CreatorTool>\n" ); 6432cdf0e10cSrcweir } 6433cdf0e10cSrcweir //creation date 6434cdf0e10cSrcweir aMetadataStream.append( " <xmp:CreateDate>" ); 6435cdf0e10cSrcweir aMetadataStream.append( m_aCreationMetaDateString ); 6436cdf0e10cSrcweir aMetadataStream.append( "</xmp:CreateDate>\n" ); 6437cdf0e10cSrcweir 6438cdf0e10cSrcweir aMetadataStream.append( " </rdf:Description>\n" ); 6439cdf0e10cSrcweir aMetadataStream.append( " </rdf:RDF>\n" ); 6440cdf0e10cSrcweir aMetadataStream.append( "</x:xmpmeta>\n" ); 6441cdf0e10cSrcweir 6442cdf0e10cSrcweir //add the padding 6443cdf0e10cSrcweir for( sal_Int32 nSpaces = 1; nSpaces <= 2100; nSpaces++ ) 6444cdf0e10cSrcweir { 6445cdf0e10cSrcweir aMetadataStream.append( " " ); 6446cdf0e10cSrcweir if( nSpaces % 100 == 0 ) 6447cdf0e10cSrcweir aMetadataStream.append( "\n" ); 6448cdf0e10cSrcweir } 6449cdf0e10cSrcweir 6450cdf0e10cSrcweir aMetadataStream.append( "<?xpacket end=\"w\"?>\n" ); 6451cdf0e10cSrcweir 6452cdf0e10cSrcweir OStringBuffer aMetadataObj( 1024 ); 6453cdf0e10cSrcweir 6454cdf0e10cSrcweir aMetadataObj.append( nObject ); 6455cdf0e10cSrcweir aMetadataObj.append( " 0 obj\n" ); 6456cdf0e10cSrcweir 6457cdf0e10cSrcweir aMetadataObj.append( "<</Type/Metadata/Subtype/XML/Length " ); 6458cdf0e10cSrcweir 6459cdf0e10cSrcweir aMetadataObj.append( (sal_Int32) aMetadataStream.getLength() ); 6460cdf0e10cSrcweir aMetadataObj.append( ">>\nstream\n" ); 6461cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aMetadataObj.getStr(), aMetadataObj.getLength() ) ); 6462cdf0e10cSrcweir //emit the stream 6463cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aMetadataStream.getStr(), aMetadataStream.getLength() ) ); 6464cdf0e10cSrcweir 6465cdf0e10cSrcweir aMetadataObj.setLength( 0 ); 6466cdf0e10cSrcweir aMetadataObj.append( "\nendstream\nendobj\n\n" ); 6467cdf0e10cSrcweir if( ! writeBuffer( aMetadataObj.getStr(), aMetadataObj.getLength() ) ) 6468cdf0e10cSrcweir nObject = 0; 6469cdf0e10cSrcweir } 6470cdf0e10cSrcweir else 6471cdf0e10cSrcweir nObject = 0; 6472cdf0e10cSrcweir 6473cdf0e10cSrcweir return nObject; 6474cdf0e10cSrcweir } 6475cdf0e10cSrcweir //<---i59651 6476cdf0e10cSrcweir 6477cdf0e10cSrcweir bool PDFWriterImpl::emitTrailer() 6478cdf0e10cSrcweir { 6479cdf0e10cSrcweir // emit doc info 6480cdf0e10cSrcweir OString aInfoValuesOut; 6481cdf0e10cSrcweir sal_Int32 nDocInfoObject = emitInfoDict( ); 6482cdf0e10cSrcweir 6483cdf0e10cSrcweir sal_Int32 nSecObject = 0; 6484cdf0e10cSrcweir 6485cdf0e10cSrcweir if( m_aContext.Encryption.Encrypt() ) 6486cdf0e10cSrcweir { 6487cdf0e10cSrcweir //emit the security information 6488cdf0e10cSrcweir //must be emitted as indirect dictionary object, since 6489cdf0e10cSrcweir //Acrobat Reader 5 works only with this kind of implementation 6490cdf0e10cSrcweir nSecObject = createObject(); 6491cdf0e10cSrcweir 6492cdf0e10cSrcweir if( updateObject( nSecObject ) ) 6493cdf0e10cSrcweir { 6494cdf0e10cSrcweir OStringBuffer aLineS( 1024 ); 6495cdf0e10cSrcweir aLineS.append( nSecObject ); 6496cdf0e10cSrcweir aLineS.append( " 0 obj\n" 6497cdf0e10cSrcweir "<</Filter/Standard/V " ); 6498cdf0e10cSrcweir // check the version 6499cdf0e10cSrcweir if( m_aContext.Encryption.Security128bit ) 6500cdf0e10cSrcweir aLineS.append( "2/Length 128/R 3" ); 6501cdf0e10cSrcweir else 6502cdf0e10cSrcweir aLineS.append( "1/R 2" ); 6503cdf0e10cSrcweir 6504cdf0e10cSrcweir // emit the owner password, must not be encrypted 6505cdf0e10cSrcweir aLineS.append( "/O(" ); 6506cdf0e10cSrcweir appendLiteralString( (const sal_Char*)&m_aContext.Encryption.OValue[0], sal_Int32(m_aContext.Encryption.OValue.size()), aLineS ); 6507cdf0e10cSrcweir aLineS.append( ")/U(" ); 6508cdf0e10cSrcweir appendLiteralString( (const sal_Char*)&m_aContext.Encryption.UValue[0], sal_Int32(m_aContext.Encryption.UValue.size()), aLineS ); 6509cdf0e10cSrcweir aLineS.append( ")/P " );// the permission set 6510cdf0e10cSrcweir aLineS.append( m_nAccessPermissions ); 6511cdf0e10cSrcweir aLineS.append( ">>\nendobj\n\n" ); 6512cdf0e10cSrcweir if( !writeBuffer( aLineS.getStr(), aLineS.getLength() ) ) 6513cdf0e10cSrcweir nSecObject = 0; 6514cdf0e10cSrcweir } 6515cdf0e10cSrcweir else 6516cdf0e10cSrcweir nSecObject = 0; 6517cdf0e10cSrcweir } 6518cdf0e10cSrcweir // emit xref table 6519cdf0e10cSrcweir // remember start 6520cdf0e10cSrcweir sal_uInt64 nXRefOffset = 0; 6521cdf0e10cSrcweir CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nXRefOffset )) ); 6522cdf0e10cSrcweir CHECK_RETURN( writeBuffer( "xref\n", 5 ) ); 6523cdf0e10cSrcweir 6524cdf0e10cSrcweir sal_Int32 nObjects = m_aObjects.size(); 6525cdf0e10cSrcweir OStringBuffer aLine; 6526cdf0e10cSrcweir aLine.append( "0 " ); 6527cdf0e10cSrcweir aLine.append( (sal_Int32)(nObjects+1) ); 6528cdf0e10cSrcweir aLine.append( "\n" ); 6529cdf0e10cSrcweir aLine.append( "0000000000 65535 f \n" ); 6530cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) ); 6531cdf0e10cSrcweir 6532cdf0e10cSrcweir for( sal_Int32 i = 0; i < nObjects; i++ ) 6533cdf0e10cSrcweir { 6534cdf0e10cSrcweir aLine.setLength( 0 ); 6535cdf0e10cSrcweir OString aOffset = OString::valueOf( (sal_Int64)m_aObjects[i] ); 6536cdf0e10cSrcweir for( sal_Int32 j = 0; j < (10-aOffset.getLength()); j++ ) 6537cdf0e10cSrcweir aLine.append( '0' ); 6538cdf0e10cSrcweir aLine.append( aOffset ); 6539cdf0e10cSrcweir aLine.append( " 00000 n \n" ); 6540cdf0e10cSrcweir DBG_ASSERT( aLine.getLength() == 20, "invalid xref entry" ); 6541cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) ); 6542cdf0e10cSrcweir } 6543cdf0e10cSrcweir 6544cdf0e10cSrcweir // prepare document checksum 6545cdf0e10cSrcweir OStringBuffer aDocChecksum( 2*RTL_DIGEST_LENGTH_MD5+1 ); 6546cdf0e10cSrcweir if( m_aDocDigest ) 6547cdf0e10cSrcweir { 6548cdf0e10cSrcweir sal_uInt8 nMD5Sum[ RTL_DIGEST_LENGTH_MD5 ]; 6549cdf0e10cSrcweir rtl_digest_getMD5( m_aDocDigest, nMD5Sum, sizeof(nMD5Sum) ); 6550cdf0e10cSrcweir for( unsigned int i = 0; i < RTL_DIGEST_LENGTH_MD5; i++ ) 6551cdf0e10cSrcweir appendHex( nMD5Sum[i], aDocChecksum ); 6552cdf0e10cSrcweir } 6553cdf0e10cSrcweir // document id set in setDocInfo method 6554cdf0e10cSrcweir // emit trailer 6555cdf0e10cSrcweir aLine.setLength( 0 ); 6556cdf0e10cSrcweir aLine.append( "trailer\n" 6557cdf0e10cSrcweir "<</Size " ); 6558cdf0e10cSrcweir aLine.append( (sal_Int32)(nObjects+1) ); 6559cdf0e10cSrcweir aLine.append( "/Root " ); 6560cdf0e10cSrcweir aLine.append( m_nCatalogObject ); 6561cdf0e10cSrcweir aLine.append( " 0 R\n" ); 6562cdf0e10cSrcweir if( nSecObject |= 0 ) 6563cdf0e10cSrcweir { 6564cdf0e10cSrcweir aLine.append( "/Encrypt "); 6565cdf0e10cSrcweir aLine.append( nSecObject ); 6566cdf0e10cSrcweir aLine.append( " 0 R\n" ); 6567cdf0e10cSrcweir } 6568cdf0e10cSrcweir if( nDocInfoObject ) 6569cdf0e10cSrcweir { 6570cdf0e10cSrcweir aLine.append( "/Info " ); 6571cdf0e10cSrcweir aLine.append( nDocInfoObject ); 6572cdf0e10cSrcweir aLine.append( " 0 R\n" ); 6573cdf0e10cSrcweir } 6574cdf0e10cSrcweir if( ! m_aContext.Encryption.DocumentIdentifier.empty() ) 6575cdf0e10cSrcweir { 6576cdf0e10cSrcweir aLine.append( "/ID [ <" ); 6577cdf0e10cSrcweir for( std::vector< sal_uInt8 >::const_iterator it = m_aContext.Encryption.DocumentIdentifier.begin(); 6578cdf0e10cSrcweir it != m_aContext.Encryption.DocumentIdentifier.end(); ++it ) 6579cdf0e10cSrcweir { 6580cdf0e10cSrcweir appendHex( sal_Int8(*it), aLine ); 6581cdf0e10cSrcweir } 6582cdf0e10cSrcweir aLine.append( ">\n" 6583cdf0e10cSrcweir "<" ); 6584cdf0e10cSrcweir for( std::vector< sal_uInt8 >::const_iterator it = m_aContext.Encryption.DocumentIdentifier.begin(); 6585cdf0e10cSrcweir it != m_aContext.Encryption.DocumentIdentifier.end(); ++it ) 6586cdf0e10cSrcweir { 6587cdf0e10cSrcweir appendHex( sal_Int8(*it), aLine ); 6588cdf0e10cSrcweir } 6589cdf0e10cSrcweir aLine.append( "> ]\n" ); 6590cdf0e10cSrcweir } 6591cdf0e10cSrcweir if( aDocChecksum.getLength() ) 6592cdf0e10cSrcweir { 6593cdf0e10cSrcweir aLine.append( "/DocChecksum /" ); 6594cdf0e10cSrcweir aLine.append( aDocChecksum ); 6595cdf0e10cSrcweir aLine.append( "\n" ); 6596cdf0e10cSrcweir } 6597cdf0e10cSrcweir if( m_aAdditionalStreams.size() > 0 ) 6598cdf0e10cSrcweir { 6599cdf0e10cSrcweir aLine.append( "/AdditionalStreams [" ); 6600cdf0e10cSrcweir for( unsigned int i = 0; i < m_aAdditionalStreams.size(); i++ ) 6601cdf0e10cSrcweir { 6602cdf0e10cSrcweir aLine.append( "/" ); 6603cdf0e10cSrcweir appendName( m_aAdditionalStreams[i].m_aMimeType, aLine ); 6604cdf0e10cSrcweir aLine.append( " " ); 6605cdf0e10cSrcweir aLine.append( m_aAdditionalStreams[i].m_nStreamObject ); 6606cdf0e10cSrcweir aLine.append( " 0 R\n" ); 6607cdf0e10cSrcweir } 6608cdf0e10cSrcweir aLine.append( "]\n" ); 6609cdf0e10cSrcweir } 6610cdf0e10cSrcweir aLine.append( ">>\n" 6611cdf0e10cSrcweir "startxref\n" ); 6612cdf0e10cSrcweir aLine.append( (sal_Int64)nXRefOffset ); 6613cdf0e10cSrcweir aLine.append( "\n" 6614cdf0e10cSrcweir "%%EOF\n" ); 6615cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) ); 6616cdf0e10cSrcweir 6617cdf0e10cSrcweir return true; 6618cdf0e10cSrcweir } 6619cdf0e10cSrcweir 6620cdf0e10cSrcweir struct AnnotationSortEntry 6621cdf0e10cSrcweir { 6622cdf0e10cSrcweir sal_Int32 nTabOrder; 6623cdf0e10cSrcweir sal_Int32 nObject; 6624cdf0e10cSrcweir sal_Int32 nWidgetIndex; 6625cdf0e10cSrcweir 6626cdf0e10cSrcweir AnnotationSortEntry( sal_Int32 nTab, sal_Int32 nObj, sal_Int32 nI ) : 6627cdf0e10cSrcweir nTabOrder( nTab ), 6628cdf0e10cSrcweir nObject( nObj ), 6629cdf0e10cSrcweir nWidgetIndex( nI ) 6630cdf0e10cSrcweir {} 6631cdf0e10cSrcweir }; 6632cdf0e10cSrcweir 6633cdf0e10cSrcweir struct AnnotSortContainer 6634cdf0e10cSrcweir { 6635cdf0e10cSrcweir std::set< sal_Int32 > aObjects; 6636cdf0e10cSrcweir std::vector< AnnotationSortEntry > aSortedAnnots; 6637cdf0e10cSrcweir }; 6638cdf0e10cSrcweir 6639cdf0e10cSrcweir struct AnnotSorterLess 6640cdf0e10cSrcweir { 6641cdf0e10cSrcweir std::vector< PDFWriterImpl::PDFWidget >& m_rWidgets; 6642cdf0e10cSrcweir 6643cdf0e10cSrcweir AnnotSorterLess( std::vector< PDFWriterImpl::PDFWidget >& rWidgets ) : m_rWidgets( rWidgets ) {} 6644cdf0e10cSrcweir 6645cdf0e10cSrcweir bool operator()( const AnnotationSortEntry& rLeft, const AnnotationSortEntry& rRight ) 6646cdf0e10cSrcweir { 6647cdf0e10cSrcweir if( rLeft.nTabOrder < rRight.nTabOrder ) 6648cdf0e10cSrcweir return true; 6649cdf0e10cSrcweir if( rRight.nTabOrder < rLeft.nTabOrder ) 6650cdf0e10cSrcweir return false; 6651cdf0e10cSrcweir if( rLeft.nWidgetIndex < 0 && rRight.nWidgetIndex < 0 ) 6652cdf0e10cSrcweir return false; 6653cdf0e10cSrcweir if( rRight.nWidgetIndex < 0 ) 6654cdf0e10cSrcweir return true; 6655cdf0e10cSrcweir if( rLeft.nWidgetIndex < 0 ) 6656cdf0e10cSrcweir return false; 6657cdf0e10cSrcweir // remember: widget rects are in PDF coordinates, so they are ordered down up 6658cdf0e10cSrcweir if( m_rWidgets[ rLeft.nWidgetIndex ].m_aRect.Top() > 6659cdf0e10cSrcweir m_rWidgets[ rRight.nWidgetIndex ].m_aRect.Top() ) 6660cdf0e10cSrcweir return true; 6661cdf0e10cSrcweir if( m_rWidgets[ rRight.nWidgetIndex ].m_aRect.Top() > 6662cdf0e10cSrcweir m_rWidgets[ rLeft.nWidgetIndex ].m_aRect.Top() ) 6663cdf0e10cSrcweir return false; 6664cdf0e10cSrcweir if( m_rWidgets[ rLeft.nWidgetIndex ].m_aRect.Left() < 6665cdf0e10cSrcweir m_rWidgets[ rRight.nWidgetIndex ].m_aRect.Left() ) 6666cdf0e10cSrcweir return true; 6667cdf0e10cSrcweir return false; 6668cdf0e10cSrcweir } 6669cdf0e10cSrcweir }; 6670cdf0e10cSrcweir 6671cdf0e10cSrcweir void PDFWriterImpl::sortWidgets() 6672cdf0e10cSrcweir { 6673cdf0e10cSrcweir // sort widget annotations on each page as per their 6674cdf0e10cSrcweir // TabOrder attribute 6675cdf0e10cSrcweir std::hash_map< sal_Int32, AnnotSortContainer > sorted; 6676cdf0e10cSrcweir int nWidgets = m_aWidgets.size(); 6677cdf0e10cSrcweir for( int nW = 0; nW < nWidgets; nW++ ) 6678cdf0e10cSrcweir { 6679cdf0e10cSrcweir const PDFWidget& rWidget = m_aWidgets[nW]; 6680cdf0e10cSrcweir if( rWidget.m_nPage >= 0 ) 6681cdf0e10cSrcweir { 6682cdf0e10cSrcweir AnnotSortContainer& rCont = sorted[ rWidget.m_nPage ]; 6683cdf0e10cSrcweir // optimize vector allocation 6684cdf0e10cSrcweir if( rCont.aSortedAnnots.empty() ) 6685cdf0e10cSrcweir rCont.aSortedAnnots.reserve( m_aPages[ rWidget.m_nPage ].m_aAnnotations.size() ); 6686cdf0e10cSrcweir // insert widget to tab sorter 6687cdf0e10cSrcweir // RadioButtons are not page annotations, only their individual check boxes are 6688cdf0e10cSrcweir if( rWidget.m_eType != PDFWriter::RadioButton ) 6689cdf0e10cSrcweir { 6690cdf0e10cSrcweir rCont.aObjects.insert( rWidget.m_nObject ); 6691cdf0e10cSrcweir rCont.aSortedAnnots.push_back( AnnotationSortEntry( rWidget.m_nTabOrder, rWidget.m_nObject, nW ) ); 6692cdf0e10cSrcweir } 6693cdf0e10cSrcweir } 6694cdf0e10cSrcweir } 6695cdf0e10cSrcweir for( std::hash_map< sal_Int32, AnnotSortContainer >::iterator it = sorted.begin(); it != sorted.end(); ++it ) 6696cdf0e10cSrcweir { 6697cdf0e10cSrcweir // append entries for non widget annotations 6698cdf0e10cSrcweir PDFPage& rPage = m_aPages[ it->first ]; 6699cdf0e10cSrcweir unsigned int nAnnots = rPage.m_aAnnotations.size(); 6700cdf0e10cSrcweir for( unsigned int nA = 0; nA < nAnnots; nA++ ) 6701cdf0e10cSrcweir if( it->second.aObjects.find( rPage.m_aAnnotations[nA] ) == it->second.aObjects.end()) 6702cdf0e10cSrcweir it->second.aSortedAnnots.push_back( AnnotationSortEntry( 10000, rPage.m_aAnnotations[nA], -1 ) ); 6703cdf0e10cSrcweir 6704cdf0e10cSrcweir AnnotSorterLess aLess( m_aWidgets ); 6705cdf0e10cSrcweir std::stable_sort( it->second.aSortedAnnots.begin(), it->second.aSortedAnnots.end(), aLess ); 6706cdf0e10cSrcweir // sanity check 6707cdf0e10cSrcweir if( it->second.aSortedAnnots.size() == nAnnots) 6708cdf0e10cSrcweir { 6709cdf0e10cSrcweir for( unsigned int nA = 0; nA < nAnnots; nA++ ) 6710cdf0e10cSrcweir rPage.m_aAnnotations[nA] = it->second.aSortedAnnots[nA].nObject; 6711cdf0e10cSrcweir } 6712cdf0e10cSrcweir else 6713cdf0e10cSrcweir { 6714cdf0e10cSrcweir DBG_ASSERT( 0, "wrong number of sorted annotations" ); 6715cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 0 6716cdf0e10cSrcweir fprintf( stderr, "PDFWriterImpl::sortWidgets(): wrong number of sorted assertions on page nr %ld\n" 6717cdf0e10cSrcweir " %ld sorted and %ld unsorted\n", (long int)it->first, (long int)it->second.aSortedAnnots.size(), (long int)nAnnots ); 6718cdf0e10cSrcweir #endif 6719cdf0e10cSrcweir } 6720cdf0e10cSrcweir } 6721cdf0e10cSrcweir 6722cdf0e10cSrcweir // FIXME: implement tab order in structure tree for PDF 1.5 6723cdf0e10cSrcweir } 6724cdf0e10cSrcweir 6725cdf0e10cSrcweir namespace vcl { 6726cdf0e10cSrcweir class PDFStreamIf : 6727cdf0e10cSrcweir public cppu::WeakImplHelper1< com::sun::star::io::XOutputStream > 6728cdf0e10cSrcweir { 6729cdf0e10cSrcweir PDFWriterImpl* m_pWriter; 6730cdf0e10cSrcweir bool m_bWrite; 6731cdf0e10cSrcweir public: 6732cdf0e10cSrcweir PDFStreamIf( PDFWriterImpl* pWriter ) : m_pWriter( pWriter ), m_bWrite( true ) {} 6733cdf0e10cSrcweir virtual ~PDFStreamIf(); 6734cdf0e10cSrcweir 6735cdf0e10cSrcweir virtual void SAL_CALL writeBytes( const com::sun::star::uno::Sequence< sal_Int8 >& aData ) throw(); 6736cdf0e10cSrcweir virtual void SAL_CALL flush() throw(); 6737cdf0e10cSrcweir virtual void SAL_CALL closeOutput() throw(); 6738cdf0e10cSrcweir }; 6739cdf0e10cSrcweir } 6740cdf0e10cSrcweir 6741cdf0e10cSrcweir PDFStreamIf::~PDFStreamIf() 6742cdf0e10cSrcweir { 6743cdf0e10cSrcweir } 6744cdf0e10cSrcweir 6745cdf0e10cSrcweir void SAL_CALL PDFStreamIf::writeBytes( const com::sun::star::uno::Sequence< sal_Int8 >& aData ) throw() 6746cdf0e10cSrcweir { 6747cdf0e10cSrcweir if( m_bWrite ) 6748cdf0e10cSrcweir { 6749cdf0e10cSrcweir sal_Int32 nBytes = aData.getLength(); 6750cdf0e10cSrcweir if( nBytes > 0 ) 6751cdf0e10cSrcweir m_pWriter->writeBuffer( aData.getConstArray(), nBytes ); 6752cdf0e10cSrcweir } 6753cdf0e10cSrcweir } 6754cdf0e10cSrcweir 6755cdf0e10cSrcweir void SAL_CALL PDFStreamIf::flush() throw() 6756cdf0e10cSrcweir { 6757cdf0e10cSrcweir } 6758cdf0e10cSrcweir 6759cdf0e10cSrcweir void SAL_CALL PDFStreamIf::closeOutput() throw() 6760cdf0e10cSrcweir { 6761cdf0e10cSrcweir m_bWrite = false; 6762cdf0e10cSrcweir } 6763cdf0e10cSrcweir 6764cdf0e10cSrcweir bool PDFWriterImpl::emitAdditionalStreams() 6765cdf0e10cSrcweir { 6766cdf0e10cSrcweir unsigned int nStreams = m_aAdditionalStreams.size(); 6767cdf0e10cSrcweir for( unsigned int i = 0; i < nStreams; i++ ) 6768cdf0e10cSrcweir { 6769cdf0e10cSrcweir PDFAddStream& rStream = m_aAdditionalStreams[i]; 6770cdf0e10cSrcweir rStream.m_nStreamObject = createObject(); 6771cdf0e10cSrcweir sal_Int32 nSizeObject = createObject(); 6772cdf0e10cSrcweir 6773cdf0e10cSrcweir if( ! updateObject( rStream.m_nStreamObject ) ) 6774cdf0e10cSrcweir return false; 6775cdf0e10cSrcweir 6776cdf0e10cSrcweir OStringBuffer aLine; 6777cdf0e10cSrcweir aLine.append( rStream.m_nStreamObject ); 6778cdf0e10cSrcweir aLine.append( " 0 obj\n<</Length " ); 6779cdf0e10cSrcweir aLine.append( nSizeObject ); 6780cdf0e10cSrcweir aLine.append( " 0 R" ); 6781cdf0e10cSrcweir if( rStream.m_bCompress ) 6782cdf0e10cSrcweir aLine.append( "/Filter/FlateDecode" ); 6783cdf0e10cSrcweir aLine.append( ">>\nstream\n" ); 6784cdf0e10cSrcweir if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) ) 6785cdf0e10cSrcweir return false; 6786cdf0e10cSrcweir sal_uInt64 nBeginStreamPos = 0, nEndStreamPos = 0; 6787cdf0e10cSrcweir if( osl_File_E_None != osl_getFilePos( m_aFile, &nBeginStreamPos ) ) 6788cdf0e10cSrcweir { 6789cdf0e10cSrcweir osl_closeFile( m_aFile ); 6790cdf0e10cSrcweir m_bOpen = false; 6791cdf0e10cSrcweir } 6792cdf0e10cSrcweir if( rStream.m_bCompress ) 6793cdf0e10cSrcweir beginCompression(); 6794cdf0e10cSrcweir 6795cdf0e10cSrcweir checkAndEnableStreamEncryption( rStream.m_nStreamObject ); 6796cdf0e10cSrcweir com::sun::star::uno::Reference< com::sun::star::io::XOutputStream > xStream( new PDFStreamIf( this ) ); 6797cdf0e10cSrcweir rStream.m_pStream->write( xStream ); 6798cdf0e10cSrcweir xStream.clear(); 6799cdf0e10cSrcweir delete rStream.m_pStream; 6800cdf0e10cSrcweir rStream.m_pStream = NULL; 6801cdf0e10cSrcweir disableStreamEncryption(); 6802cdf0e10cSrcweir 6803cdf0e10cSrcweir if( rStream.m_bCompress ) 6804cdf0e10cSrcweir endCompression(); 6805cdf0e10cSrcweir 6806cdf0e10cSrcweir if( osl_File_E_None != osl_getFilePos( m_aFile, &nEndStreamPos ) ) 6807cdf0e10cSrcweir { 6808cdf0e10cSrcweir osl_closeFile( m_aFile ); 6809cdf0e10cSrcweir m_bOpen = false; 6810cdf0e10cSrcweir return false; 6811cdf0e10cSrcweir } 6812cdf0e10cSrcweir if( ! writeBuffer( "\nendstream\nendobj\n\n", 19 ) ) 6813cdf0e10cSrcweir return false ; 6814cdf0e10cSrcweir // emit stream length object 6815cdf0e10cSrcweir if( ! updateObject( nSizeObject ) ) 6816cdf0e10cSrcweir return false; 6817cdf0e10cSrcweir aLine.setLength( 0 ); 6818cdf0e10cSrcweir aLine.append( nSizeObject ); 6819cdf0e10cSrcweir aLine.append( " 0 obj\n" ); 6820cdf0e10cSrcweir aLine.append( (sal_Int64)(nEndStreamPos-nBeginStreamPos) ); 6821cdf0e10cSrcweir aLine.append( "\nendobj\n\n" ); 6822cdf0e10cSrcweir if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) ) 6823cdf0e10cSrcweir return false; 6824cdf0e10cSrcweir } 6825cdf0e10cSrcweir return true; 6826cdf0e10cSrcweir } 6827cdf0e10cSrcweir 6828cdf0e10cSrcweir bool PDFWriterImpl::emit() 6829cdf0e10cSrcweir { 6830cdf0e10cSrcweir endPage(); 6831cdf0e10cSrcweir 6832cdf0e10cSrcweir // resort structure tree and annotations if necessary 6833cdf0e10cSrcweir // needed for widget tab order 6834cdf0e10cSrcweir sortWidgets(); 6835cdf0e10cSrcweir 6836cdf0e10cSrcweir // emit additional streams 6837cdf0e10cSrcweir CHECK_RETURN( emitAdditionalStreams() ); 6838cdf0e10cSrcweir 6839cdf0e10cSrcweir // emit catalog 6840cdf0e10cSrcweir CHECK_RETURN( emitCatalog() ); 6841cdf0e10cSrcweir 6842cdf0e10cSrcweir // emit trailer 6843cdf0e10cSrcweir CHECK_RETURN( emitTrailer() ); 6844cdf0e10cSrcweir 6845cdf0e10cSrcweir osl_closeFile( m_aFile ); 6846cdf0e10cSrcweir m_bOpen = false; 6847cdf0e10cSrcweir 6848cdf0e10cSrcweir return true; 6849cdf0e10cSrcweir } 6850cdf0e10cSrcweir 6851cdf0e10cSrcweir std::set< PDFWriter::ErrorCode > PDFWriterImpl::getErrors() 6852cdf0e10cSrcweir { 6853cdf0e10cSrcweir return m_aErrors; 6854cdf0e10cSrcweir } 6855cdf0e10cSrcweir 6856cdf0e10cSrcweir sal_Int32 PDFWriterImpl::getSystemFont( const Font& i_rFont ) 6857cdf0e10cSrcweir { 6858cdf0e10cSrcweir getReferenceDevice()->Push(); 6859cdf0e10cSrcweir getReferenceDevice()->SetFont( i_rFont ); 6860cdf0e10cSrcweir getReferenceDevice()->ImplNewFont(); 6861cdf0e10cSrcweir 6862cdf0e10cSrcweir const ImplFontData* pDevFont = m_pReferenceDevice->mpFontEntry->maFontSelData.mpFontData; 6863cdf0e10cSrcweir sal_Int32 nFontID = 0; 6864cdf0e10cSrcweir FontEmbedData::iterator it = m_aSystemFonts.find( pDevFont ); 6865cdf0e10cSrcweir if( it != m_aSystemFonts.end() ) 6866cdf0e10cSrcweir nFontID = it->second.m_nNormalFontID; 6867cdf0e10cSrcweir else 6868cdf0e10cSrcweir { 6869cdf0e10cSrcweir nFontID = m_nNextFID++; 6870cdf0e10cSrcweir m_aSystemFonts[ pDevFont ] = EmbedFont(); 6871cdf0e10cSrcweir m_aSystemFonts[ pDevFont ].m_nNormalFontID = nFontID; 6872cdf0e10cSrcweir } 6873cdf0e10cSrcweir 6874cdf0e10cSrcweir getReferenceDevice()->Pop(); 6875cdf0e10cSrcweir getReferenceDevice()->ImplNewFont(); 6876cdf0e10cSrcweir 6877cdf0e10cSrcweir return nFontID; 6878cdf0e10cSrcweir } 6879cdf0e10cSrcweir 6880cdf0e10cSrcweir void PDFWriterImpl::registerGlyphs( int nGlyphs, 6881cdf0e10cSrcweir sal_GlyphId* pGlyphs, 6882cdf0e10cSrcweir sal_Int32* pGlyphWidths, 6883cdf0e10cSrcweir sal_Ucs* pUnicodes, 6884cdf0e10cSrcweir sal_Int32* pUnicodesPerGlyph, 6885cdf0e10cSrcweir sal_uInt8* pMappedGlyphs, 6886cdf0e10cSrcweir sal_Int32* pMappedFontObjects, 6887cdf0e10cSrcweir const ImplFontData* pFallbackFonts[] ) 6888cdf0e10cSrcweir { 6889cdf0e10cSrcweir const ImplFontData* pDevFont = m_pReferenceDevice->mpFontEntry->maFontSelData.mpFontData; 6890cdf0e10cSrcweir sal_Ucs* pCurUnicode = pUnicodes; 6891cdf0e10cSrcweir for( int i = 0; i < nGlyphs; pCurUnicode += pUnicodesPerGlyph[i] , i++ ) 6892cdf0e10cSrcweir { 6893cdf0e10cSrcweir const int nFontGlyphId = pGlyphs[i] & (GF_IDXMASK | GF_ISCHAR | GF_GSUB); 6894cdf0e10cSrcweir const ImplFontData* pCurrentFont = pFallbackFonts[i] ? pFallbackFonts[i] : pDevFont; 6895cdf0e10cSrcweir 6896cdf0e10cSrcweir if( isBuiltinFont( pCurrentFont ) ) 6897cdf0e10cSrcweir { 6898cdf0e10cSrcweir sal_Int32 nFontID = 0; 6899cdf0e10cSrcweir FontEmbedData::iterator it = m_aEmbeddedFonts.find( pCurrentFont ); 6900cdf0e10cSrcweir if( it != m_aEmbeddedFonts.end() ) 6901cdf0e10cSrcweir nFontID = it->second.m_nNormalFontID; 6902cdf0e10cSrcweir else 6903cdf0e10cSrcweir { 6904cdf0e10cSrcweir nFontID = m_nNextFID++; 6905cdf0e10cSrcweir m_aEmbeddedFonts[ pCurrentFont ] = EmbedFont(); 6906cdf0e10cSrcweir m_aEmbeddedFonts[ pCurrentFont ].m_nNormalFontID = nFontID; 6907cdf0e10cSrcweir } 6908cdf0e10cSrcweir 6909cdf0e10cSrcweir pGlyphWidths[ i ] = 0; 6910cdf0e10cSrcweir pMappedGlyphs[ i ] = sal::static_int_cast<sal_Int8>( nFontGlyphId ); 6911cdf0e10cSrcweir pMappedFontObjects[ i ] = nFontID; 6912cdf0e10cSrcweir const ImplPdfBuiltinFontData* pFD = GetPdfFontData( pCurrentFont ); 6913cdf0e10cSrcweir if( pFD ) 6914cdf0e10cSrcweir { 6915cdf0e10cSrcweir const BuiltinFont* pBuiltinFont = pFD->GetBuiltinFont(); 6916cdf0e10cSrcweir pGlyphWidths[i] = pBuiltinFont->m_aWidths[ nFontGlyphId & 0x00ff ]; 6917cdf0e10cSrcweir } 6918cdf0e10cSrcweir } 6919cdf0e10cSrcweir else if( pCurrentFont->mbSubsettable ) 6920cdf0e10cSrcweir { 6921cdf0e10cSrcweir FontSubset& rSubset = m_aSubsets[ pCurrentFont ]; 6922cdf0e10cSrcweir // search for font specific glyphID 6923cdf0e10cSrcweir FontMapping::iterator it = rSubset.m_aMapping.find( nFontGlyphId ); 6924cdf0e10cSrcweir if( it != rSubset.m_aMapping.end() ) 6925cdf0e10cSrcweir { 6926cdf0e10cSrcweir pMappedFontObjects[i] = it->second.m_nFontID; 6927cdf0e10cSrcweir pMappedGlyphs[i] = it->second.m_nSubsetGlyphID; 6928cdf0e10cSrcweir } 6929cdf0e10cSrcweir else 6930cdf0e10cSrcweir { 6931cdf0e10cSrcweir // create new subset if necessary 6932cdf0e10cSrcweir if( rSubset.m_aSubsets.empty() 6933cdf0e10cSrcweir || (rSubset.m_aSubsets.back().m_aMapping.size() > 254) ) 6934cdf0e10cSrcweir { 6935cdf0e10cSrcweir rSubset.m_aSubsets.push_back( FontEmit( m_nNextFID++ ) ); 6936cdf0e10cSrcweir } 6937cdf0e10cSrcweir 6938cdf0e10cSrcweir // copy font id 6939cdf0e10cSrcweir pMappedFontObjects[i] = rSubset.m_aSubsets.back().m_nFontID; 6940cdf0e10cSrcweir // create new glyph in subset 6941cdf0e10cSrcweir sal_uInt8 nNewId = sal::static_int_cast<sal_uInt8>(rSubset.m_aSubsets.back().m_aMapping.size()+1); 6942cdf0e10cSrcweir pMappedGlyphs[i] = nNewId; 6943cdf0e10cSrcweir 6944cdf0e10cSrcweir // add new glyph to emitted font subset 6945cdf0e10cSrcweir GlyphEmit& rNewGlyphEmit = rSubset.m_aSubsets.back().m_aMapping[ nFontGlyphId ]; 6946cdf0e10cSrcweir rNewGlyphEmit.setGlyphId( nNewId ); 6947cdf0e10cSrcweir for( sal_Int32 n = 0; n < pUnicodesPerGlyph[i]; n++ ) 6948cdf0e10cSrcweir rNewGlyphEmit.addCode( pCurUnicode[n] ); 6949cdf0e10cSrcweir 6950cdf0e10cSrcweir // add new glyph to font mapping 6951cdf0e10cSrcweir Glyph& rNewGlyph = rSubset.m_aMapping[ nFontGlyphId ]; 6952cdf0e10cSrcweir rNewGlyph.m_nFontID = pMappedFontObjects[i]; 6953cdf0e10cSrcweir rNewGlyph.m_nSubsetGlyphID = nNewId; 6954cdf0e10cSrcweir } 6955cdf0e10cSrcweir getReferenceDevice()->ImplGetGraphics(); 6956cdf0e10cSrcweir const bool bVertical = ((pGlyphs[i] & GF_ROTMASK) != 0); 6957cdf0e10cSrcweir pGlyphWidths[i] = m_aFontCache.getGlyphWidth( pCurrentFont, 6958cdf0e10cSrcweir nFontGlyphId, 6959cdf0e10cSrcweir bVertical, 6960cdf0e10cSrcweir m_pReferenceDevice->mpGraphics ); 6961cdf0e10cSrcweir } 6962cdf0e10cSrcweir else if( pCurrentFont->IsEmbeddable() ) 6963cdf0e10cSrcweir { 6964cdf0e10cSrcweir sal_Int32 nFontID = 0; 6965cdf0e10cSrcweir FontEmbedData::iterator it = m_aEmbeddedFonts.find( pCurrentFont ); 6966cdf0e10cSrcweir if( it != m_aEmbeddedFonts.end() ) 6967cdf0e10cSrcweir nFontID = it->second.m_nNormalFontID; 6968cdf0e10cSrcweir else 6969cdf0e10cSrcweir { 6970cdf0e10cSrcweir nFontID = m_nNextFID++; 6971cdf0e10cSrcweir m_aEmbeddedFonts[ pCurrentFont ] = EmbedFont(); 6972cdf0e10cSrcweir m_aEmbeddedFonts[ pCurrentFont ].m_nNormalFontID = nFontID; 6973cdf0e10cSrcweir } 6974cdf0e10cSrcweir EmbedFont& rEmbedFont = m_aEmbeddedFonts[pCurrentFont]; 6975cdf0e10cSrcweir 6976cdf0e10cSrcweir const Ucs2SIntMap* pEncoding = NULL; 6977cdf0e10cSrcweir const Ucs2OStrMap* pNonEncoded = NULL; 6978cdf0e10cSrcweir getReferenceDevice()->ImplGetGraphics(); 6979cdf0e10cSrcweir pEncoding = m_pReferenceDevice->mpGraphics->GetFontEncodingVector( pCurrentFont, &pNonEncoded ); 6980cdf0e10cSrcweir 6981cdf0e10cSrcweir Ucs2SIntMap::const_iterator enc_it; 6982cdf0e10cSrcweir Ucs2OStrMap::const_iterator nonenc_it; 6983cdf0e10cSrcweir 6984cdf0e10cSrcweir sal_Int32 nCurFontID = nFontID; 6985cdf0e10cSrcweir sal_Ucs cChar = *pCurUnicode; 6986cdf0e10cSrcweir if( pEncoding ) 6987cdf0e10cSrcweir { 6988cdf0e10cSrcweir enc_it = pEncoding->find( cChar ); 6989cdf0e10cSrcweir if( enc_it != pEncoding->end() && enc_it->second > 0 ) 6990cdf0e10cSrcweir { 6991cdf0e10cSrcweir DBG_ASSERT( (enc_it->second & 0xffffff00) == 0, "Invalid character code" ); 6992cdf0e10cSrcweir cChar = (sal_Ucs)enc_it->second; 6993cdf0e10cSrcweir } 6994cdf0e10cSrcweir else if( (enc_it == pEncoding->end() || enc_it->second == -1) && 6995cdf0e10cSrcweir pNonEncoded && 6996cdf0e10cSrcweir (nonenc_it = pNonEncoded->find( cChar )) != pNonEncoded->end() ) 6997cdf0e10cSrcweir { 6998cdf0e10cSrcweir nCurFontID = 0; 6999cdf0e10cSrcweir // find non encoded glyph 7000cdf0e10cSrcweir for( std::list< EmbedEncoding >::iterator nec_it = rEmbedFont.m_aExtendedEncodings.begin(); nec_it != rEmbedFont.m_aExtendedEncodings.end(); ++nec_it ) 7001cdf0e10cSrcweir { 7002cdf0e10cSrcweir if( nec_it->m_aCMap.find( cChar ) != nec_it->m_aCMap.end() ) 7003cdf0e10cSrcweir { 7004cdf0e10cSrcweir nCurFontID = nec_it->m_nFontID; 7005cdf0e10cSrcweir cChar = (sal_Ucs)nec_it->m_aCMap[ cChar ]; 7006cdf0e10cSrcweir break; 7007cdf0e10cSrcweir } 7008cdf0e10cSrcweir } 7009cdf0e10cSrcweir if( nCurFontID == 0 ) // new nonencoded glyph 7010cdf0e10cSrcweir { 7011cdf0e10cSrcweir if( rEmbedFont.m_aExtendedEncodings.empty() || rEmbedFont.m_aExtendedEncodings.back().m_aEncVector.size() == 255 ) 7012cdf0e10cSrcweir { 7013cdf0e10cSrcweir rEmbedFont.m_aExtendedEncodings.push_back( EmbedEncoding() ); 7014cdf0e10cSrcweir rEmbedFont.m_aExtendedEncodings.back().m_nFontID = m_nNextFID++; 7015cdf0e10cSrcweir } 7016cdf0e10cSrcweir EmbedEncoding& rEncoding = rEmbedFont.m_aExtendedEncodings.back(); 7017cdf0e10cSrcweir rEncoding.m_aEncVector.push_back( EmbedCode() ); 7018cdf0e10cSrcweir rEncoding.m_aEncVector.back().m_aUnicode = cChar; 7019cdf0e10cSrcweir rEncoding.m_aEncVector.back().m_aName = nonenc_it->second; 7020cdf0e10cSrcweir rEncoding.m_aCMap[ cChar ] = (sal_Int8)(rEncoding.m_aEncVector.size()-1); 7021cdf0e10cSrcweir nCurFontID = rEncoding.m_nFontID; 7022cdf0e10cSrcweir cChar = (sal_Ucs)rEncoding.m_aCMap[ cChar ]; 7023cdf0e10cSrcweir } 7024cdf0e10cSrcweir } 7025cdf0e10cSrcweir else 7026cdf0e10cSrcweir pEncoding = NULL; 7027cdf0e10cSrcweir } 7028cdf0e10cSrcweir if( ! pEncoding ) 7029cdf0e10cSrcweir { 7030cdf0e10cSrcweir if( cChar & 0xff00 ) 7031cdf0e10cSrcweir { 7032cdf0e10cSrcweir // some characters can be used by conversion 7033cdf0e10cSrcweir if( cChar >= 0xf000 && cChar <= 0xf0ff ) // symbol encoding in private use area 7034cdf0e10cSrcweir cChar -= 0xf000; 7035cdf0e10cSrcweir else 7036cdf0e10cSrcweir { 7037cdf0e10cSrcweir String aString(cChar); 7038cdf0e10cSrcweir ByteString aChar( aString, RTL_TEXTENCODING_MS_1252 ); 7039cdf0e10cSrcweir cChar = ((sal_Ucs)aChar.GetChar( 0 )) & 0x00ff; 7040cdf0e10cSrcweir } 7041cdf0e10cSrcweir } 7042cdf0e10cSrcweir } 7043cdf0e10cSrcweir 7044cdf0e10cSrcweir pMappedGlyphs[ i ] = (sal_Int8)cChar; 7045cdf0e10cSrcweir pMappedFontObjects[ i ] = nCurFontID; 7046cdf0e10cSrcweir pGlyphWidths[ i ] = m_aFontCache.getGlyphWidth( pCurrentFont, 7047cdf0e10cSrcweir (pEncoding ? *pCurUnicode : cChar) | GF_ISCHAR, 7048cdf0e10cSrcweir false, 7049cdf0e10cSrcweir m_pReferenceDevice->mpGraphics ); 7050cdf0e10cSrcweir } 7051cdf0e10cSrcweir } 7052cdf0e10cSrcweir } 7053cdf0e10cSrcweir 7054cdf0e10cSrcweir void PDFWriterImpl::drawRelief( SalLayout& rLayout, const String& rText, bool bTextLines ) 7055cdf0e10cSrcweir { 7056cdf0e10cSrcweir push( PUSH_ALL ); 7057cdf0e10cSrcweir 7058cdf0e10cSrcweir FontRelief eRelief = m_aCurrentPDFState.m_aFont.GetRelief(); 7059cdf0e10cSrcweir 7060cdf0e10cSrcweir Color aTextColor = m_aCurrentPDFState.m_aFont.GetColor(); 7061cdf0e10cSrcweir Color aTextLineColor = m_aCurrentPDFState.m_aTextLineColor; 7062cdf0e10cSrcweir Color aOverlineColor = m_aCurrentPDFState.m_aOverlineColor; 7063cdf0e10cSrcweir Color aReliefColor( COL_LIGHTGRAY ); 7064cdf0e10cSrcweir if( aTextColor == COL_BLACK ) 7065cdf0e10cSrcweir aTextColor = Color( COL_WHITE ); 7066cdf0e10cSrcweir if( aTextLineColor == COL_BLACK ) 7067cdf0e10cSrcweir aTextLineColor = Color( COL_WHITE ); 7068cdf0e10cSrcweir if( aOverlineColor == COL_BLACK ) 7069cdf0e10cSrcweir aOverlineColor = Color( COL_WHITE ); 7070cdf0e10cSrcweir if( aTextColor == COL_WHITE ) 7071cdf0e10cSrcweir aReliefColor = Color( COL_BLACK ); 7072cdf0e10cSrcweir 7073cdf0e10cSrcweir Font aSetFont = m_aCurrentPDFState.m_aFont; 7074cdf0e10cSrcweir aSetFont.SetRelief( RELIEF_NONE ); 7075cdf0e10cSrcweir aSetFont.SetShadow( sal_False ); 7076cdf0e10cSrcweir 7077cdf0e10cSrcweir aSetFont.SetColor( aReliefColor ); 7078cdf0e10cSrcweir setTextLineColor( aReliefColor ); 7079cdf0e10cSrcweir setOverlineColor( aReliefColor ); 7080cdf0e10cSrcweir setFont( aSetFont ); 7081cdf0e10cSrcweir long nOff = 1 + getReferenceDevice()->mnDPIX/300; 7082cdf0e10cSrcweir if( eRelief == RELIEF_ENGRAVED ) 7083cdf0e10cSrcweir nOff = -nOff; 7084cdf0e10cSrcweir 7085cdf0e10cSrcweir rLayout.DrawOffset() += Point( nOff, nOff ); 7086cdf0e10cSrcweir updateGraphicsState(); 7087cdf0e10cSrcweir drawLayout( rLayout, rText, bTextLines ); 7088cdf0e10cSrcweir 7089cdf0e10cSrcweir rLayout.DrawOffset() -= Point( nOff, nOff ); 7090cdf0e10cSrcweir setTextLineColor( aTextLineColor ); 7091cdf0e10cSrcweir setOverlineColor( aOverlineColor ); 7092cdf0e10cSrcweir aSetFont.SetColor( aTextColor ); 7093cdf0e10cSrcweir setFont( aSetFont ); 7094cdf0e10cSrcweir updateGraphicsState(); 7095cdf0e10cSrcweir drawLayout( rLayout, rText, bTextLines ); 7096cdf0e10cSrcweir 7097cdf0e10cSrcweir // clean up the mess 7098cdf0e10cSrcweir pop(); 7099cdf0e10cSrcweir } 7100cdf0e10cSrcweir 7101cdf0e10cSrcweir void PDFWriterImpl::drawShadow( SalLayout& rLayout, const String& rText, bool bTextLines ) 7102cdf0e10cSrcweir { 7103cdf0e10cSrcweir Font aSaveFont = m_aCurrentPDFState.m_aFont; 7104cdf0e10cSrcweir Color aSaveTextLineColor = m_aCurrentPDFState.m_aTextLineColor; 7105cdf0e10cSrcweir Color aSaveOverlineColor = m_aCurrentPDFState.m_aOverlineColor; 7106cdf0e10cSrcweir 7107cdf0e10cSrcweir Font& rFont = m_aCurrentPDFState.m_aFont; 7108cdf0e10cSrcweir if( rFont.GetColor() == Color( COL_BLACK ) || rFont.GetColor().GetLuminance() < 8 ) 7109cdf0e10cSrcweir rFont.SetColor( Color( COL_LIGHTGRAY ) ); 7110cdf0e10cSrcweir else 7111cdf0e10cSrcweir rFont.SetColor( Color( COL_BLACK ) ); 7112cdf0e10cSrcweir rFont.SetShadow( sal_False ); 7113cdf0e10cSrcweir rFont.SetOutline( sal_False ); 7114cdf0e10cSrcweir setFont( rFont ); 7115cdf0e10cSrcweir setTextLineColor( rFont.GetColor() ); 7116cdf0e10cSrcweir setOverlineColor( rFont.GetColor() ); 7117cdf0e10cSrcweir updateGraphicsState(); 7118cdf0e10cSrcweir 7119cdf0e10cSrcweir long nOff = 1 + ((m_pReferenceDevice->mpFontEntry->mnLineHeight-24)/24); 7120cdf0e10cSrcweir if( rFont.IsOutline() ) 7121cdf0e10cSrcweir nOff++; 7122cdf0e10cSrcweir rLayout.DrawBase() += Point( nOff, nOff ); 7123cdf0e10cSrcweir drawLayout( rLayout, rText, bTextLines ); 7124cdf0e10cSrcweir rLayout.DrawBase() -= Point( nOff, nOff ); 7125cdf0e10cSrcweir 7126cdf0e10cSrcweir setFont( aSaveFont ); 7127cdf0e10cSrcweir setTextLineColor( aSaveTextLineColor ); 7128cdf0e10cSrcweir setOverlineColor( aSaveOverlineColor ); 7129cdf0e10cSrcweir updateGraphicsState(); 7130cdf0e10cSrcweir } 7131cdf0e10cSrcweir 7132cdf0e10cSrcweir void PDFWriterImpl::drawVerticalGlyphs( 7133cdf0e10cSrcweir const std::vector<PDFWriterImpl::PDFGlyph>& rGlyphs, 7134cdf0e10cSrcweir OStringBuffer& rLine, 7135cdf0e10cSrcweir const Point& rAlignOffset, 7136cdf0e10cSrcweir const Matrix3& rRotScale, 7137cdf0e10cSrcweir double fAngle, 7138cdf0e10cSrcweir double fXScale, 7139cdf0e10cSrcweir double fSkew, 7140cdf0e10cSrcweir sal_Int32 nFontHeight ) 7141cdf0e10cSrcweir { 7142cdf0e10cSrcweir long nXOffset = 0; 7143cdf0e10cSrcweir Point aCurPos( rGlyphs[0].m_aPos ); 7144cdf0e10cSrcweir aCurPos = m_pReferenceDevice->PixelToLogic( aCurPos ); 7145cdf0e10cSrcweir aCurPos += rAlignOffset; 7146cdf0e10cSrcweir for( size_t i = 0; i < rGlyphs.size(); i++ ) 7147cdf0e10cSrcweir { 7148cdf0e10cSrcweir // have to emit each glyph on its own 7149cdf0e10cSrcweir double fDeltaAngle = 0.0; 7150cdf0e10cSrcweir double fYScale = 1.0; 7151cdf0e10cSrcweir double fTempXScale = fXScale; 7152cdf0e10cSrcweir double fSkewB = fSkew; 7153cdf0e10cSrcweir double fSkewA = 0.0; 7154cdf0e10cSrcweir 7155cdf0e10cSrcweir Point aDeltaPos; 7156cdf0e10cSrcweir if( ( rGlyphs[i].m_nGlyphId & GF_ROTMASK ) == GF_ROTL ) 7157cdf0e10cSrcweir { 7158cdf0e10cSrcweir fDeltaAngle = M_PI/2.0; 7159cdf0e10cSrcweir aDeltaPos.X() = m_pReferenceDevice->GetFontMetric().GetAscent(); 7160cdf0e10cSrcweir aDeltaPos.Y() = (int)((double)m_pReferenceDevice->GetFontMetric().GetDescent() * fXScale); 7161cdf0e10cSrcweir fYScale = fXScale; 7162cdf0e10cSrcweir fTempXScale = 1.0; 7163cdf0e10cSrcweir fSkewA = -fSkewB; 7164cdf0e10cSrcweir fSkewB = 0.0; 7165cdf0e10cSrcweir } 7166cdf0e10cSrcweir else if( ( rGlyphs[i].m_nGlyphId & GF_ROTMASK ) == GF_ROTR ) 7167cdf0e10cSrcweir { 7168cdf0e10cSrcweir fDeltaAngle = -M_PI/2.0; 7169cdf0e10cSrcweir aDeltaPos.X() = (int)((double)m_pReferenceDevice->GetFontMetric().GetDescent()*fXScale); 7170cdf0e10cSrcweir aDeltaPos.Y() = -m_pReferenceDevice->GetFontMetric().GetAscent(); 7171cdf0e10cSrcweir fYScale = fXScale; 7172cdf0e10cSrcweir fTempXScale = 1.0; 7173cdf0e10cSrcweir fSkewA = fSkewB; 7174cdf0e10cSrcweir fSkewB = 0.0; 7175cdf0e10cSrcweir } 7176cdf0e10cSrcweir aDeltaPos += (m_pReferenceDevice->PixelToLogic( Point( (int)((double)nXOffset/fXScale), 0 ) ) - m_pReferenceDevice->PixelToLogic( Point() ) ); 7177cdf0e10cSrcweir if( i < rGlyphs.size()-1 ) 7178*3c19fd8cSZhe Wang // [Bug 120627] the text on the Y axis is reversed when export ppt file to PDF format 7179*3c19fd8cSZhe Wang { 7180*3c19fd8cSZhe Wang long nOffsetX = rGlyphs[i+1].m_aPos.X() - rGlyphs[i].m_aPos.X(); 7181*3c19fd8cSZhe Wang long nOffsetY = rGlyphs[i+1].m_aPos.Y() - rGlyphs[i].m_aPos.Y(); 7182*3c19fd8cSZhe Wang nXOffset += (int)sqrt(double(nOffsetX*nOffsetX + nOffsetY*nOffsetY)); 7183*3c19fd8cSZhe Wang } 7184cdf0e10cSrcweir if( ! rGlyphs[i].m_nGlyphId ) 7185cdf0e10cSrcweir continue; 7186cdf0e10cSrcweir 7187cdf0e10cSrcweir aDeltaPos = rRotScale.transform( aDeltaPos ); 7188cdf0e10cSrcweir 7189cdf0e10cSrcweir Matrix3 aMat; 7190cdf0e10cSrcweir if( fSkewB != 0.0 || fSkewA != 0.0 ) 7191cdf0e10cSrcweir aMat.skew( fSkewA, fSkewB ); 7192cdf0e10cSrcweir aMat.scale( fTempXScale, fYScale ); 7193cdf0e10cSrcweir aMat.rotate( fAngle+fDeltaAngle ); 7194cdf0e10cSrcweir aMat.translate( aCurPos.X()+aDeltaPos.X(), aCurPos.Y()+aDeltaPos.Y() ); 7195cdf0e10cSrcweir aMat.append( m_aPages.back(), rLine ); 7196cdf0e10cSrcweir rLine.append( " Tm" ); 7197cdf0e10cSrcweir if( i == 0 || rGlyphs[i-1].m_nMappedFontId != rGlyphs[i].m_nMappedFontId ) 7198cdf0e10cSrcweir { 7199cdf0e10cSrcweir rLine.append( " /F" ); 7200cdf0e10cSrcweir rLine.append( rGlyphs[i].m_nMappedFontId ); 7201cdf0e10cSrcweir rLine.append( ' ' ); 7202cdf0e10cSrcweir m_aPages.back().appendMappedLength( nFontHeight, rLine, true ); 7203cdf0e10cSrcweir rLine.append( " Tf" ); 7204cdf0e10cSrcweir } 7205cdf0e10cSrcweir rLine.append( "<" ); 7206cdf0e10cSrcweir appendHex( rGlyphs[i].m_nMappedGlyphId, rLine ); 7207cdf0e10cSrcweir rLine.append( ">Tj\n" ); 7208cdf0e10cSrcweir } 7209cdf0e10cSrcweir } 7210cdf0e10cSrcweir 7211cdf0e10cSrcweir void PDFWriterImpl::drawHorizontalGlyphs( 7212cdf0e10cSrcweir const std::vector<PDFWriterImpl::PDFGlyph>& rGlyphs, 7213cdf0e10cSrcweir OStringBuffer& rLine, 7214cdf0e10cSrcweir const Point& rAlignOffset, 7215cdf0e10cSrcweir double fAngle, 7216cdf0e10cSrcweir double fXScale, 7217cdf0e10cSrcweir double fSkew, 7218cdf0e10cSrcweir sal_Int32 nFontHeight, 7219cdf0e10cSrcweir sal_Int32 nPixelFontHeight 7220cdf0e10cSrcweir ) 7221cdf0e10cSrcweir { 7222cdf0e10cSrcweir // horizontal (= normal) case 7223cdf0e10cSrcweir 7224cdf0e10cSrcweir // fill in run end indices 7225cdf0e10cSrcweir // end is marked by index of the first glyph of the next run 7226cdf0e10cSrcweir // a run is marked by same mapped font id and same Y position 7227cdf0e10cSrcweir std::vector< sal_uInt32 > aRunEnds; 7228cdf0e10cSrcweir aRunEnds.reserve( rGlyphs.size() ); 7229cdf0e10cSrcweir for( size_t i = 1; i < rGlyphs.size(); i++ ) 7230cdf0e10cSrcweir { 7231cdf0e10cSrcweir if( rGlyphs[i].m_nMappedFontId != rGlyphs[i-1].m_nMappedFontId || 7232cdf0e10cSrcweir rGlyphs[i].m_aPos.Y() != rGlyphs[i-1].m_aPos.Y() ) 7233cdf0e10cSrcweir { 7234cdf0e10cSrcweir aRunEnds.push_back(i); 7235cdf0e10cSrcweir } 7236cdf0e10cSrcweir } 7237cdf0e10cSrcweir // last run ends at last glyph 7238cdf0e10cSrcweir aRunEnds.push_back( rGlyphs.size() ); 7239cdf0e10cSrcweir 7240cdf0e10cSrcweir // loop over runs of the same font 7241cdf0e10cSrcweir sal_uInt32 nBeginRun = 0; 7242cdf0e10cSrcweir for( size_t nRun = 0; nRun < aRunEnds.size(); nRun++ ) 7243cdf0e10cSrcweir { 7244cdf0e10cSrcweir // setup text matrix 7245cdf0e10cSrcweir Point aCurPos = rGlyphs[nBeginRun].m_aPos; 7246cdf0e10cSrcweir // back transformation to current coordinate system 7247cdf0e10cSrcweir aCurPos = m_pReferenceDevice->PixelToLogic( aCurPos ); 7248cdf0e10cSrcweir aCurPos += rAlignOffset; 7249cdf0e10cSrcweir // the first run can be set with "Td" operator 7250cdf0e10cSrcweir // subsequent use of that operator would move 7251cdf0e10cSrcweir // the texline matrix relative to what was set before 7252cdf0e10cSrcweir // making use of that would drive us into rounding issues 7253cdf0e10cSrcweir Matrix3 aMat; 7254cdf0e10cSrcweir if( nRun == 0 && fAngle == 0.0 && fXScale == 1.0 && fSkew == 0.0 ) 7255cdf0e10cSrcweir { 7256cdf0e10cSrcweir m_aPages.back().appendPoint( aCurPos, rLine, false ); 7257cdf0e10cSrcweir rLine.append( " Td " ); 7258cdf0e10cSrcweir } 7259cdf0e10cSrcweir else 7260cdf0e10cSrcweir { 7261cdf0e10cSrcweir if( fSkew != 0.0 ) 7262cdf0e10cSrcweir aMat.skew( 0.0, fSkew ); 7263cdf0e10cSrcweir aMat.scale( fXScale, 1.0 ); 7264cdf0e10cSrcweir aMat.rotate( fAngle ); 7265cdf0e10cSrcweir aMat.translate( aCurPos.X(), aCurPos.Y() ); 7266cdf0e10cSrcweir aMat.append( m_aPages.back(), rLine ); 7267cdf0e10cSrcweir rLine.append( " Tm\n" ); 7268cdf0e10cSrcweir } 7269cdf0e10cSrcweir // set up correct font 7270cdf0e10cSrcweir rLine.append( "/F" ); 7271cdf0e10cSrcweir rLine.append( rGlyphs[nBeginRun].m_nMappedFontId ); 7272cdf0e10cSrcweir rLine.append( ' ' ); 7273cdf0e10cSrcweir m_aPages.back().appendMappedLength( nFontHeight, rLine, true ); 7274cdf0e10cSrcweir rLine.append( " Tf" ); 7275cdf0e10cSrcweir 7276cdf0e10cSrcweir // output glyphs using Tj or TJ 7277cdf0e10cSrcweir OStringBuffer aKernedLine( 256 ), aUnkernedLine( 256 ); 7278cdf0e10cSrcweir aKernedLine.append( "[<" ); 7279cdf0e10cSrcweir aUnkernedLine.append( '<' ); 7280cdf0e10cSrcweir appendHex( rGlyphs[nBeginRun].m_nMappedGlyphId, aKernedLine ); 7281cdf0e10cSrcweir appendHex( rGlyphs[nBeginRun].m_nMappedGlyphId, aUnkernedLine ); 7282cdf0e10cSrcweir 7283cdf0e10cSrcweir aMat.invert(); 7284cdf0e10cSrcweir bool bNeedKern = false; 7285cdf0e10cSrcweir for( sal_uInt32 nPos = nBeginRun+1; nPos < aRunEnds[nRun]; nPos++ ) 7286cdf0e10cSrcweir { 7287cdf0e10cSrcweir appendHex( rGlyphs[nPos].m_nMappedGlyphId, aUnkernedLine ); 7288cdf0e10cSrcweir // check if default glyph positioning is sufficient 7289cdf0e10cSrcweir const Point aThisPos = aMat.transform( rGlyphs[nPos].m_aPos ); 7290cdf0e10cSrcweir const Point aPrevPos = aMat.transform( rGlyphs[nPos-1].m_aPos ); 7291cdf0e10cSrcweir double fAdvance = aThisPos.X() - aPrevPos.X(); 7292cdf0e10cSrcweir fAdvance *= 1000.0 / nPixelFontHeight; 7293cdf0e10cSrcweir const sal_Int32 nAdjustment = (sal_Int32)(rGlyphs[nPos-1].m_nNativeWidth - fAdvance + 0.5); 7294cdf0e10cSrcweir if( nAdjustment != 0 ) 7295cdf0e10cSrcweir { 7296cdf0e10cSrcweir // apply individual glyph positioning 7297cdf0e10cSrcweir bNeedKern = true; 7298cdf0e10cSrcweir aKernedLine.append( ">" ); 7299cdf0e10cSrcweir aKernedLine.append( nAdjustment ); 7300cdf0e10cSrcweir aKernedLine.append( "<" ); 7301cdf0e10cSrcweir } 7302cdf0e10cSrcweir appendHex( rGlyphs[nPos].m_nMappedGlyphId, aKernedLine ); 7303cdf0e10cSrcweir } 7304cdf0e10cSrcweir aKernedLine.append( ">]TJ\n" ); 7305cdf0e10cSrcweir aUnkernedLine.append( ">Tj\n" ); 7306cdf0e10cSrcweir rLine.append( bNeedKern ? aKernedLine : aUnkernedLine ); 7307cdf0e10cSrcweir 7308cdf0e10cSrcweir // set beginning of next run 7309cdf0e10cSrcweir nBeginRun = aRunEnds[nRun]; 7310cdf0e10cSrcweir } 7311cdf0e10cSrcweir } 7312cdf0e10cSrcweir 7313cdf0e10cSrcweir void PDFWriterImpl::drawLayout( SalLayout& rLayout, const String& rText, bool bTextLines ) 7314cdf0e10cSrcweir { 7315cdf0e10cSrcweir // relief takes precedence over shadow (see outdev3.cxx) 7316cdf0e10cSrcweir if( m_aCurrentPDFState.m_aFont.GetRelief() != RELIEF_NONE ) 7317cdf0e10cSrcweir { 7318cdf0e10cSrcweir drawRelief( rLayout, rText, bTextLines ); 7319cdf0e10cSrcweir return; 7320cdf0e10cSrcweir } 7321cdf0e10cSrcweir else if( m_aCurrentPDFState.m_aFont.IsShadow() ) 7322cdf0e10cSrcweir drawShadow( rLayout, rText, bTextLines ); 7323cdf0e10cSrcweir 7324cdf0e10cSrcweir OStringBuffer aLine( 512 ); 7325cdf0e10cSrcweir 7326cdf0e10cSrcweir const int nMaxGlyphs = 256; 7327cdf0e10cSrcweir 7328cdf0e10cSrcweir sal_GlyphId pGlyphs[nMaxGlyphs]; 7329cdf0e10cSrcweir sal_Int32 pGlyphWidths[nMaxGlyphs]; 7330cdf0e10cSrcweir sal_uInt8 pMappedGlyphs[nMaxGlyphs]; 7331cdf0e10cSrcweir sal_Int32 pMappedFontObjects[nMaxGlyphs]; 7332cdf0e10cSrcweir std::vector<sal_Ucs> aUnicodes; 7333cdf0e10cSrcweir aUnicodes.reserve( nMaxGlyphs ); 7334cdf0e10cSrcweir sal_Int32 pUnicodesPerGlyph[nMaxGlyphs]; 7335cdf0e10cSrcweir int pCharPosAry[nMaxGlyphs]; 7336cdf0e10cSrcweir sal_Int32 nAdvanceWidths[nMaxGlyphs]; 7337cdf0e10cSrcweir const ImplFontData* pFallbackFonts[nMaxGlyphs]; 7338cdf0e10cSrcweir bool bVertical = m_aCurrentPDFState.m_aFont.IsVertical(); 7339cdf0e10cSrcweir int nGlyphs; 7340cdf0e10cSrcweir int nIndex = 0; 7341cdf0e10cSrcweir int nMinCharPos = 0, nMaxCharPos = rText.Len()-1; 7342cdf0e10cSrcweir double fXScale = 1.0; 7343cdf0e10cSrcweir double fSkew = 0.0; 7344cdf0e10cSrcweir sal_Int32 nPixelFontHeight = m_pReferenceDevice->mpFontEntry->maFontSelData.mnHeight; 7345cdf0e10cSrcweir TextAlign eAlign = m_aCurrentPDFState.m_aFont.GetAlign(); 7346cdf0e10cSrcweir 7347cdf0e10cSrcweir // transform font height back to current units 7348cdf0e10cSrcweir // note: the layout calculates in outdevs device pixel !! 7349cdf0e10cSrcweir sal_Int32 nFontHeight = m_pReferenceDevice->ImplDevicePixelToLogicHeight( nPixelFontHeight ); 7350cdf0e10cSrcweir if( m_aCurrentPDFState.m_aFont.GetWidth() ) 7351cdf0e10cSrcweir { 7352cdf0e10cSrcweir Font aFont( m_aCurrentPDFState.m_aFont ); 7353cdf0e10cSrcweir aFont.SetWidth( 0 ); 7354cdf0e10cSrcweir FontMetric aMetric = m_pReferenceDevice->GetFontMetric( aFont ); 7355cdf0e10cSrcweir if( aMetric.GetWidth() != m_aCurrentPDFState.m_aFont.GetWidth() ) 7356cdf0e10cSrcweir { 7357cdf0e10cSrcweir fXScale = 7358cdf0e10cSrcweir (double)m_aCurrentPDFState.m_aFont.GetWidth() / 7359cdf0e10cSrcweir (double)aMetric.GetWidth(); 7360cdf0e10cSrcweir } 7361cdf0e10cSrcweir // force state before GetFontMetric 7362cdf0e10cSrcweir m_pReferenceDevice->ImplNewFont(); 7363cdf0e10cSrcweir } 7364cdf0e10cSrcweir 7365cdf0e10cSrcweir // perform artificial italics if necessary 7366cdf0e10cSrcweir if( ( m_aCurrentPDFState.m_aFont.GetItalic() == ITALIC_NORMAL || 7367cdf0e10cSrcweir m_aCurrentPDFState.m_aFont.GetItalic() == ITALIC_OBLIQUE ) && 7368cdf0e10cSrcweir !( m_pReferenceDevice->mpFontEntry->maFontSelData.mpFontData->GetSlant() == ITALIC_NORMAL || 7369cdf0e10cSrcweir m_pReferenceDevice->mpFontEntry->maFontSelData.mpFontData->GetSlant() == ITALIC_OBLIQUE ) 7370cdf0e10cSrcweir ) 7371cdf0e10cSrcweir { 7372cdf0e10cSrcweir fSkew = M_PI/12.0; 7373cdf0e10cSrcweir } 7374cdf0e10cSrcweir 7375cdf0e10cSrcweir // if the mapmode is distorted we need to adjust for that also 7376cdf0e10cSrcweir if( m_aCurrentPDFState.m_aMapMode.GetScaleX() != m_aCurrentPDFState.m_aMapMode.GetScaleY() ) 7377cdf0e10cSrcweir { 7378cdf0e10cSrcweir fXScale *= double(m_aCurrentPDFState.m_aMapMode.GetScaleX()) / double(m_aCurrentPDFState.m_aMapMode.GetScaleY()); 7379cdf0e10cSrcweir } 7380cdf0e10cSrcweir 7381cdf0e10cSrcweir int nAngle = m_aCurrentPDFState.m_aFont.GetOrientation(); 7382cdf0e10cSrcweir // normalize angles 7383cdf0e10cSrcweir while( nAngle < 0 ) 7384cdf0e10cSrcweir nAngle += 3600; 7385cdf0e10cSrcweir nAngle = nAngle % 3600; 7386cdf0e10cSrcweir double fAngle = (double)nAngle * M_PI / 1800.0; 7387cdf0e10cSrcweir 7388cdf0e10cSrcweir Matrix3 aRotScale; 7389cdf0e10cSrcweir aRotScale.scale( fXScale, 1.0 ); 7390cdf0e10cSrcweir if( fAngle != 0.0 ) 7391cdf0e10cSrcweir aRotScale.rotate( -fAngle ); 7392cdf0e10cSrcweir 7393cdf0e10cSrcweir bool bPop = false; 7394cdf0e10cSrcweir bool bABold = false; 7395cdf0e10cSrcweir // artificial bold necessary ? 7396cdf0e10cSrcweir if( m_pReferenceDevice->mpFontEntry->maFontSelData.mpFontData->GetWeight() <= WEIGHT_MEDIUM && 7397cdf0e10cSrcweir m_pReferenceDevice->mpFontEntry->maFontSelData.GetWeight() > WEIGHT_MEDIUM ) 7398cdf0e10cSrcweir { 7399cdf0e10cSrcweir if( ! bPop ) 7400cdf0e10cSrcweir aLine.append( "q " ); 7401cdf0e10cSrcweir bPop = true; 7402cdf0e10cSrcweir bABold = true; 7403cdf0e10cSrcweir } 7404cdf0e10cSrcweir // setup text colors (if necessary) 7405cdf0e10cSrcweir Color aStrokeColor( COL_TRANSPARENT ); 7406cdf0e10cSrcweir Color aNonStrokeColor( COL_TRANSPARENT ); 7407cdf0e10cSrcweir 7408cdf0e10cSrcweir if( m_aCurrentPDFState.m_aFont.IsOutline() ) 7409cdf0e10cSrcweir { 7410cdf0e10cSrcweir aStrokeColor = m_aCurrentPDFState.m_aFont.GetColor(); 7411cdf0e10cSrcweir aNonStrokeColor = Color( COL_WHITE ); 7412cdf0e10cSrcweir } 7413cdf0e10cSrcweir else 7414cdf0e10cSrcweir aNonStrokeColor = m_aCurrentPDFState.m_aFont.GetColor(); 7415cdf0e10cSrcweir if( bABold ) 7416cdf0e10cSrcweir aStrokeColor = m_aCurrentPDFState.m_aFont.GetColor(); 7417cdf0e10cSrcweir 7418cdf0e10cSrcweir if( aStrokeColor != Color( COL_TRANSPARENT ) && aStrokeColor != m_aCurrentPDFState.m_aLineColor ) 7419cdf0e10cSrcweir { 7420cdf0e10cSrcweir if( ! bPop ) 7421cdf0e10cSrcweir aLine.append( "q " ); 7422cdf0e10cSrcweir bPop = true; 7423cdf0e10cSrcweir appendStrokingColor( aStrokeColor, aLine ); 7424cdf0e10cSrcweir aLine.append( "\n" ); 7425cdf0e10cSrcweir } 7426cdf0e10cSrcweir if( aNonStrokeColor != Color( COL_TRANSPARENT ) && aNonStrokeColor != m_aCurrentPDFState.m_aFillColor ) 7427cdf0e10cSrcweir { 7428cdf0e10cSrcweir if( ! bPop ) 7429cdf0e10cSrcweir aLine.append( "q " ); 7430cdf0e10cSrcweir bPop = true; 7431cdf0e10cSrcweir appendNonStrokingColor( aNonStrokeColor, aLine ); 7432cdf0e10cSrcweir aLine.append( "\n" ); 7433cdf0e10cSrcweir } 7434cdf0e10cSrcweir 7435cdf0e10cSrcweir // begin text object 7436cdf0e10cSrcweir aLine.append( "BT\n" ); 7437cdf0e10cSrcweir // outline attribute ? 7438cdf0e10cSrcweir if( m_aCurrentPDFState.m_aFont.IsOutline() || bABold ) 7439cdf0e10cSrcweir { 7440cdf0e10cSrcweir // set correct text mode, set stroke width 7441cdf0e10cSrcweir aLine.append( "2 Tr " ); // fill, then stroke 7442cdf0e10cSrcweir 7443cdf0e10cSrcweir if( m_aCurrentPDFState.m_aFont.IsOutline() ) 7444cdf0e10cSrcweir { 7445cdf0e10cSrcweir // unclear what to do in case of outline and artificial bold 7446cdf0e10cSrcweir // for the time being outline wins 7447cdf0e10cSrcweir aLine.append( "0.25 w \n" ); 7448cdf0e10cSrcweir } 7449cdf0e10cSrcweir else 7450cdf0e10cSrcweir { 7451cdf0e10cSrcweir double fW = (double)m_aCurrentPDFState.m_aFont.GetHeight() / 30.0; 7452cdf0e10cSrcweir m_aPages.back().appendMappedLength( fW, aLine ); 7453cdf0e10cSrcweir aLine.append ( " w\n" ); 7454cdf0e10cSrcweir } 7455cdf0e10cSrcweir } 7456cdf0e10cSrcweir 7457cdf0e10cSrcweir FontMetric aRefDevFontMetric = m_pReferenceDevice->GetFontMetric(); 7458cdf0e10cSrcweir 7459cdf0e10cSrcweir // collect the glyphs into a single array 7460cdf0e10cSrcweir const int nTmpMaxGlyphs = rLayout.GetOrientation() ? 1 : nMaxGlyphs; // #i97991# temporary workaround for #i87686# 7461cdf0e10cSrcweir std::vector< PDFGlyph > aGlyphs; 7462cdf0e10cSrcweir aGlyphs.reserve( nTmpMaxGlyphs ); 7463cdf0e10cSrcweir // first get all the glyphs and register them; coordinates still in Pixel 7464cdf0e10cSrcweir Point aGNGlyphPos; 7465cdf0e10cSrcweir while( (nGlyphs = rLayout.GetNextGlyphs( nTmpMaxGlyphs, pGlyphs, aGNGlyphPos, nIndex, nAdvanceWidths, pCharPosAry )) != 0 ) 7466cdf0e10cSrcweir { 7467cdf0e10cSrcweir aUnicodes.clear(); 7468cdf0e10cSrcweir for( int i = 0; i < nGlyphs; i++ ) 7469cdf0e10cSrcweir { 7470cdf0e10cSrcweir pFallbackFonts[i] = rLayout.GetFallbackFontData( pGlyphs[i] ); 7471cdf0e10cSrcweir 7472cdf0e10cSrcweir // default case: 1 glyph is one unicode 7473cdf0e10cSrcweir pUnicodesPerGlyph[i] = 1; 7474cdf0e10cSrcweir if( (pGlyphs[i] & GF_ISCHAR) ) 7475cdf0e10cSrcweir { 7476cdf0e10cSrcweir aUnicodes.push_back( static_cast<sal_Ucs>(pGlyphs[i] & GF_IDXMASK) ); 7477cdf0e10cSrcweir } 7478cdf0e10cSrcweir else if( pCharPosAry[i] >= nMinCharPos && pCharPosAry[i] <= nMaxCharPos ) 7479cdf0e10cSrcweir { 7480cdf0e10cSrcweir int nChars = 1; 7481cdf0e10cSrcweir aUnicodes.push_back( rText.GetChar( sal::static_int_cast<xub_StrLen>(pCharPosAry[i]) ) ); 7482cdf0e10cSrcweir pUnicodesPerGlyph[i] = 1; 7483cdf0e10cSrcweir // try to handle ligatures and such 7484cdf0e10cSrcweir if( i < nGlyphs-1 ) 7485cdf0e10cSrcweir { 7486cdf0e10cSrcweir nChars = pCharPosAry[i+1] - pCharPosAry[i]; 7487cdf0e10cSrcweir // #i115618# fix for simple RTL+CTL cases 7488cdf0e10cSrcweir // TODO: sanitize for RTL ligatures, more complex CTL, etc. 7489cdf0e10cSrcweir if( nChars < 0 ) 7490cdf0e10cSrcweir nChars = -nChars; 7491cdf0e10cSrcweir else if( nChars == 0 ) 7492cdf0e10cSrcweir nChars = 1; 7493cdf0e10cSrcweir pUnicodesPerGlyph[i] = nChars; 7494cdf0e10cSrcweir for( int n = 1; n < nChars; n++ ) 7495cdf0e10cSrcweir aUnicodes.push_back( rText.GetChar( sal::static_int_cast<xub_StrLen>(pCharPosAry[i]+n) ) ); 7496cdf0e10cSrcweir } 7497cdf0e10cSrcweir // #i36691# hack that is needed because currently the pGlyphs[] 7498cdf0e10cSrcweir // argument is ignored for embeddable fonts and so the layout 7499cdf0e10cSrcweir // engine's glyph work is ignored (i.e. char mirroring) 7500cdf0e10cSrcweir // TODO: a real solution would be to map the layout engine's 7501cdf0e10cSrcweir // glyphid (i.e. FreeType's synthetic glyphid for a Type1 font) 7502cdf0e10cSrcweir // back to unicode and then to embeddable font's encoding 7503cdf0e10cSrcweir if( getReferenceDevice()->GetLayoutMode() & TEXT_LAYOUT_BIDI_RTL ) 7504cdf0e10cSrcweir { 7505cdf0e10cSrcweir size_t nI = aUnicodes.size()-1; 7506cdf0e10cSrcweir for( int n = 0; n < nChars; n++, nI-- ) 7507cdf0e10cSrcweir aUnicodes[nI] = static_cast<sal_Ucs>(GetMirroredChar(aUnicodes[nI])); 7508cdf0e10cSrcweir } 7509cdf0e10cSrcweir } 7510cdf0e10cSrcweir else 7511cdf0e10cSrcweir aUnicodes.push_back( 0 ); 7512cdf0e10cSrcweir // note: in case of ctl one character may result 7513cdf0e10cSrcweir // in multiple glyphs. The current SalLayout 7514cdf0e10cSrcweir // implementations set -1 then to indicate that no direct 7515cdf0e10cSrcweir // mapping is possible 7516cdf0e10cSrcweir } 7517cdf0e10cSrcweir 7518cdf0e10cSrcweir registerGlyphs( nGlyphs, pGlyphs, pGlyphWidths, &aUnicodes[0], pUnicodesPerGlyph, pMappedGlyphs, pMappedFontObjects, pFallbackFonts ); 7519cdf0e10cSrcweir 7520cdf0e10cSrcweir for( int i = 0; i < nGlyphs; i++ ) 7521cdf0e10cSrcweir { 7522cdf0e10cSrcweir aGlyphs.push_back( PDFGlyph( aGNGlyphPos, 7523cdf0e10cSrcweir pGlyphWidths[i], 7524cdf0e10cSrcweir pGlyphs[i], 7525cdf0e10cSrcweir pMappedFontObjects[i], 7526cdf0e10cSrcweir pMappedGlyphs[i] ) ); 7527cdf0e10cSrcweir if( bVertical ) 7528cdf0e10cSrcweir aGNGlyphPos.Y() += nAdvanceWidths[i]/rLayout.GetUnitsPerPixel(); 7529cdf0e10cSrcweir else 7530cdf0e10cSrcweir aGNGlyphPos.X() += nAdvanceWidths[i]/rLayout.GetUnitsPerPixel(); 7531cdf0e10cSrcweir } 7532cdf0e10cSrcweir } 7533cdf0e10cSrcweir 7534cdf0e10cSrcweir Point aAlignOffset; 7535cdf0e10cSrcweir if ( eAlign == ALIGN_BOTTOM ) 7536cdf0e10cSrcweir aAlignOffset.Y() -= aRefDevFontMetric.GetDescent(); 7537cdf0e10cSrcweir else if ( eAlign == ALIGN_TOP ) 7538cdf0e10cSrcweir aAlignOffset.Y() += aRefDevFontMetric.GetAscent(); 7539cdf0e10cSrcweir if( aAlignOffset.X() || aAlignOffset.Y() ) 7540cdf0e10cSrcweir aAlignOffset = aRotScale.transform( aAlignOffset ); 7541cdf0e10cSrcweir 7542cdf0e10cSrcweir /* #159153# do not emit an empty glyph vector; this can happen if e.g. the original 7543cdf0e10cSrcweir string contained only on of the UTF16 BOMs 7544cdf0e10cSrcweir */ 7545cdf0e10cSrcweir if( ! aGlyphs.empty() ) 7546cdf0e10cSrcweir { 7547cdf0e10cSrcweir if( bVertical ) 7548cdf0e10cSrcweir drawVerticalGlyphs( aGlyphs, aLine, aAlignOffset, aRotScale, fAngle, fXScale, fSkew, nFontHeight ); 7549cdf0e10cSrcweir else 7550cdf0e10cSrcweir drawHorizontalGlyphs( aGlyphs, aLine, aAlignOffset, fAngle, fXScale, fSkew, nFontHeight, nPixelFontHeight ); 7551cdf0e10cSrcweir } 7552cdf0e10cSrcweir 7553cdf0e10cSrcweir // end textobject 7554cdf0e10cSrcweir aLine.append( "ET\n" ); 7555cdf0e10cSrcweir if( bPop ) 7556cdf0e10cSrcweir aLine.append( "Q\n" ); 7557cdf0e10cSrcweir 7558cdf0e10cSrcweir writeBuffer( aLine.getStr(), aLine.getLength() ); 7559cdf0e10cSrcweir 7560cdf0e10cSrcweir // draw eventual textlines 7561cdf0e10cSrcweir FontStrikeout eStrikeout = m_aCurrentPDFState.m_aFont.GetStrikeout(); 7562cdf0e10cSrcweir FontUnderline eUnderline = m_aCurrentPDFState.m_aFont.GetUnderline(); 7563cdf0e10cSrcweir FontUnderline eOverline = m_aCurrentPDFState.m_aFont.GetOverline(); 7564cdf0e10cSrcweir if( bTextLines && 7565cdf0e10cSrcweir ( 7566cdf0e10cSrcweir ( eUnderline != UNDERLINE_NONE && eUnderline != UNDERLINE_DONTKNOW ) || 7567cdf0e10cSrcweir ( eOverline != UNDERLINE_NONE && eOverline != UNDERLINE_DONTKNOW ) || 7568cdf0e10cSrcweir ( eStrikeout != STRIKEOUT_NONE && eStrikeout != STRIKEOUT_DONTKNOW ) 7569cdf0e10cSrcweir ) 7570cdf0e10cSrcweir ) 7571cdf0e10cSrcweir { 7572cdf0e10cSrcweir sal_Bool bUnderlineAbove = OutputDevice::ImplIsUnderlineAbove( m_aCurrentPDFState.m_aFont ); 7573cdf0e10cSrcweir if( m_aCurrentPDFState.m_aFont.IsWordLineMode() ) 7574cdf0e10cSrcweir { 7575cdf0e10cSrcweir Point aPos, aStartPt; 7576cdf0e10cSrcweir sal_Int32 nWidth = 0, nAdvance=0; 7577cdf0e10cSrcweir for( int nStart = 0;;) 7578cdf0e10cSrcweir { 7579cdf0e10cSrcweir sal_GlyphId nGlyphIndex; 7580cdf0e10cSrcweir if( !rLayout.GetNextGlyphs( 1, &nGlyphIndex, aPos, nStart, &nAdvance ) ) 7581cdf0e10cSrcweir break; 7582cdf0e10cSrcweir 7583cdf0e10cSrcweir if( !rLayout.IsSpacingGlyph( nGlyphIndex ) ) 7584cdf0e10cSrcweir { 7585cdf0e10cSrcweir if( !nWidth ) 7586cdf0e10cSrcweir aStartPt = aPos; 7587cdf0e10cSrcweir 7588cdf0e10cSrcweir nWidth += nAdvance; 7589cdf0e10cSrcweir } 7590cdf0e10cSrcweir else if( nWidth > 0 ) 7591cdf0e10cSrcweir { 7592cdf0e10cSrcweir drawTextLine( m_pReferenceDevice->PixelToLogic( aStartPt ), 7593cdf0e10cSrcweir m_pReferenceDevice->ImplDevicePixelToLogicWidth( nWidth ), 7594cdf0e10cSrcweir eStrikeout, eUnderline, eOverline, bUnderlineAbove ); 7595cdf0e10cSrcweir nWidth = 0; 7596cdf0e10cSrcweir } 7597cdf0e10cSrcweir } 7598cdf0e10cSrcweir 7599cdf0e10cSrcweir if( nWidth > 0 ) 7600cdf0e10cSrcweir { 7601cdf0e10cSrcweir drawTextLine( m_pReferenceDevice->PixelToLogic( aStartPt ), 7602cdf0e10cSrcweir m_pReferenceDevice->ImplDevicePixelToLogicWidth( nWidth ), 7603cdf0e10cSrcweir eStrikeout, eUnderline, eOverline, bUnderlineAbove ); 7604cdf0e10cSrcweir } 7605cdf0e10cSrcweir } 7606cdf0e10cSrcweir else 7607cdf0e10cSrcweir { 7608cdf0e10cSrcweir Point aStartPt = rLayout.GetDrawPosition(); 7609cdf0e10cSrcweir int nWidth = rLayout.GetTextWidth() / rLayout.GetUnitsPerPixel(); 7610cdf0e10cSrcweir drawTextLine( m_pReferenceDevice->PixelToLogic( aStartPt ), 7611cdf0e10cSrcweir m_pReferenceDevice->ImplDevicePixelToLogicWidth( nWidth ), 7612cdf0e10cSrcweir eStrikeout, eUnderline, eOverline, bUnderlineAbove ); 7613cdf0e10cSrcweir } 7614cdf0e10cSrcweir } 7615cdf0e10cSrcweir 7616cdf0e10cSrcweir // write eventual emphasis marks 7617cdf0e10cSrcweir if( m_aCurrentPDFState.m_aFont.GetEmphasisMark() & EMPHASISMARK_STYLE ) 7618cdf0e10cSrcweir { 7619cdf0e10cSrcweir PolyPolygon aEmphPoly; 7620cdf0e10cSrcweir Rectangle aEmphRect1; 7621cdf0e10cSrcweir Rectangle aEmphRect2; 7622cdf0e10cSrcweir long nEmphYOff; 7623cdf0e10cSrcweir long nEmphWidth; 7624cdf0e10cSrcweir long nEmphHeight; 7625cdf0e10cSrcweir sal_Bool bEmphPolyLine; 7626cdf0e10cSrcweir FontEmphasisMark nEmphMark; 7627cdf0e10cSrcweir 7628cdf0e10cSrcweir push( PUSH_ALL ); 7629cdf0e10cSrcweir 7630cdf0e10cSrcweir aLine.setLength( 0 ); 7631cdf0e10cSrcweir aLine.append( "q\n" ); 7632cdf0e10cSrcweir 7633cdf0e10cSrcweir nEmphMark = m_pReferenceDevice->ImplGetEmphasisMarkStyle( m_aCurrentPDFState.m_aFont ); 7634cdf0e10cSrcweir if ( nEmphMark & EMPHASISMARK_POS_BELOW ) 7635cdf0e10cSrcweir nEmphHeight = m_pReferenceDevice->mnEmphasisDescent; 7636cdf0e10cSrcweir else 7637cdf0e10cSrcweir nEmphHeight = m_pReferenceDevice->mnEmphasisAscent; 7638cdf0e10cSrcweir m_pReferenceDevice->ImplGetEmphasisMark( aEmphPoly, 7639cdf0e10cSrcweir bEmphPolyLine, 7640cdf0e10cSrcweir aEmphRect1, 7641cdf0e10cSrcweir aEmphRect2, 7642cdf0e10cSrcweir nEmphYOff, 7643cdf0e10cSrcweir nEmphWidth, 7644cdf0e10cSrcweir nEmphMark, 7645cdf0e10cSrcweir m_pReferenceDevice->ImplDevicePixelToLogicWidth(nEmphHeight), 7646cdf0e10cSrcweir m_pReferenceDevice->mpFontEntry->mnOrientation ); 7647cdf0e10cSrcweir if ( bEmphPolyLine ) 7648cdf0e10cSrcweir { 7649cdf0e10cSrcweir setLineColor( m_aCurrentPDFState.m_aFont.GetColor() ); 7650cdf0e10cSrcweir setFillColor( Color( COL_TRANSPARENT ) ); 7651cdf0e10cSrcweir } 7652cdf0e10cSrcweir else 7653cdf0e10cSrcweir { 7654cdf0e10cSrcweir setFillColor( m_aCurrentPDFState.m_aFont.GetColor() ); 7655cdf0e10cSrcweir setLineColor( Color( COL_TRANSPARENT ) ); 7656cdf0e10cSrcweir } 7657cdf0e10cSrcweir writeBuffer( aLine.getStr(), aLine.getLength() ); 7658cdf0e10cSrcweir 7659cdf0e10cSrcweir Point aOffset = Point(0,0); 7660cdf0e10cSrcweir 7661cdf0e10cSrcweir if ( nEmphMark & EMPHASISMARK_POS_BELOW ) 7662cdf0e10cSrcweir aOffset.Y() += m_pReferenceDevice->mpFontEntry->maMetric.mnDescent + nEmphYOff; 7663cdf0e10cSrcweir else 7664cdf0e10cSrcweir aOffset.Y() -= m_pReferenceDevice->mpFontEntry->maMetric.mnAscent + nEmphYOff; 7665cdf0e10cSrcweir 7666cdf0e10cSrcweir long nEmphWidth2 = nEmphWidth / 2; 7667cdf0e10cSrcweir long nEmphHeight2 = nEmphHeight / 2; 7668cdf0e10cSrcweir aOffset += Point( nEmphWidth2, nEmphHeight2 ); 7669cdf0e10cSrcweir 7670cdf0e10cSrcweir if ( eAlign == ALIGN_BOTTOM ) 7671cdf0e10cSrcweir aOffset.Y() -= m_pReferenceDevice->mpFontEntry->maMetric.mnDescent; 7672cdf0e10cSrcweir else if ( eAlign == ALIGN_TOP ) 7673cdf0e10cSrcweir aOffset.Y() += m_pReferenceDevice->mpFontEntry->maMetric.mnAscent; 7674cdf0e10cSrcweir 7675cdf0e10cSrcweir for( int nStart = 0;;) 7676cdf0e10cSrcweir { 7677cdf0e10cSrcweir Point aPos; 7678cdf0e10cSrcweir sal_GlyphId nGlyphIndex; 7679cdf0e10cSrcweir sal_Int32 nAdvance; 7680cdf0e10cSrcweir if( !rLayout.GetNextGlyphs( 1, &nGlyphIndex, aPos, nStart, &nAdvance ) ) 7681cdf0e10cSrcweir break; 7682cdf0e10cSrcweir 7683cdf0e10cSrcweir if( !rLayout.IsSpacingGlyph( nGlyphIndex ) ) 7684cdf0e10cSrcweir { 7685cdf0e10cSrcweir Point aAdjOffset = aOffset; 7686cdf0e10cSrcweir aAdjOffset.X() += (nAdvance - nEmphWidth) / 2; 7687cdf0e10cSrcweir aAdjOffset = aRotScale.transform( aAdjOffset ); 7688cdf0e10cSrcweir 7689cdf0e10cSrcweir aAdjOffset -= Point( nEmphWidth2, nEmphHeight2 ); 7690cdf0e10cSrcweir 7691cdf0e10cSrcweir aPos += aAdjOffset; 7692cdf0e10cSrcweir aPos = m_pReferenceDevice->PixelToLogic( aPos ); 7693cdf0e10cSrcweir drawEmphasisMark( aPos.X(), aPos.Y(), 7694cdf0e10cSrcweir aEmphPoly, bEmphPolyLine, 7695cdf0e10cSrcweir aEmphRect1, aEmphRect2 ); 7696cdf0e10cSrcweir } 7697cdf0e10cSrcweir } 7698cdf0e10cSrcweir 7699cdf0e10cSrcweir writeBuffer( "Q\n", 2 ); 7700cdf0e10cSrcweir pop(); 7701cdf0e10cSrcweir } 7702cdf0e10cSrcweir 7703cdf0e10cSrcweir } 7704cdf0e10cSrcweir 7705cdf0e10cSrcweir void PDFWriterImpl::drawEmphasisMark( long nX, long nY, 7706cdf0e10cSrcweir const PolyPolygon& rPolyPoly, sal_Bool bPolyLine, 7707cdf0e10cSrcweir const Rectangle& rRect1, const Rectangle& rRect2 ) 7708cdf0e10cSrcweir { 7709cdf0e10cSrcweir // TODO: pass nWidth as width of this mark 7710cdf0e10cSrcweir // long nWidth = 0; 7711cdf0e10cSrcweir 7712cdf0e10cSrcweir if ( rPolyPoly.Count() ) 7713cdf0e10cSrcweir { 7714cdf0e10cSrcweir if ( bPolyLine ) 7715cdf0e10cSrcweir { 7716cdf0e10cSrcweir Polygon aPoly = rPolyPoly.GetObject( 0 ); 7717cdf0e10cSrcweir aPoly.Move( nX, nY ); 7718cdf0e10cSrcweir drawPolyLine( aPoly ); 7719cdf0e10cSrcweir } 7720cdf0e10cSrcweir else 7721cdf0e10cSrcweir { 7722cdf0e10cSrcweir PolyPolygon aPolyPoly = rPolyPoly; 7723cdf0e10cSrcweir aPolyPoly.Move( nX, nY ); 7724cdf0e10cSrcweir drawPolyPolygon( aPolyPoly ); 7725cdf0e10cSrcweir } 7726cdf0e10cSrcweir } 7727cdf0e10cSrcweir 7728cdf0e10cSrcweir if ( !rRect1.IsEmpty() ) 7729cdf0e10cSrcweir { 7730cdf0e10cSrcweir Rectangle aRect( Point( nX+rRect1.Left(), 7731cdf0e10cSrcweir nY+rRect1.Top() ), rRect1.GetSize() ); 7732cdf0e10cSrcweir drawRectangle( aRect ); 7733cdf0e10cSrcweir } 7734cdf0e10cSrcweir 7735cdf0e10cSrcweir if ( !rRect2.IsEmpty() ) 7736cdf0e10cSrcweir { 7737cdf0e10cSrcweir Rectangle aRect( Point( nX+rRect2.Left(), 7738cdf0e10cSrcweir nY+rRect2.Top() ), rRect2.GetSize() ); 7739cdf0e10cSrcweir 7740cdf0e10cSrcweir drawRectangle( aRect ); 7741cdf0e10cSrcweir } 7742cdf0e10cSrcweir } 7743cdf0e10cSrcweir 7744cdf0e10cSrcweir void PDFWriterImpl::drawText( const Point& rPos, const String& rText, xub_StrLen nIndex, xub_StrLen nLen, bool bTextLines ) 7745cdf0e10cSrcweir { 7746cdf0e10cSrcweir MARK( "drawText" ); 7747cdf0e10cSrcweir 7748cdf0e10cSrcweir updateGraphicsState(); 7749cdf0e10cSrcweir 7750cdf0e10cSrcweir // get a layout from the OuputDevice's SalGraphics 7751cdf0e10cSrcweir // this also enforces font substitution and sets the font on SalGraphics 7752cdf0e10cSrcweir SalLayout* pLayout = m_pReferenceDevice->ImplLayout( rText, nIndex, nLen, rPos ); 7753cdf0e10cSrcweir if( pLayout ) 7754cdf0e10cSrcweir { 7755cdf0e10cSrcweir drawLayout( *pLayout, rText, bTextLines ); 7756cdf0e10cSrcweir pLayout->Release(); 7757cdf0e10cSrcweir } 7758cdf0e10cSrcweir } 7759cdf0e10cSrcweir 7760cdf0e10cSrcweir void PDFWriterImpl::drawTextArray( const Point& rPos, const String& rText, const sal_Int32* pDXArray, xub_StrLen nIndex, xub_StrLen nLen, bool bTextLines ) 7761cdf0e10cSrcweir { 7762cdf0e10cSrcweir MARK( "drawText with array" ); 7763cdf0e10cSrcweir 7764cdf0e10cSrcweir updateGraphicsState(); 7765cdf0e10cSrcweir 7766cdf0e10cSrcweir // get a layout from the OuputDevice's SalGraphics 7767cdf0e10cSrcweir // this also enforces font substitution and sets the font on SalGraphics 7768cdf0e10cSrcweir SalLayout* pLayout = m_pReferenceDevice->ImplLayout( rText, nIndex, nLen, rPos, 0, pDXArray ); 7769cdf0e10cSrcweir if( pLayout ) 7770cdf0e10cSrcweir { 7771cdf0e10cSrcweir drawLayout( *pLayout, rText, bTextLines ); 7772cdf0e10cSrcweir pLayout->Release(); 7773cdf0e10cSrcweir } 7774cdf0e10cSrcweir } 7775cdf0e10cSrcweir 7776cdf0e10cSrcweir void PDFWriterImpl::drawStretchText( const Point& rPos, sal_uLong nWidth, const String& rText, xub_StrLen nIndex, xub_StrLen nLen, bool bTextLines ) 7777cdf0e10cSrcweir { 7778cdf0e10cSrcweir MARK( "drawStretchText" ); 7779cdf0e10cSrcweir 7780cdf0e10cSrcweir updateGraphicsState(); 7781cdf0e10cSrcweir 7782cdf0e10cSrcweir // get a layout from the OuputDevice's SalGraphics 7783cdf0e10cSrcweir // this also enforces font substitution and sets the font on SalGraphics 7784cdf0e10cSrcweir SalLayout* pLayout = m_pReferenceDevice->ImplLayout( rText, nIndex, nLen, rPos, nWidth ); 7785cdf0e10cSrcweir if( pLayout ) 7786cdf0e10cSrcweir { 7787cdf0e10cSrcweir drawLayout( *pLayout, rText, bTextLines ); 7788cdf0e10cSrcweir pLayout->Release(); 7789cdf0e10cSrcweir } 7790cdf0e10cSrcweir } 7791cdf0e10cSrcweir 7792cdf0e10cSrcweir void PDFWriterImpl::drawText( const Rectangle& rRect, const String& rOrigStr, sal_uInt16 nStyle, bool bTextLines ) 7793cdf0e10cSrcweir { 7794cdf0e10cSrcweir long nWidth = rRect.GetWidth(); 7795cdf0e10cSrcweir long nHeight = rRect.GetHeight(); 7796cdf0e10cSrcweir 7797cdf0e10cSrcweir if ( nWidth <= 0 || nHeight <= 0 ) 7798cdf0e10cSrcweir return; 7799cdf0e10cSrcweir 7800cdf0e10cSrcweir MARK( "drawText with rectangle" ); 7801cdf0e10cSrcweir 7802cdf0e10cSrcweir updateGraphicsState(); 7803cdf0e10cSrcweir 7804cdf0e10cSrcweir // clip with rectangle 7805cdf0e10cSrcweir OStringBuffer aLine; 7806cdf0e10cSrcweir aLine.append( "q " ); 7807cdf0e10cSrcweir m_aPages.back().appendRect( rRect, aLine ); 7808cdf0e10cSrcweir aLine.append( " W* n\n" ); 7809cdf0e10cSrcweir writeBuffer( aLine.getStr(), aLine.getLength() ); 7810cdf0e10cSrcweir 7811cdf0e10cSrcweir // if disabled text is needed, put in here 7812cdf0e10cSrcweir 7813cdf0e10cSrcweir Point aPos = rRect.TopLeft(); 7814cdf0e10cSrcweir 7815cdf0e10cSrcweir long nTextHeight = m_pReferenceDevice->GetTextHeight(); 7816cdf0e10cSrcweir xub_StrLen nMnemonicPos = STRING_NOTFOUND; 7817cdf0e10cSrcweir 7818cdf0e10cSrcweir String aStr = rOrigStr; 7819cdf0e10cSrcweir if ( nStyle & TEXT_DRAW_MNEMONIC ) 7820cdf0e10cSrcweir aStr = m_pReferenceDevice->GetNonMnemonicString( aStr, nMnemonicPos ); 7821cdf0e10cSrcweir 7822cdf0e10cSrcweir // multiline text 7823cdf0e10cSrcweir if ( nStyle & TEXT_DRAW_MULTILINE ) 7824cdf0e10cSrcweir { 7825cdf0e10cSrcweir XubString aLastLine; 7826cdf0e10cSrcweir ImplMultiTextLineInfo aMultiLineInfo; 7827cdf0e10cSrcweir ImplTextLineInfo* pLineInfo; 7828cdf0e10cSrcweir long nMaxTextWidth; 7829cdf0e10cSrcweir xub_StrLen i; 7830cdf0e10cSrcweir xub_StrLen nLines; 7831cdf0e10cSrcweir xub_StrLen nFormatLines; 7832cdf0e10cSrcweir 7833cdf0e10cSrcweir if ( nTextHeight ) 7834cdf0e10cSrcweir { 7835cdf0e10cSrcweir ::vcl::DefaultTextLayout aLayout( *m_pReferenceDevice ); 7836cdf0e10cSrcweir nMaxTextWidth = OutputDevice::ImplGetTextLines( aMultiLineInfo, nWidth, aStr, nStyle, aLayout ); 7837cdf0e10cSrcweir nLines = (xub_StrLen)(nHeight/nTextHeight); 7838cdf0e10cSrcweir nFormatLines = aMultiLineInfo.Count(); 7839cdf0e10cSrcweir if ( !nLines ) 7840cdf0e10cSrcweir nLines = 1; 7841cdf0e10cSrcweir if ( nFormatLines > nLines ) 7842cdf0e10cSrcweir { 7843cdf0e10cSrcweir if ( nStyle & TEXT_DRAW_ENDELLIPSIS ) 7844cdf0e10cSrcweir { 7845cdf0e10cSrcweir // handle last line 7846cdf0e10cSrcweir nFormatLines = nLines-1; 7847cdf0e10cSrcweir 7848cdf0e10cSrcweir pLineInfo = aMultiLineInfo.GetLine( nFormatLines ); 7849cdf0e10cSrcweir aLastLine = aStr.Copy( pLineInfo->GetIndex() ); 7850cdf0e10cSrcweir aLastLine.ConvertLineEnd( LINEEND_LF ); 7851cdf0e10cSrcweir // replace line feed by space 7852cdf0e10cSrcweir xub_StrLen nLastLineLen = aLastLine.Len(); 7853cdf0e10cSrcweir for ( i = 0; i < nLastLineLen; i++ ) 7854cdf0e10cSrcweir { 7855cdf0e10cSrcweir if ( aLastLine.GetChar( i ) == _LF ) 7856cdf0e10cSrcweir aLastLine.SetChar( i, ' ' ); 7857cdf0e10cSrcweir } 7858cdf0e10cSrcweir aLastLine = m_pReferenceDevice->GetEllipsisString( aLastLine, nWidth, nStyle ); 7859cdf0e10cSrcweir nStyle &= ~(TEXT_DRAW_VCENTER | TEXT_DRAW_BOTTOM); 7860cdf0e10cSrcweir nStyle |= TEXT_DRAW_TOP; 7861cdf0e10cSrcweir } 7862cdf0e10cSrcweir } 7863cdf0e10cSrcweir 7864cdf0e10cSrcweir // vertical alignment 7865cdf0e10cSrcweir if ( nStyle & TEXT_DRAW_BOTTOM ) 7866cdf0e10cSrcweir aPos.Y() += nHeight-(nFormatLines*nTextHeight); 7867cdf0e10cSrcweir else if ( nStyle & TEXT_DRAW_VCENTER ) 7868cdf0e10cSrcweir aPos.Y() += (nHeight-(nFormatLines*nTextHeight))/2; 7869cdf0e10cSrcweir 7870cdf0e10cSrcweir // draw all lines excluding the last 7871cdf0e10cSrcweir for ( i = 0; i < nFormatLines; i++ ) 7872cdf0e10cSrcweir { 7873cdf0e10cSrcweir pLineInfo = aMultiLineInfo.GetLine( i ); 7874cdf0e10cSrcweir if ( nStyle & TEXT_DRAW_RIGHT ) 7875cdf0e10cSrcweir aPos.X() += nWidth-pLineInfo->GetWidth(); 7876cdf0e10cSrcweir else if ( nStyle & TEXT_DRAW_CENTER ) 7877cdf0e10cSrcweir aPos.X() += (nWidth-pLineInfo->GetWidth())/2; 7878cdf0e10cSrcweir xub_StrLen nIndex = pLineInfo->GetIndex(); 7879cdf0e10cSrcweir xub_StrLen nLineLen = pLineInfo->GetLen(); 7880cdf0e10cSrcweir drawText( aPos, aStr, nIndex, nLineLen, bTextLines ); 7881cdf0e10cSrcweir // mnemonics should not appear in documents, 7882cdf0e10cSrcweir // if the need arises, put them in here 7883cdf0e10cSrcweir aPos.Y() += nTextHeight; 7884cdf0e10cSrcweir aPos.X() = rRect.Left(); 7885cdf0e10cSrcweir } 7886cdf0e10cSrcweir 7887cdf0e10cSrcweir 7888cdf0e10cSrcweir // output last line left adjusted since it was shortened 7889cdf0e10cSrcweir if ( aLastLine.Len() ) 7890cdf0e10cSrcweir drawText( aPos, aLastLine, 0, STRING_LEN, bTextLines ); 7891cdf0e10cSrcweir } 7892cdf0e10cSrcweir } 7893cdf0e10cSrcweir else 7894cdf0e10cSrcweir { 7895cdf0e10cSrcweir long nTextWidth = m_pReferenceDevice->GetTextWidth( aStr ); 7896cdf0e10cSrcweir 7897cdf0e10cSrcweir // Evt. Text kuerzen 7898cdf0e10cSrcweir if ( nTextWidth > nWidth ) 7899cdf0e10cSrcweir { 7900cdf0e10cSrcweir if ( nStyle & (TEXT_DRAW_ENDELLIPSIS | TEXT_DRAW_PATHELLIPSIS | TEXT_DRAW_NEWSELLIPSIS) ) 7901cdf0e10cSrcweir { 7902cdf0e10cSrcweir aStr = m_pReferenceDevice->GetEllipsisString( aStr, nWidth, nStyle ); 7903cdf0e10cSrcweir nStyle &= ~(TEXT_DRAW_CENTER | TEXT_DRAW_RIGHT); 7904cdf0e10cSrcweir nStyle |= TEXT_DRAW_LEFT; 7905cdf0e10cSrcweir nTextWidth = m_pReferenceDevice->GetTextWidth( aStr ); 7906cdf0e10cSrcweir } 7907cdf0e10cSrcweir } 7908cdf0e10cSrcweir 7909cdf0e10cSrcweir // vertical alignment 7910cdf0e10cSrcweir if ( nStyle & TEXT_DRAW_RIGHT ) 7911cdf0e10cSrcweir aPos.X() += nWidth-nTextWidth; 7912cdf0e10cSrcweir else if ( nStyle & TEXT_DRAW_CENTER ) 7913cdf0e10cSrcweir aPos.X() += (nWidth-nTextWidth)/2; 7914cdf0e10cSrcweir 7915cdf0e10cSrcweir if ( nStyle & TEXT_DRAW_BOTTOM ) 7916cdf0e10cSrcweir aPos.Y() += nHeight-nTextHeight; 7917cdf0e10cSrcweir else if ( nStyle & TEXT_DRAW_VCENTER ) 7918cdf0e10cSrcweir aPos.Y() += (nHeight-nTextHeight)/2; 7919cdf0e10cSrcweir 7920cdf0e10cSrcweir // mnemonics should be inserted here if the need arises 7921cdf0e10cSrcweir 7922cdf0e10cSrcweir // draw the actual text 7923cdf0e10cSrcweir drawText( aPos, aStr, 0, STRING_LEN, bTextLines ); 7924cdf0e10cSrcweir } 7925cdf0e10cSrcweir 7926cdf0e10cSrcweir // reset clip region to original value 7927cdf0e10cSrcweir aLine.setLength( 0 ); 7928cdf0e10cSrcweir aLine.append( "Q\n" ); 7929cdf0e10cSrcweir writeBuffer( aLine.getStr(), aLine.getLength() ); 7930cdf0e10cSrcweir } 7931cdf0e10cSrcweir 7932cdf0e10cSrcweir void PDFWriterImpl::drawLine( const Point& rStart, const Point& rStop ) 7933cdf0e10cSrcweir { 7934cdf0e10cSrcweir MARK( "drawLine" ); 7935cdf0e10cSrcweir 7936cdf0e10cSrcweir updateGraphicsState(); 7937cdf0e10cSrcweir 7938cdf0e10cSrcweir if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) ) 7939cdf0e10cSrcweir return; 7940cdf0e10cSrcweir 7941cdf0e10cSrcweir OStringBuffer aLine; 7942cdf0e10cSrcweir m_aPages.back().appendPoint( rStart, aLine ); 7943cdf0e10cSrcweir aLine.append( " m " ); 7944cdf0e10cSrcweir m_aPages.back().appendPoint( rStop, aLine ); 7945cdf0e10cSrcweir aLine.append( " l S\n" ); 7946cdf0e10cSrcweir 7947cdf0e10cSrcweir writeBuffer( aLine.getStr(), aLine.getLength() ); 7948cdf0e10cSrcweir } 7949cdf0e10cSrcweir 7950cdf0e10cSrcweir void PDFWriterImpl::drawLine( const Point& rStart, const Point& rStop, const LineInfo& rInfo ) 7951cdf0e10cSrcweir { 7952cdf0e10cSrcweir MARK( "drawLine with LineInfo" ); 7953cdf0e10cSrcweir updateGraphicsState(); 7954cdf0e10cSrcweir 7955cdf0e10cSrcweir if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) ) 7956cdf0e10cSrcweir return; 7957cdf0e10cSrcweir 7958cdf0e10cSrcweir if( rInfo.GetStyle() == LINE_SOLID && rInfo.GetWidth() < 2 ) 7959cdf0e10cSrcweir { 7960cdf0e10cSrcweir drawLine( rStart, rStop ); 7961cdf0e10cSrcweir return; 7962cdf0e10cSrcweir } 7963cdf0e10cSrcweir 7964cdf0e10cSrcweir OStringBuffer aLine; 7965cdf0e10cSrcweir 7966cdf0e10cSrcweir aLine.append( "q " ); 7967cdf0e10cSrcweir if( m_aPages.back().appendLineInfo( rInfo, aLine ) ) 7968cdf0e10cSrcweir { 7969cdf0e10cSrcweir m_aPages.back().appendPoint( rStart, aLine ); 7970cdf0e10cSrcweir aLine.append( " m " ); 7971cdf0e10cSrcweir m_aPages.back().appendPoint( rStop, aLine ); 7972cdf0e10cSrcweir aLine.append( " l S Q\n" ); 7973cdf0e10cSrcweir 7974cdf0e10cSrcweir writeBuffer( aLine.getStr(), aLine.getLength() ); 7975cdf0e10cSrcweir } 7976cdf0e10cSrcweir else 7977cdf0e10cSrcweir { 7978cdf0e10cSrcweir PDFWriter::ExtLineInfo aInfo; 7979cdf0e10cSrcweir convertLineInfoToExtLineInfo( rInfo, aInfo ); 7980cdf0e10cSrcweir Point aPolyPoints[2] = { rStart, rStop }; 7981cdf0e10cSrcweir Polygon aPoly( 2, aPolyPoints ); 7982cdf0e10cSrcweir drawPolyLine( aPoly, aInfo ); 7983cdf0e10cSrcweir } 7984cdf0e10cSrcweir } 7985cdf0e10cSrcweir 7986cdf0e10cSrcweir void PDFWriterImpl::drawWaveLine( const Point& rStart, const Point& rStop, sal_Int32 nDelta, sal_Int32 nLineWidth ) 7987cdf0e10cSrcweir { 7988cdf0e10cSrcweir Point aDiff( rStop-rStart ); 7989cdf0e10cSrcweir double fLen = sqrt( (double)(aDiff.X()*aDiff.X() + aDiff.Y()*aDiff.Y()) ); 7990cdf0e10cSrcweir if( fLen < 1.0 ) 7991cdf0e10cSrcweir return; 7992cdf0e10cSrcweir 7993cdf0e10cSrcweir MARK( "drawWaveLine" ); 7994cdf0e10cSrcweir updateGraphicsState(); 7995cdf0e10cSrcweir 7996cdf0e10cSrcweir if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) ) 7997cdf0e10cSrcweir return; 7998cdf0e10cSrcweir 7999cdf0e10cSrcweir OStringBuffer aLine( 512 ); 8000cdf0e10cSrcweir aLine.append( "q " ); 8001cdf0e10cSrcweir m_aPages.back().appendMappedLength( nLineWidth, aLine, true ); 8002cdf0e10cSrcweir aLine.append( " w " ); 8003cdf0e10cSrcweir 8004cdf0e10cSrcweir appendDouble( (double)aDiff.X()/fLen, aLine ); 8005cdf0e10cSrcweir aLine.append( ' ' ); 8006cdf0e10cSrcweir appendDouble( -(double)aDiff.Y()/fLen, aLine ); 8007cdf0e10cSrcweir aLine.append( ' ' ); 8008cdf0e10cSrcweir appendDouble( (double)aDiff.Y()/fLen, aLine ); 8009cdf0e10cSrcweir aLine.append( ' ' ); 8010cdf0e10cSrcweir appendDouble( (double)aDiff.X()/fLen, aLine ); 8011cdf0e10cSrcweir aLine.append( ' ' ); 8012cdf0e10cSrcweir m_aPages.back().appendPoint( rStart, aLine ); 8013cdf0e10cSrcweir aLine.append( " cm " ); 8014cdf0e10cSrcweir m_aPages.back().appendWaveLine( (sal_Int32)fLen, 0, nDelta, aLine ); 8015cdf0e10cSrcweir aLine.append( "Q\n" ); 8016cdf0e10cSrcweir writeBuffer( aLine.getStr(), aLine.getLength() ); 8017cdf0e10cSrcweir } 8018cdf0e10cSrcweir 8019cdf0e10cSrcweir #define WCONV( x ) m_pReferenceDevice->ImplDevicePixelToLogicWidth( x ) 8020cdf0e10cSrcweir #define HCONV( x ) m_pReferenceDevice->ImplDevicePixelToLogicHeight( x ) 8021cdf0e10cSrcweir 8022cdf0e10cSrcweir void PDFWriterImpl::drawWaveTextLine( OStringBuffer& aLine, long nWidth, FontUnderline eTextLine, Color aColor, bool bIsAbove ) 8023cdf0e10cSrcweir { 8024cdf0e10cSrcweir // note: units in pFontEntry are ref device pixel 8025cdf0e10cSrcweir ImplFontEntry* pFontEntry = m_pReferenceDevice->mpFontEntry; 8026cdf0e10cSrcweir long nLineHeight = 0; 8027cdf0e10cSrcweir long nLinePos = 0; 8028cdf0e10cSrcweir 8029cdf0e10cSrcweir appendStrokingColor( aColor, aLine ); 8030cdf0e10cSrcweir aLine.append( "\n" ); 8031cdf0e10cSrcweir 8032cdf0e10cSrcweir if ( bIsAbove ) 8033cdf0e10cSrcweir { 8034cdf0e10cSrcweir if ( !pFontEntry->maMetric.mnAboveWUnderlineSize ) 8035cdf0e10cSrcweir m_pReferenceDevice->ImplInitAboveTextLineSize(); 8036cdf0e10cSrcweir nLineHeight = HCONV( pFontEntry->maMetric.mnAboveWUnderlineSize ); 8037cdf0e10cSrcweir nLinePos = HCONV( pFontEntry->maMetric.mnAboveWUnderlineOffset ); 8038cdf0e10cSrcweir } 8039cdf0e10cSrcweir else 8040cdf0e10cSrcweir { 8041cdf0e10cSrcweir if ( !pFontEntry->maMetric.mnWUnderlineSize ) 8042cdf0e10cSrcweir m_pReferenceDevice->ImplInitTextLineSize(); 8043cdf0e10cSrcweir nLineHeight = HCONV( pFontEntry->maMetric.mnWUnderlineSize ); 8044cdf0e10cSrcweir nLinePos = HCONV( pFontEntry->maMetric.mnWUnderlineOffset ); 8045cdf0e10cSrcweir } 8046cdf0e10cSrcweir if ( (eTextLine == UNDERLINE_SMALLWAVE) && (nLineHeight > 3) ) 8047cdf0e10cSrcweir nLineHeight = 3; 8048cdf0e10cSrcweir 8049cdf0e10cSrcweir long nLineWidth = getReferenceDevice()->mnDPIX/450; 8050cdf0e10cSrcweir if ( ! nLineWidth ) 8051cdf0e10cSrcweir nLineWidth = 1; 8052cdf0e10cSrcweir 8053cdf0e10cSrcweir if ( eTextLine == UNDERLINE_BOLDWAVE ) 8054cdf0e10cSrcweir nLineWidth = 3*nLineWidth; 8055cdf0e10cSrcweir 8056cdf0e10cSrcweir m_aPages.back().appendMappedLength( (sal_Int32)nLineWidth, aLine ); 8057cdf0e10cSrcweir aLine.append( " w " ); 8058cdf0e10cSrcweir 8059cdf0e10cSrcweir if ( eTextLine == UNDERLINE_DOUBLEWAVE ) 8060cdf0e10cSrcweir { 8061cdf0e10cSrcweir long nOrgLineHeight = nLineHeight; 8062cdf0e10cSrcweir nLineHeight /= 3; 8063cdf0e10cSrcweir if ( nLineHeight < 2 ) 8064cdf0e10cSrcweir { 8065cdf0e10cSrcweir if ( nOrgLineHeight > 1 ) 8066cdf0e10cSrcweir nLineHeight = 2; 8067cdf0e10cSrcweir else 8068cdf0e10cSrcweir nLineHeight = 1; 8069cdf0e10cSrcweir } 8070cdf0e10cSrcweir long nLineDY = nOrgLineHeight-(nLineHeight*2); 8071cdf0e10cSrcweir if ( nLineDY < nLineWidth ) 8072cdf0e10cSrcweir nLineDY = nLineWidth; 8073cdf0e10cSrcweir long nLineDY2 = nLineDY/2; 8074cdf0e10cSrcweir if ( !nLineDY2 ) 8075cdf0e10cSrcweir nLineDY2 = 1; 8076cdf0e10cSrcweir 8077cdf0e10cSrcweir nLinePos -= nLineWidth-nLineDY2; 8078cdf0e10cSrcweir 8079cdf0e10cSrcweir m_aPages.back().appendWaveLine( nWidth, -nLinePos, 2*nLineHeight, aLine ); 8080cdf0e10cSrcweir 8081cdf0e10cSrcweir nLinePos += nLineWidth+nLineDY; 8082cdf0e10cSrcweir m_aPages.back().appendWaveLine( nWidth, -nLinePos, 2*nLineHeight, aLine ); 8083cdf0e10cSrcweir } 8084cdf0e10cSrcweir else 8085cdf0e10cSrcweir { 8086cdf0e10cSrcweir if ( eTextLine != UNDERLINE_BOLDWAVE ) 8087cdf0e10cSrcweir nLinePos -= nLineWidth/2; 8088cdf0e10cSrcweir m_aPages.back().appendWaveLine( nWidth, -nLinePos, nLineHeight, aLine ); 8089cdf0e10cSrcweir } 8090cdf0e10cSrcweir } 8091cdf0e10cSrcweir 8092cdf0e10cSrcweir void PDFWriterImpl::drawStraightTextLine( OStringBuffer& aLine, long nWidth, FontUnderline eTextLine, Color aColor, bool bIsAbove ) 8093cdf0e10cSrcweir { 8094cdf0e10cSrcweir // note: units in pFontEntry are ref device pixel 8095cdf0e10cSrcweir ImplFontEntry* pFontEntry = m_pReferenceDevice->mpFontEntry; 8096cdf0e10cSrcweir long nLineHeight = 0; 8097cdf0e10cSrcweir long nLinePos = 0; 8098cdf0e10cSrcweir long nLinePos2 = 0; 8099cdf0e10cSrcweir 8100cdf0e10cSrcweir if ( eTextLine > UNDERLINE_BOLDWAVE ) 8101cdf0e10cSrcweir eTextLine = UNDERLINE_SINGLE; 8102cdf0e10cSrcweir 8103cdf0e10cSrcweir switch ( eTextLine ) 8104cdf0e10cSrcweir { 8105cdf0e10cSrcweir case UNDERLINE_SINGLE: 8106cdf0e10cSrcweir case UNDERLINE_DOTTED: 8107cdf0e10cSrcweir case UNDERLINE_DASH: 8108cdf0e10cSrcweir case UNDERLINE_LONGDASH: 8109cdf0e10cSrcweir case UNDERLINE_DASHDOT: 8110cdf0e10cSrcweir case UNDERLINE_DASHDOTDOT: 8111cdf0e10cSrcweir if ( bIsAbove ) 8112cdf0e10cSrcweir { 8113cdf0e10cSrcweir if ( !pFontEntry->maMetric.mnAboveUnderlineSize ) 8114cdf0e10cSrcweir m_pReferenceDevice->ImplInitAboveTextLineSize(); 8115cdf0e10cSrcweir nLineHeight = HCONV( pFontEntry->maMetric.mnAboveUnderlineSize ); 8116cdf0e10cSrcweir nLinePos = HCONV( pFontEntry->maMetric.mnAboveUnderlineOffset ); 8117cdf0e10cSrcweir } 8118cdf0e10cSrcweir else 8119cdf0e10cSrcweir { 8120cdf0e10cSrcweir if ( !pFontEntry->maMetric.mnUnderlineSize ) 8121cdf0e10cSrcweir m_pReferenceDevice->ImplInitTextLineSize(); 8122cdf0e10cSrcweir nLineHeight = HCONV( pFontEntry->maMetric.mnUnderlineSize ); 8123cdf0e10cSrcweir nLinePos = HCONV( pFontEntry->maMetric.mnUnderlineOffset ); 8124cdf0e10cSrcweir } 8125cdf0e10cSrcweir break; 8126cdf0e10cSrcweir case UNDERLINE_BOLD: 8127cdf0e10cSrcweir case UNDERLINE_BOLDDOTTED: 8128cdf0e10cSrcweir case UNDERLINE_BOLDDASH: 8129cdf0e10cSrcweir case UNDERLINE_BOLDLONGDASH: 8130cdf0e10cSrcweir case UNDERLINE_BOLDDASHDOT: 8131cdf0e10cSrcweir case UNDERLINE_BOLDDASHDOTDOT: 8132cdf0e10cSrcweir if ( bIsAbove ) 8133cdf0e10cSrcweir { 8134cdf0e10cSrcweir if ( !pFontEntry->maMetric.mnAboveBUnderlineSize ) 8135cdf0e10cSrcweir m_pReferenceDevice->ImplInitAboveTextLineSize(); 8136cdf0e10cSrcweir nLineHeight = HCONV( pFontEntry->maMetric.mnAboveBUnderlineSize ); 8137cdf0e10cSrcweir nLinePos = HCONV( pFontEntry->maMetric.mnAboveBUnderlineOffset ); 8138cdf0e10cSrcweir } 8139cdf0e10cSrcweir else 8140cdf0e10cSrcweir { 8141cdf0e10cSrcweir if ( !pFontEntry->maMetric.mnBUnderlineSize ) 8142cdf0e10cSrcweir m_pReferenceDevice->ImplInitTextLineSize(); 8143cdf0e10cSrcweir nLineHeight = HCONV( pFontEntry->maMetric.mnBUnderlineSize ); 8144cdf0e10cSrcweir nLinePos = HCONV( pFontEntry->maMetric.mnBUnderlineOffset ); 8145cdf0e10cSrcweir nLinePos += nLineHeight/2; 8146cdf0e10cSrcweir } 8147cdf0e10cSrcweir break; 8148cdf0e10cSrcweir case UNDERLINE_DOUBLE: 8149cdf0e10cSrcweir if ( bIsAbove ) 8150cdf0e10cSrcweir { 8151cdf0e10cSrcweir if ( !pFontEntry->maMetric.mnAboveDUnderlineSize ) 8152cdf0e10cSrcweir m_pReferenceDevice->ImplInitAboveTextLineSize(); 8153cdf0e10cSrcweir nLineHeight = HCONV( pFontEntry->maMetric.mnAboveDUnderlineSize ); 8154cdf0e10cSrcweir nLinePos = HCONV( pFontEntry->maMetric.mnAboveDUnderlineOffset1 ); 8155cdf0e10cSrcweir nLinePos2 = HCONV( pFontEntry->maMetric.mnAboveDUnderlineOffset2 ); 8156cdf0e10cSrcweir } 8157cdf0e10cSrcweir else 8158cdf0e10cSrcweir { 8159cdf0e10cSrcweir if ( !pFontEntry->maMetric.mnDUnderlineSize ) 8160cdf0e10cSrcweir m_pReferenceDevice->ImplInitTextLineSize(); 8161cdf0e10cSrcweir nLineHeight = HCONV( pFontEntry->maMetric.mnDUnderlineSize ); 8162cdf0e10cSrcweir nLinePos = HCONV( pFontEntry->maMetric.mnDUnderlineOffset1 ); 8163cdf0e10cSrcweir nLinePos2 = HCONV( pFontEntry->maMetric.mnDUnderlineOffset2 ); 8164cdf0e10cSrcweir } 8165cdf0e10cSrcweir default: 8166cdf0e10cSrcweir break; 8167cdf0e10cSrcweir } 8168cdf0e10cSrcweir 8169cdf0e10cSrcweir if ( nLineHeight ) 8170cdf0e10cSrcweir { 8171cdf0e10cSrcweir m_aPages.back().appendMappedLength( (sal_Int32)nLineHeight, aLine, true ); 8172cdf0e10cSrcweir aLine.append( " w " ); 8173cdf0e10cSrcweir appendStrokingColor( aColor, aLine ); 8174cdf0e10cSrcweir aLine.append( "\n" ); 8175cdf0e10cSrcweir 8176cdf0e10cSrcweir switch ( eTextLine ) 8177cdf0e10cSrcweir { 8178cdf0e10cSrcweir case UNDERLINE_DOTTED: 8179cdf0e10cSrcweir case UNDERLINE_BOLDDOTTED: 8180cdf0e10cSrcweir aLine.append( "[ " ); 8181cdf0e10cSrcweir m_aPages.back().appendMappedLength( (sal_Int32)nLineHeight, aLine, false ); 8182cdf0e10cSrcweir aLine.append( " ] 0 d\n" ); 8183cdf0e10cSrcweir break; 8184cdf0e10cSrcweir case UNDERLINE_DASH: 8185cdf0e10cSrcweir case UNDERLINE_LONGDASH: 8186cdf0e10cSrcweir case UNDERLINE_BOLDDASH: 8187cdf0e10cSrcweir case UNDERLINE_BOLDLONGDASH: 8188cdf0e10cSrcweir { 8189cdf0e10cSrcweir sal_Int32 nDashLength = 4*nLineHeight; 8190cdf0e10cSrcweir sal_Int32 nVoidLength = 2*nLineHeight; 8191cdf0e10cSrcweir if ( ( eTextLine == UNDERLINE_LONGDASH ) || ( eTextLine == UNDERLINE_BOLDLONGDASH ) ) 8192cdf0e10cSrcweir nDashLength = 8*nLineHeight; 8193cdf0e10cSrcweir 8194cdf0e10cSrcweir aLine.append( "[ " ); 8195cdf0e10cSrcweir m_aPages.back().appendMappedLength( nDashLength, aLine, false ); 8196cdf0e10cSrcweir aLine.append( ' ' ); 8197cdf0e10cSrcweir m_aPages.back().appendMappedLength( nVoidLength, aLine, false ); 8198cdf0e10cSrcweir aLine.append( " ] 0 d\n" ); 8199cdf0e10cSrcweir } 8200cdf0e10cSrcweir break; 8201cdf0e10cSrcweir case UNDERLINE_DASHDOT: 8202cdf0e10cSrcweir case UNDERLINE_BOLDDASHDOT: 8203cdf0e10cSrcweir { 8204cdf0e10cSrcweir sal_Int32 nDashLength = 4*nLineHeight; 8205cdf0e10cSrcweir sal_Int32 nVoidLength = 2*nLineHeight; 8206cdf0e10cSrcweir aLine.append( "[ " ); 8207cdf0e10cSrcweir m_aPages.back().appendMappedLength( nDashLength, aLine, false ); 8208cdf0e10cSrcweir aLine.append( ' ' ); 8209cdf0e10cSrcweir m_aPages.back().appendMappedLength( nVoidLength, aLine, false ); 8210cdf0e10cSrcweir aLine.append( ' ' ); 8211cdf0e10cSrcweir m_aPages.back().appendMappedLength( (sal_Int32)nLineHeight, aLine, false ); 8212cdf0e10cSrcweir aLine.append( ' ' ); 8213cdf0e10cSrcweir m_aPages.back().appendMappedLength( nVoidLength, aLine, false ); 8214cdf0e10cSrcweir aLine.append( " ] 0 d\n" ); 8215cdf0e10cSrcweir } 8216cdf0e10cSrcweir break; 8217cdf0e10cSrcweir case UNDERLINE_DASHDOTDOT: 8218cdf0e10cSrcweir case UNDERLINE_BOLDDASHDOTDOT: 8219cdf0e10cSrcweir { 8220cdf0e10cSrcweir sal_Int32 nDashLength = 4*nLineHeight; 8221cdf0e10cSrcweir sal_Int32 nVoidLength = 2*nLineHeight; 8222cdf0e10cSrcweir aLine.append( "[ " ); 8223cdf0e10cSrcweir m_aPages.back().appendMappedLength( nDashLength, aLine, false ); 8224cdf0e10cSrcweir aLine.append( ' ' ); 8225cdf0e10cSrcweir m_aPages.back().appendMappedLength( nVoidLength, aLine, false ); 8226cdf0e10cSrcweir aLine.append( ' ' ); 8227cdf0e10cSrcweir m_aPages.back().appendMappedLength( (sal_Int32)nLineHeight, aLine, false ); 8228cdf0e10cSrcweir aLine.append( ' ' ); 8229cdf0e10cSrcweir m_aPages.back().appendMappedLength( nVoidLength, aLine, false ); 8230cdf0e10cSrcweir aLine.append( ' ' ); 8231cdf0e10cSrcweir m_aPages.back().appendMappedLength( (sal_Int32)nLineHeight, aLine, false ); 8232cdf0e10cSrcweir aLine.append( ' ' ); 8233cdf0e10cSrcweir m_aPages.back().appendMappedLength( nVoidLength, aLine, false ); 8234cdf0e10cSrcweir aLine.append( " ] 0 d\n" ); 8235cdf0e10cSrcweir } 8236cdf0e10cSrcweir break; 8237cdf0e10cSrcweir default: 8238cdf0e10cSrcweir break; 8239cdf0e10cSrcweir } 8240cdf0e10cSrcweir 8241cdf0e10cSrcweir aLine.append( "0 " ); 8242cdf0e10cSrcweir m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos), aLine, true ); 8243cdf0e10cSrcweir aLine.append( " m " ); 8244cdf0e10cSrcweir m_aPages.back().appendMappedLength( (sal_Int32)nWidth, aLine, false ); 8245cdf0e10cSrcweir aLine.append( ' ' ); 8246cdf0e10cSrcweir m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos), aLine, true ); 8247cdf0e10cSrcweir aLine.append( " l S\n" ); 8248cdf0e10cSrcweir if ( eTextLine == UNDERLINE_DOUBLE ) 8249cdf0e10cSrcweir { 8250cdf0e10cSrcweir aLine.append( "0 " ); 8251cdf0e10cSrcweir m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos2-nLineHeight), aLine, true ); 8252cdf0e10cSrcweir aLine.append( " m " ); 8253cdf0e10cSrcweir m_aPages.back().appendMappedLength( (sal_Int32)nWidth, aLine, false ); 8254cdf0e10cSrcweir aLine.append( ' ' ); 8255cdf0e10cSrcweir m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos2-nLineHeight), aLine, true ); 8256cdf0e10cSrcweir aLine.append( " l S\n" ); 8257cdf0e10cSrcweir } 8258cdf0e10cSrcweir } 8259cdf0e10cSrcweir } 8260cdf0e10cSrcweir 8261cdf0e10cSrcweir void PDFWriterImpl::drawStrikeoutLine( OStringBuffer& aLine, long nWidth, FontStrikeout eStrikeout, Color aColor ) 8262cdf0e10cSrcweir { 8263cdf0e10cSrcweir // note: units in pFontEntry are ref device pixel 8264cdf0e10cSrcweir ImplFontEntry* pFontEntry = m_pReferenceDevice->mpFontEntry; 8265cdf0e10cSrcweir long nLineHeight = 0; 8266cdf0e10cSrcweir long nLinePos = 0; 8267cdf0e10cSrcweir long nLinePos2 = 0; 8268cdf0e10cSrcweir 8269cdf0e10cSrcweir if ( eStrikeout > STRIKEOUT_X ) 8270cdf0e10cSrcweir eStrikeout = STRIKEOUT_SINGLE; 8271cdf0e10cSrcweir 8272cdf0e10cSrcweir switch ( eStrikeout ) 8273cdf0e10cSrcweir { 8274cdf0e10cSrcweir case STRIKEOUT_SINGLE: 8275cdf0e10cSrcweir if ( !pFontEntry->maMetric.mnStrikeoutSize ) 8276cdf0e10cSrcweir m_pReferenceDevice->ImplInitTextLineSize(); 8277cdf0e10cSrcweir nLineHeight = HCONV( pFontEntry->maMetric.mnStrikeoutSize ); 8278cdf0e10cSrcweir nLinePos = HCONV( pFontEntry->maMetric.mnStrikeoutOffset ); 8279cdf0e10cSrcweir break; 8280cdf0e10cSrcweir case STRIKEOUT_BOLD: 8281cdf0e10cSrcweir if ( !pFontEntry->maMetric.mnBStrikeoutSize ) 8282cdf0e10cSrcweir m_pReferenceDevice->ImplInitTextLineSize(); 8283cdf0e10cSrcweir nLineHeight = HCONV( pFontEntry->maMetric.mnBStrikeoutSize ); 8284cdf0e10cSrcweir nLinePos = HCONV( pFontEntry->maMetric.mnBStrikeoutOffset ); 8285cdf0e10cSrcweir break; 8286cdf0e10cSrcweir case STRIKEOUT_DOUBLE: 8287cdf0e10cSrcweir if ( !pFontEntry->maMetric.mnDStrikeoutSize ) 8288cdf0e10cSrcweir m_pReferenceDevice->ImplInitTextLineSize(); 8289cdf0e10cSrcweir nLineHeight = HCONV( pFontEntry->maMetric.mnDStrikeoutSize ); 8290cdf0e10cSrcweir nLinePos = HCONV( pFontEntry->maMetric.mnDStrikeoutOffset1 ); 8291cdf0e10cSrcweir nLinePos2 = HCONV( pFontEntry->maMetric.mnDStrikeoutOffset2 ); 8292cdf0e10cSrcweir break; 8293cdf0e10cSrcweir default: 8294cdf0e10cSrcweir break; 8295cdf0e10cSrcweir } 8296cdf0e10cSrcweir 8297cdf0e10cSrcweir if ( nLineHeight ) 8298cdf0e10cSrcweir { 8299cdf0e10cSrcweir m_aPages.back().appendMappedLength( (sal_Int32)nLineHeight, aLine, true ); 8300cdf0e10cSrcweir aLine.append( " w " ); 8301cdf0e10cSrcweir appendStrokingColor( aColor, aLine ); 8302cdf0e10cSrcweir aLine.append( "\n" ); 8303cdf0e10cSrcweir 8304cdf0e10cSrcweir aLine.append( "0 " ); 8305cdf0e10cSrcweir m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos), aLine, true ); 8306cdf0e10cSrcweir aLine.append( " m " ); 8307cdf0e10cSrcweir m_aPages.back().appendMappedLength( (sal_Int32)nWidth, aLine, true ); 8308cdf0e10cSrcweir aLine.append( ' ' ); 8309cdf0e10cSrcweir m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos), aLine, true ); 8310cdf0e10cSrcweir aLine.append( " l S\n" ); 8311cdf0e10cSrcweir 8312cdf0e10cSrcweir if ( eStrikeout == STRIKEOUT_DOUBLE ) 8313cdf0e10cSrcweir { 8314cdf0e10cSrcweir aLine.append( "0 " ); 8315cdf0e10cSrcweir m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos2-nLineHeight), aLine, true ); 8316cdf0e10cSrcweir aLine.append( " m " ); 8317cdf0e10cSrcweir m_aPages.back().appendMappedLength( (sal_Int32)nWidth, aLine, true ); 8318cdf0e10cSrcweir aLine.append( ' ' ); 8319cdf0e10cSrcweir m_aPages.back().appendMappedLength( (sal_Int32)(-nLinePos2-nLineHeight), aLine, true ); 8320cdf0e10cSrcweir aLine.append( " l S\n" ); 8321cdf0e10cSrcweir } 8322cdf0e10cSrcweir } 8323cdf0e10cSrcweir } 8324cdf0e10cSrcweir 8325cdf0e10cSrcweir void PDFWriterImpl::drawStrikeoutChar( const Point& rPos, long nWidth, FontStrikeout eStrikeout ) 8326cdf0e10cSrcweir { 8327cdf0e10cSrcweir String aStrikeoutChar = String::CreateFromAscii( eStrikeout == STRIKEOUT_SLASH ? "/" : "X" ); 8328cdf0e10cSrcweir String aStrikeout = aStrikeoutChar; 8329cdf0e10cSrcweir while( m_pReferenceDevice->GetTextWidth( aStrikeout ) < nWidth ) 8330cdf0e10cSrcweir aStrikeout.Append( aStrikeout ); 8331cdf0e10cSrcweir 8332cdf0e10cSrcweir // do not get broader than nWidth modulo 1 character 8333cdf0e10cSrcweir while( m_pReferenceDevice->GetTextWidth( aStrikeout ) >= nWidth ) 8334cdf0e10cSrcweir aStrikeout.Erase( 0, 1 ); 8335cdf0e10cSrcweir aStrikeout.Append( aStrikeoutChar ); 8336cdf0e10cSrcweir sal_Bool bShadow = m_aCurrentPDFState.m_aFont.IsShadow(); 8337cdf0e10cSrcweir if ( bShadow ) 8338cdf0e10cSrcweir { 8339cdf0e10cSrcweir Font aFont = m_aCurrentPDFState.m_aFont; 8340cdf0e10cSrcweir aFont.SetShadow( sal_False ); 8341cdf0e10cSrcweir setFont( aFont ); 8342cdf0e10cSrcweir updateGraphicsState(); 8343cdf0e10cSrcweir } 8344cdf0e10cSrcweir 8345cdf0e10cSrcweir // strikeout string is left aligned non-CTL text 8346cdf0e10cSrcweir sal_uLong nOrigTLM = m_pReferenceDevice->GetLayoutMode(); 8347cdf0e10cSrcweir m_pReferenceDevice->SetLayoutMode( TEXT_LAYOUT_BIDI_STRONG|TEXT_LAYOUT_COMPLEX_DISABLED ); 8348cdf0e10cSrcweir drawText( rPos, aStrikeout, 0, aStrikeout.Len(), false ); 8349cdf0e10cSrcweir m_pReferenceDevice->SetLayoutMode( nOrigTLM ); 8350cdf0e10cSrcweir 8351cdf0e10cSrcweir if ( bShadow ) 8352cdf0e10cSrcweir { 8353cdf0e10cSrcweir Font aFont = m_aCurrentPDFState.m_aFont; 8354cdf0e10cSrcweir aFont.SetShadow( sal_True ); 8355cdf0e10cSrcweir setFont( aFont ); 8356cdf0e10cSrcweir updateGraphicsState(); 8357cdf0e10cSrcweir } 8358cdf0e10cSrcweir } 8359cdf0e10cSrcweir 8360cdf0e10cSrcweir void PDFWriterImpl::drawTextLine( const Point& rPos, long nWidth, FontStrikeout eStrikeout, FontUnderline eUnderline, FontUnderline eOverline, bool bUnderlineAbove ) 8361cdf0e10cSrcweir { 8362cdf0e10cSrcweir if ( !nWidth || 8363cdf0e10cSrcweir ( ((eStrikeout == STRIKEOUT_NONE)||(eStrikeout == STRIKEOUT_DONTKNOW)) && 8364cdf0e10cSrcweir ((eUnderline == UNDERLINE_NONE)||(eUnderline == UNDERLINE_DONTKNOW)) && 8365cdf0e10cSrcweir ((eOverline == UNDERLINE_NONE)||(eOverline == UNDERLINE_DONTKNOW)) ) ) 8366cdf0e10cSrcweir return; 8367cdf0e10cSrcweir 8368cdf0e10cSrcweir MARK( "drawTextLine" ); 8369cdf0e10cSrcweir updateGraphicsState(); 8370cdf0e10cSrcweir 8371cdf0e10cSrcweir // note: units in pFontEntry are ref device pixel 8372cdf0e10cSrcweir ImplFontEntry* pFontEntry = m_pReferenceDevice->mpFontEntry; 8373cdf0e10cSrcweir Color aUnderlineColor = m_aCurrentPDFState.m_aTextLineColor; 8374cdf0e10cSrcweir Color aOverlineColor = m_aCurrentPDFState.m_aOverlineColor; 8375cdf0e10cSrcweir Color aStrikeoutColor = m_aCurrentPDFState.m_aFont.GetColor(); 8376cdf0e10cSrcweir bool bStrikeoutDone = false; 8377cdf0e10cSrcweir bool bUnderlineDone = false; 8378cdf0e10cSrcweir bool bOverlineDone = false; 8379cdf0e10cSrcweir 8380cdf0e10cSrcweir if ( (eStrikeout == STRIKEOUT_SLASH) || (eStrikeout == STRIKEOUT_X) ) 8381cdf0e10cSrcweir { 8382cdf0e10cSrcweir drawStrikeoutChar( rPos, nWidth, eStrikeout ); 8383cdf0e10cSrcweir bStrikeoutDone = true; 8384cdf0e10cSrcweir } 8385cdf0e10cSrcweir 8386cdf0e10cSrcweir Point aPos( rPos ); 8387cdf0e10cSrcweir TextAlign eAlign = m_aCurrentPDFState.m_aFont.GetAlign(); 8388cdf0e10cSrcweir if( eAlign == ALIGN_TOP ) 8389cdf0e10cSrcweir aPos.Y() += HCONV( pFontEntry->maMetric.mnAscent ); 8390cdf0e10cSrcweir else if( eAlign == ALIGN_BOTTOM ) 8391cdf0e10cSrcweir aPos.Y() -= HCONV( pFontEntry->maMetric.mnDescent ); 8392cdf0e10cSrcweir 8393cdf0e10cSrcweir OStringBuffer aLine( 512 ); 8394cdf0e10cSrcweir // save GS 8395cdf0e10cSrcweir aLine.append( "q " ); 8396cdf0e10cSrcweir 8397cdf0e10cSrcweir // rotate and translate matrix 8398cdf0e10cSrcweir double fAngle = (double)m_aCurrentPDFState.m_aFont.GetOrientation() * M_PI / 1800.0; 8399cdf0e10cSrcweir Matrix3 aMat; 8400cdf0e10cSrcweir aMat.rotate( fAngle ); 8401cdf0e10cSrcweir aMat.translate( aPos.X(), aPos.Y() ); 8402cdf0e10cSrcweir aMat.append( m_aPages.back(), aLine ); 8403cdf0e10cSrcweir aLine.append( " cm\n" ); 8404cdf0e10cSrcweir 8405cdf0e10cSrcweir if ( aUnderlineColor.GetTransparency() != 0 ) 8406cdf0e10cSrcweir aUnderlineColor = aStrikeoutColor; 8407cdf0e10cSrcweir 8408cdf0e10cSrcweir if ( (eUnderline == UNDERLINE_SMALLWAVE) || 8409cdf0e10cSrcweir (eUnderline == UNDERLINE_WAVE) || 8410cdf0e10cSrcweir (eUnderline == UNDERLINE_DOUBLEWAVE) || 8411cdf0e10cSrcweir (eUnderline == UNDERLINE_BOLDWAVE) ) 8412cdf0e10cSrcweir { 8413cdf0e10cSrcweir drawWaveTextLine( aLine, nWidth, eUnderline, aUnderlineColor, bUnderlineAbove ); 8414cdf0e10cSrcweir bUnderlineDone = true; 8415cdf0e10cSrcweir } 8416cdf0e10cSrcweir 8417cdf0e10cSrcweir if ( (eOverline == UNDERLINE_SMALLWAVE) || 8418cdf0e10cSrcweir (eOverline == UNDERLINE_WAVE) || 8419cdf0e10cSrcweir (eOverline == UNDERLINE_DOUBLEWAVE) || 8420cdf0e10cSrcweir (eOverline == UNDERLINE_BOLDWAVE) ) 8421cdf0e10cSrcweir { 8422cdf0e10cSrcweir drawWaveTextLine( aLine, nWidth, eOverline, aOverlineColor, true ); 8423cdf0e10cSrcweir bOverlineDone = true; 8424cdf0e10cSrcweir } 8425cdf0e10cSrcweir 8426cdf0e10cSrcweir if ( !bUnderlineDone ) 8427cdf0e10cSrcweir { 8428cdf0e10cSrcweir drawStraightTextLine( aLine, nWidth, eUnderline, aUnderlineColor, bUnderlineAbove ); 8429cdf0e10cSrcweir } 8430cdf0e10cSrcweir 8431cdf0e10cSrcweir if ( !bOverlineDone ) 8432cdf0e10cSrcweir { 8433cdf0e10cSrcweir drawStraightTextLine( aLine, nWidth, eOverline, aOverlineColor, true ); 8434cdf0e10cSrcweir } 8435cdf0e10cSrcweir 8436cdf0e10cSrcweir if ( !bStrikeoutDone ) 8437cdf0e10cSrcweir { 8438cdf0e10cSrcweir drawStrikeoutLine( aLine, nWidth, eStrikeout, aStrikeoutColor ); 8439cdf0e10cSrcweir } 8440cdf0e10cSrcweir 8441cdf0e10cSrcweir aLine.append( "Q\n" ); 8442cdf0e10cSrcweir writeBuffer( aLine.getStr(), aLine.getLength() ); 8443cdf0e10cSrcweir } 8444cdf0e10cSrcweir 8445cdf0e10cSrcweir void PDFWriterImpl::drawPolygon( const Polygon& rPoly ) 8446cdf0e10cSrcweir { 8447cdf0e10cSrcweir MARK( "drawPolygon" ); 8448cdf0e10cSrcweir 8449cdf0e10cSrcweir updateGraphicsState(); 8450cdf0e10cSrcweir 8451cdf0e10cSrcweir if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) && 8452cdf0e10cSrcweir m_aGraphicsStack.front().m_aFillColor == Color( COL_TRANSPARENT ) ) 8453cdf0e10cSrcweir return; 8454cdf0e10cSrcweir 8455cdf0e10cSrcweir int nPoints = rPoly.GetSize(); 8456cdf0e10cSrcweir OStringBuffer aLine( 20 * nPoints ); 8457cdf0e10cSrcweir m_aPages.back().appendPolygon( rPoly, aLine ); 8458cdf0e10cSrcweir if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) && 8459cdf0e10cSrcweir m_aGraphicsStack.front().m_aFillColor != Color( COL_TRANSPARENT ) ) 8460cdf0e10cSrcweir aLine.append( "B*\n" ); 8461cdf0e10cSrcweir else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) ) 8462cdf0e10cSrcweir aLine.append( "S\n" ); 8463cdf0e10cSrcweir else 8464cdf0e10cSrcweir aLine.append( "f*\n" ); 8465cdf0e10cSrcweir 8466cdf0e10cSrcweir writeBuffer( aLine.getStr(), aLine.getLength() ); 8467cdf0e10cSrcweir } 8468cdf0e10cSrcweir 8469cdf0e10cSrcweir void PDFWriterImpl::drawPolyPolygon( const PolyPolygon& rPolyPoly ) 8470cdf0e10cSrcweir { 8471cdf0e10cSrcweir MARK( "drawPolyPolygon" ); 8472cdf0e10cSrcweir 8473cdf0e10cSrcweir updateGraphicsState(); 8474cdf0e10cSrcweir 8475cdf0e10cSrcweir if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) && 8476cdf0e10cSrcweir m_aGraphicsStack.front().m_aFillColor == Color( COL_TRANSPARENT ) ) 8477cdf0e10cSrcweir return; 8478cdf0e10cSrcweir 8479cdf0e10cSrcweir int nPolygons = rPolyPoly.Count(); 8480cdf0e10cSrcweir 8481cdf0e10cSrcweir OStringBuffer aLine( 40 * nPolygons ); 8482cdf0e10cSrcweir m_aPages.back().appendPolyPolygon( rPolyPoly, aLine ); 8483cdf0e10cSrcweir if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) && 8484cdf0e10cSrcweir m_aGraphicsStack.front().m_aFillColor != Color( COL_TRANSPARENT ) ) 8485cdf0e10cSrcweir aLine.append( "B*\n" ); 8486cdf0e10cSrcweir else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) ) 8487cdf0e10cSrcweir aLine.append( "S\n" ); 8488cdf0e10cSrcweir else 8489cdf0e10cSrcweir aLine.append( "f*\n" ); 8490cdf0e10cSrcweir 8491cdf0e10cSrcweir writeBuffer( aLine.getStr(), aLine.getLength() ); 8492cdf0e10cSrcweir } 8493cdf0e10cSrcweir 8494cdf0e10cSrcweir void PDFWriterImpl::drawTransparent( const PolyPolygon& rPolyPoly, sal_uInt32 nTransparentPercent ) 8495cdf0e10cSrcweir { 8496cdf0e10cSrcweir DBG_ASSERT( nTransparentPercent <= 100, "invalid alpha value" ); 8497cdf0e10cSrcweir nTransparentPercent = nTransparentPercent % 100; 8498cdf0e10cSrcweir 8499cdf0e10cSrcweir MARK( "drawTransparent" ); 8500cdf0e10cSrcweir 8501cdf0e10cSrcweir updateGraphicsState(); 8502cdf0e10cSrcweir 8503cdf0e10cSrcweir if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) && 8504cdf0e10cSrcweir m_aGraphicsStack.front().m_aFillColor == Color( COL_TRANSPARENT ) ) 8505cdf0e10cSrcweir return; 8506cdf0e10cSrcweir 8507cdf0e10cSrcweir if( m_bIsPDF_A1 || m_aContext.Version < PDFWriter::PDF_1_4 ) 8508cdf0e10cSrcweir { 8509cdf0e10cSrcweir m_aErrors.insert( m_bIsPDF_A1 ? 8510cdf0e10cSrcweir PDFWriter::Warning_Transparency_Omitted_PDFA : 8511cdf0e10cSrcweir PDFWriter::Warning_Transparency_Omitted_PDF13 ); 8512cdf0e10cSrcweir 8513cdf0e10cSrcweir drawPolyPolygon( rPolyPoly ); 8514cdf0e10cSrcweir return; 8515cdf0e10cSrcweir } 8516cdf0e10cSrcweir 8517cdf0e10cSrcweir // create XObject 8518cdf0e10cSrcweir m_aTransparentObjects.push_back( TransparencyEmit() ); 8519cdf0e10cSrcweir // FIXME: polygons with beziers may yield incorrect bound rect 8520cdf0e10cSrcweir m_aTransparentObjects.back().m_aBoundRect = rPolyPoly.GetBoundRect(); 8521cdf0e10cSrcweir // convert rectangle to default user space 8522cdf0e10cSrcweir m_aPages.back().convertRect( m_aTransparentObjects.back().m_aBoundRect ); 8523cdf0e10cSrcweir m_aTransparentObjects.back().m_nObject = createObject(); 8524cdf0e10cSrcweir m_aTransparentObjects.back().m_nExtGStateObject = createObject(); 8525cdf0e10cSrcweir m_aTransparentObjects.back().m_fAlpha = (double)(100-nTransparentPercent) / 100.0; 8526cdf0e10cSrcweir m_aTransparentObjects.back().m_pContentStream = new SvMemoryStream( 256, 256 ); 8527cdf0e10cSrcweir // create XObject's content stream 8528cdf0e10cSrcweir OStringBuffer aContent( 256 ); 8529cdf0e10cSrcweir m_aPages.back().appendPolyPolygon( rPolyPoly, aContent ); 8530cdf0e10cSrcweir if( m_aCurrentPDFState.m_aLineColor != Color( COL_TRANSPARENT ) && 8531cdf0e10cSrcweir m_aCurrentPDFState.m_aFillColor != Color( COL_TRANSPARENT ) ) 8532cdf0e10cSrcweir aContent.append( " B*\n" ); 8533cdf0e10cSrcweir else if( m_aCurrentPDFState.m_aLineColor != Color( COL_TRANSPARENT ) ) 8534cdf0e10cSrcweir aContent.append( " S\n" ); 8535cdf0e10cSrcweir else 8536cdf0e10cSrcweir aContent.append( " f*\n" ); 8537cdf0e10cSrcweir m_aTransparentObjects.back().m_pContentStream->Write( aContent.getStr(), aContent.getLength() ); 8538cdf0e10cSrcweir 8539cdf0e10cSrcweir OStringBuffer aObjName( 16 ); 8540cdf0e10cSrcweir aObjName.append( "Tr" ); 8541cdf0e10cSrcweir aObjName.append( m_aTransparentObjects.back().m_nObject ); 8542cdf0e10cSrcweir OString aTrName( aObjName.makeStringAndClear() ); 8543cdf0e10cSrcweir aObjName.append( "EGS" ); 8544cdf0e10cSrcweir aObjName.append( m_aTransparentObjects.back().m_nExtGStateObject ); 8545cdf0e10cSrcweir OString aExtName( aObjName.makeStringAndClear() ); 8546cdf0e10cSrcweir 8547cdf0e10cSrcweir OStringBuffer aLine( 80 ); 8548cdf0e10cSrcweir // insert XObject 8549cdf0e10cSrcweir aLine.append( "q /" ); 8550cdf0e10cSrcweir aLine.append( aExtName ); 8551cdf0e10cSrcweir aLine.append( " gs /" ); 8552cdf0e10cSrcweir aLine.append( aTrName ); 8553cdf0e10cSrcweir aLine.append( " Do Q\n" ); 8554cdf0e10cSrcweir writeBuffer( aLine.getStr(), aLine.getLength() ); 8555cdf0e10cSrcweir 8556cdf0e10cSrcweir pushResource( ResXObject, aTrName, m_aTransparentObjects.back().m_nObject ); 8557cdf0e10cSrcweir pushResource( ResExtGState, aExtName, m_aTransparentObjects.back().m_nExtGStateObject ); 8558cdf0e10cSrcweir } 8559cdf0e10cSrcweir 8560cdf0e10cSrcweir void PDFWriterImpl::pushResource( ResourceKind eKind, const OString& rResource, sal_Int32 nObject ) 8561cdf0e10cSrcweir { 8562cdf0e10cSrcweir if( nObject >= 0 ) 8563cdf0e10cSrcweir { 8564cdf0e10cSrcweir switch( eKind ) 8565cdf0e10cSrcweir { 8566cdf0e10cSrcweir case ResXObject: 8567cdf0e10cSrcweir m_aGlobalResourceDict.m_aXObjects[ rResource ] = nObject; 8568cdf0e10cSrcweir if( ! m_aOutputStreams.empty() ) 8569cdf0e10cSrcweir m_aOutputStreams.front().m_aResourceDict.m_aXObjects[ rResource ] = nObject; 8570cdf0e10cSrcweir break; 8571cdf0e10cSrcweir case ResExtGState: 8572cdf0e10cSrcweir m_aGlobalResourceDict.m_aExtGStates[ rResource ] = nObject; 8573cdf0e10cSrcweir if( ! m_aOutputStreams.empty() ) 8574cdf0e10cSrcweir m_aOutputStreams.front().m_aResourceDict.m_aExtGStates[ rResource ] = nObject; 8575cdf0e10cSrcweir break; 8576cdf0e10cSrcweir case ResShading: 8577cdf0e10cSrcweir m_aGlobalResourceDict.m_aShadings[ rResource ] = nObject; 8578cdf0e10cSrcweir if( ! m_aOutputStreams.empty() ) 8579cdf0e10cSrcweir m_aOutputStreams.front().m_aResourceDict.m_aShadings[ rResource ] = nObject; 8580cdf0e10cSrcweir break; 8581cdf0e10cSrcweir case ResPattern: 8582cdf0e10cSrcweir m_aGlobalResourceDict.m_aPatterns[ rResource ] = nObject; 8583cdf0e10cSrcweir if( ! m_aOutputStreams.empty() ) 8584cdf0e10cSrcweir m_aOutputStreams.front().m_aResourceDict.m_aPatterns[ rResource ] = nObject; 8585cdf0e10cSrcweir break; 8586cdf0e10cSrcweir } 8587cdf0e10cSrcweir } 8588cdf0e10cSrcweir } 8589cdf0e10cSrcweir 8590cdf0e10cSrcweir void PDFWriterImpl::beginRedirect( SvStream* pStream, const Rectangle& rTargetRect ) 8591cdf0e10cSrcweir { 8592cdf0e10cSrcweir push( PUSH_ALL ); 8593cdf0e10cSrcweir 8594cdf0e10cSrcweir // force reemitting clip region 8595cdf0e10cSrcweir clearClipRegion(); 8596cdf0e10cSrcweir updateGraphicsState(); 8597cdf0e10cSrcweir 8598cdf0e10cSrcweir m_aOutputStreams.push_front( StreamRedirect() ); 8599cdf0e10cSrcweir m_aOutputStreams.front().m_pStream = pStream; 8600cdf0e10cSrcweir m_aOutputStreams.front().m_aMapMode = m_aMapMode; 8601cdf0e10cSrcweir 8602cdf0e10cSrcweir if( !rTargetRect.IsEmpty() ) 8603cdf0e10cSrcweir { 8604cdf0e10cSrcweir m_aOutputStreams.front().m_aTargetRect = 8605cdf0e10cSrcweir lcl_convert( m_aGraphicsStack.front().m_aMapMode, 8606cdf0e10cSrcweir m_aMapMode, 8607cdf0e10cSrcweir getReferenceDevice(), 8608cdf0e10cSrcweir rTargetRect ); 8609cdf0e10cSrcweir Point aDelta = m_aOutputStreams.front().m_aTargetRect.BottomLeft(); 8610cdf0e10cSrcweir long nPageHeight = pointToPixel(m_aPages[m_nCurrentPage].getHeight()); 8611cdf0e10cSrcweir aDelta.Y() = -(nPageHeight - m_aOutputStreams.front().m_aTargetRect.Bottom()); 8612cdf0e10cSrcweir m_aMapMode.SetOrigin( m_aMapMode.GetOrigin() + aDelta ); 8613cdf0e10cSrcweir } 8614cdf0e10cSrcweir 8615cdf0e10cSrcweir // setup graphics state for independent object stream 8616cdf0e10cSrcweir 8617cdf0e10cSrcweir // force reemitting colors 8618cdf0e10cSrcweir m_aCurrentPDFState.m_aLineColor = Color( COL_TRANSPARENT ); 8619cdf0e10cSrcweir m_aCurrentPDFState.m_aFillColor = Color( COL_TRANSPARENT ); 8620cdf0e10cSrcweir } 8621cdf0e10cSrcweir 8622cdf0e10cSrcweir Rectangle PDFWriterImpl::getRedirectTargetRect() const 8623cdf0e10cSrcweir { 8624cdf0e10cSrcweir return m_aOutputStreams.empty() ? Rectangle() : m_aOutputStreams.front().m_aTargetRect; 8625cdf0e10cSrcweir } 8626cdf0e10cSrcweir 8627cdf0e10cSrcweir SvStream* PDFWriterImpl::endRedirect() 8628cdf0e10cSrcweir { 8629cdf0e10cSrcweir SvStream* pStream = NULL; 8630cdf0e10cSrcweir if( ! m_aOutputStreams.empty() ) 8631cdf0e10cSrcweir { 8632cdf0e10cSrcweir pStream = m_aOutputStreams.front().m_pStream; 8633cdf0e10cSrcweir m_aMapMode = m_aOutputStreams.front().m_aMapMode; 8634cdf0e10cSrcweir m_aOutputStreams.pop_front(); 8635cdf0e10cSrcweir } 8636cdf0e10cSrcweir 8637cdf0e10cSrcweir pop(); 8638cdf0e10cSrcweir // force reemitting colors and clip region 8639cdf0e10cSrcweir clearClipRegion(); 8640cdf0e10cSrcweir m_aCurrentPDFState.m_bClipRegion = m_aGraphicsStack.front().m_bClipRegion; 8641cdf0e10cSrcweir m_aCurrentPDFState.m_aClipRegion = m_aGraphicsStack.front().m_aClipRegion; 8642cdf0e10cSrcweir m_aCurrentPDFState.m_aLineColor = Color( COL_TRANSPARENT ); 8643cdf0e10cSrcweir m_aCurrentPDFState.m_aFillColor = Color( COL_TRANSPARENT ); 8644cdf0e10cSrcweir 8645cdf0e10cSrcweir updateGraphicsState(); 8646cdf0e10cSrcweir 8647cdf0e10cSrcweir return pStream; 8648cdf0e10cSrcweir } 8649cdf0e10cSrcweir 8650cdf0e10cSrcweir void PDFWriterImpl::beginTransparencyGroup() 8651cdf0e10cSrcweir { 8652cdf0e10cSrcweir updateGraphicsState(); 8653cdf0e10cSrcweir if( m_aContext.Version >= PDFWriter::PDF_1_4 ) 8654cdf0e10cSrcweir beginRedirect( new SvMemoryStream( 1024, 1024 ), Rectangle() ); 8655cdf0e10cSrcweir } 8656cdf0e10cSrcweir 8657cdf0e10cSrcweir void PDFWriterImpl::endTransparencyGroup( const Rectangle& rBoundingBox, sal_uInt32 nTransparentPercent ) 8658cdf0e10cSrcweir { 8659cdf0e10cSrcweir DBG_ASSERT( nTransparentPercent <= 100, "invalid alpha value" ); 8660cdf0e10cSrcweir nTransparentPercent = nTransparentPercent % 100; 8661cdf0e10cSrcweir 8662cdf0e10cSrcweir if( m_aContext.Version >= PDFWriter::PDF_1_4 ) 8663cdf0e10cSrcweir { 8664cdf0e10cSrcweir // create XObject 8665cdf0e10cSrcweir m_aTransparentObjects.push_back( TransparencyEmit() ); 8666cdf0e10cSrcweir m_aTransparentObjects.back().m_aBoundRect = rBoundingBox; 8667cdf0e10cSrcweir // convert rectangle to default user space 8668cdf0e10cSrcweir m_aPages.back().convertRect( m_aTransparentObjects.back().m_aBoundRect ); 8669cdf0e10cSrcweir m_aTransparentObjects.back().m_nObject = createObject(); 8670cdf0e10cSrcweir m_aTransparentObjects.back().m_fAlpha = (double)(100-nTransparentPercent) / 100.0; 8671cdf0e10cSrcweir // get XObject's content stream 8672cdf0e10cSrcweir m_aTransparentObjects.back().m_pContentStream = static_cast<SvMemoryStream*>(endRedirect()); 8673cdf0e10cSrcweir m_aTransparentObjects.back().m_nExtGStateObject = createObject(); 8674cdf0e10cSrcweir 8675cdf0e10cSrcweir OStringBuffer aObjName( 16 ); 8676cdf0e10cSrcweir aObjName.append( "Tr" ); 8677cdf0e10cSrcweir aObjName.append( m_aTransparentObjects.back().m_nObject ); 8678cdf0e10cSrcweir OString aTrName( aObjName.makeStringAndClear() ); 8679cdf0e10cSrcweir aObjName.append( "EGS" ); 8680cdf0e10cSrcweir aObjName.append( m_aTransparentObjects.back().m_nExtGStateObject ); 8681cdf0e10cSrcweir OString aExtName( aObjName.makeStringAndClear() ); 8682cdf0e10cSrcweir 8683cdf0e10cSrcweir OStringBuffer aLine( 80 ); 8684cdf0e10cSrcweir // insert XObject 8685cdf0e10cSrcweir aLine.append( "q /" ); 8686cdf0e10cSrcweir aLine.append( aExtName ); 8687cdf0e10cSrcweir aLine.append( " gs /" ); 8688cdf0e10cSrcweir aLine.append( aTrName ); 8689cdf0e10cSrcweir aLine.append( " Do Q\n" ); 8690cdf0e10cSrcweir writeBuffer( aLine.getStr(), aLine.getLength() ); 8691cdf0e10cSrcweir 8692cdf0e10cSrcweir pushResource( ResXObject, aTrName, m_aTransparentObjects.back().m_nObject ); 8693cdf0e10cSrcweir pushResource( ResExtGState, aExtName, m_aTransparentObjects.back().m_nExtGStateObject ); 8694cdf0e10cSrcweir } 8695cdf0e10cSrcweir } 8696cdf0e10cSrcweir 8697cdf0e10cSrcweir void PDFWriterImpl::endTransparencyGroup( const Rectangle& rBoundingBox, const Bitmap& rAlphaMask ) 8698cdf0e10cSrcweir { 8699cdf0e10cSrcweir if( m_aContext.Version >= PDFWriter::PDF_1_4 ) 8700cdf0e10cSrcweir { 8701cdf0e10cSrcweir // create XObject 8702cdf0e10cSrcweir m_aTransparentObjects.push_back( TransparencyEmit() ); 8703cdf0e10cSrcweir m_aTransparentObjects.back().m_aBoundRect = rBoundingBox; 8704cdf0e10cSrcweir // convert rectangle to default user space 8705cdf0e10cSrcweir m_aPages.back().convertRect( m_aTransparentObjects.back().m_aBoundRect ); 8706cdf0e10cSrcweir m_aTransparentObjects.back().m_nObject = createObject(); 8707cdf0e10cSrcweir m_aTransparentObjects.back().m_fAlpha = 0.0; 8708cdf0e10cSrcweir // get XObject's content stream 8709cdf0e10cSrcweir m_aTransparentObjects.back().m_pContentStream = static_cast<SvMemoryStream*>(endRedirect()); 8710cdf0e10cSrcweir m_aTransparentObjects.back().m_nExtGStateObject = createObject(); 8711cdf0e10cSrcweir 8712cdf0e10cSrcweir // draw soft mask 8713cdf0e10cSrcweir beginRedirect( new SvMemoryStream( 1024, 1024 ), Rectangle() ); 8714cdf0e10cSrcweir drawBitmap( rBoundingBox.TopLeft(), rBoundingBox.GetSize(), rAlphaMask ); 8715cdf0e10cSrcweir m_aTransparentObjects.back().m_pSoftMaskStream = static_cast<SvMemoryStream*>(endRedirect()); 8716cdf0e10cSrcweir 8717cdf0e10cSrcweir OStringBuffer aObjName( 16 ); 8718cdf0e10cSrcweir aObjName.append( "Tr" ); 8719cdf0e10cSrcweir aObjName.append( m_aTransparentObjects.back().m_nObject ); 8720cdf0e10cSrcweir OString aTrName( aObjName.makeStringAndClear() ); 8721cdf0e10cSrcweir aObjName.append( "EGS" ); 8722cdf0e10cSrcweir aObjName.append( m_aTransparentObjects.back().m_nExtGStateObject ); 8723cdf0e10cSrcweir OString aExtName( aObjName.makeStringAndClear() ); 8724cdf0e10cSrcweir 8725cdf0e10cSrcweir OStringBuffer aLine( 80 ); 8726cdf0e10cSrcweir // insert XObject 8727cdf0e10cSrcweir aLine.append( "q /" ); 8728cdf0e10cSrcweir aLine.append( aExtName ); 8729cdf0e10cSrcweir aLine.append( " gs /" ); 8730cdf0e10cSrcweir aLine.append( aTrName ); 8731cdf0e10cSrcweir aLine.append( " Do Q\n" ); 8732cdf0e10cSrcweir writeBuffer( aLine.getStr(), aLine.getLength() ); 8733cdf0e10cSrcweir 8734cdf0e10cSrcweir pushResource( ResXObject, aTrName, m_aTransparentObjects.back().m_nObject ); 8735cdf0e10cSrcweir pushResource( ResExtGState, aExtName, m_aTransparentObjects.back().m_nExtGStateObject ); 8736cdf0e10cSrcweir } 8737cdf0e10cSrcweir } 8738cdf0e10cSrcweir 8739cdf0e10cSrcweir void PDFWriterImpl::drawRectangle( const Rectangle& rRect ) 8740cdf0e10cSrcweir { 8741cdf0e10cSrcweir MARK( "drawRectangle" ); 8742cdf0e10cSrcweir 8743cdf0e10cSrcweir updateGraphicsState(); 8744cdf0e10cSrcweir 8745cdf0e10cSrcweir if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) && 8746cdf0e10cSrcweir m_aGraphicsStack.front().m_aFillColor == Color( COL_TRANSPARENT ) ) 8747cdf0e10cSrcweir return; 8748cdf0e10cSrcweir 8749cdf0e10cSrcweir OStringBuffer aLine( 40 ); 8750cdf0e10cSrcweir m_aPages.back().appendRect( rRect, aLine ); 8751cdf0e10cSrcweir 8752cdf0e10cSrcweir if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) && 8753cdf0e10cSrcweir m_aGraphicsStack.front().m_aFillColor != Color( COL_TRANSPARENT ) ) 8754cdf0e10cSrcweir aLine.append( " B*\n" ); 8755cdf0e10cSrcweir else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) ) 8756cdf0e10cSrcweir aLine.append( " S\n" ); 8757cdf0e10cSrcweir else 8758cdf0e10cSrcweir aLine.append( " f*\n" ); 8759cdf0e10cSrcweir 8760cdf0e10cSrcweir writeBuffer( aLine.getStr(), aLine.getLength() ); 8761cdf0e10cSrcweir } 8762cdf0e10cSrcweir 8763cdf0e10cSrcweir void PDFWriterImpl::drawRectangle( const Rectangle& rRect, sal_uInt32 nHorzRound, sal_uInt32 nVertRound ) 8764cdf0e10cSrcweir { 8765cdf0e10cSrcweir MARK( "drawRectangle with rounded edges" ); 8766cdf0e10cSrcweir 8767cdf0e10cSrcweir if( !nHorzRound && !nVertRound ) 8768cdf0e10cSrcweir drawRectangle( rRect ); 8769cdf0e10cSrcweir 8770cdf0e10cSrcweir updateGraphicsState(); 8771cdf0e10cSrcweir 8772cdf0e10cSrcweir if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) && 8773cdf0e10cSrcweir m_aGraphicsStack.front().m_aFillColor == Color( COL_TRANSPARENT ) ) 8774cdf0e10cSrcweir return; 8775cdf0e10cSrcweir 8776cdf0e10cSrcweir if( nHorzRound > (sal_uInt32)rRect.GetWidth()/2 ) 8777cdf0e10cSrcweir nHorzRound = rRect.GetWidth()/2; 8778cdf0e10cSrcweir if( nVertRound > (sal_uInt32)rRect.GetHeight()/2 ) 8779cdf0e10cSrcweir nVertRound = rRect.GetHeight()/2; 8780cdf0e10cSrcweir 8781cdf0e10cSrcweir Point aPoints[16]; 8782cdf0e10cSrcweir const double kappa = 0.5522847498; 8783cdf0e10cSrcweir const sal_uInt32 kx = (sal_uInt32)((kappa*(double)nHorzRound)+0.5); 8784cdf0e10cSrcweir const sal_uInt32 ky = (sal_uInt32)((kappa*(double)nVertRound)+0.5); 8785cdf0e10cSrcweir 8786cdf0e10cSrcweir aPoints[1] = Point( rRect.TopLeft().X() + nHorzRound, rRect.TopLeft().Y() ); 8787cdf0e10cSrcweir aPoints[0] = Point( aPoints[1].X() - kx, aPoints[1].Y() ); 8788cdf0e10cSrcweir aPoints[2] = Point( rRect.TopRight().X()+1 - nHorzRound, aPoints[1].Y() ); 8789cdf0e10cSrcweir aPoints[3] = Point( aPoints[2].X()+kx, aPoints[2].Y() ); 8790cdf0e10cSrcweir 8791cdf0e10cSrcweir aPoints[5] = Point( rRect.TopRight().X()+1, rRect.TopRight().Y()+nVertRound ); 8792cdf0e10cSrcweir aPoints[4] = Point( aPoints[5].X(), aPoints[5].Y()-ky ); 8793cdf0e10cSrcweir aPoints[6] = Point( aPoints[5].X(), rRect.BottomRight().Y()+1 - nVertRound ); 8794cdf0e10cSrcweir aPoints[7] = Point( aPoints[6].X(), aPoints[6].Y()+ky ); 8795cdf0e10cSrcweir 8796cdf0e10cSrcweir aPoints[9] = Point( rRect.BottomRight().X()+1-nHorzRound, rRect.BottomRight().Y()+1 ); 8797cdf0e10cSrcweir aPoints[8] = Point( aPoints[9].X()+kx, aPoints[9].Y() ); 8798cdf0e10cSrcweir aPoints[10] = Point( rRect.BottomLeft().X() + nHorzRound, aPoints[9].Y() ); 8799cdf0e10cSrcweir aPoints[11] = Point( aPoints[10].X()-kx, aPoints[10].Y() ); 8800cdf0e10cSrcweir 8801cdf0e10cSrcweir aPoints[13] = Point( rRect.BottomLeft().X(), rRect.BottomLeft().Y()+1-nVertRound ); 8802cdf0e10cSrcweir aPoints[12] = Point( aPoints[13].X(), aPoints[13].Y()+ky ); 8803cdf0e10cSrcweir aPoints[14] = Point( rRect.TopLeft().X(), rRect.TopLeft().Y()+nVertRound ); 8804cdf0e10cSrcweir aPoints[15] = Point( aPoints[14].X(), aPoints[14].Y()-ky ); 8805cdf0e10cSrcweir 8806cdf0e10cSrcweir 8807cdf0e10cSrcweir OStringBuffer aLine( 80 ); 8808cdf0e10cSrcweir m_aPages.back().appendPoint( aPoints[1], aLine ); 8809cdf0e10cSrcweir aLine.append( " m " ); 8810cdf0e10cSrcweir m_aPages.back().appendPoint( aPoints[2], aLine ); 8811cdf0e10cSrcweir aLine.append( " l " ); 8812cdf0e10cSrcweir m_aPages.back().appendPoint( aPoints[3], aLine ); 8813cdf0e10cSrcweir aLine.append( ' ' ); 8814cdf0e10cSrcweir m_aPages.back().appendPoint( aPoints[4], aLine ); 8815cdf0e10cSrcweir aLine.append( ' ' ); 8816cdf0e10cSrcweir m_aPages.back().appendPoint( aPoints[5], aLine ); 8817cdf0e10cSrcweir aLine.append( " c\n" ); 8818cdf0e10cSrcweir m_aPages.back().appendPoint( aPoints[6], aLine ); 8819cdf0e10cSrcweir aLine.append( " l " ); 8820cdf0e10cSrcweir m_aPages.back().appendPoint( aPoints[7], aLine ); 8821cdf0e10cSrcweir aLine.append( ' ' ); 8822cdf0e10cSrcweir m_aPages.back().appendPoint( aPoints[8], aLine ); 8823cdf0e10cSrcweir aLine.append( ' ' ); 8824cdf0e10cSrcweir m_aPages.back().appendPoint( aPoints[9], aLine ); 8825cdf0e10cSrcweir aLine.append( " c\n" ); 8826cdf0e10cSrcweir m_aPages.back().appendPoint( aPoints[10], aLine ); 8827cdf0e10cSrcweir aLine.append( " l " ); 8828cdf0e10cSrcweir m_aPages.back().appendPoint( aPoints[11], aLine ); 8829cdf0e10cSrcweir aLine.append( ' ' ); 8830cdf0e10cSrcweir m_aPages.back().appendPoint( aPoints[12], aLine ); 8831cdf0e10cSrcweir aLine.append( ' ' ); 8832cdf0e10cSrcweir m_aPages.back().appendPoint( aPoints[13], aLine ); 8833cdf0e10cSrcweir aLine.append( " c\n" ); 8834cdf0e10cSrcweir m_aPages.back().appendPoint( aPoints[14], aLine ); 8835cdf0e10cSrcweir aLine.append( " l " ); 8836cdf0e10cSrcweir m_aPages.back().appendPoint( aPoints[15], aLine ); 8837cdf0e10cSrcweir aLine.append( ' ' ); 8838cdf0e10cSrcweir m_aPages.back().appendPoint( aPoints[0], aLine ); 8839cdf0e10cSrcweir aLine.append( ' ' ); 8840cdf0e10cSrcweir m_aPages.back().appendPoint( aPoints[1], aLine ); 8841cdf0e10cSrcweir aLine.append( " c " ); 8842cdf0e10cSrcweir 8843cdf0e10cSrcweir if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) && 8844cdf0e10cSrcweir m_aGraphicsStack.front().m_aFillColor != Color( COL_TRANSPARENT ) ) 8845cdf0e10cSrcweir aLine.append( "b*\n" ); 8846cdf0e10cSrcweir else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) ) 8847cdf0e10cSrcweir aLine.append( "s\n" ); 8848cdf0e10cSrcweir else 8849cdf0e10cSrcweir aLine.append( "f*\n" ); 8850cdf0e10cSrcweir 8851cdf0e10cSrcweir writeBuffer( aLine.getStr(), aLine.getLength() ); 8852cdf0e10cSrcweir } 8853cdf0e10cSrcweir 8854cdf0e10cSrcweir void PDFWriterImpl::drawEllipse( const Rectangle& rRect ) 8855cdf0e10cSrcweir { 8856cdf0e10cSrcweir MARK( "drawEllipse" ); 8857cdf0e10cSrcweir 8858cdf0e10cSrcweir updateGraphicsState(); 8859cdf0e10cSrcweir 8860cdf0e10cSrcweir if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) && 8861cdf0e10cSrcweir m_aGraphicsStack.front().m_aFillColor == Color( COL_TRANSPARENT ) ) 8862cdf0e10cSrcweir return; 8863cdf0e10cSrcweir 8864cdf0e10cSrcweir Point aPoints[12]; 8865cdf0e10cSrcweir const double kappa = 0.5522847498; 8866cdf0e10cSrcweir const sal_uInt32 kx = (sal_uInt32)((kappa*(double)rRect.GetWidth()/2.0)+0.5); 8867cdf0e10cSrcweir const sal_uInt32 ky = (sal_uInt32)((kappa*(double)rRect.GetHeight()/2.0)+0.5); 8868cdf0e10cSrcweir 8869cdf0e10cSrcweir aPoints[1] = Point( rRect.TopLeft().X() + rRect.GetWidth()/2, rRect.TopLeft().Y() ); 8870cdf0e10cSrcweir aPoints[0] = Point( aPoints[1].X() - kx, aPoints[1].Y() ); 8871cdf0e10cSrcweir aPoints[2] = Point( aPoints[1].X() + kx, aPoints[1].Y() ); 8872cdf0e10cSrcweir 8873cdf0e10cSrcweir aPoints[4] = Point( rRect.TopRight().X()+1, rRect.TopRight().Y() + rRect.GetHeight()/2 ); 8874cdf0e10cSrcweir aPoints[3] = Point( aPoints[4].X(), aPoints[4].Y() - ky ); 8875cdf0e10cSrcweir aPoints[5] = Point( aPoints[4].X(), aPoints[4].Y() + ky ); 8876cdf0e10cSrcweir 8877cdf0e10cSrcweir aPoints[7] = Point( rRect.BottomLeft().X() + rRect.GetWidth()/2, rRect.BottomLeft().Y()+1 ); 8878cdf0e10cSrcweir aPoints[6] = Point( aPoints[7].X() + kx, aPoints[7].Y() ); 8879cdf0e10cSrcweir aPoints[8] = Point( aPoints[7].X() - kx, aPoints[7].Y() ); 8880cdf0e10cSrcweir 8881cdf0e10cSrcweir aPoints[10] = Point( rRect.TopLeft().X(), rRect.TopLeft().Y() + rRect.GetHeight()/2 ); 8882cdf0e10cSrcweir aPoints[9] = Point( aPoints[10].X(), aPoints[10].Y() + ky ); 8883cdf0e10cSrcweir aPoints[11] = Point( aPoints[10].X(), aPoints[10].Y() - ky ); 8884cdf0e10cSrcweir 8885cdf0e10cSrcweir OStringBuffer aLine( 80 ); 8886cdf0e10cSrcweir m_aPages.back().appendPoint( aPoints[1], aLine ); 8887cdf0e10cSrcweir aLine.append( " m " ); 8888cdf0e10cSrcweir m_aPages.back().appendPoint( aPoints[2], aLine ); 8889cdf0e10cSrcweir aLine.append( ' ' ); 8890cdf0e10cSrcweir m_aPages.back().appendPoint( aPoints[3], aLine ); 8891cdf0e10cSrcweir aLine.append( ' ' ); 8892cdf0e10cSrcweir m_aPages.back().appendPoint( aPoints[4], aLine ); 8893cdf0e10cSrcweir aLine.append( " c\n" ); 8894cdf0e10cSrcweir m_aPages.back().appendPoint( aPoints[5], aLine ); 8895cdf0e10cSrcweir aLine.append( ' ' ); 8896cdf0e10cSrcweir m_aPages.back().appendPoint( aPoints[6], aLine ); 8897cdf0e10cSrcweir aLine.append( ' ' ); 8898cdf0e10cSrcweir m_aPages.back().appendPoint( aPoints[7], aLine ); 8899cdf0e10cSrcweir aLine.append( " c\n" ); 8900cdf0e10cSrcweir m_aPages.back().appendPoint( aPoints[8], aLine ); 8901cdf0e10cSrcweir aLine.append( ' ' ); 8902cdf0e10cSrcweir m_aPages.back().appendPoint( aPoints[9], aLine ); 8903cdf0e10cSrcweir aLine.append( ' ' ); 8904cdf0e10cSrcweir m_aPages.back().appendPoint( aPoints[10], aLine ); 8905cdf0e10cSrcweir aLine.append( " c\n" ); 8906cdf0e10cSrcweir m_aPages.back().appendPoint( aPoints[11], aLine ); 8907cdf0e10cSrcweir aLine.append( ' ' ); 8908cdf0e10cSrcweir m_aPages.back().appendPoint( aPoints[0], aLine ); 8909cdf0e10cSrcweir aLine.append( ' ' ); 8910cdf0e10cSrcweir m_aPages.back().appendPoint( aPoints[1], aLine ); 8911cdf0e10cSrcweir aLine.append( " c " ); 8912cdf0e10cSrcweir 8913cdf0e10cSrcweir if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) && 8914cdf0e10cSrcweir m_aGraphicsStack.front().m_aFillColor != Color( COL_TRANSPARENT ) ) 8915cdf0e10cSrcweir aLine.append( "b*\n" ); 8916cdf0e10cSrcweir else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) ) 8917cdf0e10cSrcweir aLine.append( "s\n" ); 8918cdf0e10cSrcweir else 8919cdf0e10cSrcweir aLine.append( "f*\n" ); 8920cdf0e10cSrcweir 8921cdf0e10cSrcweir writeBuffer( aLine.getStr(), aLine.getLength() ); 8922cdf0e10cSrcweir } 8923cdf0e10cSrcweir 8924cdf0e10cSrcweir static double calcAngle( const Rectangle& rRect, const Point& rPoint ) 8925cdf0e10cSrcweir { 8926cdf0e10cSrcweir Point aOrigin((rRect.Left()+rRect.Right()+1)/2, 8927cdf0e10cSrcweir (rRect.Top()+rRect.Bottom()+1)/2); 8928cdf0e10cSrcweir Point aPoint = rPoint - aOrigin; 8929cdf0e10cSrcweir 8930cdf0e10cSrcweir double fX = (double)aPoint.X(); 8931cdf0e10cSrcweir double fY = (double)-aPoint.Y(); 8932cdf0e10cSrcweir 8933cdf0e10cSrcweir if( rRect.GetWidth() > rRect.GetHeight() ) 8934cdf0e10cSrcweir fY = fY*((double)rRect.GetWidth()/(double)rRect.GetHeight()); 8935cdf0e10cSrcweir else if( rRect.GetHeight() > rRect.GetWidth() ) 8936cdf0e10cSrcweir fX = fX*((double)rRect.GetHeight()/(double)rRect.GetWidth()); 8937cdf0e10cSrcweir return atan2( fY, fX ); 8938cdf0e10cSrcweir } 8939cdf0e10cSrcweir 8940cdf0e10cSrcweir void PDFWriterImpl::drawArc( const Rectangle& rRect, const Point& rStart, const Point& rStop, bool bWithPie, bool bWithChord ) 8941cdf0e10cSrcweir { 8942cdf0e10cSrcweir MARK( "drawArc" ); 8943cdf0e10cSrcweir 8944cdf0e10cSrcweir updateGraphicsState(); 8945cdf0e10cSrcweir 8946cdf0e10cSrcweir if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) && 8947cdf0e10cSrcweir m_aGraphicsStack.front().m_aFillColor == Color( COL_TRANSPARENT ) ) 8948cdf0e10cSrcweir return; 8949cdf0e10cSrcweir 8950cdf0e10cSrcweir // calculate start and stop angles 8951cdf0e10cSrcweir const double fStartAngle = calcAngle( rRect, rStart ); 8952cdf0e10cSrcweir double fStopAngle = calcAngle( rRect, rStop ); 8953cdf0e10cSrcweir while( fStopAngle < fStartAngle ) 8954cdf0e10cSrcweir fStopAngle += 2.0*M_PI; 8955cdf0e10cSrcweir const int nFragments = (int)((fStopAngle-fStartAngle)/(M_PI/2.0))+1; 8956cdf0e10cSrcweir const double fFragmentDelta = (fStopAngle-fStartAngle)/(double)nFragments; 8957cdf0e10cSrcweir const double kappa = fabs( 4.0 * (1.0-cos(fFragmentDelta/2.0))/sin(fFragmentDelta/2.0) / 3.0); 8958cdf0e10cSrcweir const double halfWidth = (double)rRect.GetWidth()/2.0; 8959cdf0e10cSrcweir const double halfHeight = (double)rRect.GetHeight()/2.0; 8960cdf0e10cSrcweir 8961cdf0e10cSrcweir const Point aCenter( (rRect.Left()+rRect.Right()+1)/2, 8962cdf0e10cSrcweir (rRect.Top()+rRect.Bottom()+1)/2 ); 8963cdf0e10cSrcweir 8964cdf0e10cSrcweir OStringBuffer aLine( 30*nFragments ); 8965cdf0e10cSrcweir Point aPoint( (int)(halfWidth * cos(fStartAngle) ), 8966cdf0e10cSrcweir -(int)(halfHeight * sin(fStartAngle) ) ); 8967cdf0e10cSrcweir aPoint += aCenter; 8968cdf0e10cSrcweir m_aPages.back().appendPoint( aPoint, aLine ); 8969cdf0e10cSrcweir aLine.append( " m " ); 8970cdf0e10cSrcweir if( !basegfx::fTools::equal(fStartAngle, fStopAngle) ) 8971cdf0e10cSrcweir { 8972cdf0e10cSrcweir for( int i = 0; i < nFragments; i++ ) 8973cdf0e10cSrcweir { 8974cdf0e10cSrcweir const double fStartFragment = fStartAngle + (double)i*fFragmentDelta; 8975cdf0e10cSrcweir const double fStopFragment = fStartFragment + fFragmentDelta; 8976cdf0e10cSrcweir aPoint = Point( (int)(halfWidth * (cos(fStartFragment) - kappa*sin(fStartFragment) ) ), 8977cdf0e10cSrcweir -(int)(halfHeight * (sin(fStartFragment) + kappa*cos(fStartFragment) ) ) ); 8978cdf0e10cSrcweir aPoint += aCenter; 8979cdf0e10cSrcweir m_aPages.back().appendPoint( aPoint, aLine ); 8980cdf0e10cSrcweir aLine.append( ' ' ); 8981cdf0e10cSrcweir 8982cdf0e10cSrcweir aPoint = Point( (int)(halfWidth * (cos(fStopFragment) + kappa*sin(fStopFragment) ) ), 8983cdf0e10cSrcweir -(int)(halfHeight * (sin(fStopFragment) - kappa*cos(fStopFragment) ) ) ); 8984cdf0e10cSrcweir aPoint += aCenter; 8985cdf0e10cSrcweir m_aPages.back().appendPoint( aPoint, aLine ); 8986cdf0e10cSrcweir aLine.append( ' ' ); 8987cdf0e10cSrcweir 8988cdf0e10cSrcweir aPoint = Point( (int)(halfWidth * cos(fStopFragment) ), 8989cdf0e10cSrcweir -(int)(halfHeight * sin(fStopFragment) ) ); 8990cdf0e10cSrcweir aPoint += aCenter; 8991cdf0e10cSrcweir m_aPages.back().appendPoint( aPoint, aLine ); 8992cdf0e10cSrcweir aLine.append( " c\n" ); 8993cdf0e10cSrcweir } 8994cdf0e10cSrcweir } 8995cdf0e10cSrcweir if( bWithChord || bWithPie ) 8996cdf0e10cSrcweir { 8997cdf0e10cSrcweir if( bWithPie ) 8998cdf0e10cSrcweir { 8999cdf0e10cSrcweir m_aPages.back().appendPoint( aCenter, aLine ); 9000cdf0e10cSrcweir aLine.append( " l " ); 9001cdf0e10cSrcweir } 9002cdf0e10cSrcweir aLine.append( "h " ); 9003cdf0e10cSrcweir } 9004cdf0e10cSrcweir if( ! bWithChord && ! bWithPie ) 9005cdf0e10cSrcweir aLine.append( "S\n" ); 9006cdf0e10cSrcweir else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) && 9007cdf0e10cSrcweir m_aGraphicsStack.front().m_aFillColor != Color( COL_TRANSPARENT ) ) 9008cdf0e10cSrcweir aLine.append( "B*\n" ); 9009cdf0e10cSrcweir else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) ) 9010cdf0e10cSrcweir aLine.append( "S\n" ); 9011cdf0e10cSrcweir else 9012cdf0e10cSrcweir aLine.append( "f*\n" ); 9013cdf0e10cSrcweir 9014cdf0e10cSrcweir writeBuffer( aLine.getStr(), aLine.getLength() ); 9015cdf0e10cSrcweir } 9016cdf0e10cSrcweir 9017cdf0e10cSrcweir void PDFWriterImpl::drawPolyLine( const Polygon& rPoly ) 9018cdf0e10cSrcweir { 9019cdf0e10cSrcweir MARK( "drawPolyLine" ); 9020cdf0e10cSrcweir 9021cdf0e10cSrcweir sal_uInt16 nPoints = rPoly.GetSize(); 9022cdf0e10cSrcweir if( nPoints < 2 ) 9023cdf0e10cSrcweir return; 9024cdf0e10cSrcweir 9025cdf0e10cSrcweir updateGraphicsState(); 9026cdf0e10cSrcweir 9027cdf0e10cSrcweir if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) ) 9028cdf0e10cSrcweir return; 9029cdf0e10cSrcweir 9030cdf0e10cSrcweir OStringBuffer aLine( 20 * nPoints ); 9031cdf0e10cSrcweir m_aPages.back().appendPolygon( rPoly, aLine, rPoly[0] == rPoly[nPoints-1] ); 9032cdf0e10cSrcweir aLine.append( "S\n" ); 9033cdf0e10cSrcweir 9034cdf0e10cSrcweir writeBuffer( aLine.getStr(), aLine.getLength() ); 9035cdf0e10cSrcweir } 9036cdf0e10cSrcweir 9037cdf0e10cSrcweir void PDFWriterImpl::drawPolyLine( const Polygon& rPoly, const LineInfo& rInfo ) 9038cdf0e10cSrcweir { 9039cdf0e10cSrcweir MARK( "drawPolyLine with LineInfo" ); 9040cdf0e10cSrcweir 9041cdf0e10cSrcweir updateGraphicsState(); 9042cdf0e10cSrcweir 9043cdf0e10cSrcweir if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) ) 9044cdf0e10cSrcweir return; 9045cdf0e10cSrcweir 9046cdf0e10cSrcweir OStringBuffer aLine; 9047cdf0e10cSrcweir aLine.append( "q " ); 9048cdf0e10cSrcweir if( m_aPages.back().appendLineInfo( rInfo, aLine ) ) 9049cdf0e10cSrcweir { 9050cdf0e10cSrcweir writeBuffer( aLine.getStr(), aLine.getLength() ); 9051cdf0e10cSrcweir drawPolyLine( rPoly ); 9052cdf0e10cSrcweir writeBuffer( "Q\n", 2 ); 9053cdf0e10cSrcweir } 9054cdf0e10cSrcweir else 9055cdf0e10cSrcweir { 9056cdf0e10cSrcweir PDFWriter::ExtLineInfo aInfo; 9057cdf0e10cSrcweir convertLineInfoToExtLineInfo( rInfo, aInfo ); 9058cdf0e10cSrcweir drawPolyLine( rPoly, aInfo ); 9059cdf0e10cSrcweir } 9060cdf0e10cSrcweir } 9061cdf0e10cSrcweir 9062cdf0e10cSrcweir void PDFWriterImpl::convertLineInfoToExtLineInfo( const LineInfo& rIn, PDFWriter::ExtLineInfo& rOut ) 9063cdf0e10cSrcweir { 9064cdf0e10cSrcweir DBG_ASSERT( rIn.GetStyle() == LINE_DASH, "invalid conversion" ); 9065cdf0e10cSrcweir rOut.m_fLineWidth = rIn.GetWidth(); 9066cdf0e10cSrcweir rOut.m_fTransparency = 0.0; 9067cdf0e10cSrcweir rOut.m_eCap = PDFWriter::capButt; 9068cdf0e10cSrcweir rOut.m_eJoin = PDFWriter::joinMiter; 9069cdf0e10cSrcweir rOut.m_fMiterLimit = 10; 9070cdf0e10cSrcweir rOut.m_aDashArray.clear(); 9071cdf0e10cSrcweir 90725aaf853bSArmin Le Grand // add DashDot to DashArray 90735aaf853bSArmin Le Grand const int nDashes = rIn.GetDashCount(); 90745aaf853bSArmin Le Grand const int nDashLen = rIn.GetDashLen(); 90755aaf853bSArmin Le Grand const int nDistance = rIn.GetDistance(); 90765aaf853bSArmin Le Grand 9077cdf0e10cSrcweir for( int n = 0; n < nDashes; n++ ) 9078cdf0e10cSrcweir { 9079cdf0e10cSrcweir rOut.m_aDashArray.push_back( nDashLen ); 9080cdf0e10cSrcweir rOut.m_aDashArray.push_back( nDistance ); 9081cdf0e10cSrcweir } 90825aaf853bSArmin Le Grand 90835aaf853bSArmin Le Grand const int nDots = rIn.GetDotCount(); 90845aaf853bSArmin Le Grand const int nDotLen = rIn.GetDotLen(); 90855aaf853bSArmin Le Grand 9086cdf0e10cSrcweir for( int n = 0; n < nDots; n++ ) 9087cdf0e10cSrcweir { 9088cdf0e10cSrcweir rOut.m_aDashArray.push_back( nDotLen ); 9089cdf0e10cSrcweir rOut.m_aDashArray.push_back( nDistance ); 9090cdf0e10cSrcweir } 90915aaf853bSArmin Le Grand 90925aaf853bSArmin Le Grand // add LineJoin 90935aaf853bSArmin Le Grand switch(rIn.GetLineJoin()) 90945aaf853bSArmin Le Grand { 90955aaf853bSArmin Le Grand case basegfx::B2DLINEJOIN_BEVEL : 90965aaf853bSArmin Le Grand { 90975aaf853bSArmin Le Grand rOut.m_eJoin = PDFWriter::joinBevel; 90985aaf853bSArmin Le Grand break; 90995aaf853bSArmin Le Grand } 91005aaf853bSArmin Le Grand default : // basegfx::B2DLINEJOIN_NONE : 91015aaf853bSArmin Le Grand // Pdf has no 'none' lineJoin, default is miter 91025aaf853bSArmin Le Grand case basegfx::B2DLINEJOIN_MIDDLE : 91035aaf853bSArmin Le Grand case basegfx::B2DLINEJOIN_MITER : 91045aaf853bSArmin Le Grand { 91055aaf853bSArmin Le Grand rOut.m_eJoin = PDFWriter::joinMiter; 91065aaf853bSArmin Le Grand break; 91075aaf853bSArmin Le Grand } 91085aaf853bSArmin Le Grand case basegfx::B2DLINEJOIN_ROUND : 91095aaf853bSArmin Le Grand { 91105aaf853bSArmin Le Grand rOut.m_eJoin = PDFWriter::joinRound; 91115aaf853bSArmin Le Grand break; 91125aaf853bSArmin Le Grand } 91135aaf853bSArmin Le Grand } 91145aaf853bSArmin Le Grand 91155aaf853bSArmin Le Grand // add LineCap 91165aaf853bSArmin Le Grand switch(rIn.GetLineCap()) 91175aaf853bSArmin Le Grand { 91185aaf853bSArmin Le Grand default: /* com::sun::star::drawing::LineCap_BUTT */ 91195aaf853bSArmin Le Grand { 91205aaf853bSArmin Le Grand rOut.m_eCap = PDFWriter::capButt; 91215aaf853bSArmin Le Grand break; 91225aaf853bSArmin Le Grand } 91235aaf853bSArmin Le Grand case com::sun::star::drawing::LineCap_ROUND: 91245aaf853bSArmin Le Grand { 91255aaf853bSArmin Le Grand rOut.m_eCap = PDFWriter::capRound; 91265aaf853bSArmin Le Grand break; 91275aaf853bSArmin Le Grand } 91285aaf853bSArmin Le Grand case com::sun::star::drawing::LineCap_SQUARE: 91295aaf853bSArmin Le Grand { 91305aaf853bSArmin Le Grand rOut.m_eCap = PDFWriter::capSquare; 91315aaf853bSArmin Le Grand break; 91325aaf853bSArmin Le Grand } 91335aaf853bSArmin Le Grand } 9134cdf0e10cSrcweir } 9135cdf0e10cSrcweir 9136cdf0e10cSrcweir void PDFWriterImpl::drawPolyLine( const Polygon& rPoly, const PDFWriter::ExtLineInfo& rInfo ) 9137cdf0e10cSrcweir { 9138cdf0e10cSrcweir MARK( "drawPolyLine with ExtLineInfo" ); 9139cdf0e10cSrcweir 9140cdf0e10cSrcweir updateGraphicsState(); 9141cdf0e10cSrcweir 9142cdf0e10cSrcweir if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) ) 9143cdf0e10cSrcweir return; 9144cdf0e10cSrcweir 9145cdf0e10cSrcweir if( rInfo.m_fTransparency >= 1.0 ) 9146cdf0e10cSrcweir return; 9147cdf0e10cSrcweir 9148cdf0e10cSrcweir if( rInfo.m_fTransparency != 0.0 ) 9149cdf0e10cSrcweir beginTransparencyGroup(); 9150cdf0e10cSrcweir 9151cdf0e10cSrcweir OStringBuffer aLine; 9152cdf0e10cSrcweir aLine.append( "q " ); 9153cdf0e10cSrcweir m_aPages.back().appendMappedLength( rInfo.m_fLineWidth, aLine ); 9154cdf0e10cSrcweir aLine.append( " w" ); 9155cdf0e10cSrcweir if( rInfo.m_aDashArray.size() < 10 ) // implmentation limit of acrobat reader 9156cdf0e10cSrcweir { 9157cdf0e10cSrcweir switch( rInfo.m_eCap ) 9158cdf0e10cSrcweir { 9159cdf0e10cSrcweir default: 9160cdf0e10cSrcweir case PDFWriter::capButt: aLine.append( " 0 J" );break; 9161cdf0e10cSrcweir case PDFWriter::capRound: aLine.append( " 1 J" );break; 9162cdf0e10cSrcweir case PDFWriter::capSquare: aLine.append( " 2 J" );break; 9163cdf0e10cSrcweir } 9164cdf0e10cSrcweir switch( rInfo.m_eJoin ) 9165cdf0e10cSrcweir { 9166cdf0e10cSrcweir default: 9167cdf0e10cSrcweir case PDFWriter::joinMiter: 9168cdf0e10cSrcweir { 9169cdf0e10cSrcweir double fLimit = rInfo.m_fMiterLimit; 9170cdf0e10cSrcweir if( rInfo.m_fLineWidth < rInfo.m_fMiterLimit ) 9171cdf0e10cSrcweir fLimit = fLimit / rInfo.m_fLineWidth; 9172cdf0e10cSrcweir if( fLimit < 1.0 ) 9173cdf0e10cSrcweir fLimit = 1.0; 9174cdf0e10cSrcweir aLine.append( " 0 j " ); 9175cdf0e10cSrcweir appendDouble( fLimit, aLine ); 9176cdf0e10cSrcweir aLine.append( " M" ); 9177cdf0e10cSrcweir } 9178cdf0e10cSrcweir break; 9179cdf0e10cSrcweir case PDFWriter::joinRound: aLine.append( " 1 j" );break; 9180cdf0e10cSrcweir case PDFWriter::joinBevel: aLine.append( " 2 j" );break; 9181cdf0e10cSrcweir } 9182cdf0e10cSrcweir if( rInfo.m_aDashArray.size() > 0 ) 9183cdf0e10cSrcweir { 9184cdf0e10cSrcweir aLine.append( " [ " ); 9185cdf0e10cSrcweir for( std::vector<double>::const_iterator it = rInfo.m_aDashArray.begin(); 9186cdf0e10cSrcweir it != rInfo.m_aDashArray.end(); ++it ) 9187cdf0e10cSrcweir { 9188cdf0e10cSrcweir m_aPages.back().appendMappedLength( *it, aLine ); 9189cdf0e10cSrcweir aLine.append( ' ' ); 9190cdf0e10cSrcweir } 9191cdf0e10cSrcweir aLine.append( "] 0 d" ); 9192cdf0e10cSrcweir } 9193cdf0e10cSrcweir aLine.append( "\n" ); 9194cdf0e10cSrcweir writeBuffer( aLine.getStr(), aLine.getLength() ); 9195cdf0e10cSrcweir drawPolyLine( rPoly ); 9196cdf0e10cSrcweir } 9197cdf0e10cSrcweir else 9198cdf0e10cSrcweir { 9199cdf0e10cSrcweir basegfx::B2DPolygon aPoly(rPoly.getB2DPolygon()); 9200cdf0e10cSrcweir basegfx::B2DPolyPolygon aPolyPoly; 9201cdf0e10cSrcweir 9202cdf0e10cSrcweir basegfx::tools::applyLineDashing(aPoly, rInfo.m_aDashArray, &aPolyPoly); 9203cdf0e10cSrcweir 9204cdf0e10cSrcweir // Old applyLineDashing subdivided the polygon. New one will create bezier curve segments. 9205cdf0e10cSrcweir // To mimic old behaviour, apply subdivide here. If beziers shall be written (better quality) 9206cdf0e10cSrcweir // this line needs to be removed and the loop below adapted accordingly 9207cdf0e10cSrcweir aPolyPoly = basegfx::tools::adaptiveSubdivideByAngle(aPolyPoly); 9208cdf0e10cSrcweir 9209cdf0e10cSrcweir const sal_uInt32 nPolygonCount(aPolyPoly.count()); 9210cdf0e10cSrcweir 9211cdf0e10cSrcweir for( sal_uInt32 nPoly = 0; nPoly < nPolygonCount; nPoly++ ) 9212cdf0e10cSrcweir { 9213cdf0e10cSrcweir aLine.append( (nPoly != 0 && (nPoly & 7) == 0) ? "\n" : " " ); 9214cdf0e10cSrcweir aPoly = aPolyPoly.getB2DPolygon( nPoly ); 9215cdf0e10cSrcweir const sal_uInt32 nPointCount(aPoly.count()); 9216cdf0e10cSrcweir 9217cdf0e10cSrcweir if(nPointCount) 9218cdf0e10cSrcweir { 9219cdf0e10cSrcweir const sal_uInt32 nEdgeCount(aPoly.isClosed() ? nPointCount : nPointCount - 1); 9220cdf0e10cSrcweir basegfx::B2DPoint aCurrent(aPoly.getB2DPoint(0)); 9221cdf0e10cSrcweir 9222cdf0e10cSrcweir for(sal_uInt32 a(0); a < nEdgeCount; a++) 9223cdf0e10cSrcweir { 9224cdf0e10cSrcweir if( a > 0 ) 9225cdf0e10cSrcweir aLine.append( " " ); 9226cdf0e10cSrcweir const sal_uInt32 nNextIndex((a + 1) % nPointCount); 9227cdf0e10cSrcweir const basegfx::B2DPoint aNext(aPoly.getB2DPoint(nNextIndex)); 9228cdf0e10cSrcweir 9229cdf0e10cSrcweir m_aPages.back().appendPoint( Point( FRound(aCurrent.getX()), 9230cdf0e10cSrcweir FRound(aCurrent.getY()) ), 9231cdf0e10cSrcweir aLine ); 9232cdf0e10cSrcweir aLine.append( " m " ); 9233cdf0e10cSrcweir m_aPages.back().appendPoint( Point( FRound(aNext.getX()), 9234cdf0e10cSrcweir FRound(aNext.getY()) ), 9235cdf0e10cSrcweir aLine ); 9236cdf0e10cSrcweir aLine.append( " l" ); 9237cdf0e10cSrcweir 9238cdf0e10cSrcweir // prepare next edge 9239cdf0e10cSrcweir aCurrent = aNext; 9240cdf0e10cSrcweir } 9241cdf0e10cSrcweir } 9242cdf0e10cSrcweir } 9243cdf0e10cSrcweir aLine.append( " S " ); 9244cdf0e10cSrcweir writeBuffer( aLine.getStr(), aLine.getLength() ); 9245cdf0e10cSrcweir } 9246cdf0e10cSrcweir writeBuffer( "Q\n", 2 ); 9247cdf0e10cSrcweir 9248cdf0e10cSrcweir if( rInfo.m_fTransparency != 0.0 ) 9249cdf0e10cSrcweir { 9250cdf0e10cSrcweir // FIXME: actually this may be incorrect with bezier polygons 9251cdf0e10cSrcweir Rectangle aBoundRect( rPoly.GetBoundRect() ); 9252cdf0e10cSrcweir // avoid clipping with thick lines 9253cdf0e10cSrcweir if( rInfo.m_fLineWidth > 0.0 ) 9254cdf0e10cSrcweir { 9255cdf0e10cSrcweir sal_Int32 nLW = sal_Int32(rInfo.m_fLineWidth); 9256cdf0e10cSrcweir aBoundRect.Top() -= nLW; 9257cdf0e10cSrcweir aBoundRect.Left() -= nLW; 9258cdf0e10cSrcweir aBoundRect.Right() += nLW; 9259cdf0e10cSrcweir aBoundRect.Bottom() += nLW; 9260cdf0e10cSrcweir } 9261cdf0e10cSrcweir endTransparencyGroup( aBoundRect, (sal_uInt16)(100.0*rInfo.m_fTransparency) ); 9262cdf0e10cSrcweir } 9263cdf0e10cSrcweir } 9264cdf0e10cSrcweir 9265cdf0e10cSrcweir void PDFWriterImpl::drawPixel( const Point& rPoint, const Color& rColor ) 9266cdf0e10cSrcweir { 9267cdf0e10cSrcweir MARK( "drawPixel" ); 9268cdf0e10cSrcweir 9269cdf0e10cSrcweir Color aColor = ( rColor == Color( COL_TRANSPARENT ) ? m_aGraphicsStack.front().m_aLineColor : rColor ); 9270cdf0e10cSrcweir 9271cdf0e10cSrcweir if( aColor == Color( COL_TRANSPARENT ) ) 9272cdf0e10cSrcweir return; 9273cdf0e10cSrcweir 9274cdf0e10cSrcweir // pixels are drawn in line color, so have to set 9275cdf0e10cSrcweir // the nonstroking color to line color 9276cdf0e10cSrcweir Color aOldFillColor = m_aGraphicsStack.front().m_aFillColor; 9277cdf0e10cSrcweir setFillColor( aColor ); 9278cdf0e10cSrcweir 9279cdf0e10cSrcweir updateGraphicsState(); 9280cdf0e10cSrcweir 9281cdf0e10cSrcweir OStringBuffer aLine( 20 ); 9282cdf0e10cSrcweir m_aPages.back().appendPoint( rPoint, aLine ); 9283cdf0e10cSrcweir aLine.append( ' ' ); 9284cdf0e10cSrcweir appendDouble( 1.0/double(getReferenceDevice()->ImplGetDPIX()), aLine ); 9285cdf0e10cSrcweir aLine.append( ' ' ); 9286cdf0e10cSrcweir appendDouble( 1.0/double(getReferenceDevice()->ImplGetDPIY()), aLine ); 9287cdf0e10cSrcweir aLine.append( " re f\n" ); 9288cdf0e10cSrcweir writeBuffer( aLine.getStr(), aLine.getLength() ); 9289cdf0e10cSrcweir 9290cdf0e10cSrcweir setFillColor( aOldFillColor ); 9291cdf0e10cSrcweir } 9292cdf0e10cSrcweir 9293cdf0e10cSrcweir void PDFWriterImpl::drawPixel( const Polygon& rPoints, const Color* pColors ) 9294cdf0e10cSrcweir { 9295cdf0e10cSrcweir MARK( "drawPixel with Polygon" ); 9296cdf0e10cSrcweir 9297cdf0e10cSrcweir updateGraphicsState(); 9298cdf0e10cSrcweir 9299cdf0e10cSrcweir if( m_aGraphicsStack.front().m_aLineColor == Color( COL_TRANSPARENT ) && ! pColors ) 9300cdf0e10cSrcweir return; 9301cdf0e10cSrcweir 9302cdf0e10cSrcweir sal_uInt16 nPoints = rPoints.GetSize(); 9303cdf0e10cSrcweir OStringBuffer aLine( nPoints*40 ); 9304cdf0e10cSrcweir aLine.append( "q " ); 9305cdf0e10cSrcweir if( ! pColors ) 9306cdf0e10cSrcweir { 9307cdf0e10cSrcweir appendNonStrokingColor( m_aGraphicsStack.front().m_aLineColor, aLine ); 9308cdf0e10cSrcweir aLine.append( ' ' ); 9309cdf0e10cSrcweir } 9310cdf0e10cSrcweir 9311cdf0e10cSrcweir OStringBuffer aPixel(32); 9312cdf0e10cSrcweir aPixel.append( ' ' ); 9313cdf0e10cSrcweir appendDouble( 1.0/double(getReferenceDevice()->ImplGetDPIX()), aPixel ); 9314cdf0e10cSrcweir aPixel.append( ' ' ); 9315cdf0e10cSrcweir appendDouble( 1.0/double(getReferenceDevice()->ImplGetDPIY()), aPixel ); 9316cdf0e10cSrcweir OString aPixelStr = aPixel.makeStringAndClear(); 9317cdf0e10cSrcweir for( sal_uInt16 i = 0; i < nPoints; i++ ) 9318cdf0e10cSrcweir { 9319cdf0e10cSrcweir if( pColors ) 9320cdf0e10cSrcweir { 9321cdf0e10cSrcweir if( pColors[i] == Color( COL_TRANSPARENT ) ) 9322cdf0e10cSrcweir continue; 9323cdf0e10cSrcweir 9324cdf0e10cSrcweir appendNonStrokingColor( pColors[i], aLine ); 9325cdf0e10cSrcweir aLine.append( ' ' ); 9326cdf0e10cSrcweir } 9327cdf0e10cSrcweir m_aPages.back().appendPoint( rPoints[i], aLine ); 9328cdf0e10cSrcweir aLine.append( aPixelStr ); 9329cdf0e10cSrcweir aLine.append( " re f\n" ); 9330cdf0e10cSrcweir } 9331cdf0e10cSrcweir aLine.append( "Q\n" ); 9332cdf0e10cSrcweir writeBuffer( aLine.getStr(), aLine.getLength() ); 9333cdf0e10cSrcweir } 9334cdf0e10cSrcweir 9335cdf0e10cSrcweir class AccessReleaser 9336cdf0e10cSrcweir { 9337cdf0e10cSrcweir BitmapReadAccess* m_pAccess; 9338cdf0e10cSrcweir public: 9339cdf0e10cSrcweir AccessReleaser( BitmapReadAccess* pAccess ) : m_pAccess( pAccess ){} 9340cdf0e10cSrcweir ~AccessReleaser() { delete m_pAccess; } 9341cdf0e10cSrcweir }; 9342cdf0e10cSrcweir 9343cdf0e10cSrcweir bool PDFWriterImpl::writeTransparentObject( TransparencyEmit& rObject ) 9344cdf0e10cSrcweir { 9345cdf0e10cSrcweir CHECK_RETURN( updateObject( rObject.m_nObject ) ); 9346cdf0e10cSrcweir 9347cdf0e10cSrcweir bool bFlateFilter = compressStream( rObject.m_pContentStream ); 9348cdf0e10cSrcweir rObject.m_pContentStream->Seek( STREAM_SEEK_TO_END ); 9349cdf0e10cSrcweir sal_uLong nSize = rObject.m_pContentStream->Tell(); 9350cdf0e10cSrcweir rObject.m_pContentStream->Seek( STREAM_SEEK_TO_BEGIN ); 9351cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 9352cdf0e10cSrcweir emitComment( "PDFWriterImpl::writeTransparentObject" ); 9353cdf0e10cSrcweir #endif 9354cdf0e10cSrcweir OStringBuffer aLine( 512 ); 9355cdf0e10cSrcweir CHECK_RETURN( updateObject( rObject.m_nObject ) ); 9356cdf0e10cSrcweir aLine.append( rObject.m_nObject ); 9357cdf0e10cSrcweir aLine.append( " 0 obj\n" 9358cdf0e10cSrcweir "<</Type/XObject\n" 9359cdf0e10cSrcweir "/Subtype/Form\n" 9360cdf0e10cSrcweir "/BBox[ " ); 9361cdf0e10cSrcweir appendFixedInt( rObject.m_aBoundRect.Left(), aLine ); 9362cdf0e10cSrcweir aLine.append( ' ' ); 9363cdf0e10cSrcweir appendFixedInt( rObject.m_aBoundRect.Top(), aLine ); 9364cdf0e10cSrcweir aLine.append( ' ' ); 9365cdf0e10cSrcweir appendFixedInt( rObject.m_aBoundRect.Right(), aLine ); 9366cdf0e10cSrcweir aLine.append( ' ' ); 9367cdf0e10cSrcweir appendFixedInt( rObject.m_aBoundRect.Bottom()+1, aLine ); 9368cdf0e10cSrcweir aLine.append( " ]\n" ); 9369cdf0e10cSrcweir if( ! rObject.m_pSoftMaskStream ) 9370cdf0e10cSrcweir { 9371cdf0e10cSrcweir if( ! m_bIsPDF_A1 ) 9372cdf0e10cSrcweir { 9373cdf0e10cSrcweir aLine.append( "/Group<</S/Transparency/CS/DeviceRGB/K true>>\n" ); 9374cdf0e10cSrcweir } 9375cdf0e10cSrcweir } 9376cdf0e10cSrcweir /* #i42884# the PDF reference recommends that each Form XObject 9377cdf0e10cSrcweir * should have a resource dict; alas if that is the same object 9378cdf0e10cSrcweir * as the one of the page it triggers an endless recursion in 9379cdf0e10cSrcweir * acroread 5 (6 and up have that fixed). Since we have only one 9380cdf0e10cSrcweir * resource dict anyway, let's use the one from the page by NOT 9381cdf0e10cSrcweir * emitting a Resources entry. 9382cdf0e10cSrcweir */ 9383cdf0e10cSrcweir #if 0 9384cdf0e10cSrcweir aLine.append( " /Resources " ); 9385cdf0e10cSrcweir aLine.append( getResourceDictObj() ); 9386cdf0e10cSrcweir aLine.append( " 0 R\n" ); 9387cdf0e10cSrcweir #endif 9388cdf0e10cSrcweir 9389cdf0e10cSrcweir aLine.append( "/Length " ); 9390cdf0e10cSrcweir aLine.append( (sal_Int32)(nSize) ); 9391cdf0e10cSrcweir aLine.append( "\n" ); 9392cdf0e10cSrcweir if( bFlateFilter ) 9393cdf0e10cSrcweir aLine.append( "/Filter/FlateDecode\n" ); 9394cdf0e10cSrcweir aLine.append( ">>\n" 9395cdf0e10cSrcweir "stream\n" ); 9396cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) ); 9397cdf0e10cSrcweir checkAndEnableStreamEncryption( rObject.m_nObject ); 9398cdf0e10cSrcweir CHECK_RETURN( writeBuffer( rObject.m_pContentStream->GetData(), nSize ) ); 9399cdf0e10cSrcweir disableStreamEncryption(); 9400cdf0e10cSrcweir aLine.setLength( 0 ); 9401cdf0e10cSrcweir aLine.append( "\n" 9402cdf0e10cSrcweir "endstream\n" 9403cdf0e10cSrcweir "endobj\n\n" ); 9404cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) ); 9405cdf0e10cSrcweir 9406cdf0e10cSrcweir // write ExtGState dict for this XObject 9407cdf0e10cSrcweir aLine.setLength( 0 ); 9408cdf0e10cSrcweir aLine.append( rObject.m_nExtGStateObject ); 9409cdf0e10cSrcweir aLine.append( " 0 obj\n" 9410cdf0e10cSrcweir "<<" ); 9411cdf0e10cSrcweir if( ! rObject.m_pSoftMaskStream ) 9412cdf0e10cSrcweir { 9413cdf0e10cSrcweir //i59651 9414cdf0e10cSrcweir if( m_bIsPDF_A1 ) 9415cdf0e10cSrcweir { 9416cdf0e10cSrcweir aLine.append( "/CA 1.0/ca 1.0" ); 9417cdf0e10cSrcweir m_aErrors.insert( PDFWriter::Warning_Transparency_Omitted_PDFA ); 9418cdf0e10cSrcweir } 9419cdf0e10cSrcweir else 9420cdf0e10cSrcweir { 9421cdf0e10cSrcweir aLine.append( "/CA " ); 9422cdf0e10cSrcweir appendDouble( rObject.m_fAlpha, aLine ); 9423cdf0e10cSrcweir aLine.append( "\n" 9424cdf0e10cSrcweir " /ca " ); 9425cdf0e10cSrcweir appendDouble( rObject.m_fAlpha, aLine ); 9426cdf0e10cSrcweir } 9427cdf0e10cSrcweir aLine.append( "\n" ); 9428cdf0e10cSrcweir } 9429cdf0e10cSrcweir else 9430cdf0e10cSrcweir { 9431cdf0e10cSrcweir if( m_bIsPDF_A1 ) 9432cdf0e10cSrcweir { 9433cdf0e10cSrcweir aLine.append( "/SMask/None" ); 9434cdf0e10cSrcweir m_aErrors.insert( PDFWriter::Warning_Transparency_Omitted_PDFA ); 9435cdf0e10cSrcweir } 9436cdf0e10cSrcweir else 9437cdf0e10cSrcweir { 9438cdf0e10cSrcweir rObject.m_pSoftMaskStream->Seek( STREAM_SEEK_TO_END ); 9439cdf0e10cSrcweir sal_Int32 nMaskSize = (sal_Int32)rObject.m_pSoftMaskStream->Tell(); 9440cdf0e10cSrcweir rObject.m_pSoftMaskStream->Seek( STREAM_SEEK_TO_BEGIN ); 9441cdf0e10cSrcweir sal_Int32 nMaskObject = createObject(); 9442cdf0e10cSrcweir aLine.append( "/SMask<</Type/Mask/S/Luminosity/G " ); 9443cdf0e10cSrcweir aLine.append( nMaskObject ); 9444cdf0e10cSrcweir aLine.append( " 0 R>>\n" ); 9445cdf0e10cSrcweir 9446cdf0e10cSrcweir OStringBuffer aMask; 9447cdf0e10cSrcweir aMask.append( nMaskObject ); 9448cdf0e10cSrcweir aMask.append( " 0 obj\n" 9449cdf0e10cSrcweir "<</Type/XObject\n" 9450cdf0e10cSrcweir "/Subtype/Form\n" 9451cdf0e10cSrcweir "/BBox[" ); 9452cdf0e10cSrcweir appendFixedInt( rObject.m_aBoundRect.Left(), aMask ); 9453cdf0e10cSrcweir aMask.append( ' ' ); 9454cdf0e10cSrcweir appendFixedInt( rObject.m_aBoundRect.Top(), aMask ); 9455cdf0e10cSrcweir aMask.append( ' ' ); 9456cdf0e10cSrcweir appendFixedInt( rObject.m_aBoundRect.Right(), aMask ); 9457cdf0e10cSrcweir aMask.append( ' ' ); 9458cdf0e10cSrcweir appendFixedInt( rObject.m_aBoundRect.Bottom()+1, aMask ); 9459cdf0e10cSrcweir aMask.append( "]\n" ); 9460cdf0e10cSrcweir 9461cdf0e10cSrcweir /* #i42884# see above */ 9462cdf0e10cSrcweir #if 0 9463cdf0e10cSrcweir aLine.append( "/Resources " ); 9464cdf0e10cSrcweir aMask.append( getResourceDictObj() ); 9465cdf0e10cSrcweir aMask.append( " 0 R\n" ); 9466cdf0e10cSrcweir #endif 9467cdf0e10cSrcweir 9468cdf0e10cSrcweir aMask.append( "/Group<</S/Transparency/CS/DeviceRGB>>\n" ); 9469cdf0e10cSrcweir aMask.append( "/Length " ); 9470cdf0e10cSrcweir aMask.append( nMaskSize ); 9471cdf0e10cSrcweir aMask.append( ">>\n" 9472cdf0e10cSrcweir "stream\n" ); 9473cdf0e10cSrcweir CHECK_RETURN( updateObject( nMaskObject ) ); 9474cdf0e10cSrcweir checkAndEnableStreamEncryption( nMaskObject ); 9475cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aMask.getStr(), aMask.getLength() ) ); 9476cdf0e10cSrcweir CHECK_RETURN( writeBuffer( rObject.m_pSoftMaskStream->GetData(), nMaskSize ) ); 9477cdf0e10cSrcweir disableStreamEncryption(); 9478cdf0e10cSrcweir aMask.setLength( 0 ); 9479cdf0e10cSrcweir aMask.append( "\nendstream\n" 9480cdf0e10cSrcweir "endobj\n\n" ); 9481cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aMask.getStr(), aMask.getLength() ) ); 9482cdf0e10cSrcweir } 9483cdf0e10cSrcweir } 9484cdf0e10cSrcweir aLine.append( ">>\n" 9485cdf0e10cSrcweir "endobj\n\n" ); 9486cdf0e10cSrcweir CHECK_RETURN( updateObject( rObject.m_nExtGStateObject ) ); 9487cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) ); 9488cdf0e10cSrcweir 9489cdf0e10cSrcweir return true; 9490cdf0e10cSrcweir } 9491cdf0e10cSrcweir 9492cdf0e10cSrcweir bool PDFWriterImpl::writeGradientFunction( GradientEmit& rObject ) 9493cdf0e10cSrcweir { 9494cdf0e10cSrcweir sal_Int32 nFunctionObject = createObject(); 9495cdf0e10cSrcweir CHECK_RETURN( updateObject( nFunctionObject ) ); 9496cdf0e10cSrcweir 9497cdf0e10cSrcweir VirtualDevice aDev; 9498cdf0e10cSrcweir aDev.SetOutputSizePixel( rObject.m_aSize ); 9499cdf0e10cSrcweir aDev.SetMapMode( MapMode( MAP_PIXEL ) ); 9500cdf0e10cSrcweir if( m_aContext.ColorMode == PDFWriter::DrawGreyscale ) 9501cdf0e10cSrcweir aDev.SetDrawMode( aDev.GetDrawMode() | 9502cdf0e10cSrcweir ( DRAWMODE_GRAYLINE | DRAWMODE_GRAYFILL | DRAWMODE_GRAYTEXT | 9503cdf0e10cSrcweir DRAWMODE_GRAYBITMAP | DRAWMODE_GRAYGRADIENT ) ); 9504cdf0e10cSrcweir aDev.DrawGradient( Rectangle( Point( 0, 0 ), rObject.m_aSize ), rObject.m_aGradient ); 9505cdf0e10cSrcweir 9506cdf0e10cSrcweir Bitmap aSample = aDev.GetBitmap( Point( 0, 0 ), rObject.m_aSize ); 9507cdf0e10cSrcweir BitmapReadAccess* pAccess = aSample.AcquireReadAccess(); 9508cdf0e10cSrcweir AccessReleaser aReleaser( pAccess ); 9509cdf0e10cSrcweir 9510cdf0e10cSrcweir Size aSize = aSample.GetSizePixel(); 9511cdf0e10cSrcweir 9512cdf0e10cSrcweir sal_Int32 nStreamLengthObject = createObject(); 9513cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 9514cdf0e10cSrcweir emitComment( "PDFWriterImpl::writeGradientFunction" ); 9515cdf0e10cSrcweir #endif 9516cdf0e10cSrcweir OStringBuffer aLine( 120 ); 9517cdf0e10cSrcweir aLine.append( nFunctionObject ); 9518cdf0e10cSrcweir aLine.append( " 0 obj\n" 9519cdf0e10cSrcweir "<</FunctionType 0\n" 9520cdf0e10cSrcweir "/Domain[ 0 1 0 1 ]\n" 9521cdf0e10cSrcweir "/Size[ " ); 9522cdf0e10cSrcweir aLine.append( (sal_Int32)aSize.Width() ); 9523cdf0e10cSrcweir aLine.append( ' ' ); 9524cdf0e10cSrcweir aLine.append( (sal_Int32)aSize.Height() ); 9525cdf0e10cSrcweir aLine.append( " ]\n" 9526cdf0e10cSrcweir "/BitsPerSample 8\n" 9527cdf0e10cSrcweir "/Range[ 0 1 0 1 0 1 ]\n" 9528cdf0e10cSrcweir "/Order 3\n" 9529cdf0e10cSrcweir "/Length " ); 9530cdf0e10cSrcweir aLine.append( nStreamLengthObject ); 9531cdf0e10cSrcweir aLine.append( " 0 R\n" 9532cdf0e10cSrcweir #ifndef DEBUG_DISABLE_PDFCOMPRESSION 9533cdf0e10cSrcweir "/Filter/FlateDecode" 9534cdf0e10cSrcweir #endif 9535cdf0e10cSrcweir ">>\n" 9536cdf0e10cSrcweir "stream\n" ); 9537cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) ); 9538cdf0e10cSrcweir 9539cdf0e10cSrcweir sal_uInt64 nStartStreamPos = 0; 9540cdf0e10cSrcweir CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nStartStreamPos )) ); 9541cdf0e10cSrcweir 9542cdf0e10cSrcweir checkAndEnableStreamEncryption( nFunctionObject ); 9543cdf0e10cSrcweir beginCompression(); 9544cdf0e10cSrcweir for( int y = aSize.Height()-1; y >= 0; y-- ) 9545cdf0e10cSrcweir { 9546cdf0e10cSrcweir for( int x = 0; x < aSize.Width(); x++ ) 9547cdf0e10cSrcweir { 9548cdf0e10cSrcweir sal_uInt8 aCol[3]; 9549cdf0e10cSrcweir BitmapColor aColor = pAccess->GetColor( y, x ); 9550cdf0e10cSrcweir aCol[0] = aColor.GetRed(); 9551cdf0e10cSrcweir aCol[1] = aColor.GetGreen(); 9552cdf0e10cSrcweir aCol[2] = aColor.GetBlue(); 9553cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aCol, 3 ) ); 9554cdf0e10cSrcweir } 9555cdf0e10cSrcweir } 9556cdf0e10cSrcweir endCompression(); 9557cdf0e10cSrcweir disableStreamEncryption(); 9558cdf0e10cSrcweir 9559cdf0e10cSrcweir sal_uInt64 nEndStreamPos = 0; 9560cdf0e10cSrcweir CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nEndStreamPos )) ); 9561cdf0e10cSrcweir 9562cdf0e10cSrcweir aLine.setLength( 0 ); 9563cdf0e10cSrcweir aLine.append( "\nendstream\nendobj\n\n" ); 9564cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) ); 9565cdf0e10cSrcweir 9566cdf0e10cSrcweir // write stream length 9567cdf0e10cSrcweir CHECK_RETURN( updateObject( nStreamLengthObject ) ); 9568cdf0e10cSrcweir aLine.setLength( 0 ); 9569cdf0e10cSrcweir aLine.append( nStreamLengthObject ); 9570cdf0e10cSrcweir aLine.append( " 0 obj\n" ); 9571cdf0e10cSrcweir aLine.append( (sal_Int64)(nEndStreamPos-nStartStreamPos) ); 9572cdf0e10cSrcweir aLine.append( "\nendobj\n\n" ); 9573cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) ); 9574cdf0e10cSrcweir 9575cdf0e10cSrcweir CHECK_RETURN( updateObject( rObject.m_nObject ) ); 9576cdf0e10cSrcweir aLine.setLength( 0 ); 9577cdf0e10cSrcweir aLine.append( rObject.m_nObject ); 9578cdf0e10cSrcweir aLine.append( " 0 obj\n" 9579cdf0e10cSrcweir "<</ShadingType 1\n" 9580cdf0e10cSrcweir "/ColorSpace/DeviceRGB\n" 9581cdf0e10cSrcweir "/AntiAlias true\n" 9582cdf0e10cSrcweir "/Domain[ 0 1 0 1 ]\n" 9583cdf0e10cSrcweir "/Matrix[ " ); 9584cdf0e10cSrcweir aLine.append( (sal_Int32)aSize.Width() ); 9585cdf0e10cSrcweir aLine.append( " 0 0 " ); 9586cdf0e10cSrcweir aLine.append( (sal_Int32)aSize.Height() ); 9587cdf0e10cSrcweir aLine.append( " 0 0 ]\n" 9588cdf0e10cSrcweir "/Function " ); 9589cdf0e10cSrcweir aLine.append( nFunctionObject ); 9590cdf0e10cSrcweir aLine.append( " 0 R\n" 9591cdf0e10cSrcweir ">>\n" 9592cdf0e10cSrcweir "endobj\n\n" ); 9593cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) ); 9594cdf0e10cSrcweir 9595cdf0e10cSrcweir return true; 9596cdf0e10cSrcweir } 9597cdf0e10cSrcweir 9598cdf0e10cSrcweir bool PDFWriterImpl::writeJPG( JPGEmit& rObject ) 9599cdf0e10cSrcweir { 9600cdf0e10cSrcweir CHECK_RETURN( rObject.m_pStream ); 9601cdf0e10cSrcweir CHECK_RETURN( updateObject( rObject.m_nObject ) ); 9602cdf0e10cSrcweir 9603cdf0e10cSrcweir sal_Int32 nLength = 0; 9604cdf0e10cSrcweir rObject.m_pStream->Seek( STREAM_SEEK_TO_END ); 9605cdf0e10cSrcweir nLength = rObject.m_pStream->Tell(); 9606cdf0e10cSrcweir rObject.m_pStream->Seek( STREAM_SEEK_TO_BEGIN ); 9607cdf0e10cSrcweir 9608cdf0e10cSrcweir sal_Int32 nMaskObject = 0; 9609cdf0e10cSrcweir if( !!rObject.m_aMask ) 9610cdf0e10cSrcweir { 9611cdf0e10cSrcweir if( rObject.m_aMask.GetBitCount() == 1 || 9612cdf0e10cSrcweir ( rObject.m_aMask.GetBitCount() == 8 && m_aContext.Version >= PDFWriter::PDF_1_4 && !m_bIsPDF_A1 )//i59651 9613cdf0e10cSrcweir ) 9614cdf0e10cSrcweir { 9615cdf0e10cSrcweir nMaskObject = createObject(); 9616cdf0e10cSrcweir } 9617cdf0e10cSrcweir else if( m_bIsPDF_A1 ) 9618cdf0e10cSrcweir m_aErrors.insert( PDFWriter::Warning_Transparency_Omitted_PDFA ); 9619cdf0e10cSrcweir else if( m_aContext.Version < PDFWriter::PDF_1_4 ) 9620cdf0e10cSrcweir m_aErrors.insert( PDFWriter::Warning_Transparency_Omitted_PDF13 ); 9621cdf0e10cSrcweir 9622cdf0e10cSrcweir } 9623cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 9624cdf0e10cSrcweir emitComment( "PDFWriterImpl::writeJPG" ); 9625cdf0e10cSrcweir #endif 9626cdf0e10cSrcweir 9627cdf0e10cSrcweir OStringBuffer aLine(200); 9628cdf0e10cSrcweir aLine.append( rObject.m_nObject ); 9629cdf0e10cSrcweir aLine.append( " 0 obj\n" 9630cdf0e10cSrcweir "<</Type/XObject/Subtype/Image/Width " ); 9631cdf0e10cSrcweir aLine.append( (sal_Int32)rObject.m_aID.m_aPixelSize.Width() ); 9632cdf0e10cSrcweir aLine.append( " /Height " ); 9633cdf0e10cSrcweir aLine.append( (sal_Int32)rObject.m_aID.m_aPixelSize.Height() ); 9634cdf0e10cSrcweir aLine.append( " /BitsPerComponent 8 " ); 9635cdf0e10cSrcweir if( rObject.m_bTrueColor ) 9636cdf0e10cSrcweir aLine.append( "/ColorSpace/DeviceRGB" ); 9637cdf0e10cSrcweir else 9638cdf0e10cSrcweir aLine.append( "/ColorSpace/DeviceGray" ); 9639cdf0e10cSrcweir aLine.append( "/Filter/DCTDecode/Length " ); 9640cdf0e10cSrcweir aLine.append( nLength ); 9641cdf0e10cSrcweir if( nMaskObject ) 9642cdf0e10cSrcweir { 9643cdf0e10cSrcweir aLine.append( rObject.m_aMask.GetBitCount() == 1 ? " /Mask " : " /SMask " ); 9644cdf0e10cSrcweir aLine.append( nMaskObject ); 9645cdf0e10cSrcweir aLine.append( " 0 R " ); 9646cdf0e10cSrcweir } 9647cdf0e10cSrcweir aLine.append( ">>\nstream\n" ); 9648cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) ); 9649cdf0e10cSrcweir 9650cdf0e10cSrcweir checkAndEnableStreamEncryption( rObject.m_nObject ); 9651cdf0e10cSrcweir CHECK_RETURN( writeBuffer( rObject.m_pStream->GetData(), nLength ) ); 9652cdf0e10cSrcweir disableStreamEncryption(); 9653cdf0e10cSrcweir 9654cdf0e10cSrcweir aLine.setLength( 0 ); 9655cdf0e10cSrcweir aLine.append( "\nendstream\nendobj\n\n" ); 9656cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) ); 9657cdf0e10cSrcweir 9658cdf0e10cSrcweir if( nMaskObject ) 9659cdf0e10cSrcweir { 9660cdf0e10cSrcweir BitmapEmit aEmit; 9661cdf0e10cSrcweir aEmit.m_nObject = nMaskObject; 9662cdf0e10cSrcweir if( rObject.m_aMask.GetBitCount() == 1 ) 9663cdf0e10cSrcweir aEmit.m_aBitmap = BitmapEx( rObject.m_aMask, rObject.m_aMask ); 9664cdf0e10cSrcweir else if( rObject.m_aMask.GetBitCount() == 8 ) 9665cdf0e10cSrcweir aEmit.m_aBitmap = BitmapEx( rObject.m_aMask, AlphaMask( rObject.m_aMask ) ); 9666cdf0e10cSrcweir writeBitmapObject( aEmit, true ); 9667cdf0e10cSrcweir } 9668cdf0e10cSrcweir 9669cdf0e10cSrcweir return true; 9670cdf0e10cSrcweir } 9671cdf0e10cSrcweir 9672cdf0e10cSrcweir bool PDFWriterImpl::writeBitmapObject( BitmapEmit& rObject, bool bMask ) 9673cdf0e10cSrcweir { 9674cdf0e10cSrcweir CHECK_RETURN( updateObject( rObject.m_nObject ) ); 9675cdf0e10cSrcweir 9676cdf0e10cSrcweir Bitmap aBitmap; 9677cdf0e10cSrcweir Color aTransparentColor( COL_TRANSPARENT ); 9678cdf0e10cSrcweir bool bWriteMask = false; 9679cdf0e10cSrcweir if( ! bMask ) 9680cdf0e10cSrcweir { 9681cdf0e10cSrcweir aBitmap = rObject.m_aBitmap.GetBitmap(); 9682cdf0e10cSrcweir if( rObject.m_aBitmap.IsAlpha() ) 9683cdf0e10cSrcweir { 9684cdf0e10cSrcweir if( m_aContext.Version >= PDFWriter::PDF_1_4 ) 9685cdf0e10cSrcweir bWriteMask = true; 9686cdf0e10cSrcweir // else draw without alpha channel 9687cdf0e10cSrcweir } 9688cdf0e10cSrcweir else 9689cdf0e10cSrcweir { 9690cdf0e10cSrcweir switch( rObject.m_aBitmap.GetTransparentType() ) 9691cdf0e10cSrcweir { 9692cdf0e10cSrcweir case TRANSPARENT_NONE: 9693cdf0e10cSrcweir // comes from drawMask function 9694cdf0e10cSrcweir if( aBitmap.GetBitCount() == 1 && rObject.m_bDrawMask ) 9695cdf0e10cSrcweir bMask = true; 9696cdf0e10cSrcweir break; 9697cdf0e10cSrcweir case TRANSPARENT_COLOR: 9698cdf0e10cSrcweir aTransparentColor = rObject.m_aBitmap.GetTransparentColor(); 9699cdf0e10cSrcweir break; 9700cdf0e10cSrcweir case TRANSPARENT_BITMAP: 9701cdf0e10cSrcweir bWriteMask = true; 9702cdf0e10cSrcweir break; 9703cdf0e10cSrcweir } 9704cdf0e10cSrcweir } 9705cdf0e10cSrcweir } 9706cdf0e10cSrcweir else 9707cdf0e10cSrcweir { 9708cdf0e10cSrcweir if( m_aContext.Version < PDFWriter::PDF_1_4 || ! rObject.m_aBitmap.IsAlpha() ) 9709cdf0e10cSrcweir { 9710cdf0e10cSrcweir aBitmap = rObject.m_aBitmap.GetMask(); 9711cdf0e10cSrcweir aBitmap.Convert( BMP_CONVERSION_1BIT_THRESHOLD ); 9712cdf0e10cSrcweir DBG_ASSERT( aBitmap.GetBitCount() == 1, "mask conversion failed" ); 9713cdf0e10cSrcweir } 9714cdf0e10cSrcweir else if( aBitmap.GetBitCount() != 8 ) 9715cdf0e10cSrcweir { 9716cdf0e10cSrcweir aBitmap = rObject.m_aBitmap.GetAlpha().GetBitmap(); 9717cdf0e10cSrcweir aBitmap.Convert( BMP_CONVERSION_8BIT_GREYS ); 9718cdf0e10cSrcweir DBG_ASSERT( aBitmap.GetBitCount() == 8, "alpha mask conversion failed" ); 9719cdf0e10cSrcweir } 9720cdf0e10cSrcweir } 9721cdf0e10cSrcweir 9722cdf0e10cSrcweir BitmapReadAccess* pAccess = aBitmap.AcquireReadAccess(); 9723cdf0e10cSrcweir AccessReleaser aReleaser( pAccess ); 9724cdf0e10cSrcweir 9725cdf0e10cSrcweir bool bTrueColor; 9726cdf0e10cSrcweir sal_Int32 nBitsPerComponent; 9727cdf0e10cSrcweir switch( aBitmap.GetBitCount() ) 9728cdf0e10cSrcweir { 9729cdf0e10cSrcweir case 1: 9730cdf0e10cSrcweir case 2: 9731cdf0e10cSrcweir case 4: 9732cdf0e10cSrcweir case 8: 9733cdf0e10cSrcweir bTrueColor = false; 9734cdf0e10cSrcweir nBitsPerComponent = aBitmap.GetBitCount(); 9735cdf0e10cSrcweir break; 9736cdf0e10cSrcweir default: 9737cdf0e10cSrcweir bTrueColor = true; 9738cdf0e10cSrcweir nBitsPerComponent = 8; 9739cdf0e10cSrcweir break; 9740cdf0e10cSrcweir } 9741cdf0e10cSrcweir 9742cdf0e10cSrcweir sal_Int32 nStreamLengthObject = createObject(); 9743cdf0e10cSrcweir sal_Int32 nMaskObject = 0; 9744cdf0e10cSrcweir 9745cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 9746cdf0e10cSrcweir emitComment( "PDFWriterImpl::writeBitmapObject" ); 9747cdf0e10cSrcweir #endif 9748cdf0e10cSrcweir OStringBuffer aLine(1024); 9749cdf0e10cSrcweir aLine.append( rObject.m_nObject ); 9750cdf0e10cSrcweir aLine.append( " 0 obj\n" 9751cdf0e10cSrcweir "<</Type/XObject/Subtype/Image/Width " ); 9752cdf0e10cSrcweir aLine.append( (sal_Int32)aBitmap.GetSizePixel().Width() ); 9753cdf0e10cSrcweir aLine.append( "/Height " ); 9754cdf0e10cSrcweir aLine.append( (sal_Int32)aBitmap.GetSizePixel().Height() ); 9755cdf0e10cSrcweir aLine.append( "/BitsPerComponent " ); 9756cdf0e10cSrcweir aLine.append( nBitsPerComponent ); 9757cdf0e10cSrcweir aLine.append( "/Length " ); 9758cdf0e10cSrcweir aLine.append( nStreamLengthObject ); 9759cdf0e10cSrcweir aLine.append( " 0 R\n" ); 9760cdf0e10cSrcweir #ifndef DEBUG_DISABLE_PDFCOMPRESSION 9761cdf0e10cSrcweir if( nBitsPerComponent != 1 ) 9762cdf0e10cSrcweir { 9763cdf0e10cSrcweir aLine.append( "/Filter/FlateDecode" ); 9764cdf0e10cSrcweir } 9765cdf0e10cSrcweir else 9766cdf0e10cSrcweir { 9767cdf0e10cSrcweir aLine.append( "/Filter/CCITTFaxDecode/DecodeParms<</K -1/BlackIs1 true/Columns " ); 9768cdf0e10cSrcweir aLine.append( (sal_Int32)aBitmap.GetSizePixel().Width() ); 9769cdf0e10cSrcweir aLine.append( ">>\n" ); 9770cdf0e10cSrcweir } 9771cdf0e10cSrcweir #endif 9772cdf0e10cSrcweir if( ! bMask ) 9773cdf0e10cSrcweir { 9774cdf0e10cSrcweir aLine.append( "/ColorSpace" ); 9775cdf0e10cSrcweir if( bTrueColor ) 9776cdf0e10cSrcweir aLine.append( "/DeviceRGB\n" ); 9777cdf0e10cSrcweir else if( aBitmap.HasGreyPalette() ) 9778cdf0e10cSrcweir { 9779cdf0e10cSrcweir aLine.append( "/DeviceGray\n" ); 9780cdf0e10cSrcweir if( aBitmap.GetBitCount() == 1 ) 9781cdf0e10cSrcweir { 9782cdf0e10cSrcweir // #i47395# 1 bit bitmaps occasionally have an inverted grey palette 9783cdf0e10cSrcweir sal_Int32 nBlackIndex = pAccess->GetBestPaletteIndex( BitmapColor( Color( COL_BLACK ) ) ); 9784cdf0e10cSrcweir DBG_ASSERT( nBlackIndex == 0 || nBlackIndex == 1, "wrong black index" ); 9785cdf0e10cSrcweir if( nBlackIndex == 1 ) 9786cdf0e10cSrcweir aLine.append( "/Decode[1 0]\n" ); 9787cdf0e10cSrcweir } 9788cdf0e10cSrcweir } 9789cdf0e10cSrcweir else 9790cdf0e10cSrcweir { 9791cdf0e10cSrcweir aLine.append( "[ /Indexed/DeviceRGB " ); 9792cdf0e10cSrcweir aLine.append( (sal_Int32)(pAccess->GetPaletteEntryCount()-1) ); 9793cdf0e10cSrcweir aLine.append( "\n<" ); 9794cdf0e10cSrcweir if( m_aContext.Encryption.Encrypt() ) 9795cdf0e10cSrcweir { 9796cdf0e10cSrcweir enableStringEncryption( rObject.m_nObject ); 9797cdf0e10cSrcweir //check encryption buffer size 9798cdf0e10cSrcweir if( checkEncryptionBufferSize( pAccess->GetPaletteEntryCount()*3 ) ) 9799cdf0e10cSrcweir { 9800cdf0e10cSrcweir int nChar = 0; 9801cdf0e10cSrcweir //fill the encryption buffer 9802cdf0e10cSrcweir for( sal_uInt16 i = 0; i < pAccess->GetPaletteEntryCount(); i++ ) 9803cdf0e10cSrcweir { 9804cdf0e10cSrcweir const BitmapColor& rColor = pAccess->GetPaletteColor( i ); 9805cdf0e10cSrcweir m_pEncryptionBuffer[nChar++] = rColor.GetRed(); 9806cdf0e10cSrcweir m_pEncryptionBuffer[nChar++] = rColor.GetGreen(); 9807cdf0e10cSrcweir m_pEncryptionBuffer[nChar++] = rColor.GetBlue(); 9808cdf0e10cSrcweir } 9809cdf0e10cSrcweir //encrypt the colorspace lookup table 9810cdf0e10cSrcweir rtl_cipher_encodeARCFOUR( m_aCipher, m_pEncryptionBuffer, nChar, m_pEncryptionBuffer, nChar ); 9811cdf0e10cSrcweir //now queue the data for output 9812cdf0e10cSrcweir nChar = 0; 9813cdf0e10cSrcweir for( sal_uInt16 i = 0; i < pAccess->GetPaletteEntryCount(); i++ ) 9814cdf0e10cSrcweir { 9815cdf0e10cSrcweir appendHex(m_pEncryptionBuffer[nChar++], aLine ); 9816cdf0e10cSrcweir appendHex(m_pEncryptionBuffer[nChar++], aLine ); 9817cdf0e10cSrcweir appendHex(m_pEncryptionBuffer[nChar++], aLine ); 9818cdf0e10cSrcweir } 9819cdf0e10cSrcweir } 9820cdf0e10cSrcweir } 9821cdf0e10cSrcweir else //no encryption requested (PDF/A-1a program flow drops here) 9822cdf0e10cSrcweir { 9823cdf0e10cSrcweir for( sal_uInt16 i = 0; i < pAccess->GetPaletteEntryCount(); i++ ) 9824cdf0e10cSrcweir { 9825cdf0e10cSrcweir const BitmapColor& rColor = pAccess->GetPaletteColor( i ); 9826cdf0e10cSrcweir appendHex( rColor.GetRed(), aLine ); 9827cdf0e10cSrcweir appendHex( rColor.GetGreen(), aLine ); 9828cdf0e10cSrcweir appendHex( rColor.GetBlue(), aLine ); 9829cdf0e10cSrcweir } 9830cdf0e10cSrcweir } 9831cdf0e10cSrcweir aLine.append( ">\n]\n" ); 9832cdf0e10cSrcweir } 9833cdf0e10cSrcweir } 9834cdf0e10cSrcweir else 9835cdf0e10cSrcweir { 9836cdf0e10cSrcweir if( aBitmap.GetBitCount() == 1 ) 9837cdf0e10cSrcweir { 9838cdf0e10cSrcweir aLine.append( "/ImageMask true\n" ); 9839cdf0e10cSrcweir sal_Int32 nBlackIndex = pAccess->GetBestPaletteIndex( BitmapColor( Color( COL_BLACK ) ) ); 9840cdf0e10cSrcweir DBG_ASSERT( nBlackIndex == 0 || nBlackIndex == 1, "wrong black index" ); 9841cdf0e10cSrcweir if( nBlackIndex ) 9842cdf0e10cSrcweir aLine.append( "/Decode[ 1 0 ]\n" ); 9843cdf0e10cSrcweir else 9844cdf0e10cSrcweir aLine.append( "/Decode[ 0 1 ]\n" ); 9845cdf0e10cSrcweir } 9846cdf0e10cSrcweir else if( aBitmap.GetBitCount() == 8 ) 9847cdf0e10cSrcweir { 9848cdf0e10cSrcweir aLine.append( "/ColorSpace/DeviceGray\n" 9849cdf0e10cSrcweir "/Decode [ 1 0 ]\n" ); 9850cdf0e10cSrcweir } 9851cdf0e10cSrcweir } 9852cdf0e10cSrcweir 9853cdf0e10cSrcweir if( ! bMask && m_aContext.Version > PDFWriter::PDF_1_2 && !m_bIsPDF_A1 )//i59651 9854cdf0e10cSrcweir { 9855cdf0e10cSrcweir if( bWriteMask ) 9856cdf0e10cSrcweir { 9857cdf0e10cSrcweir nMaskObject = createObject(); 9858cdf0e10cSrcweir if( rObject.m_aBitmap.IsAlpha() && m_aContext.Version > PDFWriter::PDF_1_3 ) 9859cdf0e10cSrcweir aLine.append( "/SMask " ); 9860cdf0e10cSrcweir else 9861cdf0e10cSrcweir aLine.append( "/Mask " ); 9862cdf0e10cSrcweir aLine.append( nMaskObject ); 9863cdf0e10cSrcweir aLine.append( " 0 R\n" ); 9864cdf0e10cSrcweir } 9865cdf0e10cSrcweir else if( aTransparentColor != Color( COL_TRANSPARENT ) ) 9866cdf0e10cSrcweir { 9867cdf0e10cSrcweir aLine.append( "/Mask[ " ); 9868cdf0e10cSrcweir if( bTrueColor ) 9869cdf0e10cSrcweir { 9870cdf0e10cSrcweir aLine.append( (sal_Int32)aTransparentColor.GetRed() ); 9871cdf0e10cSrcweir aLine.append( ' ' ); 9872cdf0e10cSrcweir aLine.append( (sal_Int32)aTransparentColor.GetRed() ); 9873cdf0e10cSrcweir aLine.append( ' ' ); 9874cdf0e10cSrcweir aLine.append( (sal_Int32)aTransparentColor.GetGreen() ); 9875cdf0e10cSrcweir aLine.append( ' ' ); 9876cdf0e10cSrcweir aLine.append( (sal_Int32)aTransparentColor.GetGreen() ); 9877cdf0e10cSrcweir aLine.append( ' ' ); 9878cdf0e10cSrcweir aLine.append( (sal_Int32)aTransparentColor.GetBlue() ); 9879cdf0e10cSrcweir aLine.append( ' ' ); 9880cdf0e10cSrcweir aLine.append( (sal_Int32)aTransparentColor.GetBlue() ); 9881cdf0e10cSrcweir } 9882cdf0e10cSrcweir else 9883cdf0e10cSrcweir { 9884cdf0e10cSrcweir sal_Int32 nIndex = pAccess->GetBestPaletteIndex( BitmapColor( aTransparentColor ) ); 9885cdf0e10cSrcweir aLine.append( nIndex ); 9886cdf0e10cSrcweir } 9887cdf0e10cSrcweir aLine.append( " ]\n" ); 9888cdf0e10cSrcweir } 9889cdf0e10cSrcweir } 9890cdf0e10cSrcweir else if( m_bIsPDF_A1 && (bWriteMask || aTransparentColor != Color( COL_TRANSPARENT )) ) 9891cdf0e10cSrcweir m_aErrors.insert( PDFWriter::Warning_Transparency_Omitted_PDFA ); 9892cdf0e10cSrcweir 9893cdf0e10cSrcweir aLine.append( ">>\n" 9894cdf0e10cSrcweir "stream\n" ); 9895cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) ); 9896cdf0e10cSrcweir sal_uInt64 nStartPos = 0; 9897cdf0e10cSrcweir CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nStartPos )) ); 9898cdf0e10cSrcweir 9899cdf0e10cSrcweir checkAndEnableStreamEncryption( rObject.m_nObject ); 9900cdf0e10cSrcweir #ifndef DEBUG_DISABLE_PDFCOMPRESSION 9901cdf0e10cSrcweir if( nBitsPerComponent == 1 ) 9902cdf0e10cSrcweir { 9903cdf0e10cSrcweir writeG4Stream( pAccess ); 9904cdf0e10cSrcweir } 9905cdf0e10cSrcweir else 9906cdf0e10cSrcweir #endif 9907cdf0e10cSrcweir { 9908cdf0e10cSrcweir beginCompression(); 9909cdf0e10cSrcweir if( ! bTrueColor || pAccess->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB ) 9910cdf0e10cSrcweir { 9911cdf0e10cSrcweir const int nScanLineBytes = 1 + ( pAccess->GetBitCount() * ( pAccess->Width() - 1 ) / 8U ); 9912cdf0e10cSrcweir 9913cdf0e10cSrcweir for( int i = 0; i < pAccess->Height(); i++ ) 9914cdf0e10cSrcweir { 9915cdf0e10cSrcweir CHECK_RETURN( writeBuffer( pAccess->GetScanline( i ), nScanLineBytes ) ); 9916cdf0e10cSrcweir } 9917cdf0e10cSrcweir } 9918cdf0e10cSrcweir else 9919cdf0e10cSrcweir { 9920cdf0e10cSrcweir const int nScanLineBytes = pAccess->Width()*3; 9921cdf0e10cSrcweir boost::shared_array<sal_uInt8> pCol( new sal_uInt8[ nScanLineBytes ] ); 9922cdf0e10cSrcweir for( int y = 0; y < pAccess->Height(); y++ ) 9923cdf0e10cSrcweir { 9924cdf0e10cSrcweir for( int x = 0; x < pAccess->Width(); x++ ) 9925cdf0e10cSrcweir { 9926cdf0e10cSrcweir BitmapColor aColor = pAccess->GetColor( y, x ); 9927cdf0e10cSrcweir pCol[3*x+0] = aColor.GetRed(); 9928cdf0e10cSrcweir pCol[3*x+1] = aColor.GetGreen(); 9929cdf0e10cSrcweir pCol[3*x+2] = aColor.GetBlue(); 9930cdf0e10cSrcweir } 9931cdf0e10cSrcweir CHECK_RETURN( writeBuffer( pCol.get(), nScanLineBytes ) ); 9932cdf0e10cSrcweir } 9933cdf0e10cSrcweir } 9934cdf0e10cSrcweir endCompression(); 9935cdf0e10cSrcweir } 9936cdf0e10cSrcweir disableStreamEncryption(); 9937cdf0e10cSrcweir 9938cdf0e10cSrcweir sal_uInt64 nEndPos = 0; 9939cdf0e10cSrcweir CHECK_RETURN( (osl_File_E_None == osl_getFilePos( m_aFile, &nEndPos )) ); 9940cdf0e10cSrcweir aLine.setLength( 0 ); 9941cdf0e10cSrcweir aLine.append( "\nendstream\nendobj\n\n" ); 9942cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) ); 9943cdf0e10cSrcweir CHECK_RETURN( updateObject( nStreamLengthObject ) ); 9944cdf0e10cSrcweir aLine.setLength( 0 ); 9945cdf0e10cSrcweir aLine.append( nStreamLengthObject ); 9946cdf0e10cSrcweir aLine.append( " 0 obj\n" ); 9947cdf0e10cSrcweir aLine.append( (sal_Int64)(nEndPos-nStartPos) ); 9948cdf0e10cSrcweir aLine.append( "\nendobj\n\n" ); 9949cdf0e10cSrcweir CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) ); 9950cdf0e10cSrcweir 9951cdf0e10cSrcweir if( nMaskObject ) 9952cdf0e10cSrcweir { 9953cdf0e10cSrcweir BitmapEmit aEmit; 9954cdf0e10cSrcweir aEmit.m_nObject = nMaskObject; 9955cdf0e10cSrcweir aEmit.m_aBitmap = rObject.m_aBitmap; 9956cdf0e10cSrcweir return writeBitmapObject( aEmit, true ); 9957cdf0e10cSrcweir } 9958cdf0e10cSrcweir 9959cdf0e10cSrcweir return true; 9960cdf0e10cSrcweir } 9961cdf0e10cSrcweir 9962cdf0e10cSrcweir void PDFWriterImpl::drawJPGBitmap( SvStream& rDCTData, bool bIsTrueColor, const Size& rSizePixel, const Rectangle& rTargetArea, const Bitmap& rMask ) 9963cdf0e10cSrcweir { 9964cdf0e10cSrcweir MARK( "drawJPGBitmap" ); 9965cdf0e10cSrcweir 9966cdf0e10cSrcweir OStringBuffer aLine( 80 ); 9967cdf0e10cSrcweir updateGraphicsState(); 9968cdf0e10cSrcweir 9969cdf0e10cSrcweir // #i40055# sanity check 9970cdf0e10cSrcweir if( ! (rTargetArea.GetWidth() && rTargetArea.GetHeight() ) ) 9971cdf0e10cSrcweir return; 9972cdf0e10cSrcweir if( ! (rSizePixel.Width() && rSizePixel.Height()) ) 9973cdf0e10cSrcweir return; 9974cdf0e10cSrcweir 9975cdf0e10cSrcweir rDCTData.Seek( 0 ); 9976cdf0e10cSrcweir if( bIsTrueColor && m_aContext.ColorMode == PDFWriter::DrawGreyscale ) 9977cdf0e10cSrcweir { 9978cdf0e10cSrcweir // need to convert to grayscale; 9979cdf0e10cSrcweir // load stream to bitmap and draw the bitmap instead 9980cdf0e10cSrcweir Graphic aGraphic; 9981cdf0e10cSrcweir GraphicConverter::Import( rDCTData, aGraphic, CVT_JPG ); 9982cdf0e10cSrcweir Bitmap aBmp( aGraphic.GetBitmap() ); 9983cdf0e10cSrcweir if( !!rMask && rMask.GetSizePixel() == aBmp.GetSizePixel() ) 9984cdf0e10cSrcweir { 9985cdf0e10cSrcweir BitmapEx aBmpEx( aBmp, rMask ); 9986cdf0e10cSrcweir drawBitmap( rTargetArea.TopLeft(), rTargetArea.GetSize(), aBmpEx ); 9987cdf0e10cSrcweir } 9988cdf0e10cSrcweir else 9989cdf0e10cSrcweir drawBitmap( rTargetArea.TopLeft(), rTargetArea.GetSize(), aBmp ); 9990cdf0e10cSrcweir return; 9991cdf0e10cSrcweir } 9992cdf0e10cSrcweir 9993cdf0e10cSrcweir SvMemoryStream* pStream = new SvMemoryStream; 9994cdf0e10cSrcweir *pStream << rDCTData; 9995cdf0e10cSrcweir pStream->Seek( STREAM_SEEK_TO_END ); 9996cdf0e10cSrcweir 9997cdf0e10cSrcweir BitmapID aID; 9998cdf0e10cSrcweir aID.m_aPixelSize = rSizePixel; 9999cdf0e10cSrcweir aID.m_nSize = pStream->Tell(); 10000cdf0e10cSrcweir pStream->Seek( STREAM_SEEK_TO_BEGIN ); 10001cdf0e10cSrcweir aID.m_nChecksum = rtl_crc32( 0, pStream->GetData(), aID.m_nSize ); 10002cdf0e10cSrcweir if( ! rMask.IsEmpty() ) 10003cdf0e10cSrcweir aID.m_nMaskChecksum = rMask.GetChecksum(); 10004cdf0e10cSrcweir 10005cdf0e10cSrcweir std::list< JPGEmit >::const_iterator it; 10006cdf0e10cSrcweir for( it = m_aJPGs.begin(); it != m_aJPGs.end() && ! (aID == it->m_aID); ++it ) 10007cdf0e10cSrcweir ; 10008cdf0e10cSrcweir if( it == m_aJPGs.end() ) 10009cdf0e10cSrcweir { 10010cdf0e10cSrcweir m_aJPGs.push_front( JPGEmit() ); 10011cdf0e10cSrcweir JPGEmit& rEmit = m_aJPGs.front(); 10012cdf0e10cSrcweir rEmit.m_nObject = createObject(); 10013cdf0e10cSrcweir rEmit.m_aID = aID; 10014cdf0e10cSrcweir rEmit.m_pStream = pStream; 10015cdf0e10cSrcweir rEmit.m_bTrueColor = bIsTrueColor; 10016cdf0e10cSrcweir if( !! rMask && rMask.GetSizePixel() == rSizePixel ) 10017cdf0e10cSrcweir rEmit.m_aMask = rMask; 10018cdf0e10cSrcweir 10019cdf0e10cSrcweir it = m_aJPGs.begin(); 10020cdf0e10cSrcweir } 10021cdf0e10cSrcweir else 10022cdf0e10cSrcweir delete pStream; 10023cdf0e10cSrcweir 10024cdf0e10cSrcweir aLine.append( "q " ); 10025cdf0e10cSrcweir sal_Int32 nCheckWidth = 0; 10026cdf0e10cSrcweir m_aPages.back().appendMappedLength( (sal_Int32)rTargetArea.GetWidth(), aLine, false, &nCheckWidth ); 10027cdf0e10cSrcweir aLine.append( " 0 0 " ); 10028cdf0e10cSrcweir sal_Int32 nCheckHeight = 0; 10029cdf0e10cSrcweir m_aPages.back().appendMappedLength( (sal_Int32)rTargetArea.GetHeight(), aLine, true, &nCheckHeight ); 10030cdf0e10cSrcweir aLine.append( ' ' ); 10031cdf0e10cSrcweir m_aPages.back().appendPoint( rTargetArea.BottomLeft(), aLine ); 10032cdf0e10cSrcweir aLine.append( " cm\n/Im" ); 10033cdf0e10cSrcweir aLine.append( it->m_nObject ); 10034cdf0e10cSrcweir aLine.append( " Do Q\n" ); 10035cdf0e10cSrcweir if( nCheckWidth == 0 || nCheckHeight == 0 ) 10036cdf0e10cSrcweir { 10037cdf0e10cSrcweir // #i97512# avoid invalid current matrix 10038cdf0e10cSrcweir aLine.setLength( 0 ); 10039cdf0e10cSrcweir aLine.append( "\n%jpeg image /Im" ); 10040cdf0e10cSrcweir aLine.append( it->m_nObject ); 10041cdf0e10cSrcweir aLine.append( " scaled to zero size, omitted\n" ); 10042cdf0e10cSrcweir } 10043cdf0e10cSrcweir writeBuffer( aLine.getStr(), aLine.getLength() ); 10044cdf0e10cSrcweir 10045cdf0e10cSrcweir OStringBuffer aObjName( 16 ); 10046cdf0e10cSrcweir aObjName.append( "Im" ); 10047cdf0e10cSrcweir aObjName.append( it->m_nObject ); 10048cdf0e10cSrcweir pushResource( ResXObject, aObjName.makeStringAndClear(), it->m_nObject ); 10049cdf0e10cSrcweir 10050cdf0e10cSrcweir } 10051cdf0e10cSrcweir 10052cdf0e10cSrcweir void PDFWriterImpl::drawBitmap( const Point& rDestPoint, const Size& rDestSize, const BitmapEmit& rBitmap, const Color& rFillColor ) 10053cdf0e10cSrcweir { 10054cdf0e10cSrcweir OStringBuffer aLine( 80 ); 10055cdf0e10cSrcweir updateGraphicsState(); 10056cdf0e10cSrcweir 10057cdf0e10cSrcweir aLine.append( "q " ); 10058cdf0e10cSrcweir if( rFillColor != Color( COL_TRANSPARENT ) ) 10059cdf0e10cSrcweir { 10060cdf0e10cSrcweir appendNonStrokingColor( rFillColor, aLine ); 10061cdf0e10cSrcweir aLine.append( ' ' ); 10062cdf0e10cSrcweir } 10063cdf0e10cSrcweir sal_Int32 nCheckWidth = 0; 10064cdf0e10cSrcweir m_aPages.back().appendMappedLength( (sal_Int32)rDestSize.Width(), aLine, false, &nCheckWidth ); 10065cdf0e10cSrcweir aLine.append( " 0 0 " ); 10066cdf0e10cSrcweir sal_Int32 nCheckHeight = 0; 10067cdf0e10cSrcweir m_aPages.back().appendMappedLength( (sal_Int32)rDestSize.Height(), aLine, true, &nCheckHeight ); 10068cdf0e10cSrcweir aLine.append( ' ' ); 10069cdf0e10cSrcweir m_aPages.back().appendPoint( rDestPoint + Point( 0, rDestSize.Height()-1 ), aLine ); 10070cdf0e10cSrcweir aLine.append( " cm\n/Im" ); 10071cdf0e10cSrcweir aLine.append( rBitmap.m_nObject ); 10072cdf0e10cSrcweir aLine.append( " Do Q\n" ); 10073cdf0e10cSrcweir if( nCheckWidth == 0 || nCheckHeight == 0 ) 10074cdf0e10cSrcweir { 10075cdf0e10cSrcweir // #i97512# avoid invalid current matrix 10076cdf0e10cSrcweir aLine.setLength( 0 ); 10077cdf0e10cSrcweir aLine.append( "\n%bitmap image /Im" ); 10078cdf0e10cSrcweir aLine.append( rBitmap.m_nObject ); 10079cdf0e10cSrcweir aLine.append( " scaled to zero size, omitted\n" ); 10080cdf0e10cSrcweir } 10081cdf0e10cSrcweir writeBuffer( aLine.getStr(), aLine.getLength() ); 10082cdf0e10cSrcweir } 10083cdf0e10cSrcweir 10084cdf0e10cSrcweir const PDFWriterImpl::BitmapEmit& PDFWriterImpl::createBitmapEmit( const BitmapEx& i_rBitmap, bool bDrawMask ) 10085cdf0e10cSrcweir { 10086cdf0e10cSrcweir BitmapEx aBitmap( i_rBitmap ); 10087cdf0e10cSrcweir if( m_aContext.ColorMode == PDFWriter::DrawGreyscale ) 10088cdf0e10cSrcweir { 10089cdf0e10cSrcweir BmpConversion eConv = BMP_CONVERSION_8BIT_GREYS; 10090cdf0e10cSrcweir int nDepth = aBitmap.GetBitmap().GetBitCount(); 10091cdf0e10cSrcweir if( nDepth <= 4 ) 10092cdf0e10cSrcweir eConv = BMP_CONVERSION_4BIT_GREYS; 10093cdf0e10cSrcweir if( nDepth > 1 ) 10094cdf0e10cSrcweir aBitmap.Convert( eConv ); 10095cdf0e10cSrcweir } 10096cdf0e10cSrcweir BitmapID aID; 10097cdf0e10cSrcweir aID.m_aPixelSize = aBitmap.GetSizePixel(); 10098cdf0e10cSrcweir aID.m_nSize = aBitmap.GetBitCount(); 10099cdf0e10cSrcweir aID.m_nChecksum = aBitmap.GetBitmap().GetChecksum(); 10100cdf0e10cSrcweir aID.m_nMaskChecksum = 0; 10101cdf0e10cSrcweir if( aBitmap.IsAlpha() ) 10102cdf0e10cSrcweir aID.m_nMaskChecksum = aBitmap.GetAlpha().GetChecksum(); 10103cdf0e10cSrcweir else 10104cdf0e10cSrcweir { 10105cdf0e10cSrcweir Bitmap aMask = aBitmap.GetMask(); 10106cdf0e10cSrcweir if( ! aMask.IsEmpty() ) 10107cdf0e10cSrcweir aID.m_nMaskChecksum = aMask.GetChecksum(); 10108cdf0e10cSrcweir } 10109cdf0e10cSrcweir std::list< BitmapEmit >::const_iterator it; 10110cdf0e10cSrcweir for( it = m_aBitmaps.begin(); it != m_aBitmaps.end(); ++it ) 10111cdf0e10cSrcweir { 10112cdf0e10cSrcweir if( aID == it->m_aID ) 10113cdf0e10cSrcweir break; 10114cdf0e10cSrcweir } 10115cdf0e10cSrcweir if( it == m_aBitmaps.end() ) 10116cdf0e10cSrcweir { 10117cdf0e10cSrcweir m_aBitmaps.push_front( BitmapEmit() ); 10118cdf0e10cSrcweir m_aBitmaps.front().m_aID = aID; 10119cdf0e10cSrcweir m_aBitmaps.front().m_aBitmap = aBitmap; 10120cdf0e10cSrcweir m_aBitmaps.front().m_nObject = createObject(); 10121cdf0e10cSrcweir m_aBitmaps.front().m_bDrawMask = bDrawMask; 10122cdf0e10cSrcweir it = m_aBitmaps.begin(); 10123cdf0e10cSrcweir } 10124cdf0e10cSrcweir 10125cdf0e10cSrcweir OStringBuffer aObjName( 16 ); 10126cdf0e10cSrcweir aObjName.append( "Im" ); 10127cdf0e10cSrcweir aObjName.append( it->m_nObject ); 10128cdf0e10cSrcweir pushResource( ResXObject, aObjName.makeStringAndClear(), it->m_nObject ); 10129cdf0e10cSrcweir 10130cdf0e10cSrcweir return *it; 10131cdf0e10cSrcweir } 10132cdf0e10cSrcweir 10133cdf0e10cSrcweir void PDFWriterImpl::drawBitmap( const Point& rDestPoint, const Size& rDestSize, const Bitmap& rBitmap ) 10134cdf0e10cSrcweir { 10135cdf0e10cSrcweir MARK( "drawBitmap (Bitmap)" ); 10136cdf0e10cSrcweir 10137cdf0e10cSrcweir // #i40055# sanity check 10138cdf0e10cSrcweir if( ! (rDestSize.Width() && rDestSize.Height()) ) 10139cdf0e10cSrcweir return; 10140cdf0e10cSrcweir 10141cdf0e10cSrcweir const BitmapEmit& rEmit = createBitmapEmit( BitmapEx( rBitmap ) ); 10142cdf0e10cSrcweir drawBitmap( rDestPoint, rDestSize, rEmit, Color( COL_TRANSPARENT ) ); 10143cdf0e10cSrcweir } 10144cdf0e10cSrcweir 10145cdf0e10cSrcweir void PDFWriterImpl::drawBitmap( const Point& rDestPoint, const Size& rDestSize, const BitmapEx& rBitmap ) 10146cdf0e10cSrcweir { 10147cdf0e10cSrcweir MARK( "drawBitmap (BitmapEx)" ); 10148cdf0e10cSrcweir 10149cdf0e10cSrcweir // #i40055# sanity check 10150cdf0e10cSrcweir if( ! (rDestSize.Width() && rDestSize.Height()) ) 10151cdf0e10cSrcweir return; 10152cdf0e10cSrcweir 10153cdf0e10cSrcweir const BitmapEmit& rEmit = createBitmapEmit( rBitmap ); 10154cdf0e10cSrcweir drawBitmap( rDestPoint, rDestSize, rEmit, Color( COL_TRANSPARENT ) ); 10155cdf0e10cSrcweir } 10156cdf0e10cSrcweir 10157cdf0e10cSrcweir void PDFWriterImpl::drawMask( const Point& rDestPoint, const Size& rDestSize, const Bitmap& rBitmap, const Color& rFillColor ) 10158cdf0e10cSrcweir { 10159cdf0e10cSrcweir MARK( "drawMask" ); 10160cdf0e10cSrcweir 10161cdf0e10cSrcweir // #i40055# sanity check 10162cdf0e10cSrcweir if( ! (rDestSize.Width() && rDestSize.Height()) ) 10163cdf0e10cSrcweir return; 10164cdf0e10cSrcweir 10165cdf0e10cSrcweir Bitmap aBitmap( rBitmap ); 10166cdf0e10cSrcweir if( aBitmap.GetBitCount() > 1 ) 10167cdf0e10cSrcweir aBitmap.Convert( BMP_CONVERSION_1BIT_THRESHOLD ); 10168cdf0e10cSrcweir DBG_ASSERT( aBitmap.GetBitCount() == 1, "mask conversion failed" ); 10169cdf0e10cSrcweir 10170cdf0e10cSrcweir const BitmapEmit& rEmit = createBitmapEmit( BitmapEx( aBitmap ), true ); 10171cdf0e10cSrcweir drawBitmap( rDestPoint, rDestSize, rEmit, rFillColor ); 10172cdf0e10cSrcweir } 10173cdf0e10cSrcweir 10174cdf0e10cSrcweir sal_Int32 PDFWriterImpl::createGradient( const Gradient& rGradient, const Size& rSize ) 10175cdf0e10cSrcweir { 10176cdf0e10cSrcweir Size aPtSize( lcl_convert( m_aGraphicsStack.front().m_aMapMode, 10177cdf0e10cSrcweir MapMode( MAP_POINT ), 10178cdf0e10cSrcweir getReferenceDevice(), 10179cdf0e10cSrcweir rSize ) ); 10180cdf0e10cSrcweir // check if we already have this gradient 10181cdf0e10cSrcweir std::list<GradientEmit>::iterator it; 10182cdf0e10cSrcweir // rounding to point will generally lose some pixels 10183cdf0e10cSrcweir // round up to point boundary 10184cdf0e10cSrcweir aPtSize.Width()++; 10185cdf0e10cSrcweir aPtSize.Height()++; 10186cdf0e10cSrcweir for( it = m_aGradients.begin(); it != m_aGradients.end(); ++it ) 10187cdf0e10cSrcweir { 10188cdf0e10cSrcweir if( it->m_aGradient == rGradient ) 10189cdf0e10cSrcweir { 10190cdf0e10cSrcweir if( it->m_aSize == aPtSize ) 10191cdf0e10cSrcweir break; 10192cdf0e10cSrcweir } 10193cdf0e10cSrcweir } 10194cdf0e10cSrcweir if( it == m_aGradients.end() ) 10195cdf0e10cSrcweir { 10196cdf0e10cSrcweir m_aGradients.push_front( GradientEmit() ); 10197cdf0e10cSrcweir m_aGradients.front().m_aGradient = rGradient; 10198cdf0e10cSrcweir m_aGradients.front().m_nObject = createObject(); 10199cdf0e10cSrcweir m_aGradients.front().m_aSize = aPtSize; 10200cdf0e10cSrcweir it = m_aGradients.begin(); 10201cdf0e10cSrcweir } 10202cdf0e10cSrcweir 10203cdf0e10cSrcweir OStringBuffer aObjName( 16 ); 10204cdf0e10cSrcweir aObjName.append( 'P' ); 10205cdf0e10cSrcweir aObjName.append( it->m_nObject ); 10206cdf0e10cSrcweir pushResource( ResShading, aObjName.makeStringAndClear(), it->m_nObject ); 10207cdf0e10cSrcweir 10208cdf0e10cSrcweir return it->m_nObject; 10209cdf0e10cSrcweir } 10210cdf0e10cSrcweir 10211cdf0e10cSrcweir void PDFWriterImpl::drawGradient( const Rectangle& rRect, const Gradient& rGradient ) 10212cdf0e10cSrcweir { 10213cdf0e10cSrcweir MARK( "drawGradient (Rectangle)" ); 10214cdf0e10cSrcweir 10215cdf0e10cSrcweir if( m_aContext.Version == PDFWriter::PDF_1_2 ) 10216cdf0e10cSrcweir { 10217cdf0e10cSrcweir drawRectangle( rRect ); 10218cdf0e10cSrcweir return; 10219cdf0e10cSrcweir } 10220cdf0e10cSrcweir 10221cdf0e10cSrcweir sal_Int32 nGradient = createGradient( rGradient, rRect.GetSize() ); 10222cdf0e10cSrcweir 10223cdf0e10cSrcweir Point aTranslate( rRect.BottomLeft() ); 10224cdf0e10cSrcweir aTranslate += Point( 0, 1 ); 10225cdf0e10cSrcweir 10226cdf0e10cSrcweir updateGraphicsState(); 10227cdf0e10cSrcweir 10228cdf0e10cSrcweir OStringBuffer aLine( 80 ); 10229cdf0e10cSrcweir aLine.append( "q 1 0 0 1 " ); 10230cdf0e10cSrcweir m_aPages.back().appendPoint( aTranslate, aLine ); 10231cdf0e10cSrcweir aLine.append( " cm " ); 10232cdf0e10cSrcweir // if a stroke is appended reset the clip region before stroke 10233cdf0e10cSrcweir if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) ) 10234cdf0e10cSrcweir aLine.append( "q " ); 10235cdf0e10cSrcweir aLine.append( "0 0 " ); 10236cdf0e10cSrcweir m_aPages.back().appendMappedLength( (sal_Int32)rRect.GetWidth(), aLine, false ); 10237cdf0e10cSrcweir aLine.append( ' ' ); 10238cdf0e10cSrcweir m_aPages.back().appendMappedLength( (sal_Int32)rRect.GetHeight(), aLine, true ); 10239cdf0e10cSrcweir aLine.append( " re W n\n" ); 10240cdf0e10cSrcweir 10241cdf0e10cSrcweir aLine.append( "/P" ); 10242cdf0e10cSrcweir aLine.append( nGradient ); 10243cdf0e10cSrcweir aLine.append( " sh " ); 10244cdf0e10cSrcweir if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) ) 10245cdf0e10cSrcweir { 10246cdf0e10cSrcweir aLine.append( "Q 0 0 " ); 10247cdf0e10cSrcweir m_aPages.back().appendMappedLength( (sal_Int32)rRect.GetWidth(), aLine, false ); 10248cdf0e10cSrcweir aLine.append( ' ' ); 10249cdf0e10cSrcweir m_aPages.back().appendMappedLength( (sal_Int32)rRect.GetHeight(), aLine, true ); 10250cdf0e10cSrcweir aLine.append( " re S " ); 10251cdf0e10cSrcweir } 10252cdf0e10cSrcweir aLine.append( "Q\n" ); 10253cdf0e10cSrcweir writeBuffer( aLine.getStr(), aLine.getLength() ); 10254cdf0e10cSrcweir } 10255cdf0e10cSrcweir 10256cdf0e10cSrcweir void PDFWriterImpl::drawGradient( const PolyPolygon& rPolyPoly, const Gradient& rGradient ) 10257cdf0e10cSrcweir { 10258cdf0e10cSrcweir MARK( "drawGradient (PolyPolygon)" ); 10259cdf0e10cSrcweir 10260cdf0e10cSrcweir if( m_aContext.Version == PDFWriter::PDF_1_2 ) 10261cdf0e10cSrcweir { 10262cdf0e10cSrcweir drawPolyPolygon( rPolyPoly ); 10263cdf0e10cSrcweir return; 10264cdf0e10cSrcweir } 10265cdf0e10cSrcweir 10266cdf0e10cSrcweir Rectangle aBoundRect = rPolyPoly.GetBoundRect(); 10267cdf0e10cSrcweir sal_Int32 nGradient = createGradient( rGradient, aBoundRect.GetSize() ); 10268cdf0e10cSrcweir 10269cdf0e10cSrcweir updateGraphicsState(); 10270cdf0e10cSrcweir 10271cdf0e10cSrcweir Point aTranslate = aBoundRect.BottomLeft(); 10272cdf0e10cSrcweir int nPolygons = rPolyPoly.Count(); 10273cdf0e10cSrcweir 10274cdf0e10cSrcweir OStringBuffer aLine( 80*nPolygons ); 10275cdf0e10cSrcweir aLine.append( "q " ); 10276cdf0e10cSrcweir // set PolyPolygon as clip path 10277cdf0e10cSrcweir m_aPages.back().appendPolyPolygon( rPolyPoly, aLine ); 10278cdf0e10cSrcweir aLine.append( "W* n\n" ); 10279cdf0e10cSrcweir aLine.append( "1 0 0 1 " ); 10280cdf0e10cSrcweir m_aPages.back().appendPoint( aTranslate, aLine ); 10281cdf0e10cSrcweir aLine.append( " cm\n" ); 10282cdf0e10cSrcweir aLine.append( "/P" ); 10283cdf0e10cSrcweir aLine.append( nGradient ); 10284cdf0e10cSrcweir aLine.append( " sh Q\n" ); 10285cdf0e10cSrcweir if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) ) 10286cdf0e10cSrcweir { 10287cdf0e10cSrcweir // and draw the surrounding path 10288cdf0e10cSrcweir m_aPages.back().appendPolyPolygon( rPolyPoly, aLine ); 10289cdf0e10cSrcweir aLine.append( "S\n" ); 10290cdf0e10cSrcweir } 10291cdf0e10cSrcweir writeBuffer( aLine.getStr(), aLine.getLength() ); 10292cdf0e10cSrcweir } 10293cdf0e10cSrcweir 10294cdf0e10cSrcweir void PDFWriterImpl::drawHatch( const PolyPolygon& rPolyPoly, const Hatch& rHatch ) 10295cdf0e10cSrcweir { 10296cdf0e10cSrcweir MARK( "drawHatch" ); 10297cdf0e10cSrcweir 10298cdf0e10cSrcweir updateGraphicsState(); 10299cdf0e10cSrcweir 10300cdf0e10cSrcweir if( rPolyPoly.Count() ) 10301cdf0e10cSrcweir { 10302cdf0e10cSrcweir PolyPolygon aPolyPoly( rPolyPoly ); 10303cdf0e10cSrcweir 10304cdf0e10cSrcweir aPolyPoly.Optimize( POLY_OPTIMIZE_NO_SAME ); 10305cdf0e10cSrcweir push( PUSH_LINECOLOR ); 10306cdf0e10cSrcweir setLineColor( rHatch.GetColor() ); 10307cdf0e10cSrcweir getReferenceDevice()->ImplDrawHatch( aPolyPoly, rHatch, sal_False ); 10308cdf0e10cSrcweir pop(); 10309cdf0e10cSrcweir } 10310cdf0e10cSrcweir } 10311cdf0e10cSrcweir 10312cdf0e10cSrcweir void PDFWriterImpl::drawWallpaper( const Rectangle& rRect, const Wallpaper& rWall ) 10313cdf0e10cSrcweir { 10314cdf0e10cSrcweir MARK( "drawWallpaper" ); 10315cdf0e10cSrcweir 10316cdf0e10cSrcweir bool bDrawColor = false; 10317cdf0e10cSrcweir bool bDrawGradient = false; 10318cdf0e10cSrcweir bool bDrawBitmap = false; 10319cdf0e10cSrcweir 10320cdf0e10cSrcweir BitmapEx aBitmap; 10321cdf0e10cSrcweir Point aBmpPos = rRect.TopLeft(); 10322cdf0e10cSrcweir Size aBmpSize; 10323cdf0e10cSrcweir if( rWall.IsBitmap() ) 10324cdf0e10cSrcweir { 10325cdf0e10cSrcweir aBitmap = rWall.GetBitmap(); 10326cdf0e10cSrcweir aBmpSize = lcl_convert( aBitmap.GetPrefMapMode(), 10327cdf0e10cSrcweir getMapMode(), 10328cdf0e10cSrcweir getReferenceDevice(), 10329cdf0e10cSrcweir aBitmap.GetPrefSize() ); 10330cdf0e10cSrcweir Rectangle aRect( rRect ); 10331cdf0e10cSrcweir if( rWall.IsRect() ) 10332cdf0e10cSrcweir { 10333cdf0e10cSrcweir aRect = rWall.GetRect(); 10334cdf0e10cSrcweir aBmpPos = aRect.TopLeft(); 10335cdf0e10cSrcweir aBmpSize = aRect.GetSize(); 10336cdf0e10cSrcweir } 10337cdf0e10cSrcweir if( rWall.GetStyle() != WALLPAPER_SCALE ) 10338cdf0e10cSrcweir { 10339cdf0e10cSrcweir if( rWall.GetStyle() != WALLPAPER_TILE ) 10340cdf0e10cSrcweir { 10341cdf0e10cSrcweir bDrawBitmap = true; 10342cdf0e10cSrcweir if( rWall.IsGradient() ) 10343cdf0e10cSrcweir bDrawGradient = true; 10344cdf0e10cSrcweir else 10345cdf0e10cSrcweir bDrawColor = true; 10346cdf0e10cSrcweir switch( rWall.GetStyle() ) 10347cdf0e10cSrcweir { 10348cdf0e10cSrcweir case WALLPAPER_TOPLEFT: 10349cdf0e10cSrcweir break; 10350cdf0e10cSrcweir case WALLPAPER_TOP: 10351cdf0e10cSrcweir aBmpPos.X() += (aRect.GetWidth()-aBmpSize.Width())/2; 10352cdf0e10cSrcweir break; 10353cdf0e10cSrcweir case WALLPAPER_LEFT: 10354cdf0e10cSrcweir aBmpPos.Y() += (aRect.GetHeight()-aBmpSize.Height())/2; 10355cdf0e10cSrcweir break; 10356cdf0e10cSrcweir case WALLPAPER_TOPRIGHT: 10357cdf0e10cSrcweir aBmpPos.X() += aRect.GetWidth()-aBmpSize.Width(); 10358cdf0e10cSrcweir break; 10359cdf0e10cSrcweir case WALLPAPER_CENTER: 10360cdf0e10cSrcweir aBmpPos.X() += (aRect.GetWidth()-aBmpSize.Width())/2; 10361cdf0e10cSrcweir aBmpPos.Y() += (aRect.GetHeight()-aBmpSize.Height())/2; 10362cdf0e10cSrcweir break; 10363cdf0e10cSrcweir case WALLPAPER_RIGHT: 10364cdf0e10cSrcweir aBmpPos.X() += aRect.GetWidth()-aBmpSize.Width(); 10365cdf0e10cSrcweir aBmpPos.Y() += (aRect.GetHeight()-aBmpSize.Height())/2; 10366cdf0e10cSrcweir break; 10367cdf0e10cSrcweir case WALLPAPER_BOTTOMLEFT: 10368cdf0e10cSrcweir aBmpPos.Y() += aRect.GetHeight()-aBmpSize.Height(); 10369cdf0e10cSrcweir break; 10370cdf0e10cSrcweir case WALLPAPER_BOTTOM: 10371cdf0e10cSrcweir aBmpPos.X() += (aRect.GetWidth()-aBmpSize.Width())/2; 10372cdf0e10cSrcweir aBmpPos.Y() += aRect.GetHeight()-aBmpSize.Height(); 10373cdf0e10cSrcweir break; 10374cdf0e10cSrcweir case WALLPAPER_BOTTOMRIGHT: 10375cdf0e10cSrcweir aBmpPos.X() += aRect.GetWidth()-aBmpSize.Width(); 10376cdf0e10cSrcweir aBmpPos.Y() += aRect.GetHeight()-aBmpSize.Height(); 10377cdf0e10cSrcweir break; 10378cdf0e10cSrcweir default: ; 10379cdf0e10cSrcweir } 10380cdf0e10cSrcweir } 10381cdf0e10cSrcweir else 10382cdf0e10cSrcweir { 10383cdf0e10cSrcweir // push the bitmap 10384cdf0e10cSrcweir const BitmapEmit& rEmit = createBitmapEmit( BitmapEx( aBitmap ) ); 10385cdf0e10cSrcweir 10386cdf0e10cSrcweir // convert to page coordinates; this needs to be done here 10387cdf0e10cSrcweir // since the emit does not know the page anymore 10388cdf0e10cSrcweir Rectangle aConvertRect( aBmpPos, aBmpSize ); 10389cdf0e10cSrcweir m_aPages.back().convertRect( aConvertRect ); 10390cdf0e10cSrcweir 10391cdf0e10cSrcweir OStringBuffer aNameBuf(16); 10392cdf0e10cSrcweir aNameBuf.append( "Im" ); 10393cdf0e10cSrcweir aNameBuf.append( rEmit.m_nObject ); 10394cdf0e10cSrcweir OString aImageName( aNameBuf.makeStringAndClear() ); 10395cdf0e10cSrcweir 10396cdf0e10cSrcweir // push the pattern 10397cdf0e10cSrcweir OStringBuffer aTilingStream( 32 ); 10398cdf0e10cSrcweir appendFixedInt( aConvertRect.GetWidth(), aTilingStream ); 10399cdf0e10cSrcweir aTilingStream.append( " 0 0 " ); 10400cdf0e10cSrcweir appendFixedInt( aConvertRect.GetHeight(), aTilingStream ); 10401cdf0e10cSrcweir aTilingStream.append( " 0 0 cm\n/" ); 10402cdf0e10cSrcweir aTilingStream.append( aImageName ); 10403cdf0e10cSrcweir aTilingStream.append( " Do\n" ); 10404cdf0e10cSrcweir 10405cdf0e10cSrcweir m_aTilings.push_back( TilingEmit() ); 10406cdf0e10cSrcweir m_aTilings.back().m_nObject = createObject(); 10407cdf0e10cSrcweir m_aTilings.back().m_aRectangle = Rectangle( Point( 0, 0 ), aConvertRect.GetSize() ); 10408cdf0e10cSrcweir m_aTilings.back().m_pTilingStream = new SvMemoryStream(); 10409cdf0e10cSrcweir m_aTilings.back().m_pTilingStream->Write( aTilingStream.getStr(), aTilingStream.getLength() ); 10410cdf0e10cSrcweir // phase the tiling so wallpaper begins on upper left 10411cdf0e10cSrcweir m_aTilings.back().m_aTransform.matrix[2] = double(aConvertRect.Left() % aConvertRect.GetWidth()) / fDivisor; 10412cdf0e10cSrcweir m_aTilings.back().m_aTransform.matrix[5] = double(aConvertRect.Top() % aConvertRect.GetHeight()) / fDivisor; 10413cdf0e10cSrcweir m_aTilings.back().m_aResources.m_aXObjects[aImageName] = rEmit.m_nObject; 10414cdf0e10cSrcweir 10415cdf0e10cSrcweir updateGraphicsState(); 10416cdf0e10cSrcweir 10417cdf0e10cSrcweir OStringBuffer aObjName( 16 ); 10418cdf0e10cSrcweir aObjName.append( 'P' ); 10419cdf0e10cSrcweir aObjName.append( m_aTilings.back().m_nObject ); 10420cdf0e10cSrcweir OString aPatternName( aObjName.makeStringAndClear() ); 10421cdf0e10cSrcweir pushResource( ResPattern, aPatternName, m_aTilings.back().m_nObject ); 10422cdf0e10cSrcweir 10423cdf0e10cSrcweir // fill a rRect with the pattern 10424cdf0e10cSrcweir OStringBuffer aLine( 100 ); 10425cdf0e10cSrcweir aLine.append( "q /Pattern cs /" ); 10426cdf0e10cSrcweir aLine.append( aPatternName ); 10427cdf0e10cSrcweir aLine.append( " scn " ); 10428cdf0e10cSrcweir m_aPages.back().appendRect( rRect, aLine ); 10429cdf0e10cSrcweir aLine.append( " f Q\n" ); 10430cdf0e10cSrcweir writeBuffer( aLine.getStr(), aLine.getLength() ); 10431cdf0e10cSrcweir } 10432cdf0e10cSrcweir } 10433cdf0e10cSrcweir else 10434cdf0e10cSrcweir { 10435cdf0e10cSrcweir aBmpPos = aRect.TopLeft(); 10436cdf0e10cSrcweir aBmpSize = aRect.GetSize(); 10437cdf0e10cSrcweir bDrawBitmap = true; 10438cdf0e10cSrcweir } 10439cdf0e10cSrcweir 10440cdf0e10cSrcweir if( aBitmap.IsTransparent() ) 10441cdf0e10cSrcweir { 10442cdf0e10cSrcweir if( rWall.IsGradient() ) 10443cdf0e10cSrcweir bDrawGradient = true; 10444cdf0e10cSrcweir else 10445cdf0e10cSrcweir bDrawColor = true; 10446cdf0e10cSrcweir } 10447cdf0e10cSrcweir } 10448cdf0e10cSrcweir else if( rWall.IsGradient() ) 10449cdf0e10cSrcweir bDrawGradient = true; 10450cdf0e10cSrcweir else 10451cdf0e10cSrcweir bDrawColor = true; 10452cdf0e10cSrcweir 10453cdf0e10cSrcweir if( bDrawGradient ) 10454cdf0e10cSrcweir { 10455cdf0e10cSrcweir drawGradient( rRect, rWall.GetGradient() ); 10456cdf0e10cSrcweir } 10457cdf0e10cSrcweir if( bDrawColor ) 10458cdf0e10cSrcweir { 10459cdf0e10cSrcweir Color aOldLineColor = m_aGraphicsStack.front().m_aLineColor; 10460cdf0e10cSrcweir Color aOldFillColor = m_aGraphicsStack.front().m_aFillColor; 10461cdf0e10cSrcweir setLineColor( Color( COL_TRANSPARENT ) ); 10462cdf0e10cSrcweir setFillColor( rWall.GetColor() ); 10463cdf0e10cSrcweir drawRectangle( rRect ); 10464cdf0e10cSrcweir setLineColor( aOldLineColor ); 10465cdf0e10cSrcweir setFillColor( aOldFillColor ); 10466cdf0e10cSrcweir } 10467cdf0e10cSrcweir if( bDrawBitmap ) 10468cdf0e10cSrcweir { 10469cdf0e10cSrcweir // set temporary clip region since aBmpPos and aBmpSize 10470cdf0e10cSrcweir // may be outside rRect 10471cdf0e10cSrcweir OStringBuffer aLine( 20 ); 10472cdf0e10cSrcweir aLine.append( "q " ); 10473cdf0e10cSrcweir m_aPages.back().appendRect( rRect, aLine ); 10474cdf0e10cSrcweir aLine.append( " W n\n" ); 10475cdf0e10cSrcweir writeBuffer( aLine.getStr(), aLine.getLength() ); 10476cdf0e10cSrcweir drawBitmap( aBmpPos, aBmpSize, aBitmap ); 10477cdf0e10cSrcweir writeBuffer( "Q\n", 2 ); 10478cdf0e10cSrcweir } 10479cdf0e10cSrcweir } 10480cdf0e10cSrcweir 10481cdf0e10cSrcweir void PDFWriterImpl::beginPattern( const Rectangle& rCellRect ) 10482cdf0e10cSrcweir { 10483cdf0e10cSrcweir beginRedirect( new SvMemoryStream(), rCellRect ); 10484cdf0e10cSrcweir } 10485cdf0e10cSrcweir 10486cdf0e10cSrcweir sal_Int32 PDFWriterImpl::endPattern( const SvtGraphicFill::Transform& rTransform ) 10487cdf0e10cSrcweir { 10488cdf0e10cSrcweir Rectangle aConvertRect( getRedirectTargetRect() ); 10489cdf0e10cSrcweir DBG_ASSERT( aConvertRect.GetWidth() != 0 && aConvertRect.GetHeight() != 0, "empty cell rectangle in pattern" ); 10490cdf0e10cSrcweir 10491cdf0e10cSrcweir // get scaling between current mapmode and PDF output 10492cdf0e10cSrcweir Size aScaling( lcl_convert( m_aGraphicsStack.front().m_aMapMode, m_aMapMode, getReferenceDevice(), Size( 10000, 10000 ) ) ); 10493cdf0e10cSrcweir double fSX = (double(aScaling.Width()) / 10000.0); 10494cdf0e10cSrcweir double fSY = (double(aScaling.Height()) / 10000.0); 10495cdf0e10cSrcweir 10496cdf0e10cSrcweir // transform translation part of matrix 10497cdf0e10cSrcweir Size aTranslation( (long)rTransform.matrix[2], (long)rTransform.matrix[5] ); 10498cdf0e10cSrcweir aTranslation = lcl_convert( m_aGraphicsStack.front().m_aMapMode, m_aMapMode, getReferenceDevice(), aTranslation ); 10499cdf0e10cSrcweir 10500cdf0e10cSrcweir sal_Int32 nTilingId = m_aTilings.size(); 10501cdf0e10cSrcweir m_aTilings.push_back( TilingEmit() ); 10502cdf0e10cSrcweir TilingEmit& rTile = m_aTilings.back(); 10503cdf0e10cSrcweir rTile.m_nObject = createObject(); 10504cdf0e10cSrcweir rTile.m_aResources = m_aOutputStreams.front().m_aResourceDict; 10505cdf0e10cSrcweir rTile.m_aTransform.matrix[0] = rTransform.matrix[0] * fSX; 10506cdf0e10cSrcweir rTile.m_aTransform.matrix[1] = rTransform.matrix[1] * fSY; 10507cdf0e10cSrcweir rTile.m_aTransform.matrix[2] = aTranslation.Width(); 10508cdf0e10cSrcweir rTile.m_aTransform.matrix[3] = rTransform.matrix[3] * fSX; 10509cdf0e10cSrcweir rTile.m_aTransform.matrix[4] = rTransform.matrix[4] * fSY; 10510cdf0e10cSrcweir rTile.m_aTransform.matrix[5] = -aTranslation.Height(); 10511cdf0e10cSrcweir // caution: endRedirect pops the stream, so do this last 10512cdf0e10cSrcweir rTile.m_pTilingStream = dynamic_cast<SvMemoryStream*>(endRedirect()); 10513cdf0e10cSrcweir // FIXME: bound rect will not work with rotated matrix 10514cdf0e10cSrcweir rTile.m_aRectangle = Rectangle( Point(0,0), aConvertRect.GetSize() ); 10515cdf0e10cSrcweir rTile.m_aCellSize = aConvertRect.GetSize(); 10516cdf0e10cSrcweir 10517cdf0e10cSrcweir OStringBuffer aObjName( 16 ); 10518cdf0e10cSrcweir aObjName.append( 'P' ); 10519cdf0e10cSrcweir aObjName.append( rTile.m_nObject ); 10520cdf0e10cSrcweir pushResource( ResPattern, aObjName.makeStringAndClear(), rTile.m_nObject ); 10521cdf0e10cSrcweir return nTilingId; 10522cdf0e10cSrcweir } 10523cdf0e10cSrcweir 10524cdf0e10cSrcweir void PDFWriterImpl::drawPolyPolygon( const PolyPolygon& rPolyPoly, sal_Int32 nPattern, bool bEOFill ) 10525cdf0e10cSrcweir { 10526cdf0e10cSrcweir if( nPattern < 0 || nPattern >= (sal_Int32)m_aTilings.size() ) 10527cdf0e10cSrcweir return; 10528cdf0e10cSrcweir 10529cdf0e10cSrcweir m_aPages.back().endStream(); 10530cdf0e10cSrcweir sal_Int32 nXObject = createObject(); 10531cdf0e10cSrcweir OStringBuffer aNameBuf( 16 ); 10532cdf0e10cSrcweir aNameBuf.append( "Pol" ); 10533cdf0e10cSrcweir aNameBuf.append( nXObject ); 10534cdf0e10cSrcweir OString aObjName( aNameBuf.makeStringAndClear() ); 10535cdf0e10cSrcweir Rectangle aObjRect; 10536cdf0e10cSrcweir if( updateObject( nXObject ) ) 10537cdf0e10cSrcweir { 10538cdf0e10cSrcweir // get bounding rect of object 10539cdf0e10cSrcweir PolyPolygon aSubDiv; 10540cdf0e10cSrcweir rPolyPoly.AdaptiveSubdivide( aSubDiv ); 10541cdf0e10cSrcweir aObjRect = aSubDiv.GetBoundRect(); 10542cdf0e10cSrcweir Rectangle aConvObjRect( aObjRect ); 10543cdf0e10cSrcweir m_aPages.back().convertRect( aConvObjRect ); 10544cdf0e10cSrcweir 10545cdf0e10cSrcweir // move polypolygon to bottom left of page 10546cdf0e10cSrcweir PolyPolygon aLocalPath( rPolyPoly ); 10547cdf0e10cSrcweir sal_Int32 nPgWd = getReferenceDevice()->ImplGetDPIX() * m_aPages.back().getWidth() / 72; 10548cdf0e10cSrcweir sal_Int32 nPgHt = getReferenceDevice()->ImplGetDPIY() * m_aPages.back().getHeight() / 72; 10549cdf0e10cSrcweir Size aLogicPgSz = getReferenceDevice()->PixelToLogic( Size( nPgWd, nPgHt ), m_aGraphicsStack.front().m_aMapMode ); 10550cdf0e10cSrcweir sal_Int32 nXOff = aObjRect.Left(); 10551cdf0e10cSrcweir sal_Int32 nYOff = aLogicPgSz.Height() - aObjRect.Bottom(); 10552cdf0e10cSrcweir aLocalPath.Move( -nXOff, nYOff ); 10553cdf0e10cSrcweir 10554cdf0e10cSrcweir // prepare XObject's content stream 10555cdf0e10cSrcweir OStringBuffer aStream( 512 ); 10556cdf0e10cSrcweir aStream.append( "/Pattern cs /P" ); 10557cdf0e10cSrcweir aStream.append( m_aTilings[ nPattern ].m_nObject ); 10558cdf0e10cSrcweir aStream.append( " scn\n" ); 10559cdf0e10cSrcweir m_aPages.back().appendPolyPolygon( aLocalPath, aStream ); 10560cdf0e10cSrcweir aStream.append( bEOFill ? "f*" : "f" ); 10561cdf0e10cSrcweir SvMemoryStream aMemStream( aStream.getLength() ); 10562cdf0e10cSrcweir aMemStream.Write( aStream.getStr(), aStream.getLength() ); 10563cdf0e10cSrcweir bool bDeflate = compressStream( &aMemStream ); 10564cdf0e10cSrcweir aMemStream.Seek( STREAM_SEEK_TO_END ); 10565cdf0e10cSrcweir sal_Int32 nStreamLen = (sal_Int32)aMemStream.Tell(); 10566cdf0e10cSrcweir aMemStream.Seek( STREAM_SEEK_TO_BEGIN ); 10567cdf0e10cSrcweir 10568cdf0e10cSrcweir // add new XObject to global resource dict 10569cdf0e10cSrcweir m_aGlobalResourceDict.m_aXObjects[ aObjName ] = nXObject; 10570cdf0e10cSrcweir 10571cdf0e10cSrcweir // write XObject 10572cdf0e10cSrcweir OStringBuffer aLine( 512 ); 10573cdf0e10cSrcweir aLine.append( nXObject ); 10574cdf0e10cSrcweir aLine.append( " 0 obj\n" 10575cdf0e10cSrcweir "<</Type/XObject/Subtype/Form/BBox[0 0 " ); 10576cdf0e10cSrcweir appendFixedInt( aConvObjRect.GetWidth(), aLine ); 10577cdf0e10cSrcweir aLine.append( ' ' ); 10578cdf0e10cSrcweir appendFixedInt( aConvObjRect.GetHeight(), aLine ); 10579cdf0e10cSrcweir aLine.append( "]/Length " ); 10580cdf0e10cSrcweir aLine.append( nStreamLen ); 10581cdf0e10cSrcweir if( bDeflate ) 10582cdf0e10cSrcweir aLine.append( "/Filter/FlateDecode" ); 10583cdf0e10cSrcweir aLine.append( ">>\n" 10584cdf0e10cSrcweir "stream\n" ); 10585cdf0e10cSrcweir writeBuffer( aLine.getStr(), aLine.getLength() ); 10586cdf0e10cSrcweir checkAndEnableStreamEncryption( nXObject ); 10587cdf0e10cSrcweir writeBuffer( aMemStream.GetData(), nStreamLen ); 10588cdf0e10cSrcweir disableStreamEncryption(); 10589cdf0e10cSrcweir writeBuffer( "\nendstream\nendobj\n\n", 19 ); 10590cdf0e10cSrcweir } 10591cdf0e10cSrcweir m_aPages.back().beginStream(); 10592cdf0e10cSrcweir OStringBuffer aLine( 80 ); 10593cdf0e10cSrcweir aLine.append( "q 1 0 0 1 " ); 10594cdf0e10cSrcweir m_aPages.back().appendPoint( aObjRect.BottomLeft(), aLine ); 10595cdf0e10cSrcweir aLine.append( " cm/" ); 10596cdf0e10cSrcweir aLine.append( aObjName ); 10597cdf0e10cSrcweir aLine.append( " Do Q\n" ); 10598cdf0e10cSrcweir writeBuffer( aLine.getStr(), aLine.getLength() ); 10599cdf0e10cSrcweir } 10600cdf0e10cSrcweir 10601cdf0e10cSrcweir void PDFWriterImpl::updateGraphicsState() 10602cdf0e10cSrcweir { 10603cdf0e10cSrcweir OStringBuffer aLine( 256 ); 10604cdf0e10cSrcweir GraphicsState& rNewState = m_aGraphicsStack.front(); 10605cdf0e10cSrcweir // first set clip region since it might invalidate everything else 10606cdf0e10cSrcweir 10607cdf0e10cSrcweir if( (rNewState.m_nUpdateFlags & GraphicsState::updateClipRegion) ) 10608cdf0e10cSrcweir { 10609cdf0e10cSrcweir rNewState.m_nUpdateFlags &= ~GraphicsState::updateClipRegion; 10610cdf0e10cSrcweir 10611cdf0e10cSrcweir if( m_aCurrentPDFState.m_bClipRegion != rNewState.m_bClipRegion || 10612cdf0e10cSrcweir ( rNewState.m_bClipRegion && m_aCurrentPDFState.m_aClipRegion != rNewState.m_aClipRegion ) ) 10613cdf0e10cSrcweir { 10614cdf0e10cSrcweir if( m_aCurrentPDFState.m_bClipRegion && m_aCurrentPDFState.m_aClipRegion.count() ) 10615cdf0e10cSrcweir { 10616cdf0e10cSrcweir aLine.append( "Q " ); 10617cdf0e10cSrcweir // invalidate everything but the clip region 10618cdf0e10cSrcweir m_aCurrentPDFState = GraphicsState(); 10619cdf0e10cSrcweir rNewState.m_nUpdateFlags = sal::static_int_cast<sal_uInt16>(~GraphicsState::updateClipRegion); 10620cdf0e10cSrcweir } 10621cdf0e10cSrcweir if( rNewState.m_bClipRegion && rNewState.m_aClipRegion.count() ) 10622cdf0e10cSrcweir { 10623cdf0e10cSrcweir // clip region is always stored in private PDF mapmode 10624cdf0e10cSrcweir MapMode aNewMapMode = rNewState.m_aMapMode; 10625cdf0e10cSrcweir rNewState.m_aMapMode = m_aMapMode; 10626cdf0e10cSrcweir getReferenceDevice()->SetMapMode( rNewState.m_aMapMode ); 10627cdf0e10cSrcweir m_aCurrentPDFState.m_aMapMode = rNewState.m_aMapMode; 10628cdf0e10cSrcweir 10629cdf0e10cSrcweir aLine.append( "q " ); 10630cdf0e10cSrcweir m_aPages.back().appendPolyPolygon( rNewState.m_aClipRegion, aLine ); 10631cdf0e10cSrcweir aLine.append( "W* n\n" ); 10632cdf0e10cSrcweir rNewState.m_aMapMode = aNewMapMode; 10633cdf0e10cSrcweir getReferenceDevice()->SetMapMode( rNewState.m_aMapMode ); 10634cdf0e10cSrcweir m_aCurrentPDFState.m_aMapMode = rNewState.m_aMapMode; 10635cdf0e10cSrcweir } 10636cdf0e10cSrcweir } 10637cdf0e10cSrcweir } 10638cdf0e10cSrcweir 10639cdf0e10cSrcweir if( (rNewState.m_nUpdateFlags & GraphicsState::updateMapMode) ) 10640cdf0e10cSrcweir { 10641cdf0e10cSrcweir rNewState.m_nUpdateFlags &= ~GraphicsState::updateMapMode; 10642cdf0e10cSrcweir getReferenceDevice()->SetMapMode( rNewState.m_aMapMode ); 10643cdf0e10cSrcweir } 10644cdf0e10cSrcweir 10645cdf0e10cSrcweir if( (rNewState.m_nUpdateFlags & GraphicsState::updateFont) ) 10646cdf0e10cSrcweir { 10647cdf0e10cSrcweir rNewState.m_nUpdateFlags &= ~GraphicsState::updateFont; 10648cdf0e10cSrcweir getReferenceDevice()->SetFont( rNewState.m_aFont ); 10649cdf0e10cSrcweir getReferenceDevice()->ImplNewFont(); 10650cdf0e10cSrcweir } 10651cdf0e10cSrcweir 10652cdf0e10cSrcweir if( (rNewState.m_nUpdateFlags & GraphicsState::updateLayoutMode) ) 10653cdf0e10cSrcweir { 10654cdf0e10cSrcweir rNewState.m_nUpdateFlags &= ~GraphicsState::updateLayoutMode; 10655cdf0e10cSrcweir getReferenceDevice()->SetLayoutMode( rNewState.m_nLayoutMode ); 10656cdf0e10cSrcweir } 10657cdf0e10cSrcweir 10658cdf0e10cSrcweir if( (rNewState.m_nUpdateFlags & GraphicsState::updateDigitLanguage) ) 10659cdf0e10cSrcweir { 10660cdf0e10cSrcweir rNewState.m_nUpdateFlags &= ~GraphicsState::updateDigitLanguage; 10661cdf0e10cSrcweir getReferenceDevice()->SetDigitLanguage( rNewState.m_aDigitLanguage ); 10662cdf0e10cSrcweir } 10663cdf0e10cSrcweir 10664cdf0e10cSrcweir if( (rNewState.m_nUpdateFlags & GraphicsState::updateLineColor) ) 10665cdf0e10cSrcweir { 10666cdf0e10cSrcweir rNewState.m_nUpdateFlags &= ~GraphicsState::updateLineColor; 10667cdf0e10cSrcweir if( m_aCurrentPDFState.m_aLineColor != rNewState.m_aLineColor && 10668cdf0e10cSrcweir rNewState.m_aLineColor != Color( COL_TRANSPARENT ) ) 10669cdf0e10cSrcweir { 10670cdf0e10cSrcweir appendStrokingColor( rNewState.m_aLineColor, aLine ); 10671cdf0e10cSrcweir aLine.append( "\n" ); 10672cdf0e10cSrcweir } 10673cdf0e10cSrcweir } 10674cdf0e10cSrcweir 10675cdf0e10cSrcweir if( (rNewState.m_nUpdateFlags & GraphicsState::updateFillColor) ) 10676cdf0e10cSrcweir { 10677cdf0e10cSrcweir rNewState.m_nUpdateFlags &= ~GraphicsState::updateFillColor; 10678cdf0e10cSrcweir if( m_aCurrentPDFState.m_aFillColor != rNewState.m_aFillColor && 10679cdf0e10cSrcweir rNewState.m_aFillColor != Color( COL_TRANSPARENT ) ) 10680cdf0e10cSrcweir { 10681cdf0e10cSrcweir appendNonStrokingColor( rNewState.m_aFillColor, aLine ); 10682cdf0e10cSrcweir aLine.append( "\n" ); 10683cdf0e10cSrcweir } 10684cdf0e10cSrcweir } 10685cdf0e10cSrcweir 10686cdf0e10cSrcweir if( (rNewState.m_nUpdateFlags & GraphicsState::updateTransparentPercent) ) 10687cdf0e10cSrcweir { 10688cdf0e10cSrcweir rNewState.m_nUpdateFlags &= ~GraphicsState::updateTransparentPercent; 10689cdf0e10cSrcweir if( m_aContext.Version >= PDFWriter::PDF_1_4 && m_aCurrentPDFState.m_nTransparentPercent != rNewState.m_nTransparentPercent ) 10690cdf0e10cSrcweir { 10691cdf0e10cSrcweir // TODO: switch extended graphicsstate 10692cdf0e10cSrcweir } 10693cdf0e10cSrcweir } 10694cdf0e10cSrcweir 10695cdf0e10cSrcweir // everything is up to date now 10696cdf0e10cSrcweir m_aCurrentPDFState = m_aGraphicsStack.front(); 10697cdf0e10cSrcweir if( aLine.getLength() ) 10698cdf0e10cSrcweir writeBuffer( aLine.getStr(), aLine.getLength() ); 10699cdf0e10cSrcweir } 10700cdf0e10cSrcweir 10701cdf0e10cSrcweir /* #i47544# imitate OutputDevice behaviour: 10702cdf0e10cSrcweir * if a font with a nontransparent color is set, it overwrites the current 10703cdf0e10cSrcweir * text color. OTOH setting the text color will overwrite the color of the font. 10704cdf0e10cSrcweir */ 10705cdf0e10cSrcweir void PDFWriterImpl::setFont( const Font& rFont ) 10706cdf0e10cSrcweir { 10707cdf0e10cSrcweir Color aColor = rFont.GetColor(); 10708cdf0e10cSrcweir if( aColor == Color( COL_TRANSPARENT ) ) 10709cdf0e10cSrcweir aColor = m_aGraphicsStack.front().m_aFont.GetColor(); 10710cdf0e10cSrcweir m_aGraphicsStack.front().m_aFont = rFont; 10711cdf0e10cSrcweir m_aGraphicsStack.front().m_aFont.SetColor( aColor ); 10712cdf0e10cSrcweir m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsState::updateFont; 10713cdf0e10cSrcweir } 10714cdf0e10cSrcweir 10715cdf0e10cSrcweir void PDFWriterImpl::push( sal_uInt16 nFlags ) 10716cdf0e10cSrcweir { 10717cdf0e10cSrcweir OSL_ENSURE( m_aGraphicsStack.size() > 0, "invalid graphics stack" ); 10718cdf0e10cSrcweir m_aGraphicsStack.push_front( m_aGraphicsStack.front() ); 10719cdf0e10cSrcweir m_aGraphicsStack.front().m_nFlags = nFlags; 10720cdf0e10cSrcweir } 10721cdf0e10cSrcweir 10722cdf0e10cSrcweir void PDFWriterImpl::pop() 10723cdf0e10cSrcweir { 10724cdf0e10cSrcweir OSL_ENSURE( m_aGraphicsStack.size() > 1, "pop without push" ); 10725cdf0e10cSrcweir if( m_aGraphicsStack.size() < 2 ) 10726cdf0e10cSrcweir return; 10727cdf0e10cSrcweir 10728cdf0e10cSrcweir GraphicsState aState = m_aGraphicsStack.front(); 10729cdf0e10cSrcweir m_aGraphicsStack.pop_front(); 10730cdf0e10cSrcweir GraphicsState& rOld = m_aGraphicsStack.front(); 10731cdf0e10cSrcweir 10732cdf0e10cSrcweir // move those parameters back that were not pushed 10733cdf0e10cSrcweir // in the first place 10734cdf0e10cSrcweir if( ! (aState.m_nFlags & PUSH_LINECOLOR) ) 10735cdf0e10cSrcweir setLineColor( aState.m_aLineColor ); 10736cdf0e10cSrcweir if( ! (aState.m_nFlags & PUSH_FILLCOLOR) ) 10737cdf0e10cSrcweir setFillColor( aState.m_aFillColor ); 10738cdf0e10cSrcweir if( ! (aState.m_nFlags & PUSH_FONT) ) 10739cdf0e10cSrcweir setFont( aState.m_aFont ); 10740cdf0e10cSrcweir if( ! (aState.m_nFlags & PUSH_TEXTCOLOR) ) 10741cdf0e10cSrcweir setTextColor( aState.m_aFont.GetColor() ); 10742cdf0e10cSrcweir if( ! (aState.m_nFlags & PUSH_MAPMODE) ) 10743cdf0e10cSrcweir setMapMode( aState.m_aMapMode ); 10744cdf0e10cSrcweir if( ! (aState.m_nFlags & PUSH_CLIPREGION) ) 10745cdf0e10cSrcweir { 10746cdf0e10cSrcweir // do not use setClipRegion here 10747cdf0e10cSrcweir // it would convert again assuming the current mapmode 10748cdf0e10cSrcweir rOld.m_aClipRegion = aState.m_aClipRegion; 10749cdf0e10cSrcweir rOld.m_bClipRegion = aState.m_bClipRegion; 10750cdf0e10cSrcweir } 10751cdf0e10cSrcweir if( ! (aState.m_nFlags & PUSH_TEXTLINECOLOR ) ) 10752cdf0e10cSrcweir setTextLineColor( aState.m_aTextLineColor ); 10753cdf0e10cSrcweir if( ! (aState.m_nFlags & PUSH_OVERLINECOLOR ) ) 10754cdf0e10cSrcweir setOverlineColor( aState.m_aOverlineColor ); 10755cdf0e10cSrcweir if( ! (aState.m_nFlags & PUSH_TEXTALIGN ) ) 10756cdf0e10cSrcweir setTextAlign( aState.m_aFont.GetAlign() ); 10757cdf0e10cSrcweir if( ! (aState.m_nFlags & PUSH_TEXTFILLCOLOR) ) 10758cdf0e10cSrcweir setTextFillColor( aState.m_aFont.GetFillColor() ); 10759cdf0e10cSrcweir if( ! (aState.m_nFlags & PUSH_REFPOINT) ) 10760cdf0e10cSrcweir { 10761cdf0e10cSrcweir // what ? 10762cdf0e10cSrcweir } 10763cdf0e10cSrcweir // invalidate graphics state 10764cdf0e10cSrcweir m_aGraphicsStack.front().m_nUpdateFlags = sal::static_int_cast<sal_uInt16>(~0U); 10765cdf0e10cSrcweir } 10766cdf0e10cSrcweir 10767cdf0e10cSrcweir void PDFWriterImpl::setMapMode( const MapMode& rMapMode ) 10768cdf0e10cSrcweir { 10769cdf0e10cSrcweir m_aGraphicsStack.front().m_aMapMode = rMapMode; 10770cdf0e10cSrcweir getReferenceDevice()->SetMapMode( rMapMode ); 10771cdf0e10cSrcweir m_aCurrentPDFState.m_aMapMode = rMapMode; 10772cdf0e10cSrcweir } 10773cdf0e10cSrcweir 10774cdf0e10cSrcweir void PDFWriterImpl::setClipRegion( const basegfx::B2DPolyPolygon& rRegion ) 10775cdf0e10cSrcweir { 10776cdf0e10cSrcweir basegfx::B2DPolyPolygon aRegion = getReferenceDevice()->LogicToPixel( rRegion, m_aGraphicsStack.front().m_aMapMode ); 10777cdf0e10cSrcweir aRegion = getReferenceDevice()->PixelToLogic( aRegion, m_aMapMode ); 10778cdf0e10cSrcweir m_aGraphicsStack.front().m_aClipRegion = aRegion; 10779cdf0e10cSrcweir m_aGraphicsStack.front().m_bClipRegion = true; 10780cdf0e10cSrcweir m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsState::updateClipRegion; 10781cdf0e10cSrcweir } 10782cdf0e10cSrcweir 10783cdf0e10cSrcweir void PDFWriterImpl::moveClipRegion( sal_Int32 nX, sal_Int32 nY ) 10784cdf0e10cSrcweir { 10785cdf0e10cSrcweir if( m_aGraphicsStack.front().m_bClipRegion && m_aGraphicsStack.front().m_aClipRegion.count() ) 10786cdf0e10cSrcweir { 10787cdf0e10cSrcweir Point aPoint( lcl_convert( m_aGraphicsStack.front().m_aMapMode, 10788cdf0e10cSrcweir m_aMapMode, 10789cdf0e10cSrcweir getReferenceDevice(), 10790cdf0e10cSrcweir Point( nX, nY ) ) ); 10791cdf0e10cSrcweir aPoint -= lcl_convert( m_aGraphicsStack.front().m_aMapMode, 10792cdf0e10cSrcweir m_aMapMode, 10793cdf0e10cSrcweir getReferenceDevice(), 10794cdf0e10cSrcweir Point() ); 10795cdf0e10cSrcweir basegfx::B2DHomMatrix aMat; 10796cdf0e10cSrcweir aMat.translate( aPoint.X(), aPoint.Y() ); 10797cdf0e10cSrcweir m_aGraphicsStack.front().m_aClipRegion.transform( aMat ); 10798cdf0e10cSrcweir m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsState::updateClipRegion; 10799cdf0e10cSrcweir } 10800cdf0e10cSrcweir } 10801cdf0e10cSrcweir 10802cdf0e10cSrcweir bool PDFWriterImpl::intersectClipRegion( const Rectangle& rRect ) 10803cdf0e10cSrcweir { 10804cdf0e10cSrcweir basegfx::B2DPolyPolygon aRect( basegfx::tools::createPolygonFromRect( 10805cdf0e10cSrcweir basegfx::B2DRectangle( rRect.Left(), rRect.Top(), rRect.Right(), rRect.Bottom() ) ) ); 10806cdf0e10cSrcweir return intersectClipRegion( aRect ); 10807cdf0e10cSrcweir } 10808cdf0e10cSrcweir 10809cdf0e10cSrcweir 10810cdf0e10cSrcweir bool PDFWriterImpl::intersectClipRegion( const basegfx::B2DPolyPolygon& rRegion ) 10811cdf0e10cSrcweir { 10812cdf0e10cSrcweir basegfx::B2DPolyPolygon aRegion( getReferenceDevice()->LogicToPixel( rRegion, m_aGraphicsStack.front().m_aMapMode ) ); 10813cdf0e10cSrcweir aRegion = getReferenceDevice()->PixelToLogic( aRegion, m_aMapMode ); 10814cdf0e10cSrcweir m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsState::updateClipRegion; 10815cdf0e10cSrcweir if( m_aGraphicsStack.front().m_bClipRegion ) 10816cdf0e10cSrcweir { 10817cdf0e10cSrcweir basegfx::B2DPolyPolygon aOld( basegfx::tools::prepareForPolygonOperation( m_aGraphicsStack.front().m_aClipRegion ) ); 10818cdf0e10cSrcweir aRegion = basegfx::tools::prepareForPolygonOperation( aRegion ); 10819cdf0e10cSrcweir m_aGraphicsStack.front().m_aClipRegion = basegfx::tools::solvePolygonOperationAnd( aOld, aRegion ); 10820cdf0e10cSrcweir } 10821cdf0e10cSrcweir else 10822cdf0e10cSrcweir { 10823cdf0e10cSrcweir m_aGraphicsStack.front().m_aClipRegion = aRegion; 10824cdf0e10cSrcweir m_aGraphicsStack.front().m_bClipRegion = true; 10825cdf0e10cSrcweir } 10826cdf0e10cSrcweir return true; 10827cdf0e10cSrcweir } 10828cdf0e10cSrcweir 10829cdf0e10cSrcweir void PDFWriterImpl::createNote( const Rectangle& rRect, const PDFNote& rNote, sal_Int32 nPageNr ) 10830cdf0e10cSrcweir { 10831cdf0e10cSrcweir if( nPageNr < 0 ) 10832cdf0e10cSrcweir nPageNr = m_nCurrentPage; 10833cdf0e10cSrcweir 10834cdf0e10cSrcweir if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() ) 10835cdf0e10cSrcweir return; 10836cdf0e10cSrcweir 10837cdf0e10cSrcweir m_aNotes.push_back( PDFNoteEntry() ); 10838cdf0e10cSrcweir m_aNotes.back().m_nObject = createObject(); 10839cdf0e10cSrcweir m_aNotes.back().m_aContents = rNote; 10840cdf0e10cSrcweir m_aNotes.back().m_aRect = rRect; 10841cdf0e10cSrcweir // convert to default user space now, since the mapmode may change 10842cdf0e10cSrcweir m_aPages[nPageNr].convertRect( m_aNotes.back().m_aRect ); 10843cdf0e10cSrcweir 10844cdf0e10cSrcweir // insert note to page's annotation list 10845cdf0e10cSrcweir m_aPages[ nPageNr ].m_aAnnotations.push_back( m_aNotes.back().m_nObject ); 10846cdf0e10cSrcweir } 10847cdf0e10cSrcweir 10848cdf0e10cSrcweir sal_Int32 PDFWriterImpl::createLink( const Rectangle& rRect, sal_Int32 nPageNr ) 10849cdf0e10cSrcweir { 10850cdf0e10cSrcweir if( nPageNr < 0 ) 10851cdf0e10cSrcweir nPageNr = m_nCurrentPage; 10852cdf0e10cSrcweir 10853cdf0e10cSrcweir if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() ) 10854cdf0e10cSrcweir return -1; 10855cdf0e10cSrcweir 10856cdf0e10cSrcweir sal_Int32 nRet = m_aLinks.size(); 10857cdf0e10cSrcweir 10858cdf0e10cSrcweir m_aLinks.push_back( PDFLink() ); 10859cdf0e10cSrcweir m_aLinks.back().m_nObject = createObject(); 10860cdf0e10cSrcweir m_aLinks.back().m_nPage = nPageNr; 10861cdf0e10cSrcweir m_aLinks.back().m_aRect = rRect; 10862cdf0e10cSrcweir // convert to default user space now, since the mapmode may change 10863cdf0e10cSrcweir m_aPages[nPageNr].convertRect( m_aLinks.back().m_aRect ); 10864cdf0e10cSrcweir 10865cdf0e10cSrcweir // insert link to page's annotation list 10866cdf0e10cSrcweir m_aPages[ nPageNr ].m_aAnnotations.push_back( m_aLinks.back().m_nObject ); 10867cdf0e10cSrcweir 10868cdf0e10cSrcweir return nRet; 10869cdf0e10cSrcweir } 10870cdf0e10cSrcweir 10871cdf0e10cSrcweir //--->i56629 10872cdf0e10cSrcweir sal_Int32 PDFWriterImpl::createNamedDest( const rtl::OUString& sDestName, const Rectangle& rRect, sal_Int32 nPageNr, PDFWriter::DestAreaType eType ) 10873cdf0e10cSrcweir { 10874cdf0e10cSrcweir if( nPageNr < 0 ) 10875cdf0e10cSrcweir nPageNr = m_nCurrentPage; 10876cdf0e10cSrcweir 10877cdf0e10cSrcweir if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() ) 10878cdf0e10cSrcweir return -1; 10879cdf0e10cSrcweir 10880cdf0e10cSrcweir sal_Int32 nRet = m_aNamedDests.size(); 10881cdf0e10cSrcweir 10882cdf0e10cSrcweir m_aNamedDests.push_back( PDFNamedDest() ); 10883cdf0e10cSrcweir m_aNamedDests.back().m_aDestName = sDestName; 10884cdf0e10cSrcweir m_aNamedDests.back().m_nPage = nPageNr; 10885cdf0e10cSrcweir m_aNamedDests.back().m_eType = eType; 10886cdf0e10cSrcweir m_aNamedDests.back().m_aRect = rRect; 10887cdf0e10cSrcweir // convert to default user space now, since the mapmode may change 10888cdf0e10cSrcweir m_aPages[nPageNr].convertRect( m_aNamedDests.back().m_aRect ); 10889cdf0e10cSrcweir 10890cdf0e10cSrcweir return nRet; 10891cdf0e10cSrcweir } 10892cdf0e10cSrcweir //<---i56629 10893cdf0e10cSrcweir 10894cdf0e10cSrcweir sal_Int32 PDFWriterImpl::createDest( const Rectangle& rRect, sal_Int32 nPageNr, PDFWriter::DestAreaType eType ) 10895cdf0e10cSrcweir { 10896cdf0e10cSrcweir if( nPageNr < 0 ) 10897cdf0e10cSrcweir nPageNr = m_nCurrentPage; 10898cdf0e10cSrcweir 10899cdf0e10cSrcweir if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() ) 10900cdf0e10cSrcweir return -1; 10901cdf0e10cSrcweir 10902cdf0e10cSrcweir sal_Int32 nRet = m_aDests.size(); 10903cdf0e10cSrcweir 10904cdf0e10cSrcweir m_aDests.push_back( PDFDest() ); 10905cdf0e10cSrcweir m_aDests.back().m_nPage = nPageNr; 10906cdf0e10cSrcweir m_aDests.back().m_eType = eType; 10907cdf0e10cSrcweir m_aDests.back().m_aRect = rRect; 10908cdf0e10cSrcweir // convert to default user space now, since the mapmode may change 10909cdf0e10cSrcweir m_aPages[nPageNr].convertRect( m_aDests.back().m_aRect ); 10910cdf0e10cSrcweir 10911cdf0e10cSrcweir return nRet; 10912cdf0e10cSrcweir } 10913cdf0e10cSrcweir 10914cdf0e10cSrcweir sal_Int32 PDFWriterImpl::registerDestReference( sal_Int32 nDestId, const Rectangle& rRect, sal_Int32 nPageNr, PDFWriter::DestAreaType eType ) 10915cdf0e10cSrcweir { 10916cdf0e10cSrcweir return m_aDestinationIdTranslation[ nDestId ] = createDest( rRect, nPageNr, eType ); 10917cdf0e10cSrcweir } 10918cdf0e10cSrcweir 10919cdf0e10cSrcweir sal_Int32 PDFWriterImpl::setLinkDest( sal_Int32 nLinkId, sal_Int32 nDestId ) 10920cdf0e10cSrcweir { 10921cdf0e10cSrcweir if( nLinkId < 0 || nLinkId >= (sal_Int32)m_aLinks.size() ) 10922cdf0e10cSrcweir return -1; 10923cdf0e10cSrcweir if( nDestId < 0 || nDestId >= (sal_Int32)m_aDests.size() ) 10924cdf0e10cSrcweir return -2; 10925cdf0e10cSrcweir 10926cdf0e10cSrcweir m_aLinks[ nLinkId ].m_nDest = nDestId; 10927cdf0e10cSrcweir 10928cdf0e10cSrcweir return 0; 10929cdf0e10cSrcweir } 10930cdf0e10cSrcweir 10931cdf0e10cSrcweir sal_Int32 PDFWriterImpl::setLinkURL( sal_Int32 nLinkId, const OUString& rURL ) 10932cdf0e10cSrcweir { 10933cdf0e10cSrcweir if( nLinkId < 0 || nLinkId >= (sal_Int32)m_aLinks.size() ) 10934cdf0e10cSrcweir return -1; 10935cdf0e10cSrcweir 10936cdf0e10cSrcweir m_aLinks[ nLinkId ].m_nDest = -1; 10937cdf0e10cSrcweir 10938cdf0e10cSrcweir using namespace ::com::sun::star; 10939cdf0e10cSrcweir 10940cdf0e10cSrcweir if (!m_xTrans.is()) 10941cdf0e10cSrcweir { 10942cdf0e10cSrcweir uno::Reference< lang::XMultiServiceFactory > xFact( comphelper::getProcessServiceFactory() ); 10943cdf0e10cSrcweir if( xFact.is() ) 10944cdf0e10cSrcweir { 10945cdf0e10cSrcweir m_xTrans = uno::Reference < util::XURLTransformer >( 10946cdf0e10cSrcweir xFact->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.util.URLTransformer" ) ) ), uno::UNO_QUERY ); 10947cdf0e10cSrcweir } 10948cdf0e10cSrcweir } 10949cdf0e10cSrcweir 10950cdf0e10cSrcweir util::URL aURL; 10951cdf0e10cSrcweir aURL.Complete = rURL; 10952cdf0e10cSrcweir 10953cdf0e10cSrcweir if (m_xTrans.is()) 10954cdf0e10cSrcweir m_xTrans->parseStrict( aURL ); 10955cdf0e10cSrcweir 10956cdf0e10cSrcweir m_aLinks[ nLinkId ].m_aURL = aURL.Complete; 10957cdf0e10cSrcweir 10958cdf0e10cSrcweir return 0; 10959cdf0e10cSrcweir } 10960cdf0e10cSrcweir 10961cdf0e10cSrcweir void PDFWriterImpl::setLinkPropertyId( sal_Int32 nLinkId, sal_Int32 nPropertyId ) 10962cdf0e10cSrcweir { 10963cdf0e10cSrcweir m_aLinkPropertyMap[ nPropertyId ] = nLinkId; 10964cdf0e10cSrcweir } 10965cdf0e10cSrcweir 10966cdf0e10cSrcweir sal_Int32 PDFWriterImpl::createOutlineItem( sal_Int32 nParent, const OUString& rText, sal_Int32 nDestID ) 10967cdf0e10cSrcweir { 10968cdf0e10cSrcweir // create new item 10969cdf0e10cSrcweir sal_Int32 nNewItem = m_aOutline.size(); 10970cdf0e10cSrcweir m_aOutline.push_back( PDFOutlineEntry() ); 10971cdf0e10cSrcweir 10972cdf0e10cSrcweir // set item attributes 10973cdf0e10cSrcweir setOutlineItemParent( nNewItem, nParent ); 10974cdf0e10cSrcweir setOutlineItemText( nNewItem, rText ); 10975cdf0e10cSrcweir setOutlineItemDest( nNewItem, nDestID ); 10976cdf0e10cSrcweir 10977cdf0e10cSrcweir return nNewItem; 10978cdf0e10cSrcweir } 10979cdf0e10cSrcweir 10980cdf0e10cSrcweir sal_Int32 PDFWriterImpl::setOutlineItemParent( sal_Int32 nItem, sal_Int32 nNewParent ) 10981cdf0e10cSrcweir { 10982cdf0e10cSrcweir if( nItem < 1 || nItem >= (sal_Int32)m_aOutline.size() ) 10983cdf0e10cSrcweir return -1; 10984cdf0e10cSrcweir 10985cdf0e10cSrcweir int nRet = 0; 10986cdf0e10cSrcweir 10987cdf0e10cSrcweir if( nNewParent < 0 || nNewParent >= (sal_Int32)m_aOutline.size() || nNewParent == nItem ) 10988cdf0e10cSrcweir { 10989cdf0e10cSrcweir nNewParent = 0; 10990cdf0e10cSrcweir nRet = -2; 10991cdf0e10cSrcweir } 10992cdf0e10cSrcweir // remove item from previous parent 10993cdf0e10cSrcweir sal_Int32 nParentID = m_aOutline[ nItem ].m_nParentID; 10994cdf0e10cSrcweir if( nParentID >= 0 && nParentID < (sal_Int32)m_aOutline.size() ) 10995cdf0e10cSrcweir { 10996cdf0e10cSrcweir PDFOutlineEntry& rParent = m_aOutline[ nParentID ]; 10997cdf0e10cSrcweir 10998cdf0e10cSrcweir for( std::vector<sal_Int32>::iterator it = rParent.m_aChildren.begin(); 10999cdf0e10cSrcweir it != rParent.m_aChildren.end(); ++it ) 11000cdf0e10cSrcweir { 11001cdf0e10cSrcweir if( *it == nItem ) 11002cdf0e10cSrcweir { 11003cdf0e10cSrcweir rParent.m_aChildren.erase( it ); 11004cdf0e10cSrcweir break; 11005cdf0e10cSrcweir } 11006cdf0e10cSrcweir } 11007cdf0e10cSrcweir } 11008cdf0e10cSrcweir 11009cdf0e10cSrcweir // insert item to new parent's list of children 11010cdf0e10cSrcweir m_aOutline[ nNewParent ].m_aChildren.push_back( nItem ); 11011cdf0e10cSrcweir 11012cdf0e10cSrcweir return nRet; 11013cdf0e10cSrcweir } 11014cdf0e10cSrcweir 11015cdf0e10cSrcweir sal_Int32 PDFWriterImpl::setOutlineItemText( sal_Int32 nItem, const OUString& rText ) 11016cdf0e10cSrcweir { 11017cdf0e10cSrcweir if( nItem < 1 || nItem >= (sal_Int32)m_aOutline.size() ) 11018cdf0e10cSrcweir return -1; 11019cdf0e10cSrcweir 11020cdf0e10cSrcweir m_aOutline[ nItem ].m_aTitle = psp::WhitespaceToSpace( rText ); 11021cdf0e10cSrcweir return 0; 11022cdf0e10cSrcweir } 11023cdf0e10cSrcweir 11024cdf0e10cSrcweir sal_Int32 PDFWriterImpl::setOutlineItemDest( sal_Int32 nItem, sal_Int32 nDestID ) 11025cdf0e10cSrcweir { 11026cdf0e10cSrcweir if( nItem < 1 || nItem >= (sal_Int32)m_aOutline.size() ) // item does not exist 11027cdf0e10cSrcweir return -1; 11028cdf0e10cSrcweir if( nDestID < 0 || nDestID >= (sal_Int32)m_aDests.size() ) // dest does not exist 11029cdf0e10cSrcweir return -2; 11030cdf0e10cSrcweir m_aOutline[nItem].m_nDestID = nDestID; 11031cdf0e10cSrcweir return 0; 11032cdf0e10cSrcweir } 11033cdf0e10cSrcweir 11034cdf0e10cSrcweir const sal_Char* PDFWriterImpl::getStructureTag( PDFWriter::StructElement eType ) 11035cdf0e10cSrcweir { 11036cdf0e10cSrcweir static std::map< PDFWriter::StructElement, const char* > aTagStrings; 11037cdf0e10cSrcweir if( aTagStrings.empty() ) 11038cdf0e10cSrcweir { 11039cdf0e10cSrcweir aTagStrings[ PDFWriter::NonStructElement] = "NonStruct"; 11040cdf0e10cSrcweir aTagStrings[ PDFWriter::Document ] = "Document"; 11041cdf0e10cSrcweir aTagStrings[ PDFWriter::Part ] = "Part"; 11042cdf0e10cSrcweir aTagStrings[ PDFWriter::Article ] = "Art"; 11043cdf0e10cSrcweir aTagStrings[ PDFWriter::Section ] = "Sect"; 11044cdf0e10cSrcweir aTagStrings[ PDFWriter::Division ] = "Div"; 11045cdf0e10cSrcweir aTagStrings[ PDFWriter::BlockQuote ] = "BlockQuote"; 11046cdf0e10cSrcweir aTagStrings[ PDFWriter::Caption ] = "Caption"; 11047cdf0e10cSrcweir aTagStrings[ PDFWriter::TOC ] = "TOC"; 11048cdf0e10cSrcweir aTagStrings[ PDFWriter::TOCI ] = "TOCI"; 11049cdf0e10cSrcweir aTagStrings[ PDFWriter::Index ] = "Index"; 11050cdf0e10cSrcweir aTagStrings[ PDFWriter::Paragraph ] = "P"; 11051cdf0e10cSrcweir aTagStrings[ PDFWriter::Heading ] = "H"; 11052cdf0e10cSrcweir aTagStrings[ PDFWriter::H1 ] = "H1"; 11053cdf0e10cSrcweir aTagStrings[ PDFWriter::H2 ] = "H2"; 11054cdf0e10cSrcweir aTagStrings[ PDFWriter::H3 ] = "H3"; 11055cdf0e10cSrcweir aTagStrings[ PDFWriter::H4 ] = "H4"; 11056cdf0e10cSrcweir aTagStrings[ PDFWriter::H5 ] = "H5"; 11057cdf0e10cSrcweir aTagStrings[ PDFWriter::H6 ] = "H6"; 11058cdf0e10cSrcweir aTagStrings[ PDFWriter::List ] = "L"; 11059cdf0e10cSrcweir aTagStrings[ PDFWriter::ListItem ] = "LI"; 11060cdf0e10cSrcweir aTagStrings[ PDFWriter::LILabel ] = "Lbl"; 11061cdf0e10cSrcweir aTagStrings[ PDFWriter::LIBody ] = "LBody"; 11062cdf0e10cSrcweir aTagStrings[ PDFWriter::Table ] = "Table"; 11063cdf0e10cSrcweir aTagStrings[ PDFWriter::TableRow ] = "TR"; 11064cdf0e10cSrcweir aTagStrings[ PDFWriter::TableHeader ] = "TH"; 11065cdf0e10cSrcweir aTagStrings[ PDFWriter::TableData ] = "TD"; 11066cdf0e10cSrcweir aTagStrings[ PDFWriter::Span ] = "Span"; 11067cdf0e10cSrcweir aTagStrings[ PDFWriter::Quote ] = "Quote"; 11068cdf0e10cSrcweir aTagStrings[ PDFWriter::Note ] = "Note"; 11069cdf0e10cSrcweir aTagStrings[ PDFWriter::Reference ] = "Reference"; 11070cdf0e10cSrcweir aTagStrings[ PDFWriter::BibEntry ] = "BibEntry"; 11071cdf0e10cSrcweir aTagStrings[ PDFWriter::Code ] = "Code"; 11072cdf0e10cSrcweir aTagStrings[ PDFWriter::Link ] = "Link"; 11073cdf0e10cSrcweir aTagStrings[ PDFWriter::Figure ] = "Figure"; 11074cdf0e10cSrcweir aTagStrings[ PDFWriter::Formula ] = "Formula"; 11075cdf0e10cSrcweir aTagStrings[ PDFWriter::Form ] = "Form"; 11076cdf0e10cSrcweir } 11077cdf0e10cSrcweir 11078cdf0e10cSrcweir std::map< PDFWriter::StructElement, const char* >::const_iterator it = aTagStrings.find( eType ); 11079cdf0e10cSrcweir 11080cdf0e10cSrcweir return it != aTagStrings.end() ? it->second : "Div"; 11081cdf0e10cSrcweir } 11082cdf0e10cSrcweir 11083cdf0e10cSrcweir void PDFWriterImpl::beginStructureElementMCSeq() 11084cdf0e10cSrcweir { 11085cdf0e10cSrcweir if( m_bEmitStructure && 11086cdf0e10cSrcweir m_nCurrentStructElement > 0 && // StructTreeRoot 11087cdf0e10cSrcweir ! m_aStructure[ m_nCurrentStructElement ].m_bOpenMCSeq // already opened sequence 11088cdf0e10cSrcweir ) 11089cdf0e10cSrcweir { 11090cdf0e10cSrcweir PDFStructureElement& rEle = m_aStructure[ m_nCurrentStructElement ]; 11091cdf0e10cSrcweir OStringBuffer aLine( 128 ); 11092cdf0e10cSrcweir sal_Int32 nMCID = m_aPages[ m_nCurrentPage ].m_aMCIDParents.size(); 11093cdf0e10cSrcweir aLine.append( "/" ); 11094cdf0e10cSrcweir if( rEle.m_aAlias.getLength() > 0 ) 11095cdf0e10cSrcweir aLine.append( rEle.m_aAlias ); 11096cdf0e10cSrcweir else 11097cdf0e10cSrcweir aLine.append( getStructureTag( rEle.m_eType ) ); 11098cdf0e10cSrcweir aLine.append( "<</MCID " ); 11099cdf0e10cSrcweir aLine.append( nMCID ); 11100cdf0e10cSrcweir aLine.append( ">>BDC\n" ); 11101cdf0e10cSrcweir writeBuffer( aLine.getStr(), aLine.getLength() ); 11102cdf0e10cSrcweir 11103cdf0e10cSrcweir // update the element's content list 11104cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 11105cdf0e10cSrcweir fprintf( stderr, "beginning marked content id %" SAL_PRIdINT32 " on page object %" SAL_PRIdINT32 ", structure first page = %" SAL_PRIdINT32 "\n", 11106cdf0e10cSrcweir nMCID, 11107cdf0e10cSrcweir m_aPages[ m_nCurrentPage ].m_nPageObject, 11108cdf0e10cSrcweir rEle.m_nFirstPageObject ); 11109cdf0e10cSrcweir #endif 11110cdf0e10cSrcweir rEle.m_aKids.push_back( PDFStructureElementKid( nMCID, m_aPages[m_nCurrentPage].m_nPageObject ) ); 11111cdf0e10cSrcweir // update the page's mcid parent list 11112cdf0e10cSrcweir m_aPages[ m_nCurrentPage ].m_aMCIDParents.push_back( rEle.m_nObject ); 11113cdf0e10cSrcweir // mark element MC sequence as open 11114cdf0e10cSrcweir rEle.m_bOpenMCSeq = true; 11115cdf0e10cSrcweir } 11116cdf0e10cSrcweir // handle artifacts 11117cdf0e10cSrcweir else if( ! m_bEmitStructure && m_aContext.Tagged && 11118cdf0e10cSrcweir m_nCurrentStructElement > 0 && 11119cdf0e10cSrcweir m_aStructure[ m_nCurrentStructElement ].m_eType == PDFWriter::NonStructElement && 11120cdf0e10cSrcweir ! m_aStructure[ m_nCurrentStructElement ].m_bOpenMCSeq // already opened sequence 11121cdf0e10cSrcweir ) 11122cdf0e10cSrcweir { 11123cdf0e10cSrcweir OStringBuffer aLine( 128 ); 11124cdf0e10cSrcweir aLine.append( "/Artifact BMC\n" ); 11125cdf0e10cSrcweir writeBuffer( aLine.getStr(), aLine.getLength() ); 11126cdf0e10cSrcweir // mark element MC sequence as open 11127cdf0e10cSrcweir m_aStructure[ m_nCurrentStructElement ].m_bOpenMCSeq = true; 11128cdf0e10cSrcweir } 11129cdf0e10cSrcweir } 11130cdf0e10cSrcweir 11131cdf0e10cSrcweir void PDFWriterImpl::endStructureElementMCSeq() 11132cdf0e10cSrcweir { 11133cdf0e10cSrcweir if( m_nCurrentStructElement > 0 && // StructTreeRoot 11134cdf0e10cSrcweir ( m_bEmitStructure || m_aStructure[ m_nCurrentStructElement ].m_eType == PDFWriter::NonStructElement ) && 11135cdf0e10cSrcweir m_aStructure[ m_nCurrentStructElement ].m_bOpenMCSeq // must have an opened MC sequence 11136cdf0e10cSrcweir ) 11137cdf0e10cSrcweir { 11138cdf0e10cSrcweir writeBuffer( "EMC\n", 4 ); 11139cdf0e10cSrcweir m_aStructure[ m_nCurrentStructElement ].m_bOpenMCSeq = false; 11140cdf0e10cSrcweir } 11141cdf0e10cSrcweir } 11142cdf0e10cSrcweir 11143cdf0e10cSrcweir bool PDFWriterImpl::checkEmitStructure() 11144cdf0e10cSrcweir { 11145cdf0e10cSrcweir bool bEmit = false; 11146cdf0e10cSrcweir if( m_aContext.Tagged ) 11147cdf0e10cSrcweir { 11148cdf0e10cSrcweir bEmit = true; 11149cdf0e10cSrcweir sal_Int32 nEle = m_nCurrentStructElement; 11150cdf0e10cSrcweir while( nEle > 0 && nEle < sal_Int32(m_aStructure.size()) ) 11151cdf0e10cSrcweir { 11152cdf0e10cSrcweir if( m_aStructure[ nEle ].m_eType == PDFWriter::NonStructElement ) 11153cdf0e10cSrcweir { 11154cdf0e10cSrcweir bEmit = false; 11155cdf0e10cSrcweir break; 11156cdf0e10cSrcweir } 11157cdf0e10cSrcweir nEle = m_aStructure[ nEle ].m_nParentElement; 11158cdf0e10cSrcweir } 11159cdf0e10cSrcweir } 11160cdf0e10cSrcweir return bEmit; 11161cdf0e10cSrcweir } 11162cdf0e10cSrcweir 11163cdf0e10cSrcweir sal_Int32 PDFWriterImpl::beginStructureElement( PDFWriter::StructElement eType, const rtl::OUString& rAlias ) 11164cdf0e10cSrcweir { 11165cdf0e10cSrcweir if( m_nCurrentPage < 0 ) 11166cdf0e10cSrcweir return -1; 11167cdf0e10cSrcweir 11168cdf0e10cSrcweir if( ! m_aContext.Tagged ) 11169cdf0e10cSrcweir return -1; 11170cdf0e10cSrcweir 11171cdf0e10cSrcweir // close eventual current MC sequence 11172cdf0e10cSrcweir endStructureElementMCSeq(); 11173cdf0e10cSrcweir 11174cdf0e10cSrcweir if( m_nCurrentStructElement == 0 && 11175cdf0e10cSrcweir eType != PDFWriter::Document && eType != PDFWriter::NonStructElement ) 11176cdf0e10cSrcweir { 11177cdf0e10cSrcweir // struct tree root hit, but not beginning document 11178cdf0e10cSrcweir // this might happen with setCurrentStructureElement 11179cdf0e10cSrcweir // silently insert structure into document again if one properly exists 11180cdf0e10cSrcweir if( ! m_aStructure[ 0 ].m_aChildren.empty() ) 11181cdf0e10cSrcweir { 11182cdf0e10cSrcweir PDFWriter::StructElement childType = PDFWriter::NonStructElement; 11183cdf0e10cSrcweir sal_Int32 nNewCurElement = 0; 11184cdf0e10cSrcweir const std::list< sal_Int32 >& rRootChildren = m_aStructure[0].m_aChildren; 11185cdf0e10cSrcweir for( std::list< sal_Int32 >::const_iterator it = rRootChildren.begin(); 11186cdf0e10cSrcweir childType != PDFWriter::Document && it != rRootChildren.end(); ++it ) 11187cdf0e10cSrcweir { 11188cdf0e10cSrcweir nNewCurElement = *it; 11189cdf0e10cSrcweir childType = m_aStructure[ nNewCurElement ].m_eType; 11190cdf0e10cSrcweir } 11191cdf0e10cSrcweir if( childType == PDFWriter::Document ) 11192cdf0e10cSrcweir { 11193cdf0e10cSrcweir m_nCurrentStructElement = nNewCurElement; 11194cdf0e10cSrcweir DBG_ASSERT( 0, "Structure element inserted to StructTreeRoot that is not a document" ); 11195cdf0e10cSrcweir } 11196cdf0e10cSrcweir else { 11197cdf0e10cSrcweir DBG_ERROR( "document structure in disorder !" ); 11198cdf0e10cSrcweir } 11199cdf0e10cSrcweir } 11200cdf0e10cSrcweir else { 11201cdf0e10cSrcweir DBG_ERROR( "PDF document structure MUST be contained in a Document element" ); 11202cdf0e10cSrcweir } 11203cdf0e10cSrcweir } 11204cdf0e10cSrcweir 11205cdf0e10cSrcweir sal_Int32 nNewId = sal_Int32(m_aStructure.size()); 11206cdf0e10cSrcweir m_aStructure.push_back( PDFStructureElement() ); 11207cdf0e10cSrcweir PDFStructureElement& rEle = m_aStructure.back(); 11208cdf0e10cSrcweir rEle.m_eType = eType; 11209cdf0e10cSrcweir rEle.m_nOwnElement = nNewId; 11210cdf0e10cSrcweir rEle.m_nParentElement = m_nCurrentStructElement; 11211cdf0e10cSrcweir rEle.m_nFirstPageObject = m_aPages[ m_nCurrentPage ].m_nPageObject; 11212cdf0e10cSrcweir m_aStructure[ m_nCurrentStructElement ].m_aChildren.push_back( nNewId ); 11213cdf0e10cSrcweir m_nCurrentStructElement = nNewId; 11214cdf0e10cSrcweir 11215cdf0e10cSrcweir // handle alias names 11216cdf0e10cSrcweir if( rAlias.getLength() && eType != PDFWriter::NonStructElement ) 11217cdf0e10cSrcweir { 11218cdf0e10cSrcweir OStringBuffer aNameBuf( rAlias.getLength() ); 11219cdf0e10cSrcweir appendName( rAlias, aNameBuf ); 11220cdf0e10cSrcweir OString aAliasName( aNameBuf.makeStringAndClear() ); 11221cdf0e10cSrcweir rEle.m_aAlias = aAliasName; 11222cdf0e10cSrcweir m_aRoleMap[ aAliasName ] = getStructureTag( eType ); 11223cdf0e10cSrcweir } 11224cdf0e10cSrcweir 11225cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 11226cdf0e10cSrcweir OStringBuffer aLine( "beginStructureElement " ); 11227cdf0e10cSrcweir aLine.append( m_nCurrentStructElement ); 11228cdf0e10cSrcweir aLine.append( ": " ); 11229cdf0e10cSrcweir aLine.append( getStructureTag( eType ) ); 11230cdf0e10cSrcweir if( rEle.m_aAlias.getLength() ) 11231cdf0e10cSrcweir { 11232cdf0e10cSrcweir aLine.append( " aliased as \"" ); 11233cdf0e10cSrcweir aLine.append( rEle.m_aAlias ); 11234cdf0e10cSrcweir aLine.append( '\"' ); 11235cdf0e10cSrcweir } 11236cdf0e10cSrcweir emitComment( aLine.getStr() ); 11237cdf0e10cSrcweir #endif 11238cdf0e10cSrcweir 11239cdf0e10cSrcweir // check whether to emit structure henceforth 11240cdf0e10cSrcweir m_bEmitStructure = checkEmitStructure(); 11241cdf0e10cSrcweir 11242cdf0e10cSrcweir if( m_bEmitStructure ) // don't create nonexistant objects 11243cdf0e10cSrcweir { 11244cdf0e10cSrcweir rEle.m_nObject = createObject(); 11245cdf0e10cSrcweir // update parent's kids list 11246cdf0e10cSrcweir m_aStructure[ rEle.m_nParentElement ].m_aKids.push_back( rEle.m_nObject ); 11247cdf0e10cSrcweir } 11248cdf0e10cSrcweir return nNewId; 11249cdf0e10cSrcweir } 11250cdf0e10cSrcweir 11251cdf0e10cSrcweir void PDFWriterImpl::endStructureElement() 11252cdf0e10cSrcweir { 11253cdf0e10cSrcweir if( m_nCurrentPage < 0 ) 11254cdf0e10cSrcweir return; 11255cdf0e10cSrcweir 11256cdf0e10cSrcweir if( ! m_aContext.Tagged ) 11257cdf0e10cSrcweir return; 11258cdf0e10cSrcweir 11259cdf0e10cSrcweir if( m_nCurrentStructElement == 0 ) 11260cdf0e10cSrcweir { 11261cdf0e10cSrcweir // hit the struct tree root, that means there is an endStructureElement 11262cdf0e10cSrcweir // without corresponding beginStructureElement 11263cdf0e10cSrcweir return; 11264cdf0e10cSrcweir } 11265cdf0e10cSrcweir 11266cdf0e10cSrcweir // end the marked content sequence 11267cdf0e10cSrcweir endStructureElementMCSeq(); 11268cdf0e10cSrcweir 11269cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 11270cdf0e10cSrcweir OStringBuffer aLine( "endStructureElement " ); 11271cdf0e10cSrcweir aLine.append( m_nCurrentStructElement ); 11272cdf0e10cSrcweir aLine.append( ": " ); 11273cdf0e10cSrcweir aLine.append( getStructureTag( m_aStructure[ m_nCurrentStructElement ].m_eType ) ); 11274cdf0e10cSrcweir if( m_aStructure[ m_nCurrentStructElement ].m_aAlias.getLength() ) 11275cdf0e10cSrcweir { 11276cdf0e10cSrcweir aLine.append( " aliased as \"" ); 11277cdf0e10cSrcweir aLine.append( m_aStructure[ m_nCurrentStructElement ].m_aAlias ); 11278cdf0e10cSrcweir aLine.append( '\"' ); 11279cdf0e10cSrcweir } 11280cdf0e10cSrcweir #endif 11281cdf0e10cSrcweir 11282cdf0e10cSrcweir // "end" the structure element, the parent becomes current element 11283cdf0e10cSrcweir m_nCurrentStructElement = m_aStructure[ m_nCurrentStructElement ].m_nParentElement; 11284cdf0e10cSrcweir 11285cdf0e10cSrcweir // check whether to emit structure henceforth 11286cdf0e10cSrcweir m_bEmitStructure = checkEmitStructure(); 11287cdf0e10cSrcweir 11288cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 11289cdf0e10cSrcweir if( m_bEmitStructure ) 11290cdf0e10cSrcweir emitComment( aLine.getStr() ); 11291cdf0e10cSrcweir #endif 11292cdf0e10cSrcweir } 11293cdf0e10cSrcweir 11294cdf0e10cSrcweir //---> i94258 11295cdf0e10cSrcweir /* 11296cdf0e10cSrcweir * This function adds an internal structure list container to overcome the 8191 elements array limitation 11297cdf0e10cSrcweir * in kids element emission. 11298cdf0e10cSrcweir * Recursive function 11299cdf0e10cSrcweir * 11300cdf0e10cSrcweir */ 11301cdf0e10cSrcweir void PDFWriterImpl::addInternalStructureContainer( PDFStructureElement& rEle ) 11302cdf0e10cSrcweir { 11303cdf0e10cSrcweir if( rEle.m_eType == PDFWriter::NonStructElement && 11304cdf0e10cSrcweir rEle.m_nOwnElement != rEle.m_nParentElement ) 11305cdf0e10cSrcweir return; 11306cdf0e10cSrcweir 11307cdf0e10cSrcweir for( std::list< sal_Int32 >::const_iterator it = rEle.m_aChildren.begin(); it != rEle.m_aChildren.end(); ++it ) 11308cdf0e10cSrcweir { 11309cdf0e10cSrcweir if( *it > 0 && *it < sal_Int32(m_aStructure.size()) ) 11310cdf0e10cSrcweir { 11311cdf0e10cSrcweir PDFStructureElement& rChild = m_aStructure[ *it ]; 11312cdf0e10cSrcweir if( rChild.m_eType != PDFWriter::NonStructElement ) 11313cdf0e10cSrcweir { 11314cdf0e10cSrcweir //triggered when a child of the rEle element is found 11315cdf0e10cSrcweir if( rChild.m_nParentElement == rEle.m_nOwnElement ) 11316cdf0e10cSrcweir addInternalStructureContainer( rChild );//examine the child 11317cdf0e10cSrcweir else 11318cdf0e10cSrcweir { 11319cdf0e10cSrcweir DBG_ERROR( "PDFWriterImpl::addInternalStructureContainer: invalid child structure element" ); 11320cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 11321cdf0e10cSrcweir fprintf( stderr, "PDFWriterImpl::addInternalStructureContainer: invalid child structure elemnt with id %" SAL_PRIdINT32 "\n", *it ); 11322cdf0e10cSrcweir #endif 11323cdf0e10cSrcweir } 11324cdf0e10cSrcweir } 11325cdf0e10cSrcweir } 11326cdf0e10cSrcweir else 11327cdf0e10cSrcweir { 11328cdf0e10cSrcweir DBG_ERROR( "PDFWriterImpl::emitStructure: invalid child structure id" ); 11329cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 11330cdf0e10cSrcweir fprintf( stderr, "PDFWriterImpl::addInternalStructureContainer: invalid child structure id %" SAL_PRIdINT32 "\n", *it ); 11331cdf0e10cSrcweir #endif 11332cdf0e10cSrcweir } 11333cdf0e10cSrcweir } 11334cdf0e10cSrcweir 11335cdf0e10cSrcweir if( rEle.m_nOwnElement != rEle.m_nParentElement ) 11336cdf0e10cSrcweir { 11337cdf0e10cSrcweir if( !rEle.m_aKids.empty() ) 11338cdf0e10cSrcweir { 11339cdf0e10cSrcweir if( rEle.m_aKids.size() > ncMaxPDFArraySize ) { 11340cdf0e10cSrcweir //then we need to add the containers for the kids elements 11341cdf0e10cSrcweir // a list to be used for the new kid element 11342cdf0e10cSrcweir std::list< PDFStructureElementKid > aNewKids; 11343cdf0e10cSrcweir std::list< sal_Int32 > aNewChildren; 11344cdf0e10cSrcweir 11345cdf0e10cSrcweir // add Div in RoleMap, in case no one else did (TODO: is it needed? Is it dangerous?) 11346cdf0e10cSrcweir OStringBuffer aNameBuf( "Div" ); 11347cdf0e10cSrcweir OString aAliasName( aNameBuf.makeStringAndClear() ); 11348cdf0e10cSrcweir m_aRoleMap[ aAliasName ] = getStructureTag( PDFWriter::Division ); 11349cdf0e10cSrcweir 11350cdf0e10cSrcweir while( rEle.m_aKids.size() > ncMaxPDFArraySize ) 11351cdf0e10cSrcweir { 11352cdf0e10cSrcweir sal_Int32 nCurrentStructElement = rEle.m_nOwnElement; 11353cdf0e10cSrcweir sal_Int32 nNewId = sal_Int32(m_aStructure.size()); 11354cdf0e10cSrcweir m_aStructure.push_back( PDFStructureElement() ); 11355cdf0e10cSrcweir PDFStructureElement& rEleNew = m_aStructure.back(); 11356cdf0e10cSrcweir rEleNew.m_aAlias = aAliasName; 11357cdf0e10cSrcweir rEleNew.m_eType = PDFWriter::Division; // a new Div type container 11358cdf0e10cSrcweir rEleNew.m_nOwnElement = nNewId; 11359cdf0e10cSrcweir rEleNew.m_nParentElement = nCurrentStructElement; 11360cdf0e10cSrcweir //inherit the same page as the first child to be reparented 11361cdf0e10cSrcweir rEleNew.m_nFirstPageObject = m_aStructure[ rEle.m_aChildren.front() ].m_nFirstPageObject; 11362cdf0e10cSrcweir rEleNew.m_nObject = createObject();//assign a PDF object number 11363cdf0e10cSrcweir //add the object to the kid list of the parent 11364cdf0e10cSrcweir aNewKids.push_back( PDFStructureElementKid( rEleNew.m_nObject ) ); 11365cdf0e10cSrcweir aNewChildren.push_back( nNewId ); 11366cdf0e10cSrcweir 11367cdf0e10cSrcweir std::list< sal_Int32 >::iterator aChildEndIt( rEle.m_aChildren.begin() ); 11368cdf0e10cSrcweir std::list< PDFStructureElementKid >::iterator aKidEndIt( rEle.m_aKids.begin() ); 11369cdf0e10cSrcweir advance( aChildEndIt, ncMaxPDFArraySize ); 11370cdf0e10cSrcweir advance( aKidEndIt, ncMaxPDFArraySize ); 11371cdf0e10cSrcweir 11372cdf0e10cSrcweir rEleNew.m_aKids.splice( rEleNew.m_aKids.begin(), 11373cdf0e10cSrcweir rEle.m_aKids, 11374cdf0e10cSrcweir rEle.m_aKids.begin(), 11375cdf0e10cSrcweir aKidEndIt ); 11376cdf0e10cSrcweir rEleNew.m_aChildren.splice( rEleNew.m_aChildren.begin(), 11377cdf0e10cSrcweir rEle.m_aChildren, 11378cdf0e10cSrcweir rEle.m_aChildren.begin(), 11379cdf0e10cSrcweir aChildEndIt ); 11380cdf0e10cSrcweir // set the kid's new parent 11381cdf0e10cSrcweir for( std::list< sal_Int32 >::const_iterator it = rEleNew.m_aChildren.begin(); 11382cdf0e10cSrcweir it != rEleNew.m_aChildren.end(); ++it ) 11383cdf0e10cSrcweir { 11384cdf0e10cSrcweir m_aStructure[ *it ].m_nParentElement = nNewId; 11385cdf0e10cSrcweir } 11386cdf0e10cSrcweir } 11387cdf0e10cSrcweir //finally add the new kids resulting from the container added 11388cdf0e10cSrcweir rEle.m_aKids.insert( rEle.m_aKids.begin(), aNewKids.begin(), aNewKids.end() ); 11389cdf0e10cSrcweir rEle.m_aChildren.insert( rEle.m_aChildren.begin(), aNewChildren.begin(), aNewChildren.end() ); 11390cdf0e10cSrcweir } 11391cdf0e10cSrcweir } 11392cdf0e10cSrcweir } 11393cdf0e10cSrcweir } 11394cdf0e10cSrcweir //<--- i94258 11395cdf0e10cSrcweir 11396cdf0e10cSrcweir bool PDFWriterImpl::setCurrentStructureElement( sal_Int32 nEle ) 11397cdf0e10cSrcweir { 11398cdf0e10cSrcweir bool bSuccess = false; 11399cdf0e10cSrcweir 11400cdf0e10cSrcweir if( m_aContext.Tagged && nEle >= 0 && nEle < sal_Int32(m_aStructure.size()) ) 11401cdf0e10cSrcweir { 11402cdf0e10cSrcweir // end eventual previous marked content sequence 11403cdf0e10cSrcweir endStructureElementMCSeq(); 11404cdf0e10cSrcweir 11405cdf0e10cSrcweir m_nCurrentStructElement = nEle; 11406cdf0e10cSrcweir m_bEmitStructure = checkEmitStructure(); 11407cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 11408cdf0e10cSrcweir OStringBuffer aLine( "setCurrentStructureElement " ); 11409cdf0e10cSrcweir aLine.append( m_nCurrentStructElement ); 11410cdf0e10cSrcweir aLine.append( ": " ); 11411cdf0e10cSrcweir aLine.append( getStructureTag( m_aStructure[ m_nCurrentStructElement ].m_eType ) ); 11412cdf0e10cSrcweir if( m_aStructure[ m_nCurrentStructElement ].m_aAlias.getLength() ) 11413cdf0e10cSrcweir { 11414cdf0e10cSrcweir aLine.append( " aliased as \"" ); 11415cdf0e10cSrcweir aLine.append( m_aStructure[ m_nCurrentStructElement ].m_aAlias ); 11416cdf0e10cSrcweir aLine.append( '\"' ); 11417cdf0e10cSrcweir } 11418cdf0e10cSrcweir if( ! m_bEmitStructure ) 11419cdf0e10cSrcweir aLine.append( " (inside NonStruct)" ); 11420cdf0e10cSrcweir emitComment( aLine.getStr() ); 11421cdf0e10cSrcweir #endif 11422cdf0e10cSrcweir bSuccess = true; 11423cdf0e10cSrcweir } 11424cdf0e10cSrcweir 11425cdf0e10cSrcweir return bSuccess; 11426cdf0e10cSrcweir } 11427cdf0e10cSrcweir 11428cdf0e10cSrcweir sal_Int32 PDFWriterImpl::getCurrentStructureElement() 11429cdf0e10cSrcweir { 11430cdf0e10cSrcweir return m_nCurrentStructElement; 11431cdf0e10cSrcweir } 11432cdf0e10cSrcweir 11433cdf0e10cSrcweir bool PDFWriterImpl::setStructureAttribute( enum PDFWriter::StructAttribute eAttr, enum PDFWriter::StructAttributeValue eVal ) 11434cdf0e10cSrcweir { 11435cdf0e10cSrcweir if( !m_aContext.Tagged ) 11436cdf0e10cSrcweir return false; 11437cdf0e10cSrcweir 11438cdf0e10cSrcweir bool bInsert = false; 11439cdf0e10cSrcweir if( m_nCurrentStructElement > 0 && m_bEmitStructure ) 11440cdf0e10cSrcweir { 11441cdf0e10cSrcweir PDFWriter::StructElement eType = m_aStructure[ m_nCurrentStructElement ].m_eType; 11442cdf0e10cSrcweir switch( eAttr ) 11443cdf0e10cSrcweir { 11444cdf0e10cSrcweir case PDFWriter::Placement: 11445cdf0e10cSrcweir if( eVal == PDFWriter::Block || 11446cdf0e10cSrcweir eVal == PDFWriter::Inline || 11447cdf0e10cSrcweir eVal == PDFWriter::Before || 11448cdf0e10cSrcweir eVal == PDFWriter::Start || 11449cdf0e10cSrcweir eVal == PDFWriter::End ) 11450cdf0e10cSrcweir bInsert = true; 11451cdf0e10cSrcweir break; 11452cdf0e10cSrcweir case PDFWriter::WritingMode: 11453cdf0e10cSrcweir if( eVal == PDFWriter::LrTb || 11454cdf0e10cSrcweir eVal == PDFWriter::RlTb || 11455cdf0e10cSrcweir eVal == PDFWriter::TbRl ) 11456cdf0e10cSrcweir { 11457cdf0e10cSrcweir bInsert = true; 11458cdf0e10cSrcweir } 11459cdf0e10cSrcweir break; 11460cdf0e10cSrcweir case PDFWriter::TextAlign: 11461cdf0e10cSrcweir if( eVal == PDFWriter::Start || 11462cdf0e10cSrcweir eVal == PDFWriter::Center || 11463cdf0e10cSrcweir eVal == PDFWriter::End || 11464cdf0e10cSrcweir eVal == PDFWriter::Justify ) 11465cdf0e10cSrcweir { 11466cdf0e10cSrcweir if( eType == PDFWriter::Paragraph || 11467cdf0e10cSrcweir eType == PDFWriter::Heading || 11468cdf0e10cSrcweir eType == PDFWriter::H1 || 11469cdf0e10cSrcweir eType == PDFWriter::H2 || 11470cdf0e10cSrcweir eType == PDFWriter::H3 || 11471cdf0e10cSrcweir eType == PDFWriter::H4 || 11472cdf0e10cSrcweir eType == PDFWriter::H5 || 11473cdf0e10cSrcweir eType == PDFWriter::H6 || 11474cdf0e10cSrcweir eType == PDFWriter::List || 11475cdf0e10cSrcweir eType == PDFWriter::ListItem || 11476cdf0e10cSrcweir eType == PDFWriter::LILabel || 11477cdf0e10cSrcweir eType == PDFWriter::LIBody || 11478cdf0e10cSrcweir eType == PDFWriter::Table || 11479cdf0e10cSrcweir eType == PDFWriter::TableRow || 11480cdf0e10cSrcweir eType == PDFWriter::TableHeader || 11481cdf0e10cSrcweir eType == PDFWriter::TableData ) 11482cdf0e10cSrcweir { 11483cdf0e10cSrcweir bInsert = true; 11484cdf0e10cSrcweir } 11485cdf0e10cSrcweir } 11486cdf0e10cSrcweir break; 11487cdf0e10cSrcweir case PDFWriter::Width: 11488cdf0e10cSrcweir case PDFWriter::Height: 11489cdf0e10cSrcweir if( eVal == PDFWriter::Auto ) 11490cdf0e10cSrcweir { 11491cdf0e10cSrcweir if( eType == PDFWriter::Figure || 11492cdf0e10cSrcweir eType == PDFWriter::Formula || 11493cdf0e10cSrcweir eType == PDFWriter::Form || 11494cdf0e10cSrcweir eType == PDFWriter::Table || 11495cdf0e10cSrcweir eType == PDFWriter::TableHeader || 11496cdf0e10cSrcweir eType == PDFWriter::TableData ) 11497cdf0e10cSrcweir { 11498cdf0e10cSrcweir bInsert = true; 11499cdf0e10cSrcweir } 11500cdf0e10cSrcweir } 11501cdf0e10cSrcweir break; 11502cdf0e10cSrcweir case PDFWriter::BlockAlign: 11503cdf0e10cSrcweir if( eVal == PDFWriter::Before || 11504cdf0e10cSrcweir eVal == PDFWriter::Middle || 11505cdf0e10cSrcweir eVal == PDFWriter::After || 11506cdf0e10cSrcweir eVal == PDFWriter::Justify ) 11507cdf0e10cSrcweir { 11508cdf0e10cSrcweir if( eType == PDFWriter::TableHeader || 11509cdf0e10cSrcweir eType == PDFWriter::TableData ) 11510cdf0e10cSrcweir { 11511cdf0e10cSrcweir bInsert = true; 11512cdf0e10cSrcweir } 11513cdf0e10cSrcweir } 11514cdf0e10cSrcweir break; 11515cdf0e10cSrcweir case PDFWriter::InlineAlign: 11516cdf0e10cSrcweir if( eVal == PDFWriter::Start || 11517cdf0e10cSrcweir eVal == PDFWriter::Center || 11518cdf0e10cSrcweir eVal == PDFWriter::End ) 11519cdf0e10cSrcweir { 11520cdf0e10cSrcweir if( eType == PDFWriter::TableHeader || 11521cdf0e10cSrcweir eType == PDFWriter::TableData ) 11522cdf0e10cSrcweir { 11523cdf0e10cSrcweir bInsert = true; 11524cdf0e10cSrcweir } 11525cdf0e10cSrcweir } 11526cdf0e10cSrcweir break; 11527cdf0e10cSrcweir case PDFWriter::LineHeight: 11528cdf0e10cSrcweir if( eVal == PDFWriter::Normal || 11529cdf0e10cSrcweir eVal == PDFWriter::Auto ) 11530cdf0e10cSrcweir { 11531cdf0e10cSrcweir // only for ILSE and BLSE 11532cdf0e10cSrcweir if( eType == PDFWriter::Paragraph || 11533cdf0e10cSrcweir eType == PDFWriter::Heading || 11534cdf0e10cSrcweir eType == PDFWriter::H1 || 11535cdf0e10cSrcweir eType == PDFWriter::H2 || 11536cdf0e10cSrcweir eType == PDFWriter::H3 || 11537cdf0e10cSrcweir eType == PDFWriter::H4 || 11538cdf0e10cSrcweir eType == PDFWriter::H5 || 11539cdf0e10cSrcweir eType == PDFWriter::H6 || 11540cdf0e10cSrcweir eType == PDFWriter::List || 11541cdf0e10cSrcweir eType == PDFWriter::ListItem || 11542cdf0e10cSrcweir eType == PDFWriter::LILabel || 11543cdf0e10cSrcweir eType == PDFWriter::LIBody || 11544cdf0e10cSrcweir eType == PDFWriter::Table || 11545cdf0e10cSrcweir eType == PDFWriter::TableRow || 11546cdf0e10cSrcweir eType == PDFWriter::TableHeader || 11547cdf0e10cSrcweir eType == PDFWriter::TableData || 11548cdf0e10cSrcweir eType == PDFWriter::Span || 11549cdf0e10cSrcweir eType == PDFWriter::Quote || 11550cdf0e10cSrcweir eType == PDFWriter::Note || 11551cdf0e10cSrcweir eType == PDFWriter::Reference || 11552cdf0e10cSrcweir eType == PDFWriter::BibEntry || 11553cdf0e10cSrcweir eType == PDFWriter::Code || 11554cdf0e10cSrcweir eType == PDFWriter::Link ) 11555cdf0e10cSrcweir { 11556cdf0e10cSrcweir bInsert = true; 11557cdf0e10cSrcweir } 11558cdf0e10cSrcweir } 11559cdf0e10cSrcweir break; 11560cdf0e10cSrcweir case PDFWriter::TextDecorationType: 11561cdf0e10cSrcweir if( eVal == PDFWriter::NONE || 11562cdf0e10cSrcweir eVal == PDFWriter::Underline || 11563cdf0e10cSrcweir eVal == PDFWriter::Overline || 11564cdf0e10cSrcweir eVal == PDFWriter::LineThrough ) 11565cdf0e10cSrcweir { 11566cdf0e10cSrcweir // only for ILSE and BLSE 11567cdf0e10cSrcweir if( eType == PDFWriter::Paragraph || 11568cdf0e10cSrcweir eType == PDFWriter::Heading || 11569cdf0e10cSrcweir eType == PDFWriter::H1 || 11570cdf0e10cSrcweir eType == PDFWriter::H2 || 11571cdf0e10cSrcweir eType == PDFWriter::H3 || 11572cdf0e10cSrcweir eType == PDFWriter::H4 || 11573cdf0e10cSrcweir eType == PDFWriter::H5 || 11574cdf0e10cSrcweir eType == PDFWriter::H6 || 11575cdf0e10cSrcweir eType == PDFWriter::List || 11576cdf0e10cSrcweir eType == PDFWriter::ListItem || 11577cdf0e10cSrcweir eType == PDFWriter::LILabel || 11578cdf0e10cSrcweir eType == PDFWriter::LIBody || 11579cdf0e10cSrcweir eType == PDFWriter::Table || 11580cdf0e10cSrcweir eType == PDFWriter::TableRow || 11581cdf0e10cSrcweir eType == PDFWriter::TableHeader || 11582cdf0e10cSrcweir eType == PDFWriter::TableData || 11583cdf0e10cSrcweir eType == PDFWriter::Span || 11584cdf0e10cSrcweir eType == PDFWriter::Quote || 11585cdf0e10cSrcweir eType == PDFWriter::Note || 11586cdf0e10cSrcweir eType == PDFWriter::Reference || 11587cdf0e10cSrcweir eType == PDFWriter::BibEntry || 11588cdf0e10cSrcweir eType == PDFWriter::Code || 11589cdf0e10cSrcweir eType == PDFWriter::Link ) 11590cdf0e10cSrcweir { 11591cdf0e10cSrcweir bInsert = true; 11592cdf0e10cSrcweir } 11593cdf0e10cSrcweir } 11594cdf0e10cSrcweir break; 11595cdf0e10cSrcweir case PDFWriter::ListNumbering: 11596cdf0e10cSrcweir if( eVal == PDFWriter::NONE || 11597cdf0e10cSrcweir eVal == PDFWriter::Disc || 11598cdf0e10cSrcweir eVal == PDFWriter::Circle || 11599cdf0e10cSrcweir eVal == PDFWriter::Square || 11600cdf0e10cSrcweir eVal == PDFWriter::Decimal || 11601cdf0e10cSrcweir eVal == PDFWriter::UpperRoman || 11602cdf0e10cSrcweir eVal == PDFWriter::LowerRoman || 11603cdf0e10cSrcweir eVal == PDFWriter::UpperAlpha || 11604cdf0e10cSrcweir eVal == PDFWriter::LowerAlpha ) 11605cdf0e10cSrcweir { 11606cdf0e10cSrcweir if( eType == PDFWriter::List ) 11607cdf0e10cSrcweir bInsert = true; 11608cdf0e10cSrcweir } 11609cdf0e10cSrcweir break; 11610cdf0e10cSrcweir default: break; 11611cdf0e10cSrcweir } 11612cdf0e10cSrcweir } 11613cdf0e10cSrcweir 11614cdf0e10cSrcweir if( bInsert ) 11615cdf0e10cSrcweir m_aStructure[ m_nCurrentStructElement ].m_aAttributes[ eAttr ] = PDFStructureAttribute( eVal ); 11616cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 11617cdf0e10cSrcweir else if( m_nCurrentStructElement > 0 && m_bEmitStructure ) 11618cdf0e10cSrcweir fprintf( stderr, "rejecting setStructureAttribute( %s, %s ) on %s (%s) element\n", 11619cdf0e10cSrcweir getAttributeTag( eAttr ), 11620cdf0e10cSrcweir getAttributeValueTag( eVal ), 11621cdf0e10cSrcweir getStructureTag( m_aStructure[ m_nCurrentStructElement ].m_eType ), 11622cdf0e10cSrcweir m_aStructure[ m_nCurrentStructElement ].m_aAlias.getStr() 11623cdf0e10cSrcweir ); 11624cdf0e10cSrcweir #endif 11625cdf0e10cSrcweir 11626cdf0e10cSrcweir return bInsert; 11627cdf0e10cSrcweir } 11628cdf0e10cSrcweir 11629cdf0e10cSrcweir bool PDFWriterImpl::setStructureAttributeNumerical( enum PDFWriter::StructAttribute eAttr, sal_Int32 nValue ) 11630cdf0e10cSrcweir { 11631cdf0e10cSrcweir if( ! m_aContext.Tagged ) 11632cdf0e10cSrcweir return false; 11633cdf0e10cSrcweir 11634cdf0e10cSrcweir bool bInsert = false; 11635cdf0e10cSrcweir if( m_nCurrentStructElement > 0 && m_bEmitStructure ) 11636cdf0e10cSrcweir { 11637cdf0e10cSrcweir if( eAttr == PDFWriter::Language ) 11638cdf0e10cSrcweir { 11639cdf0e10cSrcweir m_aStructure[ m_nCurrentStructElement ].m_aLocale = MsLangId::convertLanguageToLocale( (LanguageType)nValue ); 11640cdf0e10cSrcweir return true; 11641cdf0e10cSrcweir } 11642cdf0e10cSrcweir 11643cdf0e10cSrcweir PDFWriter::StructElement eType = m_aStructure[ m_nCurrentStructElement ].m_eType; 11644cdf0e10cSrcweir switch( eAttr ) 11645cdf0e10cSrcweir { 11646cdf0e10cSrcweir case PDFWriter::SpaceBefore: 11647cdf0e10cSrcweir case PDFWriter::SpaceAfter: 11648cdf0e10cSrcweir case PDFWriter::StartIndent: 11649cdf0e10cSrcweir case PDFWriter::EndIndent: 11650cdf0e10cSrcweir // just for BLSE 11651cdf0e10cSrcweir if( eType == PDFWriter::Paragraph || 11652cdf0e10cSrcweir eType == PDFWriter::Heading || 11653cdf0e10cSrcweir eType == PDFWriter::H1 || 11654cdf0e10cSrcweir eType == PDFWriter::H2 || 11655cdf0e10cSrcweir eType == PDFWriter::H3 || 11656cdf0e10cSrcweir eType == PDFWriter::H4 || 11657cdf0e10cSrcweir eType == PDFWriter::H5 || 11658cdf0e10cSrcweir eType == PDFWriter::H6 || 11659cdf0e10cSrcweir eType == PDFWriter::List || 11660cdf0e10cSrcweir eType == PDFWriter::ListItem || 11661cdf0e10cSrcweir eType == PDFWriter::LILabel || 11662cdf0e10cSrcweir eType == PDFWriter::LIBody || 11663cdf0e10cSrcweir eType == PDFWriter::Table || 11664cdf0e10cSrcweir eType == PDFWriter::TableRow || 11665cdf0e10cSrcweir eType == PDFWriter::TableHeader || 11666cdf0e10cSrcweir eType == PDFWriter::TableData ) 11667cdf0e10cSrcweir { 11668cdf0e10cSrcweir bInsert = true; 11669cdf0e10cSrcweir } 11670cdf0e10cSrcweir break; 11671cdf0e10cSrcweir case PDFWriter::TextIndent: 11672cdf0e10cSrcweir // paragraph like BLSE and additional elements 11673cdf0e10cSrcweir if( eType == PDFWriter::Paragraph || 11674cdf0e10cSrcweir eType == PDFWriter::Heading || 11675cdf0e10cSrcweir eType == PDFWriter::H1 || 11676cdf0e10cSrcweir eType == PDFWriter::H2 || 11677cdf0e10cSrcweir eType == PDFWriter::H3 || 11678cdf0e10cSrcweir eType == PDFWriter::H4 || 11679cdf0e10cSrcweir eType == PDFWriter::H5 || 11680cdf0e10cSrcweir eType == PDFWriter::H6 || 11681cdf0e10cSrcweir eType == PDFWriter::LILabel || 11682cdf0e10cSrcweir eType == PDFWriter::LIBody || 11683cdf0e10cSrcweir eType == PDFWriter::TableHeader || 11684cdf0e10cSrcweir eType == PDFWriter::TableData ) 11685cdf0e10cSrcweir { 11686cdf0e10cSrcweir bInsert = true; 11687cdf0e10cSrcweir } 11688cdf0e10cSrcweir break; 11689cdf0e10cSrcweir case PDFWriter::Width: 11690cdf0e10cSrcweir case PDFWriter::Height: 11691cdf0e10cSrcweir if( eType == PDFWriter::Figure || 11692cdf0e10cSrcweir eType == PDFWriter::Formula || 11693cdf0e10cSrcweir eType == PDFWriter::Form || 11694cdf0e10cSrcweir eType == PDFWriter::Table || 11695cdf0e10cSrcweir eType == PDFWriter::TableHeader || 11696cdf0e10cSrcweir eType == PDFWriter::TableData ) 11697cdf0e10cSrcweir { 11698cdf0e10cSrcweir bInsert = true; 11699cdf0e10cSrcweir } 11700cdf0e10cSrcweir break; 11701cdf0e10cSrcweir case PDFWriter::LineHeight: 11702cdf0e10cSrcweir case PDFWriter::BaselineShift: 11703cdf0e10cSrcweir // only for ILSE and BLSE 11704cdf0e10cSrcweir if( eType == PDFWriter::Paragraph || 11705cdf0e10cSrcweir eType == PDFWriter::Heading || 11706cdf0e10cSrcweir eType == PDFWriter::H1 || 11707cdf0e10cSrcweir eType == PDFWriter::H2 || 11708cdf0e10cSrcweir eType == PDFWriter::H3 || 11709cdf0e10cSrcweir eType == PDFWriter::H4 || 11710cdf0e10cSrcweir eType == PDFWriter::H5 || 11711cdf0e10cSrcweir eType == PDFWriter::H6 || 11712cdf0e10cSrcweir eType == PDFWriter::List || 11713cdf0e10cSrcweir eType == PDFWriter::ListItem || 11714cdf0e10cSrcweir eType == PDFWriter::LILabel || 11715cdf0e10cSrcweir eType == PDFWriter::LIBody || 11716cdf0e10cSrcweir eType == PDFWriter::Table || 11717cdf0e10cSrcweir eType == PDFWriter::TableRow || 11718cdf0e10cSrcweir eType == PDFWriter::TableHeader || 11719cdf0e10cSrcweir eType == PDFWriter::TableData || 11720cdf0e10cSrcweir eType == PDFWriter::Span || 11721cdf0e10cSrcweir eType == PDFWriter::Quote || 11722cdf0e10cSrcweir eType == PDFWriter::Note || 11723cdf0e10cSrcweir eType == PDFWriter::Reference || 11724cdf0e10cSrcweir eType == PDFWriter::BibEntry || 11725cdf0e10cSrcweir eType == PDFWriter::Code || 11726cdf0e10cSrcweir eType == PDFWriter::Link ) 11727cdf0e10cSrcweir { 11728cdf0e10cSrcweir bInsert = true; 11729cdf0e10cSrcweir } 11730cdf0e10cSrcweir break; 11731cdf0e10cSrcweir case PDFWriter::RowSpan: 11732cdf0e10cSrcweir case PDFWriter::ColSpan: 11733cdf0e10cSrcweir // only for table cells 11734cdf0e10cSrcweir if( eType == PDFWriter::TableHeader || 11735cdf0e10cSrcweir eType == PDFWriter::TableData ) 11736cdf0e10cSrcweir { 11737cdf0e10cSrcweir bInsert = true; 11738cdf0e10cSrcweir } 11739cdf0e10cSrcweir break; 11740cdf0e10cSrcweir case PDFWriter::LinkAnnotation: 11741cdf0e10cSrcweir if( eType == PDFWriter::Link ) 11742cdf0e10cSrcweir bInsert = true; 11743cdf0e10cSrcweir break; 11744cdf0e10cSrcweir default: break; 11745cdf0e10cSrcweir } 11746cdf0e10cSrcweir } 11747cdf0e10cSrcweir 11748cdf0e10cSrcweir if( bInsert ) 11749cdf0e10cSrcweir m_aStructure[ m_nCurrentStructElement ].m_aAttributes[ eAttr ] = PDFStructureAttribute( nValue ); 11750cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 11751cdf0e10cSrcweir else if( m_nCurrentStructElement > 0 && m_bEmitStructure ) 11752cdf0e10cSrcweir fprintf( stderr, "rejecting setStructureAttributeNumerical( %s, %d ) on %s (%s) element\n", 11753cdf0e10cSrcweir getAttributeTag( eAttr ), 11754cdf0e10cSrcweir (int)nValue, 11755cdf0e10cSrcweir getStructureTag( m_aStructure[ m_nCurrentStructElement ].m_eType ), 11756cdf0e10cSrcweir m_aStructure[ m_nCurrentStructElement ].m_aAlias.getStr() ); 11757cdf0e10cSrcweir #endif 11758cdf0e10cSrcweir 11759cdf0e10cSrcweir return bInsert; 11760cdf0e10cSrcweir } 11761cdf0e10cSrcweir 11762cdf0e10cSrcweir void PDFWriterImpl::setStructureBoundingBox( const Rectangle& rRect ) 11763cdf0e10cSrcweir { 11764cdf0e10cSrcweir sal_Int32 nPageNr = m_nCurrentPage; 11765cdf0e10cSrcweir if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() || !m_aContext.Tagged ) 11766cdf0e10cSrcweir return; 11767cdf0e10cSrcweir 11768cdf0e10cSrcweir 11769cdf0e10cSrcweir if( m_nCurrentStructElement > 0 && m_bEmitStructure ) 11770cdf0e10cSrcweir { 11771cdf0e10cSrcweir PDFWriter::StructElement eType = m_aStructure[ m_nCurrentStructElement ].m_eType; 11772cdf0e10cSrcweir if( eType == PDFWriter::Figure || 11773cdf0e10cSrcweir eType == PDFWriter::Formula || 11774cdf0e10cSrcweir eType == PDFWriter::Form || 11775cdf0e10cSrcweir eType == PDFWriter::Table ) 11776cdf0e10cSrcweir { 11777cdf0e10cSrcweir m_aStructure[ m_nCurrentStructElement ].m_aBBox = rRect; 11778cdf0e10cSrcweir // convert to default user space now, since the mapmode may change 11779cdf0e10cSrcweir m_aPages[nPageNr].convertRect( m_aStructure[ m_nCurrentStructElement ].m_aBBox ); 11780cdf0e10cSrcweir } 11781cdf0e10cSrcweir } 11782cdf0e10cSrcweir } 11783cdf0e10cSrcweir 11784cdf0e10cSrcweir void PDFWriterImpl::setActualText( const String& rText ) 11785cdf0e10cSrcweir { 11786cdf0e10cSrcweir if( m_aContext.Tagged && m_nCurrentStructElement > 0 && m_bEmitStructure ) 11787cdf0e10cSrcweir { 11788cdf0e10cSrcweir m_aStructure[ m_nCurrentStructElement ].m_aActualText = rText; 11789cdf0e10cSrcweir } 11790cdf0e10cSrcweir } 11791cdf0e10cSrcweir 11792cdf0e10cSrcweir void PDFWriterImpl::setAlternateText( const String& rText ) 11793cdf0e10cSrcweir { 11794cdf0e10cSrcweir if( m_aContext.Tagged && m_nCurrentStructElement > 0 && m_bEmitStructure ) 11795cdf0e10cSrcweir { 11796cdf0e10cSrcweir m_aStructure[ m_nCurrentStructElement ].m_aAltText = rText; 11797cdf0e10cSrcweir } 11798cdf0e10cSrcweir } 11799cdf0e10cSrcweir 11800cdf0e10cSrcweir void PDFWriterImpl::setAutoAdvanceTime( sal_uInt32 nSeconds, sal_Int32 nPageNr ) 11801cdf0e10cSrcweir { 11802cdf0e10cSrcweir if( nPageNr < 0 ) 11803cdf0e10cSrcweir nPageNr = m_nCurrentPage; 11804cdf0e10cSrcweir 11805cdf0e10cSrcweir if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() ) 11806cdf0e10cSrcweir return; 11807cdf0e10cSrcweir 11808cdf0e10cSrcweir m_aPages[ nPageNr ].m_nDuration = nSeconds; 11809cdf0e10cSrcweir } 11810cdf0e10cSrcweir 11811cdf0e10cSrcweir void PDFWriterImpl::setPageTransition( PDFWriter::PageTransition eType, sal_uInt32 nMilliSec, sal_Int32 nPageNr ) 11812cdf0e10cSrcweir { 11813cdf0e10cSrcweir if( nPageNr < 0 ) 11814cdf0e10cSrcweir nPageNr = m_nCurrentPage; 11815cdf0e10cSrcweir 11816cdf0e10cSrcweir if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() ) 11817cdf0e10cSrcweir return; 11818cdf0e10cSrcweir 11819cdf0e10cSrcweir m_aPages[ nPageNr ].m_eTransition = eType; 11820cdf0e10cSrcweir m_aPages[ nPageNr ].m_nTransTime = nMilliSec; 11821cdf0e10cSrcweir } 11822cdf0e10cSrcweir 11823cdf0e10cSrcweir void PDFWriterImpl::ensureUniqueRadioOnValues() 11824cdf0e10cSrcweir { 11825cdf0e10cSrcweir // loop over radio groups 11826cdf0e10cSrcweir for( std::map<sal_Int32,sal_Int32>::const_iterator group = m_aRadioGroupWidgets.begin(); 11827cdf0e10cSrcweir group != m_aRadioGroupWidgets.end(); ++group ) 11828cdf0e10cSrcweir { 11829cdf0e10cSrcweir PDFWidget& rGroupWidget = m_aWidgets[ group->second ]; 11830cdf0e10cSrcweir // check whether all kids have a unique OnValue 11831cdf0e10cSrcweir std::hash_map< OUString, sal_Int32, OUStringHash > aOnValues; 11832cdf0e10cSrcweir int nChildren = rGroupWidget.m_aKidsIndex.size(); 11833cdf0e10cSrcweir bool bIsUnique = true; 11834cdf0e10cSrcweir for( int nKid = 0; nKid < nChildren && bIsUnique; nKid++ ) 11835cdf0e10cSrcweir { 11836cdf0e10cSrcweir int nKidIndex = rGroupWidget.m_aKidsIndex[nKid]; 11837cdf0e10cSrcweir const OUString& rVal = m_aWidgets[nKidIndex].m_aOnValue; 11838cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 11839cdf0e10cSrcweir fprintf( stderr, "OnValue: %s\n", OUStringToOString( rVal, RTL_TEXTENCODING_UTF8 ).getStr() ); 11840cdf0e10cSrcweir #endif 11841cdf0e10cSrcweir if( aOnValues.find( rVal ) == aOnValues.end() ) 11842cdf0e10cSrcweir { 11843cdf0e10cSrcweir aOnValues[ rVal ] = 1; 11844cdf0e10cSrcweir } 11845cdf0e10cSrcweir else 11846cdf0e10cSrcweir { 11847cdf0e10cSrcweir bIsUnique = false; 11848cdf0e10cSrcweir } 11849cdf0e10cSrcweir } 11850cdf0e10cSrcweir if( ! bIsUnique ) 11851cdf0e10cSrcweir { 11852cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 11853cdf0e10cSrcweir fprintf( stderr, "enforcing unique OnValues\n" ); 11854cdf0e10cSrcweir #endif 11855cdf0e10cSrcweir // make unique by using ascending OnValues 11856cdf0e10cSrcweir for( int nKid = 0; nKid < nChildren; nKid++ ) 11857cdf0e10cSrcweir { 11858cdf0e10cSrcweir int nKidIndex = rGroupWidget.m_aKidsIndex[nKid]; 11859cdf0e10cSrcweir PDFWidget& rKid = m_aWidgets[nKidIndex]; 11860cdf0e10cSrcweir rKid.m_aOnValue = OUString::valueOf( sal_Int32(nKid+1) ); 11861cdf0e10cSrcweir if( ! rKid.m_aValue.equalsAscii( "Off" ) ) 11862cdf0e10cSrcweir rKid.m_aValue = rKid.m_aOnValue; 11863cdf0e10cSrcweir } 11864cdf0e10cSrcweir } 11865cdf0e10cSrcweir // finally move the "Yes" appearance to the OnValue appearance 11866cdf0e10cSrcweir for( int nKid = 0; nKid < nChildren; nKid++ ) 11867cdf0e10cSrcweir { 11868cdf0e10cSrcweir int nKidIndex = rGroupWidget.m_aKidsIndex[nKid]; 11869cdf0e10cSrcweir PDFWidget& rKid = m_aWidgets[nKidIndex]; 11870cdf0e10cSrcweir PDFAppearanceMap::iterator app_it = rKid.m_aAppearances.find( "N" ); 11871cdf0e10cSrcweir if( app_it != rKid.m_aAppearances.end() ) 11872cdf0e10cSrcweir { 11873cdf0e10cSrcweir PDFAppearanceStreams::iterator stream_it = app_it->second.find( "Yes" ); 11874cdf0e10cSrcweir if( stream_it != app_it->second.end() ) 11875cdf0e10cSrcweir { 11876cdf0e10cSrcweir SvMemoryStream* pStream = stream_it->second; 11877cdf0e10cSrcweir app_it->second.erase( stream_it ); 11878cdf0e10cSrcweir OStringBuffer aBuf( rKid.m_aOnValue.getLength()*2 ); 11879cdf0e10cSrcweir appendName( rKid.m_aOnValue, aBuf ); 11880cdf0e10cSrcweir (app_it->second)[ aBuf.makeStringAndClear() ] = pStream; 11881cdf0e10cSrcweir } 11882cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 11883cdf0e10cSrcweir else 11884cdf0e10cSrcweir fprintf( stderr, "error: RadioButton without \"Yes\" stream\n" ); 11885cdf0e10cSrcweir #endif 11886cdf0e10cSrcweir } 11887cdf0e10cSrcweir // update selected radio button 11888cdf0e10cSrcweir if( ! rKid.m_aValue.equalsAscii( "Off" ) ) 11889cdf0e10cSrcweir { 11890cdf0e10cSrcweir rGroupWidget.m_aValue = rKid.m_aValue; 11891cdf0e10cSrcweir } 11892cdf0e10cSrcweir } 11893cdf0e10cSrcweir } 11894cdf0e10cSrcweir } 11895cdf0e10cSrcweir 11896cdf0e10cSrcweir sal_Int32 PDFWriterImpl::findRadioGroupWidget( const PDFWriter::RadioButtonWidget& rBtn ) 11897cdf0e10cSrcweir { 11898cdf0e10cSrcweir sal_Int32 nRadioGroupWidget = -1; 11899cdf0e10cSrcweir 11900cdf0e10cSrcweir std::map< sal_Int32, sal_Int32 >::const_iterator it = m_aRadioGroupWidgets.find( rBtn.RadioGroup ); 11901cdf0e10cSrcweir 11902cdf0e10cSrcweir if( it == m_aRadioGroupWidgets.end() ) 11903cdf0e10cSrcweir { 11904cdf0e10cSrcweir m_aRadioGroupWidgets[ rBtn.RadioGroup ] = nRadioGroupWidget = 11905cdf0e10cSrcweir sal_Int32(m_aWidgets.size()); 11906cdf0e10cSrcweir 11907cdf0e10cSrcweir // new group, insert the radiobutton 11908cdf0e10cSrcweir m_aWidgets.push_back( PDFWidget() ); 11909cdf0e10cSrcweir m_aWidgets.back().m_nObject = createObject(); 11910cdf0e10cSrcweir m_aWidgets.back().m_nPage = m_nCurrentPage; 11911cdf0e10cSrcweir m_aWidgets.back().m_eType = PDFWriter::RadioButton; 11912cdf0e10cSrcweir m_aWidgets.back().m_nRadioGroup = rBtn.RadioGroup; 11913cdf0e10cSrcweir m_aWidgets.back().m_nFlags |= 0x0000C000; // NoToggleToOff and Radio bits 11914cdf0e10cSrcweir 11915cdf0e10cSrcweir createWidgetFieldName( sal_Int32(m_aWidgets.size()-1), rBtn ); 11916cdf0e10cSrcweir } 11917cdf0e10cSrcweir else 11918cdf0e10cSrcweir nRadioGroupWidget = it->second; 11919cdf0e10cSrcweir 11920cdf0e10cSrcweir return nRadioGroupWidget; 11921cdf0e10cSrcweir } 11922cdf0e10cSrcweir 11923cdf0e10cSrcweir sal_Int32 PDFWriterImpl::createControl( const PDFWriter::AnyWidget& rControl, sal_Int32 nPageNr ) 11924cdf0e10cSrcweir { 11925cdf0e10cSrcweir if( nPageNr < 0 ) 11926cdf0e10cSrcweir nPageNr = m_nCurrentPage; 11927cdf0e10cSrcweir 11928cdf0e10cSrcweir if( nPageNr < 0 || nPageNr >= (sal_Int32)m_aPages.size() ) 11929cdf0e10cSrcweir return -1; 11930cdf0e10cSrcweir 11931cdf0e10cSrcweir sal_Int32 nNewWidget = m_aWidgets.size(); 11932cdf0e10cSrcweir m_aWidgets.push_back( PDFWidget() ); 11933cdf0e10cSrcweir 11934cdf0e10cSrcweir m_aWidgets.back().m_nObject = createObject(); 11935cdf0e10cSrcweir m_aWidgets.back().m_aRect = rControl.Location; 11936cdf0e10cSrcweir m_aWidgets.back().m_nPage = nPageNr; 11937cdf0e10cSrcweir m_aWidgets.back().m_eType = rControl.getType(); 11938cdf0e10cSrcweir 11939cdf0e10cSrcweir sal_Int32 nRadioGroupWidget = -1; 11940cdf0e10cSrcweir // for unknown reasons the radio buttons of a radio group must not have a 11941cdf0e10cSrcweir // field name, else the buttons are in fact check boxes - 11942cdf0e10cSrcweir // that is multiple buttons of the radio group can be selected 11943cdf0e10cSrcweir if( rControl.getType() == PDFWriter::RadioButton ) 11944cdf0e10cSrcweir nRadioGroupWidget = findRadioGroupWidget( static_cast<const PDFWriter::RadioButtonWidget&>(rControl) ); 11945cdf0e10cSrcweir else 11946cdf0e10cSrcweir { 11947cdf0e10cSrcweir createWidgetFieldName( nNewWidget, rControl ); 11948cdf0e10cSrcweir } 11949cdf0e10cSrcweir 11950cdf0e10cSrcweir // caution: m_aWidgets must not be changed after here or rNewWidget may be invalid 11951cdf0e10cSrcweir PDFWidget& rNewWidget = m_aWidgets[nNewWidget]; 11952cdf0e10cSrcweir rNewWidget.m_aDescription = rControl.Description; 11953cdf0e10cSrcweir rNewWidget.m_aText = rControl.Text; 11954cdf0e10cSrcweir rNewWidget.m_nTextStyle = rControl.TextStyle & 11955cdf0e10cSrcweir ( TEXT_DRAW_LEFT | TEXT_DRAW_CENTER | TEXT_DRAW_RIGHT | TEXT_DRAW_TOP | 11956cdf0e10cSrcweir TEXT_DRAW_VCENTER | TEXT_DRAW_BOTTOM | 11957cdf0e10cSrcweir TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK ); 11958cdf0e10cSrcweir rNewWidget.m_nTabOrder = rControl.TabOrder; 11959cdf0e10cSrcweir 11960cdf0e10cSrcweir // various properties are set via the flags (/Ff) property of the field dict 11961cdf0e10cSrcweir if( rControl.ReadOnly ) 11962cdf0e10cSrcweir rNewWidget.m_nFlags |= 1; 11963cdf0e10cSrcweir if( rControl.getType() == PDFWriter::PushButton ) 11964cdf0e10cSrcweir { 11965cdf0e10cSrcweir const PDFWriter::PushButtonWidget& rBtn = static_cast<const PDFWriter::PushButtonWidget&>(rControl); 11966cdf0e10cSrcweir if( rNewWidget.m_nTextStyle == 0 ) 11967cdf0e10cSrcweir rNewWidget.m_nTextStyle = 11968cdf0e10cSrcweir TEXT_DRAW_CENTER | TEXT_DRAW_VCENTER | 11969cdf0e10cSrcweir TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK; 11970cdf0e10cSrcweir 11971cdf0e10cSrcweir rNewWidget.m_nFlags |= 0x00010000; 11972cdf0e10cSrcweir if( rBtn.URL.getLength() ) 11973cdf0e10cSrcweir rNewWidget.m_aListEntries.push_back( rBtn.URL ); 11974cdf0e10cSrcweir rNewWidget.m_bSubmit = rBtn.Submit; 11975cdf0e10cSrcweir rNewWidget.m_bSubmitGet = rBtn.SubmitGet; 11976cdf0e10cSrcweir rNewWidget.m_nDest = rBtn.Dest; 11977cdf0e10cSrcweir createDefaultPushButtonAppearance( rNewWidget, rBtn ); 11978cdf0e10cSrcweir } 11979cdf0e10cSrcweir else if( rControl.getType() == PDFWriter::RadioButton ) 11980cdf0e10cSrcweir { 11981cdf0e10cSrcweir const PDFWriter::RadioButtonWidget& rBtn = static_cast<const PDFWriter::RadioButtonWidget&>(rControl); 11982cdf0e10cSrcweir if( rNewWidget.m_nTextStyle == 0 ) 11983cdf0e10cSrcweir rNewWidget.m_nTextStyle = 11984cdf0e10cSrcweir TEXT_DRAW_VCENTER | TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK; 11985cdf0e10cSrcweir /* PDF sees a RadioButton group as one radio button with 11986cdf0e10cSrcweir * children which are in turn check boxes 11987cdf0e10cSrcweir * 11988cdf0e10cSrcweir * so we need to create a radio button on demand for a new group 11989cdf0e10cSrcweir * and insert a checkbox for each RadioButtonWidget as its child 11990cdf0e10cSrcweir */ 11991cdf0e10cSrcweir rNewWidget.m_eType = PDFWriter::CheckBox; 11992cdf0e10cSrcweir rNewWidget.m_nRadioGroup = rBtn.RadioGroup; 11993cdf0e10cSrcweir 11994cdf0e10cSrcweir DBG_ASSERT( nRadioGroupWidget >= 0 && nRadioGroupWidget < (sal_Int32)m_aWidgets.size(), "no radio group parent" ); 11995cdf0e10cSrcweir 11996cdf0e10cSrcweir PDFWidget& rRadioButton = m_aWidgets[nRadioGroupWidget]; 11997cdf0e10cSrcweir rRadioButton.m_aKids.push_back( rNewWidget.m_nObject ); 11998cdf0e10cSrcweir rRadioButton.m_aKidsIndex.push_back( nNewWidget ); 11999cdf0e10cSrcweir rNewWidget.m_nParent = rRadioButton.m_nObject; 12000cdf0e10cSrcweir 12001cdf0e10cSrcweir rNewWidget.m_aValue = OUString( RTL_CONSTASCII_USTRINGPARAM( "Off" ) ); 12002cdf0e10cSrcweir rNewWidget.m_aOnValue = rBtn.OnValue; 12003cdf0e10cSrcweir if( ! rRadioButton.m_aValue.getLength() && rBtn.Selected ) 12004cdf0e10cSrcweir { 12005cdf0e10cSrcweir rNewWidget.m_aValue = rNewWidget.m_aOnValue; 12006cdf0e10cSrcweir rRadioButton.m_aValue = rNewWidget.m_aOnValue; 12007cdf0e10cSrcweir } 12008cdf0e10cSrcweir createDefaultRadioButtonAppearance( rNewWidget, rBtn ); 12009cdf0e10cSrcweir 12010cdf0e10cSrcweir // union rect of radio group 12011cdf0e10cSrcweir Rectangle aRect = rNewWidget.m_aRect; 12012cdf0e10cSrcweir m_aPages[ nPageNr ].convertRect( aRect ); 12013cdf0e10cSrcweir rRadioButton.m_aRect.Union( aRect ); 12014cdf0e10cSrcweir } 12015cdf0e10cSrcweir else if( rControl.getType() == PDFWriter::CheckBox ) 12016cdf0e10cSrcweir { 12017cdf0e10cSrcweir const PDFWriter::CheckBoxWidget& rBox = static_cast<const PDFWriter::CheckBoxWidget&>(rControl); 12018cdf0e10cSrcweir if( rNewWidget.m_nTextStyle == 0 ) 12019cdf0e10cSrcweir rNewWidget.m_nTextStyle = 12020cdf0e10cSrcweir TEXT_DRAW_VCENTER | TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK; 12021cdf0e10cSrcweir 12022cdf0e10cSrcweir rNewWidget.m_aValue = OUString::createFromAscii( rBox.Checked ? "Yes" : "Off" ); 12023cdf0e10cSrcweir // create default appearance before m_aRect gets transformed 12024cdf0e10cSrcweir createDefaultCheckBoxAppearance( rNewWidget, rBox ); 12025cdf0e10cSrcweir } 12026cdf0e10cSrcweir else if( rControl.getType() == PDFWriter::ListBox ) 12027cdf0e10cSrcweir { 12028cdf0e10cSrcweir if( rNewWidget.m_nTextStyle == 0 ) 12029cdf0e10cSrcweir rNewWidget.m_nTextStyle = TEXT_DRAW_VCENTER; 12030cdf0e10cSrcweir 12031cdf0e10cSrcweir const PDFWriter::ListBoxWidget& rLstBox = static_cast<const PDFWriter::ListBoxWidget&>(rControl); 12032cdf0e10cSrcweir rNewWidget.m_aListEntries = rLstBox.Entries; 12033cdf0e10cSrcweir rNewWidget.m_aSelectedEntries = rLstBox.SelectedEntries; 12034cdf0e10cSrcweir rNewWidget.m_aValue = rLstBox.Text; 12035cdf0e10cSrcweir if( rLstBox.DropDown ) 12036cdf0e10cSrcweir rNewWidget.m_nFlags |= 0x00020000; 12037cdf0e10cSrcweir if( rLstBox.Sort ) 12038cdf0e10cSrcweir rNewWidget.m_nFlags |= 0x00080000; 12039cdf0e10cSrcweir if( rLstBox.MultiSelect && !rLstBox.DropDown && (int)m_aContext.Version > (int)PDFWriter::PDF_1_3 ) 12040cdf0e10cSrcweir rNewWidget.m_nFlags |= 0x00200000; 12041cdf0e10cSrcweir 12042cdf0e10cSrcweir createDefaultListBoxAppearance( rNewWidget, rLstBox ); 12043cdf0e10cSrcweir } 12044cdf0e10cSrcweir else if( rControl.getType() == PDFWriter::ComboBox ) 12045cdf0e10cSrcweir { 12046cdf0e10cSrcweir if( rNewWidget.m_nTextStyle == 0 ) 12047cdf0e10cSrcweir rNewWidget.m_nTextStyle = TEXT_DRAW_VCENTER; 12048cdf0e10cSrcweir 12049cdf0e10cSrcweir const PDFWriter::ComboBoxWidget& rBox = static_cast<const PDFWriter::ComboBoxWidget&>(rControl); 12050cdf0e10cSrcweir rNewWidget.m_aValue = rBox.Text; 12051cdf0e10cSrcweir rNewWidget.m_aListEntries = rBox.Entries; 12052cdf0e10cSrcweir rNewWidget.m_nFlags |= 0x00060000; // combo and edit flag 12053cdf0e10cSrcweir if( rBox.Sort ) 12054cdf0e10cSrcweir rNewWidget.m_nFlags |= 0x00080000; 12055cdf0e10cSrcweir 12056cdf0e10cSrcweir PDFWriter::ListBoxWidget aLBox; 12057cdf0e10cSrcweir aLBox.Name = rBox.Name; 12058cdf0e10cSrcweir aLBox.Description = rBox.Description; 12059cdf0e10cSrcweir aLBox.Text = rBox.Text; 12060cdf0e10cSrcweir aLBox.TextStyle = rBox.TextStyle; 12061cdf0e10cSrcweir aLBox.ReadOnly = rBox.ReadOnly; 12062cdf0e10cSrcweir aLBox.Border = rBox.Border; 12063cdf0e10cSrcweir aLBox.BorderColor = rBox.BorderColor; 12064cdf0e10cSrcweir aLBox.Background = rBox.Background; 12065cdf0e10cSrcweir aLBox.BackgroundColor = rBox.BackgroundColor; 12066cdf0e10cSrcweir aLBox.TextFont = rBox.TextFont; 12067cdf0e10cSrcweir aLBox.TextColor = rBox.TextColor; 12068cdf0e10cSrcweir aLBox.DropDown = true; 12069cdf0e10cSrcweir aLBox.Sort = rBox.Sort; 12070cdf0e10cSrcweir aLBox.MultiSelect = false; 12071cdf0e10cSrcweir aLBox.Entries = rBox.Entries; 12072cdf0e10cSrcweir 12073cdf0e10cSrcweir createDefaultListBoxAppearance( rNewWidget, aLBox ); 12074cdf0e10cSrcweir } 12075cdf0e10cSrcweir else if( rControl.getType() == PDFWriter::Edit ) 12076cdf0e10cSrcweir { 12077cdf0e10cSrcweir if( rNewWidget.m_nTextStyle == 0 ) 12078cdf0e10cSrcweir rNewWidget.m_nTextStyle = TEXT_DRAW_LEFT | TEXT_DRAW_VCENTER; 12079cdf0e10cSrcweir 12080cdf0e10cSrcweir const PDFWriter::EditWidget& rEdit = static_cast<const PDFWriter::EditWidget&>(rControl); 12081cdf0e10cSrcweir if( rEdit.MultiLine ) 12082cdf0e10cSrcweir { 12083cdf0e10cSrcweir rNewWidget.m_nFlags |= 0x00001000; 12084cdf0e10cSrcweir rNewWidget.m_nTextStyle |= TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK; 12085cdf0e10cSrcweir } 12086cdf0e10cSrcweir if( rEdit.Password ) 12087cdf0e10cSrcweir rNewWidget.m_nFlags |= 0x00002000; 12088cdf0e10cSrcweir if( rEdit.FileSelect && m_aContext.Version > PDFWriter::PDF_1_3 ) 12089cdf0e10cSrcweir rNewWidget.m_nFlags |= 0x00100000; 12090cdf0e10cSrcweir rNewWidget.m_nMaxLen = rEdit.MaxLen; 12091cdf0e10cSrcweir rNewWidget.m_aValue = rEdit.Text; 12092cdf0e10cSrcweir 12093cdf0e10cSrcweir createDefaultEditAppearance( rNewWidget, rEdit ); 12094cdf0e10cSrcweir } 12095cdf0e10cSrcweir 12096cdf0e10cSrcweir // convert to default user space now, since the mapmode may change 12097cdf0e10cSrcweir // note: create default appearances before m_aRect gets transformed 12098cdf0e10cSrcweir m_aPages[ nPageNr ].convertRect( rNewWidget.m_aRect ); 12099cdf0e10cSrcweir 12100cdf0e10cSrcweir // insert widget to page's annotation list 12101cdf0e10cSrcweir m_aPages[ nPageNr ].m_aAnnotations.push_back( rNewWidget.m_nObject ); 12102cdf0e10cSrcweir 12103cdf0e10cSrcweir // mark page as having widgets 12104cdf0e10cSrcweir m_aPages[ nPageNr ].m_bHasWidgets = true; 12105cdf0e10cSrcweir 12106cdf0e10cSrcweir return nNewWidget; 12107cdf0e10cSrcweir } 12108cdf0e10cSrcweir 12109cdf0e10cSrcweir void PDFWriterImpl::beginControlAppearance( sal_Int32 nControl ) 12110cdf0e10cSrcweir { 12111cdf0e10cSrcweir if( nControl < 0 || nControl >= (sal_Int32)m_aWidgets.size() ) 12112cdf0e10cSrcweir return; 12113cdf0e10cSrcweir 12114cdf0e10cSrcweir PDFWidget& rWidget = m_aWidgets[ nControl ]; 12115cdf0e10cSrcweir m_nCurrentControl = nControl; 12116cdf0e10cSrcweir 12117cdf0e10cSrcweir SvMemoryStream* pControlStream = new SvMemoryStream( 1024, 1024 ); 12118cdf0e10cSrcweir // back conversion of control rect to current MapMode; necessary because 12119cdf0e10cSrcweir // MapMode between createControl and beginControlAppearance 12120cdf0e10cSrcweir // could have changed; therefore the widget rectangle is 12121cdf0e10cSrcweir // already converted 12122cdf0e10cSrcweir Rectangle aBack( Point( rWidget.m_aRect.Left(), pointToPixel(m_aPages[m_nCurrentPage].getHeight()) - rWidget.m_aRect.Top() - rWidget.m_aRect.GetHeight() ), 12123cdf0e10cSrcweir rWidget.m_aRect.GetSize() ); 12124cdf0e10cSrcweir aBack = lcl_convert( m_aMapMode, 12125cdf0e10cSrcweir m_aGraphicsStack.front().m_aMapMode, 12126cdf0e10cSrcweir getReferenceDevice(), 12127cdf0e10cSrcweir aBack ); 12128cdf0e10cSrcweir beginRedirect( pControlStream, aBack ); 12129cdf0e10cSrcweir writeBuffer( "/Tx BMC\n", 8 ); 12130cdf0e10cSrcweir } 12131cdf0e10cSrcweir 12132cdf0e10cSrcweir bool PDFWriterImpl::endControlAppearance( PDFWriter::WidgetState eState ) 12133cdf0e10cSrcweir { 12134cdf0e10cSrcweir bool bRet = false; 12135cdf0e10cSrcweir if( ! m_aOutputStreams.empty() ) 12136cdf0e10cSrcweir writeBuffer( "\nEMC\n", 5 ); 12137cdf0e10cSrcweir SvMemoryStream* pAppearance = static_cast<SvMemoryStream*>(endRedirect()); 12138cdf0e10cSrcweir if( pAppearance && m_nCurrentControl >= 0 && m_nCurrentControl < (sal_Int32)m_aWidgets.size() ) 12139cdf0e10cSrcweir { 12140cdf0e10cSrcweir PDFWidget& rWidget = m_aWidgets[ m_nCurrentControl ]; 12141cdf0e10cSrcweir OString aState, aStyle; 12142cdf0e10cSrcweir switch( rWidget.m_eType ) 12143cdf0e10cSrcweir { 12144cdf0e10cSrcweir case PDFWriter::PushButton: 12145cdf0e10cSrcweir if( eState == PDFWriter::Up || eState == PDFWriter::Down ) 12146cdf0e10cSrcweir { 12147cdf0e10cSrcweir aState = (eState == PDFWriter::Up) ? "N" : "D"; 12148cdf0e10cSrcweir aStyle = "Standard"; 12149cdf0e10cSrcweir } 12150cdf0e10cSrcweir break; 12151cdf0e10cSrcweir case PDFWriter::CheckBox: 12152cdf0e10cSrcweir if( eState == PDFWriter::Up || eState == PDFWriter::Down ) 12153cdf0e10cSrcweir { 12154cdf0e10cSrcweir aState = "N"; 12155cdf0e10cSrcweir aStyle = (eState == PDFWriter::Up) ? "Off" : "Yes"; 12156cdf0e10cSrcweir /* cf PDFReference 3rd ed. V1.4 p539: 12157cdf0e10cSrcweir recommended name for on state is "Yes", 12158cdf0e10cSrcweir recommended name for off state is "Off" 12159cdf0e10cSrcweir */ 12160cdf0e10cSrcweir } 12161cdf0e10cSrcweir break; 12162cdf0e10cSrcweir case PDFWriter::RadioButton: 12163cdf0e10cSrcweir if( eState == PDFWriter::Up || eState == PDFWriter::Down ) 12164cdf0e10cSrcweir { 12165cdf0e10cSrcweir aState = "N"; 12166cdf0e10cSrcweir if( eState == PDFWriter::Up ) 12167cdf0e10cSrcweir aStyle = "Off"; 12168cdf0e10cSrcweir else 12169cdf0e10cSrcweir { 12170cdf0e10cSrcweir OStringBuffer aBuf( rWidget.m_aOnValue.getLength()*2 ); 12171cdf0e10cSrcweir appendName( rWidget.m_aOnValue, aBuf ); 12172cdf0e10cSrcweir aStyle = aBuf.makeStringAndClear(); 12173cdf0e10cSrcweir } 12174cdf0e10cSrcweir } 12175cdf0e10cSrcweir break; 12176cdf0e10cSrcweir case PDFWriter::Edit: 12177cdf0e10cSrcweir aState = "N"; 12178cdf0e10cSrcweir aStyle = "Standard"; 12179cdf0e10cSrcweir break; 12180cdf0e10cSrcweir case PDFWriter::ListBox: 12181cdf0e10cSrcweir case PDFWriter::ComboBox: 12182cdf0e10cSrcweir case PDFWriter::Hierarchy: 12183cdf0e10cSrcweir break; 12184cdf0e10cSrcweir } 12185cdf0e10cSrcweir if( aState.getLength() && aStyle.getLength() ) 12186cdf0e10cSrcweir { 12187cdf0e10cSrcweir // delete eventual existing stream 12188cdf0e10cSrcweir PDFAppearanceStreams::iterator it = 12189cdf0e10cSrcweir rWidget.m_aAppearances[ aState ].find( aStyle ); 12190cdf0e10cSrcweir if( it != rWidget.m_aAppearances[ aState ].end() ) 12191cdf0e10cSrcweir delete it->second; 12192cdf0e10cSrcweir rWidget.m_aAppearances[ aState ][ aStyle ] = pAppearance; 12193cdf0e10cSrcweir bRet = true; 12194cdf0e10cSrcweir } 12195cdf0e10cSrcweir } 12196cdf0e10cSrcweir 12197cdf0e10cSrcweir if( ! bRet ) 12198cdf0e10cSrcweir delete pAppearance; 12199cdf0e10cSrcweir 12200cdf0e10cSrcweir m_nCurrentControl = -1; 12201cdf0e10cSrcweir 12202cdf0e10cSrcweir return bRet; 12203cdf0e10cSrcweir } 12204cdf0e10cSrcweir 12205cdf0e10cSrcweir void PDFWriterImpl::addStream( const String& rMimeType, PDFOutputStream* pStream, bool bCompress ) 12206cdf0e10cSrcweir { 12207cdf0e10cSrcweir if( pStream ) 12208cdf0e10cSrcweir { 12209cdf0e10cSrcweir m_aAdditionalStreams.push_back( PDFAddStream() ); 12210cdf0e10cSrcweir PDFAddStream& rStream = m_aAdditionalStreams.back(); 12211cdf0e10cSrcweir rStream.m_aMimeType = rMimeType.Len() 12212cdf0e10cSrcweir ? OUString( rMimeType ) 12213cdf0e10cSrcweir : OUString( RTL_CONSTASCII_USTRINGPARAM( "application/octet-stream" ) ); 12214cdf0e10cSrcweir rStream.m_pStream = pStream; 12215cdf0e10cSrcweir rStream.m_bCompress = bCompress; 12216cdf0e10cSrcweir } 12217cdf0e10cSrcweir } 12218cdf0e10cSrcweir 12219cdf0e10cSrcweir 12220cdf0e10cSrcweir 12221