update dev300-m58
[ooovba.git] / vcl / source / gdi / impprn.cxx
blob97226a3300023e61ef035f614792bb715daa06c6
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: impprn.cxx,v $
10 * $Revision: 1.18.86.3 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_vcl.hxx"
34 #define _SPOOLPRINTER_EXT
35 #include "tools/queue.hxx"
36 #include "vcl/svapp.hxx"
37 #include "vcl/metaact.hxx"
38 #include "vcl/gdimtf.hxx"
39 #include "vcl/timer.hxx"
40 #include "vcl/impprn.hxx"
41 #include "vcl/jobset.h"
43 #include "vcl/svdata.hxx"
44 #include "vcl/salprn.hxx"
46 // -----------
47 // - Defines -
48 // -----------
50 #define OPTIMAL_BMP_RESOLUTION 300
51 #define NORMAL_BMP_RESOLUTION 200
53 // =======================================================================
55 struct QueuePage
57 GDIMetaFile* mpMtf;
58 JobSetup* mpSetup;
59 USHORT mnPage;
60 BOOL mbEndJob;
62 QueuePage() { mpMtf = NULL; mpSetup = NULL; }
63 ~QueuePage() { delete mpMtf; if ( mpSetup ) delete mpSetup; }
66 // =======================================================================
68 ImplQPrinter::ImplQPrinter( Printer* pParent ) :
69 Printer( pParent->GetName() ),
70 mpParent( pParent ),
71 mbAborted( false ),
72 mbUserCopy( false ),
73 mbDestroyAllowed( true ),
74 mbDestroyed( false ),
75 mnMaxBmpDPIX( mnDPIX ),
76 mnMaxBmpDPIY( mnDPIY ),
77 mnCurCopyCount( 0 )
79 SetSelfAsQueuePrinter( TRUE );
80 SetPrinterProps( pParent );
81 SetPageQueueSize( 0 );
82 mnCopyCount = pParent->mnCopyCount;
83 mbCollateCopy = pParent->mbCollateCopy;
86 // -----------------------------------------------------------------------
88 ImplQPrinter::~ImplQPrinter()
90 for( std::vector< QueuePage* >::iterator it = maQueue.begin();
91 it != maQueue.end(); ++it )
92 delete (*it);
95 // -----------------------------------------------------------------------------
97 void ImplQPrinter::Destroy()
99 if( mbDestroyAllowed )
100 delete this;
101 else
102 mbDestroyed = TRUE;
105 // -----------------------------------------------------------------------
107 void ImplQPrinter::ImplPrintMtf( GDIMetaFile& rPrtMtf, long nMaxBmpDPIX, long nMaxBmpDPIY )
109 for( MetaAction* pAct = rPrtMtf.FirstAction(); pAct && !mbAborted; pAct = rPrtMtf.NextAction() )
111 const ULONG nType = pAct->GetType();
112 sal_Bool bExecuted = sal_False;
114 if( nType == META_COMMENT_ACTION )
116 // search for special comments ( ..._BEGIN/..._END )
117 MetaCommentAction* pComment = (MetaCommentAction*) pAct;
119 if( pComment->GetComment().CompareIgnoreCaseToAscii( "XGRAD_SEQ_BEGIN" ) == COMPARE_EQUAL )
121 pAct = rPrtMtf.NextAction();
123 // if next action is a GradientEx action, execute this and
124 // skip actions until a XGRAD_SEQ_END comment is found
125 if( pAct && ( pAct->GetType() == META_GRADIENTEX_ACTION ) )
127 MetaGradientExAction* pGradientExAction = (MetaGradientExAction*) pAct;
128 DrawGradientEx( this, pGradientExAction->GetPolyPolygon(), pGradientExAction->GetGradient() );
130 // seek to end of this comment
133 pAct = rPrtMtf.NextAction();
135 while( pAct &&
136 ( ( pAct->GetType() != META_COMMENT_ACTION ) ||
137 ( ( (MetaCommentAction*) pAct )->GetComment().CompareIgnoreCaseToAscii( "XGRAD_SEQ_END" ) != COMPARE_EQUAL ) ) );
139 bExecuted = sal_True;
142 else if( pComment->GetComment().CompareIgnoreCaseToAscii( "PRNSPOOL_TRANSPARENTBITMAP_BEGIN" ) == COMPARE_EQUAL )
144 pAct = rPrtMtf.NextAction();
146 if( pAct && ( pAct->GetType() == META_BMPSCALE_ACTION ) )
148 // execute action here to avoid DPI processing of bitmap;
149 pAct->Execute( this );
151 #ifdef VERBOSE_DEBUG
152 Push();
153 SetLineColor(COL_RED);
154 SetFillColor();
155 DrawRect( Rectangle(
156 static_cast<MetaBmpScaleAction*>(pAct)->GetPoint(),
157 static_cast<MetaBmpScaleAction*>(pAct)->GetSize()) );
158 Pop();
159 #endif
161 // seek to end of this comment
164 pAct = rPrtMtf.NextAction();
166 while( pAct &&
167 ( ( pAct->GetType() != META_COMMENT_ACTION ) ||
168 ( ( (MetaCommentAction*) pAct )->GetComment().CompareIgnoreCaseToAscii( "PRNSPOOL_TRANSPARENTBITMAP_END" ) != COMPARE_EQUAL ) ) );
170 bExecuted = sal_True;
174 else if( nType == META_GRADIENT_ACTION )
176 MetaGradientAction* pGradientAction = (MetaGradientAction*) pAct;
177 DrawGradientEx( this, pGradientAction->GetRect(), pGradientAction->GetGradient() );
178 bExecuted = sal_True;
180 else if( nType == META_BMPSCALE_ACTION )
182 MetaBmpScaleAction* pBmpScaleAction = (MetaBmpScaleAction*) pAct;
183 const Bitmap& rBmp = pBmpScaleAction->GetBitmap();
185 DrawBitmap( pBmpScaleAction->GetPoint(), pBmpScaleAction->GetSize(),
186 GetDownsampledBitmap( pBmpScaleAction->GetSize(),
187 Point(), rBmp.GetSizePixel(),
188 rBmp, nMaxBmpDPIX, nMaxBmpDPIY ) );
190 bExecuted = sal_True;
192 else if( nType == META_BMPSCALEPART_ACTION )
194 MetaBmpScalePartAction* pBmpScalePartAction = (MetaBmpScalePartAction*) pAct;
195 const Bitmap& rBmp = pBmpScalePartAction->GetBitmap();
197 DrawBitmap( pBmpScalePartAction->GetDestPoint(), pBmpScalePartAction->GetDestSize(),
198 GetDownsampledBitmap( pBmpScalePartAction->GetDestSize(),
199 pBmpScalePartAction->GetSrcPoint(), pBmpScalePartAction->GetSrcSize(),
200 rBmp, nMaxBmpDPIX, nMaxBmpDPIY ) );
202 bExecuted = sal_True;
204 else if( nType == META_BMPEXSCALE_ACTION )
206 MetaBmpExScaleAction* pBmpExScaleAction = (MetaBmpExScaleAction*) pAct;
207 const BitmapEx& rBmpEx = pBmpExScaleAction->GetBitmapEx();
209 DrawBitmapEx( pBmpExScaleAction->GetPoint(), pBmpExScaleAction->GetSize(),
210 GetDownsampledBitmapEx( pBmpExScaleAction->GetSize(),
211 Point(), rBmpEx.GetSizePixel(),
212 rBmpEx, nMaxBmpDPIX, nMaxBmpDPIY ) );
214 bExecuted = sal_True;
216 else if( nType == META_BMPEXSCALEPART_ACTION )
218 MetaBmpExScalePartAction* pBmpExScalePartAction = (MetaBmpExScalePartAction*) pAct;
219 const BitmapEx& rBmpEx = pBmpExScalePartAction->GetBitmapEx();
221 DrawBitmapEx( pBmpExScalePartAction->GetDestPoint(), pBmpExScalePartAction->GetDestSize(),
222 GetDownsampledBitmapEx( pBmpExScalePartAction->GetDestSize(),
223 pBmpExScalePartAction->GetSrcPoint(), pBmpExScalePartAction->GetSrcSize(),
224 rBmpEx, nMaxBmpDPIX, nMaxBmpDPIY ) );
226 bExecuted = sal_True;
228 else if( nType == META_TRANSPARENT_ACTION )
230 MetaTransparentAction* pTransAct = static_cast<MetaTransparentAction*>(pAct);
231 USHORT nTransparency( pTransAct->GetTransparence() );
233 // #i10613# Respect transparency for draw color
234 if( nTransparency )
236 Push( PUSH_LINECOLOR|PUSH_FILLCOLOR );
238 // assume white background for alpha blending
239 Color aLineColor( GetLineColor() );
240 aLineColor.SetRed( static_cast<UINT8>( (255L*nTransparency + (100L - nTransparency)*aLineColor.GetRed()) / 100L ) );
241 aLineColor.SetGreen( static_cast<UINT8>( (255L*nTransparency + (100L - nTransparency)*aLineColor.GetGreen()) / 100L ) );
242 aLineColor.SetBlue( static_cast<UINT8>( (255L*nTransparency + (100L - nTransparency)*aLineColor.GetBlue()) / 100L ) );
243 SetLineColor( aLineColor );
245 Color aFillColor( GetFillColor() );
246 aFillColor.SetRed( static_cast<UINT8>( (255L*nTransparency + (100L - nTransparency)*aFillColor.GetRed()) / 100L ) );
247 aFillColor.SetGreen( static_cast<UINT8>( (255L*nTransparency + (100L - nTransparency)*aFillColor.GetGreen()) / 100L ) );
248 aFillColor.SetBlue( static_cast<UINT8>( (255L*nTransparency + (100L - nTransparency)*aFillColor.GetBlue()) / 100L ) );
249 SetFillColor( aFillColor );
252 DrawPolyPolygon( pTransAct->GetPolyPolygon() );
254 if( nTransparency )
255 Pop();
257 bExecuted = sal_True;
259 else if( nType == META_FLOATTRANSPARENT_ACTION )
261 MetaFloatTransparentAction* pFloatAction = (MetaFloatTransparentAction*) pAct;
262 GDIMetaFile& rMtf = (GDIMetaFile&) pFloatAction->GetGDIMetaFile();
263 MapMode aDrawMap( rMtf.GetPrefMapMode() );
264 Point aDestPoint( LogicToPixel( pFloatAction->GetPoint() ) );
265 Size aDestSize( LogicToPixel( pFloatAction->GetSize() ) );
267 if( aDestSize.Width() && aDestSize.Height() )
269 Size aTmpPrefSize( LogicToPixel( rMtf.GetPrefSize(), aDrawMap ) );
271 if( !aTmpPrefSize.Width() )
272 aTmpPrefSize.Width() = aDestSize.Width();
274 if( !aTmpPrefSize.Height() )
275 aTmpPrefSize.Height() = aDestSize.Height();
277 Fraction aScaleX( aDestSize.Width(), aTmpPrefSize.Width() );
278 Fraction aScaleY( aDestSize.Height(), aTmpPrefSize.Height() );
280 aDrawMap.SetScaleX( aScaleX *= aDrawMap.GetScaleX() );
281 aDrawMap.SetScaleY( aScaleY *= aDrawMap.GetScaleY() );
282 aDrawMap.SetOrigin( PixelToLogic( aDestPoint, aDrawMap ) );
284 Push();
285 SetMapMode( aDrawMap );
286 ImplPrintMtf( rMtf, nMaxBmpDPIX, nMaxBmpDPIY );
287 Pop();
290 bExecuted = sal_True;
293 if( !bExecuted && pAct )
294 pAct->Execute( this );
296 if( ! ImplGetSVData()->maGDIData.mbPrinterPullModel )
297 Application::Reschedule();
301 // -----------------------------------------------------------------------
303 void ImplQPrinter::PrePrintPage( QueuePage* pPage )
305 mnRestoreDrawMode = GetDrawMode();
306 mnMaxBmpDPIX = mnDPIX;
307 mnMaxBmpDPIY = mnDPIY;
309 const PrinterOptions& rPrinterOptions = GetPrinterOptions();
311 if( rPrinterOptions.IsReduceBitmaps() )
313 // calculate maximum resolution for bitmap graphics
314 if( PRINTER_BITMAP_OPTIMAL == rPrinterOptions.GetReducedBitmapMode() )
316 mnMaxBmpDPIX = Min( (long) OPTIMAL_BMP_RESOLUTION, mnMaxBmpDPIX );
317 mnMaxBmpDPIY = Min( (long) OPTIMAL_BMP_RESOLUTION, mnMaxBmpDPIY );
319 else if( PRINTER_BITMAP_NORMAL == rPrinterOptions.GetReducedBitmapMode() )
321 mnMaxBmpDPIX = Min( (long) NORMAL_BMP_RESOLUTION, mnMaxBmpDPIX );
322 mnMaxBmpDPIY = Min( (long) NORMAL_BMP_RESOLUTION, mnMaxBmpDPIY );
324 else
326 mnMaxBmpDPIX = Min( (long) rPrinterOptions.GetReducedBitmapResolution(), mnMaxBmpDPIX );
327 mnMaxBmpDPIY = Min( (long) rPrinterOptions.GetReducedBitmapResolution(), mnMaxBmpDPIY );
331 // convert to greysacles
332 if( rPrinterOptions.IsConvertToGreyscales() )
334 SetDrawMode( GetDrawMode() | ( DRAWMODE_GRAYLINE | DRAWMODE_GRAYFILL | DRAWMODE_GRAYTEXT |
335 DRAWMODE_GRAYBITMAP | DRAWMODE_GRAYGRADIENT ) );
338 // disable transparency output
339 if( rPrinterOptions.IsReduceTransparency() && ( PRINTER_TRANSPARENCY_NONE == rPrinterOptions.GetReducedTransparencyMode() ) )
341 SetDrawMode( GetDrawMode() | DRAWMODE_NOTRANSPARENCY );
344 maCurPageMetaFile = GDIMetaFile();
345 RemoveTransparenciesFromMetaFile( *pPage->mpMtf, maCurPageMetaFile, mnMaxBmpDPIX, mnMaxBmpDPIY,
346 rPrinterOptions.IsReduceTransparency(),
347 rPrinterOptions.GetReducedTransparencyMode() == PRINTER_TRANSPARENCY_AUTO,
348 rPrinterOptions.IsReduceBitmaps() && rPrinterOptions.IsReducedBitmapIncludesTransparency()
352 void ImplQPrinter::PostPrintPage()
354 SetDrawMode( mnRestoreDrawMode );
357 // -----------------------------------------------------------------------
359 void ImplQPrinter::PrintPage( unsigned int nPage )
361 if( nPage >= maQueue.size() )
362 return;
363 mnCurCopyCount = (mbUserCopy && !mbCollateCopy) ? mnCopyCount : 1;
364 QueuePage* pActPage = maQueue[nPage];
365 PrePrintPage( pActPage );
366 if ( pActPage->mpSetup )
367 SetJobSetup( *pActPage->mpSetup );
369 StartPage();
370 ImplPrintMtf( maCurPageMetaFile, mnMaxBmpDPIX, mnMaxBmpDPIY );
371 EndPage();
373 mnCurCopyCount--;
374 if( mnCurCopyCount == 0 )
375 PostPrintPage();
378 // -----------------------------------------------------------------------
380 ImplJobSetup* ImplQPrinter::GetPageSetup( unsigned int nPage ) const
382 return nPage >= maQueue.size() ? NULL :
383 ( maQueue[nPage]->mpSetup ? maQueue[nPage]->mpSetup->ImplGetData() : NULL );
386 // -----------------------------------------------------------------------
387 ULONG ImplQPrinter::GetPrintPageCount() const
389 ULONG nPageCount = maQueue.size() * ((mbUserCopy && !mbCollateCopy) ? mnCopyCount : 1);
390 return nPageCount;
393 // -----------------------------------------------------------------------
395 IMPL_LINK( ImplQPrinter, ImplPrintHdl, Timer*, EMPTYARG )
397 // Ist Drucken abgebrochen wurden?
398 if( !IsPrinting() || ( mpParent->IsJobActive() && ( maQueue.size() < (ULONG)mpParent->GetPageQueueSize() ) ) )
399 return 0;
401 // Druck-Job zuende?
402 QueuePage* pActPage = maQueue.front();
403 maQueue.erase( maQueue.begin() );
406 vcl::DeletionListener aDel( this );
407 if ( pActPage->mbEndJob )
409 maTimer.Stop();
410 delete pActPage;
411 if( ! EndJob() )
412 mpParent->Error();
413 if( ! aDel.isDeleted() )
414 mpParent->ImplEndPrint();
416 else
418 mbDestroyAllowed = FALSE;
420 PrePrintPage( pActPage );
422 USHORT nCopyCount = 1;
423 if( mbUserCopy && !mbCollateCopy )
424 nCopyCount = mnCopyCount;
426 for ( USHORT i = 0; i < nCopyCount; i++ )
428 if ( pActPage->mpSetup )
430 SetJobSetup( *pActPage->mpSetup );
431 if ( mbAborted )
432 break;
435 StartPage();
437 if ( mbAborted )
438 break;
440 ImplPrintMtf( maCurPageMetaFile, mnMaxBmpDPIX, mnMaxBmpDPIY );
442 if( !mbAborted )
443 EndPage();
444 else
445 break;
448 PostPrintPage();
450 delete pActPage;
451 mbDestroyAllowed = TRUE;
453 if( mbDestroyed )
454 Destroy();
457 return 0;
460 // -----------------------------------------------------------------------
462 void ImplQPrinter::StartQueuePrint()
464 if( ! ImplGetSVData()->maGDIData.mbPrinterPullModel )
466 maTimer.SetTimeout( 50 );
467 maTimer.SetTimeoutHdl( LINK( this, ImplQPrinter, ImplPrintHdl ) );
468 maTimer.Start();
472 // -----------------------------------------------------------------------
474 void ImplQPrinter::EndQueuePrint()
476 if( ImplGetSVData()->maGDIData.mbPrinterPullModel )
478 DBG_ASSERT( mpPrinter, "no SalPrinter in ImplQPrinter" );
479 if( mpPrinter )
481 mpPrinter->StartJob( mbPrintFile ? &maPrintFile : NULL,
482 Application::GetDisplayName(),
483 maJobSetup.ImplGetConstData(),
484 this );
485 EndJob();
486 mpParent->ImplEndPrint();
489 else
491 QueuePage* pQueuePage = new QueuePage;
492 pQueuePage->mbEndJob = TRUE;
493 maQueue.push_back( pQueuePage );
497 // -----------------------------------------------------------------------
499 bool ImplQPrinter::GetPaperRanges( std::vector< ULONG >& o_rRanges, bool i_bIncludeOrientationChanges ) const
501 bool bRet = false;
503 if( ImplGetSVData()->maGDIData.mbPrinterPullModel )
505 bRet = true;
506 o_rRanges.clear();
508 if( ! maQueue.empty() )
510 ULONG nCurPage = 0;
512 // get first job data
513 const ImplJobSetup* pLastFormat = NULL;
514 if( maQueue.front()->mpSetup )
515 pLastFormat = maQueue.front()->mpSetup->ImplGetConstData();
517 // begin first range
518 o_rRanges.push_back( 0 );
519 for( std::vector< QueuePage* >::const_iterator it = maQueue.begin();
520 it != maQueue.end(); ++it, ++nCurPage )
522 const ImplJobSetup* pNewSetup = (*it)->mpSetup ? (*it)->mpSetup->ImplGetConstData() : NULL;
523 if( pNewSetup && pNewSetup != pLastFormat )
525 bool bChange = false;
526 if( pLastFormat == NULL )
528 bChange = true;
530 else if( ! i_bIncludeOrientationChanges &&
531 pNewSetup->meOrientation != pLastFormat->meOrientation )
533 bChange = true;
535 else if( pNewSetup->mePaperFormat != pLastFormat->mePaperFormat ||
536 ( pNewSetup->mePaperFormat == PAPER_USER &&
537 ( pNewSetup->mnPaperWidth != pLastFormat->mnPaperWidth ||
538 pNewSetup->mnPaperHeight != pLastFormat->mnPaperHeight ) ) )
540 bChange = true;
542 else if( pNewSetup->mnPaperBin != pLastFormat->mnPaperBin )
544 bChange = true;
546 if( bChange )
548 o_rRanges.push_back( nCurPage );
549 pLastFormat = pNewSetup;
554 o_rRanges.push_back( nCurPage );
558 return bRet;
561 // -----------------------------------------------------------------------
563 void ImplQPrinter::AbortQueuePrint()
565 maTimer.Stop();
566 mbAborted = TRUE;
567 AbortJob();
570 // -----------------------------------------------------------------------
572 void ImplQPrinter::AddQueuePage( GDIMetaFile* pPage, USHORT nPage, BOOL bNewJobSetup )
574 QueuePage* pQueuePage = new QueuePage;
575 pQueuePage->mpMtf = pPage;
576 pQueuePage->mnPage = nPage;
577 pQueuePage->mbEndJob = FALSE;
578 // ensure that the first page has a valid setup, this is needed
579 // in GetPaperRanges (used in pullmodel)
580 // caution: this depends on mnCurPage in Printer being
581 // 0: not printing 1: after StartJob, 2 after first EndPage, 3+ at following EndPage calls
582 if ( bNewJobSetup || (nPage == 2 && ImplGetSVData()->maGDIData.mbPrinterPullModel) )
583 pQueuePage->mpSetup = new JobSetup( mpParent->GetJobSetup() );
584 maQueue.push_back( pQueuePage );