1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
24 #include "psputil.hxx"
25 #include "glyphset.hxx"
27 #include "generic/printergfx.hxx"
28 #include "generic/printerjob.hxx"
29 #include "fontmanager.hxx"
30 #include "vcl/strhelper.hxx"
31 #include "vcl/printerinfomanager.hxx"
33 #include "tools/debug.hxx"
34 #include "tools/color.hxx"
35 #include "tools/poly.hxx"
39 static const sal_Int32 nMaxTextColumn
= 80;
41 GraphicsStatus::GraphicsStatus() :
42 maEncoding(RTL_TEXTENCODING_DONTKNOW
),
52 * non graphics graphics routines
56 PrinterGfx::Init (PrinterJob
&rPrinterJob
)
58 mpPageHeader
= rPrinterJob
.GetCurrentPageHeader ();
59 mpPageBody
= rPrinterJob
.GetCurrentPageBody ();
60 mnDepth
= rPrinterJob
.GetDepth ();
61 mnPSLevel
= rPrinterJob
.GetPostscriptLevel ();
62 mbColor
= rPrinterJob
.IsColorPrinter ();
64 mnDpi
= rPrinterJob
.GetResolution();
65 rPrinterJob
.GetScale (mfScaleX
, mfScaleY
);
66 const PrinterInfo
& rInfo( PrinterInfoManager::get().getPrinterInfo( rPrinterJob
.GetPrinterName() ) );
67 mbUploadPS42Fonts
= rInfo
.m_pParser
&& rInfo
.m_pParser
->isType42Capable();
73 PrinterGfx::Init (const JobData
& rData
)
77 mnDepth
= rData
.m_nColorDepth
;
78 mnPSLevel
= rData
.m_nPSLevel
? rData
.m_nPSLevel
: (rData
.m_pParser
? rData
.m_pParser
->getLanguageLevel() : 2 );
79 mbColor
= rData
.m_nColorDevice
? ( rData
.m_nColorDevice
!= -1 ) : ( rData
.m_pParser
== nullptr || rData
.m_pParser
->isColorDevice() );
80 int nRes
= rData
.m_aContext
.getRenderResolution();
82 mfScaleX
= (double)72.0 / (double)mnDpi
;
83 mfScaleY
= (double)72.0 / (double)mnDpi
;
84 const PrinterInfo
& rInfo( PrinterInfoManager::get().getPrinterInfo( rData
.m_aPrinterName
) );
85 mbUploadPS42Fonts
= rInfo
.m_pParser
&& rInfo
.m_pParser
->isType42Capable();
91 PrinterGfx::PrinterGfx()
98 , mbUploadPS42Fonts(false)
104 , mbTextVertical(false)
105 , mrFontMgr(PrintFontManager::get())
106 , mbCompressBmp(true)
107 , maFillColor(0xff,0,0)
109 , maLineColor(0, 0xff, 0)
111 maVirtualStatus
.mfLineWidth
= 1.0;
112 maVirtualStatus
.mnTextHeight
= 12;
113 maVirtualStatus
.mnTextWidth
= 0;
115 maGraphicsStack
.push_back( GraphicsStatus() );
118 PrinterGfx::~PrinterGfx()
128 maVirtualStatus
= GraphicsStatus();
129 maVirtualStatus
.mnTextHeight
= 12;
130 maVirtualStatus
.mnTextWidth
= 0;
131 maVirtualStatus
.mfLineWidth
= 1.0;
132 mbTextVertical
= false;
133 maLineColor
= PrinterColor();
134 maFillColor
= PrinterColor();
135 maTextColor
= PrinterColor();
136 mbCompressBmp
= true;
143 maClipRegion
.clear();
144 maGraphicsStack
.clear();
145 maGraphicsStack
.push_back( GraphicsStatus() );
149 * clip region handling
153 PrinterGfx::ResetClipRegion()
155 maClipRegion
.clear();
157 PSGSave (); // get "clean" clippath
161 PrinterGfx::BeginSetClipRegion( sal_uInt32
)
163 maClipRegion
.clear();
167 PrinterGfx::UnionClipRegion (sal_Int32 nX
,sal_Int32 nY
,sal_Int32 nDX
,sal_Int32 nDY
)
170 maClipRegion
.push_back (Rectangle(Point(nX
,nY
), Size(nDX
,nDY
)));
175 PrinterGfx::JoinVerticalClipRectangles( std::list
< Rectangle
>::iterator
& it
,
176 Point
& rOldPoint
, sal_Int32
& rColumn
)
178 bool bSuccess
= false;
180 std::list
< Rectangle
>::iterator tempit
, nextit
;
183 std::list
< Point
> leftside
, rightside
;
185 Rectangle
aLastRect( *it
);
186 leftside
.push_back( Point( it
->Left(), it
->Top() ) );
187 rightside
.push_back( Point( it
->Right()+1, it
->Top() ) );
188 while( nextit
!= maClipRegion
.end() )
192 if( nextit
->Top() == aLastRect
.Bottom()+1 )
195 ( nextit
->Left() >= aLastRect
.Left() && nextit
->Left() <= aLastRect
.Right() ) // left endpoint touches last rectangle
197 ( nextit
->Right() >= aLastRect
.Left() && nextit
->Right() <= aLastRect
.Right() ) // right endpoint touches last rectangle
199 ( nextit
->Left() <= aLastRect
.Left() && nextit
->Right() >= aLastRect
.Right() ) // whole line touches last rectangle
202 if( aLastRect
.GetHeight() > 1 ||
203 std::abs( aLastRect
.Left() - nextit
->Left() ) > 2 ||
204 std::abs( aLastRect
.Right() - nextit
->Right() ) > 2
207 leftside
.push_back( Point( aLastRect
.Left(), aLastRect
.Bottom()+1 ) );
208 rightside
.push_back( Point( aLastRect
.Right()+1, aLastRect
.Bottom()+1 ) );
211 leftside
.push_back( aLastRect
.TopLeft() );
212 rightside
.push_back( aLastRect
.TopRight() );
213 maClipRegion
.erase( nextit
);
218 if( leftside
.size() > 1 )
220 // push the last coordinates
221 leftside
.push_back( Point( aLastRect
.Left(), aLastRect
.Bottom()+1 ) );
222 rightside
.push_back( Point( aLastRect
.Right()+1, aLastRect
.Bottom()+1 ) );
224 // cool, we can concatenate rectangles
225 const int nDX
= -65536, nDY
= 65536;
226 int nNewDX
= 0, nNewDY
= 0;
228 Point aLastPoint
= leftside
.front();
229 PSBinMoveTo (aLastPoint
, rOldPoint
, rColumn
);
230 leftside
.pop_front();
231 while( leftside
.begin() != leftside
.end() )
233 Point
aPoint (leftside
.front());
234 leftside
.pop_front();
235 // may have been the last one
236 if( leftside
.begin() != leftside
.end() )
238 nNewDX
= aPoint
.X() - aLastPoint
.X();
239 nNewDY
= aPoint
.Y() - aLastPoint
.Y();
241 (double)nNewDY
/(double)nNewDX
== (double)nDY
/(double)nDX
)
244 PSBinLineTo (aPoint
, rOldPoint
, rColumn
);
248 aLastPoint
= rightside
.back();
249 PSBinLineTo (aLastPoint
, rOldPoint
, rColumn
);
250 rightside
.pop_back();
251 while( rightside
.begin() != rightside
.end() )
253 Point
aPoint (rightside
.back());
254 rightside
.pop_back();
255 if( rightside
.begin() != rightside
.end() )
257 nNewDX
= aPoint
.X() - aLastPoint
.X();
258 nNewDY
= aPoint
.Y() - aLastPoint
.Y();
260 (double)nNewDY
/(double)nNewDX
== (double)nDY
/(double)nDX
)
263 PSBinLineTo (aPoint
, rOldPoint
, rColumn
);
268 maClipRegion
.erase( it
);
276 PrinterGfx::EndSetClipRegion()
279 PSGSave (); // get "clean" clippath
282 Point
aOldPoint (0, 0);
283 sal_Int32 nColumn
= 0;
285 std::list
< Rectangle
>::iterator it
= maClipRegion
.begin();
286 while( it
!= maClipRegion
.end() )
288 // try to concatenate adjacent rectangles
289 // first try in y direction, then in x direction
290 if( ! JoinVerticalClipRectangles( it
, aOldPoint
, nColumn
) )
292 // failed, so it is a single rectangle
293 PSBinMoveTo (Point( it
->Left()-1, it
->Top()-1), aOldPoint
, nColumn
);
294 PSBinLineTo (Point( it
->Left()-1, it
->Bottom()+1 ), aOldPoint
, nColumn
);
295 PSBinLineTo (Point( it
->Right()+1, it
->Bottom()+1 ), aOldPoint
, nColumn
);
296 PSBinLineTo (Point( it
->Right()+1, it
->Top()-1 ), aOldPoint
, nColumn
);
303 WritePS (mpPageBody
, "closepath clip newpath\n");
304 maClipRegion
.clear();
308 * draw graphic primitives
312 PrinterGfx::DrawRect (const Rectangle
& rRectangle
)
317 nChar
= psp::getValueOf (rRectangle
.TopLeft().X(), pRect
);
318 nChar
+= psp::appendStr (" ", pRect
+ nChar
);
319 nChar
+= psp::getValueOf (rRectangle
.TopLeft().Y(), pRect
+ nChar
);
320 nChar
+= psp::appendStr (" ", pRect
+ nChar
);
321 nChar
+= psp::getValueOf (rRectangle
.GetWidth(), pRect
+ nChar
);
322 nChar
+= psp::appendStr (" ", pRect
+ nChar
);
323 nChar
+= psp::getValueOf (rRectangle
.GetHeight(), pRect
+ nChar
);
324 nChar
+= psp::appendStr (" ", pRect
+ nChar
);
326 if( maFillColor
.Is() )
328 PSSetColor (maFillColor
);
330 WritePS (mpPageBody
, pRect
, nChar
);
331 WritePS (mpPageBody
, "rectfill\n");
333 if( maLineColor
.Is() )
335 PSSetColor (maLineColor
);
338 WritePS (mpPageBody
, pRect
, nChar
);
339 WritePS (mpPageBody
, "rectstroke\n");
344 PrinterGfx::DrawLine (const Point
& rFrom
, const Point
& rTo
)
346 if( maLineColor
.Is() )
348 PSSetColor (maLineColor
);
354 WritePS (mpPageBody
, "stroke\n" );
359 PrinterGfx::DrawPixel (const Point
& rPoint
, const PrinterColor
& rPixelColor
)
361 if( rPixelColor
.Is() )
363 PSSetColor (rPixelColor
);
367 PSLineTo (Point (rPoint
.X ()+1, rPoint
.Y ()));
368 PSLineTo (Point (rPoint
.X ()+1, rPoint
.Y ()+1));
369 PSLineTo (Point (rPoint
.X (), rPoint
.Y ()+1));
370 WritePS (mpPageBody
, "fill\n" );
375 PrinterGfx::DrawPolyLine (sal_uInt32 nPoints
, const Point
* pPath
)
377 if( maLineColor
.Is() && nPoints
&& pPath
)
379 PSSetColor (maLineColor
);
383 PSBinCurrentPath (nPoints
, pPath
);
385 WritePS (mpPageBody
, "stroke\n" );
390 PrinterGfx::DrawPolygon (sal_uInt32 nPoints
, const Point
* pPath
)
392 // premature end of operation
393 if (!(nPoints
> 1) || (pPath
== NULL
) || !(maFillColor
.Is() || maLineColor
.Is()))
397 Point
aPoint( 0, 0 );
398 sal_Int32
nColumn( 0 );
401 PSBinMoveTo( pPath
[0], aPoint
, nColumn
);
402 for( unsigned int n
= 1; n
< nPoints
; n
++ )
403 PSBinLineTo( pPath
[n
], aPoint
, nColumn
);
404 if( pPath
[0] != pPath
[nPoints
-1] )
405 PSBinLineTo( pPath
[0], aPoint
, nColumn
);
408 // fill the polygon first, then draw the border, note that fill and
409 // stroke reset the currentpath
411 // if fill and stroke, save the current path
412 if( maFillColor
.Is() && maLineColor
.Is())
415 if (maFillColor
.Is ())
417 PSSetColor (maFillColor
);
419 WritePS (mpPageBody
, "eofill\n");
422 // restore the current path
423 if( maFillColor
.Is() && maLineColor
.Is())
426 if (maLineColor
.Is ())
428 PSSetColor (maLineColor
);
431 WritePS (mpPageBody
, "stroke\n");
436 PrinterGfx::DrawPolyPolygon (sal_uInt32 nPoly
, const sal_uInt32
* pSizes
, const Point
** pPaths
)
439 if ( !nPoly
|| !pPaths
|| !(maFillColor
.Is() || maLineColor
.Is()))
443 for( unsigned int i
= 0; i
< nPoly
; i
++ )
445 Point
aPoint( 0, 0 );
446 sal_Int32
nColumn( 0 );
449 PSBinMoveTo( pPaths
[i
][0], aPoint
, nColumn
);
450 for( unsigned int n
= 1; n
< pSizes
[i
]; n
++ )
451 PSBinLineTo( pPaths
[i
][n
], aPoint
, nColumn
);
452 if( pPaths
[i
][0] != pPaths
[i
][pSizes
[i
]-1] )
453 PSBinLineTo( pPaths
[i
][0], aPoint
, nColumn
);
457 // if eofill and stroke, save the current path
458 if( maFillColor
.Is() && maLineColor
.Is())
462 if( maFillColor
.Is() )
464 PSSetColor (maFillColor
);
466 WritePS (mpPageBody
, "eofill\n");
469 // restore the current path
470 if( maFillColor
.Is() && maLineColor
.Is())
474 if( maLineColor
.Is() )
476 PSSetColor (maLineColor
);
479 WritePS (mpPageBody
, "stroke\n");
484 * Bezier Polygon Drawing methods.
488 PrinterGfx::DrawPolyLineBezier (sal_uInt32 nPoints
, const Point
* pPath
, const sal_uInt8
* pFlgAry
)
490 const sal_uInt32 nBezString
= 1024;
491 sal_Char pString
[nBezString
];
493 if ( nPoints
> 1 && maLineColor
.Is() && pPath
)
495 PSSetColor (maLineColor
);
499 snprintf(pString
, nBezString
, "%li %li moveto\n", pPath
[0].X(), pPath
[0].Y());
500 WritePS(mpPageBody
, pString
);
502 // Handle the drawing of mixed lines mixed with curves
503 // - a normal point followed by a normal point is a line
504 // - a normal point followed by 2 control points and a normal point is a curve
505 for (unsigned int i
=1; i
<nPoints
;)
507 if (pFlgAry
[i
] != POLY_CONTROL
) //If the next point is a POLY_NORMAL, we're drawing a line
509 snprintf(pString
, nBezString
, "%li %li lineto\n", pPath
[i
].X(), pPath
[i
].Y());
512 else //Otherwise we're drawing a spline
515 return; //Error: wrong sequence of contol/normal points somehow
516 if ((pFlgAry
[i
] == POLY_CONTROL
) && (pFlgAry
[i
+1] == POLY_CONTROL
) &&
517 (pFlgAry
[i
+2] != POLY_CONTROL
))
519 snprintf(pString
, nBezString
, "%li %li %li %li %li %li curveto\n",
520 pPath
[i
].X(), pPath
[i
].Y(),
521 pPath
[i
+1].X(), pPath
[i
+1].Y(),
522 pPath
[i
+2].X(), pPath
[i
+2].Y());
526 OSL_FAIL( "PrinterGfx::DrawPolyLineBezier: Strange output" );
530 WritePS(mpPageBody
, pString
);
534 WritePS (mpPageBody
, "stroke\n");
539 PrinterGfx::DrawPolygonBezier (sal_uInt32 nPoints
, const Point
* pPath
, const sal_uInt8
* pFlgAry
)
541 const sal_uInt32 nBezString
= 1024;
542 sal_Char pString
[nBezString
];
543 // premature end of operation
544 if (!(nPoints
> 1) || (pPath
== NULL
) || !(maFillColor
.Is() || maLineColor
.Is()))
547 snprintf(pString
, nBezString
, "%li %li moveto\n", pPath
[0].X(), pPath
[0].Y());
548 WritePS(mpPageBody
, pString
); //Move to the starting point for the PolyPoygon
549 for (unsigned int i
=1; i
< nPoints
;)
551 if (pFlgAry
[i
] != POLY_CONTROL
)
553 snprintf(pString
, nBezString
, "%li %li lineto\n", pPath
[i
].X(), pPath
[i
].Y());
554 WritePS(mpPageBody
, pString
);
560 return; //Error: wrong sequence of contol/normal points somehow
561 if ((pFlgAry
[i
] == POLY_CONTROL
) && (pFlgAry
[i
+1] == POLY_CONTROL
) &&
562 (pFlgAry
[i
+2] != POLY_CONTROL
))
564 snprintf(pString
, nBezString
, "%li %li %li %li %li %li curveto\n",
565 pPath
[i
].X(), pPath
[i
].Y(),
566 pPath
[i
+1].X(), pPath
[i
+1].Y(),
567 pPath
[i
+2].X(), pPath
[i
+2].Y());
568 WritePS(mpPageBody
, pString
);
572 OSL_FAIL( "PrinterGfx::DrawPolygonBezier: Strange output" );
578 // if fill and stroke, save the current path
579 if( maFillColor
.Is() && maLineColor
.Is())
582 if (maFillColor
.Is ())
584 PSSetColor (maFillColor
);
586 WritePS (mpPageBody
, "eofill\n");
589 // restore the current path
590 if( maFillColor
.Is() && maLineColor
.Is())
595 PrinterGfx::DrawPolyPolygonBezier (sal_uInt32 nPoly
, const sal_uInt32
* pPoints
, const Point
* const * pPtAry
, const sal_uInt8
* const* pFlgAry
)
597 const sal_uInt32 nBezString
= 1024;
598 sal_Char pString
[nBezString
];
599 if ( !nPoly
|| !pPtAry
|| !pPoints
|| !(maFillColor
.Is() || maLineColor
.Is()))
602 for (unsigned int i
=0; i
<nPoly
;i
++)
604 sal_uInt32 nPoints
= pPoints
[i
];
606 if( nPoints
== 0 || pPtAry
[i
] == NULL
)
609 snprintf(pString
, nBezString
, "%li %li moveto\n", pPtAry
[i
][0].X(), pPtAry
[i
][0].Y()); //Move to the starting point
610 WritePS(mpPageBody
, pString
);
611 for (unsigned int j
=1; j
< nPoints
;)
613 // if no flag array exists for this polygon, then it must be a regular
614 // polygon without beziers
615 if ( ! pFlgAry
[i
] || pFlgAry
[i
][j
] != POLY_CONTROL
)
617 snprintf(pString
, nBezString
, "%li %li lineto\n", pPtAry
[i
][j
].X(), pPtAry
[i
][j
].Y());
618 WritePS(mpPageBody
, pString
);
624 break; //Error: wrong sequence of contol/normal points somehow
625 if ((pFlgAry
[i
][j
] == POLY_CONTROL
) && (pFlgAry
[i
][j
+1] == POLY_CONTROL
) && (pFlgAry
[i
][j
+2] != POLY_CONTROL
))
627 snprintf(pString
, nBezString
, "%li %li %li %li %li %li curveto\n",
628 pPtAry
[i
][j
].X(), pPtAry
[i
][j
].Y(),
629 pPtAry
[i
][j
+1].X(), pPtAry
[i
][j
+1].Y(),
630 pPtAry
[i
][j
+2].X(), pPtAry
[i
][j
+2].Y());
631 WritePS(mpPageBody
, pString
);
635 OSL_FAIL( "PrinterGfx::DrawPolyPolygonBezier: Strange output" );
642 // if fill and stroke, save the current path
643 if( maFillColor
.Is() && maLineColor
.Is())
646 if (maFillColor
.Is ())
648 PSSetColor (maFillColor
);
650 WritePS (mpPageBody
, "eofill\n");
653 // restore the current path
654 if( maFillColor
.Is() && maLineColor
.Is())
659 * postscript generating routines
662 PrinterGfx::PSGSave ()
664 WritePS (mpPageBody
, "gsave\n" );
665 GraphicsStatus aNewState
;
666 if( maGraphicsStack
.begin() != maGraphicsStack
.end() )
667 aNewState
= maGraphicsStack
.front();
668 maGraphicsStack
.push_front( aNewState
);
672 PrinterGfx::PSGRestore ()
674 WritePS (mpPageBody
, "grestore\n" );
675 if( maGraphicsStack
.begin() == maGraphicsStack
.end() )
676 WritePS (mpPageBody
, "Error: too many grestores\n" );
678 maGraphicsStack
.pop_front();
682 PrinterGfx::PSSetLineWidth ()
684 if( currentState().mfLineWidth
!= maVirtualStatus
.mfLineWidth
)
689 currentState().mfLineWidth
= maVirtualStatus
.mfLineWidth
;
690 nChar
= psp::getValueOfDouble (pBuffer
, maVirtualStatus
.mfLineWidth
, 5);
691 nChar
+= psp::appendStr (" setlinewidth\n", pBuffer
+ nChar
);
692 WritePS (mpPageBody
, pBuffer
, nChar
);
697 PrinterGfx::PSSetColor ()
699 PrinterColor
& rColor( maVirtualStatus
.maColor
);
701 if( currentState().maColor
!= rColor
)
703 currentState().maColor
= rColor
;
710 nChar
= psp::getValueOfDouble (pBuffer
,
711 (double)rColor
.GetRed() / 255.0, 5);
712 nChar
+= psp::appendStr (" ", pBuffer
+ nChar
);
713 nChar
+= psp::getValueOfDouble (pBuffer
+ nChar
,
714 (double)rColor
.GetGreen() / 255.0, 5);
715 nChar
+= psp::appendStr (" ", pBuffer
+ nChar
);
716 nChar
+= psp::getValueOfDouble (pBuffer
+ nChar
,
717 (double)rColor
.GetBlue() / 255.0, 5);
718 nChar
+= psp::appendStr (" setrgbcolor\n", pBuffer
+ nChar
);
722 Color
aColor( rColor
.GetRed(), rColor
.GetGreen(), rColor
.GetBlue() );
723 sal_uInt8 nCol
= aColor
.GetLuminance();
724 nChar
= psp::getValueOfDouble( pBuffer
, (double)nCol
/ 255.0, 5 );
725 nChar
+= psp::appendStr( " setgray\n", pBuffer
+ nChar
);
728 WritePS (mpPageBody
, pBuffer
, nChar
);
733 PrinterGfx::PSSetFont ()
735 GraphicsStatus
& rCurrent( currentState() );
736 if( maVirtualStatus
.maFont
!= rCurrent
.maFont
||
737 maVirtualStatus
.mnTextHeight
!= rCurrent
.mnTextHeight
||
738 maVirtualStatus
.maEncoding
!= rCurrent
.maEncoding
||
739 maVirtualStatus
.mnTextWidth
!= rCurrent
.mnTextWidth
||
740 maVirtualStatus
.mbArtBold
!= rCurrent
.mbArtBold
||
741 maVirtualStatus
.mbArtItalic
!= rCurrent
.mbArtItalic
744 rCurrent
.maFont
= maVirtualStatus
.maFont
;
745 rCurrent
.maEncoding
= maVirtualStatus
.maEncoding
;
746 rCurrent
.mnTextWidth
= maVirtualStatus
.mnTextWidth
;
747 rCurrent
.mnTextHeight
= maVirtualStatus
.mnTextHeight
;
748 rCurrent
.mbArtItalic
= maVirtualStatus
.mbArtItalic
;
749 rCurrent
.mbArtBold
= maVirtualStatus
.mbArtBold
;
751 sal_Int32 nTextHeight
= rCurrent
.mnTextHeight
;
752 sal_Int32 nTextWidth
= rCurrent
.mnTextWidth
? rCurrent
.mnTextWidth
753 : rCurrent
.mnTextHeight
;
755 sal_Char pSetFont
[256];
758 // postscript based fonts need reencoding
759 if ( ( rCurrent
.maEncoding
== RTL_TEXTENCODING_MS_1252
)
760 || ( rCurrent
.maEncoding
== RTL_TEXTENCODING_ISO_8859_1
)
761 || ( rCurrent
.maEncoding
>= RTL_TEXTENCODING_USER_START
762 && rCurrent
.maEncoding
<= RTL_TEXTENCODING_USER_END
)
765 OString aReencodedFont
=
766 psp::GlyphSet::GetReencodedFontName (rCurrent
.maEncoding
,
769 nChar
+= psp::appendStr ("(", pSetFont
+ nChar
);
770 nChar
+= psp::appendStr (aReencodedFont
.getStr(),
772 nChar
+= psp::appendStr (") cvn findfont ",
776 // tt based fonts mustn't reencode, the encoding is implied by the fontname
777 // same for symbol type1 fonts, dont try to touch them
779 nChar
+= psp::appendStr ("(", pSetFont
+ nChar
);
780 nChar
+= psp::appendStr (rCurrent
.maFont
.getStr(),
782 nChar
+= psp::appendStr (") cvn findfont ",
786 if( ! rCurrent
.mbArtItalic
)
788 nChar
+= psp::getValueOf (nTextWidth
, pSetFont
+ nChar
);
789 nChar
+= psp::appendStr (" ", pSetFont
+ nChar
);
790 nChar
+= psp::getValueOf (-nTextHeight
, pSetFont
+ nChar
);
791 nChar
+= psp::appendStr (" matrix scale makefont setfont\n", pSetFont
+ nChar
);
793 else // skew 15 degrees to right
795 nChar
+= psp::appendStr ( " [", pSetFont
+ nChar
);
796 nChar
+= psp::getValueOf (nTextWidth
, pSetFont
+ nChar
);
797 nChar
+= psp::appendStr (" 0 ", pSetFont
+ nChar
);
798 nChar
+= psp::getValueOfDouble (pSetFont
+ nChar
, 0.27*(double)nTextWidth
, 3 );
799 nChar
+= psp::appendStr ( " ", pSetFont
+ nChar
);
800 nChar
+= psp::getValueOf (-nTextHeight
, pSetFont
+ nChar
);
802 nChar
+= psp::appendStr (" 0 0] makefont setfont\n", pSetFont
+ nChar
);
805 WritePS (mpPageBody
, pSetFont
);
810 PrinterGfx::PSRotate (sal_Int32 nAngle
)
812 sal_Int32 nPostScriptAngle
= -nAngle
;
813 while( nPostScriptAngle
< 0 )
814 nPostScriptAngle
+= 3600;
816 if (nPostScriptAngle
== 0)
819 sal_Int32 nFullAngle
= nPostScriptAngle
/ 10;
820 sal_Int32 nTenthAngle
= nPostScriptAngle
% 10;
822 sal_Char pRotate
[48];
825 nChar
= psp::getValueOf (nFullAngle
, pRotate
);
826 nChar
+= psp::appendStr (".", pRotate
+ nChar
);
827 nChar
+= psp::getValueOf (nTenthAngle
, pRotate
+ nChar
);
828 nChar
+= psp::appendStr (" rotate\n", pRotate
+ nChar
);
830 WritePS (mpPageBody
, pRotate
);
834 PrinterGfx::PSPointOp (const Point
& rPoint
, const sal_Char
* pOperator
)
836 sal_Char pPSCommand
[48];
839 nChar
= psp::getValueOf (rPoint
.X(), pPSCommand
);
840 nChar
+= psp::appendStr (" ", pPSCommand
+ nChar
);
841 nChar
+= psp::getValueOf (rPoint
.Y(), pPSCommand
+ nChar
);
842 nChar
+= psp::appendStr (" ", pPSCommand
+ nChar
);
843 nChar
+= psp::appendStr (pOperator
, pPSCommand
+ nChar
);
844 nChar
+= psp::appendStr ("\n", pPSCommand
+ nChar
);
846 DBG_ASSERT (nChar
< 48, "Buffer overflow in PSPointOp");
848 WritePS (mpPageBody
, pPSCommand
);
852 PrinterGfx::PSTranslate (const Point
& rPoint
)
854 PSPointOp (rPoint
, "translate");
858 PrinterGfx::PSMoveTo (const Point
& rPoint
)
860 PSPointOp (rPoint
, "moveto");
864 PrinterGfx::PSLineTo (const Point
& rPoint
)
866 PSPointOp (rPoint
, "lineto");
869 /* get a compressed representation of the path information */
871 #define DEBUG_BINPATH 0
874 PrinterGfx::PSBinLineTo (const Point
& rCurrent
, Point
& rOld
, sal_Int32
& nColumn
)
876 #if (DEBUG_BINPATH == 1)
879 PSBinPath (rCurrent
, rOld
, lineto
, nColumn
);
884 PrinterGfx::PSBinMoveTo (const Point
& rCurrent
, Point
& rOld
, sal_Int32
& nColumn
)
886 #if (DEBUG_BINPATH == 1)
889 PSBinPath (rCurrent
, rOld
, moveto
, nColumn
);
894 PrinterGfx::PSBinStartPath ()
896 #if (DEBUG_BINPATH == 1)
897 WritePS (mpPageBody
, "% PSBinStartPath\n");
899 WritePS (mpPageBody
, "readpath\n" );
904 PrinterGfx::PSBinEndPath ()
906 #if (DEBUG_BINPATH == 1)
907 WritePS (mpPageBody
, "% PSBinEndPath\n");
909 WritePS (mpPageBody
, "~\n");
914 PrinterGfx::PSBinCurrentPath (sal_uInt32 nPoints
, const Point
* pPath
)
918 sal_Int32 nColumn
= 0;
921 PSBinMoveTo (*pPath
, aPoint
, nColumn
);
922 for (unsigned int i
= 1; i
< nPoints
; i
++)
923 PSBinLineTo (pPath
[i
], aPoint
, nColumn
);
928 PrinterGfx::PSBinPath (const Point
& rCurrent
, Point
& rOld
,
929 pspath_t eType
, sal_Int32
& nColumn
)
931 sal_Char pPath
[48] = {0};
934 // create the hex representation of the dx and dy path shift, store the field
935 // width as it is needed for the building the command
936 sal_Int32 nXPrec
= getAlignedHexValueOf (rCurrent
.X() - rOld
.X(), pPath
+ 1);
937 sal_Int32 nYPrec
= getAlignedHexValueOf (rCurrent
.Y() - rOld
.Y(), pPath
+ 1 + nXPrec
);
938 pPath
[ 1 + nXPrec
+ nYPrec
] = 0;
940 // build the command, it is a char with bit represention 000cxxyy
941 // c represents the char, xx and yy repr. the field width of the dx and dy shift,
942 // dx and dy represent the number of bytes to read after the opcode
943 sal_Char cCmd
= (eType
== lineto
? (sal_Char
)0x00 : (sal_Char
)0x10);
947 case 4: cCmd
|= 0x01; break;
948 case 6: cCmd
|= 0x02; break;
949 case 8: cCmd
|= 0x03; break;
950 default: OSL_FAIL("invalid x precision in binary path");
955 case 4: cCmd
|= 0x04; break;
956 case 6: cCmd
|= 0x08; break;
957 case 8: cCmd
|= 0x0c; break;
958 default: OSL_FAIL("invalid y precision in binary path");
963 // write the command to file,
964 // line breaking at column nMaxTextColumn (80)
965 nChar
= 1 + nXPrec
+ nYPrec
;
966 if ((nColumn
+ nChar
) > nMaxTextColumn
)
968 sal_Int32 nSegment
= nMaxTextColumn
- nColumn
;
970 WritePS (mpPageBody
, pPath
, nSegment
);
971 WritePS (mpPageBody
, "\n", 1);
972 WritePS (mpPageBody
, pPath
+ nSegment
, nChar
- nSegment
);
974 nColumn
= nChar
- nSegment
;
978 WritePS (mpPageBody
, pPath
, nChar
);
987 PrinterGfx::PSScale (double fScaleX
, double fScaleY
)
989 sal_Char pScale
[48];
992 nChar
= psp::getValueOfDouble (pScale
, fScaleX
, 5);
993 nChar
+= psp::appendStr (" ", pScale
+ nChar
);
994 nChar
+= psp::getValueOfDouble (pScale
+ nChar
, fScaleY
, 5);
995 nChar
+= psp::appendStr (" scale\n", pScale
+ nChar
);
997 WritePS (mpPageBody
, pScale
);
1000 /* psshowtext helper routines: draw an hex string for show/xshow */
1002 PrinterGfx::PSHexString (const unsigned char* pString
, sal_Int16 nLen
)
1004 sal_Char pHexString
[128];
1005 sal_Int32 nChar
= 0;
1007 nChar
= psp::appendStr ("<", pHexString
);
1008 for (int i
= 0; i
< nLen
; i
++)
1010 if (nChar
>= (nMaxTextColumn
- 1))
1012 nChar
+= psp::appendStr ("\n", pHexString
+ nChar
);
1013 WritePS (mpPageBody
, pHexString
, nChar
);
1016 nChar
+= psp::getHexValueOf ((sal_Int32
)pString
[i
], pHexString
+ nChar
);
1019 nChar
+= psp::appendStr (">\n", pHexString
+ nChar
);
1020 WritePS (mpPageBody
, pHexString
, nChar
);
1023 /* psshowtext helper routines: draw an array for xshow ps operator */
1025 PrinterGfx::PSDeltaArray (const sal_Int32
*pArray
, sal_Int16 nEntries
)
1027 sal_Char pPSArray
[128];
1028 sal_Int32 nChar
= 0;
1030 nChar
= psp::appendStr ("[", pPSArray
+ nChar
);
1031 nChar
+= psp::getValueOf (pArray
[0], pPSArray
+ nChar
);
1033 for (int i
= 1; i
< nEntries
; i
++)
1035 if (nChar
>= (nMaxTextColumn
- 1))
1037 nChar
+= psp::appendStr ("\n", pPSArray
+ nChar
);
1038 WritePS (mpPageBody
, pPSArray
, nChar
);
1042 nChar
+= psp::appendStr (" ", pPSArray
+ nChar
);
1043 nChar
+= psp::getValueOf (pArray
[i
] - pArray
[i
-1], pPSArray
+ nChar
);
1046 nChar
+= psp::appendStr (" 0]\n", pPSArray
+ nChar
);
1047 WritePS (mpPageBody
, pPSArray
);
1050 /* the DrawText equivalent, pDeltaArray may be NULL. For Type1 fonts or single byte
1051 * fonts in general nBytes and nGlyphs is the same. For printer resident Composite
1052 * fonts it may be different (these fonts may be SJIS encoded for example) */
1054 PrinterGfx::PSShowText (const unsigned char* pStr
, sal_Int16 nGlyphs
, sal_Int16 nBytes
,
1055 const sal_Int32
* pDeltaArray
)
1057 PSSetColor (maTextColor
);
1060 // rotate the user coordinate system
1061 if (mnTextAngle
!= 0)
1064 PSRotate (mnTextAngle
);
1067 sal_Char pBuffer
[256];
1068 if( maVirtualStatus
.mbArtBold
)
1070 sal_Int32 nLW
= maVirtualStatus
.mnTextWidth
;
1072 nLW
= maVirtualStatus
.mnTextHeight
;
1074 nLW
= nLW
< maVirtualStatus
.mnTextHeight
? nLW
: maVirtualStatus
.mnTextHeight
;
1075 psp::getValueOfDouble( pBuffer
, (double)nLW
/ 30.0 );
1077 // dispatch to the drawing method
1078 if (pDeltaArray
== NULL
)
1080 PSHexString (pStr
, nBytes
);
1082 if( maVirtualStatus
.mbArtBold
)
1084 WritePS( mpPageBody
, pBuffer
);
1085 WritePS( mpPageBody
, " bshow\n" );
1088 WritePS (mpPageBody
, "show\n");
1092 PSHexString (pStr
, nBytes
);
1093 PSDeltaArray (pDeltaArray
, nGlyphs
- 1);
1094 if( maVirtualStatus
.mbArtBold
)
1096 WritePS( mpPageBody
, pBuffer
);
1097 WritePS( mpPageBody
, " bxshow\n" );
1100 WritePS (mpPageBody
, "xshow\n");
1103 // restore the user coordinate system
1104 if (mnTextAngle
!= 0)
1109 PrinterGfx::PSComment( const sal_Char
* pComment
)
1111 const sal_Char
* pLast
= pComment
;
1112 while( pComment
&& *pComment
)
1114 while( *pComment
&& *pComment
!= '\n' && *pComment
!= '\r' )
1116 if( pComment
- pLast
> 1 )
1118 WritePS( mpPageBody
, "% ", 2 );
1119 WritePS( mpPageBody
, pLast
, pComment
- pLast
);
1120 WritePS( mpPageBody
, "\n", 1 );
1128 PrinterGfx::DrawEPS( const Rectangle
& rBoundingBox
, void* pPtr
, sal_uInt32 nSize
)
1135 bool bSuccess
= false;
1137 // first search the BoundingBox of the EPS data
1138 SvMemoryStream
aStream( pPtr
, nSize
, StreamMode::READ
);
1139 aStream
.Seek( STREAM_SEEK_TO_BEGIN
);
1143 double fLeft
= 0, fRight
= 0, fTop
= 0, fBottom
= 0;
1144 bool bEndComments
= false;
1145 while( ! aStream
.IsEof()
1146 && ( ( fLeft
== 0 && fRight
== 0 && fTop
== 0 && fBottom
== 0 ) ||
1147 ( aDocTitle
.isEmpty() && !bEndComments
) )
1150 aStream
.ReadLine( aLine
);
1151 if( aLine
.getLength() > 1 && aLine
[0] == '%' )
1153 char cChar
= aLine
[1];
1156 if( aLine
.matchIgnoreAsciiCase( OString( "%%BoundingBox:") ) )
1158 aLine
= WhitespaceToSpace( aLine
.getToken(1, ':') );
1159 if( !aLine
.isEmpty() && aLine
.indexOf( "atend" ) == -1 )
1161 fLeft
= StringToDouble( GetCommandLineToken( 0, aLine
) );
1162 fBottom
= StringToDouble( GetCommandLineToken( 1, aLine
) );
1163 fRight
= StringToDouble( GetCommandLineToken( 2, aLine
) );
1164 fTop
= StringToDouble( GetCommandLineToken( 3, aLine
) );
1167 else if( aLine
.matchIgnoreAsciiCase( "%%Title:" ) )
1168 aDocTitle
= WhitespaceToSpace( aLine
.copy( 8 ) );
1169 else if( aLine
.matchIgnoreAsciiCase( "%%EndComments" ) )
1170 bEndComments
= true;
1172 else if( cChar
== ' ' || cChar
== '\t' || cChar
== '\r' || cChar
== '\n' )
1173 bEndComments
= true;
1176 bEndComments
= true;
1179 static sal_uInt16 nEps
= 0;
1180 if( aDocTitle
.isEmpty() )
1181 aDocTitle
= OString::number(nEps
++);
1183 if( fLeft
!= fRight
&& fTop
!= fBottom
)
1185 double fScaleX
= (double)rBoundingBox
.GetWidth()/(fRight
-fLeft
);
1186 double fScaleY
= -(double)rBoundingBox
.GetHeight()/(fTop
-fBottom
);
1187 Point
aTranslatePoint( (int)(rBoundingBox
.Left()-fLeft
*fScaleX
),
1188 (int)(rBoundingBox
.Bottom()+1-fBottom
*fScaleY
) );
1190 WritePS( mpPageBody
,
1191 "/b4_Inc_state save def\n"
1192 "/dict_count countdictstack def\n"
1193 "/op_count count 1 sub def\n"
1195 "/showpage {} def\n"
1196 "0 setgray 0 setlinecap 1 setlinewidth 0 setlinejoin\n"
1197 "10 setmiterlimit [] 0 setdash newpath\n"
1198 "/languagelevel where\n"
1199 "{pop languagelevel\n"
1201 " {false setstrokeadjust false setoverprint\n"
1204 // set up clip path and scale
1205 BeginSetClipRegion( 1 );
1206 UnionClipRegion( rBoundingBox
.Left(), rBoundingBox
.Top(), rBoundingBox
.GetWidth(), rBoundingBox
.GetHeight() );
1208 PSTranslate( aTranslatePoint
);
1209 PSScale( fScaleX
, fScaleY
);
1211 // DSC requires BeginDocument
1212 WritePS( mpPageBody
, "%%BeginDocument: " );
1213 WritePS( mpPageBody
, aDocTitle
);
1214 WritePS( mpPageBody
, "\n" );
1216 // write the EPS data
1217 sal_uInt64 nOutLength
;
1218 mpPageBody
->write( pPtr
, nSize
, nOutLength
);
1219 bSuccess
= nOutLength
== nSize
;
1221 // corresponding EndDocument
1222 if( static_cast<char*>(pPtr
)[ nSize
-1 ] != '\n' )
1223 WritePS( mpPageBody
, "\n" );
1224 WritePS( mpPageBody
, "%%EndDocument\n" );
1227 WritePS( mpPageBody
,
1228 "count op_count sub {pop} repeat\n"
1229 "countdictstack dict_count sub {end} repeat\n"
1230 "b4_Inc_state restore\n" );
1235 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */