xref: /trunk/main/vcl/source/gdi/virdev.cxx (revision cdf0e10c)
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 <tools/debug.hxx>
32 
33 #include <vcl/settings.hxx>
34 #include <vcl/svapp.hxx>
35 #include <vcl/wrkwin.hxx>
36 #include <vcl/virdev.hxx>
37 
38 #include <salinst.hxx>
39 #include <salgdi.hxx>
40 #include <salframe.hxx>
41 #include <salvd.hxx>
42 #include <outdev.h>
43 #include <svdata.hxx>
44 
45 using namespace ::com::sun::star::uno;
46 
47 // =======================================================================
48 
49 void VirtualDevice::ImplInitVirDev( const OutputDevice* pOutDev,
50 									long nDX, long nDY, sal_uInt16 nBitCount, const SystemGraphicsData *pData )
51 {
52 	DBG_ASSERT( nBitCount <= 1,
53 				"VirtualDevice::VirtualDevice(): Only 0 or 1 is for BitCount allowed" );
54 
55 	if ( nDX < 1 )
56 		nDX = 1;
57 
58 	if ( nDY < 1 )
59 		nDY = 1;
60 
61 	ImplSVData* pSVData = ImplGetSVData();
62 
63 	if ( !pOutDev )
64 		pOutDev = ImplGetDefaultWindow();
65     if( !pOutDev )
66         return;
67 
68 	SalGraphics* pGraphics;
69 	if ( !pOutDev->mpGraphics )
70 		((OutputDevice*)pOutDev)->ImplGetGraphics();
71 	pGraphics = pOutDev->mpGraphics;
72 	if ( pGraphics )
73 		mpVirDev = pSVData->mpDefInst->CreateVirtualDevice( pGraphics, nDX, nDY, nBitCount, pData );
74 	else
75 		mpVirDev = NULL;
76 	if ( !mpVirDev )
77     {
78         // do not abort but throw an exception, may be the current thread terminates anyway (plugin-scenario)
79         throw ::com::sun::star::uno::RuntimeException(
80             OUString( RTL_CONSTASCII_USTRINGPARAM( "Could not create system bitmap!" ) ),
81             ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() );
82 		//GetpApp()->Exception( EXC_SYSOBJNOTCREATED );
83     }
84 
85 	mnBitCount		= ( nBitCount ? nBitCount : pOutDev->GetBitCount() );
86 	mnOutWidth		= nDX;
87 	mnOutHeight 	= nDY;
88 	mbScreenComp	= sal_True;
89     mnAlphaDepth	= -1;
90 
91     // #i59315# init vdev size from system object, when passed a
92     // SystemGraphicsData. Otherwise, output size will always
93     // incorrectly stay at (1,1)
94     if( pData && mpVirDev )
95         mpVirDev->GetSize(mnOutWidth,mnOutHeight);
96 
97     if( mnBitCount < 8 )
98         SetAntialiasing( ANTIALIASING_DISABLE_TEXT );
99 
100 	if ( pOutDev->GetOutDevType() == OUTDEV_PRINTER )
101 		mbScreenComp = sal_False;
102 	else if ( pOutDev->GetOutDevType() == OUTDEV_VIRDEV )
103 		mbScreenComp = ((VirtualDevice*)pOutDev)->mbScreenComp;
104 
105 	meOutDevType	= OUTDEV_VIRDEV;
106 	mbDevOutput 	= sal_True;
107 	mpFontList		= pSVData->maGDIData.mpScreenFontList;
108 	mpFontCache 	= pSVData->maGDIData.mpScreenFontCache;
109 	mnDPIX			= pOutDev->mnDPIX;
110 	mnDPIY			= pOutDev->mnDPIY;
111 	maFont			= pOutDev->maFont;
112 
113     if( maTextColor != pOutDev->maTextColor )
114     {
115         maTextColor	= pOutDev->maTextColor;
116         mbInitTextColor = true;
117     }
118 
119 	// Virtuelle Devices haben defaultmaessig einen weissen Hintergrund
120 	SetBackground( Wallpaper( Color( COL_WHITE ) ) );
121 
122     // #i59283# don't erase user-provided surface
123     if( !pData )
124         Erase();
125 
126 	// VirDev in Liste eintragen
127 	mpNext = pSVData->maGDIData.mpFirstVirDev;
128 	mpPrev = NULL;
129 	if ( mpNext )
130 		mpNext->mpPrev = this;
131 	else
132 		pSVData->maGDIData.mpLastVirDev = this;
133 	pSVData->maGDIData.mpFirstVirDev = this;
134 }
135 
136 // -----------------------------------------------------------------------
137 
138 VirtualDevice::VirtualDevice( sal_uInt16 nBitCount )
139 :   mpVirDev( NULL ),
140     meRefDevMode( REFDEV_NONE )
141 {
142 	DBG_TRACE1( "VirtualDevice::VirtualDevice( %hu )", nBitCount );
143 
144 	ImplInitVirDev( Application::GetDefaultDevice(), 1, 1, nBitCount );
145 }
146 
147 // -----------------------------------------------------------------------
148 
149 VirtualDevice::VirtualDevice( const OutputDevice& rCompDev, sal_uInt16 nBitCount )
150 	: mpVirDev( NULL ),
151     meRefDevMode( REFDEV_NONE )
152 {
153 	DBG_TRACE1( "VirtualDevice::VirtualDevice( %hu )", nBitCount );
154 
155 	ImplInitVirDev( &rCompDev, 1, 1, nBitCount );
156 }
157 
158 // -----------------------------------------------------------------------
159 
160 VirtualDevice::VirtualDevice( const OutputDevice& rCompDev, sal_uInt16 nBitCount, sal_uInt16 nAlphaBitCount )
161 	: mpVirDev( NULL ),
162     meRefDevMode( REFDEV_NONE )
163 {
164 	DBG_TRACE1( "VirtualDevice::VirtualDevice( %hu )", nBitCount );
165 
166 	ImplInitVirDev( &rCompDev, 1, 1, nBitCount );
167 
168     // #110958# Enable alpha channel
169     mnAlphaDepth = sal::static_int_cast<sal_Int8>(nAlphaBitCount);
170 }
171 
172 // -----------------------------------------------------------------------
173 
174 VirtualDevice::VirtualDevice( const SystemGraphicsData *pData, sal_uInt16 nBitCount )
175 :   mpVirDev( NULL ),
176     meRefDevMode( REFDEV_NONE )
177 {
178 	DBG_TRACE1( "VirtualDevice::VirtualDevice( %hu )", nBitCount );
179 
180 	ImplInitVirDev( Application::GetDefaultDevice(), 1, 1, nBitCount, pData );
181 }
182 
183 // -----------------------------------------------------------------------
184 
185 VirtualDevice::~VirtualDevice()
186 {
187 	DBG_TRACE( "VirtualDevice::~VirtualDevice()" );
188 
189     ImplSVData* pSVData = ImplGetSVData();
190 
191 	ImplReleaseGraphics();
192 
193 	if ( mpVirDev )
194 		pSVData->mpDefInst->DestroyVirtualDevice( mpVirDev );
195 
196 	// remove this VirtualDevice from the double-linked global list
197 	if( mpPrev )
198 		mpPrev->mpNext = mpNext;
199 	else
200 		pSVData->maGDIData.mpFirstVirDev = mpNext;
201 
202 	if( mpNext )
203 		mpNext->mpPrev = mpPrev;
204 	else
205 		pSVData->maGDIData.mpLastVirDev = mpPrev;
206 }
207 
208 // -----------------------------------------------------------------------
209 
210 sal_Bool VirtualDevice::ImplSetOutputSizePixel( const Size& rNewSize, sal_Bool bErase )
211 {
212 	DBG_TRACE3( "VirtualDevice::ImplSetOutputSizePixel( %ld, %ld, %d )", rNewSize.Width(), rNewSize.Height(), (int)bErase );
213 
214 	if ( !mpVirDev )
215 		return sal_False;
216 	else if ( rNewSize == GetOutputSizePixel() )
217 	{
218 		if ( bErase )
219 			Erase();
220 		return sal_True;
221 	}
222 
223 	sal_Bool bRet;
224 	long nNewWidth = rNewSize.Width(), nNewHeight = rNewSize.Height();
225 
226 	if ( nNewWidth < 1 )
227 		nNewWidth = 1;
228 
229 	if ( nNewHeight < 1 )
230 		nNewHeight = 1;
231 
232 	if ( bErase )
233 	{
234 		bRet = mpVirDev->SetSize( nNewWidth, nNewHeight );
235 
236 		if ( bRet )
237 		{
238 			mnOutWidth	= rNewSize.Width();
239 			mnOutHeight = rNewSize.Height();
240 			Erase();
241 		}
242 	}
243 	else
244 	{
245 		SalVirtualDevice*	pNewVirDev;
246 		ImplSVData* 		pSVData = ImplGetSVData();
247 
248 		// we need a graphics
249 		if ( !mpGraphics )
250 		{
251 			if ( !ImplGetGraphics() )
252 				return sal_False;
253 		}
254 
255 		pNewVirDev = pSVData->mpDefInst->CreateVirtualDevice( mpGraphics, nNewWidth, nNewHeight, mnBitCount );
256 		if ( pNewVirDev )
257 		{
258 			SalGraphics* pGraphics = pNewVirDev->GetGraphics();
259 			if ( pGraphics )
260 			{
261 				SalTwoRect aPosAry;
262 				long nWidth;
263 				long nHeight;
264 				if ( mnOutWidth < nNewWidth )
265 					nWidth = mnOutWidth;
266 				else
267 					nWidth = nNewWidth;
268 				if ( mnOutHeight < nNewHeight )
269 					nHeight = mnOutHeight;
270 				else
271 					nHeight = nNewHeight;
272 				aPosAry.mnSrcX		 = 0;
273 				aPosAry.mnSrcY		 = 0;
274 				aPosAry.mnSrcWidth	 = nWidth;
275 				aPosAry.mnSrcHeight  = nHeight;
276 				aPosAry.mnDestX 	 = 0;
277 				aPosAry.mnDestY 	 = 0;
278 				aPosAry.mnDestWidth  = nWidth;
279 				aPosAry.mnDestHeight = nHeight;
280 
281 				pGraphics->CopyBits( &aPosAry, mpGraphics, this, this );
282 				pNewVirDev->ReleaseGraphics( pGraphics );
283 				ImplReleaseGraphics();
284 				pSVData->mpDefInst->DestroyVirtualDevice( mpVirDev );
285 				mpVirDev = pNewVirDev;
286 				mnOutWidth	= rNewSize.Width();
287 				mnOutHeight = rNewSize.Height();
288 				bRet = sal_True;
289 			}
290 			else
291 			{
292 				bRet = sal_False;
293 				pSVData->mpDefInst->DestroyVirtualDevice( pNewVirDev );
294 			}
295 		}
296 		else
297 			bRet = sal_False;
298 	}
299 
300 	return bRet;
301 }
302 
303 // -----------------------------------------------------------------------
304 
305 // #i32109#: Fill opaque areas correctly (without relying on
306 // fill/linecolor state)
307 void VirtualDevice::ImplFillOpaqueRectangle( const Rectangle& rRect )
308 {
309     // Set line and fill color to black (->opaque),
310     // fill rect with that (linecolor, too, because of
311     // those pesky missing pixel problems)
312     Push( PUSH_LINECOLOR | PUSH_FILLCOLOR );
313     SetLineColor( COL_BLACK );
314     SetFillColor( COL_BLACK );
315     DrawRect( rRect );
316     Pop();
317 }
318 
319 // -----------------------------------------------------------------------
320 
321 sal_Bool VirtualDevice::SetOutputSizePixel( const Size& rNewSize, sal_Bool bErase )
322 {
323     if( ImplSetOutputSizePixel(rNewSize, bErase) )
324     {
325         if( mnAlphaDepth != -1 )
326         {
327             // #110958# Setup alpha bitmap
328 			if(mpAlphaVDev && mpAlphaVDev->GetOutputSizePixel() != rNewSize)
329 			{
330 				delete mpAlphaVDev;
331 				mpAlphaVDev = 0L;
332 			}
333 
334 			if( !mpAlphaVDev )
335             {
336                 mpAlphaVDev = new VirtualDevice( *this, mnAlphaDepth );
337                 mpAlphaVDev->ImplSetOutputSizePixel(rNewSize, bErase);
338             }
339 
340             // TODO: copy full outdev state to new one, here. Also needed in outdev2.cxx:DrawOutDev
341             if( GetLineColor() != Color( COL_TRANSPARENT ) )
342                 mpAlphaVDev->SetLineColor( COL_BLACK );
343 
344             if( GetFillColor() != Color( COL_TRANSPARENT ) )
345                 mpAlphaVDev->SetFillColor( COL_BLACK );
346 
347             mpAlphaVDev->SetMapMode( GetMapMode() );
348         }
349 
350         return sal_True;
351     }
352 
353     return sal_False;
354 }
355 
356 // -----------------------------------------------------------------------
357 
358 void VirtualDevice::SetReferenceDevice( RefDevMode i_eRefDevMode )
359 {
360     sal_Int32 nDPIX = 600, nDPIY = 600;
361     switch( i_eRefDevMode )
362     {
363     case REFDEV_NONE:
364     default:
365         DBG_ASSERT( sal_False, "VDev::SetRefDev illegal argument!" );
366         break;
367     case REFDEV_MODE06:
368         nDPIX = nDPIY = 600;
369         break;
370     case REFDEV_MODE48:
371         nDPIX = nDPIY = 4800;
372         break;
373     case REFDEV_MODE_MSO1:
374         nDPIX = nDPIY = 6*1440;
375         break;
376     case REFDEV_MODE_PDF1:
377         nDPIX = nDPIY = 720;
378         break;
379     }
380     ImplSetReferenceDevice( i_eRefDevMode, nDPIX, nDPIY );
381 }
382 
383 void VirtualDevice::SetReferenceDevice( sal_Int32 i_nDPIX, sal_Int32 i_nDPIY )
384 {
385     ImplSetReferenceDevice( REFDEV_CUSTOM, i_nDPIX, i_nDPIY );
386 }
387 
388 void VirtualDevice::ImplSetReferenceDevice( RefDevMode i_eRefDevMode, sal_Int32 i_nDPIX, sal_Int32 i_nDPIY )
389 {
390     mnDPIX = i_nDPIX;
391     mnDPIY = i_nDPIY;
392 
393     EnableOutput( sal_False );  // prevent output on reference device
394     mbScreenComp = sal_False;
395 
396     // invalidate currently selected fonts
397     mbInitFont = sal_True;
398     mbNewFont = sal_True;
399 
400     // avoid adjusting font lists when already in refdev mode
401     sal_uInt8 nOldRefDevMode = meRefDevMode;
402     sal_uInt8 nOldCompatFlag = (sal_uInt8)meRefDevMode & REFDEV_FORCE_ZERO_EXTLEAD;
403     meRefDevMode = (sal_uInt8)(i_eRefDevMode | nOldCompatFlag);
404     if( (nOldRefDevMode ^ nOldCompatFlag) != REFDEV_NONE )
405         return;
406 
407     // the reference device should have only scalable fonts
408     // => clean up the original font lists before getting new ones
409     if ( mpFontEntry )
410     {
411         mpFontCache->Release( mpFontEntry );
412         mpFontEntry = NULL;
413     }
414     if ( mpGetDevFontList )
415     {
416         delete mpGetDevFontList;
417         mpGetDevFontList = NULL;
418     }
419     if ( mpGetDevSizeList )
420     {
421         delete mpGetDevSizeList;
422         mpGetDevSizeList = NULL;
423     }
424 
425     // preserve global font lists
426     ImplSVData* pSVData = ImplGetSVData();
427     if( mpFontList && (mpFontList != pSVData->maGDIData.mpScreenFontList) )
428         delete mpFontList;
429     if( mpFontCache && (mpFontCache != pSVData->maGDIData.mpScreenFontCache) )
430         delete mpFontCache;
431 
432     // get font list with scalable fonts only
433     ImplGetGraphics();
434     mpFontList = pSVData->maGDIData.mpScreenFontList->Clone( true, false );
435 
436     // prepare to use new font lists
437     mpFontCache = new ImplFontCache( false );
438 }
439 
440 // -----------------------------------------------------------------------
441 
442 void VirtualDevice::Compat_ZeroExtleadBug()
443 {
444 	meRefDevMode = (sal_uInt8)meRefDevMode | REFDEV_FORCE_ZERO_EXTLEAD;
445 }
446 
447 // -----------------------------------------------------------------------
448 
449