bump product version to 7.2.5.1
[LibreOffice.git] / vcl / source / gdi / salmisc.cxx
blob037ea8073bae2857c675f0f2acc8724b5a2d322f
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/BitmapReadAccess.hxx>
21 #include <vcl/salgtype.hxx>
22 #include <bitmap/bmpfast.hxx>
23 #include <o3tl/safeint.hxx>
24 #include <osl/diagnose.h>
25 #include <sal/log.hxx>
26 #include <tools/helpers.hxx>
27 #include <memory>
29 #define IMPL_CASE_SET_FORMAT( Format, BitCount ) \
30 case( ScanlineFormat::Format ): \
31 { \
32 pFncSetPixel = BitmapReadAccess::SetPixelFor##Format; \
33 pDstBuffer->mnBitCount = BitCount; \
34 } \
35 break
37 #define DOUBLE_SCANLINES() \
38 while( ( nActY < nHeight1 ) && ( pMapY[ nActY + 1 ] == nMapY ) ) \
39 { \
40 memcpy( pDstScanMap[ nActY + 1 ], pDstScan, rDstBuffer.mnScanlineSize ); \
41 nActY++; \
44 constexpr int TC_TO_PAL_COLORS = 4096;
46 static tools::Long ImplIndexFromColor( const BitmapColor& rCol )
48 return ( ( static_cast<tools::Long>(rCol.GetBlue()) >> 4) << 8 ) |
49 ( ( static_cast<tools::Long>(rCol.GetGreen()) >> 4 ) << 4 ) |
50 ( static_cast<tools::Long>(rCol.GetRed()) >> 4 );
53 static void ImplPALToPAL( const BitmapBuffer& rSrcBuffer, BitmapBuffer& rDstBuffer,
54 FncGetPixel pFncGetPixel, FncSetPixel pFncSetPixel,
55 Scanline* pSrcScanMap, Scanline* pDstScanMap, tools::Long const * pMapX, const tools::Long* pMapY )
57 const tools::Long nHeight1 = rDstBuffer.mnHeight - 1;
58 const ColorMask& rSrcMask = rSrcBuffer.maColorMask;
59 const ColorMask& rDstMask = rDstBuffer.maColorMask;
60 BitmapPalette aColMap( rSrcBuffer.maPalette.GetEntryCount() );
61 BitmapColor* pColMapBuf = aColMap.ImplGetColorBuffer();
62 BitmapColor aIndex( 0 );
64 for( sal_uInt16 i = 0, nSrcCount = aColMap.GetEntryCount(), nDstCount = rDstBuffer.maPalette.GetEntryCount(); i < nSrcCount; i++ )
66 if( ( i < nDstCount ) && ( rSrcBuffer.maPalette[ i ] == rDstBuffer.maPalette[ i ] ) )
67 aIndex.SetIndex( sal::static_int_cast<sal_uInt8>(i) );
68 else
69 aIndex.SetIndex( sal::static_int_cast<sal_uInt8>(rDstBuffer.maPalette.GetBestIndex( rSrcBuffer.maPalette[ i ] )) );
71 pColMapBuf[ i ] = aIndex;
74 for (tools::Long nActY = 0; nActY < rDstBuffer.mnHeight; ++nActY)
76 tools::Long nMapY = pMapY[nActY];
77 Scanline pSrcScan(pSrcScanMap[nMapY]), pDstScan(pDstScanMap[nActY]);
79 for (tools::Long nX = 0; nX < rDstBuffer.mnWidth; ++nX)
80 pFncSetPixel( pDstScan, nX, pColMapBuf[ pFncGetPixel( pSrcScan, pMapX[ nX ], rSrcMask ).GetIndex() ], rDstMask );
82 DOUBLE_SCANLINES();
86 static void ImplPALToTC( const BitmapBuffer& rSrcBuffer, BitmapBuffer const & rDstBuffer,
87 FncGetPixel pFncGetPixel, FncSetPixel pFncSetPixel,
88 Scanline* pSrcScanMap, Scanline* pDstScanMap, tools::Long const * pMapX, const tools::Long* pMapY )
90 const tools::Long nHeight1 = rDstBuffer.mnHeight - 1;
91 const ColorMask& rSrcMask = rSrcBuffer.maColorMask;
92 const ColorMask& rDstMask = rDstBuffer.maColorMask;
93 const BitmapColor* pColBuf = rSrcBuffer.maPalette.ImplGetColorBuffer();
95 if( RemoveScanline( rSrcBuffer.mnFormat ) == ScanlineFormat::N1BitMsbPal )
97 const BitmapColor aCol0( pColBuf[ 0 ] );
98 const BitmapColor aCol1( pColBuf[ 1 ] );
99 tools::Long nMapX;
101 for (tools::Long nActY = 0; nActY < rDstBuffer.mnHeight; ++nActY)
103 tools::Long nMapY = pMapY[nActY];
104 Scanline pSrcScan(pSrcScanMap[nMapY]), pDstScan(pDstScanMap[nActY]);
106 for (tools::Long nX = 0; nX < rDstBuffer.mnWidth;)
108 nMapX = pMapX[ nX ];
109 pFncSetPixel( pDstScan, nX++,
110 pSrcScan[ nMapX >> 3 ] & ( 1 << ( 7 - ( nMapX & 7 ) ) ) ? aCol1 : aCol0,
111 rDstMask );
114 DOUBLE_SCANLINES();
117 else if( RemoveScanline( rSrcBuffer.mnFormat ) == ScanlineFormat::N8BitPal )
119 for (tools::Long nActY = 0; nActY < rDstBuffer.mnHeight; ++nActY)
121 tools::Long nMapY = pMapY[nActY];
122 Scanline pSrcScan(pSrcScanMap[nMapY]), pDstScan(pDstScanMap[nActY]);
124 for (tools::Long nX = 0; nX < rDstBuffer.mnWidth; ++nX)
125 pFncSetPixel( pDstScan, nX, pColBuf[ pSrcScan[ pMapX[ nX ] ] ], rDstMask );
127 DOUBLE_SCANLINES();
130 else
132 for (tools::Long nActY = 0; nActY < rDstBuffer.mnHeight; ++nActY)
134 tools::Long nMapY = pMapY[nActY];
135 Scanline pSrcScan(pSrcScanMap[nMapY]), pDstScan(pDstScanMap[nActY]);
137 for (tools::Long nX = 0; nX < rDstBuffer.mnWidth; ++nX)
138 pFncSetPixel( pDstScan, nX, pColBuf[ pFncGetPixel( pSrcScan, pMapX[ nX ], rSrcMask ).GetIndex() ], rDstMask );
140 DOUBLE_SCANLINES();
145 static void ImplTCToTC( const BitmapBuffer& rSrcBuffer, BitmapBuffer const & rDstBuffer,
146 FncGetPixel pFncGetPixel, FncSetPixel pFncSetPixel,
147 Scanline* pSrcScanMap, Scanline* pDstScanMap, tools::Long const * pMapX, const tools::Long* pMapY )
149 const tools::Long nHeight1 = rDstBuffer.mnHeight - 1;
150 const ColorMask& rSrcMask = rSrcBuffer.maColorMask;
151 const ColorMask& rDstMask = rDstBuffer.maColorMask;
153 if( RemoveScanline( rSrcBuffer.mnFormat ) == ScanlineFormat::N24BitTcBgr )
155 BitmapColor aCol;
156 sal_uInt8* pPixel = nullptr;
158 for (tools::Long nActY = 0; nActY < rDstBuffer.mnHeight; ++nActY)
160 tools::Long nMapY = pMapY[nActY];
161 Scanline pSrcScan(pSrcScanMap[nMapY]), pDstScan(pDstScanMap[nActY]);
163 for (tools::Long nX = 0; nX < rDstBuffer.mnWidth; ++nX)
165 pPixel = pSrcScan + pMapX[ nX ] * 3;
166 aCol.SetBlue( *pPixel++ );
167 aCol.SetGreen( *pPixel++ );
168 aCol.SetRed( *pPixel );
169 pFncSetPixel( pDstScan, nX, aCol, rDstMask );
172 DOUBLE_SCANLINES()
175 else
177 for (tools::Long nActY = 0; nActY < rDstBuffer.mnHeight; ++nActY)
179 tools::Long nMapY = pMapY[nActY];
180 Scanline pSrcScan(pSrcScanMap[nMapY]), pDstScan(pDstScanMap[nActY]);
182 for (tools::Long nX = 0; nX < rDstBuffer.mnWidth; ++nX)
183 pFncSetPixel( pDstScan, nX, pFncGetPixel( pSrcScan, pMapX[ nX ], rSrcMask ), rDstMask );
185 DOUBLE_SCANLINES();
190 static void ImplTCToPAL( const BitmapBuffer& rSrcBuffer, BitmapBuffer const & rDstBuffer,
191 FncGetPixel pFncGetPixel, FncSetPixel pFncSetPixel,
192 Scanline* pSrcScanMap, Scanline* pDstScanMap, tools::Long const * pMapX, const tools::Long* pMapY )
194 const tools::Long nHeight1 = rDstBuffer.mnHeight- 1;
195 const ColorMask& rSrcMask = rSrcBuffer.maColorMask;
196 const ColorMask& rDstMask = rDstBuffer.maColorMask;
197 std::unique_ptr<sal_uInt8[]> pColToPalMap(new sal_uInt8[ TC_TO_PAL_COLORS ]);
198 BitmapColor aIndex( 0 );
200 for( tools::Long nR = 0; nR < 16; nR++ )
202 for( tools::Long nG = 0; nG < 16; nG++ )
204 for( tools::Long nB = 0; nB < 16; nB++ )
206 BitmapColor aCol( sal::static_int_cast<sal_uInt8>(nR << 4),
207 sal::static_int_cast<sal_uInt8>(nG << 4),
208 sal::static_int_cast<sal_uInt8>(nB << 4) );
209 pColToPalMap[ ImplIndexFromColor( aCol ) ] = static_cast<sal_uInt8>(rDstBuffer.maPalette.GetBestIndex( aCol ));
214 for (tools::Long nActY = 0; nActY < rDstBuffer.mnHeight; ++nActY)
216 tools::Long nMapY = pMapY[nActY];
217 Scanline pSrcScan(pSrcScanMap[nMapY]), pDstScan(pDstScanMap[nActY]);
219 for (tools::Long nX = 0; nX < rDstBuffer.mnWidth; ++nX)
221 aIndex.SetIndex( pColToPalMap[ ImplIndexFromColor( pFncGetPixel( pSrcScan, pMapX[ nX ], rSrcMask ) ) ] );
222 pFncSetPixel( pDstScan, nX, aIndex, rDstMask );
225 DOUBLE_SCANLINES();
229 std::unique_ptr<BitmapBuffer> StretchAndConvert(
230 const BitmapBuffer& rSrcBuffer, const SalTwoRect& rTwoRect,
231 ScanlineFormat nDstBitmapFormat, const BitmapPalette* pDstPal, const ColorMask* pDstMask )
233 FncGetPixel pFncGetPixel;
234 FncSetPixel pFncSetPixel;
235 std::unique_ptr<BitmapBuffer> pDstBuffer(new BitmapBuffer);
237 // set function for getting pixels
238 pFncGetPixel = BitmapReadAccess::GetPixelFunction( rSrcBuffer.mnFormat );
239 if( !pFncGetPixel )
241 // should never come here
242 // initialize pFncGetPixel to something valid that is
243 // least likely to crash
244 pFncGetPixel = BitmapReadAccess::GetPixelForN1BitMsbPal;
245 OSL_FAIL( "unknown read format" );
248 // set function for setting pixels
249 const ScanlineFormat nDstScanlineFormat = RemoveScanline( nDstBitmapFormat );
250 switch( nDstScanlineFormat )
252 IMPL_CASE_SET_FORMAT( N1BitMsbPal, 1 );
253 IMPL_CASE_SET_FORMAT( N1BitLsbPal, 1 );
254 IMPL_CASE_SET_FORMAT( N8BitPal, 8 );
255 IMPL_CASE_SET_FORMAT( N24BitTcBgr, 24 );
256 IMPL_CASE_SET_FORMAT( N24BitTcRgb, 24 );
257 IMPL_CASE_SET_FORMAT( N32BitTcAbgr, 32 );
258 IMPL_CASE_SET_FORMAT( N32BitTcArgb, 32 );
259 IMPL_CASE_SET_FORMAT( N32BitTcBgra, 32 );
260 IMPL_CASE_SET_FORMAT( N32BitTcRgba, 32 );
261 IMPL_CASE_SET_FORMAT( N32BitTcMask, 32 );
263 default:
264 // should never come here
265 // initialize pFncSetPixel to something valid that is
266 // least likely to crash
267 pFncSetPixel = BitmapReadAccess::SetPixelForN1BitMsbPal;
268 pDstBuffer->mnBitCount = 1;
269 OSL_FAIL( "unknown write format" );
270 break;
273 // fill destination buffer
274 pDstBuffer->mnFormat = nDstBitmapFormat;
275 pDstBuffer->mnWidth = rTwoRect.mnDestWidth;
276 pDstBuffer->mnHeight = rTwoRect.mnDestHeight;
277 tools::Long nScanlineBase;
278 bool bFail = o3tl::checked_multiply<tools::Long>(pDstBuffer->mnBitCount, pDstBuffer->mnWidth, nScanlineBase);
279 if (bFail)
281 SAL_WARN("vcl.gdi", "checked multiply failed");
282 pDstBuffer->mpBits = nullptr;
283 return nullptr;
285 pDstBuffer->mnScanlineSize = AlignedWidth4Bytes(nScanlineBase);
286 if (pDstBuffer->mnScanlineSize < nScanlineBase/8)
288 SAL_WARN("vcl.gdi", "scanline calculation wraparound");
289 pDstBuffer->mpBits = nullptr;
290 return nullptr;
294 pDstBuffer->mpBits = new sal_uInt8[ pDstBuffer->mnScanlineSize * pDstBuffer->mnHeight ];
296 catch( const std::bad_alloc& )
298 // memory exception, clean up
299 pDstBuffer->mpBits = nullptr;
300 return nullptr;
303 // do we need a destination palette or color mask?
304 if( ( nDstScanlineFormat == ScanlineFormat::N1BitMsbPal ) ||
305 ( nDstScanlineFormat == ScanlineFormat::N1BitLsbPal ) ||
306 ( nDstScanlineFormat == ScanlineFormat::N8BitPal ) )
308 assert(pDstPal && "destination buffer requires palette");
309 if (!pDstPal)
311 return nullptr;
313 pDstBuffer->maPalette = *pDstPal;
315 else if(nDstScanlineFormat == ScanlineFormat::N32BitTcMask )
317 assert(pDstMask && "destination buffer requires color mask");
318 if (!pDstMask)
320 return nullptr;
322 pDstBuffer->maColorMask = *pDstMask;
325 // short circuit the most important conversions
326 bool bFastConvert = ImplFastBitmapConversion( *pDstBuffer, rSrcBuffer, rTwoRect );
327 if( bFastConvert )
328 return pDstBuffer;
330 std::unique_ptr<Scanline[]> pSrcScan;
331 std::unique_ptr<Scanline[]> pDstScan;
332 std::unique_ptr<tools::Long[]> pMapX;
333 std::unique_ptr<tools::Long[]> pMapY;
337 pSrcScan.reset(new Scanline[rSrcBuffer.mnHeight]);
338 pDstScan.reset(new Scanline[pDstBuffer->mnHeight]);
339 pMapX.reset(new tools::Long[pDstBuffer->mnWidth]);
340 pMapY.reset(new tools::Long[pDstBuffer->mnHeight]);
342 catch( const std::bad_alloc& )
344 // memory exception, clean up
345 // remark: the buffer ptr causing the exception
346 // is still NULL here
347 return nullptr;
350 // horizontal mapping table
351 if( (pDstBuffer->mnWidth != rTwoRect.mnSrcWidth) && (pDstBuffer->mnWidth != 0) )
353 const double fFactorX = static_cast<double>(rTwoRect.mnSrcWidth) / pDstBuffer->mnWidth;
355 for (tools::Long i = 0; i < pDstBuffer->mnWidth; ++i)
356 pMapX[ i ] = rTwoRect.mnSrcX + static_cast<int>( i * fFactorX );
358 else
360 for (tools::Long i = 0, nTmp = rTwoRect.mnSrcX ; i < pDstBuffer->mnWidth; ++i)
361 pMapX[ i ] = nTmp++;
364 // vertical mapping table
365 if( (pDstBuffer->mnHeight != rTwoRect.mnSrcHeight) && (pDstBuffer->mnHeight != 0) )
367 const double fFactorY = static_cast<double>(rTwoRect.mnSrcHeight) / pDstBuffer->mnHeight;
369 for (tools::Long i = 0; i < pDstBuffer->mnHeight; ++i)
370 pMapY[ i ] = rTwoRect.mnSrcY + static_cast<int>( i * fFactorY );
372 else
374 for (tools::Long i = 0, nTmp = rTwoRect.mnSrcY; i < pDstBuffer->mnHeight; ++i)
375 pMapY[ i ] = nTmp++;
378 // source scanline buffer
379 Scanline pTmpScan;
380 tools::Long nOffset;
381 if( rSrcBuffer.mnFormat & ScanlineFormat::TopDown )
383 pTmpScan = rSrcBuffer.mpBits;
384 nOffset = rSrcBuffer.mnScanlineSize;
386 else
388 pTmpScan = rSrcBuffer.mpBits + ( rSrcBuffer.mnHeight - 1 ) * rSrcBuffer.mnScanlineSize;
389 nOffset = -rSrcBuffer.mnScanlineSize;
392 for (tools::Long i = 0; i < rSrcBuffer.mnHeight; i++, pTmpScan += nOffset)
393 pSrcScan[ i ] = pTmpScan;
395 // destination scanline buffer
396 if( pDstBuffer->mnFormat & ScanlineFormat::TopDown )
398 pTmpScan = pDstBuffer->mpBits;
399 nOffset = pDstBuffer->mnScanlineSize;
401 else
403 pTmpScan = pDstBuffer->mpBits + ( pDstBuffer->mnHeight - 1 ) * pDstBuffer->mnScanlineSize;
404 nOffset = -pDstBuffer->mnScanlineSize;
407 for (tools::Long i = 0; i < pDstBuffer->mnHeight; i++, pTmpScan += nOffset)
408 pDstScan[ i ] = pTmpScan;
410 // do buffer scaling and conversion
411 if( rSrcBuffer.mnBitCount <= 8 && pDstBuffer->mnBitCount <= 8 )
413 ImplPALToPAL( rSrcBuffer, *pDstBuffer, pFncGetPixel, pFncSetPixel,
414 pSrcScan.get(), pDstScan.get(), pMapX.get(), pMapY.get() );
416 else if( rSrcBuffer.mnBitCount <= 8 && pDstBuffer->mnBitCount > 8 )
418 ImplPALToTC( rSrcBuffer, *pDstBuffer, pFncGetPixel, pFncSetPixel,
419 pSrcScan.get(), pDstScan.get(), pMapX.get(), pMapY.get() );
421 else if( rSrcBuffer.mnBitCount > 8 && pDstBuffer->mnBitCount > 8 )
423 ImplTCToTC( rSrcBuffer, *pDstBuffer, pFncGetPixel, pFncSetPixel,
424 pSrcScan.get(), pDstScan.get(), pMapX.get(), pMapY.get() );
426 else
428 ImplTCToPAL( rSrcBuffer, *pDstBuffer, pFncGetPixel, pFncSetPixel,
429 pSrcScan.get(), pDstScan.get(), pMapX.get(), pMapY.get() );
432 return pDstBuffer;
435 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */