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