Bump version to 4.1-6
[LibreOffice.git] / vcl / generic / print / common_gfx.cxx
blob260fbc951cd5688395dff9381d4fbb969382b8d7
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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"
34 using namespace psp ;
36 static const sal_Int32 nMaxTextColumn = 80;
38 GraphicsStatus::GraphicsStatus() :
39 mbArtItalic( false ),
40 mbArtBold( false ),
41 mnTextHeight( 0 ),
42 mnTextWidth( 0 ),
43 mfLineWidth( -1 )
48 * non graphics graphics routines
51 sal_Bool
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 );
67 else
68 mpFontSubstitutes = NULL;
69 mbUploadPS42Fonts = rInfo.m_pParser ? ( rInfo.m_pParser->isType42Capable() ? sal_True : sal_False ) : sal_False;
71 return sal_True;
74 sal_Bool
75 PrinterGfx::Init (const JobData& rData)
77 mpPageHeader = NULL;
78 mpPageBody = NULL;
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();
83 mnDpi = nRes;
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 );
91 else
92 mpFontSubstitutes = NULL;
93 mbUploadPS42Fonts = rInfo.m_pParser ? ( rInfo.m_pParser->isType42Capable() ? sal_True : sal_False ) : sal_False;
95 return sal_True;
98 sal_uInt16
99 PrinterGfx::GetBitCount ()
101 return mnDepth;
104 PrinterGfx::PrinterGfx() :
105 mpPageHeader (NULL),
106 mpPageBody (NULL),
107 mnFontID (0),
108 mnFallbackID (0),
109 mnTextAngle (0),
110 mbTextVertical (false),
111 mrFontMgr (PrintFontManager::get()),
112 mbCompressBmp (sal_True),
113 maFillColor (0xff,0,0),
114 maTextColor (0,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);
139 void
140 PrinterGfx::Clear()
142 mpPageHeader = NULL;
143 mpPageBody = NULL;
144 mnFontID = 0;
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;
154 mnDpi = 300;
155 mnDepth = 24;
156 mnPSLevel = 2;
157 mbColor = sal_True;
158 mnTextAngle = 0;
160 maClipRegion.clear();
161 maGraphicsStack.clear();
162 maGraphicsStack.push_back( GraphicsStatus() );
166 * clip region handling
169 void
170 PrinterGfx::ResetClipRegion()
172 maClipRegion.clear();
173 PSGRestore ();
174 PSGSave (); // get "clean" clippath
177 void
178 PrinterGfx::BeginSetClipRegion( sal_uInt32 )
180 maClipRegion.clear();
183 sal_Bool
184 PrinterGfx::UnionClipRegion (sal_Int32 nX,sal_Int32 nY,sal_Int32 nDX,sal_Int32 nDY)
186 if( nDX && nDY )
187 maClipRegion.push_back (Rectangle(Point(nX,nY ), Size(nDX,nDY)));
188 return sal_True;
191 sal_Bool
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;
198 nextit = it;
199 ++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() )
207 tempit = nextit;
208 ++tempit;
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 ) );
227 aLastRect = *nextit;
228 leftside.push_back( aLastRect.TopLeft() );
229 rightside.push_back( aLastRect.TopRight() );
230 maClipRegion.erase( nextit );
233 nextit = tempit;
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 )
258 continue;
259 if( nDX != 0 && nNewDX != 0 &&
260 (double)nNewDY/(double)nNewDX == (double)nDY/(double)nDX )
261 continue;
263 PSBinLineTo (aPoint, rOldPoint, rColumn);
264 aLastPoint = aPoint;
267 aLastPoint = rightside.back();
268 nDX = -65536;
269 nDY = 65536;
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 )
281 continue;
282 if( nDX != 0 && nNewDX != 0 &&
283 (double)nNewDY/(double)nNewDX == (double)nDY/(double)nDX )
284 continue;
286 PSBinLineTo (aPoint, rOldPoint, rColumn);
289 tempit = it;
290 ++tempit;
291 maClipRegion.erase( it );
292 it = tempit;
293 bSuccess = sal_True;
295 return bSuccess;
298 void
299 PrinterGfx::EndSetClipRegion()
301 PSGRestore ();
302 PSGSave (); // get "clean" clippath
304 PSBinStartPath ();
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 );
320 ++it;
324 PSBinEndPath ();
326 WritePS (mpPageBody, "closepath clip newpath\n");
327 maClipRegion.clear();
331 * draw graphic primitives
334 void
335 PrinterGfx::DrawRect (const Rectangle& rRectangle )
337 char pRect [128];
338 sal_Int32 nChar = 0;
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);
352 PSSetColor ();
353 WritePS (mpPageBody, pRect, nChar);
354 WritePS (mpPageBody, "rectfill\n");
356 if( maLineColor.Is() )
358 PSSetColor (maLineColor);
359 PSSetColor ();
360 PSSetLineWidth ();
361 WritePS (mpPageBody, pRect, nChar);
362 WritePS (mpPageBody, "rectstroke\n");
366 void
367 PrinterGfx::DrawLine (const Point& rFrom, const Point& rTo)
369 if( maLineColor.Is() )
371 PSSetColor (maLineColor);
372 PSSetColor ();
373 PSSetLineWidth ();
375 PSMoveTo (rFrom);
376 PSLineTo (rTo);
377 WritePS (mpPageBody, "stroke\n" );
381 void
382 PrinterGfx::DrawPixel (const Point& rPoint, const PrinterColor& rPixelColor)
384 if( rPixelColor.Is() )
386 PSSetColor (rPixelColor);
387 PSSetColor ();
389 PSMoveTo (rPoint);
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" );
397 void
398 PrinterGfx::DrawPolyLine (sal_uInt32 nPoints, const Point* pPath)
400 if( maLineColor.Is() && nPoints && pPath )
402 PSSetColor (maLineColor);
403 PSSetColor ();
404 PSSetLineWidth ();
406 PSBinCurrentPath (nPoints, pPath);
408 WritePS (mpPageBody, "stroke\n" );
412 void
413 PrinterGfx::DrawPolygon (sal_uInt32 nPoints, const Point* pPath)
415 // premature end of operation
416 if (!(nPoints > 1) || (pPath == NULL) || !(maFillColor.Is() || maLineColor.Is()))
417 return;
419 // setup closed path
420 Point aPoint( 0, 0 );
421 sal_Int32 nColumn( 0 );
423 PSBinStartPath();
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 );
429 PSBinEndPath();
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())
436 PSGSave();
438 if (maFillColor.Is ())
440 PSSetColor (maFillColor);
441 PSSetColor ();
442 WritePS (mpPageBody, "eofill\n");
445 // restore the current path
446 if( maFillColor.Is() && maLineColor.Is())
447 PSGRestore();
449 if (maLineColor.Is ())
451 PSSetColor (maLineColor);
452 PSSetColor ();
453 PSSetLineWidth ();
454 WritePS (mpPageBody, "stroke\n");
458 void
459 PrinterGfx::DrawPolyPolygon (sal_uInt32 nPoly, const sal_uInt32* pSizes, const Point** pPaths )
461 // sanity check
462 if ( !nPoly || !pPaths || !(maFillColor.Is() || maLineColor.Is()))
463 return;
466 // setup closed path
467 for( unsigned int i = 0; i < nPoly; i++ )
469 Point aPoint( 0, 0 );
470 sal_Int32 nColumn( 0 );
472 PSBinStartPath();
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 );
478 PSBinEndPath();
481 // if eofill and stroke, save the current path
482 if( maFillColor.Is() && maLineColor.Is())
483 PSGSave();
485 // first draw area
486 if( maFillColor.Is() )
488 PSSetColor (maFillColor);
489 PSSetColor ();
490 WritePS (mpPageBody, "eofill\n");
493 // restore the current path
494 if( maFillColor.Is() && maLineColor.Is())
495 PSGRestore();
497 // now draw outlines
498 if( maLineColor.Is() )
500 PSSetColor (maLineColor);
501 PSSetColor ();
502 PSSetLineWidth ();
503 WritePS (mpPageBody, "stroke\n");
508 * Bezier Polygon Drawing methods.
511 void
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);
520 PSSetColor ();
521 PSSetLineWidth ();
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());
534 i++;
536 else //Otherwise we're drawing a spline
538 if (i+2 >= nPoints)
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());
548 else
550 OSL_FAIL( "PrinterGfx::DrawPolyLineBezier: Strange output" );
552 i+=3;
554 WritePS(mpPageBody, pString);
557 // now draw outlines
558 WritePS (mpPageBody, "stroke\n");
562 void
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()))
569 return;
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);
579 i++;
581 else
583 if (i+2 >= nPoints)
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);
594 else
596 OSL_FAIL( "PrinterGfx::DrawPolygonBezier: Strange output" );
598 i+=3;
602 // if fill and stroke, save the current path
603 if( maFillColor.Is() && maLineColor.Is())
604 PSGSave();
606 if (maFillColor.Is ())
608 PSSetColor (maFillColor);
609 PSSetColor ();
610 WritePS (mpPageBody, "eofill\n");
613 // restore the current path
614 if( maFillColor.Is() && maLineColor.Is())
615 PSGRestore();
618 void
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()))
624 return;
627 for (unsigned int i=0; i<nPoly;i++)
629 sal_uInt32 nPoints = pPoints[i];
630 // sanity check
631 if( nPoints == 0 || pPtAry[i] == NULL )
632 continue;
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);
644 j++;
646 else
648 if (j+2 >= nPoints)
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);
658 else
660 OSL_FAIL( "PrinterGfx::DrawPolyPolygonBezier: Strange output" );
662 j+=3;
667 // if fill and stroke, save the current path
668 if( maFillColor.Is() && maLineColor.Is())
669 PSGSave();
671 if (maFillColor.Is ())
673 PSSetColor (maFillColor);
674 PSSetColor ();
675 WritePS (mpPageBody, "eofill\n");
678 // restore the current path
679 if( maFillColor.Is() && maLineColor.Is())
680 PSGRestore();
685 * postscript generating routines
687 void
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 );
697 void
698 PrinterGfx::PSGRestore ()
700 WritePS (mpPageBody, "grestore\n" );
701 if( maGraphicsStack.begin() == maGraphicsStack.end() )
702 WritePS (mpPageBody, "Error: too many grestores\n" );
703 else
704 maGraphicsStack.pop_front();
707 void
708 PrinterGfx::PSSetLineWidth ()
710 if( currentState().mfLineWidth != maVirtualStatus.mfLineWidth )
712 char pBuffer[128];
713 sal_Int32 nChar = 0;
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);
722 void
723 PrinterGfx::PSSetColor ()
725 PrinterColor& rColor( maVirtualStatus.maColor );
727 if( currentState().maColor != rColor )
729 currentState().maColor = rColor;
731 char pBuffer[128];
732 sal_Int32 nChar = 0;
734 if( mbColor )
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 );
746 else
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);
758 void
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];
782 sal_Int32 nChar = 0;
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,
793 rCurrent.maFont);
795 nChar += psp::appendStr ("(", pSetFont + nChar);
796 nChar += psp::appendStr (aReencodedFont.getStr(),
797 pSetFont + nChar);
798 nChar += psp::appendStr (") cvn findfont ",
799 pSetFont + nChar);
801 else
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(),
807 pSetFont + nChar);
808 nChar += psp::appendStr (") cvn findfont ",
809 pSetFont + nChar);
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);
835 void
836 PrinterGfx::PSRotate (sal_Int32 nAngle)
838 sal_Int32 nPostScriptAngle = -nAngle;
839 while( nPostScriptAngle < 0 )
840 nPostScriptAngle += 3600;
842 if (nPostScriptAngle == 0)
843 return;
845 sal_Int32 nFullAngle = nPostScriptAngle / 10;
846 sal_Int32 nTenthAngle = nPostScriptAngle % 10;
848 sal_Char pRotate [48];
849 sal_Int32 nChar = 0;
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);
859 void
860 PrinterGfx::PSPointOp (const Point& rPoint, const sal_Char* pOperator)
862 sal_Char pPSCommand [48];
863 sal_Int32 nChar = 0;
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);
877 void
878 PrinterGfx::PSTranslate (const Point& rPoint)
880 PSPointOp (rPoint, "translate");
883 void
884 PrinterGfx::PSMoveTo (const Point& rPoint)
886 PSPointOp (rPoint, "moveto");
889 void
890 PrinterGfx::PSLineTo (const Point& rPoint)
892 PSPointOp (rPoint, "lineto");
895 /* get a compressed representation of the path information */
897 #define DEBUG_BINPATH 0
899 void
900 PrinterGfx::PSBinLineTo (const Point& rCurrent, Point& rOld, sal_Int32& nColumn)
902 #if (DEBUG_BINPATH == 1)
903 PSLineTo (rCurrent);
904 #else
905 PSBinPath (rCurrent, rOld, lineto, nColumn);
906 #endif
909 void
910 PrinterGfx::PSBinMoveTo (const Point& rCurrent, Point& rOld, sal_Int32& nColumn)
912 #if (DEBUG_BINPATH == 1)
913 PSMoveTo (rCurrent);
914 #else
915 PSBinPath (rCurrent, rOld, moveto, nColumn);
916 #endif
919 void
920 PrinterGfx::PSBinStartPath ()
922 #if (DEBUG_BINPATH == 1)
923 WritePS (mpPageBody, "% PSBinStartPath\n");
924 #else
925 WritePS (mpPageBody, "readpath\n" );
926 #endif
929 void
930 PrinterGfx::PSBinEndPath ()
932 #if (DEBUG_BINPATH == 1)
933 WritePS (mpPageBody, "% PSBinEndPath\n");
934 #else
935 WritePS (mpPageBody, "~\n");
936 #endif
939 void
940 PrinterGfx::PSBinCurrentPath (sal_uInt32 nPoints, const Point* pPath)
942 // create the path
943 Point aPoint (0, 0);
944 sal_Int32 nColumn = 0;
946 PSBinStartPath ();
947 PSBinMoveTo (*pPath, aPoint, nColumn);
948 for (unsigned int i = 1; i < nPoints; i++)
949 PSBinLineTo (pPath[i], aPoint, nColumn);
950 PSBinEndPath ();
953 void
954 PrinterGfx::PSBinPath (const Point& rCurrent, Point& rOld,
955 pspath_t eType, sal_Int32& nColumn)
957 sal_Char pPath[48];
958 sal_Int32 nChar;
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);
970 switch (nYPrec)
972 case 2: break;
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");
978 switch (nXPrec)
980 case 2: break;
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");
986 cCmd += 'A';
987 pPath[0] = cCmd;
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;
1002 else
1004 WritePS (mpPageBody, pPath, nChar);
1006 nColumn += nChar;
1009 rOld = rCurrent;
1012 void
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 */
1027 void
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);
1040 nChar = 0;
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 */
1050 void
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);
1065 nChar = 0;
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) */
1079 void
1080 PrinterGfx::PSShowText (const sal_uChar* pStr, sal_Int16 nGlyphs, sal_Int16 nBytes,
1081 const sal_Int32* pDeltaArray)
1083 PSSetColor (maTextColor);
1084 PSSetColor ();
1085 PSSetFont ();
1086 // rotate the user coordinate system
1087 if (mnTextAngle != 0)
1089 PSGSave ();
1090 PSRotate (mnTextAngle);
1093 sal_Char pBuffer[256];
1094 if( maVirtualStatus.mbArtBold )
1096 sal_Int32 nLW = maVirtualStatus.mnTextWidth;
1097 if( nLW == 0 )
1098 nLW = maVirtualStatus.mnTextHeight;
1099 else
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" );
1113 else
1114 WritePS (mpPageBody, "show\n");
1116 else
1118 PSHexString (pStr, nBytes);
1119 PSDeltaArray (pDeltaArray, nGlyphs - 1);
1120 if( maVirtualStatus.mbArtBold )
1122 WritePS( mpPageBody, pBuffer );
1123 WritePS( mpPageBody, " bxshow\n" );
1125 else
1126 WritePS (mpPageBody, "xshow\n");
1129 // restore the user coordinate system
1130 if (mnTextAngle != 0)
1131 PSGRestore ();
1134 void
1135 PrinterGfx::PSComment( const sal_Char* pComment )
1137 const sal_Char* pLast = pComment;
1138 while( pComment && *pComment )
1140 while( *pComment && *pComment != '\n' && *pComment != '\r' )
1141 pComment++;
1142 if( pComment - pLast > 1 )
1144 WritePS( mpPageBody, "% ", 2 );
1145 WritePS( mpPageBody, pLast, pComment - pLast );
1146 WritePS( mpPageBody, "\n", 1 );
1148 if( *pComment )
1149 pLast = ++pComment;
1153 sal_Bool
1154 PrinterGfx::DrawEPS( const Rectangle& rBoundingBox, void* pPtr, sal_uInt32 nSize )
1156 if( nSize == 0 )
1157 return sal_True;
1158 if( ! mpPageBody )
1159 return sal_False;
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 );
1166 OString aLine;
1168 OString aDocTitle;
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];
1180 if( cChar == '%' )
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;
1201 else
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) );
1215 // prepare EPS
1216 WritePS( mpPageBody,
1217 "/b4_Inc_state save def\n"
1218 "/dict_count countdictstack def\n"
1219 "/op_count count 1 sub def\n"
1220 "userdict begin\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"
1226 "1 ne\n"
1227 " {false setstrokeadjust false setoverprint\n"
1228 " } if\n"
1229 "}if\n" );
1230 // set up clip path and scale
1231 BeginSetClipRegion( 1 );
1232 UnionClipRegion( rBoundingBox.Left(), rBoundingBox.Top(), rBoundingBox.GetWidth(), rBoundingBox.GetHeight() );
1233 EndSetClipRegion();
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" );
1252 // clean up EPS
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" );
1258 return bSuccess;
1261 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */