xref: /AOO41X/main/filter/source/graphicfilter/eps/eps.cxx (revision e6f63103da479d1a7dee04420ba89525dac05278)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_filter.hxx"
26 
27 #include <vcl/sv.h>
28 #include <tools/stream.hxx>
29 #include <tools/bigint.hxx>
30 #include <tools/poly.hxx>
31 #include <vcl/svapp.hxx>
32 #include <vcl/metaact.hxx>
33 #include <vcl/graph.hxx>
34 #include <vcl/bmpacc.hxx>
35 #include <vcl/region.hxx>
36 #include <vcl/metric.hxx>
37 #include <vcl/font.hxx>
38 #include <vcl/virdev.hxx>
39 #include <vcl/msgbox.hxx>
40 #include <vcl/cvtgrf.hxx>
41 #include <vcl/gradient.hxx>
42 #include <svl/solar.hrc>
43 #include <svtools/fltcall.hxx>
44 #include <svtools/FilterConfigItem.hxx>
45 #include <vcl/graphictools.hxx>
46 #include "strings.hrc"
47 
48 #include <math.h>
49 
50 #define POSTSCRIPT_BOUNDINGSEARCH   0x1000  // we only try to get the BoundingBox
51                                             // in the first 4096 bytes
52 
53 #define EPS_PREVIEW_TIFF    1
54 #define EPS_PREVIEW_EPSI    2
55 
56 #define PS_LINESIZE         70      // maximum number of characters a line in the output
57 
58 #define PS_NONE             0       // formating mode: action which is inserted behind the output
59 #define PS_SPACE            1
60 #define PS_RET              2
61 #define PS_WRAP             4
62 
63 // -----------------------------Feld-Typen-------------------------------
64 
65 struct ChrSet
66 {
67     struct ChrSet * pSucc;
68     sal_uInt8 nSet;
69     String aName;
70     FontWeight eWeight;
71 };
72 
73 struct StackMember
74 {
75     struct      StackMember * pSucc;
76     Color       aGlobalCol;
77     sal_Bool        bLineCol;
78     Color       aLineCol;
79     sal_Bool        bFillCol;
80     Color       aFillCol;
81     Color       aTextCol;
82     sal_Bool        bTextFillCol;
83     Color       aTextFillCol;
84     Color       aBackgroundCol;
85     Font        aFont;
86     TextAlign   eTextAlign;
87 
88     double                      fLineWidth;
89     double                      fMiterLimit;
90     SvtGraphicStroke::CapType   eLineCap;
91     SvtGraphicStroke::JoinType  eJoinType;
92     SvtGraphicStroke::DashArray aDashArray;
93 };
94 
95 struct PSLZWCTreeNode
96 {
97 
98     PSLZWCTreeNode*     pBrother;       // naechster Knoten, der den selben Vater hat
99     PSLZWCTreeNode*     pFirstChild;    // erster Sohn
100     sal_uInt16              nCode;          // Der Code fuer den String von Pixelwerten, der sich ergibt, wenn
101     sal_uInt16              nValue;         // Der Pixelwert
102 };
103 
104 class PSWriter
105 {
106 private:
107     sal_Bool                mbStatus;
108     sal_uLong               mnLevelWarning;     // number of embedded eps files which was not exported
109     sal_uLong               mnLastPercent;      // Mit welcher Zahl pCallback zuletzt aufgerufen wurde.
110     sal_uInt32              mnLatestPush;       // offset auf streamposition, an der zuletzt gepusht wurde
111 
112     long                mnLevel;            // dialog options
113     sal_Bool            mbGrayScale;
114     sal_Bool            mbCompression;
115     sal_Int32           mnPreview;
116     sal_Int32           mnTextMode;
117 
118     SvStream*           mpPS;
119     const GDIMetaFile*  pMTF;
120     GDIMetaFile*        pAMTF;              // only created if Graphics is not a Metafile
121     VirtualDevice       aVDev;
122 
123     double              nBoundingX1;        // this represents the bounding box
124     double              nBoundingY1;
125     double              nBoundingX2;
126     double              nBoundingY2;
127                                             //
128     StackMember*        pGDIStack;
129     sal_uLong               mnCursorPos;        // aktuelle Cursorposition im Output
130     Color               aColor;             // aktuelle Farbe die fuer den Output benutzt wird
131     sal_Bool                bLineColor;
132     Color               aLineColor;         // aktuelle GDIMetafile Farbeinstellungen
133     sal_Bool                bFillColor;         //
134     Color               aFillColor;         //
135     Color               aTextColor;         //
136     sal_Bool                bTextFillColor;     //
137     Color               aTextFillColor;     //
138     Color               aBackgroundColor;   //
139     sal_Bool                bRegionChanged;
140     TextAlign           eTextAlign;         //
141 
142     double                      fLineWidth;
143     double                      fMiterLimit;
144     SvtGraphicStroke::CapType   eLineCap;
145     SvtGraphicStroke::JoinType  eJoinType;
146     SvtGraphicStroke::DashArray aDashArray;
147 
148     Font                maFont;
149     Font                maLastFont;
150     sal_uInt8               nChrSet;
151     ChrSet*             pChrSetList;        // Liste der Character-Sets
152     sal_uInt8               nNextChrSetId;      // die erste unbenutzte ChrSet-Id
153 
154     PSLZWCTreeNode*     pTable;             // LZW compression data
155     PSLZWCTreeNode*     pPrefix;            // the compression is as same as the TIFF compression
156     sal_uInt16              nDataSize;
157     sal_uInt16              nClearCode;
158     sal_uInt16              nEOICode;
159     sal_uInt16              nTableSize;
160     sal_uInt16              nCodeSize;
161     sal_uLong               nOffset;
162     sal_uLong               dwShift;
163 
164     com::sun::star::uno::Reference< com::sun::star::task::XStatusIndicator > xStatusIndicator;
165 
166     void                ImplWriteProlog( const Graphic* pPreviewEPSI = NULL );
167     void                ImplWriteEpilog();
168     void                ImplWriteActions( const GDIMetaFile& rMtf, VirtualDevice& rVDev );
169 
170                         // this method makes LF's, space inserting and word wrapping as used in all nMode
171                         // parameters
172     inline void         ImplExecMode( sal_uLong nMode );
173 
174                         // writes char[] + LF to stream
175     inline void         ImplWriteLine( const char*, sal_uLong nMode = PS_RET );
176 
177                         // writes ( nNumb / 10^nCount ) in ASCII format to stream
178     void                ImplWriteF( sal_Int32 nNumb, sal_uLong nCount = 3, sal_uLong nMode = PS_SPACE );
179 
180                         // writes a double in ASCII format to stream
181     void                ImplWriteDouble( double, sal_uLong nMode = PS_SPACE );
182 
183                         // writes a long in ASCII format to stream
184     void                ImplWriteLong( sal_Int32 nNumb, sal_uLong nMode = PS_SPACE );
185 
186                         // writes a byte in ASCII format to stream
187     void                ImplWriteByte( sal_uInt8 nNumb, sal_uLong nMode = PS_SPACE );
188 
189                         // writes a byte in ASCII (hex) format to stream
190     void                ImplWriteHexByte( sal_uInt8 nNumb, sal_uLong nMode = PS_WRAP );
191 
192                         // writes nNumb as number from 0.000 till 1.000 in ASCII format to stream
193     void                ImplWriteB1( sal_uInt8 nNumb, sal_uLong nMode = PS_SPACE );
194 
195     inline void         ImplWritePoint( const Point&, sal_uInt32 nMode = PS_SPACE );
196     void                ImplMoveTo( const Point&, sal_uInt32 nMode = PS_SPACE );
197     void                ImplLineTo( const Point&, sal_uInt32 nMode = PS_SPACE );
198     void                ImplCurveTo( const Point& rP1, const Point& rP2, const Point& rP3, sal_uInt32 nMode = PS_SPACE );
199     void                ImplTranslate( const double& fX, const double& fY, sal_uInt32 nMode = PS_RET );
200     void                ImplScale( const double& fX, const double& fY, sal_uInt32 nMode = PS_RET );
201 
202     void                ImplWriteLine( const Polygon & rPolygon );
203     void                ImplAddPath( const Polygon & rPolygon );
204     void                ImplWriteLineInfo( double fLineWidth, double fMiterLimit, SvtGraphicStroke::CapType eLineCap,
205                                     SvtGraphicStroke::JoinType eJoinType, SvtGraphicStroke::DashArray& rDashArray );
206     void                ImplWriteLineInfo( const LineInfo& rLineInfo );
207     void                ImplRect( const Rectangle & rRectangle );
208     void                ImplRectFill ( const Rectangle & rRectangle );
209     void                ImplWriteGradient( const PolyPolygon& rPolyPoly, const Gradient& rGradient, VirtualDevice& rVDev );
210     void                ImplIntersect( const PolyPolygon& rPolyPoly );
211     void                ImplPolyPoly( const PolyPolygon & rPolyPolygon, sal_Bool bTextOutline = sal_False );
212     void                ImplPolyLine( const Polygon & rPolygon );
213 
214     void                ImplSetClipRegion( Region& rRegion );
215     void                ImplBmp( Bitmap*, Bitmap*, const Point &, double nWidth, double nHeight );
216     void                ImplText( const String& rUniString, const Point& rPos, const sal_Int32* pDXArry, sal_Int32 nWidth, VirtualDevice& rVDev );
217     void                ImplSetAttrForText( const Point & rPoint );
218     void                ImplWriteCharacter( sal_Char );
219     void                ImplWriteString( const ByteString&, VirtualDevice& rVDev, const sal_Int32* pDXArry = NULL, sal_Bool bStretch = sal_False );
220     void                ImplDefineFont( const char*, const char* );
221 
222     void                ImplClosePathDraw( sal_uLong nMode = PS_RET );
223     void                ImplPathDraw();
224 
225     inline void         ImplWriteLineColor( sal_uLong nMode = PS_RET );
226     inline void         ImplWriteFillColor( sal_uLong nMode = PS_RET );
227     inline void         ImplWriteTextColor( sal_uLong nMode = PS_RET );
228     inline void         ImplWriteTextFillColor( sal_uLong nMode = PS_RET );
229     void                ImplWriteColor( sal_uLong nMode );
230 
231     double              ImplGetScaling( const MapMode& );
232     void                ImplGetMapMode( const MapMode& );
233     sal_Bool                ImplGetBoundingBox( double* nNumb, sal_uInt8* pSource, sal_uLong nSize );
234     sal_uInt8*              ImplSearchEntry( sal_uInt8* pSource, sal_uInt8* pDest, sal_uLong nComp, sal_uLong nSize );
235                         // LZW methods
236     void                StartCompression();
237     void                Compress( sal_uInt8 nSrc );
238     void                EndCompression();
239     inline void         WriteBits( sal_uInt16 nCode, sal_uInt16 nCodeLen );
240 
241 public:
242     sal_Bool                WritePS( const Graphic& rGraphic, SvStream& rTargetStream, FilterConfigItem* );
243     PSWriter();
244     ~PSWriter();
245 };
246 
247 //========================== Methoden von PSWriter ==========================
248 
249 //---------------------------------------------------------------------------------
250 
PSWriter()251 PSWriter::PSWriter()
252 {
253     pAMTF = NULL;
254 }
255 
256 
~PSWriter()257 PSWriter::~PSWriter()
258 {
259     delete pAMTF;
260 }
261 
262 //---------------------------------------------------------------------------------
263 
WritePS(const Graphic & rGraphic,SvStream & rTargetStream,FilterConfigItem * pFilterConfigItem)264 sal_Bool PSWriter::WritePS( const Graphic& rGraphic, SvStream& rTargetStream, FilterConfigItem* pFilterConfigItem )
265 {
266     sal_uInt32 nStreamPosition = 0, nPSPosition = 0; // -Wall warning, unset, check
267 
268     mbStatus = sal_True;
269     mnPreview = 0;
270     mnLevelWarning = 0;
271     mnLastPercent = 0;
272     mnLatestPush = 0xEFFFFFFE;
273 
274     if ( pFilterConfigItem )
275     {
276         xStatusIndicator = pFilterConfigItem->GetStatusIndicator();
277         if ( xStatusIndicator.is() )
278         {
279             rtl::OUString aMsg;
280             xStatusIndicator->start( aMsg, 100 );
281         }
282     }
283 
284     mpPS = &rTargetStream;
285     mpPS->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
286 
287     // default values for the dialog options
288     mnLevel = 2;
289     mbGrayScale = sal_False;
290     mbCompression = sal_True;
291     mnTextMode = 0;         // default0 : export glyph outlines
292 
293     // try to get the dialog selection
294     if ( pFilterConfigItem )
295     {
296         ByteString  aResMgrName( "eps" );
297         ResMgr*     pResMgr;
298 
299         pResMgr = ResMgr::CreateResMgr( aResMgrName.GetBuffer(), Application::GetSettings().GetUILocale() );
300 
301         if( pResMgr )
302         {
303             String aPreviewStr( RTL_CONSTASCII_USTRINGPARAM( "Preview" ) );
304             String aVersionStr( RTL_CONSTASCII_USTRINGPARAM( "Version" ) );
305             String aColorStr( RTL_CONSTASCII_USTRINGPARAM( "ColorFormat" ) );
306             String aComprStr( RTL_CONSTASCII_USTRINGPARAM( "CompressionMode" ) );
307             mnPreview = pFilterConfigItem->ReadInt32( aPreviewStr, 1 );
308             mnLevel = pFilterConfigItem->ReadInt32( aVersionStr, 2 );
309             if ( mnLevel != 1 )
310                 mnLevel = 2;
311             mbGrayScale = pFilterConfigItem->ReadInt32( aColorStr, 1 ) == 2;
312             mbCompression = pFilterConfigItem->ReadInt32( aComprStr, 1 ) == 1;
313             String sTextMode( RTL_CONSTASCII_USTRINGPARAM( "TextMode" ) );
314             mnTextMode = pFilterConfigItem->ReadInt32( sTextMode, 0 );
315             if ( mnTextMode > 2 )
316                 mnTextMode = 0;
317             delete pResMgr;
318         }
319     }
320 
321     // compression is not available for Level 1
322     if ( mnLevel == 1 )
323     {
324         mbGrayScale = sal_True;
325         mbCompression = sal_False;
326     }
327 
328     if ( mnPreview & EPS_PREVIEW_TIFF )
329     {
330         rTargetStream << (sal_uInt32)0xC6D3D0C5;
331         nStreamPosition = rTargetStream.Tell();
332         rTargetStream << (sal_uInt32)0 << (sal_uInt32)0 << (sal_uInt32)0 << (sal_uInt32)0
333             << nStreamPosition + 26 << (sal_uInt32)0 << (sal_uInt16)0xffff;
334 
335         sal_uInt32 nErrCode;
336         if ( mbGrayScale )
337         {
338             BitmapEx aTempBitmapEx( rGraphic.GetBitmapEx() );
339             aTempBitmapEx.Convert( BMP_CONVERSION_8BIT_GREYS );
340             nErrCode = GraphicConverter::Export( rTargetStream, aTempBitmapEx, CVT_TIF ) ;
341         }
342         else
343             nErrCode = GraphicConverter::Export( rTargetStream, rGraphic, CVT_TIF ) ;
344 
345         if ( nErrCode == ERRCODE_NONE )
346         {
347             rTargetStream.Seek( STREAM_SEEK_TO_END );
348             nPSPosition = rTargetStream.Tell();
349             rTargetStream.Seek( nStreamPosition + 20 );
350             rTargetStream << nPSPosition - 30;  // size of tiff gfx
351             rTargetStream.Seek( nPSPosition );
352         }
353         else
354         {
355             mnPreview &=~ EPS_PREVIEW_TIFF;
356             rTargetStream.Seek( nStreamPosition - 4 );
357         }
358     }
359 
360     // global default value setting
361     ChrSet*         pCS;
362     StackMember*    pGS;
363 
364     if ( rGraphic.GetType() == GRAPHIC_GDIMETAFILE )
365         pMTF = &rGraphic.GetGDIMetaFile();
366     else
367         pMTF = pAMTF = new GDIMetaFile( rGraphic.GetGDIMetaFile() );
368     aVDev.SetMapMode( pMTF->GetPrefMapMode() );
369     nBoundingX1 = nBoundingY1 = 0;
370     nBoundingX2 = pMTF->GetPrefSize().Width();
371     nBoundingY2 = pMTF->GetPrefSize().Height();
372 
373     pGDIStack = NULL;
374     aColor = Color( COL_TRANSPARENT );
375     bLineColor = sal_True;
376     aLineColor = Color( COL_BLACK );
377     bFillColor = sal_True;
378     aFillColor = Color( COL_WHITE );
379     bTextFillColor = sal_True;
380     aTextFillColor = Color( COL_BLACK );
381     fLineWidth = 1;
382     fMiterLimit = 15; // use same limit as most graphic systems and basegfx
383     eLineCap = SvtGraphicStroke::capButt;
384     eJoinType = SvtGraphicStroke::joinMiter;
385     aBackgroundColor = Color( COL_WHITE );
386     eTextAlign = ALIGN_BASELINE;
387     bRegionChanged = sal_False;
388 
389     nChrSet = 0x00;
390     pChrSetList = NULL;
391     nNextChrSetId = 1;
392 
393     if( pMTF->GetActionCount() )
394     {
395         ImplWriteProlog( ( mnPreview & EPS_PREVIEW_EPSI ) ? &rGraphic : NULL );
396         mnCursorPos = 0;
397         ImplWriteActions( *pMTF, aVDev );
398         ImplWriteEpilog();
399         if ( mnPreview & EPS_PREVIEW_TIFF )
400         {
401             sal_uInt32 nPosition = rTargetStream.Tell();
402             rTargetStream.Seek( nStreamPosition );
403             rTargetStream << nPSPosition;
404             rTargetStream << nPosition - nPSPosition;
405             rTargetStream.Seek( nPosition );
406         }
407         while( pChrSetList )
408         {
409             pCS=pChrSetList;
410             pChrSetList=pCS->pSucc;
411             delete pCS;
412         }
413         while( pGDIStack )
414         {
415             pGS=pGDIStack;
416             pGDIStack=pGS->pSucc;
417             delete pGS;
418         }
419     }
420     else
421         mbStatus = sal_False;
422 
423     if ( mbStatus && mnLevelWarning && pFilterConfigItem )
424     {
425         ByteString  aResMgrName( "eps" );
426         ResMgr* pResMgr;
427         pResMgr = ResMgr::CreateResMgr( aResMgrName.GetBuffer(), Application::GetSettings().GetUILocale() );
428         if( pResMgr )
429         {
430             InfoBox aInfoBox( NULL, String( ResId( KEY_VERSION_CHECK, *pResMgr ) ) );
431             aInfoBox.Execute();
432             delete pResMgr;
433         }
434     }
435 
436     if ( xStatusIndicator.is() )
437         xStatusIndicator->end();
438 
439     return mbStatus;
440 }
441 
442 //---------------------------------------------------------------------------------
443 
ImplWriteProlog(const Graphic * pPreview)444 void PSWriter::ImplWriteProlog( const Graphic* pPreview )
445 {
446     ImplWriteLine( "%!PS-Adobe-3.0 EPSF-3.0 " );
447     *mpPS << "%%BoundingBox: ";                         // BoundingBox
448     ImplWriteLong( 0 );
449     ImplWriteLong( 0 );
450     Size aSizePoint = Application::GetDefaultDevice()->LogicToLogic( pMTF->GetPrefSize(),
451                         pMTF->GetPrefMapMode(), MAP_POINT );
452     ImplWriteLong( aSizePoint.Width() );
453     ImplWriteLong( aSizePoint.Height() ,PS_RET );
454     ImplWriteLine( "%%Pages: 0" );
455     ImplWriteLine( "%%Creator: Sun Microsystems, Inc." );
456     ImplWriteLine( "%%Title: none" );
457     ImplWriteLine( "%%CreationDate: none" );
458 
459 // defaults
460 
461     *mpPS << "%%LanguageLevel: ";                       // Language level
462     ImplWriteLong( mnLevel, PS_RET );
463     if ( !mbGrayScale && mnLevel == 1 )
464         ImplWriteLine( "%%Extensions: CMYK" );          // CMYK extension is to set in color mode in level 1
465     ImplWriteLine( "%%EndComments" );
466     if ( pPreview && aSizePoint.Width() && aSizePoint.Height() )
467     {
468         Size aSizeBitmap( ( aSizePoint.Width() + 7 ) & ~7, aSizePoint.Height() );
469         Bitmap aTmpBitmap( pPreview->GetBitmap() );
470         aTmpBitmap.Scale( aSizeBitmap, BMP_SCALE_INTERPOLATE );
471         aTmpBitmap.Convert( BMP_CONVERSION_1BIT_THRESHOLD );
472         BitmapReadAccess* pAcc = aTmpBitmap.AcquireReadAccess();
473         if ( pAcc )
474         {
475             *mpPS << "%%BeginPreview: ";                    // BoundingBox
476             ImplWriteLong( aSizeBitmap.Width() );
477             ImplWriteLong( aSizeBitmap.Height() );
478             *mpPS << "1 ";
479             sal_Int32 nLines = aSizeBitmap.Width() / 312;
480             if ( ( nLines * 312 ) != aSizeBitmap.Width() )
481                 nLines++;
482             nLines *= aSizeBitmap.Height();
483             ImplWriteLong( nLines );
484             char  nVal;
485             sal_Int32 nX, nY, nCount2, nCount = 4;
486             const BitmapColor aBlack( pAcc->GetBestMatchingColor( Color( COL_BLACK ) ) );
487             for ( nY = 0; nY < aSizeBitmap.Height(); nY++ )
488             {
489                 nCount2 = 0;
490                 nVal = 0;
491                 for ( nX = 0; nX < aSizeBitmap.Width(); nX++ )
492                 {
493                     if ( !nCount2 )
494                     {
495                         ImplExecMode( PS_RET );
496                         *mpPS << "%";
497                         nCount2 = 312;
498                     }
499                     nVal <<= 1;
500                     if ( pAcc->GetPixel( nY, nX ) == aBlack )
501                         nVal |= 1;
502                     if ( ! ( --nCount ) )
503                     {
504                         if ( nVal > 9 )
505                             nVal += 'A' - 10;
506                         else
507                             nVal += '0';
508                         *mpPS << nVal;
509                         nVal = 0;
510                         nCount += 4;
511                     }
512                     nCount2--;
513                 }
514             }
515             aTmpBitmap.ReleaseAccess( pAcc );
516             ImplExecMode( PS_RET );
517             ImplWriteLine( "%%EndPreview" );
518         }
519     }
520     ImplWriteLine( "%%BeginProlog" );
521     ImplWriteLine( "%%BeginResource: procset SDRes-Prolog 1.0 0" );
522 
523 //  BEGIN EPSF
524     ImplWriteLine( "/b4_inc_state save def\n/dict_count countdictstack def\n/op_count count 1 sub def\nuserdict begin" );
525     ImplWriteLine( "0 setgray 0 setlinecap 1 setlinewidth 0 setlinejoin 10 setmiterlimit[] 0 setdash newpath" );
526     ImplWriteLine( "/languagelevel where {pop languagelevel 1 ne {false setstrokeadjust false setoverprint} if} if" );
527 
528     ImplWriteLine( "/bdef {bind def} bind def" );       // der neue operator bdef wird erzeugt
529     if ( mbGrayScale )
530         ImplWriteLine( "/c {setgray} bdef" );
531     else
532         ImplWriteLine( "/c {setrgbcolor} bdef" );
533     ImplWriteLine( "/l {neg lineto} bdef" );
534     ImplWriteLine( "/rl {neg rlineto} bdef" );
535     ImplWriteLine( "/lc {setlinecap} bdef" );
536     ImplWriteLine( "/lj {setlinejoin} bdef" );
537     ImplWriteLine( "/lw {setlinewidth} bdef" );
538     ImplWriteLine( "/ml {setmiterlimit} bdef" );
539     ImplWriteLine( "/ld {setdash} bdef" );
540     ImplWriteLine( "/m {neg moveto} bdef" );
541     ImplWriteLine( "/ct {6 2 roll neg 6 2 roll neg 6 2 roll neg curveto} bdef" );
542     ImplWriteLine( "/r {rotate} bdef" );
543     ImplWriteLine( "/t {neg translate} bdef" );
544     ImplWriteLine( "/s {scale} bdef" );
545     ImplWriteLine( "/sw {show} bdef" );
546     ImplWriteLine( "/gs {gsave} bdef" );
547     ImplWriteLine( "/gr {grestore} bdef" );
548 
549     ImplWriteLine( "/f {findfont dup length dict begin" );  // Setfont
550     ImplWriteLine( "{1 index /FID ne {def} {pop pop} ifelse} forall /Encoding ISOLatin1Encoding def" );
551     ImplWriteLine( "currentdict end /NFont exch definefont pop /NFont findfont} bdef" );
552 
553     ImplWriteLine( "/p {closepath} bdef" );
554     ImplWriteLine( "/sf {scalefont setfont} bdef" );
555 
556     ImplWriteLine( "/ef {eofill}bdef"           );      // close path and fill
557     ImplWriteLine( "/pc {closepath stroke}bdef" );      // close path and draw
558     ImplWriteLine( "/ps {stroke}bdef" );                // draw current path
559     ImplWriteLine( "/pum {matrix currentmatrix}bdef" ); // pushes the current matrix
560     ImplWriteLine( "/pom {setmatrix}bdef" );            // pops the matrix
561     ImplWriteLine( "/bs {/aString exch def /nXOfs exch def /nWidth exch def currentpoint nXOfs 0 rmoveto pum nWidth aString stringwidth pop div 1 scale aString show pom moveto} bdef" );
562     ImplWriteLine( "%%EndResource" );
563     ImplWriteLine( "%%EndProlog" );
564     ImplWriteLine( "%%BeginSetup" );
565     ImplWriteLine( "%%EndSetup" );
566     ImplWriteLine( "%%Page: 1 1" );
567     ImplWriteLine( "%%BeginPageSetup" );
568     ImplWriteLine( "%%EndPageSetup" );
569     ImplWriteLine( "pum" );
570     ImplScale( (double)aSizePoint.Width() / (double)pMTF->GetPrefSize().Width(), (double)aSizePoint.Height() / (double)pMTF->GetPrefSize().Height() );
571     ImplWriteDouble( 0 );
572     ImplWriteDouble( -pMTF->GetPrefSize().Height() );
573     ImplWriteLine( "t" );
574     ImplWriteLine( "/tm matrix currentmatrix def" );
575 }
576 
577 //---------------------------------------------------------------------------------
578 
ImplWriteEpilog()579 void PSWriter::ImplWriteEpilog()
580 {
581     ImplTranslate( 0, nBoundingY2 );
582     ImplWriteLine( "pom" );
583     ImplWriteLine( "count op_count sub {pop} repeat countdictstack dict_count sub {end} repeat b4_inc_state restore" );
584 
585     ImplWriteLine( "%%PageTrailer" );
586     ImplWriteLine( "%%Trailer" );
587 
588     ImplWriteLine( "%%EOF" );
589 }
590 
591 //---------------------------------------------------------------------------------
592 //---------------------------------------------------------------------------------
593 //---------------------------------------------------------------------------------
594 
ImplWriteActions(const GDIMetaFile & rMtf,VirtualDevice & rVDev)595 void PSWriter::ImplWriteActions( const GDIMetaFile& rMtf, VirtualDevice& rVDev )
596 {
597     PolyPolygon aFillPath;
598 
599     for( sal_uLong nCurAction = 0, nCount = rMtf.GetActionCount(); nCurAction < nCount; nCurAction++ )
600     {
601         MetaAction* pMA = rMtf.GetAction( nCurAction );
602 
603         switch( pMA->GetType() )
604         {
605             case META_NULL_ACTION :
606             break;
607 
608             case META_PIXEL_ACTION :
609             {
610                 Color aOldLineColor( aLineColor );
611                 aLineColor = ( (const MetaPixelAction*) pMA )->GetColor();
612                 ImplWriteLineColor( PS_SPACE );
613                 ImplMoveTo( ( (const MetaPixelAction*)pMA )->GetPoint() );
614                 ImplLineTo( ( (const MetaPixelAction*)pMA )->GetPoint() );
615                 ImplPathDraw();
616                 aLineColor = aOldLineColor;
617             }
618             break;
619 
620             case META_POINT_ACTION :
621             {
622                 ImplWriteLineColor( PS_SPACE );
623                 ImplMoveTo( ( (const MetaPointAction*)pMA )->GetPoint() );
624                 ImplLineTo( ( (const MetaPointAction*)pMA )->GetPoint() );
625                 ImplPathDraw();
626             }
627             break;
628 
629             case META_LINE_ACTION :
630             {
631                 const LineInfo& rLineInfo = ( ( const MetaLineAction*)pMA )->GetLineInfo();
632                 ImplWriteLineInfo( rLineInfo );
633                 if ( bLineColor )
634                 {
635                     ImplWriteLineColor( PS_SPACE );
636                     ImplMoveTo( ( (const MetaLineAction*) pMA )->GetStartPoint() );
637                     ImplLineTo( ( (const MetaLineAction*) pMA )->GetEndPoint() );
638                     ImplPathDraw();
639                 }
640             }
641             break;
642 
643             case META_RECT_ACTION :
644             {
645                 ImplRect( ( (const MetaRectAction*) pMA )->GetRect() );
646             }
647             break;
648 
649             case META_ROUNDRECT_ACTION :
650                 ImplRect( ( (const MetaRoundRectAction*) pMA )->GetRect() );
651             break;
652 
653             case META_ELLIPSE_ACTION :
654             {
655                 Rectangle   aRect = ( ( (const MetaEllipseAction*) pMA )->GetRect() );
656                 Point       aCenter = aRect.Center();
657                 Polygon     aPoly( aCenter, aRect.GetWidth() / 2, aRect.GetHeight() / 2 );
658                 PolyPolygon aPolyPoly( aPoly );
659                 ImplPolyPoly( aPolyPoly );
660             }
661             break;
662 
663             case META_ARC_ACTION :
664             {
665                 Polygon aPoly( ( (const MetaArcAction*)pMA )->GetRect(), ( (const MetaArcAction*)pMA )->GetStartPoint(),
666                     ( (const MetaArcAction*)pMA )->GetEndPoint(), POLY_ARC );
667                 PolyPolygon aPolyPoly( aPoly );
668                 ImplPolyPoly( aPolyPoly );
669             }
670             break;
671 
672             case META_PIE_ACTION :
673             {
674                 Polygon aPoly( ( (const MetaPieAction*)pMA )->GetRect(), ( (const MetaPieAction*)pMA )->GetStartPoint(),
675                     ( (const MetaPieAction*)pMA )->GetEndPoint(), POLY_PIE );
676                 PolyPolygon aPolyPoly( aPoly );
677                 ImplPolyPoly( aPolyPoly );
678             }
679             break;
680 
681             case META_CHORD_ACTION :
682             {
683                 Polygon aPoly( ( (const MetaChordAction*)pMA )->GetRect(), ( (const MetaChordAction*)pMA )->GetStartPoint(),
684                     ( (const MetaChordAction*)pMA )->GetEndPoint(), POLY_CHORD );
685                 PolyPolygon aPolyPoly( aPoly );
686                 ImplPolyPoly( aPolyPoly );
687             }
688             break;
689 
690             case META_POLYLINE_ACTION :
691             {
692                 Polygon aPoly( ( (const MetaPolyLineAction*) pMA )->GetPolygon() );
693                 const LineInfo& rLineInfo = ( ( const MetaPolyLineAction*)pMA )->GetLineInfo();
694                 ImplWriteLineInfo( rLineInfo );
695 
696                 if(basegfx::B2DLINEJOIN_NONE == rLineInfo.GetLineJoin()
697                     && rLineInfo.GetWidth() > 1)
698                 {
699                     // emulate B2DLINEJOIN_NONE by creating single edges
700                     const sal_uInt16 nPoints(aPoly.GetSize());
701                     const bool bCurve(aPoly.HasFlags());
702 
703                     for(sal_uInt16 a(0); a + 1 < nPoints; a++)
704                     {
705                         if(bCurve
706                             && POLY_NORMAL != aPoly.GetFlags(a + 1)
707                             && a + 2 < nPoints
708                             && POLY_NORMAL != aPoly.GetFlags(a + 2)
709                             && a + 3 < nPoints)
710                         {
711                             const Polygon aSnippet(4,
712                                 aPoly.GetConstPointAry() + a,
713                                 aPoly.GetConstFlagAry() + a);
714                             ImplPolyLine(aSnippet);
715                             a += 2;
716                         }
717                         else
718                         {
719                             const Polygon aSnippet(2,
720                                 aPoly.GetConstPointAry() + a);
721                             ImplPolyLine(aSnippet);
722                         }
723                     }
724                 }
725                 else
726                 {
727                     ImplPolyLine( aPoly );
728                 }
729             }
730             break;
731 
732             case META_POLYGON_ACTION :
733             {
734                 PolyPolygon aPolyPoly( ( (const MetaPolygonAction*) pMA )->GetPolygon() );
735                 ImplPolyPoly( aPolyPoly );
736             }
737             break;
738 
739             case META_POLYPOLYGON_ACTION :
740             {
741                 ImplPolyPoly( ( (const MetaPolyPolygonAction*) pMA )->GetPolyPolygon() );
742             }
743             break;
744 
745             case META_TEXT_ACTION:
746             {
747                 const MetaTextAction * pA = (const MetaTextAction*) pMA;
748 
749                 String  aUniStr( pA->GetText(), pA->GetIndex(), pA->GetLen() );
750                 Point   aPoint( pA->GetPoint() );
751 
752                 ImplText( aUniStr, aPoint, NULL, 0, rVDev );
753             }
754             break;
755 
756             case META_TEXTRECT_ACTION:
757             {
758                 DBG_ERROR( "Unsupported action: TextRect...Action!" );
759             }
760             break;
761 
762             case META_STRETCHTEXT_ACTION :
763             {
764                 const MetaStretchTextAction* pA = (const MetaStretchTextAction*)pMA;
765                 String  aUniStr( pA->GetText(), pA->GetIndex(), pA->GetLen() );
766                 Point   aPoint( pA->GetPoint() );
767 
768                 ImplText( aUniStr, aPoint, NULL, pA->GetWidth(), rVDev );
769             }
770             break;
771 
772             case META_TEXTARRAY_ACTION:
773             {
774                 const MetaTextArrayAction* pA = (const MetaTextArrayAction*)pMA;
775                 String  aUniStr( pA->GetText(), pA->GetIndex(), pA->GetLen() );
776                 Point   aPoint( pA->GetPoint() );
777 
778                 ImplText( aUniStr, aPoint, pA->GetDXArray(), 0, rVDev );
779             }
780             break;
781 
782             case META_BMP_ACTION :
783             {
784                 Bitmap aBitmap = ( (const MetaBmpAction*)pMA )->GetBitmap();
785                 if ( mbGrayScale )
786                     aBitmap.Convert( BMP_CONVERSION_8BIT_GREYS );
787                 Point aPoint = ( (const MetaBmpAction*) pMA )->GetPoint();
788                 Size aSize( rVDev.PixelToLogic( aBitmap.GetSizePixel() ) );
789                 ImplBmp( &aBitmap, NULL, aPoint, aSize.Width(), aSize.Height() );
790             }
791             break;
792 
793             case META_BMPSCALE_ACTION :
794             {
795                 Bitmap aBitmap = ( (const MetaBmpScaleAction*)pMA )->GetBitmap();
796                 if ( mbGrayScale )
797                     aBitmap.Convert( BMP_CONVERSION_8BIT_GREYS );
798                 Point aPoint = ( (const MetaBmpScaleAction*) pMA )->GetPoint();
799                 Size aSize = ( (const MetaBmpScaleAction*)pMA )->GetSize();
800                 ImplBmp( &aBitmap, NULL, aPoint, aSize.Width(), aSize.Height() );
801             }
802             break;
803 
804             case META_BMPSCALEPART_ACTION :
805             {
806                 Bitmap  aBitmap( ( (const MetaBmpScalePartAction*)pMA )->GetBitmap() );
807                 aBitmap.Crop( Rectangle( ( (const MetaBmpScalePartAction*)pMA )->GetSrcPoint(),
808                     ( (const MetaBmpScalePartAction*)pMA )->GetSrcSize() ) );
809                 if ( mbGrayScale )
810                     aBitmap.Convert( BMP_CONVERSION_8BIT_GREYS );
811                 Point aPoint = ( (const MetaBmpScalePartAction*) pMA)->GetDestPoint();
812                 Size aSize = ( (const MetaBmpScalePartAction*)pMA )->GetDestSize();
813                 ImplBmp( &aBitmap, NULL, aPoint, aSize.Width(), aSize.Height() );
814             }
815             break;
816 
817             case META_BMPEX_ACTION :
818             {
819                 BitmapEx aBitmapEx( ( (MetaBmpExAction*)pMA)->GetBitmapEx() );
820                 Bitmap aBitmap( aBitmapEx.GetBitmap() );
821                 if ( mbGrayScale )
822                     aBitmap.Convert( BMP_CONVERSION_8BIT_GREYS );
823                 Bitmap aMask( aBitmapEx.GetMask() );
824                 Point aPoint( ( (const MetaBmpExAction*) pMA )->GetPoint() );
825                 Size aSize( rVDev.PixelToLogic( aBitmap.GetSizePixel() ) );
826                 ImplBmp( &aBitmap, &aMask, aPoint, aSize.Width(), aSize.Height() );
827             }
828             break;
829 
830             case META_BMPEXSCALE_ACTION :
831             {
832                 BitmapEx aBitmapEx( ( (MetaBmpExScaleAction*)pMA)->GetBitmapEx() );
833                 Bitmap aBitmap( aBitmapEx.GetBitmap() );
834                 if ( mbGrayScale )
835                     aBitmap.Convert( BMP_CONVERSION_8BIT_GREYS );
836                 Bitmap aMask( aBitmapEx.GetMask() );
837                 Point aPoint = ( (const MetaBmpExScaleAction*) pMA)->GetPoint();
838                 Size aSize( ( (const MetaBmpExScaleAction*)pMA )->GetSize() );
839                 ImplBmp( &aBitmap, &aMask, aPoint, aSize.Width(), aSize.Height() );
840             }
841             break;
842 
843             case META_BMPEXSCALEPART_ACTION :
844             {
845                 BitmapEx    aBitmapEx( ( (const MetaBmpExScalePartAction*)pMA )->GetBitmapEx() );
846                 aBitmapEx.Crop( Rectangle( ( (const MetaBmpExScalePartAction*)pMA )->GetSrcPoint(),
847                     ( (const MetaBmpExScalePartAction*)pMA )->GetSrcSize() ) );
848                 Bitmap      aBitmap( aBitmapEx.GetBitmap() );
849                 if ( mbGrayScale )
850                     aBitmap.Convert( BMP_CONVERSION_8BIT_GREYS );
851                 Bitmap      aMask( aBitmapEx.GetMask() );
852                 Point aPoint = ( (const MetaBmpExScalePartAction*) pMA)->GetDestPoint();
853                 Size aSize = ( (const MetaBmpExScalePartAction*)pMA )->GetDestSize();
854                 ImplBmp( &aBitmap, &aMask, aPoint, aSize.Width(), aSize.Height() );
855             }
856             break;
857 
858             // Unsupported Actions
859             case META_MASK_ACTION:
860             case META_MASKSCALE_ACTION:
861             case META_MASKSCALEPART_ACTION:
862             {
863                 DBG_ERROR( "Unsupported action: MetaMask...Action!" );
864             }
865             break;
866 
867             case META_GRADIENT_ACTION :
868             {
869                 PolyPolygon aPolyPoly( ( (const MetaGradientAction*)pMA)->GetRect() );
870                 ImplWriteGradient( aPolyPoly, ( (const MetaGradientAction*) pMA )->GetGradient(), rVDev );
871             }
872             break;
873 
874             case META_GRADIENTEX_ACTION :
875             {
876                 PolyPolygon aPolyPoly( ( (const MetaGradientExAction*)pMA)->GetPolyPolygon() );
877                 ImplWriteGradient( aPolyPoly, ( (const MetaGradientExAction*) pMA )->GetGradient(), rVDev );
878             }
879             break;
880 
881             case META_HATCH_ACTION :
882             {
883                 VirtualDevice   l_aVDev;
884                 GDIMetaFile     aTmpMtf;
885 
886                 l_aVDev.SetMapMode( rVDev.GetMapMode() );
887                 l_aVDev.AddHatchActions( ( (const MetaHatchAction*)pMA)->GetPolyPolygon(),
888                                          ( (const MetaHatchAction*)pMA )->GetHatch(), aTmpMtf );
889                 ImplWriteActions( aTmpMtf, rVDev );
890             }
891             break;
892 
893             case META_WALLPAPER_ACTION :
894             {
895                 const MetaWallpaperAction* pA = (const MetaWallpaperAction*)pMA;
896                 Rectangle   aRect = pA->GetRect();
897                 Wallpaper   aWallpaper = pA->GetWallpaper();
898 
899                 if ( aWallpaper.IsBitmap() )
900                 {
901                     BitmapEx aBitmapEx = aWallpaper.GetBitmap();
902                     Bitmap aBitmap( aBitmapEx.GetBitmap() );
903                     if ( aBitmapEx.IsTransparent() )
904                     {
905                         if ( aWallpaper.IsGradient() )
906                         {
907 
908                         // gradient action
909 
910                         }
911                         Bitmap aMask( aBitmapEx.GetMask() );
912                         ImplBmp( &aBitmap, &aMask, Point( aRect.Left(), aRect.Top() ), aRect.GetWidth(), aRect.GetHeight() );
913                     }
914                     else
915                         ImplBmp( &aBitmap, NULL, Point( aRect.Left(), aRect.Top() ), aRect.GetWidth(), aRect.GetHeight() );
916 
917                         // wallpaper Style
918 
919                 }
920                 else if ( aWallpaper.IsGradient() )
921                 {
922 
923                 // gradient action
924 
925                 }
926                 else
927                 {
928                     aColor = aWallpaper.GetColor();
929                     ImplRectFill( aRect );
930                 }
931             }
932             break;
933 
934             case META_ISECTRECTCLIPREGION_ACTION:
935             {
936                 const MetaISectRectClipRegionAction* pA = (const MetaISectRectClipRegionAction*) pMA;
937                 Region aRegion( pA->GetRect() );
938                 ImplSetClipRegion( aRegion );
939             }
940             break;
941 
942             case META_CLIPREGION_ACTION:
943             {
944                 const MetaClipRegionAction* pA = (const MetaClipRegionAction*) pMA;
945                 Region aRegion( pA->GetRegion() );
946                 ImplSetClipRegion( aRegion );
947             }
948             break;
949 
950             case META_ISECTREGIONCLIPREGION_ACTION:
951             {
952                 const MetaISectRegionClipRegionAction* pA = (const MetaISectRegionClipRegionAction*) pMA;
953                 Region aRegion( pA->GetRegion() );
954                 ImplSetClipRegion( aRegion );
955             }
956             break;
957 
958             case META_MOVECLIPREGION_ACTION:
959             {
960 /*
961                 if ( !aClipRegion.IsEmpty() )
962                 {
963                     const MetaMoveClipRegionAction* pA = (const MetaMoveClipRegionAction*) pMA;
964                     aClipRegion.Move( pA->GetHorzMove(), pA->GetVertMove() );
965                     ImplSetClipRegion();
966                 }
967 */
968             }
969             break;
970 
971             case META_LINECOLOR_ACTION :
972             {
973                 if ( ( (const MetaLineColorAction*) pMA)->IsSetting() )
974                 {
975                     bLineColor = sal_True;
976                     aLineColor = ( (const MetaLineColorAction*) pMA )->GetColor();
977                 }
978                 else
979                     bLineColor = sal_False;
980             }
981             break;
982 
983             case META_FILLCOLOR_ACTION :
984             {
985                 if ( ( (const MetaFillColorAction*) pMA )->IsSetting() )
986                 {
987                     bFillColor = sal_True;
988                     aFillColor =  ( (const MetaFillColorAction*) pMA )->GetColor();
989                 }
990                 else
991                     bFillColor = sal_False;
992             }
993             break;
994 
995             case META_TEXTCOLOR_ACTION :
996             {
997                 aTextColor = ( (const MetaTextColorAction*) pMA )->GetColor();
998             }
999             break;
1000 
1001             case META_TEXTFILLCOLOR_ACTION :
1002             {
1003                 if ( ( (const MetaTextFillColorAction*) pMA )->IsSetting() )
1004                 {
1005                     bTextFillColor = sal_True;
1006                     aTextFillColor = ( (const MetaTextFillColorAction*) pMA )->GetColor();
1007                 }
1008                 else
1009                     bTextFillColor = sal_False;
1010             }
1011             break;
1012 
1013             case META_TEXTALIGN_ACTION :
1014             {
1015                 eTextAlign = ( (const MetaTextAlignAction*) pMA )->GetTextAlign();
1016             }
1017             break;
1018 
1019             case META_MAPMODE_ACTION :
1020             {
1021                 pMA->Execute( &rVDev );
1022                 ImplGetMapMode( rVDev.GetMapMode() );
1023             }
1024             break;
1025 
1026             case META_FONT_ACTION :
1027             {
1028                 maFont = ((const MetaFontAction*)pMA)->GetFont();
1029                 rVDev.SetFont( maFont );
1030             }
1031             break;
1032 
1033             case META_PUSH_ACTION :
1034             {
1035                 rVDev.Push(((const MetaPushAction*)pMA)->GetFlags() );
1036                 StackMember* pGS = new StackMember;
1037                 pGS->pSucc = pGDIStack;
1038                 pGDIStack = pGS;
1039                 pGS->aDashArray = aDashArray;
1040                 pGS->eJoinType = eJoinType;
1041                 pGS->eLineCap = eLineCap;
1042                 pGS->fLineWidth = fLineWidth;
1043                 pGS->fMiterLimit = fMiterLimit;
1044                 pGS->eTextAlign = eTextAlign;
1045                 pGS->aGlobalCol = aColor;
1046                 pGS->bLineCol = bLineColor;
1047                 pGS->aLineCol = aLineColor;
1048                 pGS->bFillCol = bFillColor;
1049                 pGS->aFillCol = aFillColor;
1050                 pGS->aTextCol = aTextColor;
1051                 pGS->bTextFillCol = bTextFillColor;
1052                 pGS->aTextFillCol = aTextFillColor;
1053                 pGS->aBackgroundCol = aBackgroundColor;
1054                 bRegionChanged = sal_False;
1055                 pGS->aFont = maFont;
1056                 mnLatestPush = mpPS->Tell();
1057                 ImplWriteLine( "gs" );
1058             }
1059             break;
1060 
1061             case META_POP_ACTION :
1062             {
1063                 rVDev.Pop();
1064                 StackMember* pGS;
1065                 if( pGDIStack )
1066                 {
1067                     pGS = pGDIStack;
1068                     pGDIStack = pGS->pSucc;
1069                     aDashArray = pGS->aDashArray;
1070                     eJoinType = pGS->eJoinType;
1071                     eLineCap = pGS->eLineCap;
1072                     fLineWidth = pGS->fLineWidth;
1073                     fMiterLimit = pGS->fMiterLimit;
1074                     eTextAlign = pGS->eTextAlign;
1075                     aColor = pGS->aGlobalCol;
1076                     bLineColor = pGS->bLineCol;
1077                     aLineColor = pGS->aLineCol;
1078                     bFillColor = pGS->bFillCol;
1079                     aFillColor = pGS->aFillCol;
1080                     aTextColor = pGS->aTextCol;
1081                     bTextFillColor = pGS->bTextFillCol;
1082                     aTextFillColor = pGS->aTextFillCol;
1083                     aBackgroundColor = pGS->aBackgroundCol;
1084                     maFont = pGS->aFont;
1085                     maLastFont = Font();                // set maLastFont != maFont -> so that
1086                     delete pGS;
1087                     sal_uInt32 nCurrentPos = mpPS->Tell();
1088                     if ( nCurrentPos - 3 == mnLatestPush )
1089                     {
1090                         mpPS->Seek( mnLatestPush );
1091                         ImplWriteLine( "  " );
1092                         mpPS->Seek( mnLatestPush );
1093                     }
1094                     else
1095                         ImplWriteLine( "gr" );
1096                 }
1097             }
1098             break;
1099 
1100             case META_EPS_ACTION :
1101             {
1102                 GfxLink aGfxLink = ( (const MetaEPSAction*) pMA )->GetLink();
1103                 const GDIMetaFile aSubstitute( ( ( const MetaEPSAction*) pMA )->GetSubstitute() );
1104 
1105                 sal_Bool    bLevelConflict = sal_False;
1106                 sal_uInt8*  pSource = (sal_uInt8*) aGfxLink.GetData();
1107                 sal_uLong   nSize = aGfxLink.GetDataSize();
1108                 sal_uLong   nParseThis = POSTSCRIPT_BOUNDINGSEARCH;
1109                 if ( nSize < 64 )                       // assuming eps is larger than 64 bytes
1110                     pSource = NULL;
1111                 if ( nParseThis > nSize )
1112                     nParseThis = nSize;
1113 
1114                 if ( pSource && ( mnLevel == 1 ) )
1115                 {
1116                     sal_uInt8* pFound = ImplSearchEntry( pSource, (sal_uInt8*)"%%LanguageLevel:", nParseThis - 10, 16 );
1117                     if ( pFound )
1118                     {
1119                         sal_uInt8   k, i = 10;
1120                         pFound += 16;
1121                         while ( --i )
1122                         {
1123                             k = *pFound++;
1124                             if ( ( k > '0' ) && ( k <= '9' ) )
1125                             {
1126                                 if ( k != '1' )
1127                                 {
1128                                     bLevelConflict = sal_True;
1129                                     mnLevelWarning++;
1130                                 }
1131                                 break;
1132                             }
1133                         }
1134                     }
1135                 }
1136                 if ( !bLevelConflict )
1137                 {
1138                     double  nBoundingBox[4];
1139                     if ( pSource && ImplGetBoundingBox( nBoundingBox, pSource, nParseThis ) )
1140                     {
1141                         Point   aPoint = ( (const MetaEPSAction*) pMA )->GetPoint();
1142                         Size    aSize = ( (const MetaEPSAction*) pMA )->GetSize();
1143 
1144                         MapMode aMapMode( aSubstitute.GetPrefMapMode() );
1145                         Size aOutSize( rVDev.LogicToLogic( aSize, rVDev.GetMapMode(), aMapMode ) );
1146                         Point aOrigin( rVDev.LogicToLogic( aPoint, rVDev.GetMapMode(), aMapMode ) );
1147                         aOrigin.Y() += aOutSize.Height();
1148                         aMapMode.SetOrigin( aOrigin );
1149                         aMapMode.SetScaleX( aOutSize.Width() / ( nBoundingBox[ 2 ] - nBoundingBox[ 0 ] ) );
1150                         aMapMode.SetScaleY( aOutSize.Height() / ( nBoundingBox[ 3 ] - nBoundingBox[ 1 ] ) );
1151                         ImplWriteLine( "gs" );
1152                         ImplGetMapMode( aMapMode );
1153                         ImplWriteLine( "%%BeginDocument:" );
1154                         mpPS->Write( pSource, aGfxLink.GetDataSize() );
1155                         ImplWriteLine( "%%EndDocument\ngr" );
1156                     }
1157                 }
1158             }
1159             break;
1160 
1161             case META_TRANSPARENT_ACTION:
1162             {
1163 //              ImplLine( ( (const MetaTransparentAction*) pMA )->GetPolyPolygon() );
1164             }
1165             break;
1166 
1167             case META_RASTEROP_ACTION:
1168             {
1169                 pMA->Execute( &rVDev );
1170             }
1171             break;
1172 
1173             case META_FLOATTRANSPARENT_ACTION:
1174             {
1175                 const MetaFloatTransparentAction* pA = (const MetaFloatTransparentAction*) pMA;
1176 
1177                 GDIMetaFile     aTmpMtf( pA->GetGDIMetaFile() );
1178                 Point           aSrcPt( aTmpMtf.GetPrefMapMode().GetOrigin() );
1179                 const Size      aSrcSize( aTmpMtf.GetPrefSize() );
1180                 const Point     aDestPt( pA->GetPoint() );
1181                 const Size      aDestSize( pA->GetSize() );
1182                 const double    fScaleX = aSrcSize.Width() ? (double) aDestSize.Width() / aSrcSize.Width() : 1.0;
1183                 const double    fScaleY = aSrcSize.Height() ? (double) aDestSize.Height() / aSrcSize.Height() : 1.0;
1184                 long            nMoveX, nMoveY;
1185 
1186                 if( fScaleX != 1.0 || fScaleY != 1.0 )
1187                 {
1188                     aTmpMtf.Scale( fScaleX, fScaleY );
1189                     aSrcPt.X() = FRound( aSrcPt.X() * fScaleX ), aSrcPt.Y() = FRound( aSrcPt.Y() * fScaleY );
1190                 }
1191 
1192                 nMoveX = aDestPt.X() - aSrcPt.X(), nMoveY = aDestPt.Y() - aSrcPt.Y();
1193 
1194                 if( nMoveX || nMoveY )
1195                     aTmpMtf.Move( nMoveX, nMoveY );
1196 
1197                 ImplWriteActions( aTmpMtf, rVDev );
1198             }
1199             break;
1200 
1201             case META_COMMENT_ACTION:
1202             {
1203                 const MetaCommentAction* pA = (const MetaCommentAction*) pMA;
1204                 if ( pA->GetComment().CompareIgnoreCaseToAscii( "XGRAD_SEQ_BEGIN" ) == COMPARE_EQUAL )
1205                 {
1206                     const MetaGradientExAction* pGradAction = NULL;
1207                     while( ++nCurAction < nCount )
1208                     {
1209                         MetaAction* pAction = rMtf.GetAction( nCurAction );
1210                         if( pAction->GetType() == META_GRADIENTEX_ACTION )
1211                             pGradAction = (const MetaGradientExAction*) pAction;
1212                         else if( ( pAction->GetType() == META_COMMENT_ACTION ) &&
1213                                  ( ( (const MetaCommentAction*) pAction )->GetComment().CompareIgnoreCaseToAscii( "XGRAD_SEQ_END" ) == COMPARE_EQUAL ) )
1214                         {
1215                             break;
1216                         }
1217                     }
1218                     if( pGradAction )
1219                         ImplWriteGradient( pGradAction->GetPolyPolygon(), pGradAction->GetGradient(), rVDev );
1220                 }
1221                 else if ( pA->GetComment().Equals( "XPATHFILL_SEQ_END" ) )
1222                 {
1223                     if ( aFillPath.Count() )
1224                     {
1225                         aFillPath = PolyPolygon();
1226                         ImplWriteLine( "gr" );
1227                     }
1228                 }
1229                 else
1230                 {
1231                     const sal_uInt8* pData = pA->GetData();
1232                     if ( pData )
1233                     {
1234                         SvMemoryStream  aMemStm( (void*)pData, pA->GetDataSize(), STREAM_READ );
1235                         sal_Bool        bSkipSequence = sal_False;
1236                         ByteString      sSeqEnd;
1237 
1238                         if( pA->GetComment().Equals( "XPATHSTROKE_SEQ_BEGIN" ) )
1239                         {
1240                             sSeqEnd = ByteString( "XPATHSTROKE_SEQ_END" );
1241                             SvtGraphicStroke aStroke;
1242                             aMemStm >> aStroke;
1243 
1244                             Polygon aPath;
1245                             aStroke.getPath( aPath );
1246 
1247                             PolyPolygon aStartArrow;
1248                             PolyPolygon aEndArrow;
1249 //                          double fTransparency( aStroke.getTransparency() );
1250                             double fStrokeWidth( aStroke.getStrokeWidth() );
1251                             SvtGraphicStroke::JoinType eJT( aStroke.getJoinType() );
1252                             SvtGraphicStroke::DashArray l_aDashArray;
1253 
1254                             aStroke.getStartArrow( aStartArrow );
1255                             aStroke.getEndArrow( aEndArrow );
1256                             aStroke.getDashArray( l_aDashArray );
1257 
1258                             bSkipSequence = sal_True;
1259                             if ( l_aDashArray.size() > 11 ) // ps dasharray limit is 11
1260                                 bSkipSequence = sal_False;
1261                             if ( aStartArrow.Count() || aEndArrow.Count() )
1262                                 bSkipSequence = sal_False;
1263                             if ( (sal_uInt32)eJT > 2 )
1264                                 bSkipSequence = sal_False;
1265                             if ( l_aDashArray.size() && ( fStrokeWidth != 0.0 ) )
1266                                 bSkipSequence = sal_False;
1267                             if ( bSkipSequence )
1268                             {
1269                                 ImplWriteLineInfo( fStrokeWidth, aStroke.getMiterLimit(),
1270                                                     aStroke.getCapType(), eJT, l_aDashArray );
1271                                 ImplPolyLine( aPath );
1272                             }
1273                         }
1274                         else if( pA->GetComment().Equals( "XPATHFILL_SEQ_BEGIN" ) )
1275                         {
1276                             sSeqEnd = ByteString( "XPATHFILL_SEQ_END" );
1277                             SvtGraphicFill aFill;
1278                             aMemStm >> aFill;
1279                             switch( aFill.getFillType() )
1280                             {
1281                                 case SvtGraphicFill::fillSolid :
1282                                 {
1283                                     bSkipSequence = sal_True;
1284                                     PolyPolygon aPolyPoly;
1285                                     aFill.getPath( aPolyPoly );
1286                                     sal_uInt16 i, nPolyCount = aPolyPoly.Count();
1287                                     if ( nPolyCount )
1288                                     {
1289                                         aFillColor = aFill.getFillColor();
1290                                         ImplWriteFillColor( PS_SPACE );
1291                                         for ( i = 0; i < nPolyCount; )
1292                                         {
1293                                             ImplAddPath( aPolyPoly.GetObject( i ) );
1294                                             if ( ++i < nPolyCount )
1295                                             {
1296                                                 *mpPS << "p";
1297                                                 mnCursorPos += 2;
1298                                                 ImplExecMode( PS_RET );
1299                                             }
1300                                         }
1301                                         *mpPS << "p ef";
1302                                         mnCursorPos += 4;
1303                                         ImplExecMode( PS_RET );
1304                                     }
1305                                 }
1306                                 break;
1307 
1308                                 case SvtGraphicFill::fillTexture :
1309                                 {
1310                                     aFill.getPath( aFillPath );
1311 
1312                                     /* normally an object filling is consisting of three MetaActions:
1313                                         MetaBitmapAction        using RasterOp xor,
1314                                         MetaPolyPolygonAction   using RasterOp rop_0
1315                                         MetaBitmapAction        using RasterOp xor
1316 
1317                                         Because RasterOps cannot been used in Postscript, we have to
1318                                         replace these actions. The MetaComment "XPATHFILL_SEQ_BEGIN" is
1319                                         providing the clippath of the object. The following loop is
1320                                         trying to find the bitmap that is matching the clippath, so that
1321                                         only one bitmap is exported, otherwise if the bitmap is not
1322                                         locatable, all metaactions are played normally.
1323                                     */
1324                                     sal_uInt32 nCommentStartAction = nCurAction;
1325                                     sal_uInt32 nBitmapCount = 0;
1326                                     sal_uInt32 nBitmapAction = 0;
1327 
1328                                     sal_Bool bOk = sal_True;
1329                                     while( bOk && ( ++nCurAction < nCount ) )
1330                                     {
1331                                         MetaAction* pAction = rMtf.GetAction( nCurAction );
1332                                         switch( pAction->GetType() )
1333                                         {
1334                                             case META_BMPSCALE_ACTION :
1335                                             case META_BMPSCALEPART_ACTION :
1336                                             case META_BMPEXSCALE_ACTION :
1337                                             case META_BMPEXSCALEPART_ACTION :
1338                                             {
1339                                                 nBitmapCount++;
1340                                                 nBitmapAction = nCurAction;
1341                                             }
1342                                             break;
1343                                             case META_COMMENT_ACTION :
1344                                             {
1345                                                 if (((const MetaCommentAction*)pAction)->GetComment().Equals( "XPATHFILL_SEQ_END" ))
1346                                                     bOk = sal_False;
1347                                             }
1348                                             break;
1349                                         }
1350                                     }
1351                                     if( nBitmapCount == 2 )
1352                                     {
1353                                         ImplWriteLine( "gs" );
1354                                         ImplIntersect( aFillPath );
1355                                         GDIMetaFile aTempMtf;
1356                                         aTempMtf.AddAction( rMtf.GetAction( nBitmapAction )->Clone() );
1357                                         ImplWriteActions( aTempMtf, rVDev );
1358                                         ImplWriteLine( "gr" );
1359                                         aFillPath = PolyPolygon();
1360                                     }
1361                                     else
1362                                         nCurAction = nCommentStartAction + 1;
1363                                 }
1364                                 break;
1365 
1366                                 case SvtGraphicFill::fillGradient :
1367                                     aFill.getPath( aFillPath );
1368                                 break;
1369 
1370                                 case SvtGraphicFill::fillHatch :
1371                                 break;
1372                             }
1373                             if ( aFillPath.Count() )
1374                             {
1375                                 ImplWriteLine( "gs" );
1376                                 ImplIntersect( aFillPath );
1377                             }
1378                         }
1379                         if ( bSkipSequence )
1380                         {
1381                             while( ++nCurAction < nCount )
1382                             {
1383                                 pMA = rMtf.GetAction( nCurAction );
1384                                 if ( pMA->GetType() == META_COMMENT_ACTION )
1385                                 {
1386                                     ByteString sComment( ((MetaCommentAction*)pMA)->GetComment() );
1387                                     if ( sComment.Equals( sSeqEnd ) )
1388                                         break;
1389                                 }
1390                             }
1391                         }
1392                     }
1393                 }
1394             }
1395             break;
1396 
1397         }
1398     }
1399 }
1400 
1401 
1402 
1403 //---------------------------------------------------------------------------------
1404 
ImplWritePoint(const Point & rPoint,sal_uInt32 nMode)1405 inline void PSWriter::ImplWritePoint( const Point& rPoint, sal_uInt32 nMode )
1406 {
1407     ImplWriteDouble( rPoint.X() );
1408     ImplWriteDouble( rPoint.Y(), nMode );
1409 }
1410 
1411 //---------------------------------------------------------------------------------
1412 
ImplMoveTo(const Point & rPoint,sal_uInt32 nMode)1413 void PSWriter::ImplMoveTo( const Point& rPoint, sal_uInt32 nMode )
1414 {
1415     ImplWritePoint( rPoint );
1416     ImplWriteByte( 'm' );
1417     ImplExecMode( nMode );
1418 }
1419 
1420 //---------------------------------------------------------------------------------
1421 
ImplLineTo(const Point & rPoint,sal_uInt32 nMode)1422 void PSWriter::ImplLineTo( const Point& rPoint, sal_uInt32 nMode )
1423 {
1424     ImplWritePoint( rPoint );
1425     ImplWriteByte( 'l' );
1426     ImplExecMode( nMode );
1427 }
1428 
1429 //---------------------------------------------------------------------------------
1430 
ImplCurveTo(const Point & rP1,const Point & rP2,const Point & rP3,sal_uInt32 nMode)1431 void PSWriter::ImplCurveTo( const Point& rP1, const Point& rP2, const Point& rP3, sal_uInt32 nMode )
1432 {
1433     ImplWritePoint( rP1 );
1434     ImplWritePoint( rP2 );
1435     ImplWritePoint( rP3 );
1436     *mpPS << "ct ";
1437     ImplExecMode( nMode );
1438 }
1439 
1440 //---------------------------------------------------------------------------------
1441 
ImplTranslate(const double & fX,const double & fY,sal_uInt32 nMode)1442 void PSWriter::ImplTranslate( const double& fX, const double& fY, sal_uInt32 nMode )
1443 {
1444     ImplWriteDouble( fX );
1445     ImplWriteDouble( fY );
1446     ImplWriteByte( 't' );
1447     ImplExecMode( nMode );
1448 }
1449 
1450 //---------------------------------------------------------------------------------
1451 
ImplScale(const double & fX,const double & fY,sal_uInt32 nMode)1452 void PSWriter::ImplScale( const double& fX, const double& fY, sal_uInt32 nMode )
1453 {
1454     ImplWriteDouble( fX );
1455     ImplWriteDouble( fY );
1456     ImplWriteByte( 's' );
1457     ImplExecMode( nMode );
1458 }
1459 
1460 //---------------------------------------------------------------------------------
1461 
ImplRect(const Rectangle & rRect)1462 void PSWriter::ImplRect( const Rectangle & rRect )
1463 {
1464     if ( bFillColor )
1465         ImplRectFill( rRect );
1466     if ( bLineColor )
1467     {
1468         double nWidth = rRect.GetWidth();
1469         double nHeight = rRect.GetHeight();
1470 
1471         ImplWriteLineColor( PS_SPACE );
1472         ImplMoveTo( rRect.TopLeft() );
1473         ImplWriteDouble( nWidth );
1474         *mpPS << "0 rl 0 ";
1475         ImplWriteDouble( nHeight );
1476         *mpPS << "rl ";
1477         ImplWriteDouble( nWidth );
1478         *mpPS << "neg 0 rl ";
1479         ImplClosePathDraw();
1480     }
1481     *mpPS << (sal_uInt8)10;
1482     mnCursorPos = 0;
1483 }
1484 
1485 //---------------------------------------------------------------------------------
1486 
ImplRectFill(const Rectangle & rRect)1487 void PSWriter::ImplRectFill( const Rectangle & rRect )
1488 {
1489     double nWidth = rRect.GetWidth();
1490     double nHeight = rRect.GetHeight();
1491 
1492     ImplWriteFillColor( PS_SPACE );
1493     ImplMoveTo( rRect.TopLeft() );
1494     ImplWriteDouble( nWidth );
1495     *mpPS << "0 rl 0 ";
1496     ImplWriteDouble( nHeight );
1497     *mpPS << "rl ";
1498     ImplWriteDouble( nWidth );
1499     *mpPS << "neg 0 rl ef ";
1500     *mpPS << "p ef";
1501     mnCursorPos += 2;
1502     ImplExecMode( PS_RET );
1503 }
1504 
1505 //---------------------------------------------------------------------------------
1506 
ImplAddPath(const Polygon & rPolygon)1507 void PSWriter::ImplAddPath( const Polygon & rPolygon )
1508 {
1509     sal_uInt16 i = 1;
1510     sal_uInt16 nPointCount = rPolygon.GetSize();
1511     if ( nPointCount > 1 )
1512     {
1513         ImplMoveTo( rPolygon.GetPoint( 0 ) );
1514         while ( i < nPointCount )
1515         {
1516             if ( ( rPolygon.GetFlags( i ) == POLY_CONTROL )
1517                     && ( ( i + 2 ) < nPointCount )
1518                         && ( rPolygon.GetFlags( i + 1 ) == POLY_CONTROL )
1519                             && ( rPolygon.GetFlags( i + 2 ) != POLY_CONTROL ) )
1520             {
1521                 ImplCurveTo( rPolygon[ i ], rPolygon[ i + 1 ], rPolygon[ i + 2 ], PS_WRAP );
1522                 i += 3;
1523             }
1524             else
1525                 ImplLineTo( rPolygon.GetPoint( i++ ), PS_SPACE | PS_WRAP );
1526         }
1527     }
1528 }
1529 
1530 //---------------------------------------------------------------------------------
1531 
ImplIntersect(const PolyPolygon & rPolyPoly)1532 void PSWriter::ImplIntersect( const PolyPolygon& rPolyPoly )
1533 {
1534     sal_uInt16 i, nPolyCount = rPolyPoly.Count();
1535     for ( i = 0; i < nPolyCount; )
1536     {
1537         ImplAddPath( rPolyPoly.GetObject( i ) );
1538         if ( ++i < nPolyCount )
1539         {
1540             *mpPS << "p";
1541             mnCursorPos += 2;
1542             ImplExecMode( PS_RET );
1543         }
1544     }
1545     ImplWriteLine( "eoclip newpath" );
1546 }
1547 
1548 //---------------------------------------------------------------------------------
1549 
ImplWriteGradient(const PolyPolygon & rPolyPoly,const Gradient & rGradient,VirtualDevice & rVDev)1550 void PSWriter::ImplWriteGradient( const PolyPolygon& rPolyPoly, const Gradient& rGradient, VirtualDevice& rVDev )
1551 {
1552     VirtualDevice   l_aVDev;
1553     GDIMetaFile     aTmpMtf;
1554     l_aVDev.SetMapMode( rVDev.GetMapMode() );
1555     l_aVDev.AddGradientActions( rPolyPoly.GetBoundRect(), rGradient, aTmpMtf );
1556     ImplWriteActions( aTmpMtf, rVDev );
1557 }
1558 
1559 //---------------------------------------------------------------------------------
1560 
ImplPolyPoly(const PolyPolygon & rPolyPoly,sal_Bool bTextOutline)1561 void PSWriter::ImplPolyPoly( const PolyPolygon & rPolyPoly, sal_Bool bTextOutline )
1562 {
1563     sal_uInt16 i, nPolyCount = rPolyPoly.Count();
1564     if ( nPolyCount )
1565     {
1566         if ( bFillColor || bTextOutline )
1567         {
1568             if ( bTextOutline )
1569                 ImplWriteTextColor( PS_SPACE );
1570             else
1571                 ImplWriteFillColor( PS_SPACE );
1572             for ( i = 0; i < nPolyCount; )
1573             {
1574                 ImplAddPath( rPolyPoly.GetObject( i ) );
1575                 if ( ++i < nPolyCount )
1576                 {
1577                     *mpPS << "p";
1578                     mnCursorPos += 2;
1579                     ImplExecMode( PS_RET );
1580                 }
1581             }
1582             *mpPS << "p ef";
1583             mnCursorPos += 4;
1584             ImplExecMode( PS_RET );
1585         }
1586         if ( bLineColor )
1587         {
1588             ImplWriteLineColor( PS_SPACE );
1589             for ( i = 0; i < nPolyCount; i++ )
1590                 ImplAddPath( rPolyPoly.GetObject( i ) );
1591             ImplClosePathDraw( PS_RET );
1592         }
1593     }
1594 }
1595 
1596 //---------------------------------------------------------------------------------
1597 
ImplPolyLine(const Polygon & rPoly)1598 void PSWriter::ImplPolyLine( const Polygon & rPoly )
1599 {
1600     if ( bLineColor )
1601     {
1602         ImplWriteLineColor( PS_SPACE );
1603         sal_uInt16 i, nPointCount = rPoly.GetSize();
1604         if ( nPointCount )
1605         {
1606             if ( nPointCount > 1 )
1607             {
1608                 ImplMoveTo( rPoly.GetPoint( 0 ) );
1609                 i = 1;
1610                 while ( i < nPointCount )
1611                 {
1612                     if ( ( rPoly.GetFlags( i ) == POLY_CONTROL )
1613                             && ( ( i + 2 ) < nPointCount )
1614                                 && ( rPoly.GetFlags( i + 1 ) == POLY_CONTROL )
1615                                     && ( rPoly.GetFlags( i + 2 ) != POLY_CONTROL ) )
1616                     {
1617                         ImplCurveTo( rPoly[ i ], rPoly[ i + 1 ], rPoly[ i + 2 ], PS_WRAP );
1618                         i += 3;
1619                     }
1620                     else
1621                         ImplLineTo( rPoly.GetPoint( i++ ), PS_SPACE | PS_WRAP );
1622                 }
1623             }
1624 
1625             // #104645# explicitely close path if polygon is closed
1626             if( rPoly[ 0 ] == rPoly[ nPointCount-1 ] )
1627                 ImplClosePathDraw( PS_RET );
1628             else
1629                 ImplPathDraw();
1630         }
1631     }
1632 }
1633 
1634 //---------------------------------------------------------------------------------
1635 
ImplSetClipRegion(Region & rClipRegion)1636 void PSWriter::ImplSetClipRegion( Region& rClipRegion )
1637 {
1638     if ( !rClipRegion.IsEmpty() )
1639     {
1640         RectangleVector aRectangles;
1641         rClipRegion.GetRegionRectangles(aRectangles);
1642 
1643         for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); aRectIter++)
1644         {
1645             double nX1(aRectIter->Left());
1646             double nY1(aRectIter->Top());
1647             double nX2(aRectIter->Right());
1648             double nY2(aRectIter->Bottom());
1649 
1650             ImplWriteDouble( nX1 );
1651             ImplWriteDouble( nY1 );
1652             ImplWriteByte( 'm' );
1653             ImplWriteDouble( nX2 );
1654             ImplWriteDouble( nY1 );
1655             ImplWriteByte( 'l' );
1656             ImplWriteDouble( nX2 );
1657             ImplWriteDouble( nY2 );
1658             ImplWriteByte( 'l' );
1659             ImplWriteDouble( nX1 );
1660             ImplWriteDouble( nY2 );
1661             ImplWriteByte( 'l' );
1662             ImplWriteDouble( nX1 );
1663             ImplWriteDouble( nY1 );
1664             ImplWriteByte( 'l', PS_SPACE | PS_WRAP );
1665         }
1666 
1667         //Rectangle     aRect;
1668         //RegionHandle  hRegionHandle = rClipRegion.BeginEnumRects();
1669         //
1670         //while ( rClipRegion.GetEnumRects( hRegionHandle, aRect ) )
1671         //{
1672         //  double nX1 = aRect.Left();
1673         //  double nY1 = aRect.Top();
1674         //  double nX2 = aRect.Right();
1675         //  double nY2 = aRect.Bottom();
1676         //  ImplWriteDouble( nX1 );
1677         //  ImplWriteDouble( nY1 );
1678         //  ImplWriteByte( 'm' );
1679         //  ImplWriteDouble( nX2 );
1680         //  ImplWriteDouble( nY1 );
1681         //  ImplWriteByte( 'l' );
1682         //  ImplWriteDouble( nX2 );
1683         //  ImplWriteDouble( nY2 );
1684         //  ImplWriteByte( 'l' );
1685         //  ImplWriteDouble( nX1 );
1686         //  ImplWriteDouble( nY2 );
1687         //  ImplWriteByte( 'l' );
1688         //  ImplWriteDouble( nX1 );
1689         //  ImplWriteDouble( nY1 );
1690         //  ImplWriteByte( 'l', PS_SPACE | PS_WRAP );
1691         //};
1692         //rClipRegion.EndEnumRects( hRegionHandle );
1693         ImplWriteLine( "eoclip newpath" );
1694     }
1695 }
1696 
1697 //---------------------------------------------------------------------------------
1698 // possible gfx formats:
1699 //
1700 // level 1: grayscale   8 bit
1701 //          color      24 bit
1702 //
1703 // level 2: grayscale   8 bit
1704 //          color       1(pal), 4(pal), 8(pal), 24 Bit
1705 //
1706 
ImplBmp(Bitmap * pBitmap,Bitmap * pMaskBitmap,const Point & rPoint,double nXWidth,double nYHeightOrg)1707 void PSWriter::ImplBmp( Bitmap* pBitmap, Bitmap* pMaskBitmap, const Point & rPoint, double nXWidth, double nYHeightOrg )
1708 {
1709     if ( !pBitmap )
1710         return;
1711 
1712     sal_Int32   nHeightOrg = pBitmap->GetSizePixel().Height();
1713     sal_Int32   nHeightLeft = nHeightOrg;
1714     long    nWidth = pBitmap->GetSizePixel().Width();
1715     Point   aSourcePos( rPoint );
1716 
1717     while ( nHeightLeft )
1718     {
1719         Bitmap  aTileBitmap( *pBitmap );
1720         long    nHeight = nHeightLeft;
1721         double  nYHeight = nYHeightOrg;
1722 
1723         sal_Bool    bDoTrans = sal_False;
1724 
1725         Rectangle   aRect;
1726         Region      aRegion;
1727 
1728         if ( pMaskBitmap )
1729         {
1730             bDoTrans = sal_True;
1731             while (sal_True)
1732             {
1733                 if ( mnLevel == 1 )
1734                 {
1735                     if ( nHeight > 10 )
1736                         nHeight = 8;
1737                 }
1738                 aRect = Rectangle( Point( 0, nHeightOrg - nHeightLeft ), Size( (long)nWidth, (long)nHeight ) );
1739                 aRegion = Region( pMaskBitmap->CreateRegion( COL_BLACK, aRect ) );
1740 
1741                 if( mnLevel == 1 )
1742                 {
1743                     RectangleVector aRectangleVector;
1744                     aRegion.GetRegionRectangles(aRectangleVector);
1745 
1746                     if ( aRectangleVector.size() * 5 > 1000 )
1747                     {
1748                         nHeight >>= 1;
1749                         if ( nHeight < 2 )
1750                             return;
1751                         continue;
1752                     }
1753                 }
1754                 break;
1755             }
1756         }
1757         if ( nHeight != nHeightOrg )
1758         {
1759             nYHeight = nYHeightOrg * nHeight / nHeightOrg;
1760             aTileBitmap.Crop( Rectangle( Point( 0, nHeightOrg - nHeightLeft ), Size( nWidth, nHeight ) ) );
1761         }
1762         if ( bDoTrans )
1763         {
1764             ImplWriteLine( "gs\npum" );
1765             ImplTranslate( aSourcePos.X(), aSourcePos.Y() );
1766             ImplScale( nXWidth / nWidth,  nYHeight / nHeight );
1767 
1768             RectangleVector aRectangles;
1769             aRegion.GetRegionRectangles(aRectangles);
1770             const long nMoveVertical(nHeightLeft - nHeightOrg);
1771 
1772             for(RectangleVector::iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); aRectIter++)
1773             {
1774                 aRectIter->Move(0, nMoveVertical);
1775 
1776                 ImplWriteLong( aRectIter->Left() );
1777                 ImplWriteLong( aRectIter->Top() );
1778                 ImplWriteByte( 'm' );
1779                 ImplWriteLong( aRectIter->Right() + 1 );
1780                 ImplWriteLong( aRectIter->Top() );
1781                 ImplWriteByte( 'l' );
1782                 ImplWriteLong( aRectIter->Right() + 1 );
1783                 ImplWriteLong( aRectIter->Bottom() + 1 );
1784                 ImplWriteByte( 'l' );
1785                 ImplWriteLong( aRectIter->Left() );
1786                 ImplWriteLong( aRectIter->Bottom() + 1 );
1787                 ImplWriteByte( 'l' );
1788                 ImplWriteByte( 'p', PS_SPACE | PS_WRAP );
1789             }
1790 
1791             //RegionHandle  hRegionHandle = aRegion.BeginEnumRects();
1792             //
1793             //while ( aRegion.GetEnumRects( hRegionHandle, aRect ) )
1794             //{
1795             //  aRect.Move( 0, - ( nHeightOrg - nHeightLeft ) );
1796             //  ImplWriteLong( aRect.Left() );
1797             //  ImplWriteLong( aRect.Top() );
1798             //  ImplWriteByte( 'm' );
1799             //  ImplWriteLong( aRect.Right() + 1 );
1800             //  ImplWriteLong( aRect.Top() );
1801             //  ImplWriteByte( 'l' );
1802             //  ImplWriteLong( aRect.Right() + 1 );
1803             //  ImplWriteLong( aRect.Bottom() + 1 );
1804             //  ImplWriteByte( 'l' );
1805             //  ImplWriteLong( aRect.Left() );
1806             //  ImplWriteLong( aRect.Bottom() + 1 );
1807             //  ImplWriteByte( 'l' );
1808             //  ImplWriteByte( 'p', PS_SPACE | PS_WRAP );
1809             //};
1810             //aRegion.EndEnumRects( hRegionHandle );
1811             ImplWriteLine( "eoclip newpath" );
1812             ImplWriteLine( "pom" );
1813         }
1814         BitmapReadAccess* pAcc = aTileBitmap.AcquireReadAccess();
1815 
1816         if (!bDoTrans )
1817             ImplWriteLine( "pum" );
1818 
1819         ImplTranslate( aSourcePos.X(), aSourcePos.Y() + nYHeight );
1820         ImplScale( nXWidth, nYHeight );
1821         if ( mnLevel == 1 )                 // level 1 is always grayscale !!!
1822         {
1823             ImplWriteLong( nWidth );
1824             ImplWriteLong( nHeight );
1825             *mpPS << "8 [";
1826             ImplWriteLong( nWidth );
1827             *mpPS << "0 0 ";
1828             ImplWriteLong( -nHeight );
1829             ImplWriteLong( 0 );
1830             ImplWriteLong( nHeight );
1831             ImplWriteLine( "]" );
1832             *mpPS << "{currentfile ";
1833             ImplWriteLong( nWidth );
1834             ImplWriteLine( "string readhexstring pop}" );
1835             ImplWriteLine( "image" );
1836             for ( long y = 0; y < nHeight; y++ )
1837             {
1838                 for ( long x = 0; x < nWidth; x++ )
1839                 {
1840                     ImplWriteHexByte( pAcc->GetPixelIndex( y, x ) );
1841                 }
1842             }
1843             *mpPS << (sal_uInt8)10;
1844         }
1845         else    // Level 2
1846         {
1847             if ( mbGrayScale )
1848             {
1849                 ImplWriteLine( "/DeviceGray setcolorspace" );
1850                 ImplWriteLine( "<<" );
1851                 ImplWriteLine( "/ImageType 1" );
1852                 *mpPS << "/Width ";
1853                 ImplWriteLong( nWidth, PS_RET );
1854                 *mpPS << "/Height ";
1855                 ImplWriteLong( nHeight, PS_RET );
1856                 ImplWriteLine( "/BitsPerComponent 8" );
1857                 ImplWriteLine( "/Decode[0 1]" );
1858                 *mpPS << "/ImageMatrix[";
1859                 ImplWriteLong( nWidth );
1860                 *mpPS << "0 0 ";
1861                 ImplWriteLong( -nHeight );
1862                 ImplWriteLong( 0 );
1863                 ImplWriteLong( nHeight, PS_NONE );
1864                 ImplWriteByte( ']', PS_RET );
1865                 ImplWriteLine( "/DataSource currentfile" );
1866                 ImplWriteLine( "/ASCIIHexDecode filter" );
1867                 if ( mbCompression )
1868                     ImplWriteLine( "/LZWDecode filter" );
1869                 ImplWriteLine( ">>" );
1870                 ImplWriteLine( "image" );
1871                 if ( mbCompression )
1872                 {
1873                     StartCompression();
1874                     for ( long y = 0; y < nHeight; y++ )
1875                     {
1876                         for ( long x = 0; x < nWidth; x++ )
1877                         {
1878                             Compress( pAcc->GetPixelIndex( y, x ) );
1879                         }
1880                     }
1881                     EndCompression();
1882                 }
1883                 else
1884                 {
1885                     for ( long y = 0; y < nHeight; y++ )
1886                     {
1887                         for ( long x = 0; x < nWidth; x++ )
1888                         {
1889                             ImplWriteHexByte( pAcc->GetPixelIndex( y, x ) );
1890                         }
1891                     }
1892                 }
1893             }
1894             else
1895             {
1896                 // have we to write a palette ?
1897 
1898                 if ( pAcc->HasPalette() )
1899                 {
1900                     ImplWriteLine( "[/Indexed /DeviceRGB " );
1901                     ImplWriteLong( pAcc->GetPaletteEntryCount() - 1, PS_RET );
1902                     ImplWriteByte( '<', PS_NONE );
1903                     for ( sal_uInt16 i = 0; i < pAcc->GetPaletteEntryCount(); i++ )
1904                     {
1905                         BitmapColor aBitmapColor = pAcc->GetPaletteColor( i );
1906                         ImplWriteHexByte( aBitmapColor.GetRed(), PS_NONE );
1907                         ImplWriteHexByte( aBitmapColor.GetGreen(), PS_NONE );
1908                         ImplWriteHexByte( aBitmapColor.GetBlue(), PS_SPACE | PS_WRAP );
1909                     }
1910                     ImplWriteByte( '>', PS_RET );
1911 
1912                     ImplWriteLine( "] setcolorspace" );
1913                     ImplWriteLine( "<<" );
1914                     ImplWriteLine( "/ImageType 1" );
1915                     *mpPS << "/Width ";
1916                     ImplWriteLong( nWidth, PS_RET );
1917                     *mpPS << "/Height ";
1918                     ImplWriteLong( nHeight, PS_RET );
1919                     ImplWriteLine( "/BitsPerComponent 8" );
1920                     ImplWriteLine( "/Decode[0 255]" );
1921                     *mpPS << "/ImageMatrix[";
1922                     ImplWriteLong( nWidth );
1923                     *mpPS << "0 0 ";
1924                     ImplWriteLong( -nHeight );
1925                     ImplWriteLong( 0);
1926                     ImplWriteLong( nHeight, PS_NONE );
1927                     ImplWriteByte( ']', PS_RET );
1928                     ImplWriteLine( "/DataSource currentfile" );
1929                     ImplWriteLine( "/ASCIIHexDecode filter" );
1930                     if ( mbCompression )
1931                         ImplWriteLine( "/LZWDecode filter" );
1932                     ImplWriteLine( ">>" );
1933                     ImplWriteLine( "image" );
1934                     if ( mbCompression )
1935                     {
1936                         StartCompression();
1937                         for ( long y = 0; y < nHeight; y++ )
1938                         {
1939                             for ( long x = 0; x < nWidth; x++ )
1940                             {
1941                                 Compress( pAcc->GetPixelIndex( y, x ) );
1942                             }
1943                         }
1944                         EndCompression();
1945                     }
1946                     else
1947                     {
1948                         for ( long y = 0; y < nHeight; y++ )
1949                         {
1950                             for ( long x = 0; x < nWidth; x++ )
1951                             {
1952                                 ImplWriteHexByte( pAcc->GetPixelIndex( y, x ) );
1953                             }
1954                         }
1955                     }
1956                 }
1957                 else // 24 bit color
1958                 {
1959                     ImplWriteLine( "/DeviceRGB setcolorspace" );
1960                     ImplWriteLine( "<<" );
1961                     ImplWriteLine( "/ImageType 1" );
1962                     *mpPS << "/Width ";
1963                     ImplWriteLong( nWidth, PS_RET );
1964                     *mpPS << "/Height ";
1965                     ImplWriteLong( nHeight, PS_RET );
1966                     ImplWriteLine( "/BitsPerComponent 8" );
1967                     ImplWriteLine( "/Decode[0 1 0 1 0 1]" );
1968                     *mpPS << "/ImageMatrix[";
1969                     ImplWriteLong( nWidth );
1970                     *mpPS << "0 0 ";
1971                     ImplWriteLong( -nHeight );
1972                     ImplWriteLong( 0 );
1973                     ImplWriteLong( nHeight, PS_NONE );
1974                     ImplWriteByte( ']', PS_RET );
1975                     ImplWriteLine( "/DataSource currentfile" );
1976                     ImplWriteLine( "/ASCIIHexDecode filter" );
1977                     if ( mbCompression )
1978                         ImplWriteLine( "/LZWDecode filter" );
1979                     ImplWriteLine( ">>" );
1980                     ImplWriteLine( "image" );
1981                     if ( mbCompression )
1982                     {
1983                         StartCompression();
1984                         for ( long y = 0; y < nHeight; y++ )
1985                         {
1986                             for ( long x = 0; x < nWidth; x++ )
1987                             {
1988                                 const BitmapColor aBitmapColor( pAcc->GetPixel( y, x ) );
1989                                 Compress( aBitmapColor.GetRed() );
1990                                 Compress( aBitmapColor.GetGreen() );
1991                                 Compress( aBitmapColor.GetBlue() );
1992                             }
1993                         }
1994                         EndCompression();
1995                     }
1996                     else
1997                     {
1998                         for ( long y = 0; y < nHeight; y++ )
1999                         {
2000                             for ( long x = 0; x < nWidth; x++ )
2001                             {
2002                                 const BitmapColor aBitmapColor( pAcc->GetPixel( y, x ) );
2003                                 ImplWriteHexByte( aBitmapColor.GetRed() );
2004                                 ImplWriteHexByte( aBitmapColor.GetGreen() );
2005                                 ImplWriteHexByte( aBitmapColor.GetBlue() );
2006                             }
2007                         }
2008                     }
2009                 }
2010             }
2011             ImplWriteLine( ">" );       // in Level 2 the dictionary needs to be closed (eod)
2012         }
2013         if ( bDoTrans )
2014             ImplWriteLine( "gr" );
2015         else
2016             ImplWriteLine( "pom" );
2017 
2018         aTileBitmap.ReleaseAccess( pAcc );
2019         nHeightLeft -= nHeight;
2020         if ( nHeightLeft )
2021         {
2022             nHeightLeft++;
2023             aSourcePos.Y() = (long) ( rPoint.Y() + ( nYHeightOrg * ( nHeightOrg - nHeightLeft ) ) / nHeightOrg );
2024         }
2025     }
2026 }
2027 
2028 //---------------------------------------------------------------------------------
2029 
ImplWriteCharacter(sal_Char nChar)2030 void PSWriter::ImplWriteCharacter( sal_Char nChar )
2031 {
2032     switch( nChar )
2033     {
2034         case '(' :
2035         case ')' :
2036         case '\\' :
2037             ImplWriteByte( (sal_uInt8)'\\', PS_NONE );
2038     }
2039     ImplWriteByte( (sal_uInt8)nChar, PS_NONE );
2040 }
2041 
2042 //---------------------------------------------------------------------------------
2043 
ImplWriteString(const ByteString & rString,VirtualDevice & rVDev,const sal_Int32 * pDXArry,sal_Bool bStretch)2044 void PSWriter::ImplWriteString( const ByteString& rString, VirtualDevice& rVDev, const sal_Int32* pDXArry, sal_Bool bStretch )
2045 {
2046     sal_uInt16 nLen = rString.Len();
2047     if ( nLen )
2048     {
2049         sal_uInt16 i;
2050         if ( pDXArry )
2051         {
2052             double nx = 0;
2053 
2054             for( i = 0; i < nLen; i++ )
2055             {
2056                 if ( i > 0 )
2057                     nx = pDXArry[ i - 1 ];
2058                 ImplWriteDouble( ( bStretch ) ? nx : rVDev.GetTextWidth( rString.GetChar( i ) ) );
2059                 ImplWriteDouble( nx );
2060                 ImplWriteLine( "(", PS_NONE );
2061                 ImplWriteCharacter( rString.GetChar( i ) );
2062                 ImplWriteLine( ") bs" );
2063             }
2064         }
2065         else
2066         {
2067             ImplWriteByte( '(', PS_NONE );
2068             for ( i = 0; i < nLen; i++ )
2069                 ImplWriteCharacter( rString.GetChar( i ) );
2070             ImplWriteLine( ") sw" );
2071         }
2072     }
2073 }
2074 
2075 // ------------------------------------------------------------------------
2076 
ImplText(const String & rUniString,const Point & rPos,const sal_Int32 * pDXArry,sal_Int32 nWidth,VirtualDevice & rVDev)2077 void PSWriter::ImplText( const String& rUniString, const Point& rPos, const sal_Int32* pDXArry, sal_Int32 nWidth, VirtualDevice& rVDev )
2078 {
2079     sal_uInt16 nLen = rUniString.Len();
2080     if ( !nLen )
2081         return;
2082     if ( mnTextMode == 0 )  // using glpyh outlines
2083     {
2084         Font    aNotRotatedFont( maFont );
2085         aNotRotatedFont.SetOrientation( 0 );
2086 
2087         VirtualDevice aVirDev( 1 );
2088         aVirDev.SetMapMode( rVDev.GetMapMode() );
2089         aVirDev.SetFont( aNotRotatedFont );
2090         aVirDev.SetTextAlign( eTextAlign );
2091 
2092         sal_Int16 nRotation = maFont.GetOrientation();
2093         Polygon aPolyDummy( 1 );
2094 
2095         PolyPolygon aPolyPoly;
2096         Point aPos( rPos );
2097         if ( nRotation )
2098         {
2099             aPolyDummy.SetPoint( aPos, 0 );
2100             aPolyDummy.Rotate( rPos, nRotation );
2101             aPos = aPolyDummy.GetPoint( 0 );
2102         }
2103         sal_Bool bOldLineColor = bLineColor;
2104         bLineColor = sal_False;
2105         std::vector<PolyPolygon> aPolyPolyVec;
2106         if ( aVirDev.GetTextOutlines( aPolyPolyVec, rUniString, 0, 0, STRING_LEN, sal_True, nWidth, pDXArry ) )
2107         {
2108             // always adjust text position to match baseline alignment
2109             ImplWriteLine( "pum" );
2110             ImplWriteDouble( aPos.X() );
2111             ImplWriteDouble( aPos.Y() );
2112             ImplWriteLine( "t" );
2113             if ( nRotation )
2114             {
2115                 ImplWriteF( nRotation, 1 );
2116                 *mpPS << "r ";
2117             }
2118             std::vector<PolyPolygon>::iterator aIter( aPolyPolyVec.begin() );
2119             while ( aIter != aPolyPolyVec.end() )
2120                 ImplPolyPoly( *aIter++, sal_True );
2121             ImplWriteLine( "pom" );
2122         }
2123         bLineColor = bOldLineColor;
2124     }
2125     else if ( ( mnTextMode == 1 ) || ( mnTextMode == 2 ) )  // normal text output
2126     {
2127         if ( mnTextMode == 2 )  // forcing output one complete text packet, by
2128             pDXArry = NULL;     // ignoring the kerning array
2129         ImplSetAttrForText( rPos );
2130         ByteString aStr( rUniString, maFont.GetCharSet() );
2131         ImplWriteString( aStr, rVDev, pDXArry, nWidth != 0 );
2132         if ( maFont.GetOrientation() )
2133             ImplWriteLine( "gr" );
2134     }
2135 }
2136 
2137 // ------------------------------------------------------------------------
2138 
ImplSetAttrForText(const Point & rPoint)2139 void PSWriter::ImplSetAttrForText( const Point& rPoint )
2140 {
2141     Point aPoint( rPoint );
2142 
2143     long nRotation = maFont.GetOrientation();
2144     ImplWriteTextColor();
2145 
2146     Size aSize = maFont.GetSize();
2147 
2148     if ( maLastFont != maFont )
2149     {
2150         if ( maFont.GetPitch() == PITCH_FIXED )         // a little bit font selection
2151             ImplDefineFont( "Courier", "Oblique" );
2152         else if ( maFont.GetCharSet() == RTL_TEXTENCODING_SYMBOL )
2153             ImplWriteLine( "/Symbol findfont" );
2154         else if ( maFont.GetFamily() == FAMILY_SWISS )
2155             ImplDefineFont( "Helvetica", "Oblique" );
2156         else
2157             ImplDefineFont( "Times", "Italic" );
2158 
2159         maLastFont = maFont;
2160         aSize = maFont.GetSize();
2161         ImplWriteDouble( aSize.Height() );
2162         *mpPS << "sf ";
2163     }
2164     if ( eTextAlign != ALIGN_BASELINE )
2165     {                                                       // PostScript kennt kein FontAlignment
2166         if ( eTextAlign == ALIGN_TOP )                      // -> ich gehe daher davon aus, dass
2167             aPoint.Y() += ( aSize.Height() * 4 / 5 );       // der Bereich unter der Baseline
2168         else if ( eTextAlign == ALIGN_BOTTOM )              // in etwa 20% der Fontsize ausmacht
2169             aPoint.Y() -= ( aSize.Height() / 5 );
2170     }
2171     ImplMoveTo( aPoint );
2172     if ( nRotation )
2173     {
2174         *mpPS << "gs ";
2175         ImplWriteF( nRotation, 1 );
2176         *mpPS << "r ";
2177     }
2178 }
2179 
2180 //---------------------------------------------------------------------------------
2181 
ImplDefineFont(const char * pOriginalName,const char * pItalic)2182 void PSWriter::ImplDefineFont( const char* pOriginalName, const char* pItalic )
2183 {
2184     *mpPS << (sal_uInt8)'/';             //convert the font pOriginalName using ISOLatin1Encoding
2185     *mpPS << pOriginalName;
2186     switch ( maFont.GetWeight() )
2187     {
2188         case WEIGHT_SEMIBOLD :
2189         case WEIGHT_BOLD :
2190         case WEIGHT_ULTRABOLD :
2191         case WEIGHT_BLACK :
2192             *mpPS << "-Bold";
2193             if ( maFont.GetItalic() != ITALIC_NONE )
2194                 *mpPS << pItalic;
2195             break;
2196         default:
2197             if ( maFont.GetItalic() != ITALIC_NONE )
2198                 *mpPS << pItalic;
2199             break;
2200     }
2201     ImplWriteLine( " f" );
2202 }
2203 
2204 //---------------------------------------------------------------------------------
2205 //---------------------------------------------------------------------------------
2206 //---------------------------------------------------------------------------------
2207 
ImplClosePathDraw(sal_uLong nMode)2208 void PSWriter::ImplClosePathDraw( sal_uLong nMode )
2209 {
2210     *mpPS << "pc";
2211     mnCursorPos += 2;
2212     ImplExecMode( nMode );
2213 }
2214 
ImplPathDraw()2215 void PSWriter::ImplPathDraw()
2216 {
2217     *mpPS << "ps";
2218     mnCursorPos += 2;
2219     ImplExecMode( PS_RET );
2220 }
2221 
2222 //---------------------------------------------------------------------------------
2223 
ImplWriteLineColor(sal_uLong nMode)2224 inline void PSWriter::ImplWriteLineColor( sal_uLong nMode )
2225 {
2226     if ( aColor != aLineColor )
2227     {
2228         aColor = aLineColor;
2229         ImplWriteColor( nMode );
2230     }
2231 }
ImplWriteFillColor(sal_uLong nMode)2232 inline void PSWriter::ImplWriteFillColor( sal_uLong nMode )
2233 {
2234     if ( aColor != aFillColor )
2235     {
2236         aColor = aFillColor;
2237         ImplWriteColor( nMode );
2238     }
2239 }
ImplWriteTextColor(sal_uLong nMode)2240 inline void PSWriter::ImplWriteTextColor( sal_uLong nMode )
2241 {
2242     if ( aColor != aTextColor )
2243     {
2244         aColor = aTextColor;
2245         ImplWriteColor( nMode );
2246     }
2247 }
ImplWriteTextFillColor(sal_uLong nMode)2248 inline void PSWriter::ImplWriteTextFillColor( sal_uLong nMode )
2249 {
2250     if ( aColor != aTextFillColor )
2251     {
2252         aColor = aTextFillColor;
2253         ImplWriteColor( nMode );
2254     }
2255 }
2256 
2257 //---------------------------------------------------------------------------------
2258 
ImplWriteColor(sal_uLong nMode)2259 void PSWriter::ImplWriteColor( sal_uLong nMode )
2260 {
2261     if ( mbGrayScale )
2262     {
2263         // writes the Color (grayscale) as a Number from 0.000 up to 1.000
2264 
2265         ImplWriteF( 1000 * ( (sal_uInt8)aColor.GetRed() * 77 + (sal_uInt8)aColor.GetGreen() * 151 +
2266             (sal_uInt8)aColor.GetBlue() * 28 + 1 ) / 65536, 3, nMode );
2267     }
2268     else
2269     {
2270         ImplWriteB1 ( (sal_uInt8)aColor.GetRed() );
2271         ImplWriteB1 ( (sal_uInt8)aColor.GetGreen() );
2272         ImplWriteB1 ( (sal_uInt8)aColor.GetBlue() );
2273     }
2274     *mpPS << "c";                               // ( c is defined as setrgbcolor or setgray )
2275     ImplExecMode( nMode );
2276 }
2277 
2278 //---------------------------------------------------------------------------------
2279 
ImplGetScaling(const MapMode & rMapMode)2280 double PSWriter::ImplGetScaling( const MapMode& rMapMode )
2281 {
2282     double  nMul;
2283     switch ( rMapMode.GetMapUnit() )
2284     {
2285         case MAP_PIXEL :
2286         case MAP_SYSFONT :
2287         case MAP_APPFONT :
2288 
2289         case MAP_100TH_MM :
2290             nMul = 1;
2291             break;
2292         case MAP_10TH_MM :
2293             nMul = 10;
2294             break;
2295         case MAP_MM :
2296             nMul = 100;
2297             break;
2298         case MAP_CM :
2299             nMul = 1000;
2300             break;
2301         case MAP_1000TH_INCH :
2302             nMul = 2.54;
2303             break;
2304         case MAP_100TH_INCH :
2305             nMul = 25.4;
2306             break;
2307         case MAP_10TH_INCH :
2308             nMul = 254;
2309             break;
2310         case MAP_INCH :
2311             nMul = 2540;
2312             break;
2313         case MAP_TWIP :
2314             nMul = 1.76388889;
2315             break;
2316         case MAP_POINT :
2317             nMul = 35.27777778;
2318             break;
2319         default:
2320             nMul = 1.0;
2321             break;
2322     }
2323     return nMul;
2324 }
2325 
2326 //---------------------------------------------------------------------------------
2327 
ImplGetMapMode(const MapMode & rMapMode)2328 void PSWriter::ImplGetMapMode( const MapMode& rMapMode )
2329 {
2330     ImplWriteLine( "tm setmatrix" );
2331     double fMul = ImplGetScaling( rMapMode );
2332     double fScaleX = (double)rMapMode.GetScaleX() * fMul;
2333     double fScaleY = (double)rMapMode.GetScaleY() * fMul;
2334     ImplTranslate( rMapMode.GetOrigin().X() * fScaleX, rMapMode.GetOrigin().Y() * fScaleY );
2335     ImplScale( fScaleX, fScaleY );
2336 }
2337 
2338 //---------------------------------------------------------------------------------
2339 
ImplExecMode(sal_uLong nMode)2340 inline void PSWriter::ImplExecMode( sal_uLong nMode )
2341 {
2342     if ( nMode & PS_WRAP )
2343     {
2344         if ( mnCursorPos >= PS_LINESIZE )
2345         {
2346             mnCursorPos = 0;
2347             *mpPS << (sal_uInt8)0xa;
2348             return;
2349         }
2350     }
2351     if ( nMode & PS_SPACE )
2352     {
2353             *mpPS << (sal_uInt8)32;
2354             mnCursorPos++;
2355     }
2356     if ( nMode & PS_RET )
2357     {
2358         *mpPS << (sal_uInt8)0xa;
2359         mnCursorPos = 0;
2360     }
2361 }
2362 
2363 //---------------------------------------------------------------------------------
2364 
ImplWriteLine(const char * pString,sal_uLong nMode)2365 inline void PSWriter::ImplWriteLine( const char* pString, sal_uLong nMode )
2366 {
2367     sal_uLong i = 0;
2368     while ( pString[ i ] )
2369     {
2370         *mpPS << (sal_uInt8)pString[ i++ ];
2371     }
2372     mnCursorPos += i;
2373     ImplExecMode( nMode );
2374 }
2375 
2376 //---------------------------------------------------------------------------------
2377 
ImplWriteLineInfo(double fLWidth,double fMLimit,SvtGraphicStroke::CapType eLCap,SvtGraphicStroke::JoinType eJoin,SvtGraphicStroke::DashArray & rLDash)2378 void PSWriter::ImplWriteLineInfo( double fLWidth, double fMLimit,
2379                                     SvtGraphicStroke::CapType eLCap,
2380                                         SvtGraphicStroke::JoinType eJoin,
2381                                             SvtGraphicStroke::DashArray& rLDash )
2382 {
2383     if ( fLineWidth != fLWidth )
2384     {
2385         fLineWidth = fLWidth;
2386         ImplWriteDouble( fLineWidth );
2387         ImplWriteLine( "lw", PS_SPACE );
2388     }
2389     if ( eLineCap != eLCap )
2390     {
2391         eLineCap = eLCap;
2392         ImplWriteLong( (sal_Int32)eLineCap, PS_SPACE );
2393         ImplWriteLine( "lc", PS_SPACE );
2394     }
2395     if ( eJoinType != eJoin )
2396     {
2397         eJoinType = eJoin;
2398         ImplWriteLong( (sal_Int32)eJoinType, PS_SPACE );
2399         ImplWriteLine( "lj", PS_SPACE );
2400     }
2401     if ( eJoinType == SvtGraphicStroke::joinMiter )
2402     {
2403         if ( fMiterLimit != fMLimit )
2404         {
2405             fMiterLimit = fMLimit;
2406             ImplWriteDouble( fMiterLimit );
2407             ImplWriteLine( "ml", PS_SPACE );
2408         }
2409     }
2410     if ( aDashArray != rLDash )
2411     {
2412         aDashArray = rLDash;
2413         sal_uInt32 j, i = aDashArray.size();
2414         ImplWriteLine( "[", PS_SPACE );
2415         for ( j = 0; j < i; j++ )
2416             ImplWriteDouble( aDashArray[ j ] );
2417         ImplWriteLine( "] 0 ld" );
2418     }
2419 }
2420 
2421 //---------------------------------------------------------------------------------
2422 
ImplWriteLineInfo(const LineInfo & rLineInfo)2423 void PSWriter::ImplWriteLineInfo( const LineInfo& rLineInfo )
2424 {
2425     SvtGraphicStroke::DashArray l_aDashArray;
2426     if ( rLineInfo.GetStyle() == LINE_DASH )
2427         l_aDashArray.push_back( 2 );
2428     const double fLWidth(( ( rLineInfo.GetWidth() + 1 ) + ( rLineInfo.GetWidth() + 1 ) ) * 0.5);
2429     SvtGraphicStroke::JoinType aJoinType(SvtGraphicStroke::joinMiter);
2430     SvtGraphicStroke::CapType aCapType(SvtGraphicStroke::capButt);
2431 
2432     switch(rLineInfo.GetLineJoin())
2433     {
2434         default: // B2DLINEJOIN_NONE, B2DLINEJOIN_MIDDLE
2435             // do NOT use SvtGraphicStroke::joinNone here
2436             // since it will be written as numerical value directly
2437             // and is NOT a valid EPS value
2438             break;
2439         case basegfx::B2DLINEJOIN_MITER:
2440             aJoinType = SvtGraphicStroke::joinMiter;
2441             break;
2442         case basegfx::B2DLINEJOIN_BEVEL:
2443             aJoinType = SvtGraphicStroke::joinBevel;
2444             break;
2445         case basegfx::B2DLINEJOIN_ROUND:
2446             aJoinType = SvtGraphicStroke::joinRound;
2447             break;
2448     }
2449 
2450     switch(rLineInfo.GetLineCap())
2451     {
2452         default: /* com::sun::star::drawing::LineCap_BUTT */
2453         {
2454             aCapType = SvtGraphicStroke::capButt;
2455             break;
2456         }
2457         case com::sun::star::drawing::LineCap_ROUND:
2458         {
2459             aCapType = SvtGraphicStroke::capRound;
2460             break;
2461         }
2462         case com::sun::star::drawing::LineCap_SQUARE:
2463         {
2464             aCapType = SvtGraphicStroke::capSquare;
2465             break;
2466         }
2467     }
2468 
2469     ImplWriteLineInfo( fLWidth, fMiterLimit, aCapType, aJoinType, l_aDashArray );
2470 }
2471 
2472 //---------------------------------------------------------------------------------
2473 
ImplWriteLong(sal_Int32 nNumber,sal_uLong nMode)2474 void PSWriter::ImplWriteLong( sal_Int32 nNumber, sal_uLong nMode )
2475 {
2476     const ByteString aNumber( ByteString::CreateFromInt32( nNumber ) );
2477     sal_uLong nLen = aNumber.Len();
2478     mnCursorPos += nLen;
2479     for ( sal_uInt16 n = 0; n < nLen; n++ )
2480         *mpPS << aNumber.GetChar( n );
2481     ImplExecMode( nMode );
2482 }
2483 
2484 //---------------------------------------------------------------------------------
2485 
ImplWriteDouble(double fNumber,sal_uLong nMode)2486 void PSWriter::ImplWriteDouble( double fNumber, sal_uLong nMode )
2487 {
2488     sal_Int32 nLength;
2489 
2490     sal_Int32   nPTemp = (sal_Int32)fNumber;
2491     sal_Int32   nATemp = labs( (sal_Int32)( ( fNumber - nPTemp ) * 100000 ) );
2492 
2493     if ( !nPTemp && nATemp && ( fNumber < 0.0 ) )
2494         *mpPS << (sal_Char)'-';
2495 
2496     ByteString aNumber1( ByteString::CreateFromInt32( nPTemp ) );
2497     nLength = aNumber1.Len();
2498     mnCursorPos += nLength;
2499     for ( sal_Int32 n = 0; n < nLength; n++ )
2500         *mpPS << aNumber1.GetChar( (sal_uInt16)n );
2501 
2502     int zCount = 0;
2503     if ( nATemp )
2504     {
2505         *mpPS << (sal_uInt8)'.';
2506         mnCursorPos++;
2507         const ByteString aNumber2( ByteString::CreateFromInt32( nATemp ) );
2508 
2509         sal_Int16 n, nLen = aNumber2.Len();
2510         if ( nLen < 8 )
2511         {
2512             mnCursorPos += 6 - nLen;
2513             for ( n = 0; n < ( 5 - nLen ); n++ )
2514             {
2515                 *mpPS << (sal_uInt8)'0';
2516             }
2517         }
2518         mnCursorPos += nLen;
2519         for ( n = 0; n < nLen; n++ )
2520         {
2521             *mpPS << aNumber2.GetChar( n );
2522             zCount--;
2523             if ( aNumber2.GetChar( n ) != '0' )
2524                 zCount = 0;
2525         }
2526         if ( zCount )
2527             mpPS->SeekRel( zCount );
2528     }
2529     ImplExecMode( nMode );
2530 }
2531 
2532 //---------------------------------------------------------------------------------
2533 
2534 // writes the number to stream: nNumber / ( 10^nCount )
2535 
ImplWriteF(sal_Int32 nNumber,sal_uLong nCount,sal_uLong nMode)2536 void PSWriter::ImplWriteF( sal_Int32 nNumber, sal_uLong nCount, sal_uLong nMode )
2537 {
2538     if ( nNumber < 0 )
2539     {
2540         *mpPS << (sal_uInt8)'-';
2541         nNumber = -nNumber;
2542         mnCursorPos++;
2543     }
2544     const ByteString aScaleFactor( ByteString::CreateFromInt32( nNumber ) );
2545     sal_uLong nLen = aScaleFactor.Len();
2546     long nStSize =  ( nCount + 1 ) - nLen;
2547     if ( nStSize >= 1 )
2548     {
2549         *mpPS << (sal_uInt8)'0';
2550         mnCursorPos++;
2551     }
2552     if ( nStSize >= 2 )
2553     {
2554         *mpPS << (sal_uInt8)'.';
2555         for ( long i = 1; i < nStSize; i++ )
2556         {
2557             *mpPS << (sal_uInt8)'0';
2558             mnCursorPos++;
2559         }
2560     }
2561     mnCursorPos += nLen;
2562     for( sal_uInt16 n = 0UL; n < nLen; n++  )
2563     {
2564         if ( n == nLen - nCount )
2565         {
2566             *mpPS << (sal_uInt8)'.';
2567             mnCursorPos++;
2568         }
2569         *mpPS << aScaleFactor.GetChar( n );
2570     }
2571     ImplExecMode( nMode );
2572 }
2573 
2574 //---------------------------------------------------------------------------------
2575 
ImplWriteByte(sal_uInt8 nNumb,sal_uLong nMode)2576 void PSWriter::ImplWriteByte( sal_uInt8 nNumb, sal_uLong nMode )
2577 {
2578     *mpPS << ( nNumb );
2579     mnCursorPos++;
2580     ImplExecMode( nMode );
2581 }
2582 
2583 //---------------------------------------------------------------------------------
2584 
ImplWriteHexByte(sal_uInt8 nNumb,sal_uLong nMode)2585 void PSWriter::ImplWriteHexByte( sal_uInt8 nNumb, sal_uLong nMode )
2586 {
2587     if ( ( nNumb >> 4 ) > 9 )
2588         *mpPS << (sal_uInt8)( ( nNumb >> 4 ) + 'A' - 10 );
2589     else
2590         *mpPS << (sal_uInt8)( ( nNumb >> 4 ) + '0' );
2591 
2592     if ( ( nNumb & 0xf ) > 9 )
2593         *mpPS << (sal_uInt8)( ( nNumb & 0xf ) + 'A' - 10 );
2594     else
2595         *mpPS << (sal_uInt8)( ( nNumb & 0xf ) + '0' );
2596     mnCursorPos += 2;
2597     ImplExecMode( nMode );
2598 }
2599 
2600 //---------------------------------------------------------------------------------
2601 
2602 // writes the sal_uInt8 nNumb as a Number from 0.000 up to 1.000
2603 
ImplWriteB1(sal_uInt8 nNumb,sal_uLong nMode)2604 void PSWriter::ImplWriteB1( sal_uInt8 nNumb, sal_uLong nMode )
2605 {
2606     ImplWriteF( 1000 * ( nNumb + 1 ) / 256 , 3, nMode );
2607 }
2608 
2609 
2610 // ------------------------------------------------------------------------
2611 
WriteBits(sal_uInt16 nCode,sal_uInt16 nCodeLen)2612 inline void PSWriter::WriteBits( sal_uInt16 nCode, sal_uInt16 nCodeLen )
2613 {
2614     dwShift |= ( nCode << ( nOffset - nCodeLen ) );
2615     nOffset -= nCodeLen;
2616     while ( nOffset < 24 )
2617     {
2618         ImplWriteHexByte( (sal_uInt8)( dwShift >> 24 ) );
2619         dwShift <<= 8;
2620         nOffset += 8;
2621     }
2622     if ( nCode == 257 && nOffset != 32 )
2623         ImplWriteHexByte( (sal_uInt8)( dwShift >> 24 ) );
2624 }
2625 
2626 // ------------------------------------------------------------------------
2627 
StartCompression()2628 void PSWriter::StartCompression()
2629 {
2630     sal_uInt16 i;
2631     nDataSize = 8;
2632 
2633     nClearCode = 1 << nDataSize;
2634     nEOICode = nClearCode + 1;
2635     nTableSize = nEOICode + 1;
2636     nCodeSize = nDataSize + 1;
2637 
2638     nOffset = 32;                       // anzahl freier bits in dwShift
2639     dwShift = 0;
2640 
2641     pTable = new PSLZWCTreeNode[ 4096 ];
2642 
2643     for ( i = 0; i < 4096; i++ )
2644     {
2645         pTable[ i ].pBrother = pTable[ i ].pFirstChild = NULL;
2646         pTable[ i ].nValue = (sal_uInt8)( pTable[ i ].nCode = i );
2647     }
2648     pPrefix = NULL;
2649     WriteBits( nClearCode, nCodeSize );
2650 }
2651 
2652 // ------------------------------------------------------------------------
2653 
Compress(sal_uInt8 nCompThis)2654 void PSWriter::Compress( sal_uInt8 nCompThis )
2655 {
2656     PSLZWCTreeNode*     p;
2657     sal_uInt16              i;
2658     sal_uInt8               nV;
2659 
2660     if( !pPrefix )
2661     {
2662         pPrefix = pTable + nCompThis;
2663     }
2664     else
2665     {
2666         nV = nCompThis;
2667         for( p = pPrefix->pFirstChild; p != NULL; p = p->pBrother )
2668         {
2669             if ( p->nValue == nV )
2670                 break;
2671         }
2672 
2673         if( p )
2674             pPrefix = p;
2675         else
2676         {
2677             WriteBits( pPrefix->nCode, nCodeSize );
2678 
2679             if ( nTableSize == 409 )
2680             {
2681                 WriteBits( nClearCode, nCodeSize );
2682 
2683                 for ( i = 0; i < nClearCode; i++ )
2684                     pTable[ i ].pFirstChild = NULL;
2685 
2686                 nCodeSize = nDataSize + 1;
2687                 nTableSize = nEOICode + 1;
2688             }
2689             else
2690             {
2691                 if( nTableSize == (sal_uInt16)( ( 1 << nCodeSize ) - 1 ) )
2692                     nCodeSize++;
2693 
2694                 p = pTable + ( nTableSize++ );
2695                 p->pBrother = pPrefix->pFirstChild;
2696                 pPrefix->pFirstChild = p;
2697                 p->nValue = nV;
2698                 p->pFirstChild = NULL;
2699             }
2700 
2701             pPrefix = pTable + nV;
2702         }
2703     }
2704 }
2705 
2706 // ------------------------------------------------------------------------
2707 
EndCompression()2708 void PSWriter::EndCompression()
2709 {
2710     if( pPrefix )
2711         WriteBits( pPrefix->nCode, nCodeSize );
2712 
2713     WriteBits( nEOICode, nCodeSize );
2714     delete[] pTable;
2715 }
2716 
2717 // ------------------------------------------------------------------------
2718 
ImplSearchEntry(sal_uInt8 * pSource,sal_uInt8 * pDest,sal_uLong nComp,sal_uLong nSize)2719 sal_uInt8* PSWriter::ImplSearchEntry( sal_uInt8* pSource, sal_uInt8* pDest, sal_uLong nComp, sal_uLong nSize )
2720 {
2721     while ( nComp-- >= nSize )
2722     {
2723         sal_uLong i;
2724         for ( i = 0; i < nSize; i++ )
2725         {
2726             if ( ( pSource[i]&~0x20 ) != ( pDest[i]&~0x20 ) )
2727                 break;
2728         }
2729         if ( i == nSize )
2730             return pSource;
2731         pSource++;
2732     }
2733     return NULL;
2734 }
2735 
2736 // ------------------------------------------------------------------------
2737 
ImplGetBoundingBox(double * nNumb,sal_uInt8 * pSource,sal_uLong nSize)2738 sal_Bool PSWriter::ImplGetBoundingBox( double* nNumb, sal_uInt8* pSource, sal_uLong nSize )
2739 {
2740     sal_Bool    bRetValue = sal_False;
2741     sal_uLong   nBytesRead;
2742 
2743     if ( nSize < 256 )      // we assume that the file is greater than 256 bytes
2744         return sal_False;
2745 
2746     if ( nSize < POSTSCRIPT_BOUNDINGSEARCH )
2747         nBytesRead = nSize;
2748     else
2749         nBytesRead = POSTSCRIPT_BOUNDINGSEARCH;
2750 
2751     sal_uInt8* pDest = ImplSearchEntry( pSource, (sal_uInt8*)"%%BoundingBox:", nBytesRead, 14 );
2752     if ( pDest )
2753     {
2754         int     nSecurityCount = 100;   // only 100 bytes following the bounding box will be checked
2755         nNumb[0] = nNumb[1] = nNumb[2] = nNumb[3] = 0;
2756         pDest += 14;
2757         for ( int i = 0; ( i < 4 ) && nSecurityCount; i++ )
2758         {
2759             int     nDivision = 1;
2760             sal_Bool    bDivision = sal_False;
2761             sal_Bool    bNegative = sal_False;
2762             sal_Bool    bValid = sal_True;
2763 
2764             while ( ( --nSecurityCount ) && ( ( *pDest == ' ' ) || ( *pDest == 0x9 ) ) )
2765                 pDest++;
2766             sal_uInt8 nByte = *pDest;
2767             while ( nSecurityCount && ( nByte != ' ' ) && ( nByte != 0x9 ) && ( nByte != 0xd ) && ( nByte != 0xa ) )
2768             {
2769                 switch ( nByte )
2770                 {
2771                     case '.' :
2772                         if ( bDivision )
2773                             bValid = sal_False;
2774                         else
2775                             bDivision = sal_True;
2776                         break;
2777                     case '-' :
2778                         bNegative = sal_True;
2779                         break;
2780                     default :
2781                         if ( ( nByte < '0' ) || ( nByte > '9' ) )
2782                             nSecurityCount = 1;     // error parsing the bounding box values
2783                         else if ( bValid )
2784                         {
2785                             if ( bDivision )
2786                                 nDivision*=10;
2787                             nNumb[i] *= 10;
2788                             nNumb[i] += nByte - '0';
2789                         }
2790                         break;
2791                 }
2792                 nSecurityCount--;
2793                 nByte = *(++pDest);
2794             }
2795             if ( bNegative )
2796                 nNumb[i] = -nNumb[i];
2797             if ( bDivision && ( nDivision != 1 ) )
2798                 nNumb[i] /= nDivision;
2799         }
2800         if ( nSecurityCount)
2801             bRetValue = sal_True;
2802     }
2803     return bRetValue;
2804 }
2805 
2806 //================== GraphicExport - die exportierte Funktion ================
2807 
GraphicExport(SvStream & rStream,Graphic & rGraphic,FilterConfigItem * pFilterConfigItem,sal_Bool)2808 extern "C" sal_Bool __LOADONCALLAPI GraphicExport( SvStream & rStream, Graphic & rGraphic, FilterConfigItem* pFilterConfigItem, sal_Bool)
2809 {
2810     PSWriter aPSWriter;
2811     return aPSWriter.WritePS( rGraphic, rStream, pFilterConfigItem );
2812 }
2813 
2814