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