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