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 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 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 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 105 PrinterGfx::GetResolution (sal_Int32 &rDpiX, sal_Int32 &rDpiY) const 106 { 107 rDpiX = mnDpi; 108 rDpiY = mnDpi; 109 } 110 111 sal_uInt16 112 PrinterGfx::GetBitCount () 113 { 114 return mnDepth; 115 } 116 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 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 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 184 PrinterGfx::ResetClipRegion() 185 { 186 maClipRegion.clear(); 187 PSGRestore (); 188 PSGSave (); // get "clean" clippath 189 } 190 191 void 192 PrinterGfx::BeginSetClipRegion( sal_uInt32 ) 193 { 194 maClipRegion.clear(); 195 } 196 197 sal_Bool 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 892 PrinterGfx::PSTranslate (const Point& rPoint) 893 { 894 PSPointOp (rPoint, "translate"); 895 } 896 897 void 898 PrinterGfx::PSMoveTo (const Point& rPoint) 899 { 900 PSPointOp (rPoint, "moveto"); 901 } 902 903 void 904 PrinterGfx::PSLineTo (const Point& rPoint) 905 { 906 PSPointOp (rPoint, "lineto"); 907 } 908 909 void 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 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 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 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 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 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 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 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 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 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 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 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 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