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 // #124580# the correct DestSize needs to be calculated based on MaxXY values
829 const Point aDestPt(basegfx::fround(aTranslate.getX()), basegfx::fround(aTranslate.getY()));
830 const Size aDestSize(
831 basegfx::fround(aScale.getX() + aTranslate.getX()) - aDestPt.X(),
832 basegfx::fround(aScale.getY() + aTranslate.getY()) - aDestPt.Y());
833
834 DrawBitmapEx(aDestPt, aDestSize, rBitmapEx);
835 return;
836 }
837
838 // we have rotation,shear or mirror, check if some crazy mode needs the
839 // created transformed bitmap
840 const bool bInvert(ROP_INVERT == meRasterOp);
841 const bool bBitmapChangedColor(mnDrawMode & (DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP | DRAWMODE_GRAYBITMAP | DRAWMODE_GHOSTEDBITMAP));
842 const bool bMetafile(mpMetaFile);
843 const bool bPrinter(OUTDEV_PRINTER == meOutDevType);
844 bool bDone(false);
845 const basegfx::B2DHomMatrix aFullTransform(GetViewTransformation() * rTransformation);
846 const bool bTryDirectPaint(!bInvert && !bBitmapChangedColor && !bMetafile && !bPrinter);
847
848 if(!bForceToOwnTransformer && bTryDirectPaint)
849 {
850 // try to paint directly
851 const basegfx::B2DPoint aNull(aFullTransform * basegfx::B2DPoint(0.0, 0.0));
852 const basegfx::B2DPoint aTopX(aFullTransform * basegfx::B2DPoint(1.0, 0.0));
853 const basegfx::B2DPoint aTopY(aFullTransform * basegfx::B2DPoint(0.0, 1.0));
854 SalBitmap* pSalSrcBmp = rBitmapEx.GetBitmap().ImplGetImpBitmap()->ImplGetSalBitmap();
855 SalBitmap* pSalAlphaBmp = 0;
856
857 if(rBitmapEx.IsTransparent())
858 {
859 if(rBitmapEx.IsAlpha())
860 {
861 pSalAlphaBmp = rBitmapEx.GetAlpha().ImplGetImpBitmap()->ImplGetSalBitmap();
862 }
863 else
864 {
865 pSalAlphaBmp = rBitmapEx.GetMask().ImplGetImpBitmap()->ImplGetSalBitmap();
866 }
867 }
868
869 bDone = mpGraphics->DrawTransformedBitmap(
870 aNull,
871 aTopX,
872 aTopY,
873 *pSalSrcBmp,
874 pSalAlphaBmp,
875 this);
876 }
877
878 if(!bDone)
879 {
880 // take the fallback when no rotate and shear, but mirror (else we would have done this above)
881 if(!bForceToOwnTransformer && !bRotated && !bSheared)
882 {
883 // with no rotation or shear it can be mapped to DrawBitmapEx
884 // do *not* execute the mirroring here, it's done in the fallback
885 // #124580# the correct DestSize needs to be calculated based on MaxXY values
886 const Point aDestPt(basegfx::fround(aTranslate.getX()), basegfx::fround(aTranslate.getY()));
887 const Size aDestSize(
888 basegfx::fround(aScale.getX() + aTranslate.getX()) - aDestPt.X(),
889 basegfx::fround(aScale.getY() + aTranslate.getY()) - aDestPt.Y());
890
891 DrawBitmapEx(aDestPt, aDestSize, rBitmapEx);
892 return;
893 }
894
895 // fallback; create transformed bitmap the hard way (back-transform
896 // the pixels) and paint
897 basegfx::B2DRange aVisibleRange(0.0, 0.0, 1.0, 1.0);
898
899 // limit maximum area to something looking good for non-pixel-based targets (metafile, printer)
900 // by using a fixed minimum (allow at least, but no need to utilize) for good smooting and an area
901 // dependent of original size for good quality when e.g. rotated/sheared. Still, limit to a maximum
902 // to avoid crashes/ressource problems (ca. 1500x3000 here)
903 const Size& rOriginalSizePixel(rBitmapEx.GetSizePixel());
904 const double fOrigArea(rOriginalSizePixel.Width() * rOriginalSizePixel.Height() * 0.5);
905 const double fOrigAreaScaled(bSheared || bRotated ? fOrigArea * 1.44 : fOrigArea);
906 double fMaximumArea(std::min(4500000.0, std::max(1000000.0, fOrigAreaScaled)));
907
908 if(!bMetafile && !bPrinter)
909 {
910 // limit TargetRange to existing pixels (if pixel device)
911 // first get discrete range of object
912 basegfx::B2DRange aFullPixelRange(aVisibleRange);
913
914 aFullPixelRange.transform(aFullTransform);
915
916 if(basegfx::fTools::equalZero(aFullPixelRange.getWidth()) || basegfx::fTools::equalZero(aFullPixelRange.getHeight()))
917 {
918 // object is outside of visible area
919 return;
920 }
921
922 // now get discrete target pixels; start with OutDev pixel size and evtl.
923 // intersect with active clipping area
924 basegfx::B2DRange aOutPixel(
925 0.0,
926 0.0,
927 GetOutputSizePixel().Width(),
928 GetOutputSizePixel().Height());
929
930 if(IsClipRegion())
931 {
932 const Rectangle aRegionRectangle(GetActiveClipRegion().GetBoundRect());
933
934 aOutPixel.intersect( // caution! Range from rectangle, one too much (!)
935 basegfx::B2DRange(
936 aRegionRectangle.Left(),
937 aRegionRectangle.Top(),
938 aRegionRectangle.Right() + 1,
939 aRegionRectangle.Bottom() + 1));
940 }
941
942 if(aOutPixel.isEmpty())
943 {
944 // no active output area
945 return;
946 }
947
948 // if aFullPixelRange is not completely inside of aOutPixel,
949 // reduction of target pixels is possible
950 basegfx::B2DRange aVisiblePixelRange(aFullPixelRange);
951
952 if(!aOutPixel.isInside(aFullPixelRange))
953 {
954 aVisiblePixelRange.intersect(aOutPixel);
955
956 if(aVisiblePixelRange.isEmpty())
957 {
958 // nothing in visible part, reduces to nothing
959 return;
960 }
961
962 // aVisiblePixelRange contains the reduced output area in
963 // discrete coordinates. To make it useful everywhere, make it relative to
964 // the object range
965 basegfx::B2DHomMatrix aMakeVisibleRangeRelative;
966
967 aVisibleRange = aVisiblePixelRange;
968 aMakeVisibleRangeRelative.translate(
969 -aFullPixelRange.getMinX(),
970 -aFullPixelRange.getMinY());
971 aMakeVisibleRangeRelative.scale(
972 1.0 / aFullPixelRange.getWidth(),
973 1.0 / aFullPixelRange.getHeight());
974 aVisibleRange.transform(aMakeVisibleRangeRelative);
975 }
976
977 // for pixel devices, do *not* limit size, else OutputDevice::ImplDrawAlpha
978 // will create another, badly scaled bitmap to do the job. Nonetheless, do a
979 // maximum clipping of something big (1600x1280x2). Add 1.0 to avoid rounding
980 // errors in rough estimations
981 const double fNewMaxArea(aVisiblePixelRange.getWidth() * aVisiblePixelRange.getHeight());
982
983 fMaximumArea = std::min(4096000.0, fNewMaxArea + 1.0);
984 }
985
986 if(!aVisibleRange.isEmpty())
987 {
988 static bool bDoSmoothAtAll(true);
989 BitmapEx aTransformed(rBitmapEx);
990
991 // #122923# when the result needs an alpha channel due to being rotated or sheared
992 // and thus uncovering areas, add these channels so that the own transformer (used
993 // in getTransformed) also creates a transformed alpha channel
994 if(!aTransformed.IsTransparent() && (bSheared || bRotated))
995 {
996 // parts will be uncovered, extend aTransformed with a mask bitmap
997 const Bitmap aContent(aTransformed.GetBitmap());
998 #if defined(MACOSX)
999 AlphaMask aMaskBmp(aContent.GetSizePixel());
1000 aMaskBmp.Erase(0);
1001 #else
1002 Bitmap aMaskBmp(aContent.GetSizePixel(), 1);
1003 aMaskBmp.Erase(Color(COL_BLACK)); // #122758# Initialize to non-transparent
1004 #endif
1005 aTransformed = BitmapEx(aContent, aMaskBmp);
1006 }
1007
1008 aTransformed = aTransformed.getTransformed(
1009 aFullTransform,
1010 aVisibleRange,
1011 fMaximumArea,
1012 bDoSmoothAtAll);
1013 basegfx::B2DRange aTargetRange(0.0, 0.0, 1.0, 1.0);
1014
1015 // get logic object target range
1016 aTargetRange.transform(rTransformation);
1017
1018 // get from unified/relative VisibleRange to logoc one
1019 aVisibleRange.transform(
1020 basegfx::tools::createScaleTranslateB2DHomMatrix(
1021 aTargetRange.getRange(),
1022 aTargetRange.getMinimum()));
1023
1024 // extract point and size; do not remove size, the bitmap may have been prepared reduced by purpose
1025 // #124580# the correct DestSize needs to be calculated based on MaxXY values
1026 const Point aDestPt(basegfx::fround(aVisibleRange.getMinX()), basegfx::fround(aVisibleRange.getMinY()));
1027 const Size aDestSize(
1028 basegfx::fround(aVisibleRange.getMaxX()) - aDestPt.X(),
1029 basegfx::fround(aVisibleRange.getMaxY()) - aDestPt.Y());
1030
1031 DrawBitmapEx(aDestPt, aDestSize, aTransformed);
1032 }
1033 }
1034 }
1035
1036 // ------------------------------------------------------------------
1037
ImplDrawBitmapEx(const Point & rDestPt,const Size & rDestSize,const Point & rSrcPtPixel,const Size & rSrcSizePixel,const BitmapEx & rBitmapEx,const sal_uLong nAction)1038 void OutputDevice::ImplDrawBitmapEx( const Point& rDestPt, const Size& rDestSize,
1039 const Point& rSrcPtPixel, const Size& rSrcSizePixel,
1040 const BitmapEx& rBitmapEx, const sal_uLong nAction )
1041 {
1042 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
1043 OSL_ENSURE(TRANSPARENT_NONE != rBitmapEx.GetTransparentType(), "ImplDrawBitmapEx not needed, no transparency in BitmapEx (!)");
1044
1045 if ( mnDrawMode & DRAWMODE_NOBITMAP )
1046 return;
1047
1048 if ( ROP_INVERT == meRasterOp )
1049 {
1050 DrawRect( Rectangle( rDestPt, rDestSize ) );
1051 return;
1052 }
1053
1054 BitmapEx aBmpEx( rBitmapEx );
1055
1056 if ( mnDrawMode & ( DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP |
1057 DRAWMODE_GRAYBITMAP | DRAWMODE_GHOSTEDBITMAP ) )
1058 {
1059 if ( mnDrawMode & ( DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP ) )
1060 {
1061 Bitmap aColorBmp( aBmpEx.GetSizePixel(), ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP ) ? 4 : 1 );
1062 sal_uInt8 cCmpVal;
1063
1064 if ( mnDrawMode & DRAWMODE_BLACKBITMAP )
1065 cCmpVal = ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP ) ? 0x80 : 0;
1066 else
1067 cCmpVal = 255;
1068
1069 aColorBmp.Erase( Color( cCmpVal, cCmpVal, cCmpVal ) );
1070
1071 if( aBmpEx.IsAlpha() )
1072 {
1073 // Create one-bit mask out of alpha channel, by
1074 // thresholding it at alpha=0.5. As
1075 // DRAWMODE_BLACK/WHITEBITMAP requires monochrome
1076 // output, having alpha-induced grey levels is not
1077 // acceptable.
1078 Bitmap aMask( aBmpEx.GetAlpha().GetBitmap() );
1079 aMask.MakeMono( 128 );
1080 aBmpEx = BitmapEx( aColorBmp, aMask );
1081 }
1082 else
1083 {
1084 aBmpEx = BitmapEx( aColorBmp, aBmpEx.GetMask() );
1085 }
1086 }
1087 else if( !!aBmpEx )
1088 {
1089 if ( mnDrawMode & DRAWMODE_GRAYBITMAP )
1090 aBmpEx.Convert( BMP_CONVERSION_8BIT_GREYS );
1091
1092 if ( mnDrawMode & DRAWMODE_GHOSTEDBITMAP )
1093 aBmpEx.Convert( BMP_CONVERSION_GHOSTED );
1094 }
1095 }
1096
1097 if ( mpMetaFile )
1098 {
1099 switch( nAction )
1100 {
1101 case( META_BMPEX_ACTION ):
1102 mpMetaFile->AddAction( new MetaBmpExAction( rDestPt, aBmpEx ) );
1103 break;
1104
1105 case( META_BMPEXSCALE_ACTION ):
1106 mpMetaFile->AddAction( new MetaBmpExScaleAction( rDestPt, rDestSize, aBmpEx ) );
1107 break;
1108
1109 case( META_BMPEXSCALEPART_ACTION ):
1110 mpMetaFile->AddAction( new MetaBmpExScalePartAction( rDestPt, rDestSize,
1111 rSrcPtPixel, rSrcSizePixel, aBmpEx ) );
1112 break;
1113 }
1114 }
1115
1116 OUTDEV_INIT();
1117
1118 if( OUTDEV_PRINTER == meOutDevType )
1119 {
1120 if( aBmpEx.IsAlpha() )
1121 {
1122 // #107169# For true alpha bitmaps, no longer masking the
1123 // bitmap, but perform a full alpha blend against a white
1124 // background here.
1125 Bitmap aBmp( aBmpEx.GetBitmap() );
1126 aBmp.Blend( aBmpEx.GetAlpha(), Color( COL_WHITE) );
1127 DrawBitmap( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, aBmp );
1128 }
1129 else
1130 {
1131 Bitmap aBmp( aBmpEx.GetBitmap() ), aMask( aBmpEx.GetMask() );
1132 aBmp.Replace( aMask, Color( COL_WHITE ) );
1133 ImplPrintTransparent( aBmp, aMask, rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel );
1134 }
1135
1136 return;
1137 }
1138
1139 if(aBmpEx.IsAlpha())
1140 {
1141 ImplDrawAlpha( aBmpEx.GetBitmap(), aBmpEx.GetAlpha(), rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel );
1142 return;
1143 }
1144
1145 if( !( !aBmpEx ) )
1146 {
1147 SalTwoRect aPosAry;
1148
1149 aPosAry.mnSrcX = rSrcPtPixel.X();
1150 aPosAry.mnSrcY = rSrcPtPixel.Y();
1151 aPosAry.mnSrcWidth = rSrcSizePixel.Width();
1152 aPosAry.mnSrcHeight = rSrcSizePixel.Height();
1153 aPosAry.mnDestX = ImplLogicXToDevicePixel( rDestPt.X() );
1154 aPosAry.mnDestY = ImplLogicYToDevicePixel( rDestPt.Y() );
1155 aPosAry.mnDestWidth = ImplLogicWidthToDevicePixel( rDestSize.Width() );
1156 aPosAry.mnDestHeight = ImplLogicHeightToDevicePixel( rDestSize.Height() );
1157
1158 const sal_uLong nMirrFlags = ImplAdjustTwoRect( aPosAry, aBmpEx.GetSizePixel() );
1159
1160 if( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight )
1161 {
1162
1163 if( nMirrFlags )
1164 aBmpEx.Mirror( nMirrFlags );
1165
1166 const SalBitmap* pSalSrcBmp = aBmpEx.ImplGetBitmapImpBitmap()->ImplGetSalBitmap();
1167 const ImpBitmap* pMaskBmp = aBmpEx.ImplGetMaskImpBitmap();
1168
1169 if ( pMaskBmp )
1170 {
1171 SalBitmap* pSalAlphaBmp = pMaskBmp->ImplGetSalBitmap();
1172 bool bTryDirectPaint(pSalSrcBmp && pSalAlphaBmp);
1173
1174 if(bTryDirectPaint)
1175 {
1176 // only paint direct when no scaling and no MapMode, else the
1177 // more expensive conversions may be done for short-time Bitmap/BitmapEx
1178 // used for buffering only
1179 if(!IsMapMode() && aPosAry.mnSrcWidth == aPosAry.mnDestWidth && aPosAry.mnSrcHeight == aPosAry.mnDestHeight)
1180 {
1181 bTryDirectPaint = false;
1182 }
1183 }
1184
1185 if(bTryDirectPaint && mpGraphics->DrawAlphaBitmap(aPosAry, *pSalSrcBmp, *pSalAlphaBmp, this))
1186 {
1187 // tried to paint as alpha directly. If tis worked, we are done (except
1188 // alpha, see below)
1189 }
1190 else
1191 {
1192 // #4919452# reduce operation area to bounds of
1193 // cliprect. since masked transparency involves
1194 // creation of a large vdev and copying the screen
1195 // content into that (slooow read from framebuffer),
1196 // that should considerably increase performance for
1197 // large bitmaps and small clippings.
1198
1199 // Note that this optimisation is a workaround for a
1200 // Writer peculiarity, namely, to decompose background
1201 // graphics into myriads of disjunct, tiny
1202 // rectangles. That otherwise kills us here, since for
1203 // transparent output, SAL always prepares the whole
1204 // bitmap, if aPosAry contains the whole bitmap (and
1205 // it's _not_ to blame for that).
1206
1207 // Note the call to ImplPixelToDevicePixel(), since
1208 // aPosAry already contains the mnOutOff-offsets, they
1209 // also have to be applied to the region
1210 Rectangle aClipRegionBounds( ImplPixelToDevicePixel(maRegion).GetBoundRect() );
1211
1212 // TODO: Also respect scaling (that's a bit tricky,
1213 // since the source points have to move fractional
1214 // amounts (which is not possible, thus has to be
1215 // emulated by increases copy area)
1216 // const double nScaleX( aPosAry.mnDestWidth / aPosAry.mnSrcWidth );
1217 // const double nScaleY( aPosAry.mnDestHeight / aPosAry.mnSrcHeight );
1218
1219 // for now, only identity scales allowed
1220 if( !aClipRegionBounds.IsEmpty() &&
1221 aPosAry.mnDestWidth == aPosAry.mnSrcWidth &&
1222 aPosAry.mnDestHeight == aPosAry.mnSrcHeight )
1223 {
1224 // now intersect dest rect with clip region
1225 aClipRegionBounds.Intersection( Rectangle( aPosAry.mnDestX,
1226 aPosAry.mnDestY,
1227 aPosAry.mnDestX + aPosAry.mnDestWidth - 1,
1228 aPosAry.mnDestY + aPosAry.mnDestHeight - 1 ) );
1229
1230 // Note: I could theoretically optimize away the
1231 // DrawBitmap below, if the region is empty
1232 // here. Unfortunately, cannot rule out that
1233 // somebody relies on the side effects.
1234 if( !aClipRegionBounds.IsEmpty() )
1235 {
1236 aPosAry.mnSrcX += aClipRegionBounds.Left() - aPosAry.mnDestX;
1237 aPosAry.mnSrcY += aClipRegionBounds.Top() - aPosAry.mnDestY;
1238 aPosAry.mnSrcWidth = aClipRegionBounds.GetWidth();
1239 aPosAry.mnSrcHeight = aClipRegionBounds.GetHeight();
1240
1241 aPosAry.mnDestX = aClipRegionBounds.Left();
1242 aPosAry.mnDestY = aClipRegionBounds.Top();
1243 aPosAry.mnDestWidth = aClipRegionBounds.GetWidth();
1244 aPosAry.mnDestHeight = aClipRegionBounds.GetHeight();
1245 }
1246 }
1247
1248 mpGraphics->DrawBitmap( aPosAry, *pSalSrcBmp,
1249 *pMaskBmp->ImplGetSalBitmap(),
1250 this );
1251 }
1252
1253 // #110958# Paint mask to alpha channel. Luckily, the
1254 // black and white representation of the mask maps to
1255 // the alpha channel
1256
1257 // #i25167# Restrict mask painting to _opaque_ areas
1258 // of the mask, otherwise we spoil areas where no
1259 // bitmap content was ever visible. Interestingly
1260 // enough, this can be achieved by taking the mask as
1261 // the transparency mask of itself
1262 if( mpAlphaVDev )
1263 mpAlphaVDev->DrawBitmapEx( rDestPt,
1264 rDestSize,
1265 BitmapEx( aBmpEx.GetMask(),
1266 aBmpEx.GetMask() ) );
1267 }
1268 else
1269 {
1270 mpGraphics->DrawBitmap( aPosAry, *pSalSrcBmp, this );
1271
1272 if( mpAlphaVDev )
1273 {
1274 // #i32109#: Make bitmap area opaque
1275 mpAlphaVDev->ImplFillOpaqueRectangle( Rectangle(rDestPt, rDestSize) );
1276 }
1277 }
1278 }
1279 }
1280 }
1281
1282 // ------------------------------------------------------------------
1283
DrawMask(const Point & rDestPt,const Bitmap & rBitmap,const Color & rMaskColor)1284 void OutputDevice::DrawMask( const Point& rDestPt,
1285 const Bitmap& rBitmap, const Color& rMaskColor )
1286 {
1287 DBG_TRACE( "OutputDevice::DrawMask()" );
1288
1289 if( ImplIsRecordLayout() )
1290 return;
1291
1292 const Size aSizePix( rBitmap.GetSizePixel() );
1293 ImplDrawMask( rDestPt, PixelToLogic( aSizePix ), Point(), aSizePix, rBitmap, rMaskColor, META_MASK_ACTION );
1294
1295 if( mpAlphaVDev )
1296 {
1297 const Bitmap& rMask( rBitmap.CreateMask( rMaskColor ) );
1298
1299 // #i25167# Restrict mask painting to _opaque_ areas
1300 // of the mask, otherwise we spoil areas where no
1301 // bitmap content was ever visible. Interestingly
1302 // enough, this can be achieved by taking the mask as
1303 // the transparency mask of itself
1304 mpAlphaVDev->DrawBitmapEx( rDestPt,
1305 PixelToLogic( aSizePix ),
1306 BitmapEx( rMask, rMask ) );
1307 }
1308 }
1309
1310 // ------------------------------------------------------------------
1311
DrawMask(const Point & rDestPt,const Size & rDestSize,const Bitmap & rBitmap,const Color & rMaskColor)1312 void OutputDevice::DrawMask( const Point& rDestPt, const Size& rDestSize,
1313 const Bitmap& rBitmap, const Color& rMaskColor )
1314 {
1315 DBG_TRACE( "OutputDevice::DrawMask( Size )" );
1316
1317 if( ImplIsRecordLayout() )
1318 return;
1319
1320 ImplDrawMask( rDestPt, rDestSize, Point(), rBitmap.GetSizePixel(), rBitmap, rMaskColor, META_MASKSCALE_ACTION );
1321
1322 // TODO: Use mask here
1323 if( mpAlphaVDev )
1324 {
1325 const Bitmap& rMask( rBitmap.CreateMask( rMaskColor ) );
1326
1327 // #i25167# Restrict mask painting to _opaque_ areas
1328 // of the mask, otherwise we spoil areas where no
1329 // bitmap content was ever visible. Interestingly
1330 // enough, this can be achieved by taking the mask as
1331 // the transparency mask of itself
1332 mpAlphaVDev->DrawBitmapEx( rDestPt,
1333 rDestSize,
1334 BitmapEx( rMask, rMask ) );
1335 }
1336 }
1337
1338 // ------------------------------------------------------------------
1339
DrawMask(const Point & rDestPt,const Size & rDestSize,const Point & rSrcPtPixel,const Size & rSrcSizePixel,const Bitmap & rBitmap,const Color & rMaskColor)1340 void OutputDevice::DrawMask( const Point& rDestPt, const Size& rDestSize,
1341 const Point& rSrcPtPixel, const Size& rSrcSizePixel,
1342 const Bitmap& rBitmap, const Color& rMaskColor )
1343 {
1344 DBG_TRACE( "OutputDevice::DrawMask( Point, Size )" );
1345
1346 if( ImplIsRecordLayout() )
1347 return;
1348
1349 ImplDrawMask( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, rBitmap, rMaskColor, META_MASKSCALEPART_ACTION );
1350
1351 // TODO: Use mask here
1352 if( mpAlphaVDev )
1353 {
1354 const Bitmap& rMask( rBitmap.CreateMask( rMaskColor ) );
1355
1356 // #i25167# Restrict mask painting to _opaque_ areas
1357 // of the mask, otherwise we spoil areas where no
1358 // bitmap content was ever visible. Interestingly
1359 // enough, this can be achieved by taking the mask as
1360 // the transparency mask of itself
1361 mpAlphaVDev->DrawBitmapEx( rDestPt,
1362 rDestSize,
1363 rSrcPtPixel,
1364 rSrcSizePixel,
1365 BitmapEx( rMask, rMask ) );
1366 }
1367 }
1368
1369 // ------------------------------------------------------------------
1370
ImplDrawMask(const Point & rDestPt,const Size & rDestSize,const Point & rSrcPtPixel,const Size & rSrcSizePixel,const Bitmap & rBitmap,const Color & rMaskColor,const sal_uLong nAction)1371 void OutputDevice::ImplDrawMask( const Point& rDestPt, const Size& rDestSize,
1372 const Point& rSrcPtPixel, const Size& rSrcSizePixel,
1373 const Bitmap& rBitmap, const Color& rMaskColor,
1374 const sal_uLong nAction )
1375 {
1376 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
1377
1378 if( ROP_INVERT == meRasterOp )
1379 {
1380 DrawRect( Rectangle( rDestPt, rDestSize ) );
1381 return;
1382 }
1383
1384 if ( mpMetaFile )
1385 {
1386 switch( nAction )
1387 {
1388 case( META_MASK_ACTION ):
1389 mpMetaFile->AddAction( new MetaMaskAction( rDestPt,
1390 rBitmap, rMaskColor ) );
1391 break;
1392
1393 case( META_MASKSCALE_ACTION ):
1394 mpMetaFile->AddAction( new MetaMaskScaleAction( rDestPt,
1395 rDestSize, rBitmap, rMaskColor ) );
1396 break;
1397
1398 case( META_MASKSCALEPART_ACTION ):
1399 mpMetaFile->AddAction( new MetaMaskScalePartAction( rDestPt, rDestSize,
1400 rSrcPtPixel, rSrcSizePixel, rBitmap, rMaskColor ) );
1401 break;
1402 }
1403 }
1404
1405 OUTDEV_INIT();
1406
1407 if ( OUTDEV_PRINTER == meOutDevType )
1408 {
1409 ImplPrintMask( rBitmap, rMaskColor, rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel );
1410 return;
1411 }
1412
1413 const ImpBitmap* pImpBmp = rBitmap.ImplGetImpBitmap();
1414 if ( pImpBmp )
1415 {
1416 SalTwoRect aPosAry;
1417
1418 aPosAry.mnSrcX = rSrcPtPixel.X();
1419 aPosAry.mnSrcY = rSrcPtPixel.Y();
1420 aPosAry.mnSrcWidth = rSrcSizePixel.Width();
1421 aPosAry.mnSrcHeight = rSrcSizePixel.Height();
1422 aPosAry.mnDestX = ImplLogicXToDevicePixel( rDestPt.X() );
1423 aPosAry.mnDestY = ImplLogicYToDevicePixel( rDestPt.Y() );
1424 aPosAry.mnDestWidth = ImplLogicWidthToDevicePixel( rDestSize.Width() );
1425 aPosAry.mnDestHeight = ImplLogicHeightToDevicePixel( rDestSize.Height() );
1426
1427 // spiegeln via Koordinaten wollen wir nicht
1428 const sal_uLong nMirrFlags = ImplAdjustTwoRect( aPosAry, pImpBmp->ImplGetSize() );
1429
1430 // check if output is necessary
1431 if( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight )
1432 {
1433
1434 if( nMirrFlags )
1435 {
1436 Bitmap aTmp( rBitmap );
1437 aTmp.Mirror( nMirrFlags );
1438 mpGraphics->DrawMask( aPosAry, *aTmp.ImplGetImpBitmap()->ImplGetSalBitmap(),
1439 ImplColorToSal( rMaskColor ) , this);
1440 }
1441 else
1442 mpGraphics->DrawMask( aPosAry, *pImpBmp->ImplGetSalBitmap(),
1443 ImplColorToSal( rMaskColor ), this );
1444
1445 }
1446 }
1447 }
1448
1449 // ------------------------------------------------------------------
1450
DrawImage(const Point & rPos,const Image & rImage,sal_uInt16 nStyle)1451 void OutputDevice::DrawImage( const Point& rPos, const Image& rImage, sal_uInt16 nStyle )
1452 {
1453 DBG_ASSERT( GetOutDevType() != OUTDEV_PRINTER, "DrawImage(): Images can't be drawn on any mprinter" );
1454
1455 if( !rImage.mpImplData || ImplIsRecordLayout() )
1456 return;
1457
1458 switch( rImage.mpImplData->meType )
1459 {
1460 case IMAGETYPE_BITMAP:
1461 DrawBitmap( rPos, *static_cast< Bitmap* >( rImage.mpImplData->mpData ) );
1462 break;
1463
1464 case IMAGETYPE_IMAGE:
1465 {
1466 ImplImageData* pData = static_cast< ImplImageData* >( rImage.mpImplData->mpData );
1467
1468 if( !pData->mpImageBitmap )
1469 {
1470 const Size aSize( pData->maBmpEx.GetSizePixel() );
1471
1472 pData->mpImageBitmap = new ImplImageBmp;
1473 pData->mpImageBitmap->Create( pData->maBmpEx, aSize.Width(), aSize.Height(), 1 );
1474 }
1475
1476 pData->mpImageBitmap->Draw( 0, this, rPos, nStyle );
1477 }
1478 break;
1479
1480 default:
1481 break;
1482 }
1483 }
1484
1485 // ------------------------------------------------------------------
1486
DrawImage(const Point & rPos,const Size & rSize,const Image & rImage,sal_uInt16 nStyle)1487 void OutputDevice::DrawImage( const Point& rPos, const Size& rSize,
1488 const Image& rImage, sal_uInt16 nStyle )
1489 {
1490 DBG_ASSERT( GetOutDevType() != OUTDEV_PRINTER, "DrawImage(): Images can't be drawn on any mprinter" );
1491
1492 if( rImage.mpImplData && !ImplIsRecordLayout() )
1493 {
1494 switch( rImage.mpImplData->meType )
1495 {
1496 case IMAGETYPE_BITMAP:
1497 DrawBitmap( rPos, rSize, *static_cast< Bitmap* >( rImage.mpImplData->mpData ) );
1498 break;
1499
1500 case IMAGETYPE_IMAGE:
1501 {
1502 ImplImageData* pData = static_cast< ImplImageData* >( rImage.mpImplData->mpData );
1503
1504 if ( !pData->mpImageBitmap )
1505 {
1506 const Size aSize( pData->maBmpEx.GetSizePixel() );
1507
1508 pData->mpImageBitmap = new ImplImageBmp;
1509 pData->mpImageBitmap->Create( pData->maBmpEx, aSize.Width(), aSize.Height(), 1 );
1510 }
1511
1512 pData->mpImageBitmap->Draw( 0, this, rPos, nStyle, &rSize );
1513 }
1514 break;
1515
1516 default:
1517 break;
1518 }
1519 }
1520 }
1521
1522 // ------------------------------------------------------------------
1523
GetBitmap(const Point & rSrcPt,const Size & rSize) const1524 Bitmap OutputDevice::GetBitmap( const Point& rSrcPt, const Size& rSize ) const
1525 {
1526 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
1527 OSL_ENSURE(OUTDEV_PRINTER != GetOutDevType(), "OutputDevice::GetBitmap with sorce type OUTDEV_PRINTER should not be used (!)");
1528
1529 Bitmap aBmp;
1530 long nX = ImplLogicXToDevicePixel( rSrcPt.X() );
1531 long nY = ImplLogicYToDevicePixel( rSrcPt.Y() );
1532 long nWidth = ImplLogicWidthToDevicePixel( rSize.Width() );
1533 long nHeight = ImplLogicHeightToDevicePixel( rSize.Height() );
1534
1535 if ( mpGraphics || ( (OutputDevice*) this )->ImplGetGraphics() )
1536 {
1537 if ( nWidth > 0 && nHeight > 0 && nX <= (mnOutWidth + mnOutOffX) && nY <= (mnOutHeight + mnOutOffY))
1538 {
1539 Rectangle aRect( Point( nX, nY ), Size( nWidth, nHeight ) );
1540 sal_Bool bClipped = sal_False;
1541
1542 // X-Koordinate ausserhalb des Bereichs?
1543 if ( nX < mnOutOffX )
1544 {
1545 nWidth -= ( mnOutOffX - nX );
1546 nX = mnOutOffX;
1547 bClipped = sal_True;
1548 }
1549
1550 // Y-Koordinate ausserhalb des Bereichs?
1551 if ( nY < mnOutOffY )
1552 {
1553 nHeight -= ( mnOutOffY - nY );
1554 nY = mnOutOffY;
1555 bClipped = sal_True;
1556 }
1557
1558 // Breite ausserhalb des Bereichs?
1559 if ( (nWidth + nX) > (mnOutWidth + mnOutOffX) )
1560 {
1561 nWidth = mnOutOffX + mnOutWidth - nX;
1562 bClipped = sal_True;
1563 }
1564
1565 // Hoehe ausserhalb des Bereichs?
1566 if ( (nHeight + nY) > (mnOutHeight + mnOutOffY) )
1567 {
1568 nHeight = mnOutOffY + mnOutHeight - nY;
1569 bClipped = sal_True;
1570 }
1571
1572 if ( bClipped )
1573 {
1574 // Falls auf den sichtbaren Bereich geclipped wurde,
1575 // muessen wir eine Bitmap in der rchtigen Groesse
1576 // erzeugen, in die die geclippte Bitmap an die angepasste
1577 // Position kopiert wird
1578 VirtualDevice aVDev( *this );
1579
1580 if ( aVDev.SetOutputSizePixel( aRect.GetSize() ) )
1581 {
1582 if ( ((OutputDevice*)&aVDev)->mpGraphics || ((OutputDevice*)&aVDev)->ImplGetGraphics() )
1583 {
1584 SalTwoRect aPosAry;
1585
1586 aPosAry.mnSrcX = nX;
1587 aPosAry.mnSrcY = nY;
1588 aPosAry.mnSrcWidth = nWidth;
1589 aPosAry.mnSrcHeight = nHeight;
1590 aPosAry.mnDestX = ( aRect.Left() < mnOutOffX ) ? ( mnOutOffX - aRect.Left() ) : 0L;
1591 aPosAry.mnDestY = ( aRect.Top() < mnOutOffY ) ? ( mnOutOffY - aRect.Top() ) : 0L;
1592 aPosAry.mnDestWidth = nWidth;
1593 aPosAry.mnDestHeight = nHeight;
1594
1595 if ( (nWidth > 0) && (nHeight > 0) )
1596 {
1597 (((OutputDevice*)&aVDev)->mpGraphics)->CopyBits( aPosAry, mpGraphics, this, this );
1598 }
1599 else
1600 {
1601 OSL_ENSURE(false, "CopyBits with negative width or height (!)");
1602 }
1603
1604 aBmp = aVDev.GetBitmap( Point(), aVDev.GetOutputSizePixel() );
1605 }
1606 else
1607 bClipped = sal_False;
1608 }
1609 else
1610 bClipped = sal_False;
1611 }
1612
1613 if ( !bClipped )
1614 {
1615 SalBitmap* pSalBmp = mpGraphics->GetBitmap( nX, nY, nWidth, nHeight, this );
1616
1617 if( pSalBmp )
1618 {
1619 ImpBitmap* pImpBmp = new ImpBitmap;
1620 pImpBmp->ImplSetSalBitmap( pSalBmp );
1621 aBmp.ImplSetImpBitmap( pImpBmp );
1622 }
1623 }
1624 }
1625 }
1626
1627 return aBmp;
1628 }
1629
1630 // ------------------------------------------------------------------
1631
GetBitmapEx(const Point & rSrcPt,const Size & rSize) const1632 BitmapEx OutputDevice::GetBitmapEx( const Point& rSrcPt, const Size& rSize ) const
1633 {
1634 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
1635
1636 // #110958# Extract alpha value from VDev, if any
1637 if( mpAlphaVDev )
1638 {
1639 Bitmap aAlphaBitmap( mpAlphaVDev->GetBitmap( rSrcPt, rSize ) );
1640
1641 // ensure 8 bit alpha
1642 if( aAlphaBitmap.GetBitCount() > 8 )
1643 aAlphaBitmap.Convert( BMP_CONVERSION_8BIT_GREYS );
1644
1645 return BitmapEx(GetBitmap( rSrcPt, rSize ), AlphaMask( aAlphaBitmap ) );
1646 }
1647 else
1648 return GetBitmap( rSrcPt, rSize );
1649 }
1650
1651 // ------------------------------------------------------------------
1652
ImplGetFrameBitmap(const Point & rDestPt,const Size & rSize,Bitmap & rBitmap) const1653 void OutputDevice::ImplGetFrameBitmap( const Point& rDestPt, const Size& rSize,
1654 Bitmap& rBitmap ) const
1655 {
1656 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
1657
1658 sal_Bool bOldMap = mbMap;
1659 ((OutputDevice*)this)->mbMap = sal_False;
1660 rBitmap = GetBitmap( rDestPt, rSize );
1661 ((OutputDevice*)this)->mbMap = bOldMap;
1662 }
1663
1664 // ------------------------------------------------------------------
1665
GetPixel(const Point & rPt) const1666 Color OutputDevice::GetPixel( const Point& rPt ) const
1667 {
1668 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
1669
1670 Color aColor;
1671
1672 if ( mpGraphics || ((OutputDevice*)this)->ImplGetGraphics() )
1673 {
1674 if ( mbInitClipRegion )
1675 ((OutputDevice*)this)->ImplInitClipRegion();
1676
1677 if ( !mbOutputClipped )
1678 {
1679 const long nX = ImplLogicXToDevicePixel( rPt.X() );
1680 const long nY = ImplLogicYToDevicePixel( rPt.Y() );
1681 const SalColor aSalCol = mpGraphics->GetPixel( nX, nY, this );
1682 aColor.SetRed( SALCOLOR_RED( aSalCol ) );
1683 aColor.SetGreen( SALCOLOR_GREEN( aSalCol ) );
1684 aColor.SetBlue( SALCOLOR_BLUE( aSalCol ) );
1685 }
1686 }
1687 return aColor;
1688 }
1689
1690 // ------------------------------------------------------------------
1691
GetPixel(const Polygon & rPts) const1692 Color* OutputDevice::GetPixel( const Polygon& rPts ) const
1693 {
1694 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
1695
1696 Color* pColors = NULL;
1697 const sal_uInt16 nSize = rPts.GetSize();
1698
1699 if( nSize )
1700 {
1701 if ( mpGraphics || ((OutputDevice*)this)->ImplGetGraphics() )
1702 {
1703 if ( mbInitClipRegion )
1704 ((OutputDevice*)this)->ImplInitClipRegion();
1705
1706 if ( !mbOutputClipped )
1707 {
1708 pColors = new Color[ nSize ];
1709
1710 for( sal_uInt16 i = 0; i < nSize; i++ )
1711 {
1712 Color& rCol = pColors[ i ];
1713 const Point& rPt = rPts[ i ];
1714 const SalColor aSalCol( mpGraphics->GetPixel( ImplLogicXToDevicePixel( rPt.X() ),
1715 ImplLogicYToDevicePixel( rPt.Y() ) , this) );
1716
1717 rCol.SetRed( SALCOLOR_RED( aSalCol ) );
1718 rCol.SetGreen( SALCOLOR_GREEN( aSalCol ) );
1719 rCol.SetBlue( SALCOLOR_BLUE( aSalCol ) );
1720 }
1721 }
1722 }
1723 }
1724
1725 return pColors;
1726 }
1727
1728 // -----------------------------------------------------------------------
1729
DrawPixel(const Point & rPt)1730 void OutputDevice::DrawPixel( const Point& rPt )
1731 {
1732 DBG_TRACE( "OutputDevice::DrawPixel()" );
1733 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
1734
1735 if ( mpMetaFile )
1736 mpMetaFile->AddAction( new MetaPointAction( rPt ) );
1737
1738 if ( !IsDeviceOutputNecessary() || !mbLineColor || ImplIsRecordLayout() )
1739 return;
1740
1741 Point aPt = ImplLogicToDevicePixel( rPt );
1742
1743 // we need a graphics
1744 if ( !mpGraphics )
1745 {
1746 if ( !ImplGetGraphics() )
1747 return;
1748 }
1749
1750 if ( mbInitClipRegion )
1751 ImplInitClipRegion();
1752 if ( mbOutputClipped )
1753 return;
1754
1755 if ( mbInitLineColor )
1756 ImplInitLineColor();
1757
1758 mpGraphics->DrawPixel( aPt.X(), aPt.Y(), this );
1759
1760 if( mpAlphaVDev )
1761 mpAlphaVDev->DrawPixel( rPt );
1762 }
1763
1764 // -----------------------------------------------------------------------
1765
DrawPixel(const Point & rPt,const Color & rColor)1766 void OutputDevice::DrawPixel( const Point& rPt, const Color& rColor )
1767 {
1768 DBG_TRACE( "OutputDevice::DrawPixel()" );
1769 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
1770
1771 Color aColor( rColor );
1772
1773 if( mnDrawMode & ( DRAWMODE_BLACKLINE | DRAWMODE_WHITELINE |
1774 DRAWMODE_GRAYLINE | DRAWMODE_GHOSTEDLINE |
1775 DRAWMODE_SETTINGSLINE ) )
1776 {
1777 if( !ImplIsColorTransparent( aColor ) )
1778 {
1779 if( mnDrawMode & DRAWMODE_BLACKLINE )
1780 {
1781 aColor = Color( COL_BLACK );
1782 }
1783 else if( mnDrawMode & DRAWMODE_WHITELINE )
1784 {
1785 aColor = Color( COL_WHITE );
1786 }
1787 else if( mnDrawMode & DRAWMODE_GRAYLINE )
1788 {
1789 const sal_uInt8 cLum = aColor.GetLuminance();
1790 aColor = Color( cLum, cLum, cLum );
1791 }
1792 else if( mnDrawMode & DRAWMODE_SETTINGSLINE )
1793 {
1794 aColor = GetSettings().GetStyleSettings().GetFontColor();
1795 }
1796
1797 if( mnDrawMode & DRAWMODE_GHOSTEDLINE )
1798 {
1799 aColor = Color( ( aColor.GetRed() >> 1 ) | 0x80,
1800 ( aColor.GetGreen() >> 1 ) | 0x80,
1801 ( aColor.GetBlue() >> 1 ) | 0x80 );
1802 }
1803 }
1804 }
1805
1806 if ( mpMetaFile )
1807 mpMetaFile->AddAction( new MetaPixelAction( rPt, aColor ) );
1808
1809 if ( !IsDeviceOutputNecessary() || ImplIsColorTransparent( aColor ) || ImplIsRecordLayout() )
1810 return;
1811
1812 Point aPt = ImplLogicToDevicePixel( rPt );
1813
1814 // we need a graphics
1815 if ( !mpGraphics )
1816 {
1817 if ( !ImplGetGraphics() )
1818 return;
1819 }
1820
1821 if ( mbInitClipRegion )
1822 ImplInitClipRegion();
1823 if ( mbOutputClipped )
1824 return;
1825
1826 mpGraphics->DrawPixel( aPt.X(), aPt.Y(), ImplColorToSal( aColor ), this );
1827
1828 if( mpAlphaVDev )
1829 mpAlphaVDev->DrawPixel( rPt );
1830 }
1831
1832 // -----------------------------------------------------------------------
1833
DrawPixel(const Polygon & rPts,const Color * pColors)1834 void OutputDevice::DrawPixel( const Polygon& rPts, const Color* pColors )
1835 {
1836 if ( !pColors )
1837 DrawPixel( rPts, GetLineColor() );
1838 else
1839 {
1840 DBG_TRACE( "OutputDevice::DrawPixel()" );
1841 DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
1842 DBG_ASSERT( pColors, "OutputDevice::DrawPixel: No color array specified" );
1843
1844 const sal_uInt16 nSize = rPts.GetSize();
1845
1846 if ( nSize )
1847 {
1848 if ( mpMetaFile )
1849 for ( sal_uInt16 i = 0; i < nSize; i++ )
1850 mpMetaFile->AddAction( new MetaPixelAction( rPts[ i ], pColors[ i ] ) );
1851
1852 if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
1853 return;
1854
1855 // we need a graphics
1856 if ( mpGraphics || ImplGetGraphics() )
1857 {
1858 if ( mbInitClipRegion )
1859 ImplInitClipRegion();
1860
1861 if ( mbOutputClipped )
1862 return;
1863
1864 for ( sal_uInt16 i = 0; i < nSize; i++ )
1865 {
1866 const Point aPt( ImplLogicToDevicePixel( rPts[ i ] ) );
1867 mpGraphics->DrawPixel( aPt.X(), aPt.Y(), ImplColorToSal( pColors[ i ] ), this );
1868 }
1869 }
1870 }
1871 }
1872
1873 if( mpAlphaVDev )
1874 mpAlphaVDev->DrawPixel( rPts, pColors );
1875 }
1876
1877 // -----------------------------------------------------------------------
1878
DrawPixel(const Polygon & rPts,const Color & rColor)1879 void OutputDevice::DrawPixel( const Polygon& rPts, const Color& rColor )
1880 {
1881 if( rColor != COL_TRANSPARENT && ! ImplIsRecordLayout() )
1882 {
1883 const sal_uInt16 nSize = rPts.GetSize();
1884 Color* pColArray = new Color[ nSize ];
1885
1886 for( sal_uInt16 i = 0; i < nSize; i++ )
1887 pColArray[ i ] = rColor;
1888
1889 DrawPixel( rPts, pColArray );
1890 delete[] pColArray;
1891 }
1892
1893 if( mpAlphaVDev )
1894 mpAlphaVDev->DrawPixel( rPts, rColor );
1895 }
1896
1897 // ------------------------------------------------------------------------
1898
1899 namespace
1900 {
lcl_calcColor(const sal_uInt8 nSourceColor,const sal_uInt8 nSourceOpaq,const sal_uInt8 nDestColor)1901 sal_uInt8 lcl_calcColor( const sal_uInt8 nSourceColor, const sal_uInt8 nSourceOpaq, const sal_uInt8 nDestColor )
1902 {
1903 int c = ( (int)nDestColor * ( 255 - nSourceOpaq ) )
1904 + (int)nSourceOpaq * (int)nSourceColor;
1905 return sal_uInt8( c / 255 );
1906 }
1907 }
1908
1909 // ------------------------------------------------------------------------
1910
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)1911 Bitmap OutputDevice::ImplBlendWithAlpha( Bitmap aBmp,
1912 BitmapReadAccess* pP,
1913 BitmapReadAccess* pA,
1914 const Rectangle& aDstRect,
1915 const sal_Int32 nOffY,
1916 const sal_Int32 nDstHeight,
1917 const sal_Int32 nOffX,
1918 const sal_Int32 nDstWidth,
1919 const long* pMapX,
1920 const long* pMapY )
1921 {
1922 BitmapColor aDstCol,aSrcCol;
1923 Bitmap res;
1924 int nX, nOutX, nY, nOutY;
1925
1926 OSL_ENSURE(mpAlphaVDev,
1927 "ImplBlendWithAlpha(): call me only with valid alpha VDev!" );
1928
1929 sal_Bool bOldMapMode( mpAlphaVDev->IsMapModeEnabled() );
1930 mpAlphaVDev->EnableMapMode(sal_False);
1931
1932 Bitmap aAlphaBitmap( mpAlphaVDev->GetBitmap( aDstRect.TopLeft(), aDstRect.GetSize() ) );
1933 BitmapWriteAccess* pAlphaW = aAlphaBitmap.AcquireWriteAccess();
1934
1935 if( GetBitCount() <= 8 )
1936 {
1937 Bitmap aDither( aBmp.GetSizePixel(), 8 );
1938 BitmapColor aIndex( 0 );
1939 BitmapReadAccess* pB = aBmp.AcquireReadAccess();
1940 BitmapWriteAccess* pW = aDither.AcquireWriteAccess();
1941
1942 if( pB && pP && pA && pW && pAlphaW )
1943 {
1944 for( nY = 0, nOutY = nOffY; nY < nDstHeight; nY++, nOutY++ )
1945 {
1946 const long nMapY = pMapY[ nY ];
1947 const long nModY = ( nOutY & 0x0FL ) << 4L;
1948
1949 for( nX = 0, nOutX = nOffX; nX < nDstWidth; nX++, nOutX++ )
1950 {
1951 const long nMapX = pMapX[ nX ];
1952 const sal_uLong nD = nVCLDitherLut[ nModY | ( nOutX & 0x0FL ) ];
1953
1954 aSrcCol = pP->GetColor( nMapY, nMapX );
1955 aDstCol = pB->GetColor( nY, nX );
1956 const sal_uInt8 nSrcOpaq = 255 - pA->GetPixelIndex( nMapY, nMapX );
1957 const sal_uInt8 nDstOpaq = 255 - pAlphaW->GetPixelIndex( nY, nX );
1958
1959 aDstCol.SetRed( lcl_calcColor( aSrcCol.GetRed(), nSrcOpaq, aDstCol.GetRed() ) );
1960 aDstCol.SetBlue( lcl_calcColor( aSrcCol.GetBlue(), nSrcOpaq, aDstCol.GetBlue() ) );
1961 aDstCol.SetGreen( lcl_calcColor( aSrcCol.GetGreen(), nSrcOpaq, aDstCol.GetGreen() ) );
1962
1963 aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ ( nVCLLut[ aDstCol.GetRed() ] + nD ) >> 16UL ] +
1964 nVCLGLut[ ( nVCLLut[ aDstCol.GetGreen() ] + nD ) >> 16UL ] +
1965 nVCLBLut[ ( nVCLLut[ aDstCol.GetBlue() ] + nD ) >> 16UL ] ) );
1966 pW->SetPixel( nY, nX, aIndex );
1967
1968 // Have to perform the compositing 'algebra' in
1969 // the inverse alpha space (with 255 meaning
1970 // opaque), otherwise, transitivity is not
1971 // achieved.
1972 const sal_uInt8 nSrcAlpha = 255-COLOR_CHANNEL_MERGE( 255, (sal_uInt8)nDstOpaq, nSrcOpaq );
1973
1974 aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ ( nVCLLut[ nSrcAlpha ] + nD ) >> 16UL ] +
1975 nVCLGLut[ ( nVCLLut[ nSrcAlpha ] + nD ) >> 16UL ] +
1976 nVCLBLut[ ( nVCLLut[ nSrcAlpha ] + nD ) >> 16UL ] ) );
1977 pAlphaW->SetPixel( nY, nX, aIndex );
1978 }
1979 }
1980 }
1981
1982 aBmp.ReleaseAccess( pB );
1983 aDither.ReleaseAccess( pW );
1984 res = aDither;
1985 }
1986 else
1987 {
1988 BitmapWriteAccess* pB = aBmp.AcquireWriteAccess();
1989 if( pP && pA && pB )
1990 {
1991 for( nY = 0; nY < nDstHeight; nY++ )
1992 {
1993 const long nMapY = pMapY[ nY ];
1994
1995 for( nX = 0; nX < nDstWidth; nX++ )
1996 {
1997 const long nMapX = pMapX[ nX ];
1998
1999 aSrcCol = pP->GetColor( nMapY, nMapX );
2000 aDstCol = pB->GetColor( nY, nX );
2001 const sal_uInt8 nSrcOpaq = 255 - pA->GetPixelIndex( nMapY, nMapX );
2002 const sal_uInt8 nDstOpaq = 255 - pAlphaW->GetPixelIndex( nY, nX );
2003
2004 aDstCol.SetRed( lcl_calcColor( aSrcCol.GetRed(), nSrcOpaq, aDstCol.GetRed() ) );
2005 aDstCol.SetBlue( lcl_calcColor( aSrcCol.GetBlue(), nSrcOpaq, aDstCol.GetBlue() ) );
2006 aDstCol.SetGreen( lcl_calcColor( aSrcCol.GetGreen(), nSrcOpaq, aDstCol.GetGreen() ) );
2007
2008 pB->SetPixel( nY, nX, aDstCol );
2009
2010 // Have to perform the compositing 'algebra' in
2011 // the inverse alpha space (with 255 meaning
2012 // opaque), otherwise, transitivity is not
2013 // achieved.
2014 const sal_uInt8 nSrcAlpha = 255-COLOR_CHANNEL_MERGE( 255, (sal_uInt8)nDstOpaq, nSrcOpaq );
2015
2016 pAlphaW->SetPixel( nY, nX, Color(nSrcAlpha, nSrcAlpha, nSrcAlpha) );
2017 }
2018 }
2019 }
2020
2021 aBmp.ReleaseAccess( pB );
2022 res = aBmp;
2023 }
2024
2025 aAlphaBitmap.ReleaseAccess( pAlphaW );
2026 mpAlphaVDev->DrawBitmap( aDstRect.TopLeft(), aAlphaBitmap );
2027 mpAlphaVDev->EnableMapMode( bOldMapMode );
2028
2029 return res;
2030 }
2031
2032 // ------------------------------------------------------------------------
2033
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)2034 Bitmap OutputDevice::ImplBlend( Bitmap aBmp,
2035 BitmapReadAccess* pP,
2036 BitmapReadAccess* pA,
2037 const sal_Int32 nOffY,
2038 const sal_Int32 nDstHeight,
2039 const sal_Int32 nOffX,
2040 const sal_Int32 nDstWidth,
2041 const Rectangle& aBmpRect,
2042 const Size& aOutSz,
2043 const bool bHMirr,
2044 const bool bVMirr,
2045 const long* pMapX,
2046 const long* pMapY )
2047 {
2048 BitmapColor aDstCol;
2049 Bitmap res;
2050 int nX, nOutX, nY, nOutY;
2051
2052 if( GetBitCount() <= 8 )
2053 {
2054 Bitmap aDither( aBmp.GetSizePixel(), 8 );
2055 BitmapColor aIndex( 0 );
2056 BitmapReadAccess* pB = aBmp.AcquireReadAccess();
2057 BitmapWriteAccess* pW = aDither.AcquireWriteAccess();
2058
2059 if( pB && pP && pA && pW )
2060 {
2061 for( nY = 0, nOutY = nOffY; nY < nDstHeight; nY++, nOutY++ )
2062 {
2063 const long nMapY = pMapY[ nY ];
2064 const long nModY = ( nOutY & 0x0FL ) << 4L;
2065
2066 for( nX = 0, nOutX = nOffX; nX < nDstWidth; nX++, nOutX++ )
2067 {
2068 const long nMapX = pMapX[ nX ];
2069 const sal_uLong nD = nVCLDitherLut[ nModY | ( nOutX & 0x0FL ) ];
2070
2071 aDstCol = pB->GetColor( nY, nX );
2072 aDstCol.Merge( pP->GetColor( nMapY, nMapX ), pA->GetPixelIndex( nMapY, nMapX ) );
2073 aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ ( nVCLLut[ aDstCol.GetRed() ] + nD ) >> 16UL ] +
2074 nVCLGLut[ ( nVCLLut[ aDstCol.GetGreen() ] + nD ) >> 16UL ] +
2075 nVCLBLut[ ( nVCLLut[ aDstCol.GetBlue() ] + nD ) >> 16UL ] ) );
2076 pW->SetPixel( nY, nX, aIndex );
2077 }
2078 }
2079 }
2080
2081 aBmp.ReleaseAccess( pB );
2082 aDither.ReleaseAccess( pW );
2083 res = aDither;
2084 }
2085 else
2086 {
2087 BitmapWriteAccess* pB = aBmp.AcquireWriteAccess();
2088
2089 bool bFastBlend = false;
2090 if( pP && pA && pB )
2091 {
2092 SalTwoRect aTR;
2093 aTR.mnSrcX = aBmpRect.Left();
2094 aTR.mnSrcY = aBmpRect.Top();
2095 aTR.mnSrcWidth = aBmpRect.GetWidth();
2096 aTR.mnSrcHeight = aBmpRect.GetHeight();
2097 aTR.mnDestX = nOffX;
2098 aTR.mnDestY = nOffY;
2099 aTR.mnDestWidth = aOutSz.Width();
2100 aTR.mnDestHeight= aOutSz.Height();
2101
2102 if( !bHMirr || !bVMirr )
2103 bFastBlend = ImplFastBitmapBlending( *pB,*pP,*pA, aTR );
2104 }
2105
2106 if( pP && pA && pB && !bFastBlend )
2107 {
2108 switch( pP->GetScanlineFormat() )
2109 {
2110 case( BMP_FORMAT_8BIT_PAL ):
2111 {
2112 for( nY = 0; nY < nDstHeight; nY++ )
2113 {
2114 const long nMapY = pMapY[ nY ];
2115 Scanline pPScan = pP->GetScanline( nMapY );
2116 Scanline pAScan = pA->GetScanline( nMapY );
2117
2118 for( nX = 0; nX < nDstWidth; nX++ )
2119 {
2120 const long nMapX = pMapX[ nX ];
2121 aDstCol = pB->GetPixel( nY, nX );
2122 pB->SetPixel( nY, nX, aDstCol.Merge( pP->GetPaletteColor( pPScan[ nMapX ] ),
2123 pAScan[ nMapX ] ) );
2124 }
2125 }
2126 }
2127 break;
2128
2129 case( BMP_FORMAT_24BIT_TC_BGR ):
2130 {
2131 for( nY = 0; nY < nDstHeight; nY++ )
2132 {
2133 const long nMapY = pMapY[ nY ];
2134 Scanline pPScan = pP->GetScanline( nMapY );
2135 Scanline pAScan = pA->GetScanline( nMapY );
2136
2137 for( nX = 0; nX < nDstWidth; nX++ )
2138 {
2139 const long nMapX = pMapX[ nX ];
2140 Scanline pTmp = pPScan + nMapX * 3;
2141
2142 aDstCol = pB->GetPixel( nY, nX );
2143 pB->SetPixel( nY, nX, aDstCol.Merge( pTmp[ 2 ], pTmp[ 1 ], pTmp[ 0 ],
2144 pAScan[ nMapX ] ) );
2145 }
2146 }
2147 }
2148 break;
2149
2150 case( BMP_FORMAT_24BIT_TC_RGB ):
2151 {
2152 for( nY = 0; nY < nDstHeight; nY++ )
2153 {
2154 const long nMapY = pMapY[ nY ];
2155 Scanline pPScan = pP->GetScanline( nMapY );
2156 Scanline pAScan = pA->GetScanline( nMapY );
2157
2158 for( nX = 0; nX < nDstWidth; nX++ )
2159 {
2160 const long nMapX = pMapX[ nX ];
2161 Scanline pTmp = pPScan + nMapX * 3;
2162
2163 aDstCol = pB->GetPixel( nY, nX );
2164 pB->SetPixel( nY, nX, aDstCol.Merge( pTmp[ 0 ], pTmp[ 1 ], pTmp[ 2 ],
2165 pAScan[ nMapX ] ) );
2166 }
2167 }
2168 }
2169 break;
2170
2171 default:
2172 {
2173 for( nY = 0; nY < nDstHeight; nY++ )
2174 {
2175 const long nMapY = pMapY[ nY ];
2176 Scanline pAScan = pA->GetScanline( nMapY );
2177
2178 for( nX = 0; nX < nDstWidth; nX++ )
2179 {
2180 const long nMapX = pMapX[ nX ];
2181 aDstCol = pB->GetPixel( nY, nX );
2182 pB->SetPixel( nY, nX, aDstCol.Merge( pP->GetColor( nMapY, nMapX ),
2183 pAScan[ nMapX ] ) );
2184 }
2185 }
2186 }
2187 break;
2188 }
2189 }
2190
2191 aBmp.ReleaseAccess( pB );
2192 res = aBmp;
2193 }
2194
2195 return res;
2196 }
2197
2198 // ------------------------------------------------------------------------
2199
ImplDrawAlpha(const Bitmap & rBmp,const AlphaMask & rAlpha,const Point & rDestPt,const Size & rDestSize,const Point & rSrcPtPixel,const Size & rSrcSizePixel)2200 void OutputDevice::ImplDrawAlpha( const Bitmap& rBmp, const AlphaMask& rAlpha,
2201 const Point& rDestPt, const Size& rDestSize,
2202 const Point& rSrcPtPixel, const Size& rSrcSizePixel )
2203 {
2204 const Point aNullPt;
2205 Point aOutPt( LogicToPixel( rDestPt ) );
2206 Size aOutSz( LogicToPixel( rDestSize ) );
2207 Rectangle aDstRect( aNullPt, GetOutputSizePixel() );
2208 const sal_Bool bHMirr = aOutSz.Width() < 0, bVMirr = aOutSz.Height() < 0;
2209
2210 if( OUTDEV_WINDOW == meOutDevType )
2211 {
2212 const Region aPaintRgn( ( (Window*) this )->GetPaintRegion() );
2213
2214 if( !aPaintRgn.IsNull() )
2215 aDstRect.Intersection( LogicToPixel( aPaintRgn.GetBoundRect() ) );
2216 }
2217
2218 if( bHMirr )
2219 {
2220 aOutSz.Width() = -aOutSz.Width();
2221 aOutPt.X() -= ( aOutSz.Width() - 1L );
2222 }
2223
2224 if( bVMirr )
2225 {
2226 aOutSz.Height() = -aOutSz.Height();
2227 aOutPt.Y() -= ( aOutSz.Height() - 1L );
2228 }
2229
2230 if( !aDstRect.Intersection( Rectangle( aOutPt, aOutSz ) ).IsEmpty() )
2231 {
2232 bool bNativeAlpha = false;
2233 static const char* pDisableNative = getenv( "SAL_DISABLE_NATIVE_ALPHA");
2234 // #i83087# Naturally, system alpha blending cannot work with
2235 // separate alpha VDev
2236 bool bTryDirectPaint(!mpAlphaVDev && !pDisableNative && !bHMirr && !bVMirr);
2237
2238 #ifdef WNT
2239 if(bTryDirectPaint)
2240 {
2241 // only paint direct when no scaling and no MapMode, else the
2242 // more expensive conversions may be done for short-time Bitmap/BitmapEx
2243 // used for buffering only
2244 if(!IsMapMode() && rSrcSizePixel.Width() == aOutSz.Width() && rSrcSizePixel.Height() == aOutSz.Height())
2245 {
2246 bTryDirectPaint = false;
2247 }
2248 }
2249 #endif
2250
2251 if(bTryDirectPaint)
2252 {
2253 Point aRelPt = aOutPt + Point( mnOutOffX, mnOutOffY );
2254 SalTwoRect aTR = {
2255 rSrcPtPixel.X(), rSrcPtPixel.Y(),
2256 rSrcSizePixel.Width(), rSrcSizePixel.Height(),
2257 aRelPt.X(), aRelPt.Y(),
2258 aOutSz.Width(), aOutSz.Height()
2259 };
2260 SalBitmap* pSalSrcBmp = rBmp.ImplGetImpBitmap()->ImplGetSalBitmap();
2261 SalBitmap* pSalAlphaBmp = rAlpha.ImplGetImpBitmap()->ImplGetSalBitmap();
2262 bNativeAlpha = mpGraphics->DrawAlphaBitmap( aTR, *pSalSrcBmp, *pSalAlphaBmp, this );
2263 }
2264
2265 VirtualDevice* pOldVDev = mpAlphaVDev;
2266
2267 Rectangle aBmpRect( aNullPt, rBmp.GetSizePixel() );
2268 if( !bNativeAlpha
2269 && !aBmpRect.Intersection( Rectangle( rSrcPtPixel, rSrcSizePixel ) ).IsEmpty() )
2270 {
2271 GDIMetaFile* pOldMetaFile = mpMetaFile; mpMetaFile = NULL;
2272 const sal_Bool bOldMap = mbMap; mbMap = sal_False;
2273 Bitmap aBmp( GetBitmap( aDstRect.TopLeft(), aDstRect.GetSize() ) );
2274
2275 // #109044# The generated bitmap need not necessarily be
2276 // of aDstRect dimensions, it's internally clipped to
2277 // window bounds. Thus, we correct the dest size here,
2278 // since we later use it (in nDstWidth/Height) for pixel
2279 // access)
2280 // #i38887# reading from screen may sometimes fail
2281 if( aBmp.ImplGetImpBitmap() )
2282 aDstRect.SetSize( aBmp.GetSizePixel() );
2283
2284 BitmapColor aDstCol;
2285 const long nSrcWidth = aBmpRect.GetWidth(), nSrcHeight = aBmpRect.GetHeight();
2286 const long nDstWidth = aDstRect.GetWidth(), nDstHeight = aDstRect.GetHeight();
2287 const long nOutWidth = aOutSz.Width(), nOutHeight = aOutSz.Height();
2288 // calculate offset in original bitmap
2289 // in RTL case this is a little more complicated since the contents of the
2290 // bitmap is not mirrored (it never is), however the paint region and bmp region
2291 // are in mirrored coordinates, so the intersection of (aOutPt,aOutSz) with these
2292 // is content wise somewhere else and needs to take mirroring into account
2293 const long nOffX = IsRTLEnabled()
2294 ? aOutSz.Width() - aDstRect.GetWidth() - (aDstRect.Left() - aOutPt.X())
2295 : aDstRect.Left() - aOutPt.X(),
2296 nOffY = aDstRect.Top() - aOutPt.Y();
2297 long nX, nOutX, nY, nOutY;
2298 long nMirrOffX = 0;
2299 long nMirrOffY = 0;
2300 long* pMapX = new long[ nDstWidth ];
2301 long* pMapY = new long[ nDstHeight ];
2302
2303 // create horizontal mapping table
2304 if( bHMirr )
2305 nMirrOffX = ( aBmpRect.Left() << 1 ) + nSrcWidth - 1;
2306
2307 for( nX = 0L, nOutX = nOffX; nX < nDstWidth; nX++, nOutX++ )
2308 {
2309 pMapX[ nX ] = aBmpRect.Left() + nOutX * nSrcWidth / nOutWidth;
2310 if( bHMirr )
2311 pMapX[ nX ] = nMirrOffX - pMapX[ nX ];
2312 }
2313
2314 // create vertical mapping table
2315 if( bVMirr )
2316 nMirrOffY = ( aBmpRect.Top() << 1 ) + nSrcHeight - 1;
2317
2318 for( nY = 0L, nOutY = nOffY; nY < nDstHeight; nY++, nOutY++ )
2319 {
2320 pMapY[ nY ] = aBmpRect.Top() + nOutY * nSrcHeight / nOutHeight;
2321
2322 if( bVMirr )
2323 pMapY[ nY ] = nMirrOffY - pMapY[ nY ];
2324 }
2325
2326 BitmapReadAccess* pP = ( (Bitmap&) rBmp ).AcquireReadAccess();
2327 BitmapReadAccess* pA = ( (AlphaMask&) rAlpha ).AcquireReadAccess();
2328
2329 DBG_ASSERT( pA->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL ||
2330 pA->GetScanlineFormat() == BMP_FORMAT_8BIT_TC_MASK,
2331 "OutputDevice::ImplDrawAlpha(): non-8bit alpha no longer supported!" );
2332
2333 // #i38887# reading from screen may sometimes fail
2334 if( aBmp.ImplGetImpBitmap() )
2335 {
2336 Bitmap aTmp;
2337
2338 if( mpAlphaVDev )
2339 {
2340 aTmp = ImplBlendWithAlpha(
2341 aBmp,pP,pA,
2342 aDstRect,
2343 nOffY,nDstHeight,
2344 nOffX,nDstWidth,
2345 pMapX,pMapY );
2346 }
2347 else
2348 {
2349 aTmp = ImplBlend(
2350 aBmp,pP,pA,
2351 nOffY,nDstHeight,
2352 nOffX,nDstWidth,
2353 aBmpRect,aOutSz,
2354 bHMirr,bVMirr,
2355 pMapX,pMapY );
2356 }
2357
2358 // #110958# Disable alpha VDev, we're doing the necessary
2359 // stuff explicitly further below
2360 if( mpAlphaVDev )
2361 mpAlphaVDev = NULL;
2362
2363 DrawBitmap( aDstRect.TopLeft(),
2364 aTmp );
2365
2366 // #110958# Enable alpha VDev again
2367 mpAlphaVDev = pOldVDev;
2368 }
2369
2370 ( (Bitmap&) rBmp ).ReleaseAccess( pP );
2371 ( (AlphaMask&) rAlpha ).ReleaseAccess( pA );
2372
2373 delete[] pMapX;
2374 delete[] pMapY;
2375 mbMap = bOldMap;
2376 mpMetaFile = pOldMetaFile;
2377 }
2378 }
2379 }
2380
2381 // ------------------------------------------------------------------------
2382
ImplPrintTransparent(const Bitmap & rBmp,const Bitmap & rMask,const Point & rDestPt,const Size & rDestSize,const Point & rSrcPtPixel,const Size & rSrcSizePixel)2383 void OutputDevice::ImplPrintTransparent( const Bitmap& rBmp, const Bitmap& rMask,
2384 const Point& rDestPt, const Size& rDestSize,
2385 const Point& rSrcPtPixel, const Size& rSrcSizePixel )
2386 {
2387 Point aPt;
2388 Point aDestPt( LogicToPixel( rDestPt ) );
2389 Size aDestSz( LogicToPixel( rDestSize ) );
2390 Rectangle aSrcRect( rSrcPtPixel, rSrcSizePixel );
2391
2392 aSrcRect.Justify();
2393
2394 if( !rBmp.IsEmpty() && aSrcRect.GetWidth() && aSrcRect.GetHeight() && aDestSz.Width() && aDestSz.Height() )
2395 {
2396 Bitmap aPaint( rBmp ), aMask( rMask );
2397 sal_uLong nMirrFlags = 0UL;
2398
2399 if( aMask.GetBitCount() > 1 )
2400 aMask.Convert( BMP_CONVERSION_1BIT_THRESHOLD );
2401
2402 // mirrored horizontically
2403 if( aDestSz.Width() < 0L )
2404 {
2405 aDestSz.Width() = -aDestSz.Width();
2406 aDestPt.X() -= ( aDestSz.Width() - 1L );
2407 nMirrFlags |= BMP_MIRROR_HORZ;
2408 }
2409
2410 // mirrored vertically
2411 if( aDestSz.Height() < 0L )
2412 {
2413 aDestSz.Height() = -aDestSz.Height();
2414 aDestPt.Y() -= ( aDestSz.Height() - 1L );
2415 nMirrFlags |= BMP_MIRROR_VERT;
2416 }
2417
2418 // source cropped?
2419 if( aSrcRect != Rectangle( aPt, aPaint.GetSizePixel() ) )
2420 {
2421 aPaint.Crop( aSrcRect );
2422 aMask.Crop( aSrcRect );
2423 }
2424
2425 // destination mirrored
2426 if( nMirrFlags )
2427 {
2428 aPaint.Mirror( nMirrFlags );
2429 aMask.Mirror( nMirrFlags );
2430 }
2431
2432 // we always want to have a mask
2433 if( aMask.IsEmpty() )
2434 {
2435 aMask = Bitmap( aSrcRect.GetSize(), 1 );
2436 aMask.Erase( Color( COL_BLACK ) );
2437 }
2438
2439 // do painting
2440 const long nSrcWidth = aSrcRect.GetWidth(), nSrcHeight = aSrcRect.GetHeight();
2441 long nX, nY; // , nWorkX, nWorkY, nWorkWidth, nWorkHeight;
2442 long* pMapX = new long[ nSrcWidth + 1 ];
2443 long* pMapY = new long[ nSrcHeight + 1 ];
2444 const sal_Bool bOldMap = mbMap;
2445
2446 mbMap = sal_False;
2447
2448 // create forward mapping tables
2449 for( nX = 0L; nX <= nSrcWidth; nX++ )
2450 pMapX[ nX ] = aDestPt.X() + FRound( (double) aDestSz.Width() * nX / nSrcWidth );
2451
2452 for( nY = 0L; nY <= nSrcHeight; nY++ )
2453 pMapY[ nY ] = aDestPt.Y() + FRound( (double) aDestSz.Height() * nY / nSrcHeight );
2454
2455 // walk through all rectangles of mask
2456 const Region aWorkRgn(aMask.CreateRegion(COL_BLACK, Rectangle(Point(), aMask.GetSizePixel())));
2457 RectangleVector aRectangles;
2458 aWorkRgn.GetRegionRectangles(aRectangles);
2459
2460 for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); aRectIter++)
2461 {
2462 const Point aMapPt(pMapX[aRectIter->Left()], pMapY[aRectIter->Top()]);
2463 const Size aMapSz(
2464 pMapX[aRectIter->Right() + 1] - aMapPt.X(), // pMapX[L + W] -> L + ((R - L) + 1) -> R + 1
2465 pMapY[aRectIter->Bottom() + 1] - aMapPt.Y()); // same for Y
2466 Bitmap aBandBmp(aPaint);
2467
2468 aBandBmp.Crop(*aRectIter);
2469 ImplDrawBitmap(aMapPt, aMapSz, Point(), aBandBmp.GetSizePixel(), aBandBmp, META_BMPSCALEPART_ACTION);
2470 }
2471
2472 //Region aWorkRgn( aMask.CreateRegion( COL_BLACK, Rectangle( Point(), aMask.GetSizePixel() ) ) );
2473 //ImplRegionInfo aInfo;
2474 //sal_Bool bRgnRect = aWorkRgn.ImplGetFirstRect( aInfo, nWorkX, nWorkY, nWorkWidth, nWorkHeight );
2475 //
2476 //while( bRgnRect )
2477 //{
2478 // Bitmap aBandBmp( aPaint );
2479 // const Rectangle aBandRect( Point( nWorkX, nWorkY ), Size( nWorkWidth, nWorkHeight ) );
2480 // const Point aMapPt( pMapX[ nWorkX ], pMapY[ nWorkY ] );
2481 // const Size aMapSz( pMapX[ nWorkX + nWorkWidth ] - aMapPt.X(), pMapY[ nWorkY + nWorkHeight ] - aMapPt.Y() );
2482 //
2483 // aBandBmp.Crop( aBandRect );
2484 // ImplDrawBitmap( aMapPt, aMapSz, Point(), aBandBmp.GetSizePixel(), aBandBmp, META_BMPSCALEPART_ACTION );
2485 // bRgnRect = aWorkRgn.ImplGetNextRect( aInfo, nWorkX, nWorkY, nWorkWidth, nWorkHeight );
2486 //}
2487
2488 mbMap = bOldMap;
2489
2490 delete[] pMapX;
2491 delete[] pMapY;
2492 }
2493 }
2494
2495 // ------------------------------------------------------------------------
2496
ImplPrintMask(const Bitmap & rMask,const Color & rMaskColor,const Point & rDestPt,const Size & rDestSize,const Point & rSrcPtPixel,const Size & rSrcSizePixel)2497 void OutputDevice::ImplPrintMask( const Bitmap& rMask, const Color& rMaskColor,
2498 const Point& rDestPt, const Size& rDestSize,
2499 const Point& rSrcPtPixel, const Size& rSrcSizePixel )
2500 {
2501 Point aPt;
2502 Point aDestPt( LogicToPixel( rDestPt ) );
2503 Size aDestSz( LogicToPixel( rDestSize ) );
2504 Rectangle aSrcRect( rSrcPtPixel, rSrcSizePixel );
2505
2506 aSrcRect.Justify();
2507
2508 if( !rMask.IsEmpty() && aSrcRect.GetWidth() && aSrcRect.GetHeight() && aDestSz.Width() && aDestSz.Height() )
2509 {
2510 Bitmap aMask( rMask );
2511 sal_uLong nMirrFlags = 0UL;
2512
2513 if( aMask.GetBitCount() > 1 )
2514 aMask.Convert( BMP_CONVERSION_1BIT_THRESHOLD );
2515
2516 // mirrored horizontically
2517 if( aDestSz.Width() < 0L )
2518 {
2519 aDestSz.Width() = -aDestSz.Width();
2520 aDestPt.X() -= ( aDestSz.Width() - 1L );
2521 nMirrFlags |= BMP_MIRROR_HORZ;
2522 }
2523
2524 // mirrored vertically
2525 if( aDestSz.Height() < 0L )
2526 {
2527 aDestSz.Height() = -aDestSz.Height();
2528 aDestPt.Y() -= ( aDestSz.Height() - 1L );
2529 nMirrFlags |= BMP_MIRROR_VERT;
2530 }
2531
2532 // source cropped?
2533 if( aSrcRect != Rectangle( aPt, aMask.GetSizePixel() ) )
2534 aMask.Crop( aSrcRect );
2535
2536 // destination mirrored
2537 if( nMirrFlags )
2538 aMask.Mirror( nMirrFlags );
2539
2540 // do painting
2541 const long nSrcWidth = aSrcRect.GetWidth(), nSrcHeight = aSrcRect.GetHeight();
2542 long nX, nY; //, nWorkX, nWorkY, nWorkWidth, nWorkHeight;
2543 long* pMapX = new long[ nSrcWidth + 1 ];
2544 long* pMapY = new long[ nSrcHeight + 1 ];
2545 GDIMetaFile* pOldMetaFile = mpMetaFile;
2546 const sal_Bool bOldMap = mbMap;
2547
2548 mpMetaFile = NULL;
2549 mbMap = sal_False;
2550 Push( PUSH_FILLCOLOR | PUSH_LINECOLOR );
2551 SetLineColor( rMaskColor );
2552 SetFillColor( rMaskColor );
2553 ImplInitLineColor();
2554 ImplInitFillColor();
2555
2556 // create forward mapping tables
2557 for( nX = 0L; nX <= nSrcWidth; nX++ )
2558 pMapX[ nX ] = aDestPt.X() + FRound( (double) aDestSz.Width() * nX / nSrcWidth );
2559
2560 for( nY = 0L; nY <= nSrcHeight; nY++ )
2561 pMapY[ nY ] = aDestPt.Y() + FRound( (double) aDestSz.Height() * nY / nSrcHeight );
2562
2563 // walk through all rectangles of mask
2564 const Region aWorkRgn(aMask.CreateRegion(COL_BLACK, Rectangle(Point(), aMask.GetSizePixel())));
2565 RectangleVector aRectangles;
2566 aWorkRgn.GetRegionRectangles(aRectangles);
2567
2568 for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); aRectIter++)
2569 {
2570 const Point aMapPt(pMapX[aRectIter->Left()], pMapY[aRectIter->Top()]);
2571 const Size aMapSz(
2572 pMapX[aRectIter->Right() + 1] - aMapPt.X(), // pMapX[L + W] -> L + ((R - L) + 1) -> R + 1
2573 pMapY[aRectIter->Bottom() + 1] - aMapPt.Y()); // same for Y
2574
2575 DrawRect(Rectangle(aMapPt, aMapSz));
2576 }
2577
2578 //Region aWorkRgn( aMask.CreateRegion( COL_BLACK, Rectangle( Point(), aMask.GetSizePixel() ) ) );
2579 //ImplRegionInfo aInfo;
2580 //sal_Bool bRgnRect = aWorkRgn.ImplGetFirstRect( aInfo, nWorkX, nWorkY, nWorkWidth, nWorkHeight );
2581 //
2582 //while( bRgnRect )
2583 //{
2584 // const Point aMapPt( pMapX[ nWorkX ], pMapY[ nWorkY ] );
2585 // const Size aMapSz( pMapX[ nWorkX + nWorkWidth ] - aMapPt.X(), pMapY[ nWorkY + nWorkHeight ] - aMapPt.Y() );
2586 //
2587 // DrawRect( Rectangle( aMapPt, aMapSz ) );
2588 // bRgnRect = aWorkRgn.ImplGetNextRect( aInfo, nWorkX, nWorkY, nWorkWidth, nWorkHeight );
2589 //}
2590
2591 Pop();
2592 delete[] pMapX;
2593 delete[] pMapY;
2594 mbMap = bOldMap;
2595 mpMetaFile = pOldMetaFile;
2596 }
2597 }
2598