Version 5.4.3.2, tag libreoffice-5.4.3.2
[LibreOffice.git] / vcl / source / gdi / salmisc.cxx
blob4f239efb95c6e97698ca8ea79ccd79d996b70e3c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <vcl/bitmapaccess.hxx>
21 #include <vcl/salbtype.hxx>
22 #include <bmpfast.hxx>
23 #include <o3tl/safeint.hxx>
24 #include <osl/diagnose.h>
25 #include <memory>
27 #define IMPL_CASE_GET_FORMAT( Format ) \
28 case( ScanlineFormat::Format ): \
29 pFncGetPixel = BitmapReadAccess::GetPixelFor##Format; \
30 break
32 #define IMPL_CASE_SET_FORMAT( Format, BitCount ) \
33 case( ScanlineFormat::Format ): \
34 { \
35 pFncSetPixel = BitmapReadAccess::SetPixelFor##Format; \
36 pDstBuffer->mnBitCount = BitCount; \
37 } \
38 break
40 #define DOUBLE_SCANLINES() \
41 while( ( nActY < nHeight1 ) && ( pMapY[ nActY + 1 ] == nMapY ) ) \
42 { \
43 memcpy( pDstScanMap[ nActY + 1 ], pDstScan, rDstBuffer.mnScanlineSize ); \
44 nActY++; \
47 #define TC_TO_PAL_COLORS 4096
49 static long ImplIndexFromColor( const BitmapColor& rCol )
51 #if TC_TO_PAL_COLORS == 4096
53 return( ( ( (long) rCol.GetBlue() >> 4) << 8 ) |
54 ( ( (long) rCol.GetGreen() >> 4 ) << 4 ) |
55 ( (long) rCol.GetRed() >> 4 ) );
57 #elif TC_TO_PAL_COLORS == 32768
59 return( ( ( (long) rCol.GetBlue() >> 3) << 10 ) |
60 ( ( (long) rCol.GetGreen() >> 3 ) << 5 ) |
61 ( (long) rCol.GetRed() >> 3 ) );
63 #endif
66 static void ImplPALToPAL( const BitmapBuffer& rSrcBuffer, BitmapBuffer& rDstBuffer,
67 FncGetPixel pFncGetPixel, FncSetPixel pFncSetPixel,
68 Scanline* pSrcScanMap, Scanline* pDstScanMap, long* pMapX, long* pMapY )
70 const long nHeight1 = rDstBuffer.mnHeight - 1;
71 const ColorMask& rSrcMask = rSrcBuffer.maColorMask;
72 const ColorMask& rDstMask = rDstBuffer.maColorMask;
73 BitmapPalette aColMap( rSrcBuffer.maPalette.GetEntryCount() );
74 BitmapColor* pColMapBuf = aColMap.ImplGetColorBuffer();
75 BitmapColor aIndex( 0 );
77 for( sal_uInt16 i = 0, nSrcCount = aColMap.GetEntryCount(), nDstCount = rDstBuffer.maPalette.GetEntryCount(); i < nSrcCount; i++ )
79 if( ( i < nDstCount ) && ( rSrcBuffer.maPalette[ i ] == rDstBuffer.maPalette[ i ] ) )
80 aIndex.SetIndex( sal::static_int_cast<sal_uInt8>(i) );
81 else
82 aIndex.SetIndex( sal::static_int_cast<sal_uInt8>(rDstBuffer.maPalette.GetBestIndex( rSrcBuffer.maPalette[ i ] )) );
84 pColMapBuf[ i ] = aIndex;
87 for (long nActY = 0; nActY < rDstBuffer.mnHeight; ++nActY)
89 long nMapY = pMapY[nActY];
90 Scanline pSrcScan(pSrcScanMap[nMapY]), pDstScan(pDstScanMap[nActY]);
92 for (long nX = 0; nX < rDstBuffer.mnWidth; ++nX)
93 pFncSetPixel( pDstScan, nX, pColMapBuf[ pFncGetPixel( pSrcScan, pMapX[ nX ], rSrcMask ).GetIndex() ], rDstMask );
95 DOUBLE_SCANLINES();
99 static void ImplPALToTC( const BitmapBuffer& rSrcBuffer, BitmapBuffer& rDstBuffer,
100 FncGetPixel pFncGetPixel, FncSetPixel pFncSetPixel,
101 Scanline* pSrcScanMap, Scanline* pDstScanMap, long* pMapX, long* pMapY )
103 const long nHeight1 = rDstBuffer.mnHeight - 1;
104 const ColorMask& rSrcMask = rSrcBuffer.maColorMask;
105 const ColorMask& rDstMask = rDstBuffer.maColorMask;
106 const BitmapColor* pColBuf = rSrcBuffer.maPalette.ImplGetColorBuffer();
108 if( RemoveScanline( rSrcBuffer.mnFormat ) == ScanlineFormat::N1BitMsbPal )
110 const BitmapColor aCol0( pColBuf[ 0 ] );
111 const BitmapColor aCol1( pColBuf[ 1 ] );
112 long nMapX;
114 for (long nActY = 0; nActY < rDstBuffer.mnHeight; ++nActY)
116 long nMapY = pMapY[nActY];
117 Scanline pSrcScan(pSrcScanMap[nMapY]), pDstScan(pDstScanMap[nActY]);
119 for (long nX = 0; nX < rDstBuffer.mnWidth;)
121 nMapX = pMapX[ nX ];
122 pFncSetPixel( pDstScan, nX++,
123 pSrcScan[ nMapX >> 3 ] & ( 1 << ( 7 - ( nMapX & 7 ) ) ) ? aCol1 : aCol0,
124 rDstMask );
127 DOUBLE_SCANLINES();
130 else if( RemoveScanline( rSrcBuffer.mnFormat ) == ScanlineFormat::N4BitMsnPal )
132 long nMapX;
134 for (long nActY = 0; nActY < rDstBuffer.mnHeight; ++nActY)
136 long nMapY = pMapY[nActY];
137 Scanline pSrcScan(pSrcScanMap[nMapY]), pDstScan(pDstScanMap[nActY]);
139 for (long nX = 0; nX < rDstBuffer.mnWidth;)
141 nMapX = pMapX[ nX ];
142 pFncSetPixel( pDstScan, nX++,
143 pColBuf[ ( pSrcScan[ nMapX >> 1 ] >> ( nMapX & 1 ? 0 : 4 ) ) & 0x0f ],
144 rDstMask );
147 DOUBLE_SCANLINES();
150 else if( RemoveScanline( rSrcBuffer.mnFormat ) == ScanlineFormat::N8BitPal )
152 for (long nActY = 0; nActY < rDstBuffer.mnHeight; ++nActY)
154 long nMapY = pMapY[nActY];
155 Scanline pSrcScan(pSrcScanMap[nMapY]), pDstScan(pDstScanMap[nActY]);
157 for (long nX = 0; nX < rDstBuffer.mnWidth; ++nX)
158 pFncSetPixel( pDstScan, nX, pColBuf[ pSrcScan[ pMapX[ nX ] ] ], rDstMask );
160 DOUBLE_SCANLINES();
163 else
165 for (long nActY = 0; nActY < rDstBuffer.mnHeight; ++nActY)
167 long nMapY = pMapY[nActY];
168 Scanline pSrcScan(pSrcScanMap[nMapY]), pDstScan(pDstScanMap[nActY]);
170 for (long nX = 0; nX < rDstBuffer.mnWidth; ++nX)
171 pFncSetPixel( pDstScan, nX, pColBuf[ pFncGetPixel( pSrcScan, pMapX[ nX ], rSrcMask ).GetIndex() ], rDstMask );
173 DOUBLE_SCANLINES();
178 static void ImplTCToTC( const BitmapBuffer& rSrcBuffer, BitmapBuffer& rDstBuffer,
179 FncGetPixel pFncGetPixel, FncSetPixel pFncSetPixel,
180 Scanline* pSrcScanMap, Scanline* pDstScanMap, long* pMapX, long* pMapY )
182 const long nHeight1 = rDstBuffer.mnHeight - 1;
183 const ColorMask& rSrcMask = rSrcBuffer.maColorMask;
184 const ColorMask& rDstMask = rDstBuffer.maColorMask;
186 if( RemoveScanline( rSrcBuffer.mnFormat ) == ScanlineFormat::N24BitTcBgr )
188 BitmapColor aCol;
189 sal_uInt8* pPixel = nullptr;
191 for (long nActY = 0; nActY < rDstBuffer.mnHeight; ++nActY)
193 long nMapY = pMapY[nActY];
194 Scanline pSrcScan(pSrcScanMap[nMapY]), pDstScan(pDstScanMap[nActY]);
196 for (long nX = 0; nX < rDstBuffer.mnWidth; ++nX)
198 aCol.SetBlue( *( pPixel = ( pSrcScan + pMapX[ nX ] * 3 ) )++ );
199 aCol.SetGreen( *pPixel++ );
200 aCol.SetRed( *pPixel );
201 pFncSetPixel( pDstScan, nX, aCol, rDstMask );
204 DOUBLE_SCANLINES()
207 else
209 for (long nActY = 0; nActY < rDstBuffer.mnHeight; ++nActY)
211 long nMapY = pMapY[nActY];
212 Scanline pSrcScan(pSrcScanMap[nMapY]), pDstScan(pDstScanMap[nActY]);
214 for (long nX = 0; nX < rDstBuffer.mnWidth; ++nX)
215 pFncSetPixel( pDstScan, nX, pFncGetPixel( pSrcScan, pMapX[ nX ], rSrcMask ), rDstMask );
217 DOUBLE_SCANLINES();
222 static void ImplTCToPAL( const BitmapBuffer& rSrcBuffer, BitmapBuffer& rDstBuffer,
223 FncGetPixel pFncGetPixel, FncSetPixel pFncSetPixel,
224 Scanline* pSrcScanMap, Scanline* pDstScanMap, long* pMapX, long* pMapY )
226 const long nHeight1 = rDstBuffer.mnHeight- 1;
227 const ColorMask& rSrcMask = rSrcBuffer.maColorMask;
228 const ColorMask& rDstMask = rDstBuffer.maColorMask;
229 BitmapPalette aColMap( rSrcBuffer.maPalette.GetEntryCount() );
230 std::unique_ptr<sal_uInt8[]> pColToPalMap(new sal_uInt8[ TC_TO_PAL_COLORS ]);
231 BitmapColor aIndex( 0 );
233 for( long nR = 0; nR < 16; nR++ )
235 for( long nG = 0; nG < 16; nG++ )
237 for( long nB = 0; nB < 16; nB++ )
239 BitmapColor aCol( sal::static_int_cast<sal_uInt8>(nR << 4),
240 sal::static_int_cast<sal_uInt8>(nG << 4),
241 sal::static_int_cast<sal_uInt8>(nB << 4) );
242 pColToPalMap[ ImplIndexFromColor( aCol ) ] = (sal_uInt8) rDstBuffer.maPalette.GetBestIndex( aCol );
247 for (long nActY = 0; nActY < rDstBuffer.mnHeight; ++nActY)
249 long nMapY = pMapY[nActY];
250 Scanline pSrcScan(pSrcScanMap[nMapY]), pDstScan(pDstScanMap[nActY]);
252 for (long nX = 0; nX < rDstBuffer.mnWidth; ++nX)
254 aIndex.SetIndex( pColToPalMap[ ImplIndexFromColor( pFncGetPixel( pSrcScan, pMapX[ nX ], rSrcMask ) ) ] );
255 pFncSetPixel( pDstScan, nX, aIndex, rDstMask );
258 DOUBLE_SCANLINES();
262 BitmapBuffer* StretchAndConvert(
263 const BitmapBuffer& rSrcBuffer, const SalTwoRect& rTwoRect,
264 ScanlineFormat nDstBitmapFormat, const BitmapPalette* pDstPal, const ColorMask* pDstMask )
266 FncGetPixel pFncGetPixel;
267 FncSetPixel pFncSetPixel;
268 BitmapBuffer* pDstBuffer = new BitmapBuffer;
270 // set function for getting pixels
271 switch( RemoveScanline( rSrcBuffer.mnFormat ) )
273 IMPL_CASE_GET_FORMAT( N1BitMsbPal );
274 IMPL_CASE_GET_FORMAT( N1BitLsbPal );
275 IMPL_CASE_GET_FORMAT( N4BitMsnPal );
276 IMPL_CASE_GET_FORMAT( N4BitLsnPal );
277 IMPL_CASE_GET_FORMAT( N8BitPal );
278 IMPL_CASE_GET_FORMAT( N8BitTcMask );
279 IMPL_CASE_GET_FORMAT( N16BitTcMsbMask );
280 IMPL_CASE_GET_FORMAT( N16BitTcLsbMask );
281 IMPL_CASE_GET_FORMAT( N24BitTcBgr );
282 IMPL_CASE_GET_FORMAT( N24BitTcRgb );
283 IMPL_CASE_GET_FORMAT( N32BitTcAbgr );
284 IMPL_CASE_GET_FORMAT( N32BitTcArgb );
285 IMPL_CASE_GET_FORMAT( N32BitTcBgra );
286 IMPL_CASE_GET_FORMAT( N32BitTcRgba );
287 IMPL_CASE_GET_FORMAT( N32BitTcMask );
289 default:
290 // should never come here
291 // initialize pFncGetPixel to something valid that is
292 // least likely to crash
293 pFncGetPixel = BitmapReadAccess::GetPixelForN1BitMsbPal;
294 OSL_FAIL( "unknown read format" );
295 break;
298 // set function for setting pixels
299 const ScanlineFormat nDstScanlineFormat = RemoveScanline( nDstBitmapFormat );
300 switch( nDstScanlineFormat )
302 IMPL_CASE_SET_FORMAT( N1BitMsbPal, 1 );
303 IMPL_CASE_SET_FORMAT( N1BitLsbPal, 1 );
304 IMPL_CASE_SET_FORMAT( N4BitMsnPal, 1 );
305 IMPL_CASE_SET_FORMAT( N4BitLsnPal, 4 );
306 IMPL_CASE_SET_FORMAT( N8BitPal, 8 );
307 IMPL_CASE_SET_FORMAT( N8BitTcMask, 8 );
308 IMPL_CASE_SET_FORMAT( N16BitTcMsbMask, 16 );
309 IMPL_CASE_SET_FORMAT( N16BitTcLsbMask, 16 );
310 IMPL_CASE_SET_FORMAT( N24BitTcBgr, 24 );
311 IMPL_CASE_SET_FORMAT( N24BitTcRgb, 24 );
312 IMPL_CASE_SET_FORMAT( N32BitTcAbgr, 32 );
313 IMPL_CASE_SET_FORMAT( N32BitTcArgb, 32 );
314 IMPL_CASE_SET_FORMAT( N32BitTcBgra, 32 );
315 IMPL_CASE_SET_FORMAT( N32BitTcRgba, 32 );
316 IMPL_CASE_SET_FORMAT( N32BitTcMask, 32 );
318 default:
319 // should never come here
320 // initialize pFncSetPixel to something valid that is
321 // least likely to crash
322 pFncSetPixel = BitmapReadAccess::SetPixelForN1BitMsbPal;
323 pDstBuffer->mnBitCount = 1;
324 OSL_FAIL( "unknown write format" );
325 break;
328 // fill destination buffer
329 pDstBuffer->mnFormat = nDstBitmapFormat;
330 pDstBuffer->mnWidth = rTwoRect.mnDestWidth;
331 pDstBuffer->mnHeight = rTwoRect.mnDestHeight;
332 long nScanlineBase;
333 bool bFail = o3tl::checked_multiply<long>(pDstBuffer->mnBitCount, pDstBuffer->mnWidth, nScanlineBase);
334 if (bFail)
336 SAL_WARN("vcl.gdi", "checked multiply failed");
337 pDstBuffer->mpBits = nullptr;
338 delete pDstBuffer;
339 return nullptr;
341 pDstBuffer->mnScanlineSize = AlignedWidth4Bytes(nScanlineBase);
342 if (pDstBuffer->mnScanlineSize < nScanlineBase/8)
344 SAL_WARN("vcl.gdi", "scanline calculation wraparound");
345 pDstBuffer->mpBits = nullptr;
346 delete pDstBuffer;
347 return nullptr;
351 pDstBuffer->mpBits = new sal_uInt8[ pDstBuffer->mnScanlineSize * pDstBuffer->mnHeight ];
353 catch( const std::bad_alloc& )
355 // memory exception, clean up
356 pDstBuffer->mpBits = nullptr;
357 delete pDstBuffer;
358 return nullptr;
361 // do we need a destination palette or color mask?
362 if( ( nDstScanlineFormat == ScanlineFormat::N1BitMsbPal ) ||
363 ( nDstScanlineFormat == ScanlineFormat::N1BitLsbPal ) ||
364 ( nDstScanlineFormat == ScanlineFormat::N4BitMsnPal ) ||
365 ( nDstScanlineFormat == ScanlineFormat::N4BitLsnPal ) ||
366 ( nDstScanlineFormat == ScanlineFormat::N8BitPal ) )
368 assert(pDstPal && "destination buffer requires palette");
369 if (!pDstPal)
371 delete pDstBuffer;
372 return nullptr;
374 pDstBuffer->maPalette = *pDstPal;
376 else if( ( nDstScanlineFormat == ScanlineFormat::N8BitTcMask ) ||
377 ( nDstScanlineFormat == ScanlineFormat::N16BitTcMsbMask ) ||
378 ( nDstScanlineFormat == ScanlineFormat::N16BitTcLsbMask ) ||
379 ( nDstScanlineFormat == ScanlineFormat::N32BitTcMask ) )
381 assert(pDstMask && "destination buffer requires color mask");
382 if (!pDstMask)
384 delete pDstBuffer;
385 return nullptr;
387 pDstBuffer->maColorMask = *pDstMask;
390 // short circuit the most important conversions
391 bool bFastConvert = ImplFastBitmapConversion( *pDstBuffer, rSrcBuffer, rTwoRect );
392 if( bFastConvert )
393 return pDstBuffer;
395 std::unique_ptr<Scanline[]> pSrcScan;
396 std::unique_ptr<Scanline[]> pDstScan;
397 std::unique_ptr<long[]> pMapX;
398 std::unique_ptr<long[]> pMapY;
402 pSrcScan.reset(new Scanline[rSrcBuffer.mnHeight]);
403 pDstScan.reset(new Scanline[pDstBuffer->mnHeight]);
404 pMapX.reset(new long[pDstBuffer->mnWidth]);
405 pMapY.reset(new long[pDstBuffer->mnHeight]);
407 catch( const std::bad_alloc& )
409 // memory exception, clean up
410 // remark: the buffer ptr causing the exception
411 // is still NULL here
412 delete pDstBuffer;
413 return nullptr;
416 // horizontal mapping table
417 if( (pDstBuffer->mnWidth != rTwoRect.mnSrcWidth) && (pDstBuffer->mnWidth != 0) )
419 const double fFactorX = (double)rTwoRect.mnSrcWidth / pDstBuffer->mnWidth;
421 for (long i = 0; i < pDstBuffer->mnWidth; ++i)
422 pMapX[ i ] = rTwoRect.mnSrcX + static_cast<int>( i * fFactorX );
424 else
426 for (long i = 0, nTmp = rTwoRect.mnSrcX ; i < pDstBuffer->mnWidth; ++i)
427 pMapX[ i ] = nTmp++;
430 // vertical mapping table
431 if( (pDstBuffer->mnHeight != rTwoRect.mnSrcHeight) && (pDstBuffer->mnHeight != 0) )
433 const double fFactorY = (double)rTwoRect.mnSrcHeight / pDstBuffer->mnHeight;
435 for (long i = 0; i < pDstBuffer->mnHeight; ++i)
436 pMapY[ i ] = rTwoRect.mnSrcY + static_cast<int>( i * fFactorY );
438 else
440 for (long i = 0, nTmp = rTwoRect.mnSrcY; i < pDstBuffer->mnHeight; ++i)
441 pMapY[ i ] = nTmp++;
444 // source scanline buffer
445 Scanline pTmpScan;
446 long nOffset;
447 if( rSrcBuffer.mnFormat & ScanlineFormat::TopDown )
449 pTmpScan = rSrcBuffer.mpBits;
450 nOffset = rSrcBuffer.mnScanlineSize;
452 else
454 pTmpScan = rSrcBuffer.mpBits + ( rSrcBuffer.mnHeight - 1 ) * rSrcBuffer.mnScanlineSize;
455 nOffset = -rSrcBuffer.mnScanlineSize;
458 for (long i = 0; i < rSrcBuffer.mnHeight; i++, pTmpScan += nOffset)
459 pSrcScan[ i ] = pTmpScan;
461 // destination scanline buffer
462 if( pDstBuffer->mnFormat & ScanlineFormat::TopDown )
464 pTmpScan = pDstBuffer->mpBits;
465 nOffset = pDstBuffer->mnScanlineSize;
467 else
469 pTmpScan = pDstBuffer->mpBits + ( pDstBuffer->mnHeight - 1 ) * pDstBuffer->mnScanlineSize;
470 nOffset = -pDstBuffer->mnScanlineSize;
473 for (long i = 0; i < pDstBuffer->mnHeight; i++, pTmpScan += nOffset)
474 pDstScan[ i ] = pTmpScan;
476 // do buffer scaling and conversion
477 if( rSrcBuffer.mnBitCount <= 8 && pDstBuffer->mnBitCount <= 8 )
479 ImplPALToPAL( rSrcBuffer, *pDstBuffer, pFncGetPixel, pFncSetPixel,
480 pSrcScan.get(), pDstScan.get(), pMapX.get(), pMapY.get() );
482 else if( rSrcBuffer.mnBitCount <= 8 && pDstBuffer->mnBitCount > 8 )
484 ImplPALToTC( rSrcBuffer, *pDstBuffer, pFncGetPixel, pFncSetPixel,
485 pSrcScan.get(), pDstScan.get(), pMapX.get(), pMapY.get() );
487 else if( rSrcBuffer.mnBitCount > 8 && pDstBuffer->mnBitCount > 8 )
489 ImplTCToTC( rSrcBuffer, *pDstBuffer, pFncGetPixel, pFncSetPixel,
490 pSrcScan.get(), pDstScan.get(), pMapX.get(), pMapY.get() );
492 else
494 ImplTCToPAL( rSrcBuffer, *pDstBuffer, pFncGetPixel, pFncSetPixel,
495 pSrcScan.get(), pDstScan.get(), pMapX.get(), pMapY.get() );
498 return pDstBuffer;
501 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */