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