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