xref: /trunk/main/vcl/source/gdi/virdev.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
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