Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <tools/debug.hxx>
21 : #include <vcl/bitmap.hxx>
22 : #include <vcl/bitmapex.hxx>
23 : #include <vcl/window.hxx>
24 : #include <vcl/metaact.hxx>
25 : #include <vcl/gdimtf.hxx>
26 : #include <vcl/virdev.hxx>
27 : #include <vcl/bmpacc.hxx>
28 : #include <vcl/outdev.hxx>
29 : #include <vcl/image.hxx>
30 : #include <bmpfast.hxx>
31 : #include <salbmp.hxx>
32 : #include <salgdi.hxx>
33 : #include <impbmp.hxx>
34 : #include <sallayout.hxx>
35 : #include <image.h>
36 : #include <outdev.h>
37 : #include <window.h>
38 : #include <outdata.hxx>
39 : #include <basegfx/matrix/b2dhommatrix.hxx>
40 : #include <basegfx/matrix/b2dhommatrixtools.hxx>
41 : #include <boost/scoped_array.hpp>
42 :
43 : #define OUTDEV_INIT() \
44 : { \
45 : if ( !IsDeviceOutputNecessary() ) \
46 : return; \
47 : \
48 : if ( !mpGraphics ) \
49 : if ( !ImplGetGraphics() ) \
50 : return; \
51 : \
52 : if ( mbInitClipRegion ) \
53 : ImplInitClipRegion(); \
54 : \
55 : if ( mbOutputClipped ) \
56 : return; \
57 : }
58 :
59 : extern const sal_uLong nVCLRLut[ 6 ];
60 : extern const sal_uLong nVCLGLut[ 6 ];
61 : extern const sal_uLong nVCLBLut[ 6 ];
62 : extern const sal_uLong nVCLDitherLut[ 256 ];
63 : extern const sal_uLong nVCLLut[ 256 ];
64 :
65 0 : sal_uLong ImplAdjustTwoRect( SalTwoRect& rTwoRect, const Size& rSizePix )
66 : {
67 0 : sal_uLong nMirrFlags = 0;
68 :
69 0 : if ( rTwoRect.mnDestWidth < 0 )
70 : {
71 0 : rTwoRect.mnSrcX = rSizePix.Width() - rTwoRect.mnSrcX - rTwoRect.mnSrcWidth;
72 0 : rTwoRect.mnDestWidth = -rTwoRect.mnDestWidth;
73 0 : rTwoRect.mnDestX -= rTwoRect.mnDestWidth-1;
74 0 : nMirrFlags |= BMP_MIRROR_HORZ;
75 : }
76 :
77 0 : if ( rTwoRect.mnDestHeight < 0 )
78 : {
79 0 : rTwoRect.mnSrcY = rSizePix.Height() - rTwoRect.mnSrcY - rTwoRect.mnSrcHeight;
80 0 : rTwoRect.mnDestHeight = -rTwoRect.mnDestHeight;
81 0 : rTwoRect.mnDestY -= rTwoRect.mnDestHeight-1;
82 0 : nMirrFlags |= BMP_MIRROR_VERT;
83 : }
84 :
85 0 : if( ( rTwoRect.mnSrcX < 0 ) || ( rTwoRect.mnSrcX >= rSizePix.Width() ) ||
86 0 : ( rTwoRect.mnSrcY < 0 ) || ( rTwoRect.mnSrcY >= rSizePix.Height() ) ||
87 0 : ( ( rTwoRect.mnSrcX + rTwoRect.mnSrcWidth ) > rSizePix.Width() ) ||
88 0 : ( ( rTwoRect.mnSrcY + rTwoRect.mnSrcHeight ) > rSizePix.Height() ) )
89 : {
90 : const Rectangle aSourceRect( Point( rTwoRect.mnSrcX, rTwoRect.mnSrcY ),
91 0 : Size( rTwoRect.mnSrcWidth, rTwoRect.mnSrcHeight ) );
92 0 : Rectangle aCropRect( aSourceRect );
93 :
94 0 : aCropRect.Intersection( Rectangle( Point(), rSizePix ) );
95 :
96 0 : if( aCropRect.IsEmpty() )
97 0 : rTwoRect.mnSrcWidth = rTwoRect.mnSrcHeight = rTwoRect.mnDestWidth = rTwoRect.mnDestHeight = 0;
98 : else
99 : {
100 0 : const double fFactorX = ( rTwoRect.mnSrcWidth > 1 ) ? (double) ( rTwoRect.mnDestWidth - 1 ) / ( rTwoRect.mnSrcWidth - 1 ) : 0.0;
101 0 : const double fFactorY = ( rTwoRect.mnSrcHeight > 1 ) ? (double) ( rTwoRect.mnDestHeight - 1 ) / ( rTwoRect.mnSrcHeight - 1 ) : 0.0;
102 :
103 0 : const long nDstX1 = rTwoRect.mnDestX + FRound( fFactorX * ( aCropRect.Left() - rTwoRect.mnSrcX ) );
104 0 : const long nDstY1 = rTwoRect.mnDestY + FRound( fFactorY * ( aCropRect.Top() - rTwoRect.mnSrcY ) );
105 0 : const long nDstX2 = rTwoRect.mnDestX + FRound( fFactorX * ( aCropRect.Right() - rTwoRect.mnSrcX ) );
106 0 : const long nDstY2 = rTwoRect.mnDestY + FRound( fFactorY * ( aCropRect.Bottom() - rTwoRect.mnSrcY ) );
107 :
108 0 : rTwoRect.mnSrcX = aCropRect.Left();
109 0 : rTwoRect.mnSrcY = aCropRect.Top();
110 0 : rTwoRect.mnSrcWidth = aCropRect.GetWidth();
111 0 : rTwoRect.mnSrcHeight = aCropRect.GetHeight();
112 0 : rTwoRect.mnDestX = nDstX1;
113 0 : rTwoRect.mnDestY = nDstY1;
114 0 : rTwoRect.mnDestWidth = nDstX2 - nDstX1 + 1;
115 0 : rTwoRect.mnDestHeight = nDstY2 - nDstY1 + 1;
116 : }
117 : }
118 :
119 0 : return nMirrFlags;
120 : }
121 :
122 0 : void ImplAdjustTwoRect( SalTwoRect& rTwoRect, const Rectangle& rValidSrcRect )
123 : {
124 0 : if( ( rTwoRect.mnSrcX < rValidSrcRect.Left() ) || ( rTwoRect.mnSrcX >= rValidSrcRect.Right() ) ||
125 0 : ( rTwoRect.mnSrcY < rValidSrcRect.Top() ) || ( rTwoRect.mnSrcY >= rValidSrcRect.Bottom() ) ||
126 0 : ( ( rTwoRect.mnSrcX + rTwoRect.mnSrcWidth ) > rValidSrcRect.Right() ) ||
127 0 : ( ( rTwoRect.mnSrcY + rTwoRect.mnSrcHeight ) > rValidSrcRect.Bottom() ) )
128 : {
129 : const Rectangle aSourceRect( Point( rTwoRect.mnSrcX, rTwoRect.mnSrcY ),
130 0 : Size( rTwoRect.mnSrcWidth, rTwoRect.mnSrcHeight ) );
131 0 : Rectangle aCropRect( aSourceRect );
132 :
133 0 : aCropRect.Intersection( rValidSrcRect );
134 :
135 0 : if( aCropRect.IsEmpty() )
136 0 : rTwoRect.mnSrcWidth = rTwoRect.mnSrcHeight = rTwoRect.mnDestWidth = rTwoRect.mnDestHeight = 0;
137 : else
138 : {
139 0 : const double fFactorX = ( rTwoRect.mnSrcWidth > 1 ) ? (double) ( rTwoRect.mnDestWidth - 1 ) / ( rTwoRect.mnSrcWidth - 1 ) : 0.0;
140 0 : const double fFactorY = ( rTwoRect.mnSrcHeight > 1 ) ? (double) ( rTwoRect.mnDestHeight - 1 ) / ( rTwoRect.mnSrcHeight - 1 ) : 0.0;
141 :
142 0 : const long nDstX1 = rTwoRect.mnDestX + FRound( fFactorX * ( aCropRect.Left() - rTwoRect.mnSrcX ) );
143 0 : const long nDstY1 = rTwoRect.mnDestY + FRound( fFactorY * ( aCropRect.Top() - rTwoRect.mnSrcY ) );
144 0 : const long nDstX2 = rTwoRect.mnDestX + FRound( fFactorX * ( aCropRect.Right() - rTwoRect.mnSrcX ) );
145 0 : const long nDstY2 = rTwoRect.mnDestY + FRound( fFactorY * ( aCropRect.Bottom() - rTwoRect.mnSrcY ) );
146 :
147 0 : rTwoRect.mnSrcX = aCropRect.Left();
148 0 : rTwoRect.mnSrcY = aCropRect.Top();
149 0 : rTwoRect.mnSrcWidth = aCropRect.GetWidth();
150 0 : rTwoRect.mnSrcHeight = aCropRect.GetHeight();
151 0 : rTwoRect.mnDestX = nDstX1;
152 0 : rTwoRect.mnDestY = nDstY1;
153 0 : rTwoRect.mnDestWidth = nDstX2 - nDstX1 + 1;
154 0 : rTwoRect.mnDestHeight = nDstY2 - nDstY1 + 1;
155 : }
156 : }
157 0 : }
158 :
159 0 : void OutputDevice::ImplDrawOutDevDirect( const OutputDevice* pSrcDev, SalTwoRect& rPosAry )
160 : {
161 : SalGraphics* pGraphics2;
162 :
163 0 : if ( this == pSrcDev )
164 0 : pGraphics2 = NULL;
165 : else
166 : {
167 0 : if ( (GetOutDevType() != pSrcDev->GetOutDevType()) ||
168 0 : (GetOutDevType() != OUTDEV_WINDOW) )
169 : {
170 0 : if ( !pSrcDev->mpGraphics )
171 : {
172 0 : if ( !((OutputDevice*)pSrcDev)->ImplGetGraphics() )
173 0 : return;
174 : }
175 0 : pGraphics2 = pSrcDev->mpGraphics;
176 : }
177 : else
178 : {
179 0 : if ( ((Window*)this)->mpWindowImpl->mpFrameWindow == ((Window*)pSrcDev)->mpWindowImpl->mpFrameWindow )
180 0 : pGraphics2 = NULL;
181 : else
182 : {
183 0 : if ( !pSrcDev->mpGraphics )
184 : {
185 0 : if ( !((OutputDevice*)pSrcDev)->ImplGetGraphics() )
186 0 : return;
187 : }
188 0 : pGraphics2 = pSrcDev->mpGraphics;
189 :
190 0 : if ( !mpGraphics )
191 : {
192 0 : if ( !ImplGetGraphics() )
193 0 : return;
194 : }
195 : DBG_ASSERT( mpGraphics && pSrcDev->mpGraphics,
196 : "OutputDevice::DrawOutDev(): We need more than one Graphics" );
197 : }
198 : }
199 : }
200 :
201 : // #102532# Offset only has to be pseudo window offset
202 : const Rectangle aSrcOutRect( Point( pSrcDev->mnOutOffX, pSrcDev->mnOutOffY ),
203 0 : Size( pSrcDev->mnOutWidth, pSrcDev->mnOutHeight ) );
204 :
205 0 : ImplAdjustTwoRect( rPosAry, aSrcOutRect );
206 :
207 0 : if ( rPosAry.mnSrcWidth && rPosAry.mnSrcHeight && rPosAry.mnDestWidth && rPosAry.mnDestHeight )
208 : {
209 : // --- RTL --- if this is no window, but pSrcDev is a window
210 : // mirroring may be required
211 : // because only windows have a SalGraphicsLayout
212 : // mirroring is performed here
213 0 : if( (GetOutDevType() != OUTDEV_WINDOW) && pGraphics2 && (pGraphics2->GetLayout() & SAL_LAYOUT_BIDI_RTL) )
214 : {
215 0 : SalTwoRect aPosAry2 = rPosAry;
216 0 : pGraphics2->mirror( aPosAry2.mnSrcX, aPosAry2.mnSrcWidth, pSrcDev );
217 0 : mpGraphics->CopyBits( aPosAry2, pGraphics2, this, pSrcDev );
218 : }
219 : else
220 0 : mpGraphics->CopyBits( rPosAry, pGraphics2, this, pSrcDev );
221 : }
222 : }
223 :
224 0 : void OutputDevice::DrawOutDev( const Point& rDestPt, const Size& rDestSize,
225 : const Point& rSrcPt, const Size& rSrcSize )
226 : {
227 0 : if( ImplIsRecordLayout() )
228 0 : return;
229 :
230 0 : if ( ROP_INVERT == meRasterOp )
231 : {
232 0 : DrawRect( Rectangle( rDestPt, rDestSize ) );
233 0 : return;
234 : }
235 :
236 0 : if ( mpMetaFile )
237 : {
238 0 : const Bitmap aBmp( GetBitmap( rSrcPt, rSrcSize ) );
239 0 : mpMetaFile->AddAction( new MetaBmpScaleAction( rDestPt, rDestSize, aBmp ) );
240 : }
241 :
242 0 : OUTDEV_INIT();
243 :
244 : SalTwoRect aPosAry;
245 0 : aPosAry.mnSrcWidth = ImplLogicWidthToDevicePixel( rSrcSize.Width() );
246 0 : aPosAry.mnSrcHeight = ImplLogicHeightToDevicePixel( rSrcSize.Height() );
247 0 : aPosAry.mnDestWidth = ImplLogicWidthToDevicePixel( rDestSize.Width() );
248 0 : aPosAry.mnDestHeight = ImplLogicHeightToDevicePixel( rDestSize.Height() );
249 :
250 0 : if ( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight )
251 : {
252 0 : aPosAry.mnSrcX = ImplLogicXToDevicePixel( rSrcPt.X() );
253 0 : aPosAry.mnSrcY = ImplLogicYToDevicePixel( rSrcPt.Y() );
254 0 : aPosAry.mnDestX = ImplLogicXToDevicePixel( rDestPt.X() );
255 0 : aPosAry.mnDestY = ImplLogicYToDevicePixel( rDestPt.Y() );
256 :
257 : const Rectangle aSrcOutRect( Point( mnOutOffX, mnOutOffY ),
258 0 : Size( mnOutWidth, mnOutHeight ) );
259 :
260 0 : ImplAdjustTwoRect( aPosAry, aSrcOutRect );
261 :
262 0 : if ( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight )
263 0 : mpGraphics->CopyBits( aPosAry, NULL, this, NULL );
264 : }
265 :
266 0 : if( mpAlphaVDev )
267 0 : mpAlphaVDev->DrawOutDev( rDestPt, rDestSize, rSrcPt, rSrcSize );
268 : }
269 :
270 0 : void OutputDevice::DrawOutDev( const Point& rDestPt, const Size& rDestSize,
271 : const Point& rSrcPt, const Size& rSrcSize,
272 : const OutputDevice& rOutDev )
273 : {
274 0 : if ( ImplIsRecordLayout() )
275 0 : return;
276 :
277 0 : if ( ROP_INVERT == meRasterOp )
278 : {
279 0 : DrawRect( Rectangle( rDestPt, rDestSize ) );
280 0 : return;
281 : }
282 :
283 0 : if ( mpMetaFile )
284 : {
285 0 : const Bitmap aBmp( rOutDev.GetBitmap( rSrcPt, rSrcSize ) );
286 0 : mpMetaFile->AddAction( new MetaBmpScaleAction( rDestPt, rDestSize, aBmp ) );
287 : }
288 :
289 0 : OUTDEV_INIT();
290 :
291 : SalTwoRect aPosAry;
292 0 : aPosAry.mnSrcX = rOutDev.ImplLogicXToDevicePixel( rSrcPt.X() );
293 0 : aPosAry.mnSrcY = rOutDev.ImplLogicYToDevicePixel( rSrcPt.Y() );
294 0 : aPosAry.mnSrcWidth = rOutDev.ImplLogicWidthToDevicePixel( rSrcSize.Width() );
295 0 : aPosAry.mnSrcHeight = rOutDev.ImplLogicHeightToDevicePixel( rSrcSize.Height() );
296 0 : aPosAry.mnDestX = ImplLogicXToDevicePixel( rDestPt.X() );
297 0 : aPosAry.mnDestY = ImplLogicYToDevicePixel( rDestPt.Y() );
298 0 : aPosAry.mnDestWidth = ImplLogicWidthToDevicePixel( rDestSize.Width() );
299 0 : aPosAry.mnDestHeight = ImplLogicHeightToDevicePixel( rDestSize.Height() );
300 :
301 0 : if( mpAlphaVDev )
302 : {
303 0 : if( rOutDev.mpAlphaVDev )
304 : {
305 : // alpha-blend source over destination
306 0 : DrawBitmapEx( rDestPt, rDestSize, rOutDev.GetBitmapEx(rSrcPt, rSrcSize) );
307 : }
308 : else
309 : {
310 0 : ImplDrawOutDevDirect( &rOutDev, aPosAry );
311 :
312 : // #i32109#: make destination rectangle opaque - source has no alpha
313 0 : mpAlphaVDev->ImplFillOpaqueRectangle( Rectangle(rDestPt, rDestSize) );
314 : }
315 : }
316 : else
317 : {
318 0 : if( rOutDev.mpAlphaVDev )
319 : {
320 : // alpha-blend source over destination
321 0 : DrawBitmapEx( rDestPt, rDestSize, rOutDev.GetBitmapEx(rSrcPt, rSrcSize) );
322 : }
323 : else
324 : {
325 : // no alpha at all, neither in source nor destination device
326 0 : ImplDrawOutDevDirect( &rOutDev, aPosAry );
327 : }
328 : }
329 : }
330 :
331 0 : void OutputDevice::CopyArea( const Point& rDestPt,
332 : const Point& rSrcPt, const Size& rSrcSize,
333 : sal_uInt16 nFlags )
334 : {
335 0 : if ( ImplIsRecordLayout() )
336 0 : return;
337 :
338 0 : RasterOp eOldRop = GetRasterOp();
339 0 : SetRasterOp( ROP_OVERPAINT );
340 :
341 0 : OUTDEV_INIT();
342 :
343 : SalTwoRect aPosAry;
344 0 : aPosAry.mnSrcWidth = ImplLogicWidthToDevicePixel( rSrcSize.Width() );
345 0 : aPosAry.mnSrcHeight = ImplLogicHeightToDevicePixel( rSrcSize.Height() );
346 :
347 0 : if ( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight )
348 : {
349 0 : aPosAry.mnSrcX = ImplLogicXToDevicePixel( rSrcPt.X() );
350 0 : aPosAry.mnSrcY = ImplLogicYToDevicePixel( rSrcPt.Y() );
351 0 : aPosAry.mnDestX = ImplLogicXToDevicePixel( rDestPt.X() );
352 0 : aPosAry.mnDestY = ImplLogicYToDevicePixel( rDestPt.Y() );
353 0 : aPosAry.mnDestWidth = aPosAry.mnSrcWidth;
354 0 : aPosAry.mnDestHeight = aPosAry.mnSrcHeight;
355 :
356 : const Rectangle aSrcOutRect( Point( mnOutOffX, mnOutOffY ),
357 0 : Size( mnOutWidth, mnOutHeight ) );
358 :
359 0 : ImplAdjustTwoRect( aPosAry, aSrcOutRect );
360 :
361 0 : CopyAreaFinal ( aPosAry, nFlags );
362 : }
363 :
364 0 : SetRasterOp( eOldRop );
365 :
366 0 : if( mpAlphaVDev )
367 0 : mpAlphaVDev->CopyArea( rDestPt, rSrcPt, rSrcSize, nFlags );
368 : }
369 :
370 0 : void OutputDevice::CopyAreaFinal( SalTwoRect& aPosAry, sal_uInt32 /*nFlags*/)
371 : {
372 0 : if (aPosAry.mnSrcWidth == 0 || aPosAry.mnSrcHeight == 0 || aPosAry.mnDestWidth == 0 || aPosAry.mnDestHeight == 0)
373 0 : return;
374 :
375 0 : aPosAry.mnDestWidth = aPosAry.mnSrcWidth;
376 0 : aPosAry.mnDestHeight = aPosAry.mnSrcHeight;
377 0 : mpGraphics->CopyBits(aPosAry, NULL, this, NULL);
378 : }
379 :
380 0 : void OutputDevice::ImplDrawFrameDev( const Point& rPt, const Point& rDevPt, const Size& rDevSize,
381 : const OutputDevice& rOutDev, const Region& rRegion )
382 : {
383 :
384 0 : GDIMetaFile* pOldMetaFile = mpMetaFile;
385 0 : bool bOldMap = mbMap;
386 0 : RasterOp eOldROP = GetRasterOp();
387 0 : mpMetaFile = NULL;
388 0 : mbMap = false;
389 0 : SetRasterOp( ROP_OVERPAINT );
390 :
391 0 : if ( !IsDeviceOutputNecessary() )
392 0 : return;
393 :
394 0 : if ( !mpGraphics )
395 : {
396 0 : if ( !ImplGetGraphics() )
397 0 : return;
398 : }
399 :
400 : // ClipRegion zuruecksetzen
401 0 : if ( rRegion.IsNull() )
402 0 : mpGraphics->ResetClipRegion();
403 : else
404 0 : ImplSelectClipRegion( rRegion );
405 :
406 : SalTwoRect aPosAry;
407 0 : aPosAry.mnSrcX = rDevPt.X();
408 0 : aPosAry.mnSrcY = rDevPt.Y();
409 0 : aPosAry.mnSrcWidth = rDevSize.Width();
410 0 : aPosAry.mnSrcHeight = rDevSize.Height();
411 0 : aPosAry.mnDestX = rPt.X();
412 0 : aPosAry.mnDestY = rPt.Y();
413 0 : aPosAry.mnDestWidth = rDevSize.Width();
414 0 : aPosAry.mnDestHeight = rDevSize.Height();
415 0 : ImplDrawOutDevDirect( &rOutDev, aPosAry );
416 :
417 : // Ensure that ClipRegion is recalculated and set
418 0 : mbInitClipRegion = true;
419 :
420 0 : SetRasterOp( eOldROP );
421 0 : mbMap = bOldMap;
422 0 : mpMetaFile = pOldMetaFile;
423 : }
424 :
425 0 : void OutputDevice::ImplGetFrameDev( const Point& rPt, const Point& rDevPt, const Size& rDevSize,
426 : OutputDevice& rDev )
427 : {
428 :
429 0 : bool bOldMap = mbMap;
430 0 : mbMap = false;
431 0 : rDev.DrawOutDev( rDevPt, rDevSize, rPt, rDevSize, *this );
432 0 : mbMap = bOldMap;
433 0 : }
434 :
435 0 : void OutputDevice::DrawBitmap( const Point& rDestPt, const Bitmap& rBitmap )
436 : {
437 0 : if( ImplIsRecordLayout() )
438 0 : return;
439 :
440 0 : const Size aSizePix( rBitmap.GetSizePixel() );
441 0 : ImplDrawBitmap( rDestPt, PixelToLogic( aSizePix ), Point(), aSizePix, rBitmap, META_BMP_ACTION );
442 :
443 0 : if( mpAlphaVDev )
444 : {
445 : // #i32109#: Make bitmap area opaque
446 0 : mpAlphaVDev->ImplFillOpaqueRectangle( Rectangle(rDestPt, PixelToLogic( aSizePix )) );
447 : }
448 : }
449 :
450 0 : void OutputDevice::DrawBitmap( const Point& rDestPt, const Size& rDestSize, const Bitmap& rBitmap )
451 : {
452 0 : if( ImplIsRecordLayout() )
453 0 : return;
454 :
455 0 : ImplDrawBitmap( rDestPt, rDestSize, Point(), rBitmap.GetSizePixel(), rBitmap, META_BMPSCALE_ACTION );
456 :
457 0 : if( mpAlphaVDev )
458 : {
459 : // #i32109#: Make bitmap area opaque
460 0 : mpAlphaVDev->ImplFillOpaqueRectangle( Rectangle(rDestPt, rDestSize) );
461 : }
462 : }
463 :
464 0 : void OutputDevice::DrawBitmap( const Point& rDestPt, const Size& rDestSize,
465 : const Point& rSrcPtPixel, const Size& rSrcSizePixel,
466 : const Bitmap& rBitmap )
467 : {
468 0 : if( ImplIsRecordLayout() )
469 0 : return;
470 :
471 0 : ImplDrawBitmap( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, rBitmap, META_BMPSCALEPART_ACTION );
472 :
473 0 : if( mpAlphaVDev )
474 : {
475 : // #i32109#: Make bitmap area opaque
476 0 : mpAlphaVDev->ImplFillOpaqueRectangle( Rectangle(rDestPt, rDestSize) );
477 : }
478 : }
479 :
480 0 : void OutputDevice::ImplDrawBitmap( const Point& rDestPt, const Size& rDestSize,
481 : const Point& rSrcPtPixel, const Size& rSrcSizePixel,
482 : const Bitmap& rBitmap, const sal_uLong nAction )
483 : {
484 :
485 0 : if ( ( mnDrawMode & DRAWMODE_NOBITMAP ) )
486 : {
487 0 : return;
488 : }
489 0 : if ( ROP_INVERT == meRasterOp )
490 : {
491 0 : DrawRect( Rectangle( rDestPt, rDestSize ) );
492 0 : return;
493 : }
494 :
495 0 : Bitmap aBmp( rBitmap );
496 :
497 0 : if ( mnDrawMode & ( DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP |
498 : DRAWMODE_GRAYBITMAP | DRAWMODE_GHOSTEDBITMAP ) )
499 : {
500 0 : if ( mnDrawMode & ( DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP ) )
501 : {
502 : sal_uInt8 cCmpVal;
503 :
504 0 : if ( mnDrawMode & DRAWMODE_BLACKBITMAP )
505 0 : cCmpVal = ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP ) ? 0x80 : 0;
506 : else
507 0 : cCmpVal = 255;
508 :
509 0 : Color aCol( cCmpVal, cCmpVal, cCmpVal );
510 0 : Push( PUSH_LINECOLOR | PUSH_FILLCOLOR );
511 0 : SetLineColor( aCol );
512 0 : SetFillColor( aCol );
513 0 : DrawRect( Rectangle( rDestPt, rDestSize ) );
514 0 : Pop();
515 0 : return;
516 : }
517 0 : else if( !!aBmp )
518 : {
519 0 : if ( mnDrawMode & DRAWMODE_GRAYBITMAP )
520 0 : aBmp.Convert( BMP_CONVERSION_8BIT_GREYS );
521 :
522 0 : if ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP )
523 0 : aBmp.Convert( BMP_CONVERSION_GHOSTED );
524 : }
525 : }
526 :
527 0 : if ( mpMetaFile )
528 : {
529 0 : switch( nAction )
530 : {
531 : case( META_BMP_ACTION ):
532 0 : mpMetaFile->AddAction( new MetaBmpAction( rDestPt, aBmp ) );
533 0 : break;
534 :
535 : case( META_BMPSCALE_ACTION ):
536 0 : mpMetaFile->AddAction( new MetaBmpScaleAction( rDestPt, rDestSize, aBmp ) );
537 0 : break;
538 :
539 : case( META_BMPSCALEPART_ACTION ):
540 : mpMetaFile->AddAction( new MetaBmpScalePartAction(
541 0 : rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, aBmp ) );
542 0 : break;
543 : }
544 : }
545 :
546 0 : OUTDEV_INIT();
547 :
548 0 : if( !aBmp.IsEmpty() )
549 : {
550 : SalTwoRect aPosAry;
551 :
552 0 : aPosAry.mnSrcX = rSrcPtPixel.X();
553 0 : aPosAry.mnSrcY = rSrcPtPixel.Y();
554 0 : aPosAry.mnSrcWidth = rSrcSizePixel.Width();
555 0 : aPosAry.mnSrcHeight = rSrcSizePixel.Height();
556 0 : aPosAry.mnDestX = ImplLogicXToDevicePixel( rDestPt.X() );
557 0 : aPosAry.mnDestY = ImplLogicYToDevicePixel( rDestPt.Y() );
558 0 : aPosAry.mnDestWidth = ImplLogicWidthToDevicePixel( rDestSize.Width() );
559 0 : aPosAry.mnDestHeight = ImplLogicHeightToDevicePixel( rDestSize.Height() );
560 :
561 0 : if ( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight )
562 : {
563 0 : const sal_uLong nMirrFlags = ImplAdjustTwoRect( aPosAry, aBmp.GetSizePixel() );
564 :
565 0 : if ( nMirrFlags )
566 0 : aBmp.Mirror( nMirrFlags );
567 :
568 0 : if ( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight )
569 : {
570 0 : if ( nAction == META_BMPSCALE_ACTION )
571 0 : ScaleBitmap (aBmp, aPosAry);
572 :
573 0 : mpGraphics->DrawBitmap( aPosAry, *aBmp.ImplGetImpBitmap()->ImplGetSalBitmap(), this );
574 : }
575 : }
576 0 : }
577 : }
578 :
579 0 : void OutputDevice::ScaleBitmap (Bitmap &rBmp, SalTwoRect &rPosAry)
580 : {
581 0 : const double nScaleX = rPosAry.mnDestWidth / static_cast<double>( rPosAry.mnSrcWidth );
582 0 : const double nScaleY = rPosAry.mnDestHeight / static_cast<double>( rPosAry.mnSrcHeight );
583 :
584 : // If subsampling, use Bitmap::Scale for subsampling for better quality.
585 0 : if ( nScaleX < 1.0 || nScaleY < 1.0 )
586 : {
587 0 : rBmp.Scale ( nScaleX, nScaleY );
588 0 : rPosAry.mnSrcWidth = rPosAry.mnDestWidth;
589 0 : rPosAry.mnSrcHeight = rPosAry.mnDestHeight;
590 : }
591 0 : }
592 :
593 0 : void OutputDevice::DrawBitmapEx( const Point& rDestPt,
594 : const BitmapEx& rBitmapEx )
595 : {
596 0 : if( ImplIsRecordLayout() )
597 0 : return;
598 :
599 0 : if( TRANSPARENT_NONE == rBitmapEx.GetTransparentType() )
600 : {
601 0 : DrawBitmap( rDestPt, rBitmapEx.GetBitmap() );
602 : }
603 : else
604 : {
605 0 : const Size aSizePix( rBitmapEx.GetSizePixel() );
606 0 : ImplDrawBitmapEx( rDestPt, PixelToLogic( aSizePix ), Point(), aSizePix, rBitmapEx, META_BMPEX_ACTION );
607 : }
608 : }
609 :
610 0 : void OutputDevice::DrawBitmapEx( const Point& rDestPt, const Size& rDestSize,
611 : const BitmapEx& rBitmapEx )
612 : {
613 0 : if( ImplIsRecordLayout() )
614 0 : return;
615 :
616 0 : if ( TRANSPARENT_NONE == rBitmapEx.GetTransparentType() )
617 : {
618 0 : DrawBitmap( rDestPt, rDestSize, rBitmapEx.GetBitmap() );
619 : }
620 : else
621 : {
622 0 : ImplDrawBitmapEx( rDestPt, rDestSize, Point(), rBitmapEx.GetSizePixel(), rBitmapEx, META_BMPEXSCALE_ACTION );
623 : }
624 : }
625 :
626 0 : void OutputDevice::DrawBitmapEx( const Point& rDestPt, const Size& rDestSize,
627 : const Point& rSrcPtPixel, const Size& rSrcSizePixel,
628 : const BitmapEx& rBitmapEx )
629 : {
630 0 : if( ImplIsRecordLayout() )
631 0 : return;
632 :
633 0 : if( TRANSPARENT_NONE == rBitmapEx.GetTransparentType() )
634 : {
635 0 : DrawBitmap( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, rBitmapEx.GetBitmap() );
636 : }
637 : else
638 : {
639 0 : ImplDrawBitmapEx( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, rBitmapEx, META_BMPEXSCALEPART_ACTION );
640 : }
641 : }
642 :
643 0 : bool OutputDevice::DrawTransformBitmapExDirect(
644 : const basegfx::B2DHomMatrix& aFullTransform,
645 : const BitmapEx& rBitmapEx)
646 : {
647 0 : bool bDone = false;
648 :
649 : // try to paint directly
650 0 : const basegfx::B2DPoint aNull(aFullTransform * basegfx::B2DPoint(0.0, 0.0));
651 0 : const basegfx::B2DPoint aTopX(aFullTransform * basegfx::B2DPoint(1.0, 0.0));
652 0 : const basegfx::B2DPoint aTopY(aFullTransform * basegfx::B2DPoint(0.0, 1.0));
653 0 : SalBitmap* pSalSrcBmp = rBitmapEx.GetBitmap().ImplGetImpBitmap()->ImplGetSalBitmap();
654 0 : SalBitmap* pSalAlphaBmp = 0;
655 :
656 0 : if(rBitmapEx.IsTransparent())
657 : {
658 0 : if(rBitmapEx.IsAlpha())
659 : {
660 0 : pSalAlphaBmp = rBitmapEx.GetAlpha().ImplGetImpBitmap()->ImplGetSalBitmap();
661 : }
662 : else
663 : {
664 0 : pSalAlphaBmp = rBitmapEx.GetMask().ImplGetImpBitmap()->ImplGetSalBitmap();
665 : }
666 : }
667 :
668 : bDone = mpGraphics->DrawTransformedBitmap(
669 : aNull,
670 : aTopX,
671 : aTopY,
672 : *pSalSrcBmp,
673 : pSalAlphaBmp,
674 0 : this);
675 :
676 0 : return bDone;
677 : };
678 :
679 0 : bool OutputDevice::TransformReduceBitmapExTargetRange(
680 : const basegfx::B2DHomMatrix& aFullTransform,
681 : basegfx::B2DRange &aVisibleRange,
682 : double &fMaximumArea)
683 : {
684 : // limit TargetRange to existing pixels (if pixel device)
685 : // first get discrete range of object
686 0 : basegfx::B2DRange aFullPixelRange(aVisibleRange);
687 :
688 0 : aFullPixelRange.transform(aFullTransform);
689 :
690 0 : if(basegfx::fTools::equalZero(aFullPixelRange.getWidth()) || basegfx::fTools::equalZero(aFullPixelRange.getHeight()))
691 : {
692 : // object is outside of visible area
693 0 : return false;
694 : }
695 :
696 : // now get discrete target pixels; start with OutDev pixel size and evtl.
697 : // intersect with active clipping area
698 : basegfx::B2DRange aOutPixel(
699 : 0.0,
700 : 0.0,
701 0 : GetOutputSizePixel().Width(),
702 0 : GetOutputSizePixel().Height());
703 :
704 0 : if(IsClipRegion())
705 : {
706 0 : const Rectangle aRegionRectangle(GetActiveClipRegion().GetBoundRect());
707 :
708 : aOutPixel.intersect( // caution! Range from rectangle, one too much (!)
709 : basegfx::B2DRange(
710 0 : aRegionRectangle.Left(),
711 0 : aRegionRectangle.Top(),
712 0 : aRegionRectangle.Right() + 1,
713 0 : aRegionRectangle.Bottom() + 1));
714 : }
715 :
716 0 : if(aOutPixel.isEmpty())
717 : {
718 : // no active output area
719 0 : return false;
720 : }
721 :
722 : // if aFullPixelRange is not completely inside of aOutPixel,
723 : // reduction of target pixels is possible
724 0 : basegfx::B2DRange aVisiblePixelRange(aFullPixelRange);
725 :
726 0 : if(!aOutPixel.isInside(aFullPixelRange))
727 : {
728 0 : aVisiblePixelRange.intersect(aOutPixel);
729 :
730 0 : if(aVisiblePixelRange.isEmpty())
731 : {
732 : // nothing in visible part, reduces to nothing
733 0 : return false;
734 : }
735 :
736 : // aVisiblePixelRange contains the reduced output area in
737 : // discrete coordinates. To make it useful everywhere, make it relative to
738 : // the object range
739 0 : basegfx::B2DHomMatrix aMakeVisibleRangeRelative;
740 :
741 0 : aVisibleRange = aVisiblePixelRange;
742 : aMakeVisibleRangeRelative.translate(
743 0 : -aFullPixelRange.getMinX(),
744 0 : -aFullPixelRange.getMinY());
745 : aMakeVisibleRangeRelative.scale(
746 0 : 1.0 / aFullPixelRange.getWidth(),
747 0 : 1.0 / aFullPixelRange.getHeight());
748 0 : aVisibleRange.transform(aMakeVisibleRangeRelative);
749 : }
750 :
751 : // for pixel devices, do *not* limit size, else OutputDevice::ImplDrawAlpha
752 : // will create another, badly scaled bitmap to do the job. Nonetheless, do a
753 : // maximum clipping of something big (1600x1280x2). Add 1.0 to avoid rounding
754 : // errors in rough estimations
755 0 : const double fNewMaxArea(aVisiblePixelRange.getWidth() * aVisiblePixelRange.getHeight());
756 :
757 0 : fMaximumArea = std::min(4096000.0, fNewMaxArea + 1.0);
758 :
759 0 : return true;
760 : }
761 :
762 0 : void OutputDevice::DrawTransformedBitmapEx(
763 : const basegfx::B2DHomMatrix& rTransformation,
764 : const BitmapEx& rBitmapEx)
765 : {
766 0 : if( ImplIsRecordLayout() )
767 0 : return;
768 :
769 0 : if(rBitmapEx.IsEmpty())
770 0 : return;
771 :
772 0 : if ( mnDrawMode & DRAWMODE_NOBITMAP )
773 0 : return;
774 :
775 : // decompose matrix to check rotation and shear
776 0 : basegfx::B2DVector aScale, aTranslate;
777 : double fRotate, fShearX;
778 0 : rTransformation.decompose(aScale, aTranslate, fRotate, fShearX);
779 0 : const bool bRotated(!basegfx::fTools::equalZero(fRotate));
780 0 : const bool bSheared(!basegfx::fTools::equalZero(fShearX));
781 0 : const bool bMirroredX(basegfx::fTools::less(aScale.getX(), 0.0));
782 0 : const bool bMirroredY(basegfx::fTools::less(aScale.getY(), 0.0));
783 : static bool bForceToOwnTransformer(false);
784 :
785 0 : if(!bForceToOwnTransformer && !bRotated && !bSheared && !bMirroredX && !bMirroredY)
786 : {
787 : // with no rotation, shear or mirroring it can be mapped to DrawBitmapEx
788 : // do *not* execute the mirroring here, it's done in the fallback
789 : // #i124580# the correct DestSize needs to be calculated based on MaxXY values
790 0 : const Point aDestPt(basegfx::fround(aTranslate.getX()), basegfx::fround(aTranslate.getY()));
791 : const Size aDestSize(
792 0 : basegfx::fround(aScale.getX() + aTranslate.getX()) - aDestPt.X(),
793 0 : basegfx::fround(aScale.getY() + aTranslate.getY()) - aDestPt.Y());
794 :
795 0 : DrawBitmapEx(aDestPt, aDestSize, rBitmapEx);
796 0 : return;
797 : }
798 :
799 : // we have rotation,shear or mirror, check if some crazy mode needs the
800 : // created transformed bitmap
801 0 : const bool bInvert(ROP_INVERT == meRasterOp);
802 0 : const bool bBitmapChangedColor(mnDrawMode & (DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP | DRAWMODE_GRAYBITMAP | DRAWMODE_GHOSTEDBITMAP));
803 0 : const bool bMetafile(mpMetaFile);
804 0 : bool bDone(false);
805 0 : const basegfx::B2DHomMatrix aFullTransform(GetViewTransformation() * rTransformation);
806 0 : const bool bTryDirectPaint(!bInvert && !bBitmapChangedColor && !bMetafile );
807 :
808 0 : if(!bForceToOwnTransformer && bTryDirectPaint)
809 : {
810 0 : bDone = DrawTransformBitmapExDirect(aFullTransform, rBitmapEx);
811 : }
812 :
813 0 : if(!bDone)
814 : {
815 : // take the fallback when no rotate and shear, but mirror (else we would have done this above)
816 0 : if(!bForceToOwnTransformer && !bRotated && !bSheared)
817 : {
818 : // with no rotation or shear it can be mapped to DrawBitmapEx
819 : // do *not* execute the mirroring here, it's done in the fallback
820 : // #i124580# the correct DestSize needs to be calculated based on MaxXY values
821 0 : const Point aDestPt(basegfx::fround(aTranslate.getX()), basegfx::fround(aTranslate.getY()));
822 : const Size aDestSize(
823 0 : basegfx::fround(aScale.getX() + aTranslate.getX()) - aDestPt.X(),
824 0 : basegfx::fround(aScale.getY() + aTranslate.getY()) - aDestPt.Y());
825 :
826 0 : DrawBitmapEx(aDestPt, aDestSize, rBitmapEx);
827 0 : return;
828 : }
829 :
830 : // fallback; create transformed bitmap the hard way (back-transform
831 : // the pixels) and paint
832 0 : basegfx::B2DRange aVisibleRange(0.0, 0.0, 1.0, 1.0);
833 :
834 : // limit maximum area to something looking good for non-pixel-based targets (metafile, printer)
835 : // by using a fixed minimum (allow at least, but no need to utilize) for good smooting and an area
836 : // dependent of original size for good quality when e.g. rotated/sheared. Still, limit to a maximum
837 : // to avoid crashes/ressource problems (ca. 1500x3000 here)
838 0 : const Size& rOriginalSizePixel(rBitmapEx.GetSizePixel());
839 0 : const double fOrigArea(rOriginalSizePixel.Width() * rOriginalSizePixel.Height() * 0.5);
840 0 : const double fOrigAreaScaled(bSheared || bRotated ? fOrigArea * 1.44 : fOrigArea);
841 0 : double fMaximumArea(std::min(4500000.0, std::max(1000000.0, fOrigAreaScaled)));
842 :
843 0 : if(!bMetafile)
844 : {
845 0 : if ( !TransformReduceBitmapExTargetRange( aFullTransform, aVisibleRange, fMaximumArea ) )
846 0 : return;
847 : }
848 :
849 0 : if(!aVisibleRange.isEmpty())
850 : {
851 : static bool bDoSmoothAtAll(true);
852 0 : BitmapEx aTransformed(rBitmapEx);
853 :
854 : // #122923# when the result needs an alpha channel due to being rotated or sheared
855 : // and thus uncovering areas, add these channels so that the own transformer (used
856 : // in getTransformed) also creates a transformed alpha channel
857 0 : if(!aTransformed.IsTransparent() && (bSheared || bRotated))
858 : {
859 : // parts will be uncovered, extend aTransformed with a mask bitmap
860 0 : const Bitmap aContent(aTransformed.GetBitmap());
861 : #if defined(MACOSX) || defined(IOS)
862 : AlphaMask aMaskBmp(aContent.GetSizePixel());
863 : aMaskBmp.Erase(0);
864 : #else
865 0 : Bitmap aMaskBmp(aContent.GetSizePixel(), 1);
866 0 : aMaskBmp.Erase(Color(COL_BLACK)); // #122758# Initialize to non-transparent
867 : #endif
868 0 : aTransformed = BitmapEx(aContent, aMaskBmp);
869 : }
870 :
871 0 : aTransformed = aTransformed.getTransformed(
872 : aFullTransform,
873 : aVisibleRange,
874 : fMaximumArea,
875 0 : bDoSmoothAtAll);
876 0 : basegfx::B2DRange aTargetRange(0.0, 0.0, 1.0, 1.0);
877 :
878 : // get logic object target range
879 0 : aTargetRange.transform(rTransformation);
880 :
881 : // get from unified/relative VisibleRange to logoc one
882 : aVisibleRange.transform(
883 : basegfx::tools::createScaleTranslateB2DHomMatrix(
884 : aTargetRange.getRange(),
885 0 : aTargetRange.getMinimum()));
886 :
887 : // extract point and size; do not remove size, the bitmap may have been prepared reduced by purpose
888 : // #i124580# the correct DestSize needs to be calculated based on MaxXY values
889 0 : const Point aDestPt(basegfx::fround(aVisibleRange.getMinX()), basegfx::fround(aVisibleRange.getMinY()));
890 : const Size aDestSize(
891 0 : basegfx::fround(aVisibleRange.getMaxX()) - aDestPt.X(),
892 0 : basegfx::fround(aVisibleRange.getMaxY()) - aDestPt.Y());
893 :
894 0 : DrawBitmapEx(aDestPt, aDestSize, aTransformed);
895 : }
896 0 : }
897 : }
898 :
899 0 : void OutputDevice::ImplDrawBitmapEx( const Point& rDestPt, const Size& rDestSize,
900 : const Point& rSrcPtPixel, const Size& rSrcSizePixel,
901 : const BitmapEx& rBitmapEx, const sal_uLong nAction )
902 : {
903 : OSL_ENSURE(TRANSPARENT_NONE != rBitmapEx.GetTransparentType(), "ImplDrawBitmapEx not needed, no transparency in BitmapEx (!)");
904 :
905 0 : if ( mnDrawMode & DRAWMODE_NOBITMAP )
906 0 : return;
907 :
908 0 : if ( ROP_INVERT == meRasterOp )
909 : {
910 0 : DrawRect( Rectangle( rDestPt, rDestSize ) );
911 0 : return;
912 : }
913 :
914 0 : BitmapEx aBmpEx( rBitmapEx );
915 :
916 0 : if ( mnDrawMode & ( DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP |
917 : DRAWMODE_GRAYBITMAP | DRAWMODE_GHOSTEDBITMAP ) )
918 : {
919 0 : if ( mnDrawMode & ( DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP ) )
920 : {
921 0 : Bitmap aColorBmp( aBmpEx.GetSizePixel(), ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP ) ? 4 : 1 );
922 : sal_uInt8 cCmpVal;
923 :
924 0 : if ( mnDrawMode & DRAWMODE_BLACKBITMAP )
925 0 : cCmpVal = ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP ) ? 0x80 : 0;
926 : else
927 0 : cCmpVal = 255;
928 :
929 0 : aColorBmp.Erase( Color( cCmpVal, cCmpVal, cCmpVal ) );
930 :
931 0 : if( aBmpEx.IsAlpha() )
932 : {
933 : // Create one-bit mask out of alpha channel, by
934 : // thresholding it at alpha=0.5. As
935 : // DRAWMODE_BLACK/WHITEBITMAP requires monochrome
936 : // output, having alpha-induced grey levels is not
937 : // acceptable.
938 0 : Bitmap aMask( aBmpEx.GetAlpha().GetBitmap() );
939 0 : aMask.MakeMono( 129 );
940 0 : aBmpEx = BitmapEx( aColorBmp, aMask );
941 : }
942 : else
943 : {
944 0 : aBmpEx = BitmapEx( aColorBmp, aBmpEx.GetMask() );
945 0 : }
946 : }
947 0 : else if( !!aBmpEx )
948 : {
949 0 : if ( mnDrawMode & DRAWMODE_GRAYBITMAP )
950 0 : aBmpEx.Convert( BMP_CONVERSION_8BIT_GREYS );
951 :
952 0 : if ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP )
953 0 : aBmpEx.Convert( BMP_CONVERSION_GHOSTED );
954 : }
955 : }
956 :
957 0 : if ( mpMetaFile )
958 : {
959 0 : switch( nAction )
960 : {
961 : case( META_BMPEX_ACTION ):
962 0 : mpMetaFile->AddAction( new MetaBmpExAction( rDestPt, aBmpEx ) );
963 0 : break;
964 :
965 : case( META_BMPEXSCALE_ACTION ):
966 0 : mpMetaFile->AddAction( new MetaBmpExScaleAction( rDestPt, rDestSize, aBmpEx ) );
967 0 : break;
968 :
969 : case( META_BMPEXSCALEPART_ACTION ):
970 : mpMetaFile->AddAction( new MetaBmpExScalePartAction( rDestPt, rDestSize,
971 0 : rSrcPtPixel, rSrcSizePixel, aBmpEx ) );
972 0 : break;
973 : }
974 : }
975 :
976 0 : OUTDEV_INIT();
977 :
978 0 : DrawDeviceBitmap( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, aBmpEx );
979 : }
980 :
981 0 : void OutputDevice::DrawDeviceBitmap( const Point& rDestPt, const Size& rDestSize,
982 : const Point& rSrcPtPixel, const Size& rSrcSizePixel,
983 : BitmapEx& rBmpEx )
984 : {
985 0 : if(rBmpEx.IsAlpha())
986 : {
987 0 : Size aDestSizePixel(LogicToPixel(rDestSize));
988 :
989 0 : BitmapEx aScaledBitmapEx(rBmpEx);
990 0 : Point aSrcPtPixel(rSrcPtPixel);
991 0 : Size aSrcSizePixel(rSrcSizePixel);
992 :
993 : // we have beautiful scaling algorithms, let's use them
994 0 : if (aDestSizePixel != rSrcSizePixel && rSrcSizePixel.Width() != 0 && rSrcSizePixel.Height() != 0)
995 : {
996 0 : double fScaleX = double(aDestSizePixel.Width()) / rSrcSizePixel.Width();
997 0 : double fScaleY = double(aDestSizePixel.Height()) / rSrcSizePixel.Height();
998 :
999 0 : aScaledBitmapEx.Scale(fScaleX, fScaleY);
1000 :
1001 0 : aSrcSizePixel = aDestSizePixel;
1002 0 : aSrcPtPixel.X() = rSrcPtPixel.X() * fScaleX;
1003 0 : aSrcPtPixel.Y() = rSrcPtPixel.Y() * fScaleY;
1004 : }
1005 0 : ImplDrawAlpha(aScaledBitmapEx.GetBitmap(), aScaledBitmapEx.GetAlpha(), rDestPt, rDestSize, aSrcPtPixel, aSrcSizePixel);
1006 0 : return;
1007 : }
1008 :
1009 0 : if( !( !rBmpEx ) )
1010 : {
1011 : SalTwoRect aPosAry;
1012 :
1013 0 : aPosAry.mnSrcX = rSrcPtPixel.X();
1014 0 : aPosAry.mnSrcY = rSrcPtPixel.Y();
1015 0 : aPosAry.mnSrcWidth = rSrcSizePixel.Width();
1016 0 : aPosAry.mnSrcHeight = rSrcSizePixel.Height();
1017 0 : aPosAry.mnDestX = ImplLogicXToDevicePixel( rDestPt.X() );
1018 0 : aPosAry.mnDestY = ImplLogicYToDevicePixel( rDestPt.Y() );
1019 0 : aPosAry.mnDestWidth = ImplLogicWidthToDevicePixel( rDestSize.Width() );
1020 0 : aPosAry.mnDestHeight = ImplLogicHeightToDevicePixel( rDestSize.Height() );
1021 :
1022 0 : const sal_uLong nMirrFlags = ImplAdjustTwoRect( aPosAry, rBmpEx.GetSizePixel() );
1023 :
1024 0 : if( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight )
1025 : {
1026 :
1027 0 : if( nMirrFlags )
1028 0 : rBmpEx.Mirror( nMirrFlags );
1029 :
1030 0 : const SalBitmap* pSalSrcBmp = rBmpEx.ImplGetBitmapImpBitmap()->ImplGetSalBitmap();
1031 0 : const ImpBitmap* pMaskBmp = rBmpEx.ImplGetMaskImpBitmap();
1032 :
1033 0 : if ( pMaskBmp )
1034 : {
1035 0 : SalBitmap* pSalAlphaBmp = pMaskBmp->ImplGetSalBitmap();
1036 0 : bool bTryDirectPaint(pSalSrcBmp && pSalAlphaBmp);
1037 :
1038 0 : if(bTryDirectPaint)
1039 : {
1040 : // only paint direct when no scaling and no MapMode, else the
1041 : // more expensive conversions may be done for short-time Bitmap/BitmapEx
1042 : // used for buffering only
1043 0 : if(!IsMapMode() && aPosAry.mnSrcWidth == aPosAry.mnDestWidth && aPosAry.mnSrcHeight == aPosAry.mnDestHeight)
1044 : {
1045 0 : bTryDirectPaint = false;
1046 : }
1047 : }
1048 :
1049 0 : if(bTryDirectPaint && mpGraphics->DrawAlphaBitmap(aPosAry, *pSalSrcBmp, *pSalAlphaBmp, this))
1050 : {
1051 : // tried to paint as alpha directly. If tis worked, we are done (except
1052 : // alpha, see below)
1053 : }
1054 : else
1055 : {
1056 : // #4919452# reduce operation area to bounds of
1057 : // cliprect. since masked transparency involves
1058 : // creation of a large vdev and copying the screen
1059 : // content into that (slooow read from framebuffer),
1060 : // that should considerably increase performance for
1061 : // large bitmaps and small clippings.
1062 :
1063 : // Note that this optimization is a workaround for a
1064 : // Writer peculiarity, namely, to decompose background
1065 : // graphics into myriads of disjunct, tiny
1066 : // rectangles. That otherwise kills us here, since for
1067 : // transparent output, SAL always prepares the whole
1068 : // bitmap, if aPosAry contains the whole bitmap (and
1069 : // it's _not_ to blame for that).
1070 :
1071 : // Note the call to ImplPixelToDevicePixel(), since
1072 : // aPosAry already contains the mnOutOff-offsets, they
1073 : // also have to be applied to the region
1074 0 : Rectangle aClipRegionBounds( ImplPixelToDevicePixel(maRegion).GetBoundRect() );
1075 :
1076 : // TODO: Also respect scaling (that's a bit tricky,
1077 : // since the source points have to move fractional
1078 : // amounts (which is not possible, thus has to be
1079 : // emulated by increases copy area)
1080 : // const double nScaleX( aPosAry.mnDestWidth / aPosAry.mnSrcWidth );
1081 : // const double nScaleY( aPosAry.mnDestHeight / aPosAry.mnSrcHeight );
1082 :
1083 : // for now, only identity scales allowed
1084 0 : if( !aClipRegionBounds.IsEmpty() &&
1085 0 : aPosAry.mnDestWidth == aPosAry.mnSrcWidth &&
1086 0 : aPosAry.mnDestHeight == aPosAry.mnSrcHeight )
1087 : {
1088 : // now intersect dest rect with clip region
1089 : aClipRegionBounds.Intersection( Rectangle( aPosAry.mnDestX,
1090 : aPosAry.mnDestY,
1091 0 : aPosAry.mnDestX + aPosAry.mnDestWidth - 1,
1092 0 : aPosAry.mnDestY + aPosAry.mnDestHeight - 1 ) );
1093 :
1094 : // Note: I could theoretically optimize away the
1095 : // DrawBitmap below, if the region is empty
1096 : // here. Unfortunately, cannot rule out that
1097 : // somebody relies on the side effects.
1098 0 : if( !aClipRegionBounds.IsEmpty() )
1099 : {
1100 0 : aPosAry.mnSrcX += aClipRegionBounds.Left() - aPosAry.mnDestX;
1101 0 : aPosAry.mnSrcY += aClipRegionBounds.Top() - aPosAry.mnDestY;
1102 0 : aPosAry.mnSrcWidth = aClipRegionBounds.GetWidth();
1103 0 : aPosAry.mnSrcHeight = aClipRegionBounds.GetHeight();
1104 :
1105 0 : aPosAry.mnDestX = aClipRegionBounds.Left();
1106 0 : aPosAry.mnDestY = aClipRegionBounds.Top();
1107 0 : aPosAry.mnDestWidth = aClipRegionBounds.GetWidth();
1108 0 : aPosAry.mnDestHeight = aClipRegionBounds.GetHeight();
1109 : }
1110 : }
1111 :
1112 : mpGraphics->DrawBitmap( aPosAry, *pSalSrcBmp,
1113 0 : *pMaskBmp->ImplGetSalBitmap(),
1114 0 : this );
1115 : }
1116 :
1117 : // #110958# Paint mask to alpha channel. Luckily, the
1118 : // black and white representation of the mask maps to
1119 : // the alpha channel
1120 :
1121 : // #i25167# Restrict mask painting to _opaque_ areas
1122 : // of the mask, otherwise we spoil areas where no
1123 : // bitmap content was ever visible. Interestingly
1124 : // enough, this can be achieved by taking the mask as
1125 : // the transparency mask of itself
1126 0 : if( mpAlphaVDev )
1127 : mpAlphaVDev->DrawBitmapEx( rDestPt,
1128 : rDestSize,
1129 : BitmapEx( rBmpEx.GetMask(),
1130 0 : rBmpEx.GetMask() ) );
1131 : }
1132 : else
1133 : {
1134 0 : mpGraphics->DrawBitmap( aPosAry, *pSalSrcBmp, this );
1135 :
1136 0 : if( mpAlphaVDev )
1137 : {
1138 : // #i32109#: Make bitmap area opaque
1139 0 : mpAlphaVDev->ImplFillOpaqueRectangle( Rectangle(rDestPt, rDestSize) );
1140 : }
1141 : }
1142 : }
1143 : }
1144 : }
1145 :
1146 0 : void OutputDevice::DrawMask( const Point& rDestPt,
1147 : const Bitmap& rBitmap, const Color& rMaskColor )
1148 : {
1149 0 : const Size aSizePix( rBitmap.GetSizePixel() );
1150 0 : DrawMask( rDestPt, PixelToLogic( aSizePix ), Point(), aSizePix, rBitmap, rMaskColor, META_MASK_ACTION );
1151 0 : }
1152 :
1153 0 : void OutputDevice::DrawMask( const Point& rDestPt, const Size& rDestSize,
1154 : const Bitmap& rBitmap, const Color& rMaskColor )
1155 : {
1156 0 : DrawMask( rDestPt, rDestSize, Point(), rBitmap.GetSizePixel(), rBitmap, rMaskColor, META_MASKSCALE_ACTION );
1157 0 : }
1158 :
1159 0 : void OutputDevice::DrawMask( const Point& rDestPt, const Size& rDestSize,
1160 : const Point& rSrcPtPixel, const Size& rSrcSizePixel,
1161 : const Bitmap& rBitmap, const Color& rMaskColor,
1162 : const sal_uLong nAction )
1163 : {
1164 0 : if( ImplIsRecordLayout() )
1165 0 : return;
1166 :
1167 0 : if( ROP_INVERT == meRasterOp )
1168 : {
1169 0 : DrawRect( Rectangle( rDestPt, rDestSize ) );
1170 0 : return;
1171 : }
1172 :
1173 0 : if ( mpMetaFile )
1174 : {
1175 0 : switch( nAction )
1176 : {
1177 : case( META_MASK_ACTION ):
1178 : mpMetaFile->AddAction( new MetaMaskAction( rDestPt,
1179 0 : rBitmap, rMaskColor ) );
1180 0 : break;
1181 :
1182 : case( META_MASKSCALE_ACTION ):
1183 : mpMetaFile->AddAction( new MetaMaskScaleAction( rDestPt,
1184 0 : rDestSize, rBitmap, rMaskColor ) );
1185 0 : break;
1186 :
1187 : case( META_MASKSCALEPART_ACTION ):
1188 : mpMetaFile->AddAction( new MetaMaskScalePartAction( rDestPt, rDestSize,
1189 0 : rSrcPtPixel, rSrcSizePixel, rBitmap, rMaskColor ) );
1190 0 : break;
1191 : }
1192 : }
1193 :
1194 0 : OUTDEV_INIT();
1195 :
1196 0 : if ( OUTDEV_PRINTER == meOutDevType )
1197 : {
1198 0 : ImplPrintMask( rBitmap, rMaskColor, rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel );
1199 0 : return;
1200 : }
1201 :
1202 0 : const ImpBitmap* pImpBmp = rBitmap.ImplGetImpBitmap();
1203 0 : if ( pImpBmp )
1204 : {
1205 : SalTwoRect aPosAry;
1206 :
1207 0 : aPosAry.mnSrcX = rSrcPtPixel.X();
1208 0 : aPosAry.mnSrcY = rSrcPtPixel.Y();
1209 0 : aPosAry.mnSrcWidth = rSrcSizePixel.Width();
1210 0 : aPosAry.mnSrcHeight = rSrcSizePixel.Height();
1211 0 : aPosAry.mnDestX = ImplLogicXToDevicePixel( rDestPt.X() );
1212 0 : aPosAry.mnDestY = ImplLogicYToDevicePixel( rDestPt.Y() );
1213 0 : aPosAry.mnDestWidth = ImplLogicWidthToDevicePixel( rDestSize.Width() );
1214 0 : aPosAry.mnDestHeight = ImplLogicHeightToDevicePixel( rDestSize.Height() );
1215 :
1216 : // we don't want to mirror via cooridates
1217 0 : const sal_uLong nMirrFlags = ImplAdjustTwoRect( aPosAry, pImpBmp->ImplGetSize() );
1218 :
1219 : // check if output is necessary
1220 0 : if( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight )
1221 : {
1222 :
1223 0 : if( nMirrFlags )
1224 : {
1225 0 : Bitmap aTmp( rBitmap );
1226 0 : aTmp.Mirror( nMirrFlags );
1227 0 : mpGraphics->DrawMask( aPosAry, *aTmp.ImplGetImpBitmap()->ImplGetSalBitmap(),
1228 0 : ImplColorToSal( rMaskColor ) , this);
1229 : }
1230 : else
1231 0 : mpGraphics->DrawMask( aPosAry, *pImpBmp->ImplGetSalBitmap(),
1232 0 : ImplColorToSal( rMaskColor ), this );
1233 :
1234 : }
1235 : }
1236 :
1237 : // TODO: Use mask here
1238 0 : if( mpAlphaVDev )
1239 : {
1240 0 : const Bitmap& rMask( rBitmap.CreateMask( rMaskColor ) );
1241 :
1242 : // #i25167# Restrict mask painting to _opaque_ areas
1243 : // of the mask, otherwise we spoil areas where no
1244 : // bitmap content was ever visible. Interestingly
1245 : // enough, this can be achieved by taking the mask as
1246 : // the transparency mask of itself
1247 : mpAlphaVDev->DrawBitmapEx( rDestPt,
1248 : rDestSize,
1249 : rSrcPtPixel,
1250 : rSrcSizePixel,
1251 0 : BitmapEx( rMask, rMask ) );
1252 : }
1253 : }
1254 :
1255 : namespace
1256 : {
1257 0 : BitmapEx makeDisabledBitmap(const Bitmap &rBitmap)
1258 : {
1259 0 : const Size aTotalSize( rBitmap.GetSizePixel() );
1260 0 : Bitmap aGrey( aTotalSize, 8, &Bitmap::GetGreyPalette( 256 ) );
1261 0 : AlphaMask aGreyAlphaMask( aTotalSize );
1262 0 : BitmapReadAccess* pBmp = const_cast<Bitmap&>(rBitmap).AcquireReadAccess();
1263 0 : BitmapWriteAccess* pGrey = aGrey.AcquireWriteAccess();
1264 0 : BitmapWriteAccess* pGreyAlphaMask = aGreyAlphaMask.AcquireWriteAccess();
1265 :
1266 0 : if( pBmp && pGrey && pGreyAlphaMask )
1267 : {
1268 0 : BitmapColor aGreyVal( 0 );
1269 0 : BitmapColor aGreyAlphaMaskVal( 0 );
1270 0 : const int nLeft = 0, nRight = aTotalSize.Width();
1271 0 : const int nTop = 0, nBottom = nTop + aTotalSize.Height();
1272 :
1273 0 : for( int nY = nTop; nY < nBottom; ++nY )
1274 : {
1275 0 : for( int nX = nLeft; nX < nRight; ++nX )
1276 : {
1277 0 : aGreyVal.SetIndex( pBmp->GetLuminance( nY, nX ) );
1278 0 : pGrey->SetPixel( nY, nX, aGreyVal );
1279 :
1280 0 : aGreyAlphaMaskVal.SetIndex( static_cast< sal_uInt8 >( 128ul ) );
1281 0 : pGreyAlphaMask->SetPixel( nY, nX, aGreyAlphaMaskVal );
1282 : }
1283 0 : }
1284 : }
1285 :
1286 0 : const_cast<Bitmap&>(rBitmap).ReleaseAccess( pBmp );
1287 0 : aGrey.ReleaseAccess( pGrey );
1288 0 : aGreyAlphaMask.ReleaseAccess( pGreyAlphaMask );
1289 0 : return BitmapEx( aGrey, aGreyAlphaMask );
1290 : }
1291 : }
1292 :
1293 0 : void OutputDevice::DrawImage( const Point& rPos, const Image& rImage, sal_uInt16 nStyle )
1294 : {
1295 : DBG_ASSERT( GetOutDevType() != OUTDEV_PRINTER, "DrawImage(): Images can't be drawn on any mprinter" );
1296 :
1297 0 : if( !rImage.mpImplData || ImplIsRecordLayout() )
1298 0 : return;
1299 :
1300 0 : switch( rImage.mpImplData->meType )
1301 : {
1302 : case IMAGETYPE_BITMAP:
1303 : {
1304 0 : const Bitmap &rBitmap = *static_cast< Bitmap* >( rImage.mpImplData->mpData );
1305 0 : if( nStyle & IMAGE_DRAW_DISABLE )
1306 0 : DrawBitmapEx( rPos, makeDisabledBitmap(rBitmap) );
1307 : else
1308 0 : DrawBitmap( rPos, rBitmap );
1309 : }
1310 0 : break;
1311 :
1312 : case IMAGETYPE_IMAGE:
1313 : {
1314 0 : ImplImageData* pData = static_cast< ImplImageData* >( rImage.mpImplData->mpData );
1315 :
1316 0 : if( !pData->mpImageBitmap )
1317 : {
1318 0 : const Size aSize( pData->maBmpEx.GetSizePixel() );
1319 :
1320 0 : pData->mpImageBitmap = new ImplImageBmp;
1321 0 : pData->mpImageBitmap->Create( pData->maBmpEx, aSize.Width(), aSize.Height(), 1 );
1322 : }
1323 :
1324 0 : pData->mpImageBitmap->Draw( 0, this, rPos, nStyle );
1325 : }
1326 0 : break;
1327 :
1328 : default:
1329 0 : break;
1330 : }
1331 : }
1332 :
1333 0 : void OutputDevice::DrawImage( const Point& rPos, const Size& rSize,
1334 : const Image& rImage, sal_uInt16 nStyle )
1335 : {
1336 : DBG_ASSERT( GetOutDevType() != OUTDEV_PRINTER, "DrawImage(): Images can't be drawn on any mprinter" );
1337 :
1338 0 : if( rImage.mpImplData && !ImplIsRecordLayout() )
1339 : {
1340 0 : switch( rImage.mpImplData->meType )
1341 : {
1342 : case IMAGETYPE_BITMAP:
1343 : {
1344 0 : const Bitmap &rBitmap = *static_cast< Bitmap* >( rImage.mpImplData->mpData );
1345 0 : if( nStyle & IMAGE_DRAW_DISABLE )
1346 0 : DrawBitmapEx( rPos, rSize, makeDisabledBitmap(rBitmap) );
1347 : else
1348 0 : DrawBitmap( rPos, rSize, rBitmap );
1349 : }
1350 0 : break;
1351 :
1352 : case IMAGETYPE_IMAGE:
1353 : {
1354 0 : ImplImageData* pData = static_cast< ImplImageData* >( rImage.mpImplData->mpData );
1355 :
1356 0 : if ( !pData->mpImageBitmap )
1357 : {
1358 0 : const Size aSize( pData->maBmpEx.GetSizePixel() );
1359 :
1360 0 : pData->mpImageBitmap = new ImplImageBmp;
1361 0 : pData->mpImageBitmap->Create( pData->maBmpEx, aSize.Width(), aSize.Height(), 1 );
1362 : }
1363 :
1364 0 : pData->mpImageBitmap->Draw( 0, this, rPos, nStyle, &rSize );
1365 : }
1366 0 : break;
1367 :
1368 : default:
1369 0 : break;
1370 : }
1371 : }
1372 0 : }
1373 :
1374 0 : Bitmap OutputDevice::GetBitmap( const Point& rSrcPt, const Size& rSize ) const
1375 : {
1376 : OSL_ENSURE(OUTDEV_PRINTER != GetOutDevType(), "OutputDevice::GetBitmap with sorce type OUTDEV_PRINTER should not be used (!)");
1377 :
1378 0 : Bitmap aBmp;
1379 0 : long nX = ImplLogicXToDevicePixel( rSrcPt.X() );
1380 0 : long nY = ImplLogicYToDevicePixel( rSrcPt.Y() );
1381 0 : long nWidth = ImplLogicWidthToDevicePixel( rSize.Width() );
1382 0 : long nHeight = ImplLogicHeightToDevicePixel( rSize.Height() );
1383 :
1384 0 : if ( mpGraphics || ( (OutputDevice*) this )->ImplGetGraphics() )
1385 : {
1386 0 : if ( nWidth > 0 && nHeight > 0 && nX <= (mnOutWidth + mnOutOffX) && nY <= (mnOutHeight + mnOutOffY))
1387 : {
1388 0 : Rectangle aRect( Point( nX, nY ), Size( nWidth, nHeight ) );
1389 0 : bool bClipped = false;
1390 :
1391 : // X-Coordinate outside of draw area?
1392 0 : if ( nX < mnOutOffX )
1393 : {
1394 0 : nWidth -= ( mnOutOffX - nX );
1395 0 : nX = mnOutOffX;
1396 0 : bClipped = true;
1397 : }
1398 :
1399 : // Y-Coordinate outside of draw area?
1400 0 : if ( nY < mnOutOffY )
1401 : {
1402 0 : nHeight -= ( mnOutOffY - nY );
1403 0 : nY = mnOutOffY;
1404 0 : bClipped = true;
1405 : }
1406 :
1407 : // Width outside of draw area?
1408 0 : if ( (nWidth + nX) > (mnOutWidth + mnOutOffX) )
1409 : {
1410 0 : nWidth = mnOutOffX + mnOutWidth - nX;
1411 0 : bClipped = true;
1412 : }
1413 :
1414 : // Height outside of draw area?
1415 0 : if ( (nHeight + nY) > (mnOutHeight + mnOutOffY) )
1416 : {
1417 0 : nHeight = mnOutOffY + mnOutHeight - nY;
1418 0 : bClipped = true;
1419 : }
1420 :
1421 0 : if ( bClipped )
1422 : {
1423 : // If the visible part has been clipped, we have to create a
1424 : // Bitmap with the correct size in which we copy the clipped
1425 : // Bitmap to the correct position.
1426 0 : VirtualDevice aVDev( *this );
1427 :
1428 0 : if ( aVDev.SetOutputSizePixel( aRect.GetSize() ) )
1429 : {
1430 0 : if ( ((OutputDevice*)&aVDev)->mpGraphics || ((OutputDevice*)&aVDev)->ImplGetGraphics() )
1431 : {
1432 : SalTwoRect aPosAry;
1433 :
1434 0 : aPosAry.mnSrcX = nX;
1435 0 : aPosAry.mnSrcY = nY;
1436 0 : aPosAry.mnSrcWidth = nWidth;
1437 0 : aPosAry.mnSrcHeight = nHeight;
1438 0 : aPosAry.mnDestX = ( aRect.Left() < mnOutOffX ) ? ( mnOutOffX - aRect.Left() ) : 0L;
1439 0 : aPosAry.mnDestY = ( aRect.Top() < mnOutOffY ) ? ( mnOutOffY - aRect.Top() ) : 0L;
1440 0 : aPosAry.mnDestWidth = nWidth;
1441 0 : aPosAry.mnDestHeight = nHeight;
1442 :
1443 0 : if ( (nWidth > 0) && (nHeight > 0) )
1444 : {
1445 0 : (((OutputDevice*)&aVDev)->mpGraphics)->CopyBits( aPosAry, mpGraphics, this, this );
1446 : }
1447 : else
1448 : {
1449 : OSL_ENSURE(false, "CopyBits with negative width or height (!)");
1450 : }
1451 :
1452 0 : aBmp = aVDev.GetBitmap( Point(), aVDev.GetOutputSizePixel() );
1453 : }
1454 : else
1455 0 : bClipped = false;
1456 : }
1457 : else
1458 0 : bClipped = false;
1459 : }
1460 :
1461 0 : if ( !bClipped )
1462 : {
1463 0 : SalBitmap* pSalBmp = mpGraphics->GetBitmap( nX, nY, nWidth, nHeight, this );
1464 :
1465 0 : if( pSalBmp )
1466 : {
1467 0 : ImpBitmap* pImpBmp = new ImpBitmap;
1468 0 : pImpBmp->ImplSetSalBitmap( pSalBmp );
1469 0 : aBmp.ImplSetImpBitmap( pImpBmp );
1470 : }
1471 : }
1472 : }
1473 : }
1474 :
1475 0 : return aBmp;
1476 : }
1477 :
1478 0 : BitmapEx OutputDevice::GetBitmapEx( const Point& rSrcPt, const Size& rSize ) const
1479 : {
1480 :
1481 : // #110958# Extract alpha value from VDev, if any
1482 0 : if( mpAlphaVDev )
1483 : {
1484 0 : Bitmap aAlphaBitmap( mpAlphaVDev->GetBitmap( rSrcPt, rSize ) );
1485 :
1486 : // ensure 8 bit alpha
1487 0 : if( aAlphaBitmap.GetBitCount() > 8 )
1488 0 : aAlphaBitmap.Convert( BMP_CONVERSION_8BIT_GREYS );
1489 :
1490 0 : return BitmapEx(GetBitmap( rSrcPt, rSize ), AlphaMask( aAlphaBitmap ) );
1491 : }
1492 : else
1493 0 : return GetBitmap( rSrcPt, rSize );
1494 : }
1495 :
1496 0 : Color OutputDevice::GetPixel( const Point& rPt ) const
1497 : {
1498 :
1499 0 : Color aColor;
1500 :
1501 0 : if ( mpGraphics || ((OutputDevice*)this)->ImplGetGraphics() )
1502 : {
1503 0 : if ( mbInitClipRegion )
1504 0 : ((OutputDevice*)this)->ImplInitClipRegion();
1505 :
1506 0 : if ( !mbOutputClipped )
1507 : {
1508 0 : const long nX = ImplLogicXToDevicePixel( rPt.X() );
1509 0 : const long nY = ImplLogicYToDevicePixel( rPt.Y() );
1510 0 : const SalColor aSalCol = mpGraphics->GetPixel( nX, nY, this );
1511 0 : aColor.SetRed( SALCOLOR_RED( aSalCol ) );
1512 0 : aColor.SetGreen( SALCOLOR_GREEN( aSalCol ) );
1513 0 : aColor.SetBlue( SALCOLOR_BLUE( aSalCol ) );
1514 : }
1515 : }
1516 0 : return aColor;
1517 : }
1518 :
1519 0 : void OutputDevice::DrawPixel( const Point& rPt )
1520 : {
1521 :
1522 0 : if ( mpMetaFile )
1523 0 : mpMetaFile->AddAction( new MetaPointAction( rPt ) );
1524 :
1525 0 : if ( !IsDeviceOutputNecessary() || !mbLineColor || ImplIsRecordLayout() )
1526 0 : return;
1527 :
1528 0 : Point aPt = ImplLogicToDevicePixel( rPt );
1529 :
1530 0 : if ( !mpGraphics )
1531 : {
1532 0 : if ( !ImplGetGraphics() )
1533 0 : return;
1534 : }
1535 :
1536 0 : if ( mbInitClipRegion )
1537 0 : ImplInitClipRegion();
1538 0 : if ( mbOutputClipped )
1539 0 : return;
1540 :
1541 0 : if ( mbInitLineColor )
1542 0 : ImplInitLineColor();
1543 :
1544 0 : mpGraphics->DrawPixel( aPt.X(), aPt.Y(), this );
1545 :
1546 0 : if( mpAlphaVDev )
1547 0 : mpAlphaVDev->DrawPixel( rPt );
1548 : }
1549 :
1550 0 : void OutputDevice::DrawPixel( const Point& rPt, const Color& rColor )
1551 : {
1552 :
1553 0 : Color aColor = ImplDrawModeToColor( rColor );
1554 :
1555 0 : if ( mpMetaFile )
1556 0 : mpMetaFile->AddAction( new MetaPixelAction( rPt, aColor ) );
1557 :
1558 0 : if ( !IsDeviceOutputNecessary() || ImplIsColorTransparent( aColor ) || ImplIsRecordLayout() )
1559 0 : return;
1560 :
1561 0 : Point aPt = ImplLogicToDevicePixel( rPt );
1562 :
1563 0 : if ( !mpGraphics )
1564 : {
1565 0 : if ( !ImplGetGraphics() )
1566 0 : return;
1567 : }
1568 :
1569 0 : if ( mbInitClipRegion )
1570 0 : ImplInitClipRegion();
1571 0 : if ( mbOutputClipped )
1572 0 : return;
1573 :
1574 0 : mpGraphics->DrawPixel( aPt.X(), aPt.Y(), ImplColorToSal( aColor ), this );
1575 :
1576 0 : if( mpAlphaVDev )
1577 0 : mpAlphaVDev->DrawPixel( rPt );
1578 : }
1579 :
1580 0 : void OutputDevice::DrawPixel( const Polygon& rPts, const Color* pColors )
1581 : {
1582 0 : if ( !pColors )
1583 0 : DrawPixel( rPts, GetLineColor() );
1584 : else
1585 : {
1586 : DBG_ASSERT( pColors, "OutputDevice::DrawPixel: No color array specified" );
1587 :
1588 0 : const sal_uInt16 nSize = rPts.GetSize();
1589 :
1590 0 : if ( nSize )
1591 : {
1592 0 : if ( mpMetaFile )
1593 0 : for ( sal_uInt16 i = 0; i < nSize; i++ )
1594 0 : mpMetaFile->AddAction( new MetaPixelAction( rPts[ i ], pColors[ i ] ) );
1595 :
1596 0 : if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
1597 0 : return;
1598 :
1599 0 : if ( mpGraphics || ImplGetGraphics() )
1600 : {
1601 0 : if ( mbInitClipRegion )
1602 0 : ImplInitClipRegion();
1603 :
1604 0 : if ( mbOutputClipped )
1605 0 : return;
1606 :
1607 0 : for ( sal_uInt16 i = 0; i < nSize; i++ )
1608 : {
1609 0 : const Point aPt( ImplLogicToDevicePixel( rPts[ i ] ) );
1610 0 : mpGraphics->DrawPixel( aPt.X(), aPt.Y(), ImplColorToSal( pColors[ i ] ), this );
1611 : }
1612 : }
1613 : }
1614 : }
1615 :
1616 0 : if( mpAlphaVDev )
1617 0 : mpAlphaVDev->DrawPixel( rPts, pColors );
1618 : }
1619 :
1620 0 : void OutputDevice::DrawPixel( const Polygon& rPts, const Color& rColor )
1621 : {
1622 0 : if( rColor != COL_TRANSPARENT && ! ImplIsRecordLayout() )
1623 : {
1624 0 : const sal_uInt16 nSize = rPts.GetSize();
1625 0 : boost::scoped_array<Color> pColArray(new Color[ nSize ]);
1626 :
1627 0 : for( sal_uInt16 i = 0; i < nSize; i++ )
1628 0 : pColArray[ i ] = rColor;
1629 :
1630 0 : DrawPixel( rPts, pColArray.get() );
1631 : }
1632 :
1633 0 : if( mpAlphaVDev )
1634 0 : mpAlphaVDev->DrawPixel( rPts, rColor );
1635 0 : }
1636 :
1637 : namespace
1638 : {
1639 : // Co = Cs + Cd*(1-As) premultiplied alpha -or-
1640 : // Co = (AsCs + AdCd*(1-As)) / Ao
1641 0 : inline sal_uInt8 lcl_calcColor( const sal_uInt8 nSourceColor, const sal_uInt8 nSourceAlpha,
1642 : const sal_uInt8 nDstAlpha, const sal_uInt8 nResAlpha, const sal_uInt8 nDestColor )
1643 : {
1644 0 : int c = nResAlpha ? ( (int)nSourceAlpha*nSourceColor + (int)nDstAlpha*nDestColor -
1645 0 : (int)nDstAlpha*nDestColor*nSourceAlpha/255 ) / (int)nResAlpha : 0;
1646 0 : return sal_uInt8( c );
1647 : }
1648 :
1649 0 : inline BitmapColor lcl_AlphaBlend( int nX, int nY,
1650 : const long nMapX,
1651 : const long nMapY,
1652 : BitmapReadAccess* pP,
1653 : BitmapReadAccess* pA,
1654 : BitmapReadAccess* pB,
1655 : BitmapWriteAccess* pAlphaW,
1656 : sal_uInt8& nResAlpha )
1657 : {
1658 0 : BitmapColor aDstCol,aSrcCol;
1659 0 : aSrcCol = pP->GetColor( nMapY, nMapX );
1660 0 : aDstCol = pB->GetColor( nY, nX );
1661 :
1662 : // vcl stores transparency, not alpha - invert it
1663 0 : const sal_uInt8 nSrcAlpha = 255 - pA->GetPixelIndex( nMapY, nMapX );
1664 0 : const sal_uInt8 nDstAlpha = 255 - pAlphaW->GetPixelIndex( nY, nX );
1665 :
1666 : // Perform porter-duff compositing 'over' operation
1667 :
1668 : // Co = Cs + Cd*(1-As)
1669 : // Ad = As + Ad*(1-As)
1670 0 : nResAlpha = (int)nSrcAlpha + (int)nDstAlpha - (int)nDstAlpha*nSrcAlpha/255;
1671 :
1672 0 : aDstCol.SetRed( lcl_calcColor( aSrcCol.GetRed(), nSrcAlpha, nDstAlpha, nResAlpha, aDstCol.GetRed() ) );
1673 0 : aDstCol.SetBlue( lcl_calcColor( aSrcCol.GetBlue(), nSrcAlpha, nDstAlpha, nResAlpha, aDstCol.GetBlue() ) );
1674 0 : aDstCol.SetGreen( lcl_calcColor( aSrcCol.GetGreen(), nSrcAlpha, nDstAlpha, nResAlpha, aDstCol.GetGreen() ) );
1675 :
1676 0 : return aDstCol;
1677 : }
1678 : }
1679 :
1680 0 : Bitmap OutputDevice::ImplBlendWithAlpha( Bitmap aBmp,
1681 : BitmapReadAccess* pP,
1682 : BitmapReadAccess* pA,
1683 : const Rectangle& aDstRect,
1684 : const sal_Int32 nOffY,
1685 : const sal_Int32 nDstHeight,
1686 : const sal_Int32 nOffX,
1687 : const sal_Int32 nDstWidth,
1688 : const long* pMapX,
1689 : const long* pMapY )
1690 : {
1691 0 : BitmapColor aDstCol;
1692 0 : Bitmap res;
1693 : int nX, nY;
1694 : sal_uInt8 nResAlpha;
1695 :
1696 : OSL_ENSURE(mpAlphaVDev,
1697 : "ImplBlendWithAlpha(): call me only with valid alpha VDev!" );
1698 :
1699 0 : bool bOldMapMode( mpAlphaVDev->IsMapModeEnabled() );
1700 0 : mpAlphaVDev->EnableMapMode(false);
1701 :
1702 0 : Bitmap aAlphaBitmap( mpAlphaVDev->GetBitmap( aDstRect.TopLeft(), aDstRect.GetSize() ) );
1703 0 : BitmapWriteAccess* pAlphaW = aAlphaBitmap.AcquireWriteAccess();
1704 :
1705 0 : if( GetBitCount() <= 8 )
1706 : {
1707 0 : Bitmap aDither( aBmp.GetSizePixel(), 8 );
1708 0 : BitmapColor aIndex( 0 );
1709 0 : BitmapReadAccess* pB = aBmp.AcquireReadAccess();
1710 0 : BitmapWriteAccess* pW = aDither.AcquireWriteAccess();
1711 :
1712 0 : if( pB && pP && pA && pW && pAlphaW )
1713 : {
1714 : int nOutY;
1715 :
1716 0 : for( nY = 0, nOutY = nOffY; nY < nDstHeight; nY++, nOutY++ )
1717 : {
1718 0 : const long nMapY = pMapY[ nY ];
1719 0 : const long nModY = ( nOutY & 0x0FL ) << 4L;
1720 : int nOutX;
1721 :
1722 0 : for( nX = 0, nOutX = nOffX; nX < nDstWidth; nX++, nOutX++ )
1723 : {
1724 0 : const long nMapX = pMapX[ nX ];
1725 0 : const sal_uLong nD = nVCLDitherLut[ nModY | ( nOutX & 0x0FL ) ];
1726 :
1727 0 : aDstCol = lcl_AlphaBlend( nX, nY, nMapX, nMapY, pP, pA, pB, pAlphaW, nResAlpha );
1728 :
1729 0 : aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ ( nVCLLut[ aDstCol.GetRed() ] + nD ) >> 16UL ] +
1730 0 : nVCLGLut[ ( nVCLLut[ aDstCol.GetGreen() ] + nD ) >> 16UL ] +
1731 0 : nVCLBLut[ ( nVCLLut[ aDstCol.GetBlue() ] + nD ) >> 16UL ] ) );
1732 0 : pW->SetPixel( nY, nX, aIndex );
1733 :
1734 0 : aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ ( nVCLLut[ 255-nResAlpha ] + nD ) >> 16UL ] +
1735 0 : nVCLGLut[ ( nVCLLut[ 255-nResAlpha ] + nD ) >> 16UL ] +
1736 0 : nVCLBLut[ ( nVCLLut[ 255-nResAlpha ] + nD ) >> 16UL ] ) );
1737 0 : pAlphaW->SetPixel( nY, nX, aIndex );
1738 : }
1739 : }
1740 : }
1741 :
1742 0 : aBmp.ReleaseAccess( pB );
1743 0 : aDither.ReleaseAccess( pW );
1744 0 : res = aDither;
1745 : }
1746 : else
1747 : {
1748 0 : BitmapWriteAccess* pB = aBmp.AcquireWriteAccess();
1749 0 : if( pP && pA && pB )
1750 : {
1751 0 : for( nY = 0; nY < nDstHeight; nY++ )
1752 : {
1753 0 : const long nMapY = pMapY[ nY ];
1754 :
1755 0 : for( nX = 0; nX < nDstWidth; nX++ )
1756 : {
1757 0 : const long nMapX = pMapX[ nX ];
1758 0 : aDstCol = lcl_AlphaBlend( nX, nY, nMapX, nMapY, pP, pA, pB, pAlphaW, nResAlpha );
1759 :
1760 0 : pB->SetPixel( nY, nX, aDstCol );
1761 0 : pAlphaW->SetPixel( nY, nX, Color(255L-nResAlpha, 255L-nResAlpha, 255L-nResAlpha) );
1762 : }
1763 : }
1764 : }
1765 :
1766 0 : aBmp.ReleaseAccess( pB );
1767 0 : res = aBmp;
1768 : }
1769 :
1770 0 : aAlphaBitmap.ReleaseAccess( pAlphaW );
1771 0 : mpAlphaVDev->DrawBitmap( aDstRect.TopLeft(), aAlphaBitmap );
1772 0 : mpAlphaVDev->EnableMapMode( bOldMapMode );
1773 :
1774 0 : return res;
1775 : }
1776 :
1777 0 : Bitmap OutputDevice::ImplBlend( Bitmap aBmp,
1778 : BitmapReadAccess* pP,
1779 : BitmapReadAccess* pA,
1780 : const sal_Int32 nOffY,
1781 : const sal_Int32 nDstHeight,
1782 : const sal_Int32 nOffX,
1783 : const sal_Int32 nDstWidth,
1784 : const Rectangle& aBmpRect,
1785 : const Size& aOutSz,
1786 : const bool bHMirr,
1787 : const bool bVMirr,
1788 : const long* pMapX,
1789 : const long* pMapY )
1790 : {
1791 0 : BitmapColor aDstCol;
1792 0 : Bitmap res;
1793 : int nX, nY;
1794 :
1795 0 : if( GetBitCount() <= 8 )
1796 : {
1797 0 : Bitmap aDither( aBmp.GetSizePixel(), 8 );
1798 0 : BitmapColor aIndex( 0 );
1799 0 : BitmapReadAccess* pB = aBmp.AcquireReadAccess();
1800 0 : BitmapWriteAccess* pW = aDither.AcquireWriteAccess();
1801 :
1802 0 : if( pB && pP && pA && pW )
1803 : {
1804 : int nOutY;
1805 :
1806 0 : for( nY = 0, nOutY = nOffY; nY < nDstHeight; nY++, nOutY++ )
1807 : {
1808 0 : const long nMapY = pMapY[ nY ];
1809 0 : const long nModY = ( nOutY & 0x0FL ) << 4L;
1810 : int nOutX;
1811 :
1812 0 : for( nX = 0, nOutX = nOffX; nX < nDstWidth; nX++, nOutX++ )
1813 : {
1814 0 : const long nMapX = pMapX[ nX ];
1815 0 : const sal_uLong nD = nVCLDitherLut[ nModY | ( nOutX & 0x0FL ) ];
1816 :
1817 0 : aDstCol = pB->GetColor( nY, nX );
1818 0 : aDstCol.Merge( pP->GetColor( nMapY, nMapX ), pA->GetPixelIndex( nMapY, nMapX ) );
1819 0 : aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ ( nVCLLut[ aDstCol.GetRed() ] + nD ) >> 16UL ] +
1820 0 : nVCLGLut[ ( nVCLLut[ aDstCol.GetGreen() ] + nD ) >> 16UL ] +
1821 0 : nVCLBLut[ ( nVCLLut[ aDstCol.GetBlue() ] + nD ) >> 16UL ] ) );
1822 0 : pW->SetPixel( nY, nX, aIndex );
1823 : }
1824 : }
1825 : }
1826 :
1827 0 : aBmp.ReleaseAccess( pB );
1828 0 : aDither.ReleaseAccess( pW );
1829 0 : res = aDither;
1830 : }
1831 : else
1832 : {
1833 0 : BitmapWriteAccess* pB = aBmp.AcquireWriteAccess();
1834 :
1835 0 : bool bFastBlend = false;
1836 0 : if( pP && pA && pB )
1837 : {
1838 : SalTwoRect aTR;
1839 0 : aTR.mnSrcX = aBmpRect.Left();
1840 0 : aTR.mnSrcY = aBmpRect.Top();
1841 0 : aTR.mnSrcWidth = aBmpRect.GetWidth();
1842 0 : aTR.mnSrcHeight = aBmpRect.GetHeight();
1843 0 : aTR.mnDestX = nOffX;
1844 0 : aTR.mnDestY = nOffY;
1845 0 : aTR.mnDestWidth = aOutSz.Width();
1846 0 : aTR.mnDestHeight= aOutSz.Height();
1847 :
1848 0 : if( !bHMirr && !bVMirr )
1849 0 : bFastBlend = ImplFastBitmapBlending( *pB,*pP,*pA, aTR );
1850 : }
1851 :
1852 0 : if( pP && pA && pB && !bFastBlend )
1853 : {
1854 0 : switch( pP->GetScanlineFormat() )
1855 : {
1856 : case( BMP_FORMAT_8BIT_PAL ):
1857 : {
1858 0 : for( nY = 0; nY < nDstHeight; nY++ )
1859 : {
1860 0 : const long nMapY = pMapY[ nY ];
1861 0 : Scanline pPScan = pP->GetScanline( nMapY );
1862 0 : Scanline pAScan = pA->GetScanline( nMapY );
1863 :
1864 0 : for( nX = 0; nX < nDstWidth; nX++ )
1865 : {
1866 0 : const long nMapX = pMapX[ nX ];
1867 0 : aDstCol = pB->GetPixel( nY, nX );
1868 0 : pB->SetPixel( nY, nX, aDstCol.Merge( pP->GetPaletteColor( pPScan[ nMapX ] ),
1869 0 : pAScan[ nMapX ] ) );
1870 : }
1871 : }
1872 : }
1873 0 : break;
1874 :
1875 : case( BMP_FORMAT_24BIT_TC_BGR ):
1876 : {
1877 0 : for( nY = 0; nY < nDstHeight; nY++ )
1878 : {
1879 0 : const long nMapY = pMapY[ nY ];
1880 0 : Scanline pPScan = pP->GetScanline( nMapY );
1881 0 : Scanline pAScan = pA->GetScanline( nMapY );
1882 :
1883 0 : for( nX = 0; nX < nDstWidth; nX++ )
1884 : {
1885 0 : const long nMapX = pMapX[ nX ];
1886 0 : Scanline pTmp = pPScan + nMapX * 3;
1887 :
1888 0 : aDstCol = pB->GetPixel( nY, nX );
1889 0 : pB->SetPixel( nY, nX, aDstCol.Merge( pTmp[ 2 ], pTmp[ 1 ], pTmp[ 0 ],
1890 0 : pAScan[ nMapX ] ) );
1891 : }
1892 : }
1893 : }
1894 0 : break;
1895 :
1896 : case( BMP_FORMAT_24BIT_TC_RGB ):
1897 : {
1898 0 : for( nY = 0; nY < nDstHeight; nY++ )
1899 : {
1900 0 : const long nMapY = pMapY[ nY ];
1901 0 : Scanline pPScan = pP->GetScanline( nMapY );
1902 0 : Scanline pAScan = pA->GetScanline( nMapY );
1903 :
1904 0 : for( nX = 0; nX < nDstWidth; nX++ )
1905 : {
1906 0 : const long nMapX = pMapX[ nX ];
1907 0 : Scanline pTmp = pPScan + nMapX * 3;
1908 :
1909 0 : aDstCol = pB->GetPixel( nY, nX );
1910 0 : pB->SetPixel( nY, nX, aDstCol.Merge( pTmp[ 0 ], pTmp[ 1 ], pTmp[ 2 ],
1911 0 : pAScan[ nMapX ] ) );
1912 : }
1913 : }
1914 : }
1915 0 : break;
1916 :
1917 : default:
1918 : {
1919 0 : for( nY = 0; nY < nDstHeight; nY++ )
1920 : {
1921 0 : const long nMapY = pMapY[ nY ];
1922 0 : Scanline pAScan = pA->GetScanline( nMapY );
1923 :
1924 0 : for( nX = 0; nX < nDstWidth; nX++ )
1925 : {
1926 0 : const long nMapX = pMapX[ nX ];
1927 0 : aDstCol = pB->GetPixel( nY, nX );
1928 : pB->SetPixel( nY, nX, aDstCol.Merge( pP->GetColor( nMapY, nMapX ),
1929 0 : pAScan[ nMapX ] ) );
1930 : }
1931 : }
1932 : }
1933 0 : break;
1934 : }
1935 : }
1936 :
1937 0 : aBmp.ReleaseAccess( pB );
1938 0 : res = aBmp;
1939 : }
1940 :
1941 0 : return res;
1942 : }
1943 :
1944 0 : void OutputDevice::ClipToPaintRegion(Rectangle& /*rDstRect*/)
1945 : {
1946 0 : }
1947 :
1948 0 : void OutputDevice::ImplDrawAlpha( const Bitmap& rBmp, const AlphaMask& rAlpha,
1949 : const Point& rDestPt, const Size& rDestSize,
1950 : const Point& rSrcPtPixel, const Size& rSrcSizePixel )
1951 : {
1952 0 : const Point aNullPt;
1953 0 : Point aOutPt( LogicToPixel( rDestPt ) );
1954 0 : Size aOutSz( LogicToPixel( rDestSize ) );
1955 0 : Rectangle aDstRect( aNullPt, GetOutputSizePixel() );
1956 0 : const bool bHMirr = aOutSz.Width() < 0;
1957 0 : const bool bVMirr = aOutSz.Height() < 0;
1958 :
1959 0 : ClipToPaintRegion(aDstRect);
1960 :
1961 0 : if( bHMirr )
1962 : {
1963 0 : aOutSz.Width() = -aOutSz.Width();
1964 0 : aOutPt.X() -= ( aOutSz.Width() - 1L );
1965 : }
1966 :
1967 0 : if( bVMirr )
1968 : {
1969 0 : aOutSz.Height() = -aOutSz.Height();
1970 0 : aOutPt.Y() -= ( aOutSz.Height() - 1L );
1971 : }
1972 :
1973 0 : if( !aDstRect.Intersection( Rectangle( aOutPt, aOutSz ) ).IsEmpty() )
1974 : {
1975 0 : bool bNativeAlpha = false;
1976 0 : static const char* pDisableNative = getenv( "SAL_DISABLE_NATIVE_ALPHA");
1977 : // #i83087# Naturally, system alpha blending cannot work with
1978 : // separate alpha VDev
1979 0 : bool bTryDirectPaint(!mpAlphaVDev && !pDisableNative && !bHMirr && !bVMirr);
1980 :
1981 : #ifdef WNT
1982 : if(bTryDirectPaint)
1983 : {
1984 : // only paint direct when no scaling and no MapMode, else the
1985 : // more expensive conversions may be done for short-time Bitmap/BitmapEx
1986 : // used for buffering only
1987 : if(!IsMapMode() && rSrcSizePixel.Width() == aOutSz.Width() && rSrcSizePixel.Height() == aOutSz.Height())
1988 : {
1989 : bTryDirectPaint = false;
1990 : }
1991 : }
1992 : #endif
1993 :
1994 0 : if(bTryDirectPaint)
1995 : {
1996 0 : Point aRelPt = aOutPt + Point( mnOutOffX, mnOutOffY );
1997 : SalTwoRect aTR = {
1998 0 : rSrcPtPixel.X(), rSrcPtPixel.Y(),
1999 0 : rSrcSizePixel.Width(), rSrcSizePixel.Height(),
2000 0 : aRelPt.X(), aRelPt.Y(),
2001 0 : aOutSz.Width(), aOutSz.Height()
2002 0 : };
2003 0 : SalBitmap* pSalSrcBmp = rBmp.ImplGetImpBitmap()->ImplGetSalBitmap();
2004 0 : SalBitmap* pSalAlphaBmp = rAlpha.ImplGetImpBitmap()->ImplGetSalBitmap();
2005 0 : bNativeAlpha = mpGraphics->DrawAlphaBitmap( aTR, *pSalSrcBmp, *pSalAlphaBmp, this );
2006 : }
2007 :
2008 0 : VirtualDevice* pOldVDev = mpAlphaVDev;
2009 :
2010 0 : Rectangle aBmpRect( aNullPt, rBmp.GetSizePixel() );
2011 0 : if( !bNativeAlpha
2012 0 : && !aBmpRect.Intersection( Rectangle( rSrcPtPixel, rSrcSizePixel ) ).IsEmpty() )
2013 : {
2014 : // The scaling in this code path produces really ugly results - it
2015 : // does the most trivial scaling with no smoothing.
2016 :
2017 0 : GDIMetaFile* pOldMetaFile = mpMetaFile;
2018 0 : const bool bOldMap = mbMap;
2019 0 : mpMetaFile = NULL; // fdo#55044 reset before GetBitmap!
2020 0 : mbMap = false;
2021 0 : Bitmap aBmp( GetBitmap( aDstRect.TopLeft(), aDstRect.GetSize() ) );
2022 :
2023 : // #109044# The generated bitmap need not necessarily be
2024 : // of aDstRect dimensions, it's internally clipped to
2025 : // window bounds. Thus, we correct the dest size here,
2026 : // since we later use it (in nDstWidth/Height) for pixel
2027 : // access)
2028 : // #i38887# reading from screen may sometimes fail
2029 0 : if( aBmp.ImplGetImpBitmap() )
2030 0 : aDstRect.SetSize( aBmp.GetSizePixel() );
2031 :
2032 0 : BitmapColor aDstCol;
2033 0 : const long nSrcWidth = aBmpRect.GetWidth(), nSrcHeight = aBmpRect.GetHeight();
2034 0 : const long nDstWidth = aDstRect.GetWidth(), nDstHeight = aDstRect.GetHeight();
2035 0 : const long nOutWidth = aOutSz.Width(), nOutHeight = aOutSz.Height();
2036 : // calculate offset in original bitmap
2037 : // in RTL case this is a little more complicated since the contents of the
2038 : // bitmap is not mirrored (it never is), however the paint region and bmp region
2039 : // are in mirrored coordinates, so the intersection of (aOutPt,aOutSz) with these
2040 : // is content wise somewhere else and needs to take mirroring into account
2041 0 : const long nOffX = IsRTLEnabled()
2042 0 : ? aOutSz.Width() - aDstRect.GetWidth() - (aDstRect.Left() - aOutPt.X())
2043 0 : : aDstRect.Left() - aOutPt.X(),
2044 0 : nOffY = aDstRect.Top() - aOutPt.Y();
2045 : long nX, nOutX, nY, nOutY;
2046 0 : long nMirrOffX = 0;
2047 0 : long nMirrOffY = 0;
2048 0 : boost::scoped_array<long> pMapX(new long[ nDstWidth ]);
2049 0 : boost::scoped_array<long> pMapY(new long[ nDstHeight ]);
2050 :
2051 : // create horizontal mapping table
2052 0 : if( bHMirr )
2053 0 : nMirrOffX = ( aBmpRect.Left() << 1 ) + nSrcWidth - 1;
2054 :
2055 0 : for( nX = 0L, nOutX = nOffX; nX < nDstWidth; nX++, nOutX++ )
2056 : {
2057 0 : pMapX[ nX ] = aBmpRect.Left() + nOutX * nSrcWidth / nOutWidth;
2058 0 : if( bHMirr )
2059 0 : pMapX[ nX ] = nMirrOffX - pMapX[ nX ];
2060 : }
2061 :
2062 : // create vertical mapping table
2063 0 : if( bVMirr )
2064 0 : nMirrOffY = ( aBmpRect.Top() << 1 ) + nSrcHeight - 1;
2065 :
2066 0 : for( nY = 0L, nOutY = nOffY; nY < nDstHeight; nY++, nOutY++ )
2067 : {
2068 0 : pMapY[ nY ] = aBmpRect.Top() + nOutY * nSrcHeight / nOutHeight;
2069 :
2070 0 : if( bVMirr )
2071 0 : pMapY[ nY ] = nMirrOffY - pMapY[ nY ];
2072 : }
2073 :
2074 0 : BitmapReadAccess* pP = ( (Bitmap&) rBmp ).AcquireReadAccess();
2075 0 : BitmapReadAccess* pA = ( (AlphaMask&) rAlpha ).AcquireReadAccess();
2076 :
2077 : DBG_ASSERT( pA->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL ||
2078 : pA->GetScanlineFormat() == BMP_FORMAT_8BIT_TC_MASK,
2079 : "OutputDevice::ImplDrawAlpha(): non-8bit alpha no longer supported!" );
2080 :
2081 : // #i38887# reading from screen may sometimes fail
2082 0 : if( aBmp.ImplGetImpBitmap() )
2083 : {
2084 0 : Bitmap aTmp;
2085 :
2086 0 : if( mpAlphaVDev )
2087 : {
2088 0 : aTmp = ImplBlendWithAlpha(
2089 : aBmp,pP,pA,
2090 : aDstRect,
2091 : nOffY,nDstHeight,
2092 : nOffX,nDstWidth,
2093 0 : pMapX.get(),pMapY.get() );
2094 : }
2095 : else
2096 : {
2097 0 : aTmp = ImplBlend(
2098 : aBmp,pP,pA,
2099 : nOffY,nDstHeight,
2100 : nOffX,nDstWidth,
2101 : aBmpRect,aOutSz,
2102 : bHMirr,bVMirr,
2103 0 : pMapX.get(),pMapY.get() );
2104 : }
2105 :
2106 : // #110958# Disable alpha VDev, we're doing the necessary
2107 : // stuff explicitly furher below
2108 0 : if( mpAlphaVDev )
2109 0 : mpAlphaVDev = NULL;
2110 :
2111 : DrawBitmap( aDstRect.TopLeft(),
2112 0 : aTmp );
2113 :
2114 : // #110958# Enable alpha VDev again
2115 0 : mpAlphaVDev = pOldVDev;
2116 : }
2117 :
2118 0 : ( (Bitmap&) rBmp ).ReleaseAccess( pP );
2119 0 : ( (AlphaMask&) rAlpha ).ReleaseAccess( pA );
2120 :
2121 0 : mbMap = bOldMap;
2122 0 : mpMetaFile = pOldMetaFile;
2123 : }
2124 : }
2125 0 : }
2126 :
2127 0 : void OutputDevice::ImplPrintTransparent( const Bitmap& rBmp, const Bitmap& rMask,
2128 : const Point& rDestPt, const Size& rDestSize,
2129 : const Point& rSrcPtPixel, const Size& rSrcSizePixel )
2130 : {
2131 0 : Point aPt;
2132 0 : Point aDestPt( LogicToPixel( rDestPt ) );
2133 0 : Size aDestSz( LogicToPixel( rDestSize ) );
2134 0 : Rectangle aSrcRect( rSrcPtPixel, rSrcSizePixel );
2135 :
2136 0 : aSrcRect.Justify();
2137 :
2138 0 : if( !rBmp.IsEmpty() && aSrcRect.GetWidth() && aSrcRect.GetHeight() && aDestSz.Width() && aDestSz.Height() )
2139 : {
2140 0 : Bitmap aPaint( rBmp ), aMask( rMask );
2141 0 : sal_uLong nMirrFlags = 0UL;
2142 :
2143 0 : if( aMask.GetBitCount() > 1 )
2144 0 : aMask.Convert( BMP_CONVERSION_1BIT_THRESHOLD );
2145 :
2146 : // mirrored horizontically
2147 0 : if( aDestSz.Width() < 0L )
2148 : {
2149 0 : aDestSz.Width() = -aDestSz.Width();
2150 0 : aDestPt.X() -= ( aDestSz.Width() - 1L );
2151 0 : nMirrFlags |= BMP_MIRROR_HORZ;
2152 : }
2153 :
2154 : // mirrored vertically
2155 0 : if( aDestSz.Height() < 0L )
2156 : {
2157 0 : aDestSz.Height() = -aDestSz.Height();
2158 0 : aDestPt.Y() -= ( aDestSz.Height() - 1L );
2159 0 : nMirrFlags |= BMP_MIRROR_VERT;
2160 : }
2161 :
2162 : // source cropped?
2163 0 : if( aSrcRect != Rectangle( aPt, aPaint.GetSizePixel() ) )
2164 : {
2165 0 : aPaint.Crop( aSrcRect );
2166 0 : aMask.Crop( aSrcRect );
2167 : }
2168 :
2169 : // destination mirrored
2170 0 : if( nMirrFlags )
2171 : {
2172 0 : aPaint.Mirror( nMirrFlags );
2173 0 : aMask.Mirror( nMirrFlags );
2174 : }
2175 :
2176 : // we always want to have a mask
2177 0 : if( aMask.IsEmpty() )
2178 : {
2179 0 : aMask = Bitmap( aSrcRect.GetSize(), 1 );
2180 0 : aMask.Erase( Color( COL_BLACK ) );
2181 : }
2182 :
2183 : // do painting
2184 0 : const long nSrcWidth = aSrcRect.GetWidth(), nSrcHeight = aSrcRect.GetHeight();
2185 : long nX, nY; // , nWorkX, nWorkY, nWorkWidth, nWorkHeight;
2186 0 : boost::scoped_array<long> pMapX(new long[ nSrcWidth + 1 ]);
2187 0 : boost::scoped_array<long> pMapY(new long[ nSrcHeight + 1 ]);
2188 0 : const bool bOldMap = mbMap;
2189 :
2190 0 : mbMap = false;
2191 :
2192 : // create forward mapping tables
2193 0 : for( nX = 0L; nX <= nSrcWidth; nX++ )
2194 0 : pMapX[ nX ] = aDestPt.X() + FRound( (double) aDestSz.Width() * nX / nSrcWidth );
2195 :
2196 0 : for( nY = 0L; nY <= nSrcHeight; nY++ )
2197 0 : pMapY[ nY ] = aDestPt.Y() + FRound( (double) aDestSz.Height() * nY / nSrcHeight );
2198 :
2199 : // walk through all rectangles of mask
2200 0 : const Region aWorkRgn(aMask.CreateRegion(COL_BLACK, Rectangle(Point(), aMask.GetSizePixel())));
2201 0 : RectangleVector aRectangles;
2202 0 : aWorkRgn.GetRegionRectangles(aRectangles);
2203 :
2204 0 : for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); ++aRectIter)
2205 : {
2206 0 : const Point aMapPt(pMapX[aRectIter->Left()], pMapY[aRectIter->Top()]);
2207 : const Size aMapSz(
2208 0 : pMapX[aRectIter->Right() + 1] - aMapPt.X(), // pMapX[L + W] -> L + ((R - L) + 1) -> R + 1
2209 0 : pMapY[aRectIter->Bottom() + 1] - aMapPt.Y()); // same for Y
2210 0 : Bitmap aBandBmp(aPaint);
2211 :
2212 0 : aBandBmp.Crop(*aRectIter);
2213 0 : ImplDrawBitmap(aMapPt, aMapSz, Point(), aBandBmp.GetSizePixel(), aBandBmp, META_BMPSCALEPART_ACTION);
2214 0 : }
2215 :
2216 0 : mbMap = bOldMap;
2217 : }
2218 0 : }
2219 :
2220 0 : void OutputDevice::ImplPrintMask( const Bitmap& /*rMask*/, const Color& /*rMaskColor*/,
2221 : const Point& /*rDestPt*/, const Size& /*rDestSize*/,
2222 : const Point& /*rSrcPtPixel*/, const Size& /*rSrcSizePixel*/ )
2223 : {
2224 : // let's leave this for Printer
2225 0 : return;
2226 3 : }
2227 :
2228 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|