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