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 .
21 #include "psputil.hxx"
22 #include "glyphset.hxx"
24 #include "generic/printergfx.hxx"
25 #include "generic/printerjob.hxx"
26 #include "vcl/fontmanager.hxx"
27 #include "vcl/strhelper.hxx"
28 #include "vcl/printerinfomanager.hxx"
30 #include "tools/debug.hxx"
31 #include "tools/color.hxx"
32 #include "tools/poly.hxx"
36 static const sal_Int32 nMaxTextColumn
= 80;
38 GraphicsStatus::GraphicsStatus() :
48 * non graphics graphics routines
52 PrinterGfx::Init (PrinterJob
&rPrinterJob
)
54 mpPageHeader
= rPrinterJob
.GetCurrentPageHeader ();
55 mpPageBody
= rPrinterJob
.GetCurrentPageBody ();
56 mnDepth
= rPrinterJob
.GetDepth ();
57 mnPSLevel
= rPrinterJob
.GetPostscriptLevel ();
58 mbColor
= rPrinterJob
.IsColorPrinter ();
60 mnDpi
= rPrinterJob
.GetResolution();
61 rPrinterJob
.GetScale (mfScaleX
, mfScaleY
);
62 const PrinterInfo
& rInfo( PrinterInfoManager::get().getPrinterInfo( rPrinterJob
.GetPrinterName() ) );
63 if( mpFontSubstitutes
)
64 delete const_cast< ::boost::unordered_map
<fontID
,fontID
>* >(mpFontSubstitutes
);
65 if( rInfo
.m_bPerformFontSubstitution
)
66 mpFontSubstitutes
= new ::boost::unordered_map
< fontID
, fontID
>( rInfo
.m_aFontSubstitutions
);
68 mpFontSubstitutes
= NULL
;
69 mbUploadPS42Fonts
= rInfo
.m_pParser
? ( rInfo
.m_pParser
->isType42Capable() ? sal_True
: sal_False
) : sal_False
;
75 PrinterGfx::Init (const JobData
& rData
)
79 mnDepth
= rData
.m_nColorDepth
;
80 mnPSLevel
= rData
.m_nPSLevel
? rData
.m_nPSLevel
: (rData
.m_pParser
? rData
.m_pParser
->getLanguageLevel() : 2 );
81 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
) );
82 int nRes
= rData
.m_aContext
.getRenderResolution();
84 mfScaleX
= (double)72.0 / (double)mnDpi
;
85 mfScaleY
= (double)72.0 / (double)mnDpi
;
86 const PrinterInfo
& rInfo( PrinterInfoManager::get().getPrinterInfo( rData
.m_aPrinterName
) );
87 if( mpFontSubstitutes
)
88 delete const_cast< ::boost::unordered_map
<fontID
,fontID
>* >(mpFontSubstitutes
);
89 if( rInfo
.m_bPerformFontSubstitution
)
90 mpFontSubstitutes
= new ::boost::unordered_map
< fontID
, fontID
>( rInfo
.m_aFontSubstitutions
);
92 mpFontSubstitutes
= NULL
;
93 mbUploadPS42Fonts
= rInfo
.m_pParser
? ( rInfo
.m_pParser
->isType42Capable() ? sal_True
: sal_False
) : sal_False
;
99 PrinterGfx::GetBitCount ()
104 PrinterGfx::PrinterGfx() :
110 mbTextVertical (false),
111 mrFontMgr (PrintFontManager::get()),
112 mbCompressBmp (sal_True
),
113 maFillColor (0xff,0,0),
115 maLineColor (0, 0xff, 0),
116 mpFontSubstitutes( NULL
)
118 maVirtualStatus
.mfLineWidth
= 1.0;
119 maVirtualStatus
.mnTextHeight
= 12;
120 maVirtualStatus
.mnTextWidth
= 0;
122 maGraphicsStack
.push_back( GraphicsStatus() );
125 PrinterGfx::~PrinterGfx()
128 * the original reasoning why mpFontSubstitutes is a pointer was
129 * that applications should release all PrinterGfx when printers change
130 * because they are really invalid; the corresponding printers may have
131 * changed their settings or even not exist anymore.
133 * Alas, this is not always done real time. So we keep a local copy of
134 * the font substitutes now in case of bad timing.
136 delete const_cast< ::boost::unordered_map
<fontID
,fontID
>* >(mpFontSubstitutes
);
145 maVirtualStatus
= GraphicsStatus();
146 maVirtualStatus
.mnTextHeight
= 12;
147 maVirtualStatus
.mnTextWidth
= 0;
148 maVirtualStatus
.mfLineWidth
= 1.0;
149 mbTextVertical
= false;
150 maLineColor
= PrinterColor();
151 maFillColor
= PrinterColor();
152 maTextColor
= PrinterColor();
153 mbCompressBmp
= sal_True
;
160 maClipRegion
.clear();
161 maGraphicsStack
.clear();
162 maGraphicsStack
.push_back( GraphicsStatus() );
166 * clip region handling
170 PrinterGfx::ResetClipRegion()
172 maClipRegion
.clear();
174 PSGSave (); // get "clean" clippath
178 PrinterGfx::BeginSetClipRegion( sal_uInt32
)
180 maClipRegion
.clear();
184 PrinterGfx::UnionClipRegion (sal_Int32 nX
,sal_Int32 nY
,sal_Int32 nDX
,sal_Int32 nDY
)
187 maClipRegion
.push_back (Rectangle(Point(nX
,nY
), Size(nDX
,nDY
)));
192 PrinterGfx::JoinVerticalClipRectangles( std::list
< Rectangle
>::iterator
& it
,
193 Point
& rOldPoint
, sal_Int32
& rColumn
)
195 sal_Bool bSuccess
= sal_False
;
197 std::list
< Rectangle
>::iterator tempit
, nextit
;
200 std::list
< Point
> leftside
, rightside
;
202 Rectangle
aLastRect( *it
);
203 leftside
.push_back( Point( it
->Left(), it
->Top() ) );
204 rightside
.push_back( Point( it
->Right()+1, it
->Top() ) );
205 while( nextit
!= maClipRegion
.end() )
209 if( nextit
->Top() == aLastRect
.Bottom()+1 )
212 ( nextit
->Left() >= aLastRect
.Left() && nextit
->Left() <= aLastRect
.Right() ) // left endpoint touches last rectangle
214 ( nextit
->Right() >= aLastRect
.Left() && nextit
->Right() <= aLastRect
.Right() ) // right endpoint touches last rectangle
216 ( nextit
->Left() <= aLastRect
.Left() && nextit
->Right() >= aLastRect
.Right() ) // whole line touches last rectangle
219 if( aLastRect
.GetHeight() > 1 ||
220 abs( aLastRect
.Left() - nextit
->Left() ) > 2 ||
221 abs( aLastRect
.Right() - nextit
->Right() ) > 2
224 leftside
.push_back( Point( aLastRect
.Left(), aLastRect
.Bottom()+1 ) );
225 rightside
.push_back( Point( aLastRect
.Right()+1, aLastRect
.Bottom()+1 ) );
228 leftside
.push_back( aLastRect
.TopLeft() );
229 rightside
.push_back( aLastRect
.TopRight() );
230 maClipRegion
.erase( nextit
);
235 if( leftside
.size() > 1 )
237 // push the last coordinates
238 leftside
.push_back( Point( aLastRect
.Left(), aLastRect
.Bottom()+1 ) );
239 rightside
.push_back( Point( aLastRect
.Right()+1, aLastRect
.Bottom()+1 ) );
241 // cool, we can concatenate rectangles
242 int nDX
= -65536, nDY
= 65536;
243 int nNewDX
= 0, nNewDY
= 0;
245 Point aLastPoint
= leftside
.front();
246 PSBinMoveTo (aLastPoint
, rOldPoint
, rColumn
);
247 leftside
.pop_front();
248 while( leftside
.begin() != leftside
.end() )
250 Point
aPoint (leftside
.front());
251 leftside
.pop_front();
252 // may have been the last one
253 if( leftside
.begin() != leftside
.end() )
255 nNewDX
= aPoint
.X() - aLastPoint
.X();
256 nNewDY
= aPoint
.Y() - aLastPoint
.Y();
257 if( nNewDX
== 0 && nDX
== 0 )
259 if( nDX
!= 0 && nNewDX
!= 0 &&
260 (double)nNewDY
/(double)nNewDX
== (double)nDY
/(double)nDX
)
263 PSBinLineTo (aPoint
, rOldPoint
, rColumn
);
267 aLastPoint
= rightside
.back();
270 PSBinLineTo (aLastPoint
, rOldPoint
, rColumn
);
271 rightside
.pop_back();
272 while( rightside
.begin() != rightside
.end() )
274 Point
aPoint (rightside
.back());
275 rightside
.pop_back();
276 if( rightside
.begin() != rightside
.end() )
278 nNewDX
= aPoint
.X() - aLastPoint
.X();
279 nNewDY
= aPoint
.Y() - aLastPoint
.Y();
280 if( nNewDX
== 0 && nDX
== 0 )
282 if( nDX
!= 0 && nNewDX
!= 0 &&
283 (double)nNewDY
/(double)nNewDX
== (double)nDY
/(double)nDX
)
286 PSBinLineTo (aPoint
, rOldPoint
, rColumn
);
291 maClipRegion
.erase( it
);
299 PrinterGfx::EndSetClipRegion()
302 PSGSave (); // get "clean" clippath
305 Point
aOldPoint (0, 0);
306 sal_Int32 nColumn
= 0;
308 std::list
< Rectangle
>::iterator it
= maClipRegion
.begin();
309 while( it
!= maClipRegion
.end() )
311 // try to concatenate adjacent rectangles
312 // first try in y direction, then in x direction
313 if( ! JoinVerticalClipRectangles( it
, aOldPoint
, nColumn
) )
315 // failed, so it is a single rectangle
316 PSBinMoveTo (it
->TopLeft(), aOldPoint
, nColumn
);
317 PSBinLineTo (Point( it
->Left(), it
->Bottom()+1 ), aOldPoint
, nColumn
);
318 PSBinLineTo (Point( it
->Right()+1, it
->Bottom()+1 ), aOldPoint
, nColumn
);
319 PSBinLineTo (Point( it
->Right()+1, it
->Top() ), aOldPoint
, nColumn
);
326 WritePS (mpPageBody
, "closepath clip newpath\n");
327 maClipRegion
.clear();
331 * draw graphic primitives
335 PrinterGfx::DrawRect (const Rectangle
& rRectangle
)
340 nChar
= psp::getValueOf (rRectangle
.TopLeft().X(), pRect
);
341 nChar
+= psp::appendStr (" ", pRect
+ nChar
);
342 nChar
+= psp::getValueOf (rRectangle
.TopLeft().Y(), pRect
+ nChar
);
343 nChar
+= psp::appendStr (" ", pRect
+ nChar
);
344 nChar
+= psp::getValueOf (rRectangle
.GetWidth(), pRect
+ nChar
);
345 nChar
+= psp::appendStr (" ", pRect
+ nChar
);
346 nChar
+= psp::getValueOf (rRectangle
.GetHeight(), pRect
+ nChar
);
347 nChar
+= psp::appendStr (" ", pRect
+ nChar
);
349 if( maFillColor
.Is() )
351 PSSetColor (maFillColor
);
353 WritePS (mpPageBody
, pRect
, nChar
);
354 WritePS (mpPageBody
, "rectfill\n");
356 if( maLineColor
.Is() )
358 PSSetColor (maLineColor
);
361 WritePS (mpPageBody
, pRect
, nChar
);
362 WritePS (mpPageBody
, "rectstroke\n");
367 PrinterGfx::DrawLine (const Point
& rFrom
, const Point
& rTo
)
369 if( maLineColor
.Is() )
371 PSSetColor (maLineColor
);
377 WritePS (mpPageBody
, "stroke\n" );
382 PrinterGfx::DrawPixel (const Point
& rPoint
, const PrinterColor
& rPixelColor
)
384 if( rPixelColor
.Is() )
386 PSSetColor (rPixelColor
);
390 PSLineTo (Point (rPoint
.X ()+1, rPoint
.Y ()));
391 PSLineTo (Point (rPoint
.X ()+1, rPoint
.Y ()+1));
392 PSLineTo (Point (rPoint
.X (), rPoint
.Y ()+1));
393 WritePS (mpPageBody
, "fill\n" );
398 PrinterGfx::DrawPolyLine (sal_uInt32 nPoints
, const Point
* pPath
)
400 if( maLineColor
.Is() && nPoints
&& pPath
)
402 PSSetColor (maLineColor
);
406 PSBinCurrentPath (nPoints
, pPath
);
408 WritePS (mpPageBody
, "stroke\n" );
413 PrinterGfx::DrawPolygon (sal_uInt32 nPoints
, const Point
* pPath
)
415 // premature end of operation
416 if (!(nPoints
> 1) || (pPath
== NULL
) || !(maFillColor
.Is() || maLineColor
.Is()))
420 Point
aPoint( 0, 0 );
421 sal_Int32
nColumn( 0 );
424 PSBinMoveTo( pPath
[0], aPoint
, nColumn
);
425 for( unsigned int n
= 1; n
< nPoints
; n
++ )
426 PSBinLineTo( pPath
[n
], aPoint
, nColumn
);
427 if( pPath
[0] != pPath
[nPoints
-1] )
428 PSBinLineTo( pPath
[0], aPoint
, nColumn
);
431 // fill the polygon first, then draw the border, note that fill and
432 // stroke reset the currentpath
434 // if fill and stroke, save the current path
435 if( maFillColor
.Is() && maLineColor
.Is())
438 if (maFillColor
.Is ())
440 PSSetColor (maFillColor
);
442 WritePS (mpPageBody
, "eofill\n");
445 // restore the current path
446 if( maFillColor
.Is() && maLineColor
.Is())
449 if (maLineColor
.Is ())
451 PSSetColor (maLineColor
);
454 WritePS (mpPageBody
, "stroke\n");
459 PrinterGfx::DrawPolyPolygon (sal_uInt32 nPoly
, const sal_uInt32
* pSizes
, const Point
** pPaths
)
462 if ( !nPoly
|| !pPaths
|| !(maFillColor
.Is() || maLineColor
.Is()))
467 for( unsigned int i
= 0; i
< nPoly
; i
++ )
469 Point
aPoint( 0, 0 );
470 sal_Int32
nColumn( 0 );
473 PSBinMoveTo( pPaths
[i
][0], aPoint
, nColumn
);
474 for( unsigned int n
= 1; n
< pSizes
[i
]; n
++ )
475 PSBinLineTo( pPaths
[i
][n
], aPoint
, nColumn
);
476 if( pPaths
[i
][0] != pPaths
[i
][pSizes
[i
]-1] )
477 PSBinLineTo( pPaths
[i
][0], aPoint
, nColumn
);
481 // if eofill and stroke, save the current path
482 if( maFillColor
.Is() && maLineColor
.Is())
486 if( maFillColor
.Is() )
488 PSSetColor (maFillColor
);
490 WritePS (mpPageBody
, "eofill\n");
493 // restore the current path
494 if( maFillColor
.Is() && maLineColor
.Is())
498 if( maLineColor
.Is() )
500 PSSetColor (maLineColor
);
503 WritePS (mpPageBody
, "stroke\n");
508 * Bezier Polygon Drawing methods.
512 PrinterGfx::DrawPolyLineBezier (sal_uInt32 nPoints
, const Point
* pPath
, const sal_uInt8
* pFlgAry
)
514 const sal_uInt32 nBezString
= 1024;
515 sal_Char pString
[nBezString
];
517 if ( nPoints
> 1 && maLineColor
.Is() && pPath
)
519 PSSetColor (maLineColor
);
523 snprintf(pString
, nBezString
, "%li %li moveto\n", pPath
[0].X(), pPath
[0].Y());
524 WritePS(mpPageBody
, pString
);
526 // Handle the drawing of mixed lines mixed with curves
527 // - a normal point followed by a normal point is a line
528 // - a normal point followed by 2 control points and a normal point is a curve
529 for (unsigned int i
=1; i
<nPoints
;)
531 if (pFlgAry
[i
] != POLY_CONTROL
) //If the next point is a POLY_NORMAL, we're drawing a line
533 snprintf(pString
, nBezString
, "%li %li lineto\n", pPath
[i
].X(), pPath
[i
].Y());
536 else //Otherwise we're drawing a spline
539 return; //Error: wrong sequence of contol/normal points somehow
540 if ((pFlgAry
[i
] == POLY_CONTROL
) && (pFlgAry
[i
+1] == POLY_CONTROL
) &&
541 (pFlgAry
[i
+2] != POLY_CONTROL
))
543 snprintf(pString
, nBezString
, "%li %li %li %li %li %li curveto\n",
544 pPath
[i
].X(), pPath
[i
].Y(),
545 pPath
[i
+1].X(), pPath
[i
+1].Y(),
546 pPath
[i
+2].X(), pPath
[i
+2].Y());
550 OSL_FAIL( "PrinterGfx::DrawPolyLineBezier: Strange output" );
554 WritePS(mpPageBody
, pString
);
558 WritePS (mpPageBody
, "stroke\n");
563 PrinterGfx::DrawPolygonBezier (sal_uInt32 nPoints
, const Point
* pPath
, const sal_uInt8
* pFlgAry
)
565 const sal_uInt32 nBezString
= 1024;
566 sal_Char pString
[nBezString
];
567 // premature end of operation
568 if (!(nPoints
> 1) || (pPath
== NULL
) || !(maFillColor
.Is() || maLineColor
.Is()))
571 snprintf(pString
, nBezString
, "%li %li moveto\n", pPath
[0].X(), pPath
[0].Y());
572 WritePS(mpPageBody
, pString
); //Move to the starting point for the PolyPoygon
573 for (unsigned int i
=1; i
< nPoints
;)
575 if (pFlgAry
[i
] != POLY_CONTROL
)
577 snprintf(pString
, nBezString
, "%li %li lineto\n", pPath
[i
].X(), pPath
[i
].Y());
578 WritePS(mpPageBody
, pString
);
584 return; //Error: wrong sequence of contol/normal points somehow
585 if ((pFlgAry
[i
] == POLY_CONTROL
) && (pFlgAry
[i
+1] == POLY_CONTROL
) &&
586 (pFlgAry
[i
+2] != POLY_CONTROL
))
588 snprintf(pString
, nBezString
, "%li %li %li %li %li %li curveto\n",
589 pPath
[i
].X(), pPath
[i
].Y(),
590 pPath
[i
+1].X(), pPath
[i
+1].Y(),
591 pPath
[i
+2].X(), pPath
[i
+2].Y());
592 WritePS(mpPageBody
, pString
);
596 OSL_FAIL( "PrinterGfx::DrawPolygonBezier: Strange output" );
602 // if fill and stroke, save the current path
603 if( maFillColor
.Is() && maLineColor
.Is())
606 if (maFillColor
.Is ())
608 PSSetColor (maFillColor
);
610 WritePS (mpPageBody
, "eofill\n");
613 // restore the current path
614 if( maFillColor
.Is() && maLineColor
.Is())
619 PrinterGfx::DrawPolyPolygonBezier (sal_uInt32 nPoly
, const sal_uInt32
* pPoints
, const Point
* const * pPtAry
, const sal_uInt8
* const* pFlgAry
)
621 const sal_uInt32 nBezString
= 1024;
622 sal_Char pString
[nBezString
];
623 if ( !nPoly
|| !pPtAry
|| !pPoints
|| !(maFillColor
.Is() || maLineColor
.Is()))
627 for (unsigned int i
=0; i
<nPoly
;i
++)
629 sal_uInt32 nPoints
= pPoints
[i
];
631 if( nPoints
== 0 || pPtAry
[i
] == NULL
)
634 snprintf(pString
, nBezString
, "%li %li moveto\n", pPtAry
[i
][0].X(), pPtAry
[i
][0].Y()); //Move to the starting point
635 WritePS(mpPageBody
, pString
);
636 for (unsigned int j
=1; j
< nPoints
;)
638 // if no flag array exists for this polygon, then it must be a regular
639 // polygon without beziers
640 if ( ! pFlgAry
[i
] || pFlgAry
[i
][j
] != POLY_CONTROL
)
642 snprintf(pString
, nBezString
, "%li %li lineto\n", pPtAry
[i
][j
].X(), pPtAry
[i
][j
].Y());
643 WritePS(mpPageBody
, pString
);
649 break; //Error: wrong sequence of contol/normal points somehow
650 if ((pFlgAry
[i
][j
] == POLY_CONTROL
) && (pFlgAry
[i
][j
+1] == POLY_CONTROL
) && (pFlgAry
[i
][j
+2] != POLY_CONTROL
))
652 snprintf(pString
, nBezString
, "%li %li %li %li %li %li curveto\n",
653 pPtAry
[i
][j
].X(), pPtAry
[i
][j
].Y(),
654 pPtAry
[i
][j
+1].X(), pPtAry
[i
][j
+1].Y(),
655 pPtAry
[i
][j
+2].X(), pPtAry
[i
][j
+2].Y());
656 WritePS(mpPageBody
, pString
);
660 OSL_FAIL( "PrinterGfx::DrawPolyPolygonBezier: Strange output" );
667 // if fill and stroke, save the current path
668 if( maFillColor
.Is() && maLineColor
.Is())
671 if (maFillColor
.Is ())
673 PSSetColor (maFillColor
);
675 WritePS (mpPageBody
, "eofill\n");
678 // restore the current path
679 if( maFillColor
.Is() && maLineColor
.Is())
685 * postscript generating routines
688 PrinterGfx::PSGSave ()
690 WritePS (mpPageBody
, "gsave\n" );
691 GraphicsStatus aNewState
;
692 if( maGraphicsStack
.begin() != maGraphicsStack
.end() )
693 aNewState
= maGraphicsStack
.front();
694 maGraphicsStack
.push_front( aNewState
);
698 PrinterGfx::PSGRestore ()
700 WritePS (mpPageBody
, "grestore\n" );
701 if( maGraphicsStack
.begin() == maGraphicsStack
.end() )
702 WritePS (mpPageBody
, "Error: too many grestores\n" );
704 maGraphicsStack
.pop_front();
708 PrinterGfx::PSSetLineWidth ()
710 if( currentState().mfLineWidth
!= maVirtualStatus
.mfLineWidth
)
715 currentState().mfLineWidth
= maVirtualStatus
.mfLineWidth
;
716 nChar
= psp::getValueOfDouble (pBuffer
, maVirtualStatus
.mfLineWidth
, 5);
717 nChar
+= psp::appendStr (" setlinewidth\n", pBuffer
+ nChar
);
718 WritePS (mpPageBody
, pBuffer
, nChar
);
723 PrinterGfx::PSSetColor ()
725 PrinterColor
& rColor( maVirtualStatus
.maColor
);
727 if( currentState().maColor
!= rColor
)
729 currentState().maColor
= rColor
;
736 nChar
= psp::getValueOfDouble (pBuffer
,
737 (double)rColor
.GetRed() / 255.0, 5);
738 nChar
+= psp::appendStr (" ", pBuffer
+ nChar
);
739 nChar
+= psp::getValueOfDouble (pBuffer
+ nChar
,
740 (double)rColor
.GetGreen() / 255.0, 5);
741 nChar
+= psp::appendStr (" ", pBuffer
+ nChar
);
742 nChar
+= psp::getValueOfDouble (pBuffer
+ nChar
,
743 (double)rColor
.GetBlue() / 255.0, 5);
744 nChar
+= psp::appendStr (" setrgbcolor\n", pBuffer
+ nChar
);
748 Color
aColor( rColor
.GetRed(), rColor
.GetGreen(), rColor
.GetBlue() );
749 sal_uInt8 nCol
= aColor
.GetLuminance();
750 nChar
= psp::getValueOfDouble( pBuffer
, (double)nCol
/ 255.0, 5 );
751 nChar
+= psp::appendStr( " setgray\n", pBuffer
+ nChar
);
754 WritePS (mpPageBody
, pBuffer
, nChar
);
759 PrinterGfx::PSSetFont ()
761 GraphicsStatus
& rCurrent( currentState() );
762 if( maVirtualStatus
.maFont
!= rCurrent
.maFont
||
763 maVirtualStatus
.mnTextHeight
!= rCurrent
.mnTextHeight
||
764 maVirtualStatus
.maEncoding
!= rCurrent
.maEncoding
||
765 maVirtualStatus
.mnTextWidth
!= rCurrent
.mnTextWidth
||
766 maVirtualStatus
.mbArtBold
!= rCurrent
.mbArtBold
||
767 maVirtualStatus
.mbArtItalic
!= rCurrent
.mbArtItalic
770 rCurrent
.maFont
= maVirtualStatus
.maFont
;
771 rCurrent
.maEncoding
= maVirtualStatus
.maEncoding
;
772 rCurrent
.mnTextWidth
= maVirtualStatus
.mnTextWidth
;
773 rCurrent
.mnTextHeight
= maVirtualStatus
.mnTextHeight
;
774 rCurrent
.mbArtItalic
= maVirtualStatus
.mbArtItalic
;
775 rCurrent
.mbArtBold
= maVirtualStatus
.mbArtBold
;
777 sal_Int32 nTextHeight
= rCurrent
.mnTextHeight
;
778 sal_Int32 nTextWidth
= rCurrent
.mnTextWidth
? rCurrent
.mnTextWidth
779 : rCurrent
.mnTextHeight
;
781 sal_Char pSetFont
[256];
784 // postscript based fonts need reencoding
785 if ( ( rCurrent
.maEncoding
== RTL_TEXTENCODING_MS_1252
)
786 || ( rCurrent
.maEncoding
== RTL_TEXTENCODING_ISO_8859_1
)
787 || ( rCurrent
.maEncoding
>= RTL_TEXTENCODING_USER_START
788 && rCurrent
.maEncoding
<= RTL_TEXTENCODING_USER_END
)
791 OString aReencodedFont
=
792 psp::GlyphSet::GetReencodedFontName (rCurrent
.maEncoding
,
795 nChar
+= psp::appendStr ("(", pSetFont
+ nChar
);
796 nChar
+= psp::appendStr (aReencodedFont
.getStr(),
798 nChar
+= psp::appendStr (") cvn findfont ",
802 // tt based fonts mustn't reencode, the encoding is implied by the fontname
803 // same for symbol type1 fonts, dont try to touch them
805 nChar
+= psp::appendStr ("(", pSetFont
+ nChar
);
806 nChar
+= psp::appendStr (rCurrent
.maFont
.getStr(),
808 nChar
+= psp::appendStr (") cvn findfont ",
812 if( ! rCurrent
.mbArtItalic
)
814 nChar
+= psp::getValueOf (nTextWidth
, pSetFont
+ nChar
);
815 nChar
+= psp::appendStr (" ", pSetFont
+ nChar
);
816 nChar
+= psp::getValueOf (-nTextHeight
, pSetFont
+ nChar
);
817 nChar
+= psp::appendStr (" matrix scale makefont setfont\n", pSetFont
+ nChar
);
819 else // skew 15 degrees to right
821 nChar
+= psp::appendStr ( " [", pSetFont
+ nChar
);
822 nChar
+= psp::getValueOf (nTextWidth
, pSetFont
+ nChar
);
823 nChar
+= psp::appendStr (" 0 ", pSetFont
+ nChar
);
824 nChar
+= psp::getValueOfDouble (pSetFont
+ nChar
, 0.27*(double)nTextWidth
, 3 );
825 nChar
+= psp::appendStr ( " ", pSetFont
+ nChar
);
826 nChar
+= psp::getValueOf (-nTextHeight
, pSetFont
+ nChar
);
828 nChar
+= psp::appendStr (" 0 0] makefont setfont\n", pSetFont
+ nChar
);
831 WritePS (mpPageBody
, pSetFont
);
836 PrinterGfx::PSRotate (sal_Int32 nAngle
)
838 sal_Int32 nPostScriptAngle
= -nAngle
;
839 while( nPostScriptAngle
< 0 )
840 nPostScriptAngle
+= 3600;
842 if (nPostScriptAngle
== 0)
845 sal_Int32 nFullAngle
= nPostScriptAngle
/ 10;
846 sal_Int32 nTenthAngle
= nPostScriptAngle
% 10;
848 sal_Char pRotate
[48];
851 nChar
= psp::getValueOf (nFullAngle
, pRotate
);
852 nChar
+= psp::appendStr (".", pRotate
+ nChar
);
853 nChar
+= psp::getValueOf (nTenthAngle
, pRotate
+ nChar
);
854 nChar
+= psp::appendStr (" rotate\n", pRotate
+ nChar
);
856 WritePS (mpPageBody
, pRotate
);
860 PrinterGfx::PSPointOp (const Point
& rPoint
, const sal_Char
* pOperator
)
862 sal_Char pPSCommand
[48];
865 nChar
= psp::getValueOf (rPoint
.X(), pPSCommand
);
866 nChar
+= psp::appendStr (" ", pPSCommand
+ nChar
);
867 nChar
+= psp::getValueOf (rPoint
.Y(), pPSCommand
+ nChar
);
868 nChar
+= psp::appendStr (" ", pPSCommand
+ nChar
);
869 nChar
+= psp::appendStr (pOperator
, pPSCommand
+ nChar
);
870 nChar
+= psp::appendStr ("\n", pPSCommand
+ nChar
);
872 DBG_ASSERT (nChar
< 48, "Buffer overflow in PSPointOp");
874 WritePS (mpPageBody
, pPSCommand
);
878 PrinterGfx::PSTranslate (const Point
& rPoint
)
880 PSPointOp (rPoint
, "translate");
884 PrinterGfx::PSMoveTo (const Point
& rPoint
)
886 PSPointOp (rPoint
, "moveto");
890 PrinterGfx::PSLineTo (const Point
& rPoint
)
892 PSPointOp (rPoint
, "lineto");
895 /* get a compressed representation of the path information */
897 #define DEBUG_BINPATH 0
900 PrinterGfx::PSBinLineTo (const Point
& rCurrent
, Point
& rOld
, sal_Int32
& nColumn
)
902 #if (DEBUG_BINPATH == 1)
905 PSBinPath (rCurrent
, rOld
, lineto
, nColumn
);
910 PrinterGfx::PSBinMoveTo (const Point
& rCurrent
, Point
& rOld
, sal_Int32
& nColumn
)
912 #if (DEBUG_BINPATH == 1)
915 PSBinPath (rCurrent
, rOld
, moveto
, nColumn
);
920 PrinterGfx::PSBinStartPath ()
922 #if (DEBUG_BINPATH == 1)
923 WritePS (mpPageBody
, "% PSBinStartPath\n");
925 WritePS (mpPageBody
, "readpath\n" );
930 PrinterGfx::PSBinEndPath ()
932 #if (DEBUG_BINPATH == 1)
933 WritePS (mpPageBody
, "% PSBinEndPath\n");
935 WritePS (mpPageBody
, "~\n");
940 PrinterGfx::PSBinCurrentPath (sal_uInt32 nPoints
, const Point
* pPath
)
944 sal_Int32 nColumn
= 0;
947 PSBinMoveTo (*pPath
, aPoint
, nColumn
);
948 for (unsigned int i
= 1; i
< nPoints
; i
++)
949 PSBinLineTo (pPath
[i
], aPoint
, nColumn
);
954 PrinterGfx::PSBinPath (const Point
& rCurrent
, Point
& rOld
,
955 pspath_t eType
, sal_Int32
& nColumn
)
960 // create the hex representation of the dx and dy path shift, store the field
961 // width as it is needed for the building the command
962 sal_Int32 nXPrec
= getAlignedHexValueOf (rCurrent
.X() - rOld
.X(), pPath
+ 1);
963 sal_Int32 nYPrec
= getAlignedHexValueOf (rCurrent
.Y() - rOld
.Y(), pPath
+ 1 + nXPrec
);
964 pPath
[ 1 + nXPrec
+ nYPrec
] = 0;
966 // build the command, it is a char with bit represention 000cxxyy
967 // c represents the char, xx and yy repr. the field width of the dx and dy shift,
968 // dx and dy represent the number of bytes to read after the opcode
969 sal_Char cCmd
= (eType
== lineto
? (sal_Char
)0x00 : (sal_Char
)0x10);
973 case 4: cCmd
|= 0x01; break;
974 case 6: cCmd
|= 0x02; break;
975 case 8: cCmd
|= 0x03; break;
976 default: OSL_FAIL("invalid x precision in binary path");
981 case 4: cCmd
|= 0x04; break;
982 case 6: cCmd
|= 0x08; break;
983 case 8: cCmd
|= 0x0c; break;
984 default: OSL_FAIL("invalid y precision in binary path");
989 // write the command to file,
990 // line breaking at column nMaxTextColumn (80)
991 nChar
= 1 + nXPrec
+ nYPrec
;
992 if ((nColumn
+ nChar
) > nMaxTextColumn
)
994 sal_Int32 nSegment
= nMaxTextColumn
- nColumn
;
996 WritePS (mpPageBody
, pPath
, nSegment
);
997 WritePS (mpPageBody
, "\n", 1);
998 WritePS (mpPageBody
, pPath
+ nSegment
, nChar
- nSegment
);
1000 nColumn
= nChar
- nSegment
;
1004 WritePS (mpPageBody
, pPath
, nChar
);
1013 PrinterGfx::PSScale (double fScaleX
, double fScaleY
)
1015 sal_Char pScale
[48];
1016 sal_Int32 nChar
= 0;
1018 nChar
= psp::getValueOfDouble (pScale
, fScaleX
, 5);
1019 nChar
+= psp::appendStr (" ", pScale
+ nChar
);
1020 nChar
+= psp::getValueOfDouble (pScale
+ nChar
, fScaleY
, 5);
1021 nChar
+= psp::appendStr (" scale\n", pScale
+ nChar
);
1023 WritePS (mpPageBody
, pScale
);
1026 /* psshowtext helper routines: draw an hex string for show/xshow */
1028 PrinterGfx::PSHexString (const sal_uChar
* pString
, sal_Int16 nLen
)
1030 sal_Char pHexString
[128];
1031 sal_Int32 nChar
= 0;
1033 nChar
= psp::appendStr ("<", pHexString
);
1034 for (int i
= 0; i
< nLen
; i
++)
1036 if (nChar
>= (nMaxTextColumn
- 1))
1038 nChar
+= psp::appendStr ("\n", pHexString
+ nChar
);
1039 WritePS (mpPageBody
, pHexString
, nChar
);
1042 nChar
+= psp::getHexValueOf ((sal_Int32
)pString
[i
], pHexString
+ nChar
);
1045 nChar
+= psp::appendStr (">\n", pHexString
+ nChar
);
1046 WritePS (mpPageBody
, pHexString
, nChar
);
1049 /* psshowtext helper routines: draw an array for xshow ps operator */
1051 PrinterGfx::PSDeltaArray (const sal_Int32
*pArray
, sal_Int16 nEntries
)
1053 sal_Char pPSArray
[128];
1054 sal_Int32 nChar
= 0;
1056 nChar
= psp::appendStr ("[", pPSArray
+ nChar
);
1057 nChar
+= psp::getValueOf (pArray
[0], pPSArray
+ nChar
);
1059 for (int i
= 1; i
< nEntries
; i
++)
1061 if (nChar
>= (nMaxTextColumn
- 1))
1063 nChar
+= psp::appendStr ("\n", pPSArray
+ nChar
);
1064 WritePS (mpPageBody
, pPSArray
, nChar
);
1068 nChar
+= psp::appendStr (" ", pPSArray
+ nChar
);
1069 nChar
+= psp::getValueOf (pArray
[i
] - pArray
[i
-1], pPSArray
+ nChar
);
1072 nChar
+= psp::appendStr (" 0]\n", pPSArray
+ nChar
);
1073 WritePS (mpPageBody
, pPSArray
);
1076 /* the DrawText equivalent, pDeltaArray may be NULL. For Type1 fonts or single byte
1077 * fonts in general nBytes and nGlyphs is the same. For printer resident Composite
1078 * fonts it may be different (these fonts may be SJIS encoded for example) */
1080 PrinterGfx::PSShowText (const sal_uChar
* pStr
, sal_Int16 nGlyphs
, sal_Int16 nBytes
,
1081 const sal_Int32
* pDeltaArray
)
1083 PSSetColor (maTextColor
);
1086 // rotate the user coordinate system
1087 if (mnTextAngle
!= 0)
1090 PSRotate (mnTextAngle
);
1093 sal_Char pBuffer
[256];
1094 if( maVirtualStatus
.mbArtBold
)
1096 sal_Int32 nLW
= maVirtualStatus
.mnTextWidth
;
1098 nLW
= maVirtualStatus
.mnTextHeight
;
1100 nLW
= nLW
< maVirtualStatus
.mnTextHeight
? nLW
: maVirtualStatus
.mnTextHeight
;
1101 psp::getValueOfDouble( pBuffer
, (double)nLW
/ 30.0 );
1103 // dispatch to the drawing method
1104 if (pDeltaArray
== NULL
)
1106 PSHexString (pStr
, nBytes
);
1108 if( maVirtualStatus
.mbArtBold
)
1110 WritePS( mpPageBody
, pBuffer
);
1111 WritePS( mpPageBody
, " bshow\n" );
1114 WritePS (mpPageBody
, "show\n");
1118 PSHexString (pStr
, nBytes
);
1119 PSDeltaArray (pDeltaArray
, nGlyphs
- 1);
1120 if( maVirtualStatus
.mbArtBold
)
1122 WritePS( mpPageBody
, pBuffer
);
1123 WritePS( mpPageBody
, " bxshow\n" );
1126 WritePS (mpPageBody
, "xshow\n");
1129 // restore the user coordinate system
1130 if (mnTextAngle
!= 0)
1135 PrinterGfx::PSComment( const sal_Char
* pComment
)
1137 const sal_Char
* pLast
= pComment
;
1138 while( pComment
&& *pComment
)
1140 while( *pComment
&& *pComment
!= '\n' && *pComment
!= '\r' )
1142 if( pComment
- pLast
> 1 )
1144 WritePS( mpPageBody
, "% ", 2 );
1145 WritePS( mpPageBody
, pLast
, pComment
- pLast
);
1146 WritePS( mpPageBody
, "\n", 1 );
1154 PrinterGfx::DrawEPS( const Rectangle
& rBoundingBox
, void* pPtr
, sal_uInt32 nSize
)
1161 sal_Bool bSuccess
= sal_False
;
1163 // first search the BoundingBox of the EPS data
1164 SvMemoryStream
aStream( pPtr
, nSize
, STREAM_READ
);
1165 aStream
.Seek( STREAM_SEEK_TO_BEGIN
);
1169 double fLeft
= 0, fRight
= 0, fTop
= 0, fBottom
= 0;
1170 bool bEndComments
= false;
1171 while( ! aStream
.IsEof()
1172 && ( ( fLeft
== 0 && fRight
== 0 && fTop
== 0 && fBottom
== 0 ) ||
1173 ( aDocTitle
.isEmpty() && bEndComments
== false ) )
1176 aStream
.ReadLine( aLine
);
1177 if( aLine
.getLength() > 1 && aLine
[0] == '%' )
1179 char cChar
= aLine
[1];
1182 if( aLine
.matchIgnoreAsciiCase( OString( "%%BoundingBox:") ) )
1184 aLine
= WhitespaceToSpace( aLine
.getToken(1, ':') );
1185 if( !aLine
.isEmpty() && aLine
.indexOf( "atend" ) == -1 )
1187 fLeft
= StringToDouble( GetCommandLineToken( 0, aLine
) );
1188 fBottom
= StringToDouble( GetCommandLineToken( 1, aLine
) );
1189 fRight
= StringToDouble( GetCommandLineToken( 2, aLine
) );
1190 fTop
= StringToDouble( GetCommandLineToken( 3, aLine
) );
1193 else if( aLine
.matchIgnoreAsciiCase( "%%Title:" ) )
1194 aDocTitle
= WhitespaceToSpace( aLine
.copy( 8 ) );
1195 else if( aLine
.matchIgnoreAsciiCase( "%%EndComments" ) )
1196 bEndComments
= true;
1198 else if( cChar
== ' ' || cChar
== '\t' || cChar
== '\r' || cChar
== '\n' )
1199 bEndComments
= true;
1202 bEndComments
= true;
1205 static sal_uInt16 nEps
= 0;
1206 if( aDocTitle
.isEmpty() )
1207 aDocTitle
= OString::number(nEps
++);
1209 if( fLeft
!= fRight
&& fTop
!= fBottom
)
1211 double fScaleX
= (double)rBoundingBox
.GetWidth()/(fRight
-fLeft
);
1212 double fScaleY
= -(double)rBoundingBox
.GetHeight()/(fTop
-fBottom
);
1213 Point
aTranslatePoint( (int)(rBoundingBox
.Left()-fLeft
*fScaleX
),
1214 (int)(rBoundingBox
.Bottom()+1-fBottom
*fScaleY
) );
1216 WritePS( mpPageBody
,
1217 "/b4_Inc_state save def\n"
1218 "/dict_count countdictstack def\n"
1219 "/op_count count 1 sub def\n"
1221 "/showpage {} def\n"
1222 "0 setgray 0 setlinecap 1 setlinewidth 0 setlinejoin\n"
1223 "10 setmiterlimit [] 0 setdash newpath\n"
1224 "/languagelevel where\n"
1225 "{pop languagelevel\n"
1227 " {false setstrokeadjust false setoverprint\n"
1230 // set up clip path and scale
1231 BeginSetClipRegion( 1 );
1232 UnionClipRegion( rBoundingBox
.Left(), rBoundingBox
.Top(), rBoundingBox
.GetWidth(), rBoundingBox
.GetHeight() );
1234 PSTranslate( aTranslatePoint
);
1235 PSScale( fScaleX
, fScaleY
);
1237 // DSC requires BeginDocument
1238 WritePS( mpPageBody
, "%%BeginDocument: " );
1239 WritePS( mpPageBody
, aDocTitle
);
1240 WritePS( mpPageBody
, "\n" );
1242 // write the EPS data
1243 sal_uInt64 nOutLength
;
1244 mpPageBody
->write( pPtr
, nSize
, nOutLength
);
1245 bSuccess
= nOutLength
== nSize
;
1247 // corresponding EndDocument
1248 if( ((char*)pPtr
)[ nSize
-1 ] != '\n' )
1249 WritePS( mpPageBody
, "\n" );
1250 WritePS( mpPageBody
, "%%EndDocument\n" );
1253 WritePS( mpPageBody
,
1254 "count op_count sub {pop} repeat\n"
1255 "countdictstack dict_count sub {end} repeat\n"
1256 "b4_Inc_state restore\n" );
1261 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */