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