Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 :
21 : #include "psputil.hxx"
22 : #include "glyphset.hxx"
23 :
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"
29 :
30 : #include "tools/debug.hxx"
31 : #include "tools/color.hxx"
32 : #include "tools/poly.hxx"
33 :
34 : using namespace psp ;
35 :
36 : static const sal_Int32 nMaxTextColumn = 80;
37 :
38 0 : GraphicsStatus::GraphicsStatus() :
39 : mbArtItalic( false ),
40 : mbArtBold( false ),
41 : mnTextHeight( 0 ),
42 : mnTextWidth( 0 ),
43 0 : mfLineWidth( -1 )
44 : {
45 0 : }
46 :
47 : /*
48 : * non graphics graphics routines
49 : */
50 :
51 : sal_Bool
52 0 : PrinterGfx::Init (PrinterJob &rPrinterJob)
53 : {
54 0 : mpPageHeader = rPrinterJob.GetCurrentPageHeader ();
55 0 : mpPageBody = rPrinterJob.GetCurrentPageBody ();
56 0 : mnDepth = rPrinterJob.GetDepth ();
57 0 : mnPSLevel = rPrinterJob.GetPostscriptLevel ();
58 0 : mbColor = rPrinterJob.IsColorPrinter ();
59 :
60 0 : mnDpi = rPrinterJob.GetResolution();
61 0 : rPrinterJob.GetScale (mfScaleX, mfScaleY);
62 0 : const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( rPrinterJob.GetPrinterName() ) );
63 0 : if( mpFontSubstitutes )
64 0 : delete const_cast< ::boost::unordered_map<fontID,fontID>* >(mpFontSubstitutes);
65 0 : if( rInfo.m_bPerformFontSubstitution )
66 0 : mpFontSubstitutes = new ::boost::unordered_map< fontID, fontID >( rInfo.m_aFontSubstitutions );
67 : else
68 0 : mpFontSubstitutes = NULL;
69 0 : mbUploadPS42Fonts = rInfo.m_pParser ? ( rInfo.m_pParser->isType42Capable() ? sal_True : sal_False ) : sal_False;
70 :
71 0 : return sal_True;
72 : }
73 :
74 : sal_Bool
75 0 : PrinterGfx::Init (const JobData& rData)
76 : {
77 0 : mpPageHeader = NULL;
78 0 : mpPageBody = NULL;
79 0 : mnDepth = rData.m_nColorDepth;
80 0 : mnPSLevel = rData.m_nPSLevel ? rData.m_nPSLevel : (rData.m_pParser ? rData.m_pParser->getLanguageLevel() : 2 );
81 0 : 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 0 : int nRes = rData.m_aContext.getRenderResolution();
83 0 : mnDpi = nRes;
84 0 : mfScaleX = (double)72.0 / (double)mnDpi;
85 0 : mfScaleY = (double)72.0 / (double)mnDpi;
86 0 : const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( rData.m_aPrinterName ) );
87 0 : if( mpFontSubstitutes )
88 0 : delete const_cast< ::boost::unordered_map<fontID,fontID>* >(mpFontSubstitutes);
89 0 : if( rInfo.m_bPerformFontSubstitution )
90 0 : mpFontSubstitutes = new ::boost::unordered_map< fontID, fontID >( rInfo.m_aFontSubstitutions );
91 : else
92 0 : mpFontSubstitutes = NULL;
93 0 : mbUploadPS42Fonts = rInfo.m_pParser ? ( rInfo.m_pParser->isType42Capable() ? sal_True : sal_False ) : sal_False;
94 :
95 0 : return sal_True;
96 : }
97 :
98 : sal_uInt16
99 0 : PrinterGfx::GetBitCount ()
100 : {
101 0 : return mnDepth;
102 : }
103 :
104 0 : PrinterGfx::PrinterGfx() :
105 : mpPageHeader (NULL),
106 : mpPageBody (NULL),
107 : mnFontID (0),
108 : mnFallbackID (0),
109 : mnTextAngle (0),
110 : mbTextVertical (false),
111 0 : mrFontMgr (PrintFontManager::get()),
112 : mbCompressBmp (sal_True),
113 : maFillColor (0xff,0,0),
114 : maTextColor (0,0,0),
115 : maLineColor (0, 0xff, 0),
116 0 : mpFontSubstitutes( NULL )
117 : {
118 0 : maVirtualStatus.mfLineWidth = 1.0;
119 0 : maVirtualStatus.mnTextHeight = 12;
120 0 : maVirtualStatus.mnTextWidth = 0;
121 :
122 0 : maGraphicsStack.push_back( GraphicsStatus() );
123 0 : }
124 :
125 0 : PrinterGfx::~PrinterGfx()
126 : {
127 : /*
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.
132 : *
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.
135 : */
136 0 : delete const_cast< ::boost::unordered_map<fontID,fontID>* >(mpFontSubstitutes);
137 0 : }
138 :
139 : void
140 0 : PrinterGfx::Clear()
141 : {
142 0 : mpPageHeader = NULL;
143 0 : mpPageBody = NULL;
144 0 : mnFontID = 0;
145 0 : maVirtualStatus = GraphicsStatus();
146 0 : maVirtualStatus.mnTextHeight = 12;
147 0 : maVirtualStatus.mnTextWidth = 0;
148 0 : maVirtualStatus.mfLineWidth = 1.0;
149 0 : mbTextVertical = false;
150 0 : maLineColor = PrinterColor();
151 0 : maFillColor = PrinterColor();
152 0 : maTextColor = PrinterColor();
153 0 : mbCompressBmp = sal_True;
154 0 : mnDpi = 300;
155 0 : mnDepth = 24;
156 0 : mnPSLevel = 2;
157 0 : mbColor = sal_True;
158 0 : mnTextAngle = 0;
159 :
160 0 : maClipRegion.clear();
161 0 : maGraphicsStack.clear();
162 0 : maGraphicsStack.push_back( GraphicsStatus() );
163 0 : }
164 :
165 : /*
166 : * clip region handling
167 : */
168 :
169 : void
170 0 : PrinterGfx::ResetClipRegion()
171 : {
172 0 : maClipRegion.clear();
173 0 : PSGRestore ();
174 0 : PSGSave (); // get "clean" clippath
175 0 : }
176 :
177 : void
178 0 : PrinterGfx::BeginSetClipRegion( sal_uInt32 )
179 : {
180 0 : maClipRegion.clear();
181 0 : }
182 :
183 : sal_Bool
184 0 : PrinterGfx::UnionClipRegion (sal_Int32 nX,sal_Int32 nY,sal_Int32 nDX,sal_Int32 nDY)
185 : {
186 0 : if( nDX && nDY )
187 0 : maClipRegion.push_back (Rectangle(Point(nX,nY ), Size(nDX,nDY)));
188 0 : return sal_True;
189 : }
190 :
191 : sal_Bool
192 0 : PrinterGfx::JoinVerticalClipRectangles( std::list< Rectangle >::iterator& it,
193 : Point& rOldPoint, sal_Int32& rColumn )
194 : {
195 0 : sal_Bool bSuccess = sal_False;
196 :
197 0 : std::list< Rectangle >::iterator tempit, nextit;
198 0 : nextit = it;
199 0 : ++nextit;
200 0 : std::list< Point > leftside, rightside;
201 :
202 0 : Rectangle aLastRect( *it );
203 0 : leftside.push_back( Point( it->Left(), it->Top() ) );
204 0 : rightside.push_back( Point( it->Right()+1, it->Top() ) );
205 0 : while( nextit != maClipRegion.end() )
206 : {
207 0 : tempit = nextit;
208 0 : ++tempit;
209 0 : if( nextit->Top() == aLastRect.Bottom()+1 )
210 : {
211 0 : if(
212 0 : ( nextit->Left() >= aLastRect.Left() && nextit->Left() <= aLastRect.Right() ) // left endpoint touches last rectangle
213 : ||
214 0 : ( nextit->Right() >= aLastRect.Left() && nextit->Right() <= aLastRect.Right() ) // right endpoint touches last rectangle
215 : ||
216 0 : ( nextit->Left() <= aLastRect.Left() && nextit->Right() >= aLastRect.Right() ) // whole line touches last rectangle
217 : )
218 : {
219 0 : if( aLastRect.GetHeight() > 1 ||
220 0 : abs( aLastRect.Left() - nextit->Left() ) > 2 ||
221 0 : abs( aLastRect.Right() - nextit->Right() ) > 2
222 : )
223 : {
224 0 : leftside.push_back( Point( aLastRect.Left(), aLastRect.Bottom()+1 ) );
225 0 : rightside.push_back( Point( aLastRect.Right()+1, aLastRect.Bottom()+1 ) );
226 : }
227 0 : aLastRect = *nextit;
228 0 : leftside.push_back( aLastRect.TopLeft() );
229 0 : rightside.push_back( aLastRect.TopRight() );
230 0 : maClipRegion.erase( nextit );
231 : }
232 : }
233 0 : nextit = tempit;
234 : }
235 0 : if( leftside.size() > 1 )
236 : {
237 : // push the last coordinates
238 0 : leftside.push_back( Point( aLastRect.Left(), aLastRect.Bottom()+1 ) );
239 0 : rightside.push_back( Point( aLastRect.Right()+1, aLastRect.Bottom()+1 ) );
240 :
241 : // cool, we can concatenate rectangles
242 0 : int nDX = -65536, nDY = 65536;
243 0 : int nNewDX = 0, nNewDY = 0;
244 :
245 0 : Point aLastPoint = leftside.front();
246 0 : PSBinMoveTo (aLastPoint, rOldPoint, rColumn);
247 0 : leftside.pop_front();
248 0 : while( leftside.begin() != leftside.end() )
249 : {
250 0 : Point aPoint (leftside.front());
251 0 : leftside.pop_front();
252 : // may have been the last one
253 0 : if( leftside.begin() != leftside.end() )
254 : {
255 0 : nNewDX = aPoint.X() - aLastPoint.X();
256 0 : nNewDY = aPoint.Y() - aLastPoint.Y();
257 0 : if( nNewDX == 0 && nDX == 0 )
258 0 : continue;
259 0 : if( nDX != 0 && nNewDX != 0 &&
260 : (double)nNewDY/(double)nNewDX == (double)nDY/(double)nDX )
261 0 : continue;
262 : }
263 0 : PSBinLineTo (aPoint, rOldPoint, rColumn);
264 0 : aLastPoint = aPoint;
265 : }
266 :
267 0 : aLastPoint = rightside.back();
268 0 : nDX = -65536;
269 0 : nDY = 65536;
270 0 : PSBinLineTo (aLastPoint, rOldPoint, rColumn);
271 0 : rightside.pop_back();
272 0 : while( rightside.begin() != rightside.end() )
273 : {
274 0 : Point aPoint (rightside.back());
275 0 : rightside.pop_back();
276 0 : if( rightside.begin() != rightside.end() )
277 : {
278 0 : nNewDX = aPoint.X() - aLastPoint.X();
279 0 : nNewDY = aPoint.Y() - aLastPoint.Y();
280 0 : if( nNewDX == 0 && nDX == 0 )
281 0 : continue;
282 0 : if( nDX != 0 && nNewDX != 0 &&
283 : (double)nNewDY/(double)nNewDX == (double)nDY/(double)nDX )
284 0 : continue;
285 : }
286 0 : PSBinLineTo (aPoint, rOldPoint, rColumn);
287 : }
288 :
289 0 : tempit = it;
290 0 : ++tempit;
291 0 : maClipRegion.erase( it );
292 0 : it = tempit;
293 0 : bSuccess = sal_True;
294 : }
295 0 : return bSuccess;
296 : }
297 :
298 : void
299 0 : PrinterGfx::EndSetClipRegion()
300 : {
301 0 : PSGRestore ();
302 0 : PSGSave (); // get "clean" clippath
303 :
304 0 : PSBinStartPath ();
305 0 : Point aOldPoint (0, 0);
306 0 : sal_Int32 nColumn = 0;
307 :
308 0 : std::list< Rectangle >::iterator it = maClipRegion.begin();
309 0 : while( it != maClipRegion.end() )
310 : {
311 : // try to concatenate adjacent rectangles
312 : // first try in y direction, then in x direction
313 0 : if( ! JoinVerticalClipRectangles( it, aOldPoint, nColumn ) )
314 : {
315 : // failed, so it is a single rectangle
316 0 : PSBinMoveTo (it->TopLeft(), aOldPoint, nColumn );
317 0 : PSBinLineTo (Point( it->Left(), it->Bottom()+1 ), aOldPoint, nColumn );
318 0 : PSBinLineTo (Point( it->Right()+1, it->Bottom()+1 ), aOldPoint, nColumn );
319 0 : PSBinLineTo (Point( it->Right()+1, it->Top() ), aOldPoint, nColumn );
320 0 : ++it;
321 : }
322 : }
323 :
324 0 : PSBinEndPath ();
325 :
326 0 : WritePS (mpPageBody, "closepath clip newpath\n");
327 0 : maClipRegion.clear();
328 0 : }
329 :
330 : /*
331 : * draw graphic primitives
332 : */
333 :
334 : void
335 0 : PrinterGfx::DrawRect (const Rectangle& rRectangle )
336 : {
337 : char pRect [128];
338 0 : sal_Int32 nChar = 0;
339 :
340 0 : nChar = psp::getValueOf (rRectangle.TopLeft().X(), pRect);
341 0 : nChar += psp::appendStr (" ", pRect + nChar);
342 0 : nChar += psp::getValueOf (rRectangle.TopLeft().Y(), pRect + nChar);
343 0 : nChar += psp::appendStr (" ", pRect + nChar);
344 0 : nChar += psp::getValueOf (rRectangle.GetWidth(), pRect + nChar);
345 0 : nChar += psp::appendStr (" ", pRect + nChar);
346 0 : nChar += psp::getValueOf (rRectangle.GetHeight(), pRect + nChar);
347 0 : nChar += psp::appendStr (" ", pRect + nChar);
348 :
349 0 : if( maFillColor.Is() )
350 : {
351 0 : PSSetColor (maFillColor);
352 0 : PSSetColor ();
353 0 : WritePS (mpPageBody, pRect, nChar);
354 0 : WritePS (mpPageBody, "rectfill\n");
355 : }
356 0 : if( maLineColor.Is() )
357 : {
358 0 : PSSetColor (maLineColor);
359 0 : PSSetColor ();
360 0 : PSSetLineWidth ();
361 0 : WritePS (mpPageBody, pRect, nChar);
362 0 : WritePS (mpPageBody, "rectstroke\n");
363 : }
364 0 : }
365 :
366 : void
367 0 : PrinterGfx::DrawLine (const Point& rFrom, const Point& rTo)
368 : {
369 0 : if( maLineColor.Is() )
370 : {
371 0 : PSSetColor (maLineColor);
372 0 : PSSetColor ();
373 0 : PSSetLineWidth ();
374 :
375 0 : PSMoveTo (rFrom);
376 0 : PSLineTo (rTo);
377 0 : WritePS (mpPageBody, "stroke\n" );
378 : }
379 0 : }
380 :
381 : void
382 0 : PrinterGfx::DrawPixel (const Point& rPoint, const PrinterColor& rPixelColor)
383 : {
384 0 : if( rPixelColor.Is() )
385 : {
386 0 : PSSetColor (rPixelColor);
387 0 : PSSetColor ();
388 :
389 0 : PSMoveTo (rPoint);
390 0 : PSLineTo (Point (rPoint.X ()+1, rPoint.Y ()));
391 0 : PSLineTo (Point (rPoint.X ()+1, rPoint.Y ()+1));
392 0 : PSLineTo (Point (rPoint.X (), rPoint.Y ()+1));
393 0 : WritePS (mpPageBody, "fill\n" );
394 : }
395 0 : }
396 :
397 : void
398 0 : PrinterGfx::DrawPolyLine (sal_uInt32 nPoints, const Point* pPath)
399 : {
400 0 : if( maLineColor.Is() && nPoints && pPath )
401 : {
402 0 : PSSetColor (maLineColor);
403 0 : PSSetColor ();
404 0 : PSSetLineWidth ();
405 :
406 0 : PSBinCurrentPath (nPoints, pPath);
407 :
408 0 : WritePS (mpPageBody, "stroke\n" );
409 : }
410 0 : }
411 :
412 : void
413 0 : PrinterGfx::DrawPolygon (sal_uInt32 nPoints, const Point* pPath)
414 : {
415 : // premature end of operation
416 0 : if (!(nPoints > 1) || (pPath == NULL) || !(maFillColor.Is() || maLineColor.Is()))
417 0 : return;
418 :
419 : // setup closed path
420 0 : Point aPoint( 0, 0 );
421 0 : sal_Int32 nColumn( 0 );
422 :
423 0 : PSBinStartPath();
424 0 : PSBinMoveTo( pPath[0], aPoint, nColumn );
425 0 : for( unsigned int n = 1; n < nPoints; n++ )
426 0 : PSBinLineTo( pPath[n], aPoint, nColumn );
427 0 : if( pPath[0] != pPath[nPoints-1] )
428 0 : PSBinLineTo( pPath[0], aPoint, nColumn );
429 0 : PSBinEndPath();
430 :
431 : // fill the polygon first, then draw the border, note that fill and
432 : // stroke reset the currentpath
433 :
434 : // if fill and stroke, save the current path
435 0 : if( maFillColor.Is() && maLineColor.Is())
436 0 : PSGSave();
437 :
438 0 : if (maFillColor.Is ())
439 : {
440 0 : PSSetColor (maFillColor);
441 0 : PSSetColor ();
442 0 : WritePS (mpPageBody, "eofill\n");
443 : }
444 :
445 : // restore the current path
446 0 : if( maFillColor.Is() && maLineColor.Is())
447 0 : PSGRestore();
448 :
449 0 : if (maLineColor.Is ())
450 : {
451 0 : PSSetColor (maLineColor);
452 0 : PSSetColor ();
453 0 : PSSetLineWidth ();
454 0 : WritePS (mpPageBody, "stroke\n");
455 : }
456 : }
457 :
458 : void
459 0 : PrinterGfx::DrawPolyPolygon (sal_uInt32 nPoly, const sal_uInt32* pSizes, const Point** pPaths )
460 : {
461 : // sanity check
462 0 : if ( !nPoly || !pPaths || !(maFillColor.Is() || maLineColor.Is()))
463 0 : return;
464 :
465 :
466 : // setup closed path
467 0 : for( unsigned int i = 0; i < nPoly; i++ )
468 : {
469 0 : Point aPoint( 0, 0 );
470 0 : sal_Int32 nColumn( 0 );
471 :
472 0 : PSBinStartPath();
473 0 : PSBinMoveTo( pPaths[i][0], aPoint, nColumn );
474 0 : for( unsigned int n = 1; n < pSizes[i]; n++ )
475 0 : PSBinLineTo( pPaths[i][n], aPoint, nColumn );
476 0 : if( pPaths[i][0] != pPaths[i][pSizes[i]-1] )
477 0 : PSBinLineTo( pPaths[i][0], aPoint, nColumn );
478 0 : PSBinEndPath();
479 : }
480 :
481 : // if eofill and stroke, save the current path
482 0 : if( maFillColor.Is() && maLineColor.Is())
483 0 : PSGSave();
484 :
485 : // first draw area
486 0 : if( maFillColor.Is() )
487 : {
488 0 : PSSetColor (maFillColor);
489 0 : PSSetColor ();
490 0 : WritePS (mpPageBody, "eofill\n");
491 : }
492 :
493 : // restore the current path
494 0 : if( maFillColor.Is() && maLineColor.Is())
495 0 : PSGRestore();
496 :
497 : // now draw outlines
498 0 : if( maLineColor.Is() )
499 : {
500 0 : PSSetColor (maLineColor);
501 0 : PSSetColor ();
502 0 : PSSetLineWidth ();
503 0 : WritePS (mpPageBody, "stroke\n");
504 : }
505 : }
506 :
507 : /*
508 : * Bezier Polygon Drawing methods.
509 : */
510 :
511 : void
512 0 : PrinterGfx::DrawPolyLineBezier (sal_uInt32 nPoints, const Point* pPath, const sal_uInt8* pFlgAry)
513 : {
514 0 : const sal_uInt32 nBezString= 1024;
515 : sal_Char pString[nBezString];
516 :
517 0 : if ( nPoints > 1 && maLineColor.Is() && pPath )
518 : {
519 0 : PSSetColor (maLineColor);
520 0 : PSSetColor ();
521 0 : PSSetLineWidth ();
522 :
523 0 : snprintf(pString, nBezString, "%li %li moveto\n", pPath[0].X(), pPath[0].Y());
524 0 : WritePS(mpPageBody, pString);
525 :
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 0 : for (unsigned int i=1; i<nPoints;)
530 : {
531 0 : if (pFlgAry[i] != POLY_CONTROL) //If the next point is a POLY_NORMAL, we're drawing a line
532 : {
533 0 : snprintf(pString, nBezString, "%li %li lineto\n", pPath[i].X(), pPath[i].Y());
534 0 : i++;
535 : }
536 : else //Otherwise we're drawing a spline
537 : {
538 0 : if (i+2 >= nPoints)
539 0 : return; //Error: wrong sequence of contol/normal points somehow
540 0 : if ((pFlgAry[i] == POLY_CONTROL) && (pFlgAry[i+1] == POLY_CONTROL) &&
541 0 : (pFlgAry[i+2] != POLY_CONTROL))
542 : {
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 0 : pPath[i+2].X(), pPath[i+2].Y());
547 : }
548 : else
549 : {
550 : OSL_FAIL( "PrinterGfx::DrawPolyLineBezier: Strange output" );
551 : }
552 0 : i+=3;
553 : }
554 0 : WritePS(mpPageBody, pString);
555 : }
556 :
557 : // now draw outlines
558 0 : WritePS (mpPageBody, "stroke\n");
559 : }
560 : }
561 :
562 : void
563 0 : PrinterGfx::DrawPolygonBezier (sal_uInt32 nPoints, const Point* pPath, const sal_uInt8* pFlgAry)
564 : {
565 0 : const sal_uInt32 nBezString = 1024;
566 : sal_Char pString[nBezString];
567 : // premature end of operation
568 0 : if (!(nPoints > 1) || (pPath == NULL) || !(maFillColor.Is() || maLineColor.Is()))
569 : return;
570 :
571 0 : snprintf(pString, nBezString, "%li %li moveto\n", pPath[0].X(), pPath[0].Y());
572 0 : WritePS(mpPageBody, pString); //Move to the starting point for the PolyPoygon
573 0 : for (unsigned int i=1; i < nPoints;)
574 : {
575 0 : if (pFlgAry[i] != POLY_CONTROL)
576 : {
577 0 : snprintf(pString, nBezString, "%li %li lineto\n", pPath[i].X(), pPath[i].Y());
578 0 : WritePS(mpPageBody, pString);
579 0 : i++;
580 : }
581 : else
582 : {
583 0 : if (i+2 >= nPoints)
584 : return; //Error: wrong sequence of contol/normal points somehow
585 0 : if ((pFlgAry[i] == POLY_CONTROL) && (pFlgAry[i+1] == POLY_CONTROL) &&
586 0 : (pFlgAry[i+2] != POLY_CONTROL))
587 : {
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 0 : pPath[i+2].X(), pPath[i+2].Y());
592 0 : WritePS(mpPageBody, pString);
593 : }
594 : else
595 : {
596 : OSL_FAIL( "PrinterGfx::DrawPolygonBezier: Strange output" );
597 : }
598 0 : i+=3;
599 : }
600 : }
601 :
602 : // if fill and stroke, save the current path
603 0 : if( maFillColor.Is() && maLineColor.Is())
604 0 : PSGSave();
605 :
606 0 : if (maFillColor.Is ())
607 : {
608 0 : PSSetColor (maFillColor);
609 0 : PSSetColor ();
610 0 : WritePS (mpPageBody, "eofill\n");
611 : }
612 :
613 : // restore the current path
614 0 : if( maFillColor.Is() && maLineColor.Is())
615 0 : PSGRestore();
616 : }
617 :
618 : void
619 0 : PrinterGfx::DrawPolyPolygonBezier (sal_uInt32 nPoly, const sal_uInt32 * pPoints, const Point* const * pPtAry, const sal_uInt8* const* pFlgAry)
620 : {
621 0 : const sal_uInt32 nBezString = 1024;
622 : sal_Char pString[nBezString];
623 0 : if ( !nPoly || !pPtAry || !pPoints || !(maFillColor.Is() || maLineColor.Is()))
624 0 : return;
625 :
626 :
627 0 : for (unsigned int i=0; i<nPoly;i++)
628 : {
629 0 : sal_uInt32 nPoints = pPoints[i];
630 : // sanity check
631 0 : if( nPoints == 0 || pPtAry[i] == NULL )
632 0 : continue;
633 :
634 0 : snprintf(pString, nBezString, "%li %li moveto\n", pPtAry[i][0].X(), pPtAry[i][0].Y()); //Move to the starting point
635 0 : WritePS(mpPageBody, pString);
636 0 : for (unsigned int j=1; j < nPoints;)
637 : {
638 : // if no flag array exists for this polygon, then it must be a regular
639 : // polygon without beziers
640 0 : if ( ! pFlgAry[i] || pFlgAry[i][j] != POLY_CONTROL)
641 : {
642 0 : snprintf(pString, nBezString, "%li %li lineto\n", pPtAry[i][j].X(), pPtAry[i][j].Y());
643 0 : WritePS(mpPageBody, pString);
644 0 : j++;
645 : }
646 : else
647 : {
648 0 : if (j+2 >= nPoints)
649 0 : break; //Error: wrong sequence of contol/normal points somehow
650 0 : if ((pFlgAry[i][j] == POLY_CONTROL) && (pFlgAry[i][j+1] == POLY_CONTROL) && (pFlgAry[i][j+2] != POLY_CONTROL))
651 : {
652 : snprintf(pString, nBezString, "%li %li %li %li %li %li curveto\n",
653 0 : pPtAry[i][j].X(), pPtAry[i][j].Y(),
654 0 : pPtAry[i][j+1].X(), pPtAry[i][j+1].Y(),
655 0 : pPtAry[i][j+2].X(), pPtAry[i][j+2].Y());
656 0 : WritePS(mpPageBody, pString);
657 : }
658 : else
659 : {
660 : OSL_FAIL( "PrinterGfx::DrawPolyPolygonBezier: Strange output" );
661 : }
662 0 : j+=3;
663 : }
664 : }
665 : }
666 :
667 : // if fill and stroke, save the current path
668 0 : if( maFillColor.Is() && maLineColor.Is())
669 0 : PSGSave();
670 :
671 0 : if (maFillColor.Is ())
672 : {
673 0 : PSSetColor (maFillColor);
674 0 : PSSetColor ();
675 0 : WritePS (mpPageBody, "eofill\n");
676 : }
677 :
678 : // restore the current path
679 0 : if( maFillColor.Is() && maLineColor.Is())
680 0 : PSGRestore();
681 : }
682 :
683 :
684 : /*
685 : * postscript generating routines
686 : */
687 : void
688 0 : PrinterGfx::PSGSave ()
689 : {
690 0 : WritePS (mpPageBody, "gsave\n" );
691 0 : GraphicsStatus aNewState;
692 0 : if( maGraphicsStack.begin() != maGraphicsStack.end() )
693 0 : aNewState = maGraphicsStack.front();
694 0 : maGraphicsStack.push_front( aNewState );
695 0 : }
696 :
697 : void
698 0 : PrinterGfx::PSGRestore ()
699 : {
700 0 : WritePS (mpPageBody, "grestore\n" );
701 0 : if( maGraphicsStack.begin() == maGraphicsStack.end() )
702 0 : WritePS (mpPageBody, "Error: too many grestores\n" );
703 : else
704 0 : maGraphicsStack.pop_front();
705 0 : }
706 :
707 : void
708 0 : PrinterGfx::PSSetLineWidth ()
709 : {
710 0 : if( currentState().mfLineWidth != maVirtualStatus.mfLineWidth )
711 : {
712 : char pBuffer[128];
713 0 : sal_Int32 nChar = 0;
714 :
715 0 : currentState().mfLineWidth = maVirtualStatus.mfLineWidth;
716 0 : nChar = psp::getValueOfDouble (pBuffer, maVirtualStatus.mfLineWidth, 5);
717 0 : nChar += psp::appendStr (" setlinewidth\n", pBuffer + nChar);
718 0 : WritePS (mpPageBody, pBuffer, nChar);
719 : }
720 0 : }
721 :
722 : void
723 0 : PrinterGfx::PSSetColor ()
724 : {
725 0 : PrinterColor& rColor( maVirtualStatus.maColor );
726 :
727 0 : if( currentState().maColor != rColor )
728 : {
729 0 : currentState().maColor = rColor;
730 :
731 : char pBuffer[128];
732 0 : sal_Int32 nChar = 0;
733 :
734 0 : if( mbColor )
735 : {
736 : nChar = psp::getValueOfDouble (pBuffer,
737 0 : (double)rColor.GetRed() / 255.0, 5);
738 0 : nChar += psp::appendStr (" ", pBuffer + nChar);
739 : nChar += psp::getValueOfDouble (pBuffer + nChar,
740 0 : (double)rColor.GetGreen() / 255.0, 5);
741 0 : nChar += psp::appendStr (" ", pBuffer + nChar);
742 : nChar += psp::getValueOfDouble (pBuffer + nChar,
743 0 : (double)rColor.GetBlue() / 255.0, 5);
744 0 : nChar += psp::appendStr (" setrgbcolor\n", pBuffer + nChar );
745 : }
746 : else
747 : {
748 0 : Color aColor( rColor.GetRed(), rColor.GetGreen(), rColor.GetBlue() );
749 0 : sal_uInt8 nCol = aColor.GetLuminance();
750 0 : nChar = psp::getValueOfDouble( pBuffer, (double)nCol / 255.0, 5 );
751 0 : nChar += psp::appendStr( " setgray\n", pBuffer + nChar );
752 : }
753 :
754 0 : WritePS (mpPageBody, pBuffer, nChar);
755 : }
756 0 : }
757 :
758 : void
759 0 : PrinterGfx::PSSetFont ()
760 : {
761 0 : GraphicsStatus& rCurrent( currentState() );
762 0 : 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
768 : )
769 : {
770 0 : rCurrent.maFont = maVirtualStatus.maFont;
771 0 : rCurrent.maEncoding = maVirtualStatus.maEncoding;
772 0 : rCurrent.mnTextWidth = maVirtualStatus.mnTextWidth;
773 0 : rCurrent.mnTextHeight = maVirtualStatus.mnTextHeight;
774 0 : rCurrent.mbArtItalic = maVirtualStatus.mbArtItalic;
775 0 : rCurrent.mbArtBold = maVirtualStatus.mbArtBold;
776 :
777 0 : sal_Int32 nTextHeight = rCurrent.mnTextHeight;
778 : sal_Int32 nTextWidth = rCurrent.mnTextWidth ? rCurrent.mnTextWidth
779 0 : : rCurrent.mnTextHeight;
780 :
781 : sal_Char pSetFont [256];
782 0 : sal_Int32 nChar = 0;
783 :
784 : // postscript based fonts need reencoding
785 0 : 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)
789 : )
790 : {
791 : rtl::OString aReencodedFont =
792 : psp::GlyphSet::GetReencodedFontName (rCurrent.maEncoding,
793 0 : rCurrent.maFont);
794 :
795 0 : nChar += psp::appendStr ("(", pSetFont + nChar);
796 : nChar += psp::appendStr (aReencodedFont.getStr(),
797 0 : pSetFont + nChar);
798 : nChar += psp::appendStr (") cvn findfont ",
799 0 : pSetFont + nChar);
800 : }
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
804 : {
805 0 : nChar += psp::appendStr ("(", pSetFont + nChar);
806 : nChar += psp::appendStr (rCurrent.maFont.getStr(),
807 0 : pSetFont + nChar);
808 : nChar += psp::appendStr (") cvn findfont ",
809 0 : pSetFont + nChar);
810 : }
811 :
812 0 : if( ! rCurrent.mbArtItalic )
813 : {
814 0 : nChar += psp::getValueOf (nTextWidth, pSetFont + nChar);
815 0 : nChar += psp::appendStr (" ", pSetFont + nChar);
816 0 : nChar += psp::getValueOf (-nTextHeight, pSetFont + nChar);
817 0 : nChar += psp::appendStr (" matrix scale makefont setfont\n", pSetFont + nChar);
818 : }
819 : else // skew 15 degrees to right
820 : {
821 0 : nChar += psp::appendStr ( " [", pSetFont + nChar);
822 0 : nChar += psp::getValueOf (nTextWidth, pSetFont + nChar);
823 0 : nChar += psp::appendStr (" 0 ", pSetFont + nChar);
824 0 : nChar += psp::getValueOfDouble (pSetFont + nChar, 0.27*(double)nTextWidth, 3 );
825 0 : nChar += psp::appendStr ( " ", pSetFont + nChar);
826 0 : nChar += psp::getValueOf (-nTextHeight, pSetFont + nChar);
827 :
828 0 : nChar += psp::appendStr (" 0 0] makefont setfont\n", pSetFont + nChar);
829 : }
830 :
831 0 : WritePS (mpPageBody, pSetFont);
832 : }
833 0 : }
834 :
835 : void
836 0 : PrinterGfx::PSRotate (sal_Int32 nAngle)
837 : {
838 0 : sal_Int32 nPostScriptAngle = -nAngle;
839 0 : while( nPostScriptAngle < 0 )
840 0 : nPostScriptAngle += 3600;
841 :
842 0 : if (nPostScriptAngle == 0)
843 0 : return;
844 :
845 0 : sal_Int32 nFullAngle = nPostScriptAngle / 10;
846 0 : sal_Int32 nTenthAngle = nPostScriptAngle % 10;
847 :
848 : sal_Char pRotate [48];
849 0 : sal_Int32 nChar = 0;
850 :
851 0 : nChar = psp::getValueOf (nFullAngle, pRotate);
852 0 : nChar += psp::appendStr (".", pRotate + nChar);
853 0 : nChar += psp::getValueOf (nTenthAngle, pRotate + nChar);
854 0 : nChar += psp::appendStr (" rotate\n", pRotate + nChar);
855 :
856 0 : WritePS (mpPageBody, pRotate);
857 : }
858 :
859 : void
860 0 : PrinterGfx::PSPointOp (const Point& rPoint, const sal_Char* pOperator)
861 : {
862 : sal_Char pPSCommand [48];
863 0 : sal_Int32 nChar = 0;
864 :
865 0 : nChar = psp::getValueOf (rPoint.X(), pPSCommand);
866 0 : nChar += psp::appendStr (" ", pPSCommand + nChar);
867 0 : nChar += psp::getValueOf (rPoint.Y(), pPSCommand + nChar);
868 0 : nChar += psp::appendStr (" ", pPSCommand + nChar);
869 0 : nChar += psp::appendStr (pOperator, pPSCommand + nChar);
870 0 : nChar += psp::appendStr ("\n", pPSCommand + nChar);
871 :
872 : DBG_ASSERT (nChar < 48, "Buffer overflow in PSPointOp");
873 :
874 0 : WritePS (mpPageBody, pPSCommand);
875 0 : }
876 :
877 : void
878 0 : PrinterGfx::PSTranslate (const Point& rPoint)
879 : {
880 0 : PSPointOp (rPoint, "translate");
881 0 : }
882 :
883 : void
884 0 : PrinterGfx::PSMoveTo (const Point& rPoint)
885 : {
886 0 : PSPointOp (rPoint, "moveto");
887 0 : }
888 :
889 : void
890 0 : PrinterGfx::PSLineTo (const Point& rPoint)
891 : {
892 0 : PSPointOp (rPoint, "lineto");
893 0 : }
894 :
895 : /* get a compressed representation of the path information */
896 :
897 : #define DEBUG_BINPATH 0
898 :
899 : void
900 0 : PrinterGfx::PSBinLineTo (const Point& rCurrent, Point& rOld, sal_Int32& nColumn)
901 : {
902 : #if (DEBUG_BINPATH == 1)
903 : PSLineTo (rCurrent);
904 : #else
905 0 : PSBinPath (rCurrent, rOld, lineto, nColumn);
906 : #endif
907 0 : }
908 :
909 : void
910 0 : PrinterGfx::PSBinMoveTo (const Point& rCurrent, Point& rOld, sal_Int32& nColumn)
911 : {
912 : #if (DEBUG_BINPATH == 1)
913 : PSMoveTo (rCurrent);
914 : #else
915 0 : PSBinPath (rCurrent, rOld, moveto, nColumn);
916 : #endif
917 0 : }
918 :
919 : void
920 0 : PrinterGfx::PSBinStartPath ()
921 : {
922 : #if (DEBUG_BINPATH == 1)
923 : WritePS (mpPageBody, "% PSBinStartPath\n");
924 : #else
925 0 : WritePS (mpPageBody, "readpath\n" );
926 : #endif
927 0 : }
928 :
929 : void
930 0 : PrinterGfx::PSBinEndPath ()
931 : {
932 : #if (DEBUG_BINPATH == 1)
933 : WritePS (mpPageBody, "% PSBinEndPath\n");
934 : #else
935 0 : WritePS (mpPageBody, "~\n");
936 : #endif
937 0 : }
938 :
939 : void
940 0 : PrinterGfx::PSBinCurrentPath (sal_uInt32 nPoints, const Point* pPath)
941 : {
942 : // create the path
943 0 : Point aPoint (0, 0);
944 0 : sal_Int32 nColumn = 0;
945 :
946 0 : PSBinStartPath ();
947 0 : PSBinMoveTo (*pPath, aPoint, nColumn);
948 0 : for (unsigned int i = 1; i < nPoints; i++)
949 0 : PSBinLineTo (pPath[i], aPoint, nColumn);
950 0 : PSBinEndPath ();
951 0 : }
952 :
953 : void
954 0 : PrinterGfx::PSBinPath (const Point& rCurrent, Point& rOld,
955 : pspath_t eType, sal_Int32& nColumn)
956 : {
957 : sal_Char pPath[48];
958 : sal_Int32 nChar;
959 :
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 0 : sal_Int32 nXPrec = getAlignedHexValueOf (rCurrent.X() - rOld.X(), pPath + 1);
963 0 : sal_Int32 nYPrec = getAlignedHexValueOf (rCurrent.Y() - rOld.Y(), pPath + 1 + nXPrec);
964 0 : pPath [ 1 + nXPrec + nYPrec ] = 0;
965 :
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 0 : sal_Char cCmd = (eType == lineto ? (sal_Char)0x00 : (sal_Char)0x10);
970 0 : switch (nYPrec)
971 : {
972 0 : case 2: break;
973 0 : case 4: cCmd |= 0x01; break;
974 0 : case 6: cCmd |= 0x02; break;
975 0 : case 8: cCmd |= 0x03; break;
976 : default: OSL_FAIL("invalid x precision in binary path");
977 : }
978 0 : switch (nXPrec)
979 : {
980 0 : case 2: break;
981 0 : case 4: cCmd |= 0x04; break;
982 0 : case 6: cCmd |= 0x08; break;
983 0 : case 8: cCmd |= 0x0c; break;
984 : default: OSL_FAIL("invalid y precision in binary path");
985 : }
986 0 : cCmd += 'A';
987 0 : pPath[0] = cCmd;
988 :
989 : // write the command to file,
990 : // line breaking at column nMaxTextColumn (80)
991 0 : nChar = 1 + nXPrec + nYPrec;
992 0 : if ((nColumn + nChar) > nMaxTextColumn)
993 : {
994 0 : sal_Int32 nSegment = nMaxTextColumn - nColumn;
995 :
996 0 : WritePS (mpPageBody, pPath, nSegment);
997 0 : WritePS (mpPageBody, "\n", 1);
998 0 : WritePS (mpPageBody, pPath + nSegment, nChar - nSegment);
999 :
1000 0 : nColumn = nChar - nSegment;
1001 : }
1002 : else
1003 : {
1004 0 : WritePS (mpPageBody, pPath, nChar);
1005 :
1006 0 : nColumn += nChar;
1007 : }
1008 :
1009 0 : rOld = rCurrent;
1010 0 : }
1011 :
1012 : void
1013 0 : PrinterGfx::PSScale (double fScaleX, double fScaleY)
1014 : {
1015 : sal_Char pScale [48];
1016 0 : sal_Int32 nChar = 0;
1017 :
1018 0 : nChar = psp::getValueOfDouble (pScale, fScaleX, 5);
1019 0 : nChar += psp::appendStr (" ", pScale + nChar);
1020 0 : nChar += psp::getValueOfDouble (pScale + nChar, fScaleY, 5);
1021 0 : nChar += psp::appendStr (" scale\n", pScale + nChar);
1022 :
1023 0 : WritePS (mpPageBody, pScale);
1024 0 : }
1025 :
1026 : /* psshowtext helper routines: draw an hex string for show/xshow */
1027 : void
1028 0 : PrinterGfx::PSHexString (const sal_uChar* pString, sal_Int16 nLen)
1029 : {
1030 : sal_Char pHexString [128];
1031 0 : sal_Int32 nChar = 0;
1032 :
1033 0 : nChar = psp::appendStr ("<", pHexString);
1034 0 : for (int i = 0; i < nLen; i++)
1035 : {
1036 0 : if (nChar >= (nMaxTextColumn - 1))
1037 : {
1038 0 : nChar += psp::appendStr ("\n", pHexString + nChar);
1039 0 : WritePS (mpPageBody, pHexString, nChar);
1040 0 : nChar = 0;
1041 : }
1042 0 : nChar += psp::getHexValueOf ((sal_Int32)pString[i], pHexString + nChar);
1043 : }
1044 :
1045 0 : nChar += psp::appendStr (">\n", pHexString + nChar);
1046 0 : WritePS (mpPageBody, pHexString, nChar);
1047 0 : }
1048 :
1049 : /* psshowtext helper routines: draw an array for xshow ps operator */
1050 : void
1051 0 : PrinterGfx::PSDeltaArray (const sal_Int32 *pArray, sal_Int16 nEntries)
1052 : {
1053 : sal_Char pPSArray [128];
1054 0 : sal_Int32 nChar = 0;
1055 :
1056 0 : nChar = psp::appendStr ("[", pPSArray + nChar);
1057 0 : nChar += psp::getValueOf (pArray[0], pPSArray + nChar);
1058 :
1059 0 : for (int i = 1; i < nEntries; i++)
1060 : {
1061 0 : if (nChar >= (nMaxTextColumn - 1))
1062 : {
1063 0 : nChar += psp::appendStr ("\n", pPSArray + nChar);
1064 0 : WritePS (mpPageBody, pPSArray, nChar);
1065 0 : nChar = 0;
1066 : }
1067 :
1068 0 : nChar += psp::appendStr (" ", pPSArray + nChar);
1069 0 : nChar += psp::getValueOf (pArray[i] - pArray[i-1], pPSArray + nChar);
1070 : }
1071 :
1072 0 : nChar += psp::appendStr (" 0]\n", pPSArray + nChar);
1073 0 : WritePS (mpPageBody, pPSArray);
1074 0 : }
1075 :
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 0 : PrinterGfx::PSShowText (const sal_uChar* pStr, sal_Int16 nGlyphs, sal_Int16 nBytes,
1081 : const sal_Int32* pDeltaArray)
1082 : {
1083 0 : PSSetColor (maTextColor);
1084 0 : PSSetColor ();
1085 0 : PSSetFont ();
1086 : // rotate the user coordinate system
1087 0 : if (mnTextAngle != 0)
1088 : {
1089 0 : PSGSave ();
1090 0 : PSRotate (mnTextAngle);
1091 : }
1092 :
1093 : sal_Char pBuffer[256];
1094 0 : if( maVirtualStatus.mbArtBold )
1095 : {
1096 0 : sal_Int32 nLW = maVirtualStatus.mnTextWidth;
1097 0 : if( nLW == 0 )
1098 0 : nLW = maVirtualStatus.mnTextHeight;
1099 : else
1100 0 : nLW = nLW < maVirtualStatus.mnTextHeight ? nLW : maVirtualStatus.mnTextHeight;
1101 0 : psp::getValueOfDouble( pBuffer, (double)nLW / 30.0 );
1102 : }
1103 : // dispatch to the drawing method
1104 0 : if (pDeltaArray == NULL)
1105 : {
1106 0 : PSHexString (pStr, nBytes);
1107 :
1108 0 : if( maVirtualStatus.mbArtBold )
1109 : {
1110 0 : WritePS( mpPageBody, pBuffer );
1111 0 : WritePS( mpPageBody, " bshow\n" );
1112 : }
1113 : else
1114 0 : WritePS (mpPageBody, "show\n");
1115 : }
1116 : else
1117 : {
1118 0 : PSHexString (pStr, nBytes);
1119 0 : PSDeltaArray (pDeltaArray, nGlyphs - 1);
1120 0 : if( maVirtualStatus.mbArtBold )
1121 : {
1122 0 : WritePS( mpPageBody, pBuffer );
1123 0 : WritePS( mpPageBody, " bxshow\n" );
1124 : }
1125 : else
1126 0 : WritePS (mpPageBody, "xshow\n");
1127 : }
1128 :
1129 : // restore the user coordinate system
1130 0 : if (mnTextAngle != 0)
1131 0 : PSGRestore ();
1132 0 : }
1133 :
1134 : void
1135 0 : PrinterGfx::PSComment( const sal_Char* pComment )
1136 : {
1137 0 : const sal_Char* pLast = pComment;
1138 0 : while( pComment && *pComment )
1139 : {
1140 0 : while( *pComment && *pComment != '\n' && *pComment != '\r' )
1141 0 : pComment++;
1142 0 : if( pComment - pLast > 1 )
1143 : {
1144 0 : WritePS( mpPageBody, "% ", 2 );
1145 0 : WritePS( mpPageBody, pLast, pComment - pLast );
1146 0 : WritePS( mpPageBody, "\n", 1 );
1147 : }
1148 0 : if( *pComment )
1149 0 : pLast = ++pComment;
1150 : }
1151 0 : }
1152 :
1153 : sal_Bool
1154 0 : PrinterGfx::DrawEPS( const Rectangle& rBoundingBox, void* pPtr, sal_uInt32 nSize )
1155 : {
1156 0 : if( nSize == 0 )
1157 0 : return sal_True;
1158 0 : if( ! mpPageBody )
1159 0 : return sal_False;
1160 :
1161 0 : sal_Bool bSuccess = sal_False;
1162 :
1163 : // first search the BoundingBox of the EPS data
1164 0 : SvMemoryStream aStream( pPtr, nSize, STREAM_READ );
1165 0 : aStream.Seek( STREAM_SEEK_TO_BEGIN );
1166 0 : rtl::OString aLine;
1167 :
1168 0 : rtl::OString aDocTitle;
1169 0 : double fLeft = 0, fRight = 0, fTop = 0, fBottom = 0;
1170 0 : bool bEndComments = false;
1171 0 : while( ! aStream.IsEof()
1172 : && ( ( fLeft == 0 && fRight == 0 && fTop == 0 && fBottom == 0 ) ||
1173 0 : ( aDocTitle.isEmpty() && bEndComments == false ) )
1174 : )
1175 : {
1176 0 : aStream.ReadLine( aLine );
1177 0 : if( aLine.getLength() > 1 && aLine[0] == '%' )
1178 : {
1179 0 : char cChar = aLine[1];
1180 0 : if( cChar == '%' )
1181 : {
1182 0 : if( aLine.matchIgnoreAsciiCase( rtl::OString( RTL_CONSTASCII_STRINGPARAM("%%BoundingBox:") ) ) )
1183 : {
1184 0 : aLine = WhitespaceToSpace( aLine.getToken(1, ':') );
1185 0 : if( !aLine.isEmpty() && aLine.indexOf( "atend" ) == -1 )
1186 : {
1187 0 : fLeft = StringToDouble( GetCommandLineToken( 0, aLine ) );
1188 0 : fBottom = StringToDouble( GetCommandLineToken( 1, aLine ) );
1189 0 : fRight = StringToDouble( GetCommandLineToken( 2, aLine ) );
1190 0 : fTop = StringToDouble( GetCommandLineToken( 3, aLine ) );
1191 : }
1192 : }
1193 0 : else if( aLine.matchIgnoreAsciiCase( rtl::OString( RTL_CONSTASCII_STRINGPARAM("%%Title:") ) ) )
1194 0 : aDocTitle = WhitespaceToSpace( aLine.copy( 8 ) );
1195 0 : else if( aLine.matchIgnoreAsciiCase( rtl::OString( RTL_CONSTASCII_STRINGPARAM("%%EndComments") ) ) )
1196 0 : bEndComments = true;
1197 : }
1198 0 : else if( cChar == ' ' || cChar == '\t' || cChar == '\r' || cChar == '\n' )
1199 0 : bEndComments = true;
1200 : }
1201 : else
1202 0 : bEndComments = true;
1203 : }
1204 :
1205 : static sal_uInt16 nEps = 0;
1206 0 : if( aDocTitle.isEmpty() )
1207 0 : aDocTitle = rtl::OString::valueOf(static_cast<sal_Int32>(nEps++));
1208 :
1209 0 : if( fLeft != fRight && fTop != fBottom )
1210 : {
1211 0 : double fScaleX = (double)rBoundingBox.GetWidth()/(fRight-fLeft);
1212 0 : double fScaleY = -(double)rBoundingBox.GetHeight()/(fTop-fBottom);
1213 0 : Point aTranslatePoint( (int)(rBoundingBox.Left()-fLeft*fScaleX),
1214 0 : (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 0 : "}if\n" );
1230 : // set up clip path and scale
1231 0 : BeginSetClipRegion( 1 );
1232 0 : UnionClipRegion( rBoundingBox.Left(), rBoundingBox.Top(), rBoundingBox.GetWidth(), rBoundingBox.GetHeight() );
1233 0 : EndSetClipRegion();
1234 0 : PSTranslate( aTranslatePoint );
1235 0 : PSScale( fScaleX, fScaleY );
1236 :
1237 : // DSC requires BeginDocument
1238 0 : WritePS( mpPageBody, "%%BeginDocument: " );
1239 0 : WritePS( mpPageBody, aDocTitle );
1240 0 : WritePS( mpPageBody, "\n" );
1241 :
1242 : // write the EPS data
1243 : sal_uInt64 nOutLength;
1244 0 : mpPageBody->write( pPtr, nSize, nOutLength );
1245 0 : bSuccess = nOutLength == nSize;
1246 :
1247 : // corresponding EndDocument
1248 0 : if( ((char*)pPtr)[ nSize-1 ] != '\n' )
1249 0 : WritePS( mpPageBody, "\n" );
1250 0 : WritePS( mpPageBody, "%%EndDocument\n" );
1251 :
1252 : // clean up EPS
1253 : WritePS( mpPageBody,
1254 : "count op_count sub {pop} repeat\n"
1255 : "countdictstack dict_count sub {end} repeat\n"
1256 0 : "b4_Inc_state restore\n" );
1257 : }
1258 0 : return bSuccess;
1259 : }
1260 :
1261 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|