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