1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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"
50 #define OPTIMAL_BMP_RESOLUTION 300
51 #define NORMAL_BMP_RESOLUTION 200
53 // =======================================================================
62 QueuePage() { mpMtf
= NULL
; mpSetup
= NULL
; }
63 ~QueuePage() { delete mpMtf
; if ( mpSetup
) delete mpSetup
; }
66 // =======================================================================
68 ImplQPrinter::ImplQPrinter( Printer
* pParent
) :
69 Printer( pParent
->GetName() ),
73 mbDestroyAllowed( true ),
75 mnMaxBmpDPIX( mnDPIX
),
76 mnMaxBmpDPIY( mnDPIY
),
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
)
95 // -----------------------------------------------------------------------------
97 void ImplQPrinter::Destroy()
99 if( mbDestroyAllowed
)
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();
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 );
153 SetLineColor(COL_RED
);
156 static_cast<MetaBmpScaleAction
*>(pAct
)->GetPoint(),
157 static_cast<MetaBmpScaleAction
*>(pAct
)->GetSize()) );
161 // seek to end of this comment
164 pAct
= rPrtMtf
.NextAction();
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
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() );
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
) );
285 SetMapMode( aDrawMap
);
286 ImplPrintMtf( rMtf
, nMaxBmpDPIX
, nMaxBmpDPIY
);
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
);
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() )
363 mnCurCopyCount
= (mbUserCopy
&& !mbCollateCopy
) ? mnCopyCount
: 1;
364 QueuePage
* pActPage
= maQueue
[nPage
];
365 PrePrintPage( pActPage
);
366 if ( pActPage
->mpSetup
)
367 SetJobSetup( *pActPage
->mpSetup
);
370 ImplPrintMtf( maCurPageMetaFile
, mnMaxBmpDPIX
, mnMaxBmpDPIY
);
374 if( mnCurCopyCount
== 0 )
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);
393 // -----------------------------------------------------------------------
395 IMPL_LINK( ImplQPrinter
, ImplPrintHdl
, Timer
*, EMPTYARG
)
397 // Ist Drucken abgebrochen wurden?
398 if( !IsPrinting() || ( mpParent
->IsJobActive() && ( maQueue
.size() < (ULONG
)mpParent
->GetPageQueueSize() ) ) )
402 QueuePage
* pActPage
= maQueue
.front();
403 maQueue
.erase( maQueue
.begin() );
406 vcl::DeletionListener
aDel( this );
407 if ( pActPage
->mbEndJob
)
413 if( ! aDel
.isDeleted() )
414 mpParent
->ImplEndPrint();
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
);
440 ImplPrintMtf( maCurPageMetaFile
, mnMaxBmpDPIX
, mnMaxBmpDPIY
);
451 mbDestroyAllowed
= TRUE
;
460 // -----------------------------------------------------------------------
462 void ImplQPrinter::StartQueuePrint()
464 if( ! ImplGetSVData()->maGDIData
.mbPrinterPullModel
)
466 maTimer
.SetTimeout( 50 );
467 maTimer
.SetTimeoutHdl( LINK( this, ImplQPrinter
, ImplPrintHdl
) );
472 // -----------------------------------------------------------------------
474 void ImplQPrinter::EndQueuePrint()
476 if( ImplGetSVData()->maGDIData
.mbPrinterPullModel
)
478 DBG_ASSERT( mpPrinter
, "no SalPrinter in ImplQPrinter" );
481 mpPrinter
->StartJob( mbPrintFile
? &maPrintFile
: NULL
,
482 Application::GetDisplayName(),
483 maJobSetup
.ImplGetConstData(),
486 mpParent
->ImplEndPrint();
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
503 if( ImplGetSVData()->maGDIData
.mbPrinterPullModel
)
508 if( ! maQueue
.empty() )
512 // get first job data
513 const ImplJobSetup
* pLastFormat
= NULL
;
514 if( maQueue
.front()->mpSetup
)
515 pLastFormat
= maQueue
.front()->mpSetup
->ImplGetConstData();
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
)
530 else if( ! i_bIncludeOrientationChanges
&&
531 pNewSetup
->meOrientation
!= pLastFormat
->meOrientation
)
535 else if( pNewSetup
->mePaperFormat
!= pLastFormat
->mePaperFormat
||
536 ( pNewSetup
->mePaperFormat
== PAPER_USER
&&
537 ( pNewSetup
->mnPaperWidth
!= pLastFormat
->mnPaperWidth
||
538 pNewSetup
->mnPaperHeight
!= pLastFormat
->mnPaperHeight
) ) )
542 else if( pNewSetup
->mnPaperBin
!= pLastFormat
->mnPaperBin
)
548 o_rRanges
.push_back( nCurPage
);
549 pLastFormat
= pNewSetup
;
554 o_rRanges
.push_back( nCurPage
);
561 // -----------------------------------------------------------------------
563 void ImplQPrinter::AbortQueuePrint()
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
);