Update ooo320-m1
[ooovba.git] / vcl / unx / source / printergfx / common_gfx.cxx
blobbd4777752b03fb1dbc7e75400e9b13420059f3b6
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
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"
47 using namespace psp ;
49 static const sal_Int32 nMaxTextColumn = 80;
51 GraphicsStatus::GraphicsStatus() :
52 mbArtItalic( false ),
53 mbArtBold( false ),
54 mnTextHeight( 0 ),
55 mnTextWidth( 0 ),
56 mfLineWidth( -1 )
61 * non graphics graphics routines
64 sal_Bool
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 );
80 else
81 mpFontSubstitutes = NULL;
82 mbUploadPS42Fonts = rInfo.m_pParser ? ( rInfo.m_pParser->isType42Capable() ? sal_True : sal_False ) : sal_False;
84 return sal_True;
87 sal_Bool
88 PrinterGfx::Init (const JobData& rData)
90 mpPageHeader = NULL;
91 mpPageBody = NULL;
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();
96 mnDpi = nRes;
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 );
104 else
105 mpFontSubstitutes = NULL;
106 mbUploadPS42Fonts = rInfo.m_pParser ? ( rInfo.m_pParser->isType42Capable() ? sal_True : sal_False ) : sal_False;
108 return sal_True;
111 void
112 PrinterGfx::GetResolution (sal_Int32 &rDpiX, sal_Int32 &rDpiY) const
114 rDpiX = mnDpi;
115 rDpiY = mnDpi;
118 sal_uInt16
119 PrinterGfx::GetBitCount ()
121 return mnDepth;
124 PrinterGfx::PrinterGfx() :
125 mpPageHeader (NULL),
126 mpPageBody (NULL),
127 mnFontID (0),
128 mnFallbackID (0),
129 mnTextAngle (0),
130 mbTextVertical (false),
131 mrFontMgr (PrintFontManager::get()),
132 mbCompressBmp (sal_True),
133 maFillColor (0xff,0,0),
134 maTextColor (0,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);
160 void
161 PrinterGfx::Clear()
163 mpPageHeader = NULL;
164 mpPageBody = NULL;
165 mnFontID = 0;
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;
175 mnDpi = 300;
176 mnDepth = 24;
177 mnPSLevel = 2;
178 mbColor = sal_True;
179 mnTextAngle = 0;
181 maClipRegion.clear();
182 maGraphicsStack.clear();
183 maGraphicsStack.push_back( GraphicsStatus() );
187 * clip region handling
190 void
191 PrinterGfx::ResetClipRegion()
193 maClipRegion.clear();
194 PSGRestore ();
195 PSGSave (); // get "clean" clippath
198 void
199 PrinterGfx::BeginSetClipRegion( sal_uInt32 )
201 maClipRegion.clear();
204 sal_Bool
205 PrinterGfx::UnionClipRegion (sal_Int32 nX,sal_Int32 nY,sal_Int32 nDX,sal_Int32 nDY)
207 if( nDX && nDY )
208 maClipRegion.push_back (Rectangle(Point(nX,nY ), Size(nDX,nDY)));
209 return sal_True;
212 sal_Bool
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;
219 nextit = it;
220 ++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() )
228 tempit = nextit;
229 ++tempit;
230 if( nextit->Top() == aLastRect.Bottom()+1 )
232 if(
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 ) );
248 aLastRect = *nextit;
249 leftside.push_back( aLastRect.TopLeft() );
250 rightside.push_back( aLastRect.TopRight() );
251 maClipRegion.erase( nextit );
254 nextit = tempit;
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 )
279 continue;
280 if( nDX != 0 && nNewDX != 0 &&
281 (double)nNewDY/(double)nNewDX == (double)nDY/(double)nDX )
282 continue;
284 PSBinLineTo (aPoint, rOldPoint, rColumn);
285 aLastPoint = aPoint;
288 aLastPoint = rightside.back();
289 nDX = -65536;
290 nDY = 65536;
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 )
302 continue;
303 if( nDX != 0 && nNewDX != 0 &&
304 (double)nNewDY/(double)nNewDX == (double)nDY/(double)nDX )
305 continue;
307 PSBinLineTo (aPoint, rOldPoint, rColumn);
310 tempit = it;
311 ++tempit;
312 maClipRegion.erase( it );
313 it = tempit;
314 bSuccess = sal_True;
316 return bSuccess;
319 void
320 PrinterGfx::EndSetClipRegion()
322 PSGRestore ();
323 PSGSave (); // get "clean" clippath
325 PSBinStartPath ();
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 );
341 ++it;
345 PSBinEndPath ();
347 WritePS (mpPageBody, "closepath clip newpath\n");
348 maClipRegion.clear();
352 * draw graphic primitives
355 void
356 PrinterGfx::DrawRect (const Rectangle& rRectangle )
358 char pRect [128];
359 sal_Int32 nChar = 0;
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);
373 PSSetColor ();
374 WritePS (mpPageBody, pRect, nChar);
375 WritePS (mpPageBody, "rectfill\n");
377 if( maLineColor.Is() )
379 PSSetColor (maLineColor);
380 PSSetColor ();
381 PSSetLineWidth ();
382 WritePS (mpPageBody, pRect, nChar);
383 WritePS (mpPageBody, "rectstroke\n");
387 void
388 PrinterGfx::DrawLine (const Point& rFrom, const Point& rTo)
390 if( maLineColor.Is() )
392 PSSetColor (maLineColor);
393 PSSetColor ();
394 PSSetLineWidth ();
396 PSMoveTo (rFrom);
397 PSLineTo (rTo);
398 WritePS (mpPageBody, "stroke\n" );
402 void
403 PrinterGfx::DrawPixel (const Point& rPoint, const PrinterColor& rPixelColor)
405 if( rPixelColor.Is() )
407 PSSetColor (rPixelColor);
408 PSSetColor ();
410 PSMoveTo (rPoint);
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" );
418 void
419 PrinterGfx::DrawPolyLine (sal_uInt32 nPoints, const Point* pPath)
421 if( maLineColor.Is() && nPoints && pPath )
423 PSSetColor (maLineColor);
424 PSSetColor ();
425 PSSetLineWidth ();
427 PSBinCurrentPath (nPoints, pPath);
429 WritePS (mpPageBody, "stroke\n" );
433 void
434 PrinterGfx::DrawPolygon (sal_uInt32 nPoints, const Point* pPath)
436 // premature end of operation
437 if (!(nPoints > 1) || (pPath == NULL) || !(maFillColor.Is() || maLineColor.Is()))
438 return;
440 // setup closed path
441 Point aPoint( 0, 0 );
442 sal_Int32 nColumn( 0 );
444 PSBinStartPath();
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 );
450 PSBinEndPath();
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())
457 PSGSave();
459 if (maFillColor.Is ())
461 PSSetColor (maFillColor);
462 PSSetColor ();
463 WritePS (mpPageBody, "eofill\n");
466 // restore the current path
467 if( maFillColor.Is() && maLineColor.Is())
468 PSGRestore();
470 if (maLineColor.Is ())
472 PSSetColor (maLineColor);
473 PSSetColor ();
474 PSSetLineWidth ();
475 WritePS (mpPageBody, "stroke\n");
479 void
480 PrinterGfx::DrawPolyPolygon (sal_uInt32 nPoly, const sal_uInt32* pSizes, const Point** pPaths )
482 // sanity check
483 if ( !nPoly || !pPaths || !(maFillColor.Is() || maLineColor.Is()))
484 return;
487 // setup closed path
488 for( unsigned int i = 0; i < nPoly; i++ )
490 Point aPoint( 0, 0 );
491 sal_Int32 nColumn( 0 );
493 PSBinStartPath();
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 );
499 PSBinEndPath();
502 // if eofill and stroke, save the current path
503 if( maFillColor.Is() && maLineColor.Is())
504 PSGSave();
506 // first draw area
507 if( maFillColor.Is() )
509 PSSetColor (maFillColor);
510 PSSetColor ();
511 WritePS (mpPageBody, "eofill\n");
514 // restore the current path
515 if( maFillColor.Is() && maLineColor.Is())
516 PSGRestore();
518 // now draw outlines
519 if( maLineColor.Is() )
521 PSSetColor (maLineColor);
522 PSSetColor ();
523 PSSetLineWidth ();
524 WritePS (mpPageBody, "stroke\n");
529 * Bezier Polygon Drawing methods.
532 void
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);
541 PSSetColor ();
542 PSSetLineWidth ();
544 if (pFlgAry[0] != POLY_NORMAL) //There must be a starting point to moveto
546 return;
548 else
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());
563 i++;
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());
572 i+=3;
574 WritePS(mpPageBody, pString);
578 // if eofill and stroke, save the current path
579 if( maFillColor.Is() && maLineColor.Is())
580 PSGSave();
582 // first draw area
583 if( maFillColor.Is() )
585 PSSetColor (maFillColor);
586 PSSetColor ();
587 WritePS (mpPageBody, "eofill\n");
590 // restore the current path
591 if( maFillColor.Is() && maLineColor.Is())
592 PSGRestore();
594 // now draw outlines
595 if( maLineColor.Is() )
597 PSSetColor (maLineColor);
598 PSSetColor ();
599 PSSetLineWidth ();
600 WritePS (mpPageBody, "stroke\n");
604 void
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()))
611 return;
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);
621 i++;
623 else
625 if (i+2 >= nPoints)
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);
636 else
638 fprintf(stderr, "Strange output\n");
640 i+=3;
644 // if fill and stroke, save the current path
645 if( maFillColor.Is() && maLineColor.Is())
646 PSGSave();
648 if (maFillColor.Is ())
650 PSSetColor (maFillColor);
651 PSSetColor ();
652 WritePS (mpPageBody, "eofill\n");
655 // restore the current path
656 if( maFillColor.Is() && maLineColor.Is())
657 PSGRestore();
660 void
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()))
666 return;
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 )
674 continue;
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);
686 j++;
688 else
690 if (j+2 >= nPoints)
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);
700 else
702 #if OSL_DEBUG_LEVEL > 1
703 fprintf(stderr, "Strange output\n");
704 #endif
706 j+=3;
711 // if fill and stroke, save the current path
712 if( maFillColor.Is() && maLineColor.Is())
713 PSGSave();
715 if (maFillColor.Is ())
717 PSSetColor (maFillColor);
718 PSSetColor ();
719 WritePS (mpPageBody, "eofill\n");
722 // restore the current path
723 if( maFillColor.Is() && maLineColor.Is())
724 PSGRestore();
729 * postscript generating routines
731 void
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 );
741 void
742 PrinterGfx::PSGRestore ()
744 WritePS (mpPageBody, "grestore\n" );
745 if( maGraphicsStack.begin() == maGraphicsStack.end() )
746 WritePS (mpPageBody, "Error: too many grestores\n" );
747 else
748 maGraphicsStack.pop_front();
751 void
752 PrinterGfx::PSSetLineWidth ()
754 if( currentState().mfLineWidth != maVirtualStatus.mfLineWidth )
756 char pBuffer[128];
757 sal_Int32 nChar = 0;
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);
766 void
767 PrinterGfx::PSSetColor ()
769 PrinterColor& rColor( maVirtualStatus.maColor );
771 if( currentState().maColor != rColor )
773 currentState().maColor = rColor;
775 char pBuffer[128];
776 sal_Int32 nChar = 0;
778 if( mbColor )
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 );
790 else
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);
802 void
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];
826 sal_Int32 nChar = 0;
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,
837 rCurrent.maFont);
839 nChar += psp::appendStr ("(", pSetFont + nChar);
840 nChar += psp::appendStr (aReencodedFont.getStr(),
841 pSetFont + nChar);
842 nChar += psp::appendStr (") cvn findfont ",
843 pSetFont + nChar);
845 else
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(),
851 pSetFont + nChar);
852 nChar += psp::appendStr (") cvn findfont ",
853 pSetFont + nChar);
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);
879 void
880 PrinterGfx::PSRotate (sal_Int32 nAngle)
882 sal_Int32 nPostScriptAngle = -nAngle;
883 while( nPostScriptAngle < 0 )
884 nPostScriptAngle += 3600;
886 if (nPostScriptAngle == 0)
887 return;
889 sal_Int32 nFullAngle = nPostScriptAngle / 10;
890 sal_Int32 nTenthAngle = nPostScriptAngle % 10;
892 sal_Char pRotate [48];
893 sal_Int32 nChar = 0;
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);
903 void
904 PrinterGfx::PSPointOp (const Point& rPoint, const sal_Char* pOperator)
906 sal_Char pPSCommand [48];
907 sal_Int32 nChar = 0;
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);
921 void
922 PrinterGfx::PSTranslate (const Point& rPoint)
924 PSPointOp (rPoint, "translate");
927 void
928 PrinterGfx::PSMoveTo (const Point& rPoint)
930 PSPointOp (rPoint, "moveto");
933 void
934 PrinterGfx::PSLineTo (const Point& rPoint)
936 PSPointOp (rPoint, "lineto");
939 void
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
950 void
951 PrinterGfx::PSBinLineTo (const Point& rCurrent, Point& rOld, sal_Int32& nColumn)
953 #if (DEBUG_BINPATH == 1)
954 PSLineTo (rCurrent);
955 #else
956 PSBinPath (rCurrent, rOld, lineto, nColumn);
957 #endif
960 void
961 PrinterGfx::PSBinMoveTo (const Point& rCurrent, Point& rOld, sal_Int32& nColumn)
963 #if (DEBUG_BINPATH == 1)
964 PSMoveTo (rCurrent);
965 #else
966 PSBinPath (rCurrent, rOld, moveto, nColumn);
967 #endif
970 void
971 PrinterGfx::PSBinStartPath ()
973 #if (DEBUG_BINPATH == 1)
974 WritePS (mpPageBody, "% PSBinStartPath\n");
975 #else
976 WritePS (mpPageBody, "readpath\n" );
977 #endif
980 void
981 PrinterGfx::PSBinEndPath ()
983 #if (DEBUG_BINPATH == 1)
984 WritePS (mpPageBody, "% PSBinEndPath\n");
985 #else
986 WritePS (mpPageBody, "~\n");
987 #endif
990 void
991 PrinterGfx::PSBinCurrentPath (sal_uInt32 nPoints, const Point* pPath)
993 // create the path
994 Point aPoint (0, 0);
995 sal_Int32 nColumn = 0;
997 PSBinStartPath ();
998 PSBinMoveTo (*pPath, aPoint, nColumn);
999 for (unsigned int i = 1; i < nPoints; i++)
1000 PSBinLineTo (pPath[i], aPoint, nColumn);
1001 PSBinEndPath ();
1004 void
1005 PrinterGfx::PSBinPath (const Point& rCurrent, Point& rOld,
1006 pspath_t eType, sal_Int32& nColumn)
1008 sal_Char pPath[48];
1009 sal_Int32 nChar;
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);
1021 switch (nYPrec)
1023 case 2: break;
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");
1029 switch (nXPrec)
1031 case 2: break;
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");
1037 cCmd += 'A';
1038 pPath[0] = cCmd;
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;
1053 else
1055 WritePS (mpPageBody, pPath, nChar);
1057 nColumn += nChar;
1060 rOld = rCurrent;
1063 void
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 */
1078 void
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);
1091 nChar = 0;
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 */
1101 void
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);
1116 nChar = 0;
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) */
1130 void
1131 PrinterGfx::PSShowText (const sal_uChar* pStr, sal_Int16 nGlyphs, sal_Int16 nBytes,
1132 const sal_Int32* pDeltaArray)
1134 PSSetColor (maTextColor);
1135 PSSetColor ();
1136 PSSetFont ();
1137 // rotate the user coordinate system
1138 if (mnTextAngle != 0)
1140 PSGSave ();
1141 PSRotate (mnTextAngle);
1144 sal_Char pBuffer[256];
1145 if( maVirtualStatus.mbArtBold )
1147 sal_Int32 nLW = maVirtualStatus.mnTextWidth;
1148 if( nLW == 0 )
1149 nLW = maVirtualStatus.mnTextHeight;
1150 else
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" );
1164 else
1165 WritePS (mpPageBody, "show\n");
1167 else
1169 PSHexString (pStr, nBytes);
1170 PSDeltaArray (pDeltaArray, nGlyphs - 1);
1171 if( maVirtualStatus.mbArtBold )
1173 WritePS( mpPageBody, pBuffer );
1174 WritePS( mpPageBody, " bxshow\n" );
1176 else
1177 WritePS (mpPageBody, "xshow\n");
1180 // restore the user coordinate system
1181 if (mnTextAngle != 0)
1182 PSGRestore ();
1185 void
1186 PrinterGfx::PSComment( const sal_Char* pComment )
1188 const sal_Char* pLast = pComment;
1189 while( pComment && *pComment )
1191 while( *pComment && *pComment != '\n' && *pComment != '\r' )
1192 pComment++;
1193 if( pComment - pLast > 1 )
1195 WritePS( mpPageBody, "% ", 2 );
1196 WritePS( mpPageBody, pLast, pComment - pLast );
1197 WritePS( mpPageBody, "\n", 1 );
1199 if( *pComment )
1200 pLast = ++pComment;
1204 sal_Bool
1205 PrinterGfx::DrawEPS( const Rectangle& rBoundingBox, void* pPtr, sal_uInt32 nSize )
1207 if( nSize == 0 )
1208 return sal_True;
1209 if( ! mpPageBody )
1210 return sal_False;
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 );
1217 ByteString aLine;
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);
1231 if( cChar == '%' )
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;
1252 else
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) );
1266 // prepare EPS
1267 WritePS( mpPageBody,
1268 "/b4_Inc_state save def\n"
1269 "/dict_count countdictstack def\n"
1270 "/op_count count 1 sub def\n"
1271 "userdict begin\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"
1277 "1 ne\n"
1278 " {false setstrokeadjust false setoverprint\n"
1279 " } if\n"
1280 "}if\n" );
1281 // set up clip path and scale
1282 BeginSetClipRegion( 1 );
1283 UnionClipRegion( rBoundingBox.Left(), rBoundingBox.Top(), rBoundingBox.GetWidth(), rBoundingBox.GetHeight() );
1284 EndSetClipRegion();
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" );
1303 // clean up EPS
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" );
1309 return bSuccess;