Branch libreoffice-5-0-4
[LibreOffice.git] / vcl / generic / print / common_gfx.cxx
blobb02c57706c27dbc0b53ccf6a22e035cd94a0646a
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 .
20 #include <sal/config.h>
22 #include <cstdlib>
24 #include "psputil.hxx"
25 #include "glyphset.hxx"
27 #include "generic/printergfx.hxx"
28 #include "generic/printerjob.hxx"
29 #include "fontmanager.hxx"
30 #include "vcl/strhelper.hxx"
31 #include "vcl/printerinfomanager.hxx"
33 #include "tools/debug.hxx"
34 #include "tools/color.hxx"
35 #include "tools/poly.hxx"
37 using namespace psp ;
39 static const sal_Int32 nMaxTextColumn = 80;
41 GraphicsStatus::GraphicsStatus() :
42 maEncoding(RTL_TEXTENCODING_DONTKNOW),
43 mbArtItalic( false ),
44 mbArtBold( false ),
45 mnTextHeight( 0 ),
46 mnTextWidth( 0 ),
47 mfLineWidth( -1 )
52 * non graphics graphics routines
55 bool
56 PrinterGfx::Init (PrinterJob &rPrinterJob)
58 mpPageHeader = rPrinterJob.GetCurrentPageHeader ();
59 mpPageBody = rPrinterJob.GetCurrentPageBody ();
60 mnDepth = rPrinterJob.GetDepth ();
61 mnPSLevel = rPrinterJob.GetPostscriptLevel ();
62 mbColor = rPrinterJob.IsColorPrinter ();
64 mnDpi = rPrinterJob.GetResolution();
65 rPrinterJob.GetScale (mfScaleX, mfScaleY);
66 const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( rPrinterJob.GetPrinterName() ) );
67 mbUploadPS42Fonts = rInfo.m_pParser && rInfo.m_pParser->isType42Capable();
69 return true;
72 bool
73 PrinterGfx::Init (const JobData& rData)
75 mpPageHeader = NULL;
76 mpPageBody = NULL;
77 mnDepth = rData.m_nColorDepth;
78 mnPSLevel = rData.m_nPSLevel ? rData.m_nPSLevel : (rData.m_pParser ? rData.m_pParser->getLanguageLevel() : 2 );
79 mbColor = rData.m_nColorDevice ? ( rData.m_nColorDevice != -1 ) : ( rData.m_pParser == nullptr || rData.m_pParser->isColorDevice() );
80 int nRes = rData.m_aContext.getRenderResolution();
81 mnDpi = nRes;
82 mfScaleX = (double)72.0 / (double)mnDpi;
83 mfScaleY = (double)72.0 / (double)mnDpi;
84 const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( rData.m_aPrinterName ) );
85 mbUploadPS42Fonts = rInfo.m_pParser && rInfo.m_pParser->isType42Capable();
87 return true;
91 PrinterGfx::PrinterGfx()
92 : mfScaleX(0.0)
93 , mfScaleY(0.0)
94 , mnDpi(0)
95 , mnDepth(0)
96 , mnPSLevel(0)
97 , mbColor(false)
98 , mbUploadPS42Fonts(false)
99 , mpPageHeader(NULL)
100 , mpPageBody(NULL)
101 , mnFontID(0)
102 , mnFallbackID(0)
103 , mnTextAngle(0)
104 , mbTextVertical(false)
105 , mrFontMgr(PrintFontManager::get())
106 , mbCompressBmp(true)
107 , maFillColor(0xff,0,0)
108 , maTextColor(0,0,0)
109 , maLineColor(0, 0xff, 0)
111 maVirtualStatus.mfLineWidth = 1.0;
112 maVirtualStatus.mnTextHeight = 12;
113 maVirtualStatus.mnTextWidth = 0;
115 maGraphicsStack.push_back( GraphicsStatus() );
118 PrinterGfx::~PrinterGfx()
122 void
123 PrinterGfx::Clear()
125 mpPageHeader = NULL;
126 mpPageBody = NULL;
127 mnFontID = 0;
128 maVirtualStatus = GraphicsStatus();
129 maVirtualStatus.mnTextHeight = 12;
130 maVirtualStatus.mnTextWidth = 0;
131 maVirtualStatus.mfLineWidth = 1.0;
132 mbTextVertical = false;
133 maLineColor = PrinterColor();
134 maFillColor = PrinterColor();
135 maTextColor = PrinterColor();
136 mbCompressBmp = true;
137 mnDpi = 300;
138 mnDepth = 24;
139 mnPSLevel = 2;
140 mbColor = true;
141 mnTextAngle = 0;
143 maClipRegion.clear();
144 maGraphicsStack.clear();
145 maGraphicsStack.push_back( GraphicsStatus() );
149 * clip region handling
152 void
153 PrinterGfx::ResetClipRegion()
155 maClipRegion.clear();
156 PSGRestore ();
157 PSGSave (); // get "clean" clippath
160 void
161 PrinterGfx::BeginSetClipRegion( sal_uInt32 )
163 maClipRegion.clear();
166 bool
167 PrinterGfx::UnionClipRegion (sal_Int32 nX,sal_Int32 nY,sal_Int32 nDX,sal_Int32 nDY)
169 if( nDX && nDY )
170 maClipRegion.push_back (Rectangle(Point(nX,nY ), Size(nDX,nDY)));
171 return true;
174 bool
175 PrinterGfx::JoinVerticalClipRectangles( std::list< Rectangle >::iterator& it,
176 Point& rOldPoint, sal_Int32& rColumn )
178 bool bSuccess = false;
180 std::list< Rectangle >::iterator tempit, nextit;
181 nextit = it;
182 ++nextit;
183 std::list< Point > leftside, rightside;
185 Rectangle aLastRect( *it );
186 leftside.push_back( Point( it->Left(), it->Top() ) );
187 rightside.push_back( Point( it->Right()+1, it->Top() ) );
188 while( nextit != maClipRegion.end() )
190 tempit = nextit;
191 ++tempit;
192 if( nextit->Top() == aLastRect.Bottom()+1 )
195 ( nextit->Left() >= aLastRect.Left() && nextit->Left() <= aLastRect.Right() ) // left endpoint touches last rectangle
197 ( nextit->Right() >= aLastRect.Left() && nextit->Right() <= aLastRect.Right() ) // right endpoint touches last rectangle
199 ( nextit->Left() <= aLastRect.Left() && nextit->Right() >= aLastRect.Right() ) // whole line touches last rectangle
202 if( aLastRect.GetHeight() > 1 ||
203 std::abs( aLastRect.Left() - nextit->Left() ) > 2 ||
204 std::abs( aLastRect.Right() - nextit->Right() ) > 2
207 leftside.push_back( Point( aLastRect.Left(), aLastRect.Bottom()+1 ) );
208 rightside.push_back( Point( aLastRect.Right()+1, aLastRect.Bottom()+1 ) );
210 aLastRect = *nextit;
211 leftside.push_back( aLastRect.TopLeft() );
212 rightside.push_back( aLastRect.TopRight() );
213 maClipRegion.erase( nextit );
216 nextit = tempit;
218 if( leftside.size() > 1 )
220 // push the last coordinates
221 leftside.push_back( Point( aLastRect.Left(), aLastRect.Bottom()+1 ) );
222 rightside.push_back( Point( aLastRect.Right()+1, aLastRect.Bottom()+1 ) );
224 // cool, we can concatenate rectangles
225 const int nDX = -65536, nDY = 65536;
226 int nNewDX = 0, nNewDY = 0;
228 Point aLastPoint = leftside.front();
229 PSBinMoveTo (aLastPoint, rOldPoint, rColumn);
230 leftside.pop_front();
231 while( leftside.begin() != leftside.end() )
233 Point aPoint (leftside.front());
234 leftside.pop_front();
235 // may have been the last one
236 if( leftside.begin() != leftside.end() )
238 nNewDX = aPoint.X() - aLastPoint.X();
239 nNewDY = aPoint.Y() - aLastPoint.Y();
240 if( nNewDX != 0 &&
241 (double)nNewDY/(double)nNewDX == (double)nDY/(double)nDX )
242 continue;
244 PSBinLineTo (aPoint, rOldPoint, rColumn);
245 aLastPoint = aPoint;
248 aLastPoint = rightside.back();
249 PSBinLineTo (aLastPoint, rOldPoint, rColumn);
250 rightside.pop_back();
251 while( rightside.begin() != rightside.end() )
253 Point aPoint (rightside.back());
254 rightside.pop_back();
255 if( rightside.begin() != rightside.end() )
257 nNewDX = aPoint.X() - aLastPoint.X();
258 nNewDY = aPoint.Y() - aLastPoint.Y();
259 if( nNewDX != 0 &&
260 (double)nNewDY/(double)nNewDX == (double)nDY/(double)nDX )
261 continue;
263 PSBinLineTo (aPoint, rOldPoint, rColumn);
266 tempit = it;
267 ++tempit;
268 maClipRegion.erase( it );
269 it = tempit;
270 bSuccess = true;
272 return bSuccess;
275 void
276 PrinterGfx::EndSetClipRegion()
278 PSGRestore ();
279 PSGSave (); // get "clean" clippath
281 PSBinStartPath ();
282 Point aOldPoint (0, 0);
283 sal_Int32 nColumn = 0;
285 std::list< Rectangle >::iterator it = maClipRegion.begin();
286 while( it != maClipRegion.end() )
288 // try to concatenate adjacent rectangles
289 // first try in y direction, then in x direction
290 if( ! JoinVerticalClipRectangles( it, aOldPoint, nColumn ) )
292 // failed, so it is a single rectangle
293 PSBinMoveTo (Point( it->Left()-1, it->Top()-1), aOldPoint, nColumn );
294 PSBinLineTo (Point( it->Left()-1, it->Bottom()+1 ), aOldPoint, nColumn );
295 PSBinLineTo (Point( it->Right()+1, it->Bottom()+1 ), aOldPoint, nColumn );
296 PSBinLineTo (Point( it->Right()+1, it->Top()-1 ), aOldPoint, nColumn );
297 ++it;
301 PSBinEndPath ();
303 WritePS (mpPageBody, "closepath clip newpath\n");
304 maClipRegion.clear();
308 * draw graphic primitives
311 void
312 PrinterGfx::DrawRect (const Rectangle& rRectangle )
314 char pRect [128];
315 sal_Int32 nChar = 0;
317 nChar = psp::getValueOf (rRectangle.TopLeft().X(), pRect);
318 nChar += psp::appendStr (" ", pRect + nChar);
319 nChar += psp::getValueOf (rRectangle.TopLeft().Y(), pRect + nChar);
320 nChar += psp::appendStr (" ", pRect + nChar);
321 nChar += psp::getValueOf (rRectangle.GetWidth(), pRect + nChar);
322 nChar += psp::appendStr (" ", pRect + nChar);
323 nChar += psp::getValueOf (rRectangle.GetHeight(), pRect + nChar);
324 nChar += psp::appendStr (" ", pRect + nChar);
326 if( maFillColor.Is() )
328 PSSetColor (maFillColor);
329 PSSetColor ();
330 WritePS (mpPageBody, pRect, nChar);
331 WritePS (mpPageBody, "rectfill\n");
333 if( maLineColor.Is() )
335 PSSetColor (maLineColor);
336 PSSetColor ();
337 PSSetLineWidth ();
338 WritePS (mpPageBody, pRect, nChar);
339 WritePS (mpPageBody, "rectstroke\n");
343 void
344 PrinterGfx::DrawLine (const Point& rFrom, const Point& rTo)
346 if( maLineColor.Is() )
348 PSSetColor (maLineColor);
349 PSSetColor ();
350 PSSetLineWidth ();
352 PSMoveTo (rFrom);
353 PSLineTo (rTo);
354 WritePS (mpPageBody, "stroke\n" );
358 void
359 PrinterGfx::DrawPixel (const Point& rPoint, const PrinterColor& rPixelColor)
361 if( rPixelColor.Is() )
363 PSSetColor (rPixelColor);
364 PSSetColor ();
366 PSMoveTo (rPoint);
367 PSLineTo (Point (rPoint.X ()+1, rPoint.Y ()));
368 PSLineTo (Point (rPoint.X ()+1, rPoint.Y ()+1));
369 PSLineTo (Point (rPoint.X (), rPoint.Y ()+1));
370 WritePS (mpPageBody, "fill\n" );
374 void
375 PrinterGfx::DrawPolyLine (sal_uInt32 nPoints, const Point* pPath)
377 if( maLineColor.Is() && nPoints && pPath )
379 PSSetColor (maLineColor);
380 PSSetColor ();
381 PSSetLineWidth ();
383 PSBinCurrentPath (nPoints, pPath);
385 WritePS (mpPageBody, "stroke\n" );
389 void
390 PrinterGfx::DrawPolygon (sal_uInt32 nPoints, const Point* pPath)
392 // premature end of operation
393 if (!(nPoints > 1) || (pPath == NULL) || !(maFillColor.Is() || maLineColor.Is()))
394 return;
396 // setup closed path
397 Point aPoint( 0, 0 );
398 sal_Int32 nColumn( 0 );
400 PSBinStartPath();
401 PSBinMoveTo( pPath[0], aPoint, nColumn );
402 for( unsigned int n = 1; n < nPoints; n++ )
403 PSBinLineTo( pPath[n], aPoint, nColumn );
404 if( pPath[0] != pPath[nPoints-1] )
405 PSBinLineTo( pPath[0], aPoint, nColumn );
406 PSBinEndPath();
408 // fill the polygon first, then draw the border, note that fill and
409 // stroke reset the currentpath
411 // if fill and stroke, save the current path
412 if( maFillColor.Is() && maLineColor.Is())
413 PSGSave();
415 if (maFillColor.Is ())
417 PSSetColor (maFillColor);
418 PSSetColor ();
419 WritePS (mpPageBody, "eofill\n");
422 // restore the current path
423 if( maFillColor.Is() && maLineColor.Is())
424 PSGRestore();
426 if (maLineColor.Is ())
428 PSSetColor (maLineColor);
429 PSSetColor ();
430 PSSetLineWidth ();
431 WritePS (mpPageBody, "stroke\n");
435 void
436 PrinterGfx::DrawPolyPolygon (sal_uInt32 nPoly, const sal_uInt32* pSizes, const Point** pPaths )
438 // sanity check
439 if ( !nPoly || !pPaths || !(maFillColor.Is() || maLineColor.Is()))
440 return;
442 // setup closed path
443 for( unsigned int i = 0; i < nPoly; i++ )
445 Point aPoint( 0, 0 );
446 sal_Int32 nColumn( 0 );
448 PSBinStartPath();
449 PSBinMoveTo( pPaths[i][0], aPoint, nColumn );
450 for( unsigned int n = 1; n < pSizes[i]; n++ )
451 PSBinLineTo( pPaths[i][n], aPoint, nColumn );
452 if( pPaths[i][0] != pPaths[i][pSizes[i]-1] )
453 PSBinLineTo( pPaths[i][0], aPoint, nColumn );
454 PSBinEndPath();
457 // if eofill and stroke, save the current path
458 if( maFillColor.Is() && maLineColor.Is())
459 PSGSave();
461 // first draw area
462 if( maFillColor.Is() )
464 PSSetColor (maFillColor);
465 PSSetColor ();
466 WritePS (mpPageBody, "eofill\n");
469 // restore the current path
470 if( maFillColor.Is() && maLineColor.Is())
471 PSGRestore();
473 // now draw outlines
474 if( maLineColor.Is() )
476 PSSetColor (maLineColor);
477 PSSetColor ();
478 PSSetLineWidth ();
479 WritePS (mpPageBody, "stroke\n");
484 * Bezier Polygon Drawing methods.
487 void
488 PrinterGfx::DrawPolyLineBezier (sal_uInt32 nPoints, const Point* pPath, const sal_uInt8* pFlgAry)
490 const sal_uInt32 nBezString= 1024;
491 sal_Char pString[nBezString];
493 if ( nPoints > 1 && maLineColor.Is() && pPath )
495 PSSetColor (maLineColor);
496 PSSetColor ();
497 PSSetLineWidth ();
499 snprintf(pString, nBezString, "%li %li moveto\n", pPath[0].X(), pPath[0].Y());
500 WritePS(mpPageBody, pString);
502 // Handle the drawing of mixed lines mixed with curves
503 // - a normal point followed by a normal point is a line
504 // - a normal point followed by 2 control points and a normal point is a curve
505 for (unsigned int i=1; i<nPoints;)
507 if (pFlgAry[i] != POLY_CONTROL) //If the next point is a POLY_NORMAL, we're drawing a line
509 snprintf(pString, nBezString, "%li %li lineto\n", pPath[i].X(), pPath[i].Y());
510 i++;
512 else //Otherwise we're drawing a spline
514 if (i+2 >= nPoints)
515 return; //Error: wrong sequence of contol/normal points somehow
516 if ((pFlgAry[i] == POLY_CONTROL) && (pFlgAry[i+1] == POLY_CONTROL) &&
517 (pFlgAry[i+2] != POLY_CONTROL))
519 snprintf(pString, nBezString, "%li %li %li %li %li %li curveto\n",
520 pPath[i].X(), pPath[i].Y(),
521 pPath[i+1].X(), pPath[i+1].Y(),
522 pPath[i+2].X(), pPath[i+2].Y());
524 else
526 OSL_FAIL( "PrinterGfx::DrawPolyLineBezier: Strange output" );
528 i+=3;
530 WritePS(mpPageBody, pString);
533 // now draw outlines
534 WritePS (mpPageBody, "stroke\n");
538 void
539 PrinterGfx::DrawPolygonBezier (sal_uInt32 nPoints, const Point* pPath, const sal_uInt8* pFlgAry)
541 const sal_uInt32 nBezString = 1024;
542 sal_Char pString[nBezString];
543 // premature end of operation
544 if (!(nPoints > 1) || (pPath == NULL) || !(maFillColor.Is() || maLineColor.Is()))
545 return;
547 snprintf(pString, nBezString, "%li %li moveto\n", pPath[0].X(), pPath[0].Y());
548 WritePS(mpPageBody, pString); //Move to the starting point for the PolyPoygon
549 for (unsigned int i=1; i < nPoints;)
551 if (pFlgAry[i] != POLY_CONTROL)
553 snprintf(pString, nBezString, "%li %li lineto\n", pPath[i].X(), pPath[i].Y());
554 WritePS(mpPageBody, pString);
555 i++;
557 else
559 if (i+2 >= nPoints)
560 return; //Error: wrong sequence of contol/normal points somehow
561 if ((pFlgAry[i] == POLY_CONTROL) && (pFlgAry[i+1] == POLY_CONTROL) &&
562 (pFlgAry[i+2] != POLY_CONTROL))
564 snprintf(pString, nBezString, "%li %li %li %li %li %li curveto\n",
565 pPath[i].X(), pPath[i].Y(),
566 pPath[i+1].X(), pPath[i+1].Y(),
567 pPath[i+2].X(), pPath[i+2].Y());
568 WritePS(mpPageBody, pString);
570 else
572 OSL_FAIL( "PrinterGfx::DrawPolygonBezier: Strange output" );
574 i+=3;
578 // if fill and stroke, save the current path
579 if( maFillColor.Is() && maLineColor.Is())
580 PSGSave();
582 if (maFillColor.Is ())
584 PSSetColor (maFillColor);
585 PSSetColor ();
586 WritePS (mpPageBody, "eofill\n");
589 // restore the current path
590 if( maFillColor.Is() && maLineColor.Is())
591 PSGRestore();
594 void
595 PrinterGfx::DrawPolyPolygonBezier (sal_uInt32 nPoly, const sal_uInt32 * pPoints, const Point* const * pPtAry, const sal_uInt8* const* pFlgAry)
597 const sal_uInt32 nBezString = 1024;
598 sal_Char pString[nBezString];
599 if ( !nPoly || !pPtAry || !pPoints || !(maFillColor.Is() || maLineColor.Is()))
600 return;
602 for (unsigned int i=0; i<nPoly;i++)
604 sal_uInt32 nPoints = pPoints[i];
605 // sanity check
606 if( nPoints == 0 || pPtAry[i] == NULL )
607 continue;
609 snprintf(pString, nBezString, "%li %li moveto\n", pPtAry[i][0].X(), pPtAry[i][0].Y()); //Move to the starting point
610 WritePS(mpPageBody, pString);
611 for (unsigned int j=1; j < nPoints;)
613 // if no flag array exists for this polygon, then it must be a regular
614 // polygon without beziers
615 if ( ! pFlgAry[i] || pFlgAry[i][j] != POLY_CONTROL)
617 snprintf(pString, nBezString, "%li %li lineto\n", pPtAry[i][j].X(), pPtAry[i][j].Y());
618 WritePS(mpPageBody, pString);
619 j++;
621 else
623 if (j+2 >= nPoints)
624 break; //Error: wrong sequence of contol/normal points somehow
625 if ((pFlgAry[i][j] == POLY_CONTROL) && (pFlgAry[i][j+1] == POLY_CONTROL) && (pFlgAry[i][j+2] != POLY_CONTROL))
627 snprintf(pString, nBezString, "%li %li %li %li %li %li curveto\n",
628 pPtAry[i][j].X(), pPtAry[i][j].Y(),
629 pPtAry[i][j+1].X(), pPtAry[i][j+1].Y(),
630 pPtAry[i][j+2].X(), pPtAry[i][j+2].Y());
631 WritePS(mpPageBody, pString);
633 else
635 OSL_FAIL( "PrinterGfx::DrawPolyPolygonBezier: Strange output" );
637 j+=3;
642 // if fill and stroke, save the current path
643 if( maFillColor.Is() && maLineColor.Is())
644 PSGSave();
646 if (maFillColor.Is ())
648 PSSetColor (maFillColor);
649 PSSetColor ();
650 WritePS (mpPageBody, "eofill\n");
653 // restore the current path
654 if( maFillColor.Is() && maLineColor.Is())
655 PSGRestore();
659 * postscript generating routines
661 void
662 PrinterGfx::PSGSave ()
664 WritePS (mpPageBody, "gsave\n" );
665 GraphicsStatus aNewState;
666 if( maGraphicsStack.begin() != maGraphicsStack.end() )
667 aNewState = maGraphicsStack.front();
668 maGraphicsStack.push_front( aNewState );
671 void
672 PrinterGfx::PSGRestore ()
674 WritePS (mpPageBody, "grestore\n" );
675 if( maGraphicsStack.begin() == maGraphicsStack.end() )
676 WritePS (mpPageBody, "Error: too many grestores\n" );
677 else
678 maGraphicsStack.pop_front();
681 void
682 PrinterGfx::PSSetLineWidth ()
684 if( currentState().mfLineWidth != maVirtualStatus.mfLineWidth )
686 char pBuffer[128];
687 sal_Int32 nChar = 0;
689 currentState().mfLineWidth = maVirtualStatus.mfLineWidth;
690 nChar = psp::getValueOfDouble (pBuffer, maVirtualStatus.mfLineWidth, 5);
691 nChar += psp::appendStr (" setlinewidth\n", pBuffer + nChar);
692 WritePS (mpPageBody, pBuffer, nChar);
696 void
697 PrinterGfx::PSSetColor ()
699 PrinterColor& rColor( maVirtualStatus.maColor );
701 if( currentState().maColor != rColor )
703 currentState().maColor = rColor;
705 char pBuffer[128];
706 sal_Int32 nChar = 0;
708 if( mbColor )
710 nChar = psp::getValueOfDouble (pBuffer,
711 (double)rColor.GetRed() / 255.0, 5);
712 nChar += psp::appendStr (" ", pBuffer + nChar);
713 nChar += psp::getValueOfDouble (pBuffer + nChar,
714 (double)rColor.GetGreen() / 255.0, 5);
715 nChar += psp::appendStr (" ", pBuffer + nChar);
716 nChar += psp::getValueOfDouble (pBuffer + nChar,
717 (double)rColor.GetBlue() / 255.0, 5);
718 nChar += psp::appendStr (" setrgbcolor\n", pBuffer + nChar );
720 else
722 Color aColor( rColor.GetRed(), rColor.GetGreen(), rColor.GetBlue() );
723 sal_uInt8 nCol = aColor.GetLuminance();
724 nChar = psp::getValueOfDouble( pBuffer, (double)nCol / 255.0, 5 );
725 nChar += psp::appendStr( " setgray\n", pBuffer + nChar );
728 WritePS (mpPageBody, pBuffer, nChar);
732 void
733 PrinterGfx::PSSetFont ()
735 GraphicsStatus& rCurrent( currentState() );
736 if( maVirtualStatus.maFont != rCurrent.maFont ||
737 maVirtualStatus.mnTextHeight != rCurrent.mnTextHeight ||
738 maVirtualStatus.maEncoding != rCurrent.maEncoding ||
739 maVirtualStatus.mnTextWidth != rCurrent.mnTextWidth ||
740 maVirtualStatus.mbArtBold != rCurrent.mbArtBold ||
741 maVirtualStatus.mbArtItalic != rCurrent.mbArtItalic
744 rCurrent.maFont = maVirtualStatus.maFont;
745 rCurrent.maEncoding = maVirtualStatus.maEncoding;
746 rCurrent.mnTextWidth = maVirtualStatus.mnTextWidth;
747 rCurrent.mnTextHeight = maVirtualStatus.mnTextHeight;
748 rCurrent.mbArtItalic = maVirtualStatus.mbArtItalic;
749 rCurrent.mbArtBold = maVirtualStatus.mbArtBold;
751 sal_Int32 nTextHeight = rCurrent.mnTextHeight;
752 sal_Int32 nTextWidth = rCurrent.mnTextWidth ? rCurrent.mnTextWidth
753 : rCurrent.mnTextHeight;
755 sal_Char pSetFont [256];
756 sal_Int32 nChar = 0;
758 // postscript based fonts need reencoding
759 if ( ( rCurrent.maEncoding == RTL_TEXTENCODING_MS_1252)
760 || ( rCurrent.maEncoding == RTL_TEXTENCODING_ISO_8859_1)
761 || ( rCurrent.maEncoding >= RTL_TEXTENCODING_USER_START
762 && rCurrent.maEncoding <= RTL_TEXTENCODING_USER_END)
765 OString aReencodedFont =
766 psp::GlyphSet::GetReencodedFontName (rCurrent.maEncoding,
767 rCurrent.maFont);
769 nChar += psp::appendStr ("(", pSetFont + nChar);
770 nChar += psp::appendStr (aReencodedFont.getStr(),
771 pSetFont + nChar);
772 nChar += psp::appendStr (") cvn findfont ",
773 pSetFont + nChar);
775 else
776 // tt based fonts mustn't reencode, the encoding is implied by the fontname
777 // same for symbol type1 fonts, dont try to touch them
779 nChar += psp::appendStr ("(", pSetFont + nChar);
780 nChar += psp::appendStr (rCurrent.maFont.getStr(),
781 pSetFont + nChar);
782 nChar += psp::appendStr (") cvn findfont ",
783 pSetFont + nChar);
786 if( ! rCurrent.mbArtItalic )
788 nChar += psp::getValueOf (nTextWidth, pSetFont + nChar);
789 nChar += psp::appendStr (" ", pSetFont + nChar);
790 nChar += psp::getValueOf (-nTextHeight, pSetFont + nChar);
791 nChar += psp::appendStr (" matrix scale makefont setfont\n", pSetFont + nChar);
793 else // skew 15 degrees to right
795 nChar += psp::appendStr ( " [", pSetFont + nChar);
796 nChar += psp::getValueOf (nTextWidth, pSetFont + nChar);
797 nChar += psp::appendStr (" 0 ", pSetFont + nChar);
798 nChar += psp::getValueOfDouble (pSetFont + nChar, 0.27*(double)nTextWidth, 3 );
799 nChar += psp::appendStr ( " ", pSetFont + nChar);
800 nChar += psp::getValueOf (-nTextHeight, pSetFont + nChar);
802 nChar += psp::appendStr (" 0 0] makefont setfont\n", pSetFont + nChar);
805 WritePS (mpPageBody, pSetFont);
809 void
810 PrinterGfx::PSRotate (sal_Int32 nAngle)
812 sal_Int32 nPostScriptAngle = -nAngle;
813 while( nPostScriptAngle < 0 )
814 nPostScriptAngle += 3600;
816 if (nPostScriptAngle == 0)
817 return;
819 sal_Int32 nFullAngle = nPostScriptAngle / 10;
820 sal_Int32 nTenthAngle = nPostScriptAngle % 10;
822 sal_Char pRotate [48];
823 sal_Int32 nChar = 0;
825 nChar = psp::getValueOf (nFullAngle, pRotate);
826 nChar += psp::appendStr (".", pRotate + nChar);
827 nChar += psp::getValueOf (nTenthAngle, pRotate + nChar);
828 nChar += psp::appendStr (" rotate\n", pRotate + nChar);
830 WritePS (mpPageBody, pRotate);
833 void
834 PrinterGfx::PSPointOp (const Point& rPoint, const sal_Char* pOperator)
836 sal_Char pPSCommand [48];
837 sal_Int32 nChar = 0;
839 nChar = psp::getValueOf (rPoint.X(), pPSCommand);
840 nChar += psp::appendStr (" ", pPSCommand + nChar);
841 nChar += psp::getValueOf (rPoint.Y(), pPSCommand + nChar);
842 nChar += psp::appendStr (" ", pPSCommand + nChar);
843 nChar += psp::appendStr (pOperator, pPSCommand + nChar);
844 nChar += psp::appendStr ("\n", pPSCommand + nChar);
846 DBG_ASSERT (nChar < 48, "Buffer overflow in PSPointOp");
848 WritePS (mpPageBody, pPSCommand);
851 void
852 PrinterGfx::PSTranslate (const Point& rPoint)
854 PSPointOp (rPoint, "translate");
857 void
858 PrinterGfx::PSMoveTo (const Point& rPoint)
860 PSPointOp (rPoint, "moveto");
863 void
864 PrinterGfx::PSLineTo (const Point& rPoint)
866 PSPointOp (rPoint, "lineto");
869 /* get a compressed representation of the path information */
871 #define DEBUG_BINPATH 0
873 void
874 PrinterGfx::PSBinLineTo (const Point& rCurrent, Point& rOld, sal_Int32& nColumn)
876 #if (DEBUG_BINPATH == 1)
877 PSLineTo (rCurrent);
878 #else
879 PSBinPath (rCurrent, rOld, lineto, nColumn);
880 #endif
883 void
884 PrinterGfx::PSBinMoveTo (const Point& rCurrent, Point& rOld, sal_Int32& nColumn)
886 #if (DEBUG_BINPATH == 1)
887 PSMoveTo (rCurrent);
888 #else
889 PSBinPath (rCurrent, rOld, moveto, nColumn);
890 #endif
893 void
894 PrinterGfx::PSBinStartPath ()
896 #if (DEBUG_BINPATH == 1)
897 WritePS (mpPageBody, "% PSBinStartPath\n");
898 #else
899 WritePS (mpPageBody, "readpath\n" );
900 #endif
903 void
904 PrinterGfx::PSBinEndPath ()
906 #if (DEBUG_BINPATH == 1)
907 WritePS (mpPageBody, "% PSBinEndPath\n");
908 #else
909 WritePS (mpPageBody, "~\n");
910 #endif
913 void
914 PrinterGfx::PSBinCurrentPath (sal_uInt32 nPoints, const Point* pPath)
916 // create the path
917 Point aPoint (0, 0);
918 sal_Int32 nColumn = 0;
920 PSBinStartPath ();
921 PSBinMoveTo (*pPath, aPoint, nColumn);
922 for (unsigned int i = 1; i < nPoints; i++)
923 PSBinLineTo (pPath[i], aPoint, nColumn);
924 PSBinEndPath ();
927 void
928 PrinterGfx::PSBinPath (const Point& rCurrent, Point& rOld,
929 pspath_t eType, sal_Int32& nColumn)
931 sal_Char pPath[48] = {0};
932 sal_Int32 nChar;
934 // create the hex representation of the dx and dy path shift, store the field
935 // width as it is needed for the building the command
936 sal_Int32 nXPrec = getAlignedHexValueOf (rCurrent.X() - rOld.X(), pPath + 1);
937 sal_Int32 nYPrec = getAlignedHexValueOf (rCurrent.Y() - rOld.Y(), pPath + 1 + nXPrec);
938 pPath [ 1 + nXPrec + nYPrec ] = 0;
940 // build the command, it is a char with bit represention 000cxxyy
941 // c represents the char, xx and yy repr. the field width of the dx and dy shift,
942 // dx and dy represent the number of bytes to read after the opcode
943 sal_Char cCmd = (eType == lineto ? (sal_Char)0x00 : (sal_Char)0x10);
944 switch (nYPrec)
946 case 2: break;
947 case 4: cCmd |= 0x01; break;
948 case 6: cCmd |= 0x02; break;
949 case 8: cCmd |= 0x03; break;
950 default: OSL_FAIL("invalid x precision in binary path");
952 switch (nXPrec)
954 case 2: break;
955 case 4: cCmd |= 0x04; break;
956 case 6: cCmd |= 0x08; break;
957 case 8: cCmd |= 0x0c; break;
958 default: OSL_FAIL("invalid y precision in binary path");
960 cCmd += 'A';
961 pPath[0] = cCmd;
963 // write the command to file,
964 // line breaking at column nMaxTextColumn (80)
965 nChar = 1 + nXPrec + nYPrec;
966 if ((nColumn + nChar) > nMaxTextColumn)
968 sal_Int32 nSegment = nMaxTextColumn - nColumn;
970 WritePS (mpPageBody, pPath, nSegment);
971 WritePS (mpPageBody, "\n", 1);
972 WritePS (mpPageBody, pPath + nSegment, nChar - nSegment);
974 nColumn = nChar - nSegment;
976 else
978 WritePS (mpPageBody, pPath, nChar);
980 nColumn += nChar;
983 rOld = rCurrent;
986 void
987 PrinterGfx::PSScale (double fScaleX, double fScaleY)
989 sal_Char pScale [48];
990 sal_Int32 nChar = 0;
992 nChar = psp::getValueOfDouble (pScale, fScaleX, 5);
993 nChar += psp::appendStr (" ", pScale + nChar);
994 nChar += psp::getValueOfDouble (pScale + nChar, fScaleY, 5);
995 nChar += psp::appendStr (" scale\n", pScale + nChar);
997 WritePS (mpPageBody, pScale);
1000 /* psshowtext helper routines: draw an hex string for show/xshow */
1001 void
1002 PrinterGfx::PSHexString (const unsigned char* pString, sal_Int16 nLen)
1004 sal_Char pHexString [128];
1005 sal_Int32 nChar = 0;
1007 nChar = psp::appendStr ("<", pHexString);
1008 for (int i = 0; i < nLen; i++)
1010 if (nChar >= (nMaxTextColumn - 1))
1012 nChar += psp::appendStr ("\n", pHexString + nChar);
1013 WritePS (mpPageBody, pHexString, nChar);
1014 nChar = 0;
1016 nChar += psp::getHexValueOf ((sal_Int32)pString[i], pHexString + nChar);
1019 nChar += psp::appendStr (">\n", pHexString + nChar);
1020 WritePS (mpPageBody, pHexString, nChar);
1023 /* psshowtext helper routines: draw an array for xshow ps operator */
1024 void
1025 PrinterGfx::PSDeltaArray (const sal_Int32 *pArray, sal_Int16 nEntries)
1027 sal_Char pPSArray [128];
1028 sal_Int32 nChar = 0;
1030 nChar = psp::appendStr ("[", pPSArray + nChar);
1031 nChar += psp::getValueOf (pArray[0], pPSArray + nChar);
1033 for (int i = 1; i < nEntries; i++)
1035 if (nChar >= (nMaxTextColumn - 1))
1037 nChar += psp::appendStr ("\n", pPSArray + nChar);
1038 WritePS (mpPageBody, pPSArray, nChar);
1039 nChar = 0;
1042 nChar += psp::appendStr (" ", pPSArray + nChar);
1043 nChar += psp::getValueOf (pArray[i] - pArray[i-1], pPSArray + nChar);
1046 nChar += psp::appendStr (" 0]\n", pPSArray + nChar);
1047 WritePS (mpPageBody, pPSArray);
1050 /* the DrawText equivalent, pDeltaArray may be NULL. For Type1 fonts or single byte
1051 * fonts in general nBytes and nGlyphs is the same. For printer resident Composite
1052 * fonts it may be different (these fonts may be SJIS encoded for example) */
1053 void
1054 PrinterGfx::PSShowText (const unsigned char* pStr, sal_Int16 nGlyphs, sal_Int16 nBytes,
1055 const sal_Int32* pDeltaArray)
1057 PSSetColor (maTextColor);
1058 PSSetColor ();
1059 PSSetFont ();
1060 // rotate the user coordinate system
1061 if (mnTextAngle != 0)
1063 PSGSave ();
1064 PSRotate (mnTextAngle);
1067 sal_Char pBuffer[256];
1068 if( maVirtualStatus.mbArtBold )
1070 sal_Int32 nLW = maVirtualStatus.mnTextWidth;
1071 if( nLW == 0 )
1072 nLW = maVirtualStatus.mnTextHeight;
1073 else
1074 nLW = nLW < maVirtualStatus.mnTextHeight ? nLW : maVirtualStatus.mnTextHeight;
1075 psp::getValueOfDouble( pBuffer, (double)nLW / 30.0 );
1077 // dispatch to the drawing method
1078 if (pDeltaArray == NULL)
1080 PSHexString (pStr, nBytes);
1082 if( maVirtualStatus.mbArtBold )
1084 WritePS( mpPageBody, pBuffer );
1085 WritePS( mpPageBody, " bshow\n" );
1087 else
1088 WritePS (mpPageBody, "show\n");
1090 else
1092 PSHexString (pStr, nBytes);
1093 PSDeltaArray (pDeltaArray, nGlyphs - 1);
1094 if( maVirtualStatus.mbArtBold )
1096 WritePS( mpPageBody, pBuffer );
1097 WritePS( mpPageBody, " bxshow\n" );
1099 else
1100 WritePS (mpPageBody, "xshow\n");
1103 // restore the user coordinate system
1104 if (mnTextAngle != 0)
1105 PSGRestore ();
1108 void
1109 PrinterGfx::PSComment( const sal_Char* pComment )
1111 const sal_Char* pLast = pComment;
1112 while( pComment && *pComment )
1114 while( *pComment && *pComment != '\n' && *pComment != '\r' )
1115 pComment++;
1116 if( pComment - pLast > 1 )
1118 WritePS( mpPageBody, "% ", 2 );
1119 WritePS( mpPageBody, pLast, pComment - pLast );
1120 WritePS( mpPageBody, "\n", 1 );
1122 if( *pComment )
1123 pLast = ++pComment;
1127 bool
1128 PrinterGfx::DrawEPS( const Rectangle& rBoundingBox, void* pPtr, sal_uInt32 nSize )
1130 if( nSize == 0 )
1131 return true;
1132 if( ! mpPageBody )
1133 return false;
1135 bool bSuccess = false;
1137 // first search the BoundingBox of the EPS data
1138 SvMemoryStream aStream( pPtr, nSize, StreamMode::READ );
1139 aStream.Seek( STREAM_SEEK_TO_BEGIN );
1140 OString aLine;
1142 OString aDocTitle;
1143 double fLeft = 0, fRight = 0, fTop = 0, fBottom = 0;
1144 bool bEndComments = false;
1145 while( ! aStream.IsEof()
1146 && ( ( fLeft == 0 && fRight == 0 && fTop == 0 && fBottom == 0 ) ||
1147 ( aDocTitle.isEmpty() && !bEndComments ) )
1150 aStream.ReadLine( aLine );
1151 if( aLine.getLength() > 1 && aLine[0] == '%' )
1153 char cChar = aLine[1];
1154 if( cChar == '%' )
1156 if( aLine.matchIgnoreAsciiCase( OString( "%%BoundingBox:") ) )
1158 aLine = WhitespaceToSpace( aLine.getToken(1, ':') );
1159 if( !aLine.isEmpty() && aLine.indexOf( "atend" ) == -1 )
1161 fLeft = StringToDouble( GetCommandLineToken( 0, aLine ) );
1162 fBottom = StringToDouble( GetCommandLineToken( 1, aLine ) );
1163 fRight = StringToDouble( GetCommandLineToken( 2, aLine ) );
1164 fTop = StringToDouble( GetCommandLineToken( 3, aLine ) );
1167 else if( aLine.matchIgnoreAsciiCase( "%%Title:" ) )
1168 aDocTitle = WhitespaceToSpace( aLine.copy( 8 ) );
1169 else if( aLine.matchIgnoreAsciiCase( "%%EndComments" ) )
1170 bEndComments = true;
1172 else if( cChar == ' ' || cChar == '\t' || cChar == '\r' || cChar == '\n' )
1173 bEndComments = true;
1175 else
1176 bEndComments = true;
1179 static sal_uInt16 nEps = 0;
1180 if( aDocTitle.isEmpty() )
1181 aDocTitle = OString::number(nEps++);
1183 if( fLeft != fRight && fTop != fBottom )
1185 double fScaleX = (double)rBoundingBox.GetWidth()/(fRight-fLeft);
1186 double fScaleY = -(double)rBoundingBox.GetHeight()/(fTop-fBottom);
1187 Point aTranslatePoint( (int)(rBoundingBox.Left()-fLeft*fScaleX),
1188 (int)(rBoundingBox.Bottom()+1-fBottom*fScaleY) );
1189 // prepare EPS
1190 WritePS( mpPageBody,
1191 "/b4_Inc_state save def\n"
1192 "/dict_count countdictstack def\n"
1193 "/op_count count 1 sub def\n"
1194 "userdict begin\n"
1195 "/showpage {} def\n"
1196 "0 setgray 0 setlinecap 1 setlinewidth 0 setlinejoin\n"
1197 "10 setmiterlimit [] 0 setdash newpath\n"
1198 "/languagelevel where\n"
1199 "{pop languagelevel\n"
1200 "1 ne\n"
1201 " {false setstrokeadjust false setoverprint\n"
1202 " } if\n"
1203 "}if\n" );
1204 // set up clip path and scale
1205 BeginSetClipRegion( 1 );
1206 UnionClipRegion( rBoundingBox.Left(), rBoundingBox.Top(), rBoundingBox.GetWidth(), rBoundingBox.GetHeight() );
1207 EndSetClipRegion();
1208 PSTranslate( aTranslatePoint );
1209 PSScale( fScaleX, fScaleY );
1211 // DSC requires BeginDocument
1212 WritePS( mpPageBody, "%%BeginDocument: " );
1213 WritePS( mpPageBody, aDocTitle );
1214 WritePS( mpPageBody, "\n" );
1216 // write the EPS data
1217 sal_uInt64 nOutLength;
1218 mpPageBody->write( pPtr, nSize, nOutLength );
1219 bSuccess = nOutLength == nSize;
1221 // corresponding EndDocument
1222 if( static_cast<char*>(pPtr)[ nSize-1 ] != '\n' )
1223 WritePS( mpPageBody, "\n" );
1224 WritePS( mpPageBody, "%%EndDocument\n" );
1226 // clean up EPS
1227 WritePS( mpPageBody,
1228 "count op_count sub {pop} repeat\n"
1229 "countdictstack dict_count sub {end} repeat\n"
1230 "b4_Inc_state restore\n" );
1232 return bSuccess;
1235 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */