1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_vcl.hxx"
30 
31 #include "psputil.hxx"
32 #include "glyphset.hxx"
33 
34 #include "printergfx.hxx"
35 #include "printerjob.hxx"
36 #include "vcl/fontmanager.hxx"
37 #include "vcl/strhelper.hxx"
38 #include "vcl/printerinfomanager.hxx"
39 
40 #include "tools/debug.hxx"
41 #include "tools/color.hxx"
42 #include "tools/poly.hxx"
43 
44 using namespace psp ;
45 
46 static const sal_Int32 nMaxTextColumn = 80;
47 
48 GraphicsStatus::GraphicsStatus() :
49         mbArtItalic( false ),
50         mbArtBold( false ),
51         mnTextHeight( 0 ),
52         mnTextWidth( 0 ),
53         mfLineWidth( -1 )
54 {
55 }
56 
57 /*
58  * non graphics graphics routines
59  */
60 
61 sal_Bool
62 PrinterGfx::Init (PrinterJob &rPrinterJob)
63 {
64     mpPageHeader = rPrinterJob.GetCurrentPageHeader ();
65     mpPageBody   = rPrinterJob.GetCurrentPageBody ();
66     mnDepth      = rPrinterJob.GetDepth ();
67     mnPSLevel    = rPrinterJob.GetPostscriptLevel ();
68     mbColor      = rPrinterJob.IsColorPrinter ();
69 
70     mnDpi = rPrinterJob.GetResolution();
71     rPrinterJob.GetScale (mfScaleX, mfScaleY);
72     const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( rPrinterJob.GetPrinterName() ) );
73     if( mpFontSubstitutes )
74         delete const_cast< ::std::hash_map<fontID,fontID>* >(mpFontSubstitutes);
75     if( rInfo.m_bPerformFontSubstitution )
76         mpFontSubstitutes = new ::std::hash_map< fontID, fontID >( rInfo.m_aFontSubstitutions );
77     else
78         mpFontSubstitutes = NULL;
79     mbUploadPS42Fonts = rInfo.m_pParser ? ( rInfo.m_pParser->isType42Capable() ? sal_True : sal_False ) : sal_False;
80 
81     return sal_True;
82 }
83 
84 sal_Bool
85 PrinterGfx::Init (const JobData& rData)
86 {
87     mpPageHeader    = NULL;
88     mpPageBody      = NULL;
89     mnDepth         = rData.m_nColorDepth;
90     mnPSLevel       = rData.m_nPSLevel ? rData.m_nPSLevel : (rData.m_pParser ? rData.m_pParser->getLanguageLevel() : 2 );
91     mbColor         = rData.m_nColorDevice ? ( rData.m_nColorDevice == -1 ? sal_False : sal_True ) : (( rData.m_pParser ?  (rData.m_pParser->isColorDevice() ? sal_True : sal_False ) : sal_True ) );
92     int nRes = rData.m_aContext.getRenderResolution();
93     mnDpi           = nRes;
94     mfScaleX        = (double)72.0 / (double)mnDpi;
95     mfScaleY        = (double)72.0 / (double)mnDpi;
96     const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( rData.m_aPrinterName ) );
97     if( mpFontSubstitutes )
98         delete const_cast< ::std::hash_map<fontID,fontID>* >(mpFontSubstitutes);
99     if( rInfo.m_bPerformFontSubstitution )
100         mpFontSubstitutes = new ::std::hash_map< fontID, fontID >( rInfo.m_aFontSubstitutions );
101     else
102         mpFontSubstitutes = NULL;
103     mbUploadPS42Fonts = rInfo.m_pParser ? ( rInfo.m_pParser->isType42Capable() ? sal_True : sal_False ) : sal_False;
104 
105     return sal_True;
106 }
107 
108 void
109 PrinterGfx::GetResolution (sal_Int32 &rDpiX, sal_Int32 &rDpiY) const
110 {
111     rDpiX = mnDpi;
112     rDpiY = mnDpi;
113 }
114 
115 sal_uInt16
116 PrinterGfx::GetBitCount ()
117 {
118     return mnDepth;
119 }
120 
121 PrinterGfx::PrinterGfx() :
122         mpPageHeader (NULL),
123         mpPageBody (NULL),
124         mnFontID (0),
125         mnFallbackID (0),
126         mnTextAngle (0),
127         mbTextVertical (false),
128         mrFontMgr (PrintFontManager::get()),
129         mbCompressBmp (sal_True),
130         maFillColor (0xff,0,0),
131         maTextColor (0,0,0),
132         maLineColor (0, 0xff, 0),
133         mpFontSubstitutes( NULL ),
134         mbStrictSO52Compatibility( false )
135 {
136     maVirtualStatus.mfLineWidth = 1.0;
137     maVirtualStatus.mnTextHeight = 12;
138     maVirtualStatus.mnTextWidth = 0;
139 
140     maGraphicsStack.push_back( GraphicsStatus() );
141 }
142 
143 PrinterGfx::~PrinterGfx()
144 {
145     /*
146      *  #95810# the original reasoning why mpFontSubstitutes is a pointer was
147      *  that applications should release all PrinterGfx when printers change
148      *  because they are really invalid; the corresponding printers may have
149      *  changed their settings or even not exist anymore.
150      *
151      *  Alas, this is not always done real time. So we keep a local copy of
152      *  the font substitutes now in case of bad timing.
153      */
154     delete const_cast< ::std::hash_map<fontID,fontID>* >(mpFontSubstitutes);
155 }
156 
157 void
158 PrinterGfx::Clear()
159 {
160     mpPageHeader                    = NULL;
161     mpPageBody                      = NULL;
162     mnFontID                        = 0;
163     maVirtualStatus                 = GraphicsStatus();
164     maVirtualStatus.mnTextHeight    = 12;
165     maVirtualStatus.mnTextWidth     = 0;
166     maVirtualStatus.mfLineWidth     = 1.0;
167     mbTextVertical                  = false;
168     maLineColor                     = PrinterColor();
169     maFillColor                     = PrinterColor();
170     maTextColor                     = PrinterColor();
171     mbCompressBmp                   = sal_True;
172     mnDpi                           = 300;
173     mnDepth                         = 24;
174     mnPSLevel                       = 2;
175     mbColor                         = sal_True;
176     mnTextAngle                     = 0;
177 
178     maClipRegion.clear();
179     maGraphicsStack.clear();
180     maGraphicsStack.push_back( GraphicsStatus() );
181 }
182 
183 /*
184  * clip region handling
185  */
186 
187 void
188 PrinterGfx::ResetClipRegion()
189 {
190     maClipRegion.clear();
191     PSGRestore ();
192     PSGSave (); // get "clean" clippath
193 }
194 
195 void
196 PrinterGfx::BeginSetClipRegion( sal_uInt32 )
197 {
198     maClipRegion.clear();
199 }
200 
201 sal_Bool
202 PrinterGfx::UnionClipRegion (sal_Int32 nX,sal_Int32 nY,sal_Int32 nDX,sal_Int32 nDY)
203 {
204     if( nDX && nDY )
205         maClipRegion.push_back (Rectangle(Point(nX,nY ), Size(nDX,nDY)));
206     return sal_True;
207 }
208 
209 sal_Bool
210 PrinterGfx::JoinVerticalClipRectangles( std::list< Rectangle >::iterator& it,
211                                         Point& rOldPoint, sal_Int32& rColumn )
212 {
213     sal_Bool bSuccess = sal_False;
214 
215     std::list< Rectangle >::iterator tempit, nextit;
216     nextit = it;
217     ++nextit;
218     std::list< Point > leftside, rightside;
219 
220     Rectangle aLastRect( *it );
221     leftside.push_back( Point( it->Left(), it->Top() ) );
222     rightside.push_back( Point( it->Right()+1, it->Top() ) );
223     while( nextit != maClipRegion.end() )
224     {
225         tempit = nextit;
226         ++tempit;
227         if( nextit->Top() == aLastRect.Bottom()+1 )
228         {
229             if(
230                ( nextit->Left() >= aLastRect.Left() && nextit->Left() <= aLastRect.Right() ) // left endpoint touches last rectangle
231                ||
232                ( nextit->Right() >= aLastRect.Left() && nextit->Right() <= aLastRect.Right() ) // right endpoint touches last rectangle
233                ||
234                ( nextit->Left() <= aLastRect.Left() && nextit->Right() >= aLastRect.Right() ) // whole line touches last rectangle
235                )
236             {
237                 if( aLastRect.GetHeight() > 1                           ||
238                     abs( aLastRect.Left() - nextit->Left() ) > 2        ||
239                     abs( aLastRect.Right() - nextit->Right() ) > 2
240                     )
241                 {
242                     leftside.push_back( Point( aLastRect.Left(), aLastRect.Bottom()+1 ) );
243                     rightside.push_back( Point( aLastRect.Right()+1, aLastRect.Bottom()+1 ) );
244                 }
245                 aLastRect = *nextit;
246                 leftside.push_back( aLastRect.TopLeft() );
247                 rightside.push_back( aLastRect.TopRight() );
248                 maClipRegion.erase( nextit );
249             }
250         }
251         nextit = tempit;
252     }
253     if( leftside.size() > 1 )
254     {
255         // push the last coordinates
256         leftside.push_back( Point( aLastRect.Left(), aLastRect.Bottom()+1 ) );
257         rightside.push_back( Point( aLastRect.Right()+1, aLastRect.Bottom()+1 ) );
258 
259         // cool, we can concatenate rectangles
260         int nDX = -65536, nDY = 65536;
261         int nNewDX = 0, nNewDY = 0;
262 
263         Point aLastPoint = leftside.front();
264         PSBinMoveTo (aLastPoint, rOldPoint, rColumn);
265         leftside.pop_front();
266         while( leftside.begin() != leftside.end() )
267         {
268             Point aPoint (leftside.front());
269             leftside.pop_front();
270             // may have been the last one
271             if( leftside.begin() != leftside.end() )
272             {
273                 nNewDX = aPoint.X() - aLastPoint.X();
274                 nNewDY = aPoint.Y() - aLastPoint.Y();
275                 if( nNewDX == 0 && nDX == 0 )
276                     continue;
277                 if( nDX != 0 && nNewDX != 0 &&
278                     (double)nNewDY/(double)nNewDX == (double)nDY/(double)nDX )
279                     continue;
280             }
281             PSBinLineTo (aPoint, rOldPoint, rColumn);
282             aLastPoint = aPoint;
283         }
284 
285         aLastPoint = rightside.back();
286         nDX = -65536;
287         nDY = 65536;
288         PSBinLineTo (aLastPoint, rOldPoint, rColumn);
289         rightside.pop_back();
290         while( rightside.begin() != rightside.end() )
291         {
292             Point aPoint (rightside.back());
293             rightside.pop_back();
294             if( rightside.begin() != rightside.end() )
295             {
296                 nNewDX = aPoint.X() - aLastPoint.X();
297                 nNewDY = aPoint.Y() - aLastPoint.Y();
298                 if( nNewDX == 0 && nDX == 0 )
299                     continue;
300                 if( nDX != 0 && nNewDX != 0 &&
301                     (double)nNewDY/(double)nNewDX == (double)nDY/(double)nDX )
302                     continue;
303             }
304             PSBinLineTo (aPoint, rOldPoint, rColumn);
305         }
306 
307         tempit = it;
308         ++tempit;
309         maClipRegion.erase( it );
310         it = tempit;
311         bSuccess = sal_True;
312     }
313     return bSuccess;
314 }
315 
316 void
317 PrinterGfx::EndSetClipRegion()
318 {
319     PSGRestore ();
320     PSGSave (); // get "clean" clippath
321 
322     PSBinStartPath ();
323     Point aOldPoint (0, 0);
324     sal_Int32 nColumn = 0;
325 
326     std::list< Rectangle >::iterator it = maClipRegion.begin();
327     while( it != maClipRegion.end() )
328     {
329         // try to concatenate adjacent rectangles
330         // first try in y direction, then in x direction
331         if( ! JoinVerticalClipRectangles( it, aOldPoint, nColumn ) )
332         {
333             // failed, so it is a single rectangle
334             PSBinMoveTo (it->TopLeft(),                          aOldPoint, nColumn );
335             PSBinLineTo (Point( it->Left(), it->Bottom()+1 ),    aOldPoint, nColumn );
336             PSBinLineTo (Point( it->Right()+1, it->Bottom()+1 ), aOldPoint, nColumn );
337             PSBinLineTo (Point( it->Right()+1, it->Top() ),      aOldPoint, nColumn );
338             ++it;
339         }
340     }
341 
342     PSBinEndPath ();
343 
344     WritePS (mpPageBody, "closepath clip newpath\n");
345     maClipRegion.clear();
346 }
347 
348 /*
349  * draw graphic primitives
350  */
351 
352 void
353 PrinterGfx::DrawRect (const Rectangle& rRectangle )
354 {
355     char pRect [128];
356     sal_Int32 nChar = 0;
357 
358     nChar  = psp::getValueOf (rRectangle.TopLeft().X(),     pRect);
359     nChar += psp::appendStr (" ",                           pRect + nChar);
360     nChar += psp::getValueOf (rRectangle.TopLeft().Y(),     pRect + nChar);
361     nChar += psp::appendStr (" ",                           pRect + nChar);
362     nChar += psp::getValueOf (rRectangle.GetWidth(),        pRect + nChar);
363     nChar += psp::appendStr (" ",                           pRect + nChar);
364     nChar += psp::getValueOf (rRectangle.GetHeight(),       pRect + nChar);
365     nChar += psp::appendStr (" ",                           pRect + nChar);
366 
367     if( maFillColor.Is() )
368     {
369         PSSetColor (maFillColor);
370         PSSetColor ();
371         WritePS (mpPageBody, pRect, nChar);
372         WritePS (mpPageBody, "rectfill\n");
373     }
374     if( maLineColor.Is() )
375     {
376         PSSetColor (maLineColor);
377         PSSetColor ();
378         PSSetLineWidth ();
379         WritePS (mpPageBody, pRect, nChar);
380         WritePS (mpPageBody, "rectstroke\n");
381     }
382 }
383 
384 void
385 PrinterGfx::DrawLine (const Point& rFrom, const Point& rTo)
386 {
387     if( maLineColor.Is() )
388     {
389         PSSetColor (maLineColor);
390         PSSetColor ();
391         PSSetLineWidth ();
392 
393         PSMoveTo (rFrom);
394         PSLineTo (rTo);
395         WritePS (mpPageBody, "stroke\n" );
396     }
397 }
398 
399 void
400 PrinterGfx::DrawPixel (const Point& rPoint, const PrinterColor& rPixelColor)
401 {
402     if( rPixelColor.Is() )
403     {
404         PSSetColor (rPixelColor);
405         PSSetColor ();
406 
407         PSMoveTo (rPoint);
408         PSLineTo (Point (rPoint.X ()+1, rPoint.Y ()));
409         PSLineTo (Point (rPoint.X ()+1, rPoint.Y ()+1));
410         PSLineTo (Point (rPoint.X (), rPoint.Y ()+1));
411         WritePS (mpPageBody, "fill\n" );
412     }
413 }
414 
415 void
416 PrinterGfx::DrawPolyLine (sal_uInt32 nPoints, const Point* pPath)
417 {
418     if( maLineColor.Is() && nPoints && pPath )
419     {
420         PSSetColor (maLineColor);
421         PSSetColor ();
422         PSSetLineWidth ();
423 
424         PSBinCurrentPath (nPoints, pPath);
425 
426         WritePS (mpPageBody, "stroke\n" );
427     }
428 }
429 
430 void
431 PrinterGfx::DrawPolygon (sal_uInt32 nPoints, const Point* pPath)
432 {
433     // premature end of operation
434     if (!(nPoints > 1) || (pPath == NULL) || !(maFillColor.Is() || maLineColor.Is()))
435         return;
436 
437     // setup closed path
438     Point aPoint( 0, 0 );
439     sal_Int32 nColumn( 0 );
440 
441     PSBinStartPath();
442     PSBinMoveTo( pPath[0], aPoint, nColumn );
443     for( unsigned int n = 1; n < nPoints; n++ )
444         PSBinLineTo( pPath[n], aPoint, nColumn );
445     if( pPath[0] != pPath[nPoints-1] )
446         PSBinLineTo( pPath[0], aPoint, nColumn );
447     PSBinEndPath();
448 
449     // fill the polygon first, then draw the border, note that fill and
450     // stroke reset the currentpath
451 
452     // if fill and stroke, save the current path
453     if( maFillColor.Is() && maLineColor.Is())
454         PSGSave();
455 
456     if (maFillColor.Is ())
457     {
458         PSSetColor (maFillColor);
459         PSSetColor ();
460         WritePS (mpPageBody, "eofill\n");
461     }
462 
463     // restore the current path
464     if( maFillColor.Is() && maLineColor.Is())
465         PSGRestore();
466 
467     if (maLineColor.Is ())
468     {
469         PSSetColor (maLineColor);
470         PSSetColor ();
471         PSSetLineWidth ();
472         WritePS (mpPageBody, "stroke\n");
473     }
474 }
475 
476 void
477 PrinterGfx::DrawPolyPolygon (sal_uInt32 nPoly, const sal_uInt32* pSizes, const Point** pPaths )
478 {
479     // sanity check
480     if ( !nPoly || !pPaths || !(maFillColor.Is() || maLineColor.Is()))
481         return;
482 
483 
484     // setup closed path
485     for( unsigned int i = 0; i < nPoly; i++ )
486     {
487         Point aPoint( 0, 0 );
488         sal_Int32 nColumn( 0 );
489 
490         PSBinStartPath();
491         PSBinMoveTo( pPaths[i][0], aPoint, nColumn );
492         for( unsigned int n = 1; n < pSizes[i]; n++ )
493             PSBinLineTo( pPaths[i][n], aPoint, nColumn );
494         if( pPaths[i][0] != pPaths[i][pSizes[i]-1] )
495                 PSBinLineTo( pPaths[i][0], aPoint, nColumn );
496         PSBinEndPath();
497     }
498 
499     // if eofill and stroke, save the current path
500     if( maFillColor.Is() && maLineColor.Is())
501         PSGSave();
502 
503     // first draw area
504     if( maFillColor.Is() )
505     {
506         PSSetColor (maFillColor);
507         PSSetColor ();
508         WritePS (mpPageBody, "eofill\n");
509     }
510 
511     // restore the current path
512     if( maFillColor.Is() && maLineColor.Is())
513         PSGRestore();
514 
515     // now draw outlines
516     if( maLineColor.Is() )
517     {
518         PSSetColor (maLineColor);
519         PSSetColor ();
520         PSSetLineWidth ();
521         WritePS (mpPageBody, "stroke\n");
522     }
523 }
524 
525 /*
526  * Bezier Polygon Drawing methods.
527  */
528 
529 void
530 PrinterGfx::DrawPolyLineBezier (sal_uInt32 nPoints, const Point* pPath, const sal_uInt8* pFlgAry)
531 {
532     const sal_uInt32 nBezString= 1024;
533     sal_Char pString[nBezString];
534 
535     if ( nPoints > 1 && maLineColor.Is() && pPath )
536     {
537         PSSetColor (maLineColor);
538         PSSetColor ();
539         PSSetLineWidth ();
540 
541         snprintf(pString, nBezString, "%li %li moveto\n", pPath[0].X(), pPath[0].Y());
542         WritePS(mpPageBody, pString);
543 
544         // Handle the drawing of mixed lines mixed with curves
545         // - a normal point followed by a normal point is a line
546         // - a normal point followed by 2 control points and a normal point is a curve
547         for (unsigned int i=1; i<nPoints;)
548         {
549             if (pFlgAry[i] != POLY_CONTROL) //If the next point is a POLY_NORMAL, we're drawing a line
550             {
551                 snprintf(pString, nBezString, "%li %li lineto\n", pPath[i].X(), pPath[i].Y());
552                 i++;
553             }
554             else //Otherwise we're drawing a spline
555             {
556                 if (i+2 >= nPoints)
557                     return; //Error: wrong sequence of contol/normal points somehow
558                 if ((pFlgAry[i] == POLY_CONTROL) && (pFlgAry[i+1] == POLY_CONTROL) &&
559                     (pFlgAry[i+2] != POLY_CONTROL))
560                 {
561                     snprintf(pString, nBezString, "%li %li %li %li %li %li curveto\n",
562                              pPath[i].X(), pPath[i].Y(),
563                              pPath[i+1].X(), pPath[i+1].Y(),
564                              pPath[i+2].X(), pPath[i+2].Y());
565                 }
566                 else
567                 {
568                     DBG_ERROR( "PrinterGfx::DrawPolyLineBezier: Strange output" );
569                 }
570                 i+=3;
571             }
572             WritePS(mpPageBody, pString);
573         }
574 
575         // now draw outlines
576         WritePS (mpPageBody, "stroke\n");
577     }
578 }
579 
580 void
581 PrinterGfx::DrawPolygonBezier (sal_uInt32 nPoints, const Point* pPath, const sal_uInt8* pFlgAry)
582 {
583     const sal_uInt32 nBezString = 1024;
584     sal_Char pString[nBezString];
585     // premature end of operation
586     if (!(nPoints > 1) || (pPath == NULL) || !(maFillColor.Is() || maLineColor.Is()))
587         return;
588 
589     snprintf(pString, nBezString, "%li %li moveto\n", pPath[0].X(), pPath[0].Y());
590     WritePS(mpPageBody, pString); //Move to the starting point for the PolyPoygon
591     for (unsigned int i=1; i < nPoints;)
592     {
593         if (pFlgAry[i] != POLY_CONTROL)
594         {
595             snprintf(pString, nBezString, "%li %li lineto\n", pPath[i].X(), pPath[i].Y());
596             WritePS(mpPageBody, pString);
597             i++;
598         }
599         else
600         {
601             if (i+2 >= nPoints)
602                 return; //Error: wrong sequence of contol/normal points somehow
603             if ((pFlgAry[i] == POLY_CONTROL) && (pFlgAry[i+1] == POLY_CONTROL) &&
604                     (pFlgAry[i+2] != POLY_CONTROL))
605             {
606                 snprintf(pString, nBezString, "%li %li %li %li %li %li curveto\n",
607                         pPath[i].X(), pPath[i].Y(),
608                         pPath[i+1].X(), pPath[i+1].Y(),
609                         pPath[i+2].X(), pPath[i+2].Y());
610                 WritePS(mpPageBody, pString);
611             }
612             else
613             {
614                 DBG_ERROR( "PrinterGfx::DrawPolygonBezier: Strange output" );
615             }
616             i+=3;
617         }
618     }
619 
620     // if fill and stroke, save the current path
621     if( maFillColor.Is() && maLineColor.Is())
622         PSGSave();
623 
624     if (maFillColor.Is ())
625     {
626         PSSetColor (maFillColor);
627         PSSetColor ();
628         WritePS (mpPageBody, "eofill\n");
629     }
630 
631     // restore the current path
632     if( maFillColor.Is() && maLineColor.Is())
633         PSGRestore();
634 }
635 
636 void
637 PrinterGfx::DrawPolyPolygonBezier (sal_uInt32 nPoly, const sal_uInt32 * pPoints, const Point* const * pPtAry, const sal_uInt8* const* pFlgAry)
638 {
639     const sal_uInt32 nBezString = 1024;
640     sal_Char pString[nBezString];
641     if ( !nPoly || !pPtAry || !pPoints || !(maFillColor.Is() || maLineColor.Is()))
642         return;
643 
644 
645     for (unsigned int i=0; i<nPoly;i++)
646     {
647         sal_uInt32 nPoints = pPoints[i];
648         // #112689# sanity check
649         if( nPoints == 0 || pPtAry[i] == NULL )
650             continue;
651 
652         snprintf(pString, nBezString, "%li %li moveto\n", pPtAry[i][0].X(), pPtAry[i][0].Y()); //Move to the starting point
653         WritePS(mpPageBody, pString);
654         for (unsigned int j=1; j < nPoints;)
655         {
656             // if no flag array exists for this polygon, then it must be a regular
657             // polygon without beziers
658             if ( ! pFlgAry[i] || pFlgAry[i][j] != POLY_CONTROL)
659             {
660                 snprintf(pString, nBezString, "%li %li lineto\n", pPtAry[i][j].X(), pPtAry[i][j].Y());
661                 WritePS(mpPageBody, pString);
662                 j++;
663             }
664             else
665             {
666                 if (j+2 >= nPoints)
667                     break; //Error: wrong sequence of contol/normal points somehow
668                 if ((pFlgAry[i][j] == POLY_CONTROL) && (pFlgAry[i][j+1] == POLY_CONTROL) && (pFlgAry[i][j+2] != POLY_CONTROL))
669                 {
670                     snprintf(pString, nBezString, "%li %li %li %li %li %li curveto\n",
671                             pPtAry[i][j].X(), pPtAry[i][j].Y(),
672                             pPtAry[i][j+1].X(), pPtAry[i][j+1].Y(),
673                             pPtAry[i][j+2].X(), pPtAry[i][j+2].Y());
674                     WritePS(mpPageBody, pString);
675                 }
676                 else
677                 {
678                     DBG_ERROR( "PrinterGfx::DrawPolyPolygonBezier: Strange output" );
679                 }
680                 j+=3;
681             }
682         }
683     }
684 
685     // if fill and stroke, save the current path
686     if( maFillColor.Is() && maLineColor.Is())
687         PSGSave();
688 
689     if (maFillColor.Is ())
690     {
691         PSSetColor (maFillColor);
692         PSSetColor ();
693         WritePS (mpPageBody, "eofill\n");
694     }
695 
696     // restore the current path
697     if( maFillColor.Is() && maLineColor.Is())
698         PSGRestore();
699 }
700 
701 
702 /*
703  * postscript generating routines
704  */
705 void
706 PrinterGfx::PSGSave ()
707 {
708     WritePS (mpPageBody, "gsave\n" );
709     GraphicsStatus aNewState;
710     if( maGraphicsStack.begin() != maGraphicsStack.end() )
711         aNewState = maGraphicsStack.front();
712     maGraphicsStack.push_front( aNewState );
713 }
714 
715 void
716 PrinterGfx::PSGRestore ()
717 {
718     WritePS (mpPageBody, "grestore\n" );
719     if( maGraphicsStack.begin() == maGraphicsStack.end() )
720         WritePS (mpPageBody, "Error: too many grestores\n" );
721     else
722         maGraphicsStack.pop_front();
723 }
724 
725 void
726 PrinterGfx::PSSetLineWidth ()
727 {
728     if( currentState().mfLineWidth != maVirtualStatus.mfLineWidth )
729     {
730         char pBuffer[128];
731         sal_Int32 nChar = 0;
732 
733         currentState().mfLineWidth = maVirtualStatus.mfLineWidth;
734         nChar  = psp::getValueOfDouble (pBuffer, maVirtualStatus.mfLineWidth, 5);
735         nChar += psp::appendStr (" setlinewidth\n", pBuffer + nChar);
736         WritePS (mpPageBody, pBuffer, nChar);
737     }
738 }
739 
740 void
741 PrinterGfx::PSSetColor ()
742 {
743     PrinterColor& rColor( maVirtualStatus.maColor );
744 
745     if( currentState().maColor != rColor )
746     {
747         currentState().maColor = rColor;
748 
749         char pBuffer[128];
750         sal_Int32 nChar = 0;
751 
752         if( mbColor )
753         {
754             nChar  = psp::getValueOfDouble (pBuffer,
755                                             (double)rColor.GetRed() / 255.0, 5);
756             nChar += psp::appendStr (" ", pBuffer + nChar);
757             nChar += psp::getValueOfDouble (pBuffer + nChar,
758                                             (double)rColor.GetGreen() / 255.0, 5);
759             nChar += psp::appendStr (" ", pBuffer + nChar);
760             nChar += psp::getValueOfDouble (pBuffer + nChar,
761                                             (double)rColor.GetBlue() / 255.0, 5);
762             nChar += psp::appendStr (" setrgbcolor\n", pBuffer + nChar );
763         }
764         else
765         {
766             Color aColor( rColor.GetRed(), rColor.GetGreen(), rColor.GetBlue() );
767             sal_uInt8 nCol = aColor.GetLuminance();
768             nChar  = psp::getValueOfDouble( pBuffer, (double)nCol / 255.0, 5 );
769             nChar += psp::appendStr( " setgray\n", pBuffer + nChar );
770         }
771 
772         WritePS (mpPageBody, pBuffer, nChar);
773     }
774 }
775 
776 void
777 PrinterGfx::PSSetFont ()
778 {
779     GraphicsStatus& rCurrent( currentState() );
780     if( maVirtualStatus.maFont			!= rCurrent.maFont			||
781         maVirtualStatus.mnTextHeight	!= rCurrent.mnTextHeight	||
782         maVirtualStatus.maEncoding      != rCurrent.maEncoding		||
783         maVirtualStatus.mnTextWidth     != rCurrent.mnTextWidth		||
784         maVirtualStatus.mbArtBold		!= rCurrent.mbArtBold		||
785         maVirtualStatus.mbArtItalic		!= rCurrent.mbArtItalic
786         )
787     {
788         rCurrent.maFont              = maVirtualStatus.maFont;
789         rCurrent.maEncoding          = maVirtualStatus.maEncoding;
790         rCurrent.mnTextWidth         = maVirtualStatus.mnTextWidth;
791         rCurrent.mnTextHeight        = maVirtualStatus.mnTextHeight;
792         rCurrent.mbArtItalic		 = maVirtualStatus.mbArtItalic;
793         rCurrent.mbArtBold			 = maVirtualStatus.mbArtBold;
794 
795         sal_Int32 nTextHeight = rCurrent.mnTextHeight;
796         sal_Int32 nTextWidth  = rCurrent.mnTextWidth ? rCurrent.mnTextWidth
797                                                      : rCurrent.mnTextHeight;
798 
799         sal_Char  pSetFont [256];
800         sal_Int32 nChar = 0;
801 
802         // postscript based fonts need reencoding
803         if (   (   rCurrent.maEncoding == RTL_TEXTENCODING_MS_1252)
804             || (   rCurrent.maEncoding == RTL_TEXTENCODING_ISO_8859_1)
805             || (   rCurrent.maEncoding >= RTL_TEXTENCODING_USER_START
806                 && rCurrent.maEncoding <= RTL_TEXTENCODING_USER_END)
807            )
808         {
809             rtl::OString aReencodedFont =
810                         psp::GlyphSet::GetReencodedFontName (rCurrent.maEncoding,
811                                                                 rCurrent.maFont);
812 
813             nChar += psp::appendStr  ("(",          pSetFont + nChar);
814             nChar += psp::appendStr  (aReencodedFont.getStr(),
815                                                     pSetFont + nChar);
816             nChar += psp::appendStr  (") cvn findfont ",
817                                                     pSetFont + nChar);
818         }
819         else
820         // tt based fonts mustn't reencode, the encoding is implied by the fontname
821         // same for symbol type1 fonts, dont try to touch them
822         {
823             nChar += psp::appendStr  ("(",          pSetFont + nChar);
824             nChar += psp::appendStr  (rCurrent.maFont.getStr(),
825                                                     pSetFont + nChar);
826             nChar += psp::appendStr  (") cvn findfont ",
827                                                     pSetFont + nChar);
828         }
829 
830         if( ! rCurrent.mbArtItalic )
831         {
832             nChar += psp::getValueOf (nTextWidth,   pSetFont + nChar);
833             nChar += psp::appendStr  (" ",          pSetFont + nChar);
834             nChar += psp::getValueOf (-nTextHeight, pSetFont + nChar);
835             nChar += psp::appendStr  (" matrix scale makefont setfont\n", pSetFont + nChar);
836         }
837         else // skew 15 degrees to right
838         {
839             nChar += psp::appendStr  ( " [",		pSetFont + nChar);
840             nChar += psp::getValueOf (nTextWidth,	pSetFont + nChar);
841             nChar += psp::appendStr  (" 0 ",        pSetFont + nChar);
842             nChar += psp::getValueOfDouble (pSetFont + nChar, 0.27*(double)nTextWidth, 3 );
843             nChar += psp::appendStr  ( " ",			pSetFont + nChar);
844             nChar += psp::getValueOf (-nTextHeight, pSetFont + nChar);
845 
846             nChar += psp::appendStr  (" 0 0] makefont setfont\n", pSetFont + nChar);
847         }
848 
849         WritePS (mpPageBody, pSetFont);
850     }
851 }
852 
853 void
854 PrinterGfx::PSRotate (sal_Int32 nAngle)
855 {
856     sal_Int32 nPostScriptAngle = -nAngle;
857     while( nPostScriptAngle < 0 )
858         nPostScriptAngle += 3600;
859 
860     if (nPostScriptAngle == 0)
861         return;
862 
863     sal_Int32 nFullAngle  = nPostScriptAngle / 10;
864     sal_Int32 nTenthAngle = nPostScriptAngle % 10;
865 
866     sal_Char  pRotate [48];
867     sal_Int32 nChar = 0;
868 
869     nChar  = psp::getValueOf (nFullAngle,  pRotate);
870     nChar += psp::appendStr (".",          pRotate + nChar);
871     nChar += psp::getValueOf (nTenthAngle, pRotate + nChar);
872     nChar += psp::appendStr (" rotate\n",  pRotate + nChar);
873 
874     WritePS (mpPageBody, pRotate);
875 }
876 
877 void
878 PrinterGfx::PSPointOp (const Point& rPoint, const sal_Char* pOperator)
879 {
880     sal_Char  pPSCommand [48];
881     sal_Int32 nChar = 0;
882 
883     nChar  = psp::getValueOf (rPoint.X(), pPSCommand);
884     nChar += psp::appendStr  (" ",        pPSCommand + nChar);
885     nChar += psp::getValueOf (rPoint.Y(), pPSCommand + nChar);
886     nChar += psp::appendStr  (" ",        pPSCommand + nChar);
887     nChar += psp::appendStr  (pOperator,  pPSCommand + nChar);
888     nChar += psp::appendStr  ("\n",       pPSCommand + nChar);
889 
890     DBG_ASSERT (nChar < 48, "Buffer overflow in PSPointOp");
891 
892     WritePS (mpPageBody, pPSCommand);
893 }
894 
895 void
896 PrinterGfx::PSTranslate (const Point& rPoint)
897 {
898     PSPointOp (rPoint, "translate");
899 }
900 
901 void
902 PrinterGfx::PSMoveTo (const Point& rPoint)
903 {
904     PSPointOp (rPoint, "moveto");
905 }
906 
907 void
908 PrinterGfx::PSLineTo (const Point& rPoint)
909 {
910     PSPointOp (rPoint, "lineto");
911 }
912 
913 void
914 PrinterGfx::PSRMoveTo (sal_Int32 nDx, sal_Int32 nDy)
915 {
916     Point aPoint(nDx, nDy);
917     PSPointOp (aPoint, "rmoveto");
918 }
919 
920 /* get a compressed representation of the path information */
921 
922 #define DEBUG_BINPATH 0
923 
924 void
925 PrinterGfx::PSBinLineTo (const Point& rCurrent, Point& rOld, sal_Int32& nColumn)
926 {
927 #if (DEBUG_BINPATH == 1)
928     PSLineTo (rCurrent);
929 #else
930     PSBinPath (rCurrent, rOld, lineto, nColumn);
931 #endif
932 }
933 
934 void
935 PrinterGfx::PSBinMoveTo (const Point& rCurrent, Point& rOld, sal_Int32& nColumn)
936 {
937 #if (DEBUG_BINPATH == 1)
938     PSMoveTo (rCurrent);
939 #else
940     PSBinPath (rCurrent, rOld, moveto, nColumn);
941 #endif
942 }
943 
944 void
945 PrinterGfx::PSBinStartPath ()
946 {
947 #if (DEBUG_BINPATH == 1)
948     WritePS (mpPageBody, "% PSBinStartPath\n");
949 #else
950     WritePS (mpPageBody, "readpath\n" );
951 #endif
952 }
953 
954 void
955 PrinterGfx::PSBinEndPath ()
956 {
957 #if (DEBUG_BINPATH == 1)
958     WritePS (mpPageBody, "% PSBinEndPath\n");
959 #else
960     WritePS (mpPageBody, "~\n");
961 #endif
962 }
963 
964 void
965 PrinterGfx::PSBinCurrentPath (sal_uInt32 nPoints, const Point* pPath)
966 {
967     // create the path
968     Point     aPoint (0, 0);
969     sal_Int32 nColumn = 0;
970 
971     PSBinStartPath ();
972     PSBinMoveTo (*pPath, aPoint, nColumn);
973     for (unsigned int i = 1; i < nPoints; i++)
974         PSBinLineTo (pPath[i], aPoint, nColumn);
975     PSBinEndPath ();
976 }
977 
978 void
979 PrinterGfx::PSBinPath (const Point& rCurrent, Point& rOld,
980                        pspath_t eType, sal_Int32& nColumn)
981 {
982     sal_Char  pPath[48];
983     sal_Int32 nChar;
984 
985     // create the hex representation of the dx and dy path shift, store the field
986     // width as it is needed for the building the command
987     sal_Int32 nXPrec = getAlignedHexValueOf (rCurrent.X() - rOld.X(), pPath + 1);
988     sal_Int32 nYPrec = getAlignedHexValueOf (rCurrent.Y() - rOld.Y(), pPath + 1 + nXPrec);
989     pPath [ 1 + nXPrec + nYPrec ] = 0;
990 
991     // build the command, it is a char with bit represention 000cxxyy
992     // c represents the char, xx and yy repr. the field width of the dx and dy shift,
993     // dx and dy represent the number of bytes to read after the opcode
994     sal_Char cCmd = (eType == lineto ? (sal_Char)0x00 : (sal_Char)0x10);
995     switch (nYPrec)
996     {
997         case 2: break;
998         case 4: cCmd |= 0x01;   break;
999         case 6: cCmd |= 0x02;   break;
1000         case 8: cCmd |= 0x03;   break;
1001         default:    DBG_ERROR ("invalid x precision in binary path");
1002     }
1003     switch (nXPrec)
1004     {
1005         case 2: break;
1006         case 4: cCmd |= 0x04;   break;
1007         case 6: cCmd |= 0x08;   break;
1008         case 8: cCmd |= 0x0c;   break;
1009         default:    DBG_ERROR ("invalid y precision in binary path");
1010     }
1011     cCmd += 'A';
1012     pPath[0] = cCmd;
1013 
1014     // write the command to file,
1015     // line breaking at column nMaxTextColumn (80)
1016     nChar = 1 + nXPrec + nYPrec;
1017     if ((nColumn + nChar) > nMaxTextColumn)
1018     {
1019         sal_Int32 nSegment = nMaxTextColumn - nColumn;
1020 
1021         WritePS (mpPageBody, pPath, nSegment);
1022         WritePS (mpPageBody, "\n", 1);
1023         WritePS (mpPageBody, pPath + nSegment, nChar - nSegment);
1024 
1025         nColumn  = nChar - nSegment;
1026     }
1027     else
1028     {
1029         WritePS (mpPageBody, pPath, nChar);
1030 
1031         nColumn += nChar;
1032     }
1033 
1034     rOld = rCurrent;
1035 }
1036 
1037 void
1038 PrinterGfx::PSScale (double fScaleX, double fScaleY)
1039 {
1040     sal_Char  pScale [48];
1041     sal_Int32 nChar = 0;
1042 
1043     nChar  = psp::getValueOfDouble (pScale, fScaleX, 5);
1044     nChar += psp::appendStr        (" ", pScale + nChar);
1045     nChar += psp::getValueOfDouble (pScale + nChar, fScaleY, 5);
1046     nChar += psp::appendStr        (" scale\n", pScale + nChar);
1047 
1048     WritePS (mpPageBody, pScale);
1049 }
1050 
1051 /* psshowtext helper routines: draw an hex string for show/xshow */
1052 void
1053 PrinterGfx::PSHexString (const sal_uChar* pString, sal_Int16 nLen)
1054 {
1055     sal_Char pHexString [128];
1056     sal_Int32 nChar = 0;
1057 
1058     nChar = psp::appendStr ("<", pHexString);
1059     for (int i = 0; i < nLen; i++)
1060     {
1061         if (nChar >= (nMaxTextColumn - 1))
1062         {
1063             nChar += psp::appendStr ("\n", pHexString + nChar);
1064             WritePS (mpPageBody, pHexString, nChar);
1065             nChar = 0;
1066         }
1067         nChar += psp::getHexValueOf ((sal_Int32)pString[i], pHexString + nChar);
1068     }
1069 
1070     nChar += psp::appendStr (">\n", pHexString + nChar);
1071     WritePS (mpPageBody, pHexString, nChar);
1072 }
1073 
1074 /* psshowtext helper routines: draw an array for xshow ps operator */
1075 void
1076 PrinterGfx::PSDeltaArray (const sal_Int32 *pArray, sal_Int16 nEntries)
1077 {
1078     sal_Char pPSArray [128];
1079     sal_Int32 nChar = 0;
1080 
1081     nChar  = psp::appendStr  ("[", pPSArray + nChar);
1082     nChar += psp::getValueOf (pArray[0], pPSArray + nChar);
1083 
1084     for (int i = 1; i < nEntries; i++)
1085     {
1086         if (nChar >= (nMaxTextColumn - 1))
1087         {
1088             nChar += psp::appendStr ("\n", pPSArray + nChar);
1089             WritePS (mpPageBody, pPSArray, nChar);
1090             nChar = 0;
1091         }
1092 
1093         nChar += psp::appendStr  (" ", pPSArray + nChar);
1094         nChar += psp::getValueOf (pArray[i] - pArray[i-1], pPSArray + nChar);
1095     }
1096 
1097     nChar  += psp::appendStr (" 0]\n", pPSArray + nChar);
1098     WritePS (mpPageBody, pPSArray);
1099 }
1100 
1101 /* the DrawText equivalent, pDeltaArray may be NULL. For Type1 fonts or single byte
1102  * fonts in general nBytes and nGlyphs is the same. For printer resident Composite
1103  * fonts it may be different (these fonts may be SJIS encoded for example) */
1104 void
1105 PrinterGfx::PSShowText (const sal_uChar* pStr, sal_Int16 nGlyphs, sal_Int16 nBytes,
1106                         const sal_Int32* pDeltaArray)
1107 {
1108     PSSetColor (maTextColor);
1109     PSSetColor ();
1110     PSSetFont  ();
1111     // rotate the user coordinate system
1112     if (mnTextAngle != 0)
1113     {
1114         PSGSave ();
1115         PSRotate (mnTextAngle);
1116     }
1117 
1118     sal_Char pBuffer[256];
1119     if( maVirtualStatus.mbArtBold )
1120     {
1121         sal_Int32 nLW = maVirtualStatus.mnTextWidth;
1122         if( nLW == 0 )
1123             nLW = maVirtualStatus.mnTextHeight;
1124         else
1125             nLW = nLW < maVirtualStatus.mnTextHeight ? nLW : maVirtualStatus.mnTextHeight;
1126         psp::getValueOfDouble( pBuffer, (double)nLW / 30.0 );
1127     }
1128     // dispatch to the drawing method
1129     if (pDeltaArray == NULL)
1130     {
1131         PSHexString (pStr, nBytes);
1132 
1133         if( maVirtualStatus.mbArtBold )
1134         {
1135             WritePS( mpPageBody, pBuffer );
1136             WritePS( mpPageBody, " bshow\n" );
1137         }
1138         else
1139             WritePS (mpPageBody, "show\n");
1140     }
1141     else
1142     {
1143         PSHexString (pStr, nBytes);
1144         PSDeltaArray (pDeltaArray, nGlyphs - 1);
1145         if( maVirtualStatus.mbArtBold )
1146         {
1147             WritePS( mpPageBody, pBuffer );
1148             WritePS( mpPageBody, " bxshow\n" );
1149         }
1150         else
1151             WritePS (mpPageBody, "xshow\n");
1152     }
1153 
1154     // restore the user coordinate system
1155     if (mnTextAngle != 0)
1156         PSGRestore ();
1157 }
1158 
1159 void
1160 PrinterGfx::PSComment( const sal_Char* pComment )
1161 {
1162     const sal_Char* pLast = pComment;
1163     while( pComment && *pComment )
1164     {
1165         while( *pComment && *pComment != '\n' && *pComment != '\r' )
1166             pComment++;
1167         if( pComment - pLast > 1 )
1168         {
1169             WritePS( mpPageBody, "% ", 2 );
1170             WritePS( mpPageBody, pLast, pComment - pLast );
1171             WritePS( mpPageBody, "\n", 1 );
1172         }
1173         if( *pComment )
1174             pLast = ++pComment;
1175     }
1176 }
1177 
1178 sal_Bool
1179 PrinterGfx::DrawEPS( const Rectangle& rBoundingBox, void* pPtr, sal_uInt32 nSize )
1180 {
1181     if( nSize == 0 )
1182         return sal_True;
1183     if( ! mpPageBody )
1184         return sal_False;
1185 
1186     sal_Bool bSuccess = sal_False;
1187 
1188     // first search the BoundingBox of the EPS data
1189     SvMemoryStream aStream( pPtr, nSize, STREAM_READ );
1190     aStream.Seek( STREAM_SEEK_TO_BEGIN );
1191     ByteString aLine;
1192 
1193     ByteString aDocTitle;
1194     double fLeft = 0, fRight = 0, fTop = 0, fBottom = 0;
1195     bool bEndComments = false;
1196     while( ! aStream.IsEof()
1197            && ( ( fLeft == 0 && fRight == 0 && fTop == 0 && fBottom == 0 ) ||
1198                 ( aDocTitle.Len() == 0 && bEndComments == false ) )
1199            )
1200     {
1201         aStream.ReadLine( aLine );
1202         if( aLine.Len() > 1 && aLine.GetChar( 0 ) == '%' )
1203         {
1204             char cChar = aLine.GetChar(1);
1205             if( cChar == '%' )
1206             {
1207                 if( aLine.CompareIgnoreCaseToAscii( "%%BoundingBox:", 14 ) == COMPARE_EQUAL )
1208                 {
1209                     aLine = WhitespaceToSpace( aLine.GetToken( 1, ':' ) );
1210                     if( aLine.Len() && aLine.Search( "atend" ) == STRING_NOTFOUND )
1211                     {
1212                         fLeft   = StringToDouble( GetCommandLineToken( 0, aLine ) );
1213                         fBottom = StringToDouble( GetCommandLineToken( 1, aLine ) );
1214                         fRight  = StringToDouble( GetCommandLineToken( 2, aLine ) );
1215                         fTop    = StringToDouble( GetCommandLineToken( 3, aLine ) );
1216                     }
1217                 }
1218                 else if( aLine.CompareIgnoreCaseToAscii( "%%Title:", 8 ) == COMPARE_EQUAL )
1219                     aDocTitle = WhitespaceToSpace( aLine.Copy( 8 ) );
1220                 else if( aLine.CompareIgnoreCaseToAscii( "%%EndComments", 13 ) == COMPARE_EQUAL )
1221                     bEndComments = true;
1222             }
1223             else if( cChar == ' ' || cChar == '\t' || cChar == '\r' || cChar == '\n' )
1224                 bEndComments = true;
1225         }
1226         else
1227             bEndComments = true;
1228     }
1229 
1230     static sal_uInt16 nEps = 0;
1231     if( ! aDocTitle.Len() )
1232         aDocTitle = ByteString::CreateFromInt32( (sal_Int32)(nEps++) );
1233 
1234     if( fLeft != fRight && fTop != fBottom )
1235     {
1236         double fScaleX = (double)rBoundingBox.GetWidth()/(fRight-fLeft);
1237         double fScaleY = -(double)rBoundingBox.GetHeight()/(fTop-fBottom);
1238         Point aTranslatePoint( (int)(rBoundingBox.Left()-fLeft*fScaleX),
1239                                (int)(rBoundingBox.Bottom()+1-fBottom*fScaleY) );
1240         // prepare EPS
1241         WritePS( mpPageBody,
1242                  "/b4_Inc_state save def\n"
1243                  "/dict_count countdictstack def\n"
1244                  "/op_count count 1 sub def\n"
1245                  "userdict begin\n"
1246                  "/showpage {} def\n"
1247                  "0 setgray 0 setlinecap 1 setlinewidth 0 setlinejoin\n"
1248                  "10 setmiterlimit [] 0 setdash newpath\n"
1249                  "/languagelevel where\n"
1250                  "{pop languagelevel\n"
1251                  "1 ne\n"
1252                  "  {false setstrokeadjust false setoverprint\n"
1253                  "  } if\n"
1254                  "}if\n" );
1255         // set up clip path and scale
1256         BeginSetClipRegion( 1 );
1257         UnionClipRegion( rBoundingBox.Left(), rBoundingBox.Top(), rBoundingBox.GetWidth(), rBoundingBox.GetHeight() );
1258         EndSetClipRegion();
1259         PSTranslate( aTranslatePoint );
1260         PSScale( fScaleX, fScaleY );
1261 
1262         // DSC requires BeginDocument
1263         WritePS( mpPageBody, "%%BeginDocument: " );
1264         WritePS( mpPageBody, aDocTitle );
1265         WritePS( mpPageBody, "\n" );
1266 
1267         // write the EPS data
1268         sal_uInt64 nOutLength;
1269         mpPageBody->write( pPtr, nSize, nOutLength );
1270         bSuccess = nOutLength == nSize;
1271 
1272         // corresponding EndDocument
1273         if( ((char*)pPtr)[ nSize-1 ] != '\n' )
1274             WritePS( mpPageBody, "\n" );
1275         WritePS( mpPageBody, "%%EndDocument\n" );
1276 
1277         // clean up EPS
1278         WritePS( mpPageBody,
1279                  "count op_count sub {pop} repeat\n"
1280                  "countdictstack dict_count sub {end} repeat\n"
1281                  "b4_Inc_state restore\n" );
1282     }
1283     return bSuccess;
1284 }
1285