1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: common_gfx.cxx,v $
10 * $Revision: 1.20.18.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_vcl.hxx"
34 #include "psputil.hxx"
35 #include "glyphset.hxx"
37 #include "vcl/printergfx.hxx"
38 #include "vcl/printerjob.hxx"
39 #include "vcl/fontmanager.hxx"
40 #include "vcl/strhelper.hxx"
41 #include "vcl/printerinfomanager.hxx"
43 #include "tools/debug.hxx"
44 #include "tools/color.hxx"
45 #include "tools/poly.hxx"
49 static const sal_Int32 nMaxTextColumn
= 80;
51 GraphicsStatus::GraphicsStatus() :
61 * non graphics graphics routines
65 PrinterGfx::Init (PrinterJob
&rPrinterJob
)
67 mpPageHeader
= rPrinterJob
.GetCurrentPageHeader ();
68 mpPageBody
= rPrinterJob
.GetCurrentPageBody ();
69 mnDepth
= rPrinterJob
.GetDepth ();
70 mnPSLevel
= rPrinterJob
.GetPostscriptLevel ();
71 mbColor
= rPrinterJob
.IsColorPrinter ();
73 mnDpi
= rPrinterJob
.GetResolution();
74 rPrinterJob
.GetScale (mfScaleX
, mfScaleY
);
75 const PrinterInfo
& rInfo( PrinterInfoManager::get().getPrinterInfo( rPrinterJob
.GetPrinterName() ) );
76 if( mpFontSubstitutes
)
77 delete const_cast< ::std::hash_map
<fontID
,fontID
>* >(mpFontSubstitutes
);
78 if( rInfo
.m_bPerformFontSubstitution
)
79 mpFontSubstitutes
= new ::std::hash_map
< fontID
, fontID
>( rInfo
.m_aFontSubstitutions
);
81 mpFontSubstitutes
= NULL
;
82 mbUploadPS42Fonts
= rInfo
.m_pParser
? ( rInfo
.m_pParser
->isType42Capable() ? sal_True
: sal_False
) : sal_False
;
88 PrinterGfx::Init (const JobData
& rData
)
92 mnDepth
= rData
.m_nColorDepth
;
93 mnPSLevel
= rData
.m_nPSLevel
? rData
.m_nPSLevel
: (rData
.m_pParser
? rData
.m_pParser
->getLanguageLevel() : 2 );
94 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
) );
95 int nRes
= rData
.m_aContext
.getRenderResolution();
97 mfScaleX
= (double)72.0 / (double)mnDpi
;
98 mfScaleY
= (double)72.0 / (double)mnDpi
;
99 const PrinterInfo
& rInfo( PrinterInfoManager::get().getPrinterInfo( rData
.m_aPrinterName
) );
100 if( mpFontSubstitutes
)
101 delete const_cast< ::std::hash_map
<fontID
,fontID
>* >(mpFontSubstitutes
);
102 if( rInfo
.m_bPerformFontSubstitution
)
103 mpFontSubstitutes
= new ::std::hash_map
< fontID
, fontID
>( rInfo
.m_aFontSubstitutions
);
105 mpFontSubstitutes
= NULL
;
106 mbUploadPS42Fonts
= rInfo
.m_pParser
? ( rInfo
.m_pParser
->isType42Capable() ? sal_True
: sal_False
) : sal_False
;
112 PrinterGfx::GetResolution (sal_Int32
&rDpiX
, sal_Int32
&rDpiY
) const
119 PrinterGfx::GetBitCount ()
124 PrinterGfx::PrinterGfx() :
130 mbTextVertical (false),
131 mrFontMgr (PrintFontManager::get()),
132 mbCompressBmp (sal_True
),
133 maFillColor (0xff,0,0),
135 maLineColor (0, 0xff, 0),
136 mpFontSubstitutes( NULL
),
137 mbStrictSO52Compatibility( false )
139 maVirtualStatus
.mfLineWidth
= 1.0;
140 maVirtualStatus
.mnTextHeight
= 12;
141 maVirtualStatus
.mnTextWidth
= 0;
143 maGraphicsStack
.push_back( GraphicsStatus() );
146 PrinterGfx::~PrinterGfx()
149 * #95810# the original reasoning why mpFontSubstitutes is a pointer was
150 * that applications should release all PrinterGfx when printers change
151 * because they are really invalid; the corresponding printers may have
152 * changed their settings or even not exist anymore.
154 * Alas, this is not always done real time. So we keep a local copy of
155 * the font substitutes now in case of bad timing.
157 delete const_cast< ::std::hash_map
<fontID
,fontID
>* >(mpFontSubstitutes
);
166 maVirtualStatus
= GraphicsStatus();
167 maVirtualStatus
.mnTextHeight
= 12;
168 maVirtualStatus
.mnTextWidth
= 0;
169 maVirtualStatus
.mfLineWidth
= 1.0;
170 mbTextVertical
= false;
171 maLineColor
= PrinterColor();
172 maFillColor
= PrinterColor();
173 maTextColor
= PrinterColor();
174 mbCompressBmp
= sal_True
;
181 maClipRegion
.clear();
182 maGraphicsStack
.clear();
183 maGraphicsStack
.push_back( GraphicsStatus() );
187 * clip region handling
191 PrinterGfx::ResetClipRegion()
193 maClipRegion
.clear();
195 PSGSave (); // get "clean" clippath
199 PrinterGfx::BeginSetClipRegion( sal_uInt32
)
201 maClipRegion
.clear();
205 PrinterGfx::UnionClipRegion (sal_Int32 nX
,sal_Int32 nY
,sal_Int32 nDX
,sal_Int32 nDY
)
208 maClipRegion
.push_back (Rectangle(Point(nX
,nY
), Size(nDX
,nDY
)));
213 PrinterGfx::JoinVerticalClipRectangles( std::list
< Rectangle
>::iterator
& it
,
214 Point
& rOldPoint
, sal_Int32
& rColumn
)
216 sal_Bool bSuccess
= sal_False
;
218 std::list
< Rectangle
>::iterator tempit
, nextit
;
221 std::list
< Point
> leftside
, rightside
;
223 Rectangle
aLastRect( *it
);
224 leftside
.push_back( Point( it
->Left(), it
->Top() ) );
225 rightside
.push_back( Point( it
->Right()+1, it
->Top() ) );
226 while( nextit
!= maClipRegion
.end() )
230 if( nextit
->Top() == aLastRect
.Bottom()+1 )
233 ( nextit
->Left() >= aLastRect
.Left() && nextit
->Left() <= aLastRect
.Right() ) // left endpoint touches last rectangle
235 ( nextit
->Right() >= aLastRect
.Left() && nextit
->Right() <= aLastRect
.Right() ) // right endpoint touches last rectangle
237 ( nextit
->Left() <= aLastRect
.Left() && nextit
->Right() >= aLastRect
.Right() ) // whole line touches last rectangle
240 if( aLastRect
.GetHeight() > 1 ||
241 abs( aLastRect
.Left() - nextit
->Left() ) > 2 ||
242 abs( aLastRect
.Right() - nextit
->Right() ) > 2
245 leftside
.push_back( Point( aLastRect
.Left(), aLastRect
.Bottom()+1 ) );
246 rightside
.push_back( Point( aLastRect
.Right()+1, aLastRect
.Bottom()+1 ) );
249 leftside
.push_back( aLastRect
.TopLeft() );
250 rightside
.push_back( aLastRect
.TopRight() );
251 maClipRegion
.erase( nextit
);
256 if( leftside
.size() > 1 )
258 // push the last coordinates
259 leftside
.push_back( Point( aLastRect
.Left(), aLastRect
.Bottom()+1 ) );
260 rightside
.push_back( Point( aLastRect
.Right()+1, aLastRect
.Bottom()+1 ) );
262 // cool, we can concatenate rectangles
263 int nDX
= -65536, nDY
= 65536;
264 int nNewDX
= 0, nNewDY
= 0;
266 Point aLastPoint
= leftside
.front();
267 PSBinMoveTo (aLastPoint
, rOldPoint
, rColumn
);
268 leftside
.pop_front();
269 while( leftside
.begin() != leftside
.end() )
271 Point
aPoint (leftside
.front());
272 leftside
.pop_front();
273 // may have been the last one
274 if( leftside
.begin() != leftside
.end() )
276 nNewDX
= aPoint
.X() - aLastPoint
.X();
277 nNewDY
= aPoint
.Y() - aLastPoint
.Y();
278 if( nNewDX
== 0 && nDX
== 0 )
280 if( nDX
!= 0 && nNewDX
!= 0 &&
281 (double)nNewDY
/(double)nNewDX
== (double)nDY
/(double)nDX
)
284 PSBinLineTo (aPoint
, rOldPoint
, rColumn
);
288 aLastPoint
= rightside
.back();
291 PSBinLineTo (aLastPoint
, rOldPoint
, rColumn
);
292 rightside
.pop_back();
293 while( rightside
.begin() != rightside
.end() )
295 Point
aPoint (rightside
.back());
296 rightside
.pop_back();
297 if( rightside
.begin() != rightside
.end() )
299 nNewDX
= aPoint
.X() - aLastPoint
.X();
300 nNewDY
= aPoint
.Y() - aLastPoint
.Y();
301 if( nNewDX
== 0 && nDX
== 0 )
303 if( nDX
!= 0 && nNewDX
!= 0 &&
304 (double)nNewDY
/(double)nNewDX
== (double)nDY
/(double)nDX
)
307 PSBinLineTo (aPoint
, rOldPoint
, rColumn
);
312 maClipRegion
.erase( it
);
320 PrinterGfx::EndSetClipRegion()
323 PSGSave (); // get "clean" clippath
326 Point
aOldPoint (0, 0);
327 sal_Int32 nColumn
= 0;
329 std::list
< Rectangle
>::iterator it
= maClipRegion
.begin();
330 while( it
!= maClipRegion
.end() )
332 // try to concatenate adjacent rectangles
333 // first try in y direction, then in x direction
334 if( ! JoinVerticalClipRectangles( it
, aOldPoint
, nColumn
) )
336 // failed, so it is a single rectangle
337 PSBinMoveTo (it
->TopLeft(), aOldPoint
, nColumn
);
338 PSBinLineTo (Point( it
->Left(), it
->Bottom()+1 ), aOldPoint
, nColumn
);
339 PSBinLineTo (Point( it
->Right()+1, it
->Bottom()+1 ), aOldPoint
, nColumn
);
340 PSBinLineTo (Point( it
->Right()+1, it
->Top() ), aOldPoint
, nColumn
);
347 WritePS (mpPageBody
, "closepath clip newpath\n");
348 maClipRegion
.clear();
352 * draw graphic primitives
356 PrinterGfx::DrawRect (const Rectangle
& rRectangle
)
361 nChar
= psp::getValueOf (rRectangle
.TopLeft().X(), pRect
);
362 nChar
+= psp::appendStr (" ", pRect
+ nChar
);
363 nChar
+= psp::getValueOf (rRectangle
.TopLeft().Y(), pRect
+ nChar
);
364 nChar
+= psp::appendStr (" ", pRect
+ nChar
);
365 nChar
+= psp::getValueOf (rRectangle
.GetWidth(), pRect
+ nChar
);
366 nChar
+= psp::appendStr (" ", pRect
+ nChar
);
367 nChar
+= psp::getValueOf (rRectangle
.GetHeight(), pRect
+ nChar
);
368 nChar
+= psp::appendStr (" ", pRect
+ nChar
);
370 if( maFillColor
.Is() )
372 PSSetColor (maFillColor
);
374 WritePS (mpPageBody
, pRect
, nChar
);
375 WritePS (mpPageBody
, "rectfill\n");
377 if( maLineColor
.Is() )
379 PSSetColor (maLineColor
);
382 WritePS (mpPageBody
, pRect
, nChar
);
383 WritePS (mpPageBody
, "rectstroke\n");
388 PrinterGfx::DrawLine (const Point
& rFrom
, const Point
& rTo
)
390 if( maLineColor
.Is() )
392 PSSetColor (maLineColor
);
398 WritePS (mpPageBody
, "stroke\n" );
403 PrinterGfx::DrawPixel (const Point
& rPoint
, const PrinterColor
& rPixelColor
)
405 if( rPixelColor
.Is() )
407 PSSetColor (rPixelColor
);
411 PSLineTo (Point (rPoint
.X ()+1, rPoint
.Y ()));
412 PSLineTo (Point (rPoint
.X ()+1, rPoint
.Y ()+1));
413 PSLineTo (Point (rPoint
.X (), rPoint
.Y ()+1));
414 WritePS (mpPageBody
, "fill\n" );
419 PrinterGfx::DrawPolyLine (sal_uInt32 nPoints
, const Point
* pPath
)
421 if( maLineColor
.Is() && nPoints
&& pPath
)
423 PSSetColor (maLineColor
);
427 PSBinCurrentPath (nPoints
, pPath
);
429 WritePS (mpPageBody
, "stroke\n" );
434 PrinterGfx::DrawPolygon (sal_uInt32 nPoints
, const Point
* pPath
)
436 // premature end of operation
437 if (!(nPoints
> 1) || (pPath
== NULL
) || !(maFillColor
.Is() || maLineColor
.Is()))
441 Point
aPoint( 0, 0 );
442 sal_Int32
nColumn( 0 );
445 PSBinMoveTo( pPath
[0], aPoint
, nColumn
);
446 for( unsigned int n
= 1; n
< nPoints
; n
++ )
447 PSBinLineTo( pPath
[n
], aPoint
, nColumn
);
448 if( pPath
[0] != pPath
[nPoints
-1] )
449 PSBinLineTo( pPath
[0], aPoint
, nColumn
);
452 // fill the polygon first, then draw the border, note that fill and
453 // stroke reset the currentpath
455 // if fill and stroke, save the current path
456 if( maFillColor
.Is() && maLineColor
.Is())
459 if (maFillColor
.Is ())
461 PSSetColor (maFillColor
);
463 WritePS (mpPageBody
, "eofill\n");
466 // restore the current path
467 if( maFillColor
.Is() && maLineColor
.Is())
470 if (maLineColor
.Is ())
472 PSSetColor (maLineColor
);
475 WritePS (mpPageBody
, "stroke\n");
480 PrinterGfx::DrawPolyPolygon (sal_uInt32 nPoly
, const sal_uInt32
* pSizes
, const Point
** pPaths
)
483 if ( !nPoly
|| !pPaths
|| !(maFillColor
.Is() || maLineColor
.Is()))
488 for( unsigned int i
= 0; i
< nPoly
; i
++ )
490 Point
aPoint( 0, 0 );
491 sal_Int32
nColumn( 0 );
494 PSBinMoveTo( pPaths
[i
][0], aPoint
, nColumn
);
495 for( unsigned int n
= 1; n
< pSizes
[i
]; n
++ )
496 PSBinLineTo( pPaths
[i
][n
], aPoint
, nColumn
);
497 if( pPaths
[i
][0] != pPaths
[i
][pSizes
[i
]-1] )
498 PSBinLineTo( pPaths
[i
][0], aPoint
, nColumn
);
502 // if eofill and stroke, save the current path
503 if( maFillColor
.Is() && maLineColor
.Is())
507 if( maFillColor
.Is() )
509 PSSetColor (maFillColor
);
511 WritePS (mpPageBody
, "eofill\n");
514 // restore the current path
515 if( maFillColor
.Is() && maLineColor
.Is())
519 if( maLineColor
.Is() )
521 PSSetColor (maLineColor
);
524 WritePS (mpPageBody
, "stroke\n");
529 * Bezier Polygon Drawing methods.
533 PrinterGfx::DrawPolyLineBezier (sal_uInt32 nPoints
, const Point
* pPath
, const BYTE
* pFlgAry
)
535 const sal_uInt32 nBezString
= 1024;
536 sal_Char pString
[nBezString
];
538 if ( maLineColor
.Is() && nPoints
&& pPath
)
540 PSSetColor (maLineColor
);
544 if (pFlgAry
[0] != POLY_NORMAL
) //There must be a starting point to moveto
550 snprintf(pString
, nBezString
, "%li %li moveto\n", pPath
[0].X(), pPath
[0].Y());
551 WritePS(mpPageBody
, pString
);
554 // Handle the drawing of mixed lines mixed with curves
555 // - a normal point followed by a normal point is a line
556 // - a normal point followed by 2 control points and a normal point is a curve
557 for (unsigned int i
=1; i
<nPoints
;)
559 if (pFlgAry
[i
+1] != POLY_CONTROL
) //If the next point is a POLY_NORMAL, we're drawing a line
561 if (i
+1 >= nPoints
) return; //Make sure we don't pass the end of the array
562 snprintf(pString
, nBezString
, "%li %li lineto\n", pPath
[i
].X(), pPath
[i
].Y());
565 else //Otherwise we're drawing a spline
567 if (i
+3 >= nPoints
) return; //Make sure we don't pass the end of the array
568 snprintf(pString
, nBezString
, "%li %li %li %li %li %li curveto\n",
569 pPath
[i
+1].X(), pPath
[i
+1].Y(),
570 pPath
[i
+2].X(), pPath
[i
+2].Y(),
571 pPath
[i
+3].X(), pPath
[i
+3].Y());
574 WritePS(mpPageBody
, pString
);
578 // if eofill and stroke, save the current path
579 if( maFillColor
.Is() && maLineColor
.Is())
583 if( maFillColor
.Is() )
585 PSSetColor (maFillColor
);
587 WritePS (mpPageBody
, "eofill\n");
590 // restore the current path
591 if( maFillColor
.Is() && maLineColor
.Is())
595 if( maLineColor
.Is() )
597 PSSetColor (maLineColor
);
600 WritePS (mpPageBody
, "stroke\n");
605 PrinterGfx::DrawPolygonBezier (sal_uInt32 nPoints
, const Point
* pPath
, const BYTE
* pFlgAry
)
607 const sal_uInt32 nBezString
= 1024;
608 sal_Char pString
[nBezString
];
609 // premature end of operation
610 if (!(nPoints
> 1) || (pPath
== NULL
) || !(maFillColor
.Is() || maLineColor
.Is()))
613 snprintf(pString
, nBezString
, "%li %li moveto\n", pPath
[0].X(), pPath
[0].Y());
614 WritePS(mpPageBody
, pString
); //Move to the starting point for the PolyPoygon
615 for (unsigned int i
=1; i
< nPoints
;)
617 if (pFlgAry
[i
] != POLY_CONTROL
)
619 snprintf(pString
, nBezString
, "%li %li lineto\n", pPath
[i
].X(), pPath
[i
].Y());
620 WritePS(mpPageBody
, pString
);
626 return; //Error: wrong sequence of contol/normal points somehow
627 if ((pFlgAry
[i
] == POLY_CONTROL
) && (pFlgAry
[i
+1] == POLY_CONTROL
) &&
628 (pFlgAry
[i
+2] != POLY_CONTROL
))
630 snprintf(pString
, nBezString
, "%li %li %li %li %li %li curveto\n",
631 pPath
[i
].X(), pPath
[i
].Y(),
632 pPath
[i
+1].X(), pPath
[i
+1].Y(),
633 pPath
[i
+2].X(), pPath
[i
+2].Y());
634 WritePS(mpPageBody
, pString
);
638 fprintf(stderr
, "Strange output\n");
644 // if fill and stroke, save the current path
645 if( maFillColor
.Is() && maLineColor
.Is())
648 if (maFillColor
.Is ())
650 PSSetColor (maFillColor
);
652 WritePS (mpPageBody
, "eofill\n");
655 // restore the current path
656 if( maFillColor
.Is() && maLineColor
.Is())
661 PrinterGfx::DrawPolyPolygonBezier (sal_uInt32 nPoly
, const sal_uInt32
* pPoints
, const Point
* const * pPtAry
, const BYTE
* const* pFlgAry
)
663 const sal_uInt32 nBezString
= 1024;
664 sal_Char pString
[nBezString
];
665 if ( !nPoly
|| !pPtAry
|| !pPoints
|| !(maFillColor
.Is() || maLineColor
.Is()))
669 for (unsigned int i
=0; i
<nPoly
;i
++)
671 sal_uInt32 nPoints
= pPoints
[i
];
672 // #112689# sanity check
673 if( nPoints
== 0 || pPtAry
[i
] == NULL
)
676 snprintf(pString
, nBezString
, "%li %li moveto\n", pPtAry
[i
][0].X(), pPtAry
[i
][0].Y()); //Move to the starting point
677 WritePS(mpPageBody
, pString
);
678 for (unsigned int j
=1; j
< nPoints
;)
680 // if no flag array exists for this polygon, then it must be a regular
681 // polygon without beziers
682 if ( ! pFlgAry
[i
] || pFlgAry
[i
][j
] != POLY_CONTROL
)
684 snprintf(pString
, nBezString
, "%li %li lineto\n", pPtAry
[i
][j
].X(), pPtAry
[i
][j
].Y());
685 WritePS(mpPageBody
, pString
);
691 break; //Error: wrong sequence of contol/normal points somehow
692 if ((pFlgAry
[i
][j
] == POLY_CONTROL
) && (pFlgAry
[i
][j
+1] == POLY_CONTROL
) && (pFlgAry
[i
][j
+2] != POLY_CONTROL
))
694 snprintf(pString
, nBezString
, "%li %li %li %li %li %li curveto\n",
695 pPtAry
[i
][j
].X(), pPtAry
[i
][j
].Y(),
696 pPtAry
[i
][j
+1].X(), pPtAry
[i
][j
+1].Y(),
697 pPtAry
[i
][j
+2].X(), pPtAry
[i
][j
+2].Y());
698 WritePS(mpPageBody
, pString
);
702 #if OSL_DEBUG_LEVEL > 1
703 fprintf(stderr
, "Strange output\n");
711 // if fill and stroke, save the current path
712 if( maFillColor
.Is() && maLineColor
.Is())
715 if (maFillColor
.Is ())
717 PSSetColor (maFillColor
);
719 WritePS (mpPageBody
, "eofill\n");
722 // restore the current path
723 if( maFillColor
.Is() && maLineColor
.Is())
729 * postscript generating routines
732 PrinterGfx::PSGSave ()
734 WritePS (mpPageBody
, "gsave\n" );
735 GraphicsStatus aNewState
;
736 if( maGraphicsStack
.begin() != maGraphicsStack
.end() )
737 aNewState
= maGraphicsStack
.front();
738 maGraphicsStack
.push_front( aNewState
);
742 PrinterGfx::PSGRestore ()
744 WritePS (mpPageBody
, "grestore\n" );
745 if( maGraphicsStack
.begin() == maGraphicsStack
.end() )
746 WritePS (mpPageBody
, "Error: too many grestores\n" );
748 maGraphicsStack
.pop_front();
752 PrinterGfx::PSSetLineWidth ()
754 if( currentState().mfLineWidth
!= maVirtualStatus
.mfLineWidth
)
759 currentState().mfLineWidth
= maVirtualStatus
.mfLineWidth
;
760 nChar
= psp::getValueOfDouble (pBuffer
, maVirtualStatus
.mfLineWidth
, 5);
761 nChar
+= psp::appendStr (" setlinewidth\n", pBuffer
+ nChar
);
762 WritePS (mpPageBody
, pBuffer
, nChar
);
767 PrinterGfx::PSSetColor ()
769 PrinterColor
& rColor( maVirtualStatus
.maColor
);
771 if( currentState().maColor
!= rColor
)
773 currentState().maColor
= rColor
;
780 nChar
= psp::getValueOfDouble (pBuffer
,
781 (double)rColor
.GetRed() / 255.0, 5);
782 nChar
+= psp::appendStr (" ", pBuffer
+ nChar
);
783 nChar
+= psp::getValueOfDouble (pBuffer
+ nChar
,
784 (double)rColor
.GetGreen() / 255.0, 5);
785 nChar
+= psp::appendStr (" ", pBuffer
+ nChar
);
786 nChar
+= psp::getValueOfDouble (pBuffer
+ nChar
,
787 (double)rColor
.GetBlue() / 255.0, 5);
788 nChar
+= psp::appendStr (" setrgbcolor\n", pBuffer
+ nChar
);
792 Color
aColor( rColor
.GetRed(), rColor
.GetGreen(), rColor
.GetBlue() );
793 sal_uInt8 nCol
= aColor
.GetLuminance();
794 nChar
= psp::getValueOfDouble( pBuffer
, (double)nCol
/ 255.0, 5 );
795 nChar
+= psp::appendStr( " setgray\n", pBuffer
+ nChar
);
798 WritePS (mpPageBody
, pBuffer
, nChar
);
803 PrinterGfx::PSSetFont ()
805 GraphicsStatus
& rCurrent( currentState() );
806 if( maVirtualStatus
.maFont
!= rCurrent
.maFont
||
807 maVirtualStatus
.mnTextHeight
!= rCurrent
.mnTextHeight
||
808 maVirtualStatus
.maEncoding
!= rCurrent
.maEncoding
||
809 maVirtualStatus
.mnTextWidth
!= rCurrent
.mnTextWidth
||
810 maVirtualStatus
.mbArtBold
!= rCurrent
.mbArtBold
||
811 maVirtualStatus
.mbArtItalic
!= rCurrent
.mbArtItalic
814 rCurrent
.maFont
= maVirtualStatus
.maFont
;
815 rCurrent
.maEncoding
= maVirtualStatus
.maEncoding
;
816 rCurrent
.mnTextWidth
= maVirtualStatus
.mnTextWidth
;
817 rCurrent
.mnTextHeight
= maVirtualStatus
.mnTextHeight
;
818 rCurrent
.mbArtItalic
= maVirtualStatus
.mbArtItalic
;
819 rCurrent
.mbArtBold
= maVirtualStatus
.mbArtBold
;
821 sal_Int32 nTextHeight
= rCurrent
.mnTextHeight
;
822 sal_Int32 nTextWidth
= rCurrent
.mnTextWidth
? rCurrent
.mnTextWidth
823 : rCurrent
.mnTextHeight
;
825 sal_Char pSetFont
[256];
828 // postscript based fonts need reencoding
829 if ( ( rCurrent
.maEncoding
== RTL_TEXTENCODING_MS_1252
)
830 || ( rCurrent
.maEncoding
== RTL_TEXTENCODING_ISO_8859_1
)
831 || ( rCurrent
.maEncoding
>= RTL_TEXTENCODING_USER_START
832 && rCurrent
.maEncoding
<= RTL_TEXTENCODING_USER_END
)
835 rtl::OString aReencodedFont
=
836 psp::GlyphSet::GetReencodedFontName (rCurrent
.maEncoding
,
839 nChar
+= psp::appendStr ("(", pSetFont
+ nChar
);
840 nChar
+= psp::appendStr (aReencodedFont
.getStr(),
842 nChar
+= psp::appendStr (") cvn findfont ",
846 // tt based fonts mustn't reencode, the encoding is implied by the fontname
847 // same for symbol type1 fonts, dont try to touch them
849 nChar
+= psp::appendStr ("(", pSetFont
+ nChar
);
850 nChar
+= psp::appendStr (rCurrent
.maFont
.getStr(),
852 nChar
+= psp::appendStr (") cvn findfont ",
856 if( ! rCurrent
.mbArtItalic
)
858 nChar
+= psp::getValueOf (nTextWidth
, pSetFont
+ nChar
);
859 nChar
+= psp::appendStr (" ", pSetFont
+ nChar
);
860 nChar
+= psp::getValueOf (-nTextHeight
, pSetFont
+ nChar
);
861 nChar
+= psp::appendStr (" matrix scale makefont setfont\n", pSetFont
+ nChar
);
863 else // skew 15 degrees to right
865 nChar
+= psp::appendStr ( " [", pSetFont
+ nChar
);
866 nChar
+= psp::getValueOf (nTextWidth
, pSetFont
+ nChar
);
867 nChar
+= psp::appendStr (" 0 ", pSetFont
+ nChar
);
868 nChar
+= psp::getValueOfDouble (pSetFont
+ nChar
, 0.27*(double)nTextWidth
, 3 );
869 nChar
+= psp::appendStr ( " ", pSetFont
+ nChar
);
870 nChar
+= psp::getValueOf (-nTextHeight
, pSetFont
+ nChar
);
872 nChar
+= psp::appendStr (" 0 0] makefont setfont\n", pSetFont
+ nChar
);
875 WritePS (mpPageBody
, pSetFont
);
880 PrinterGfx::PSRotate (sal_Int32 nAngle
)
882 sal_Int32 nPostScriptAngle
= -nAngle
;
883 while( nPostScriptAngle
< 0 )
884 nPostScriptAngle
+= 3600;
886 if (nPostScriptAngle
== 0)
889 sal_Int32 nFullAngle
= nPostScriptAngle
/ 10;
890 sal_Int32 nTenthAngle
= nPostScriptAngle
% 10;
892 sal_Char pRotate
[48];
895 nChar
= psp::getValueOf (nFullAngle
, pRotate
);
896 nChar
+= psp::appendStr (".", pRotate
+ nChar
);
897 nChar
+= psp::getValueOf (nTenthAngle
, pRotate
+ nChar
);
898 nChar
+= psp::appendStr (" rotate\n", pRotate
+ nChar
);
900 WritePS (mpPageBody
, pRotate
);
904 PrinterGfx::PSPointOp (const Point
& rPoint
, const sal_Char
* pOperator
)
906 sal_Char pPSCommand
[48];
909 nChar
= psp::getValueOf (rPoint
.X(), pPSCommand
);
910 nChar
+= psp::appendStr (" ", pPSCommand
+ nChar
);
911 nChar
+= psp::getValueOf (rPoint
.Y(), pPSCommand
+ nChar
);
912 nChar
+= psp::appendStr (" ", pPSCommand
+ nChar
);
913 nChar
+= psp::appendStr (pOperator
, pPSCommand
+ nChar
);
914 nChar
+= psp::appendStr ("\n", pPSCommand
+ nChar
);
916 DBG_ASSERT (nChar
< 48, "Buffer overflow in PSPointOp");
918 WritePS (mpPageBody
, pPSCommand
);
922 PrinterGfx::PSTranslate (const Point
& rPoint
)
924 PSPointOp (rPoint
, "translate");
928 PrinterGfx::PSMoveTo (const Point
& rPoint
)
930 PSPointOp (rPoint
, "moveto");
934 PrinterGfx::PSLineTo (const Point
& rPoint
)
936 PSPointOp (rPoint
, "lineto");
940 PrinterGfx::PSRMoveTo (sal_Int32 nDx
, sal_Int32 nDy
)
942 Point
aPoint(nDx
, nDy
);
943 PSPointOp (aPoint
, "rmoveto");
946 /* get a compressed representation of the path information */
948 #define DEBUG_BINPATH 0
951 PrinterGfx::PSBinLineTo (const Point
& rCurrent
, Point
& rOld
, sal_Int32
& nColumn
)
953 #if (DEBUG_BINPATH == 1)
956 PSBinPath (rCurrent
, rOld
, lineto
, nColumn
);
961 PrinterGfx::PSBinMoveTo (const Point
& rCurrent
, Point
& rOld
, sal_Int32
& nColumn
)
963 #if (DEBUG_BINPATH == 1)
966 PSBinPath (rCurrent
, rOld
, moveto
, nColumn
);
971 PrinterGfx::PSBinStartPath ()
973 #if (DEBUG_BINPATH == 1)
974 WritePS (mpPageBody
, "% PSBinStartPath\n");
976 WritePS (mpPageBody
, "readpath\n" );
981 PrinterGfx::PSBinEndPath ()
983 #if (DEBUG_BINPATH == 1)
984 WritePS (mpPageBody
, "% PSBinEndPath\n");
986 WritePS (mpPageBody
, "~\n");
991 PrinterGfx::PSBinCurrentPath (sal_uInt32 nPoints
, const Point
* pPath
)
995 sal_Int32 nColumn
= 0;
998 PSBinMoveTo (*pPath
, aPoint
, nColumn
);
999 for (unsigned int i
= 1; i
< nPoints
; i
++)
1000 PSBinLineTo (pPath
[i
], aPoint
, nColumn
);
1005 PrinterGfx::PSBinPath (const Point
& rCurrent
, Point
& rOld
,
1006 pspath_t eType
, sal_Int32
& nColumn
)
1011 // create the hex representation of the dx and dy path shift, store the field
1012 // width as it is needed for the building the command
1013 sal_Int32 nXPrec
= getAlignedHexValueOf (rCurrent
.X() - rOld
.X(), pPath
+ 1);
1014 sal_Int32 nYPrec
= getAlignedHexValueOf (rCurrent
.Y() - rOld
.Y(), pPath
+ 1 + nXPrec
);
1015 pPath
[ 1 + nXPrec
+ nYPrec
] = 0;
1017 // build the command, it is a char with bit represention 000cxxyy
1018 // c represents the char, xx and yy repr. the field width of the dx and dy shift,
1019 // dx and dy represent the number of bytes to read after the opcode
1020 sal_Char cCmd
= (eType
== lineto
? (sal_Char
)0x00 : (sal_Char
)0x10);
1024 case 4: cCmd
|= 0x01; break;
1025 case 6: cCmd
|= 0x02; break;
1026 case 8: cCmd
|= 0x03; break;
1027 default: DBG_ERROR ("invalid x precision in binary path");
1032 case 4: cCmd
|= 0x04; break;
1033 case 6: cCmd
|= 0x08; break;
1034 case 8: cCmd
|= 0x0c; break;
1035 default: DBG_ERROR ("invalid y precision in binary path");
1040 // write the command to file,
1041 // line breaking at column nMaxTextColumn (80)
1042 nChar
= 1 + nXPrec
+ nYPrec
;
1043 if ((nColumn
+ nChar
) > nMaxTextColumn
)
1045 sal_Int32 nSegment
= nMaxTextColumn
- nColumn
;
1047 WritePS (mpPageBody
, pPath
, nSegment
);
1048 WritePS (mpPageBody
, "\n", 1);
1049 WritePS (mpPageBody
, pPath
+ nSegment
, nChar
- nSegment
);
1051 nColumn
= nChar
- nSegment
;
1055 WritePS (mpPageBody
, pPath
, nChar
);
1064 PrinterGfx::PSScale (double fScaleX
, double fScaleY
)
1066 sal_Char pScale
[48];
1067 sal_Int32 nChar
= 0;
1069 nChar
= psp::getValueOfDouble (pScale
, fScaleX
, 5);
1070 nChar
+= psp::appendStr (" ", pScale
+ nChar
);
1071 nChar
+= psp::getValueOfDouble (pScale
+ nChar
, fScaleY
, 5);
1072 nChar
+= psp::appendStr (" scale\n", pScale
+ nChar
);
1074 WritePS (mpPageBody
, pScale
);
1077 /* psshowtext helper routines: draw an hex string for show/xshow */
1079 PrinterGfx::PSHexString (const sal_uChar
* pString
, sal_Int16 nLen
)
1081 sal_Char pHexString
[128];
1082 sal_Int32 nChar
= 0;
1084 nChar
= psp::appendStr ("<", pHexString
);
1085 for (int i
= 0; i
< nLen
; i
++)
1087 if (nChar
>= (nMaxTextColumn
- 1))
1089 nChar
+= psp::appendStr ("\n", pHexString
+ nChar
);
1090 WritePS (mpPageBody
, pHexString
, nChar
);
1093 nChar
+= psp::getHexValueOf ((sal_Int32
)pString
[i
], pHexString
+ nChar
);
1096 nChar
+= psp::appendStr (">\n", pHexString
+ nChar
);
1097 WritePS (mpPageBody
, pHexString
, nChar
);
1100 /* psshowtext helper routines: draw an array for xshow ps operator */
1102 PrinterGfx::PSDeltaArray (const sal_Int32
*pArray
, sal_Int16 nEntries
)
1104 sal_Char pPSArray
[128];
1105 sal_Int32 nChar
= 0;
1107 nChar
= psp::appendStr ("[", pPSArray
+ nChar
);
1108 nChar
+= psp::getValueOf (pArray
[0], pPSArray
+ nChar
);
1110 for (int i
= 1; i
< nEntries
; i
++)
1112 if (nChar
>= (nMaxTextColumn
- 1))
1114 nChar
+= psp::appendStr ("\n", pPSArray
+ nChar
);
1115 WritePS (mpPageBody
, pPSArray
, nChar
);
1119 nChar
+= psp::appendStr (" ", pPSArray
+ nChar
);
1120 nChar
+= psp::getValueOf (pArray
[i
] - pArray
[i
-1], pPSArray
+ nChar
);
1123 nChar
+= psp::appendStr (" 0]\n", pPSArray
+ nChar
);
1124 WritePS (mpPageBody
, pPSArray
);
1127 /* the DrawText equivalent, pDeltaArray may be NULL. For Type1 fonts or single byte
1128 * fonts in general nBytes and nGlyphs is the same. For printer resident Composite
1129 * fonts it may be different (these fonts may be SJIS encoded for example) */
1131 PrinterGfx::PSShowText (const sal_uChar
* pStr
, sal_Int16 nGlyphs
, sal_Int16 nBytes
,
1132 const sal_Int32
* pDeltaArray
)
1134 PSSetColor (maTextColor
);
1137 // rotate the user coordinate system
1138 if (mnTextAngle
!= 0)
1141 PSRotate (mnTextAngle
);
1144 sal_Char pBuffer
[256];
1145 if( maVirtualStatus
.mbArtBold
)
1147 sal_Int32 nLW
= maVirtualStatus
.mnTextWidth
;
1149 nLW
= maVirtualStatus
.mnTextHeight
;
1151 nLW
= nLW
< maVirtualStatus
.mnTextHeight
? nLW
: maVirtualStatus
.mnTextHeight
;
1152 psp::getValueOfDouble( pBuffer
, (double)nLW
/ 30.0 );
1154 // dispatch to the drawing method
1155 if (pDeltaArray
== NULL
)
1157 PSHexString (pStr
, nBytes
);
1159 if( maVirtualStatus
.mbArtBold
)
1161 WritePS( mpPageBody
, pBuffer
);
1162 WritePS( mpPageBody
, " bshow\n" );
1165 WritePS (mpPageBody
, "show\n");
1169 PSHexString (pStr
, nBytes
);
1170 PSDeltaArray (pDeltaArray
, nGlyphs
- 1);
1171 if( maVirtualStatus
.mbArtBold
)
1173 WritePS( mpPageBody
, pBuffer
);
1174 WritePS( mpPageBody
, " bxshow\n" );
1177 WritePS (mpPageBody
, "xshow\n");
1180 // restore the user coordinate system
1181 if (mnTextAngle
!= 0)
1186 PrinterGfx::PSComment( const sal_Char
* pComment
)
1188 const sal_Char
* pLast
= pComment
;
1189 while( pComment
&& *pComment
)
1191 while( *pComment
&& *pComment
!= '\n' && *pComment
!= '\r' )
1193 if( pComment
- pLast
> 1 )
1195 WritePS( mpPageBody
, "% ", 2 );
1196 WritePS( mpPageBody
, pLast
, pComment
- pLast
);
1197 WritePS( mpPageBody
, "\n", 1 );
1205 PrinterGfx::DrawEPS( const Rectangle
& rBoundingBox
, void* pPtr
, sal_uInt32 nSize
)
1212 sal_Bool bSuccess
= sal_False
;
1214 // first search the BoundingBox of the EPS data
1215 SvMemoryStream
aStream( pPtr
, nSize
, STREAM_READ
);
1216 aStream
.Seek( STREAM_SEEK_TO_BEGIN
);
1219 ByteString aDocTitle
;
1220 double fLeft
= 0, fRight
= 0, fTop
= 0, fBottom
= 0;
1221 bool bEndComments
= false;
1222 while( ! aStream
.IsEof()
1223 && ( ( fLeft
== 0 && fRight
== 0 && fTop
== 0 && fBottom
== 0 ) ||
1224 ( aDocTitle
.Len() == 0 && bEndComments
== false ) )
1227 aStream
.ReadLine( aLine
);
1228 if( aLine
.Len() > 1 && aLine
.GetChar( 0 ) == '%' )
1230 char cChar
= aLine
.GetChar(1);
1233 if( aLine
.CompareIgnoreCaseToAscii( "%%BoundingBox:", 14 ) == COMPARE_EQUAL
)
1235 aLine
= WhitespaceToSpace( aLine
.GetToken( 1, ':' ) );
1236 if( aLine
.Len() && aLine
.Search( "atend" ) == STRING_NOTFOUND
)
1238 fLeft
= StringToDouble( GetCommandLineToken( 0, aLine
) );
1239 fBottom
= StringToDouble( GetCommandLineToken( 1, aLine
) );
1240 fRight
= StringToDouble( GetCommandLineToken( 2, aLine
) );
1241 fTop
= StringToDouble( GetCommandLineToken( 3, aLine
) );
1244 else if( aLine
.CompareIgnoreCaseToAscii( "%%Title:", 8 ) == COMPARE_EQUAL
)
1245 aDocTitle
= WhitespaceToSpace( aLine
.Copy( 8 ) );
1246 else if( aLine
.CompareIgnoreCaseToAscii( "%%EndComments", 13 ) == COMPARE_EQUAL
)
1247 bEndComments
= true;
1249 else if( cChar
== ' ' || cChar
== '\t' || cChar
== '\r' || cChar
== '\n' )
1250 bEndComments
= true;
1253 bEndComments
= true;
1256 static sal_uInt16 nEps
= 0;
1257 if( ! aDocTitle
.Len() )
1258 aDocTitle
= ByteString::CreateFromInt32( (sal_Int32
)(nEps
++) );
1260 if( fLeft
!= fRight
&& fTop
!= fBottom
)
1262 double fScaleX
= (double)rBoundingBox
.GetWidth()/(fRight
-fLeft
);
1263 double fScaleY
= -(double)rBoundingBox
.GetHeight()/(fTop
-fBottom
);
1264 Point
aTranslatePoint( (int)(rBoundingBox
.Left()-fLeft
*fScaleX
),
1265 (int)(rBoundingBox
.Bottom()+1-fBottom
*fScaleY
) );
1267 WritePS( mpPageBody
,
1268 "/b4_Inc_state save def\n"
1269 "/dict_count countdictstack def\n"
1270 "/op_count count 1 sub def\n"
1272 "/showpage {} def\n"
1273 "0 setgray 0 setlinecap 1 setlinewidth 0 setlinejoin\n"
1274 "10 setmiterlimit [] 0 setdash newpath\n"
1275 "/languagelevel where\n"
1276 "{pop languagelevel\n"
1278 " {false setstrokeadjust false setoverprint\n"
1281 // set up clip path and scale
1282 BeginSetClipRegion( 1 );
1283 UnionClipRegion( rBoundingBox
.Left(), rBoundingBox
.Top(), rBoundingBox
.GetWidth(), rBoundingBox
.GetHeight() );
1285 PSTranslate( aTranslatePoint
);
1286 PSScale( fScaleX
, fScaleY
);
1288 // DSC requires BeginDocument
1289 WritePS( mpPageBody
, "%%BeginDocument: " );
1290 WritePS( mpPageBody
, aDocTitle
);
1291 WritePS( mpPageBody
, "\n" );
1293 // write the EPS data
1294 sal_uInt64 nOutLength
;
1295 mpPageBody
->write( pPtr
, nSize
, nOutLength
);
1296 bSuccess
= nOutLength
== nSize
;
1298 // corresponding EndDocument
1299 if( ((char*)pPtr
)[ nSize
-1 ] != '\n' )
1300 WritePS( mpPageBody
, "\n" );
1301 WritePS( mpPageBody
, "%%EndDocument\n" );
1304 WritePS( mpPageBody
,
1305 "count op_count sub {pop} repeat\n"
1306 "countdictstack dict_count sub {end} repeat\n"
1307 "b4_Inc_state restore\n" );