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 <stdio.h> 32 #include <sys/types.h> 33 #include <sys/stat.h> 34 #include <fcntl.h> 35 #include <unistd.h> 36 #include <pwd.h> 37 38 #include "psputil.hxx" 39 #include "glyphset.hxx" 40 41 #include "printerjob.hxx" 42 #include "printergfx.hxx" 43 #include "vcl/ppdparser.hxx" 44 #include "vcl/strhelper.hxx" 45 #include "vcl/printerinfomanager.hxx" 46 47 #include "rtl/ustring.hxx" 48 #include "rtl/strbuf.hxx" 49 #include "rtl/ustrbuf.hxx" 50 51 #include "osl/thread.h" 52 #include "sal/alloca.h" 53 54 #include <algorithm> 55 #include <vector> 56 57 using namespace psp; 58 using namespace rtl; 59 60 // forward declaration 61 62 #define nBLOCKSIZE 0x2000 63 64 namespace psp 65 { 66 67 sal_Bool 68 AppendPS (FILE* pDst, osl::File* pSrc, sal_uChar* pBuffer, 69 sal_uInt32 nBlockSize = nBLOCKSIZE) 70 { 71 if ((pDst == NULL) || (pSrc == NULL)) 72 return sal_False; 73 74 if (nBlockSize == 0) 75 nBlockSize = nBLOCKSIZE; 76 if (pBuffer == NULL) 77 pBuffer = (sal_uChar*)alloca (nBlockSize); 78 79 pSrc->setPos (osl_Pos_Absolut, 0); 80 81 sal_uInt64 nIn = 0; 82 sal_uInt64 nOut = 0; 83 do 84 { 85 pSrc->read (pBuffer, nBlockSize, nIn); 86 if (nIn > 0) 87 nOut = fwrite (pBuffer, 1, sal::static_int_cast<sal_uInt32>(nIn), pDst); 88 } 89 while ((nIn > 0) && (nIn == nOut)); 90 91 return sal_True; 92 } 93 94 } // namespace psp 95 96 /* 97 * private convenience routines for file handling 98 */ 99 100 osl::File* 101 PrinterJob::CreateSpoolFile (const rtl::OUString& rName, const rtl::OUString& rExtension) 102 { 103 osl::File::RC nError = osl::File::E_None; 104 osl::File* pFile = NULL; 105 106 rtl::OUString aFile = rName + rExtension; 107 rtl::OUString aFileURL; 108 nError = osl::File::getFileURLFromSystemPath( aFile, aFileURL ); 109 if (nError != osl::File::E_None) 110 return NULL; 111 aFileURL = maSpoolDirName + rtl::OUString::createFromAscii ("/") + aFileURL; 112 113 pFile = new osl::File (aFileURL); 114 nError = pFile->open (OpenFlag_Read | OpenFlag_Write | OpenFlag_Create); 115 if (nError != osl::File::E_None) 116 { 117 delete pFile; 118 return NULL; 119 } 120 121 pFile->setAttributes (aFileURL, 122 osl_File_Attribute_OwnWrite | osl_File_Attribute_OwnRead); 123 return pFile; 124 } 125 126 /* 127 * public methods of PrinterJob: for use in PrinterGfx 128 */ 129 130 void 131 PrinterJob::GetScale (double &rXScale, double &rYScale) const 132 { 133 rXScale = mfXScale; 134 rYScale = mfYScale; 135 } 136 137 sal_uInt16 138 PrinterJob::GetDepth () const 139 { 140 sal_Int32 nLevel = GetPostscriptLevel(); 141 sal_Bool bColor = IsColorPrinter (); 142 143 return nLevel > 1 && bColor ? 24 : 8; 144 } 145 146 sal_uInt16 147 PrinterJob::GetPostscriptLevel (const JobData *pJobData) const 148 { 149 sal_uInt16 nPSLevel = 2; 150 151 if( pJobData == NULL ) 152 pJobData = &m_aLastJobData; 153 154 if( pJobData->m_nPSLevel ) 155 nPSLevel = pJobData->m_nPSLevel; 156 else 157 if( pJobData->m_pParser ) 158 nPSLevel = pJobData->m_pParser->getLanguageLevel(); 159 160 return nPSLevel; 161 } 162 163 sal_Bool 164 PrinterJob::IsColorPrinter () const 165 { 166 sal_Bool bColor = sal_False; 167 168 if( m_aLastJobData.m_nColorDevice ) 169 bColor = m_aLastJobData.m_nColorDevice == -1 ? sal_False : sal_True; 170 else if( m_aLastJobData.m_pParser ) 171 bColor = m_aLastJobData.m_pParser->isColorDevice() ? sal_True : sal_False; 172 173 return bColor; 174 } 175 176 osl::File* 177 PrinterJob::GetDocumentHeader () 178 { 179 return mpJobHeader; 180 } 181 182 osl::File* 183 PrinterJob::GetDocumentTrailer () 184 { 185 return mpJobTrailer; 186 } 187 188 osl::File* 189 PrinterJob::GetCurrentPageHeader () 190 { 191 return maHeaderList.back(); 192 } 193 194 osl::File* 195 PrinterJob::GetCurrentPageBody () 196 { 197 return maPageList.back(); 198 } 199 200 /* 201 * public methods of PrinterJob: the actual job / spool handling 202 */ 203 204 PrinterJob::PrinterJob () : 205 mpJobHeader( NULL ), 206 mpJobTrailer( NULL ), 207 m_bQuickJob( false ) 208 { 209 } 210 211 namespace psp 212 { 213 214 /* check whether the given name points to a directory which is 215 usable for the user */ 216 sal_Bool 217 existsTmpDir (const char* pName) 218 { 219 struct stat aFileStatus; 220 221 if (pName == NULL) 222 return sal_False; 223 if (stat(pName, &aFileStatus) != 0) 224 return sal_False; 225 if (! S_ISDIR(aFileStatus.st_mode)) 226 return sal_False; 227 228 return access(pName, W_OK | R_OK) == 0 ? sal_True : sal_False; 229 } 230 231 /* return the username in the given buffer */ 232 sal_Bool 233 getUserName (char* pName, int nSize) 234 { 235 struct passwd *pPWEntry; 236 struct passwd aPWEntry; 237 sal_Char pPWBuffer[256]; 238 239 sal_Bool bSuccess = sal_False; 240 241 #ifdef FREEBSD 242 pPWEntry = getpwuid( getuid()); 243 #else 244 if (getpwuid_r(getuid(), &aPWEntry, pPWBuffer, sizeof(pPWBuffer), &pPWEntry) != 0) 245 pPWEntry = NULL; 246 #endif 247 248 if (pPWEntry != NULL && pPWEntry->pw_name != NULL) 249 { 250 sal_Int32 nLen = strlen(pPWEntry->pw_name); 251 if (nLen > 0 && nLen < nSize) 252 { 253 memcpy (pName, pPWEntry->pw_name, nLen); 254 pName[nLen] = '\0'; 255 256 bSuccess = sal_True; 257 } 258 } 259 260 // wipe the passwd off the stack 261 memset (pPWBuffer, 0, sizeof(pPWBuffer)); 262 263 return bSuccess; 264 } 265 266 /* remove all our temporary files, uses external program "rm", since 267 osl functionality is inadequate */ 268 void 269 removeSpoolDir (const rtl::OUString& rSpoolDir) 270 { 271 rtl::OUString aSysPath; 272 if( osl::File::E_None != osl::File::getSystemPathFromFileURL( rSpoolDir, aSysPath ) ) 273 { 274 // Conversion did not work, as this is quite a dangerous action, 275 // we should abort here .... 276 OSL_ENSURE( 0, "psprint: couldn't remove spool directory" ); 277 return; 278 } 279 rtl::OString aSysPathByte = 280 rtl::OUStringToOString (aSysPath, osl_getThreadTextEncoding()); 281 sal_Char pSystem [128]; 282 sal_Int32 nChar = 0; 283 284 nChar = psp::appendStr ("rm -rf ", pSystem); 285 nChar += psp::appendStr (aSysPathByte.getStr(), pSystem + nChar); 286 287 if (system (pSystem) == -1) 288 OSL_ENSURE( 0, "psprint: couldn't remove spool directory" ); 289 } 290 291 /* creates a spool directory with a "pidgin random" value based on 292 current system time */ 293 rtl::OUString 294 createSpoolDir () 295 { 296 TimeValue aCur; 297 osl_getSystemTime( &aCur ); 298 sal_Int32 nRand = aCur.Seconds ^ (aCur.Nanosec/1000); 299 300 rtl::OUString aTmpDir; 301 osl_getTempDirURL( &aTmpDir.pData ); 302 303 do 304 { 305 rtl::OUStringBuffer aDir( aTmpDir.getLength() + 16 ); 306 aDir.append( aTmpDir ); 307 aDir.appendAscii( "/psp" ); 308 aDir.append(nRand); 309 rtl::OUString aResult = aDir.makeStringAndClear(); 310 if( osl::Directory::create( aResult ) == osl::FileBase::E_None ) 311 { 312 osl::File::setAttributes( aResult, 313 osl_File_Attribute_OwnWrite 314 | osl_File_Attribute_OwnRead 315 | osl_File_Attribute_OwnExe ); 316 return aResult; 317 } 318 nRand++; 319 } while( nRand ); 320 return rtl::OUString(); 321 } 322 323 } // namespace psp 324 325 PrinterJob::~PrinterJob () 326 { 327 std::list< osl::File* >::iterator pPage; 328 for (pPage = maPageList.begin(); pPage != maPageList.end(); pPage++) 329 { 330 //(*pPage)->remove(); 331 delete *pPage; 332 } 333 for (pPage = maHeaderList.begin(); pPage != maHeaderList.end(); pPage++) 334 { 335 //(*pPage)->remove(); 336 delete *pPage; 337 } 338 // mpJobHeader->remove(); 339 delete mpJobHeader; 340 // mpJobTrailer->remove(); 341 delete mpJobTrailer; 342 343 // XXX should really call osl::remove routines 344 if( maSpoolDirName.getLength() ) 345 removeSpoolDir (maSpoolDirName); 346 347 // osl::Directory::remove (maSpoolDirName); 348 } 349 350 namespace psp 351 { 352 353 // get locale invariant, 7bit clean current local time string 354 sal_Char* 355 getLocalTime(sal_Char* pBuffer) 356 { 357 time_t nTime = time (NULL); 358 struct tm aTime; 359 struct tm *pLocalTime = localtime_r (&nTime, &aTime); 360 361 return asctime_r(pLocalTime, pBuffer); 362 } 363 364 } 365 366 static bool isAscii( const rtl::OUString& rStr ) 367 { 368 const sal_Unicode* pStr = rStr; 369 sal_Int32 nLen = rStr.getLength(); 370 for( sal_Int32 i = 0; i < nLen; i++ ) 371 if( pStr[i] > 127 ) 372 return false; 373 return true; 374 } 375 376 sal_Bool 377 PrinterJob::StartJob ( 378 const rtl::OUString& rFileName, 379 int nMode, 380 const rtl::OUString& rJobName, 381 const rtl::OUString& rAppName, 382 const JobData& rSetupData, 383 PrinterGfx* pGraphics, 384 bool bIsQuickJob 385 ) 386 { 387 m_bQuickJob = bIsQuickJob; 388 mnMaxWidthPt = mnMaxHeightPt = 0; 389 mnLandscapes = mnPortraits = 0; 390 m_pGraphics = pGraphics; 391 InitPaperSize (rSetupData); 392 393 // create file container for document header and trailer 394 maFileName = rFileName; 395 mnFileMode = nMode; 396 maSpoolDirName = createSpoolDir (); 397 maJobTitle = rJobName; 398 399 rtl::OUString aExt = rtl::OUString::createFromAscii (".ps"); 400 mpJobHeader = CreateSpoolFile (rtl::OUString::createFromAscii("psp_head"), aExt); 401 mpJobTrailer = CreateSpoolFile (rtl::OUString::createFromAscii("psp_tail"), aExt); 402 if( ! (mpJobHeader && mpJobTrailer) ) // existing files are removed in destructor 403 return sal_False; 404 405 // write document header according to Document Structuring Conventions (DSC) 406 WritePS (mpJobHeader, 407 "%!PS-Adobe-3.0\n" 408 "%%BoundingBox: (atend)\n" ); 409 410 rtl::OUString aFilterWS; 411 412 // Creator (this application) 413 aFilterWS = WhitespaceToSpace( rAppName, sal_False ); 414 WritePS (mpJobHeader, "%%Creator: ("); 415 WritePS (mpJobHeader, aFilterWS); 416 WritePS (mpJobHeader, ")\n"); 417 418 // For (user name) 419 sal_Char pUserName[64]; 420 if (getUserName(pUserName, sizeof(pUserName))) 421 { 422 WritePS (mpJobHeader, "%%For: ("); 423 WritePS (mpJobHeader, pUserName); 424 WritePS (mpJobHeader, ")\n"); 425 } 426 427 // Creation Date (locale independent local time) 428 sal_Char pCreationDate [256]; 429 WritePS (mpJobHeader, "%%CreationDate: ("); 430 getLocalTime(pCreationDate); 431 for( unsigned int i = 0; i < sizeof(pCreationDate)/sizeof(pCreationDate[0]); i++ ) 432 { 433 if( pCreationDate[i] == '\n' ) 434 { 435 pCreationDate[i] = 0; 436 break; 437 } 438 } 439 WritePS (mpJobHeader, pCreationDate ); 440 WritePS (mpJobHeader, ")\n"); 441 442 // Document Title 443 /* #i74335# 444 * The title should be clean ascii; rJobName however may 445 * contain any Unicode character. So implement the following 446 * algorithm: 447 * use rJobName, if it contains only ascii 448 * use the filename, if it contains only ascii 449 * else omit %%Title 450 */ 451 aFilterWS = WhitespaceToSpace( rJobName, sal_False ); 452 rtl::OUString aTitle( aFilterWS ); 453 if( ! isAscii( aTitle ) ) 454 { 455 sal_Int32 nIndex = 0; 456 while( nIndex != -1 ) 457 aTitle = rFileName.getToken( 0, '/', nIndex ); 458 aTitle = WhitespaceToSpace( aTitle, sal_False ); 459 if( ! isAscii( aTitle ) ) 460 aTitle = rtl::OUString(); 461 } 462 463 maJobTitle = aFilterWS; 464 if( aTitle.getLength() ) 465 { 466 WritePS (mpJobHeader, "%%Title: ("); 467 WritePS (mpJobHeader, aTitle); 468 WritePS (mpJobHeader, ")\n"); 469 } 470 471 // Language Level 472 sal_Char pLevel[16]; 473 sal_Int32 nSz = getValueOf(GetPostscriptLevel(&rSetupData), pLevel); 474 pLevel[nSz++] = '\n'; 475 pLevel[nSz ] = '\0'; 476 WritePS (mpJobHeader, "%%LanguageLevel: "); 477 WritePS (mpJobHeader, pLevel); 478 479 // Other 480 WritePS (mpJobHeader, "%%DocumentData: Clean7Bit\n"); 481 WritePS (mpJobHeader, "%%Pages: (atend)\n"); 482 WritePS (mpJobHeader, "%%Orientation: (atend)\n"); 483 WritePS (mpJobHeader, "%%PageOrder: Ascend\n"); 484 WritePS (mpJobHeader, "%%EndComments\n"); 485 486 // write Prolog 487 writeProlog (mpJobHeader, rSetupData); 488 489 // mark last job setup as not set 490 m_aLastJobData.m_pParser = NULL; 491 m_aLastJobData.m_aContext.setParser( NULL ); 492 493 return sal_True; 494 } 495 496 sal_Bool 497 PrinterJob::EndJob () 498 { 499 // no pages ? that really means no print job 500 if( maPageList.empty() ) 501 return sal_False; 502 503 // write document setup (done here because it 504 // includes the accumulated fonts 505 if( mpJobHeader ) 506 writeSetup( mpJobHeader, m_aDocumentJobData ); 507 m_pGraphics->OnEndJob(); 508 if( ! (mpJobHeader && mpJobTrailer) ) 509 return sal_False; 510 511 // write document trailer according to Document Structuring Conventions (DSC) 512 rtl::OStringBuffer aTrailer(512); 513 aTrailer.append( "%%Trailer\n" ); 514 aTrailer.append( "%%BoundingBox: 0 0 " ); 515 aTrailer.append( (sal_Int32)mnMaxWidthPt ); 516 aTrailer.append( " " ); 517 aTrailer.append( (sal_Int32)mnMaxHeightPt ); 518 if( mnLandscapes > mnPortraits ) 519 aTrailer.append("\n%%Orientation: Landscape"); 520 else 521 aTrailer.append("\n%%Orientation: Portrait"); 522 aTrailer.append( "\n%%Pages: " ); 523 aTrailer.append( (sal_Int32)maPageList.size() ); 524 aTrailer.append( "\n%%EOF\n" ); 525 WritePS (mpJobTrailer, aTrailer.getStr()); 526 527 /* 528 * spool the set of files to their final destination, this is U**X dependent 529 */ 530 531 FILE* pDestFILE = NULL; 532 533 /* create a destination either as file or as a pipe */ 534 sal_Bool bSpoolToFile = maFileName.getLength() > 0 ? sal_True : sal_False; 535 if (bSpoolToFile) 536 { 537 const rtl::OString aFileName = rtl::OUStringToOString (maFileName, 538 osl_getThreadTextEncoding()); 539 if( mnFileMode ) 540 { 541 int nFile = open( aFileName.getStr(), O_CREAT | O_EXCL | O_RDWR, mnFileMode ); 542 if( nFile != -1 ) 543 { 544 pDestFILE = fdopen( nFile, "w" ); 545 if( pDestFILE == NULL ) 546 { 547 close( nFile ); 548 unlink( aFileName.getStr() ); 549 return sal_False; 550 } 551 } 552 else 553 chmod( aFileName.getStr(), mnFileMode ); 554 } 555 if (pDestFILE == NULL) 556 pDestFILE = fopen (aFileName.getStr(), "w"); 557 558 if (pDestFILE == NULL) 559 return sal_False; 560 } 561 else 562 { 563 PrinterInfoManager& rPrinterInfoManager = PrinterInfoManager::get (); 564 pDestFILE = rPrinterInfoManager.startSpool( m_aLastJobData.m_aPrinterName, m_bQuickJob ); 565 if (pDestFILE == NULL) 566 return sal_False; 567 } 568 569 /* spool the document parts to the destination */ 570 571 sal_uChar pBuffer[ nBLOCKSIZE ]; 572 573 AppendPS (pDestFILE, mpJobHeader, pBuffer); 574 mpJobHeader->close(); 575 576 sal_Bool bSuccess = sal_True; 577 std::list< osl::File* >::iterator pPageBody; 578 std::list< osl::File* >::iterator pPageHead; 579 for (pPageBody = maPageList.begin(), pPageHead = maHeaderList.begin(); 580 pPageBody != maPageList.end() && pPageHead != maHeaderList.end(); 581 pPageBody++, pPageHead++) 582 { 583 if( *pPageHead ) 584 { 585 osl::File::RC nError = (*pPageHead)->open(OpenFlag_Read); 586 if (nError == osl::File::E_None) 587 { 588 AppendPS (pDestFILE, *pPageHead, pBuffer); 589 (*pPageHead)->close(); 590 } 591 } 592 else 593 bSuccess = sal_False; 594 if( *pPageBody ) 595 { 596 osl::File::RC nError = (*pPageBody)->open(OpenFlag_Read); 597 if (nError == osl::File::E_None) 598 { 599 AppendPS (pDestFILE, *pPageBody, pBuffer); 600 (*pPageBody)->close(); 601 } 602 } 603 else 604 bSuccess = sal_False; 605 } 606 607 AppendPS (pDestFILE, mpJobTrailer, pBuffer); 608 mpJobTrailer->close(); 609 610 /* well done */ 611 612 if (bSpoolToFile) 613 fclose (pDestFILE); 614 else 615 { 616 PrinterInfoManager& rPrinterInfoManager = PrinterInfoManager::get(); 617 if (0 == rPrinterInfoManager.endSpool( m_aLastJobData.m_aPrinterName, 618 maJobTitle, pDestFILE, m_aDocumentJobData, true )) 619 { 620 bSuccess = sal_False; 621 } 622 } 623 624 return bSuccess; 625 } 626 627 sal_Bool 628 PrinterJob::AbortJob () 629 { 630 m_pGraphics->OnEndJob(); 631 return sal_False; 632 } 633 634 void 635 PrinterJob::InitPaperSize (const JobData& rJobSetup) 636 { 637 int nRes = rJobSetup.m_aContext.getRenderResolution (); 638 639 String aPaper; 640 int nWidth, nHeight; 641 rJobSetup.m_aContext.getPageSize (aPaper, nWidth, nHeight); 642 643 int nLeft = 0, nRight = 0, nUpper = 0, nLower = 0; 644 const PPDParser* pParser = rJobSetup.m_aContext.getParser(); 645 if (pParser != NULL) 646 pParser->getMargins (aPaper, nLeft, nRight, nUpper, nLower); 647 648 mnResolution = nRes; 649 650 mnWidthPt = nWidth; 651 mnHeightPt = nHeight; 652 653 if( mnWidthPt > mnMaxWidthPt ) 654 mnMaxWidthPt = mnWidthPt; 655 if( mnHeightPt > mnMaxHeightPt ) 656 mnMaxHeightPt = mnHeightPt; 657 658 mnLMarginPt = nLeft; 659 mnRMarginPt = nRight; 660 mnTMarginPt = nUpper; 661 mnBMarginPt = nLower; 662 663 mfXScale = (double)72.0 / (double)mnResolution; 664 mfYScale = -1.0 * (double)72.0 / (double)mnResolution; 665 } 666 667 668 sal_Bool 669 PrinterJob::StartPage (const JobData& rJobSetup) 670 { 671 InitPaperSize (rJobSetup); 672 673 rtl::OUString aPageNo = rtl::OUString::valueOf ((sal_Int32)maPageList.size()+1); // sequential page number must start with 1 674 rtl::OUString aExt = aPageNo + rtl::OUString::createFromAscii (".ps"); 675 676 osl::File* pPageHeader = CreateSpoolFile ( 677 rtl::OUString::createFromAscii("psp_pghead"), aExt); 678 osl::File* pPageBody = CreateSpoolFile ( 679 rtl::OUString::createFromAscii("psp_pgbody"), aExt); 680 681 maHeaderList.push_back (pPageHeader); 682 maPageList.push_back (pPageBody); 683 684 if( ! (pPageHeader && pPageBody) ) 685 return sal_False; 686 687 // write page header according to Document Structuring Conventions (DSC) 688 WritePS (pPageHeader, "%%Page: "); 689 WritePS (pPageHeader, aPageNo); 690 WritePS (pPageHeader, " "); 691 WritePS (pPageHeader, aPageNo); 692 WritePS (pPageHeader, "\n"); 693 694 if( rJobSetup.m_eOrientation == orientation::Landscape ) 695 { 696 WritePS (pPageHeader, "%%PageOrientation: Landscape\n"); 697 mnLandscapes++; 698 } 699 else 700 { 701 WritePS (pPageHeader, "%%PageOrientation: Portrait\n"); 702 mnPortraits++; 703 } 704 705 sal_Char pBBox [256]; 706 sal_Int32 nChar = 0; 707 708 nChar = psp::appendStr ("%%PageBoundingBox: ", pBBox); 709 nChar += psp::getValueOf (mnLMarginPt, pBBox + nChar); 710 nChar += psp::appendStr (" ", pBBox + nChar); 711 nChar += psp::getValueOf (mnBMarginPt, pBBox + nChar); 712 nChar += psp::appendStr (" ", pBBox + nChar); 713 nChar += psp::getValueOf (mnWidthPt - mnRMarginPt, pBBox + nChar); 714 nChar += psp::appendStr (" ", pBBox + nChar); 715 nChar += psp::getValueOf (mnHeightPt - mnTMarginPt, pBBox + nChar); 716 nChar += psp::appendStr ("\n", pBBox + nChar); 717 718 WritePS (pPageHeader, pBBox); 719 720 /* #i7262# #i65491# write setup only before first page 721 * (to %%Begin(End)Setup, instead of %%Begin(End)PageSetup) 722 * don't do this in StartJob since the jobsetup there may be 723 * different. 724 */ 725 bool bWriteFeatures = true; 726 if( 1 == maPageList.size() ) 727 { 728 m_aDocumentJobData = rJobSetup; 729 bWriteFeatures = false; 730 } 731 732 if ( writePageSetup( pPageHeader, rJobSetup, bWriteFeatures ) ) 733 { 734 m_aLastJobData = rJobSetup; 735 return true; 736 } 737 738 return false; 739 } 740 741 sal_Bool 742 PrinterJob::EndPage () 743 { 744 m_pGraphics->OnEndPage(); 745 746 osl::File* pPageHeader = maHeaderList.back(); 747 osl::File* pPageBody = maPageList.back(); 748 749 if( ! (pPageBody && pPageHeader) ) 750 return sal_False; 751 752 // copy page to paper and write page trailer according to DSC 753 754 sal_Char pTrailer[256]; 755 sal_Int32 nChar = 0; 756 nChar = psp::appendStr ("grestore grestore\n", pTrailer); 757 nChar += psp::appendStr ("showpage\n", pTrailer + nChar); 758 nChar += psp::appendStr ("%%PageTrailer\n\n", pTrailer + nChar); 759 WritePS (pPageBody, pTrailer); 760 761 // this page is done for now, close it to avoid having too many open fd's 762 763 pPageHeader->close(); 764 pPageBody->close(); 765 766 return sal_True; 767 } 768 769 sal_uInt32 770 PrinterJob::GetErrorCode () 771 { 772 /* TODO */ 773 return 0; 774 } 775 776 struct less_ppd_key : public ::std::binary_function<double, double, bool> 777 { 778 bool operator()(const PPDKey* left, const PPDKey* right) 779 { return left->getOrderDependency() < right->getOrderDependency(); } 780 }; 781 782 static bool writeFeature( osl::File* pFile, const PPDKey* pKey, const PPDValue* pValue, bool bUseIncluseFeature ) 783 { 784 if( ! pKey || ! pValue ) 785 return true; 786 787 OStringBuffer aFeature(256); 788 aFeature.append( "[{\n" ); 789 if( bUseIncluseFeature ) 790 aFeature.append( "%%IncludeFeature:" ); 791 else 792 aFeature.append( "%%BeginFeature:" ); 793 aFeature.append( " *" ); 794 aFeature.append( OUStringToOString( pKey->getKey(), RTL_TEXTENCODING_ASCII_US ) ); 795 aFeature.append( ' ' ); 796 aFeature.append( OUStringToOString( pValue->m_aOption, RTL_TEXTENCODING_ASCII_US ) ); 797 if( !bUseIncluseFeature ) 798 { 799 aFeature.append( '\n' ); 800 aFeature.append( OUStringToOString( pValue->m_aValue, RTL_TEXTENCODING_ASCII_US ) ); 801 aFeature.append( "\n%%EndFeature" ); 802 } 803 aFeature.append( "\n} stopped cleartomark\n" ); 804 sal_uInt64 nWritten = 0; 805 return pFile->write( aFeature.getStr(), aFeature.getLength(), nWritten ) 806 || nWritten != (sal_uInt64)aFeature.getLength() ? false : true; 807 } 808 809 bool PrinterJob::writeFeatureList( osl::File* pFile, const JobData& rJob, bool bDocumentSetup ) 810 { 811 bool bSuccess = true; 812 int i; 813 814 // emit features ordered to OrderDependency 815 // ignore features that are set to default 816 817 // sanity check 818 if( rJob.m_pParser == rJob.m_aContext.getParser() && 819 rJob.m_pParser && 820 ( m_aLastJobData.m_pParser == rJob.m_pParser || m_aLastJobData.m_pParser == NULL ) 821 ) 822 { 823 int nKeys = rJob.m_aContext.countValuesModified(); 824 ::std::vector< const PPDKey* > aKeys( nKeys ); 825 for( i = 0; i < nKeys; i++ ) 826 aKeys[i] = rJob.m_aContext.getModifiedKey( i ); 827 ::std::sort( aKeys.begin(), aKeys.end(), less_ppd_key() ); 828 829 for( i = 0; i < nKeys && bSuccess; i++ ) 830 { 831 const PPDKey* pKey = aKeys[i]; 832 bool bEmit = false; 833 if( bDocumentSetup ) 834 { 835 if( pKey->getSetupType() == PPDKey::DocumentSetup ) 836 bEmit = true; 837 } 838 if( pKey->getSetupType() == PPDKey::PageSetup || 839 pKey->getSetupType() == PPDKey::AnySetup ) 840 bEmit = true; 841 if( bEmit ) 842 { 843 const PPDValue* pValue = rJob.m_aContext.getValue( pKey ); 844 if( pValue 845 && pValue->m_eType == eInvocation 846 && ( m_aLastJobData.m_pParser == NULL 847 || m_aLastJobData.m_aContext.getValue( pKey ) != pValue 848 || bDocumentSetup 849 ) 850 ) 851 { 852 // try to avoid PS level 2 feature commands if level is set to 1 853 if( GetPostscriptLevel( &rJob ) == 1 ) 854 { 855 bool bHavePS2 = 856 ( pValue->m_aValue.SearchAscii( "<<" ) != STRING_NOTFOUND ) 857 || 858 ( pValue->m_aValue.SearchAscii( ">>" ) != STRING_NOTFOUND ); 859 if( bHavePS2 ) 860 continue; 861 } 862 bSuccess = writeFeature( pFile, pKey, pValue, PrinterInfoManager::get().getUseIncludeFeature() ); 863 } 864 } 865 } 866 } 867 else 868 bSuccess = false; 869 870 return bSuccess; 871 } 872 873 bool PrinterJob::writePageSetup( osl::File* pFile, const JobData& rJob, bool bWriteFeatures ) 874 { 875 bool bSuccess = true; 876 877 WritePS (pFile, "%%BeginPageSetup\n%\n"); 878 if ( bWriteFeatures ) 879 bSuccess = writeFeatureList( pFile, rJob, false ); 880 WritePS (pFile, "%%EndPageSetup\n"); 881 882 sal_Char pTranslate [128]; 883 sal_Int32 nChar = 0; 884 885 if( rJob.m_eOrientation == orientation::Portrait ) 886 { 887 nChar = psp::appendStr ("gsave\n[", pTranslate); 888 nChar += psp::getValueOfDouble ( pTranslate + nChar, mfXScale, 5); 889 nChar += psp::appendStr (" 0 0 ", pTranslate + nChar); 890 nChar += psp::getValueOfDouble ( pTranslate + nChar, mfYScale, 5); 891 nChar += psp::appendStr (" ", pTranslate + nChar); 892 nChar += psp::getValueOf (mnRMarginPt, pTranslate + nChar); 893 nChar += psp::appendStr (" ", pTranslate + nChar); 894 nChar += psp::getValueOf (mnHeightPt-mnTMarginPt, 895 pTranslate + nChar); 896 nChar += psp::appendStr ("] concat\ngsave\n", 897 pTranslate + nChar); 898 } 899 else 900 { 901 nChar = psp::appendStr ("gsave\n", pTranslate); 902 nChar += psp::appendStr ("[ 0 ", pTranslate + nChar); 903 nChar += psp::getValueOfDouble ( pTranslate + nChar, -mfYScale, 5); 904 nChar += psp::appendStr (" ", pTranslate + nChar); 905 nChar += psp::getValueOfDouble ( pTranslate + nChar, mfXScale, 5); 906 nChar += psp::appendStr (" 0 ", pTranslate + nChar ); 907 nChar += psp::getValueOfDouble ( pTranslate + nChar, mnLMarginPt, 5 ); 908 nChar += psp::appendStr (" ", pTranslate + nChar); 909 nChar += psp::getValueOf (mnBMarginPt, pTranslate + nChar ); 910 nChar += psp::appendStr ("] concat\ngsave\n", 911 pTranslate + nChar); 912 } 913 914 WritePS (pFile, pTranslate); 915 916 return bSuccess; 917 } 918 919 void PrinterJob::writeJobPatch( osl::File* pFile, const JobData& rJobData ) 920 { 921 if( ! PrinterInfoManager::get().getUseJobPatch() ) 922 return; 923 924 const PPDKey* pKey = NULL; 925 926 if( rJobData.m_pParser ) 927 pKey = rJobData.m_pParser->getKey( OUString( RTL_CONSTASCII_USTRINGPARAM( "JobPatchFile" ) ) ); 928 if( ! pKey ) 929 return; 930 931 // order the patch files 932 // according to PPD spec the JobPatchFile options must be int 933 // and should be emitted in order 934 std::list< sal_Int32 > patch_order; 935 int nValueCount = pKey->countValues(); 936 for( int i = 0; i < nValueCount; i++ ) 937 { 938 const PPDValue* pVal = pKey->getValue( i ); 939 patch_order.push_back( pVal->m_aOption.ToInt32() ); 940 if( patch_order.back() == 0 && ! pVal->m_aOption.EqualsAscii( "0" ) ) 941 { 942 WritePS( pFile, "% Warning: left out JobPatchFile option \"" ); 943 OString aOption = OUStringToOString( pVal->m_aOption, RTL_TEXTENCODING_ASCII_US ); 944 WritePS( pFile, aOption.getStr() ); 945 WritePS( pFile, 946 "\"\n% as it violates the PPD spec;\n" 947 "% JobPatchFile options need to be numbered for ordering.\n" ); 948 } 949 } 950 951 patch_order.sort(); 952 patch_order.unique(); 953 954 while( patch_order.begin() != patch_order.end() ) 955 { 956 // note: this discards patch files not adhering to the "int" scheme 957 // as there won't be a value for them 958 writeFeature( pFile, pKey, pKey->getValue( OUString::valueOf( patch_order.front() ) ), false ); 959 patch_order.pop_front(); 960 } 961 } 962 963 bool PrinterJob::writeProlog (osl::File* pFile, const JobData& rJobData ) 964 { 965 WritePS( pFile, "%%BeginProlog\n" ); 966 967 // JobPatchFile feature needs to be emitted at begin of prolog 968 writeJobPatch( pFile, rJobData ); 969 970 static const sal_Char pProlog[] = { 971 "%%BeginResource: procset PSPrint-Prolog 1.0 0\n" 972 "/ISO1252Encoding [\n" 973 "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n" 974 "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n" 975 "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n" 976 "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n" 977 "/space /exclam /quotedbl /numbersign /dollar /percent /ampersand /quotesingle\n" 978 "/parenleft /parenright /asterisk /plus /comma /hyphen /period /slash\n" 979 "/zero /one /two /three /four /five /six /seven\n" 980 "/eight /nine /colon /semicolon /less /equal /greater /question\n" 981 "/at /A /B /C /D /E /F /G\n" 982 "/H /I /J /K /L /M /N /O\n" 983 "/P /Q /R /S /T /U /V /W\n" 984 "/X /Y /Z /bracketleft /backslash /bracketright /asciicircum /underscore\n" 985 "/grave /a /b /c /d /e /f /g\n" 986 "/h /i /j /k /l /m /n /o\n" 987 "/p /q /r /s /t /u /v /w\n" 988 "/x /y /z /braceleft /bar /braceright /asciitilde /unused\n" 989 "/Euro /unused /quotesinglbase /florin /quotedblbase /ellipsis /dagger /daggerdbl\n" 990 "/circumflex /perthousand /Scaron /guilsinglleft /OE /unused /Zcaron /unused\n" 991 "/unused /quoteleft /quoteright /quotedblleft /quotedblright /bullet /endash /emdash\n" 992 "/tilde /trademark /scaron /guilsinglright /oe /unused /zcaron /Ydieresis\n" 993 "/space /exclamdown /cent /sterling /currency /yen /brokenbar /section\n" 994 "/dieresis /copyright /ordfeminine /guillemotleft /logicalnot /hyphen /registered /macron\n" 995 "/degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph /periodcentered\n" 996 "/cedilla /onesuperior /ordmasculine /guillemotright /onequarter /onehalf /threequarters /questiondown\n" 997 "/Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla\n" 998 "/Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis\n" 999 "/Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply\n" 1000 "/Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls\n" 1001 "/agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla\n" 1002 "/egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis\n" 1003 "/eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide\n" 1004 "/oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis] def\n" 1005 "\n" 1006 "/psp_definefont { exch dup findfont dup length dict begin { 1 index /FID ne\n" 1007 "{ def } { pop pop } ifelse } forall /Encoding 3 -1 roll def\n" 1008 "currentdict end exch pop definefont pop } def\n" 1009 "\n" 1010 "/pathdict dup 8 dict def load begin\n" 1011 "/rcmd { { currentfile 1 string readstring pop 0 get dup 32 gt { exit }\n" 1012 "{ pop } ifelse } loop dup 126 eq { pop exit } if 65 sub dup 16#3 and 1\n" 1013 "add exch dup 16#C and -2 bitshift 16#3 and 1 add exch 16#10 and 16#10\n" 1014 "eq 3 1 roll exch } def\n" 1015 "/rhex { dup 1 sub exch currentfile exch string readhexstring pop dup 0\n" 1016 "get dup 16#80 and 16#80 eq dup 3 1 roll { 16#7f and } if 2 index 0 3\n" 1017 "-1 roll put 3 1 roll 0 0 1 5 -1 roll { 2 index exch get add 256 mul }\n" 1018 "for 256 div exch pop exch { neg } if } def\n" 1019 "/xcmd { rcmd exch rhex exch rhex exch 5 -1 roll add exch 4 -1 roll add\n" 1020 "1 index 1 index 5 -1 roll { moveto } { lineto } ifelse } def end\n" 1021 "/readpath { 0 0 pathdict begin { xcmd } loop end pop pop } def\n" 1022 "\n" 1023 "systemdict /languagelevel known not {\n" 1024 "/xshow { exch dup length 0 1 3 -1 roll 1 sub { dup 3 index exch get\n" 1025 "exch 2 index exch get 1 string dup 0 4 -1 roll put currentpoint 3 -1\n" 1026 "roll show moveto 0 rmoveto } for pop pop } def\n" 1027 "/rectangle { 4 -2 roll moveto 1 index 0 rlineto 0 exch rlineto neg 0\n" 1028 "rlineto closepath } def\n" 1029 "/rectfill { rectangle fill } def\n" 1030 "/rectstroke { rectangle stroke } def } if\n" 1031 "/bshow { currentlinewidth 3 1 roll currentpoint 3 index show moveto\n" 1032 "setlinewidth false charpath stroke setlinewidth } def\n" 1033 "/bxshow { currentlinewidth 4 1 roll setlinewidth exch dup length 1 sub\n" 1034 "0 1 3 -1 roll { 1 string 2 index 2 index get 1 index exch 0 exch put dup\n" 1035 "currentpoint 3 -1 roll show moveto currentpoint 3 -1 roll false charpath\n" 1036 "stroke moveto 2 index exch get 0 rmoveto } for pop pop setlinewidth } def\n" 1037 "\n" 1038 "/psp_lzwfilter { currentfile /ASCII85Decode filter /LZWDecode filter } def\n" 1039 "/psp_ascii85filter { currentfile /ASCII85Decode filter } def\n" 1040 "/psp_lzwstring { psp_lzwfilter 1024 string readstring } def\n" 1041 "/psp_ascii85string { psp_ascii85filter 1024 string readstring } def\n" 1042 "/psp_imagedict {\n" 1043 "/psp_bitspercomponent { 3 eq { 1 }{ 8 } ifelse } def\n" 1044 "/psp_decodearray { [ [0 1 0 1 0 1] [0 255] [0 1] [0 255] ] exch get }\n" 1045 "def 7 dict dup\n" 1046 "/ImageType 1 put dup\n" 1047 "/Width 7 -1 roll put dup\n" 1048 "/Height 5 index put dup\n" 1049 "/BitsPerComponent 4 index psp_bitspercomponent put dup\n" 1050 "/Decode 5 -1 roll psp_decodearray put dup\n" 1051 "/ImageMatrix [1 0 0 1 0 0] dup 5 8 -1 roll put put dup\n" 1052 "/DataSource 4 -1 roll 1 eq { psp_lzwfilter } { psp_ascii85filter } ifelse put\n" 1053 "} def\n" 1054 "%%EndResource\n" 1055 "%%EndProlog\n" 1056 }; 1057 static const sal_Char pSO52CompatProlog[] = { 1058 "%%BeginResource: procset PSPrint-Prolog 1.0 0\n" 1059 "/ISO1252Encoding [\n" 1060 "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n" 1061 "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n" 1062 "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n" 1063 "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n" 1064 "/space /exclam /quotedbl /numbersign /dollar /percent /ampersand /quoteright\n" 1065 "/parenleft /parenright /asterisk /plus /comma /minus /period /slash\n" 1066 "/zero /one /two /three /four /five /six /seven\n" 1067 "/eight /nine /colon /semicolon /less /equal /greater /question\n" 1068 "/at /A /B /C /D /E /F /G\n" 1069 "/H /I /J /K /L /M /N /O\n" 1070 "/P /Q /R /S /T /U /V /W\n" 1071 "/X /Y /Z /bracketleft /backslash /bracketright /asciicircum /underscore\n" 1072 "/grave /a /b /c /d /e /f /g\n" 1073 "/h /i /j /k /l /m /n /o\n" 1074 "/p /q /r /s /t /u /v /w\n" 1075 "/x /y /z /braceleft /bar /braceright /asciitilde /unused\n" 1076 "/Euro /unused /quotesinglbase /florin /quotedblbase /ellipsis /dagger /daggerdbl\n" 1077 "/circumflex /perthousand /Scaron /guilsinglleft /OE /unused /Zcaron /unused\n" 1078 "/unused /quoteleft /quoteright /quotedblleft /quotedblright /bullet /endash /emdash\n" 1079 "/tilde /trademark /scaron /guilsinglright /oe /unused /zcaron /Ydieresis\n" 1080 "/space /exclamdown /cent /sterling /currency /yen /brokenbar /section\n" 1081 "/dieresis /copyright /ordfeminine /guillemotleft /logicalnot /hyphen /registered /macron\n" 1082 "/degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph /periodcentered\n" 1083 "/cedilla /onesuperior /ordmasculine /guillemotright /onequarter /onehalf /threequarters /questiondown\n" 1084 "/Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla\n" 1085 "/Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis\n" 1086 "/Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply\n" 1087 "/Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls\n" 1088 "/agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla\n" 1089 "/egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis\n" 1090 "/eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide\n" 1091 "/oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis] def\n" 1092 "\n" 1093 "/psp_definefont { exch dup findfont dup length dict begin { 1 index /FID ne\n" 1094 "{ def } { pop pop } ifelse } forall /Encoding 3 -1 roll def\n" 1095 "currentdict end exch pop definefont pop } def\n" 1096 "\n" 1097 "/pathdict dup 8 dict def load begin\n" 1098 "/rcmd { { currentfile 1 string readstring pop 0 get dup 32 gt { exit }\n" 1099 "{ pop } ifelse } loop dup 126 eq { pop exit } if 65 sub dup 16#3 and 1\n" 1100 "add exch dup 16#C and -2 bitshift 16#3 and 1 add exch 16#10 and 16#10\n" 1101 "eq 3 1 roll exch } def\n" 1102 "/rhex { dup 1 sub exch currentfile exch string readhexstring pop dup 0\n" 1103 "get dup 16#80 and 16#80 eq dup 3 1 roll { 16#7f and } if 2 index 0 3\n" 1104 "-1 roll put 3 1 roll 0 0 1 5 -1 roll { 2 index exch get add 256 mul }\n" 1105 "for 256 div exch pop exch { neg } if } def\n" 1106 "/xcmd { rcmd exch rhex exch rhex exch 5 -1 roll add exch 4 -1 roll add\n" 1107 "1 index 1 index 5 -1 roll { moveto } { lineto } ifelse } def end\n" 1108 "/readpath { 0 0 pathdict begin { xcmd } loop end pop pop } def\n" 1109 "\n" 1110 "systemdict /languagelevel known not {\n" 1111 "/xshow { exch dup length 0 1 3 -1 roll 1 sub { dup 3 index exch get\n" 1112 "exch 2 index exch get 1 string dup 0 4 -1 roll put currentpoint 3 -1\n" 1113 "roll show moveto 0 rmoveto } for pop pop } def\n" 1114 "/rectangle { 4 -2 roll moveto 1 index 0 rlineto 0 exch rlineto neg 0\n" 1115 "rlineto closepath } def\n" 1116 "/rectfill { rectangle fill } def\n" 1117 "/rectstroke { rectangle stroke } def } if\n" 1118 "/bshow { currentlinewidth 3 1 roll currentpoint 3 index show moveto\n" 1119 "setlinewidth false charpath stroke setlinewidth } def\n" 1120 "/bxshow { currentlinewidth 4 1 roll setlinewidth exch dup length 1 sub\n" 1121 "0 1 3 -1 roll { 1 string 2 index 2 index get 1 index exch 0 exch put dup\n" 1122 "currentpoint 3 -1 roll show moveto currentpoint 3 -1 roll false charpath\n" 1123 "stroke moveto 2 index exch get 0 rmoveto } for pop pop setlinewidth } def\n" 1124 "\n" 1125 "/psp_lzwfilter { currentfile /ASCII85Decode filter /LZWDecode filter } def\n" 1126 "/psp_ascii85filter { currentfile /ASCII85Decode filter } def\n" 1127 "/psp_lzwstring { psp_lzwfilter 1024 string readstring } def\n" 1128 "/psp_ascii85string { psp_ascii85filter 1024 string readstring } def\n" 1129 "/psp_imagedict {\n" 1130 "/psp_bitspercomponent { 3 eq { 1 }{ 8 } ifelse } def\n" 1131 "/psp_decodearray { [ [0 1 0 1 0 1] [0 255] [0 1] [0 255] ] exch get }\n" 1132 "def 7 dict dup\n" 1133 "/ImageType 1 put dup\n" 1134 "/Width 7 -1 roll put dup\n" 1135 "/Height 5 index put dup\n" 1136 "/BitsPerComponent 4 index psp_bitspercomponent put dup\n" 1137 "/Decode 5 -1 roll psp_decodearray put dup\n" 1138 "/ImageMatrix [1 0 0 1 0 0] dup 5 8 -1 roll put put dup\n" 1139 "/DataSource 4 -1 roll 1 eq { psp_lzwfilter } { psp_ascii85filter } ifelse put\n" 1140 "} def\n" 1141 "%%EndResource\n" 1142 "%%EndProlog\n" 1143 }; 1144 WritePS (pFile, m_pGraphics && m_pGraphics->getStrictSO52Compatibility() ? pSO52CompatProlog : pProlog); 1145 1146 return true; 1147 } 1148 1149 bool PrinterJob::writeSetup( osl::File* pFile, const JobData& rJob ) 1150 { 1151 WritePS (pFile, "%%BeginSetup\n%\n"); 1152 1153 // download fonts 1154 std::list< rtl::OString > aFonts[2]; 1155 m_pGraphics->writeResources( pFile, aFonts[0], aFonts[1] ); 1156 1157 for( int i = 0; i < 2; i++ ) 1158 { 1159 if( !aFonts[i].empty() ) 1160 { 1161 std::list< rtl::OString >::const_iterator it = aFonts[i].begin(); 1162 rtl::OStringBuffer aLine( 256 ); 1163 if( i == 0 ) 1164 aLine.append( "%%DocumentSuppliedResources: font " ); 1165 else 1166 aLine.append( "%%DocumentNeededResources: font " ); 1167 aLine.append( *it ); 1168 aLine.append( "\n" ); 1169 WritePS ( pFile, aLine.getStr() ); 1170 while( (++it) != aFonts[i].end() ) 1171 { 1172 aLine.setLength(0); 1173 aLine.append( "%%+ font " ); 1174 aLine.append( *it ); 1175 aLine.append( "\n" ); 1176 WritePS ( pFile, aLine.getStr() ); 1177 } 1178 } 1179 } 1180 1181 bool bSuccess = true; 1182 // in case of external print dialog the number of copies is prepended 1183 // to the job, let us not complicate things by emitting our own copy count 1184 bool bExternalDialog = PrinterInfoManager::get().checkFeatureToken( GetPrinterName(), "external_dialog" ); 1185 if( ! bExternalDialog && rJob.m_nCopies > 1 ) 1186 { 1187 // setup code 1188 ByteString aLine( "/#copies " ); 1189 aLine += ByteString::CreateFromInt32( rJob.m_nCopies ); 1190 aLine += " def\n"; 1191 sal_uInt64 nWritten = 0; 1192 bSuccess = pFile->write( aLine.GetBuffer(), aLine.Len(), nWritten ) 1193 || nWritten != aLine.Len() ? false : true; 1194 1195 if( bSuccess && GetPostscriptLevel( &rJob ) >= 2 ) 1196 WritePS (pFile, "<< /NumCopies null /Policies << /NumCopies 1 >> >> setpagedevice\n" ); 1197 } 1198 1199 bool bFeatureSuccess = writeFeatureList( pFile, rJob, true ); 1200 1201 WritePS (pFile, "%%EndSetup\n"); 1202 1203 return bSuccess && bFeatureSuccess; 1204 } 1205