1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20 #include <vcl/salgtype.hxx>
21
22 #include <bitmap/BitmapWriteAccess.hxx>
23 #include <bitmap/bmpfast.hxx>
24
25 #include <sal/log.hxx>
26
27 typedef unsigned char PIXBYTE;
28
29 namespace {
30
31 class BasePixelPtr
32 {
33 public:
BasePixelPtr(PIXBYTE * p=nullptr)34 explicit BasePixelPtr( PIXBYTE* p = nullptr ) : mpPixel( p ) {}
SetRawPtr(PIXBYTE * pRawPtr)35 void SetRawPtr( PIXBYTE* pRawPtr ) { mpPixel = pRawPtr; }
AddByteOffset(int nByteOffset)36 void AddByteOffset( int nByteOffset ) { mpPixel += nByteOffset; }
37
38 protected:
39 PIXBYTE* mpPixel;
40 };
41
42 template <ScanlineFormat PIXFMT>
43 class TrueColorPixelPtr : public BasePixelPtr
44 {
45 public:
46 PIXBYTE GetRed() const;
47 PIXBYTE GetGreen() const;
48 PIXBYTE GetBlue() const;
49 PIXBYTE GetAlpha() const;
50
51 void SetColor( PIXBYTE r, PIXBYTE g, PIXBYTE b ) const;
52 void SetAlpha( PIXBYTE a ) const;
53 };
54
55 // template specializations for truecolor pixel formats
56 template <>
57 class TrueColorPixelPtr<ScanlineFormat::N24BitTcRgb> : public BasePixelPtr
58 {
59 public:
operator ++()60 void operator++() { mpPixel += 3; }
61
GetRed() const62 PIXBYTE GetRed() const { return mpPixel[0]; }
GetGreen() const63 PIXBYTE GetGreen() const { return mpPixel[1]; }
GetBlue() const64 PIXBYTE GetBlue() const { return mpPixel[2]; }
GetAlpha()65 static PIXBYTE GetAlpha() { return 255; }
SetAlpha(PIXBYTE)66 static void SetAlpha( PIXBYTE ) {}
67
SetColor(PIXBYTE r,PIXBYTE g,PIXBYTE b) const68 void SetColor( PIXBYTE r, PIXBYTE g, PIXBYTE b ) const
69 {
70 mpPixel[0] = r;
71 mpPixel[1] = g;
72 mpPixel[2] = b;
73 }
74 };
75
76 template <>
77 class TrueColorPixelPtr<ScanlineFormat::N24BitTcBgr> : public BasePixelPtr
78 {
79 public:
operator ++()80 void operator++() { mpPixel += 3; }
81
GetRed() const82 PIXBYTE GetRed() const { return mpPixel[2]; }
GetGreen() const83 PIXBYTE GetGreen() const { return mpPixel[1]; }
GetBlue() const84 PIXBYTE GetBlue() const { return mpPixel[0]; }
GetAlpha()85 static PIXBYTE GetAlpha() { return 255; }
SetAlpha(PIXBYTE)86 static void SetAlpha( PIXBYTE ) {}
87
SetColor(PIXBYTE r,PIXBYTE g,PIXBYTE b) const88 void SetColor( PIXBYTE r, PIXBYTE g, PIXBYTE b ) const
89 {
90 mpPixel[0] = b;
91 mpPixel[1] = g;
92 mpPixel[2] = r;
93 }
94 };
95
96 template <>
97 class TrueColorPixelPtr<ScanlineFormat::N32BitTcArgb> : public BasePixelPtr
98 {
99 public:
operator ++()100 void operator++() { mpPixel += 4; }
101
GetRed() const102 PIXBYTE GetRed() const { return mpPixel[1]; }
GetGreen() const103 PIXBYTE GetGreen() const { return mpPixel[2]; }
GetBlue() const104 PIXBYTE GetBlue() const { return mpPixel[3]; }
GetAlpha() const105 PIXBYTE GetAlpha() const { return mpPixel[0]; }
SetAlpha(PIXBYTE a) const106 void SetAlpha( PIXBYTE a ) const { mpPixel[0] = a; }
107
SetColor(PIXBYTE r,PIXBYTE g,PIXBYTE b) const108 void SetColor( PIXBYTE r, PIXBYTE g, PIXBYTE b ) const
109 {
110 mpPixel[1] = r;
111 mpPixel[2] = g;
112 mpPixel[3] = b;
113 }
114 };
115
116 template <>
117 class TrueColorPixelPtr<ScanlineFormat::N32BitTcAbgr> : public BasePixelPtr
118 {
119 public:
operator ++()120 void operator++() { mpPixel += 4; }
121
GetRed() const122 PIXBYTE GetRed() const { return mpPixel[3]; }
GetGreen() const123 PIXBYTE GetGreen() const { return mpPixel[2]; }
GetBlue() const124 PIXBYTE GetBlue() const { return mpPixel[1]; }
GetAlpha() const125 PIXBYTE GetAlpha() const { return mpPixel[0]; }
SetAlpha(PIXBYTE a) const126 void SetAlpha( PIXBYTE a ) const { mpPixel[0] = a; }
127
SetColor(PIXBYTE r,PIXBYTE g,PIXBYTE b) const128 void SetColor( PIXBYTE r, PIXBYTE g, PIXBYTE b ) const
129 {
130 mpPixel[1] = b;
131 mpPixel[2] = g;
132 mpPixel[3] = r;
133 }
134 };
135
136 template <>
137 class TrueColorPixelPtr<ScanlineFormat::N32BitTcRgba> : public BasePixelPtr
138 {
139 public:
operator ++()140 void operator++() { mpPixel += 4; }
141
GetRed() const142 PIXBYTE GetRed() const { return mpPixel[0]; }
GetGreen() const143 PIXBYTE GetGreen() const { return mpPixel[1]; }
GetBlue() const144 PIXBYTE GetBlue() const { return mpPixel[2]; }
GetAlpha() const145 PIXBYTE GetAlpha() const { return mpPixel[3]; }
SetAlpha(PIXBYTE a) const146 void SetAlpha( PIXBYTE a ) const{ mpPixel[3] = a; }
147
SetColor(PIXBYTE r,PIXBYTE g,PIXBYTE b) const148 void SetColor( PIXBYTE r, PIXBYTE g, PIXBYTE b ) const
149 {
150 mpPixel[0] = r;
151 mpPixel[1] = g;
152 mpPixel[2] = b;
153 }
154 };
155
156 template <>
157 class TrueColorPixelPtr<ScanlineFormat::N32BitTcBgra> : public BasePixelPtr
158 {
159 public:
operator ++()160 void operator++() { mpPixel += 4; }
161
GetRed() const162 PIXBYTE GetRed() const { return mpPixel[2]; }
GetGreen() const163 PIXBYTE GetGreen() const { return mpPixel[1]; }
GetBlue() const164 PIXBYTE GetBlue() const { return mpPixel[0]; }
GetAlpha() const165 PIXBYTE GetAlpha() const { return mpPixel[3]; }
SetAlpha(PIXBYTE a) const166 void SetAlpha( PIXBYTE a ) const{ mpPixel[3] = a; }
167
SetColor(PIXBYTE r,PIXBYTE g,PIXBYTE b) const168 void SetColor( PIXBYTE r, PIXBYTE g, PIXBYTE b ) const
169 {
170 mpPixel[0] = b;
171 mpPixel[1] = g;
172 mpPixel[2] = r;
173 }
174 };
175
176 // This assumes the content uses the grayscale palette (needs to be checked
177 // by code allowing the use of the format).
178 // Only reading color is implemented, since e.g. 24bpp input couldn't be
179 // easily guaranteed to be grayscale.
180 template <>
181 class TrueColorPixelPtr<ScanlineFormat::N8BitPal> : public BasePixelPtr
182 {
183 public:
operator ++()184 void operator++() { mpPixel += 1; }
185
GetRed() const186 PIXBYTE GetRed() const { return mpPixel[0]; }
GetGreen() const187 PIXBYTE GetGreen() const { return mpPixel[0]; }
GetBlue() const188 PIXBYTE GetBlue() const { return mpPixel[0]; }
GetAlpha()189 static PIXBYTE GetAlpha() { return 255; }
190 };
191
192 }
193
194 // converting truecolor formats
195 template <ScanlineFormat SRCFMT, ScanlineFormat DSTFMT>
ImplConvertPixel(const TrueColorPixelPtr<DSTFMT> & rDst,const TrueColorPixelPtr<SRCFMT> & rSrc)196 static void ImplConvertPixel( const TrueColorPixelPtr<DSTFMT>& rDst,
197 const TrueColorPixelPtr<SRCFMT>& rSrc )
198 {
199 rDst.SetColor( rSrc.GetRed(), rSrc.GetGreen(), rSrc.GetBlue() );
200 rDst.SetAlpha( rSrc.GetAlpha() );
201 }
202
203 template <ScanlineFormat SRCFMT, ScanlineFormat DSTFMT>
ImplConvertLine(const TrueColorPixelPtr<DSTFMT> & rDst,const TrueColorPixelPtr<SRCFMT> & rSrc,int nPixelCount)204 static void ImplConvertLine( const TrueColorPixelPtr<DSTFMT>& rDst,
205 const TrueColorPixelPtr<SRCFMT>& rSrc, int nPixelCount )
206 {
207 TrueColorPixelPtr<DSTFMT> aDst( rDst );
208 TrueColorPixelPtr<SRCFMT> aSrc( rSrc );
209 while( --nPixelCount >= 0 )
210 {
211 ImplConvertPixel( aDst, aSrc );
212 ++aSrc;
213 ++aDst;
214 }
215 }
216
217 // alpha blending truecolor pixels
218 template <ScanlineFormat SRCFMT, ScanlineFormat DSTFMT>
ImplBlendPixels(const TrueColorPixelPtr<DSTFMT> & rDst,const TrueColorPixelPtr<SRCFMT> & rSrc,unsigned nAlphaVal)219 static void ImplBlendPixels( const TrueColorPixelPtr<DSTFMT>& rDst,
220 const TrueColorPixelPtr<SRCFMT>& rSrc, unsigned nAlphaVal )
221 {
222 static const unsigned nAlphaShift = 8;
223 if( !nAlphaVal )
224 ImplConvertPixel( rDst, rSrc );
225 else if( nAlphaVal != ~(~0U << nAlphaShift) )
226 {
227 int nR = rDst.GetRed();
228 int nS = rSrc.GetRed();
229 nR = nS + (((nR - nS) * nAlphaVal) >> nAlphaShift);
230
231 int nG = rDst.GetGreen();
232 nS = rSrc.GetGreen();
233 nG = nS + (((nG - nS) * nAlphaVal) >> nAlphaShift);
234
235 int nB = rDst.GetBlue();
236 nS = rSrc.GetBlue();
237 nB = nS + (((nB - nS) * nAlphaVal) >> nAlphaShift);
238
239 rDst.SetColor( sal::static_int_cast<PIXBYTE>(nR),
240 sal::static_int_cast<PIXBYTE>(nG),
241 sal::static_int_cast<PIXBYTE>(nB) );
242 }
243 }
244
245 template <ScanlineFormat MASKFMT, ScanlineFormat SRCFMT, ScanlineFormat DSTFMT>
ImplBlendLines(const TrueColorPixelPtr<DSTFMT> & rDst,const TrueColorPixelPtr<SRCFMT> & rSrc,const TrueColorPixelPtr<MASKFMT> & rMsk,int nPixelCount)246 static void ImplBlendLines( const TrueColorPixelPtr<DSTFMT>& rDst,
247 const TrueColorPixelPtr<SRCFMT>& rSrc, const TrueColorPixelPtr<MASKFMT>& rMsk,
248 int nPixelCount )
249 {
250 TrueColorPixelPtr<MASKFMT> aMsk( rMsk );
251 TrueColorPixelPtr<DSTFMT> aDst( rDst );
252 TrueColorPixelPtr<SRCFMT> aSrc( rSrc );
253 while( --nPixelCount >= 0 )
254 {
255 // VCL masks store alpha as color, hence the GetRed() and not GetAlpha().
256 ImplBlendPixels(aDst, aSrc, aMsk.GetRed());
257 ++aDst;
258 ++aSrc;
259 ++aMsk;
260 }
261 }
262
ImplCopyImage(BitmapBuffer & rDstBuffer,const BitmapBuffer & rSrcBuffer)263 static bool ImplCopyImage( BitmapBuffer& rDstBuffer, const BitmapBuffer& rSrcBuffer )
264 {
265 const int nSrcLinestep = rSrcBuffer.mnScanlineSize;
266 int nDstLinestep = rDstBuffer.mnScanlineSize;
267
268 const PIXBYTE* pRawSrc = rSrcBuffer.mpBits;
269 PIXBYTE* pRawDst = rDstBuffer.mpBits;
270
271 // source and destination don't match upside down
272 if( ScanlineFormat::TopDown & (rSrcBuffer.mnFormat ^ rDstBuffer.mnFormat) )
273 {
274 pRawDst += (rSrcBuffer.mnHeight - 1) * nDstLinestep;
275 nDstLinestep = -rDstBuffer.mnScanlineSize;
276 }
277 else if( nSrcLinestep == nDstLinestep )
278 {
279 memcpy( pRawDst, pRawSrc, rSrcBuffer.mnHeight * nDstLinestep );
280 return true;
281 }
282
283 int nByteWidth = nSrcLinestep;
284 if( nByteWidth > rDstBuffer.mnScanlineSize )
285 nByteWidth = rDstBuffer.mnScanlineSize;
286
287 for( int y = rSrcBuffer.mnHeight; --y >= 0; )
288 {
289 memcpy( pRawDst, pRawSrc, nByteWidth );
290 pRawSrc += nSrcLinestep;
291 pRawDst += nDstLinestep;
292 }
293
294 return true;
295 }
296
297 template <ScanlineFormat DSTFMT,ScanlineFormat SRCFMT>
ImplConvertToBitmap(TrueColorPixelPtr<SRCFMT> & rSrcLine,BitmapBuffer & rDstBuffer,const BitmapBuffer & rSrcBuffer)298 static bool ImplConvertToBitmap( TrueColorPixelPtr<SRCFMT>& rSrcLine,
299 BitmapBuffer& rDstBuffer, const BitmapBuffer& rSrcBuffer )
300 {
301 // help the compiler to avoid instantiations of unneeded conversions
302 SAL_WARN_IF( SRCFMT == DSTFMT, "vcl.gdi", "ImplConvertToBitmap into same format");
303 if( SRCFMT == DSTFMT )
304 return false;
305
306 const int nSrcLinestep = rSrcBuffer.mnScanlineSize;
307 int nDstLinestep = rDstBuffer.mnScanlineSize;
308
309 TrueColorPixelPtr<DSTFMT> aDstLine; aDstLine.SetRawPtr( rDstBuffer.mpBits );
310
311 // source and destination don't match upside down
312 if( ScanlineFormat::TopDown & (rSrcBuffer.mnFormat ^ rDstBuffer.mnFormat) )
313 {
314 aDstLine.AddByteOffset( (rSrcBuffer.mnHeight - 1) * nDstLinestep );
315 nDstLinestep = -nDstLinestep;
316 }
317
318 for( int y = rSrcBuffer.mnHeight; --y >= 0; )
319 {
320 ImplConvertLine( aDstLine, rSrcLine, rSrcBuffer.mnWidth );
321 rSrcLine.AddByteOffset( nSrcLinestep );
322 aDstLine.AddByteOffset( nDstLinestep );
323 }
324
325 return true;
326 }
327
328 template <ScanlineFormat SRCFMT>
ImplConvertFromBitmap(BitmapBuffer & rDst,const BitmapBuffer & rSrc)329 static bool ImplConvertFromBitmap( BitmapBuffer& rDst, const BitmapBuffer& rSrc )
330 {
331 TrueColorPixelPtr<SRCFMT> aSrcType; aSrcType.SetRawPtr( rSrc.mpBits );
332
333 // select the matching instantiation for the destination's bitmap format
334 switch (RemoveScanline(rDst.mnFormat))
335 {
336 case ScanlineFormat::N1BitMsbPal:
337 case ScanlineFormat::N1BitLsbPal:
338 case ScanlineFormat::N8BitPal:
339 break;
340
341 case ScanlineFormat::N32BitTcMask:
342 // return ImplConvertToBitmap<ScanlineFormat::N32BitTcMask>( aSrcType, rDst, rSrc );
343 break;
344
345 case ScanlineFormat::N24BitTcBgr:
346 return ImplConvertToBitmap<ScanlineFormat::N24BitTcBgr>( aSrcType, rDst, rSrc );
347 case ScanlineFormat::N24BitTcRgb:
348 return ImplConvertToBitmap<ScanlineFormat::N24BitTcRgb>( aSrcType, rDst, rSrc );
349
350 case ScanlineFormat::N32BitTcAbgr:
351 return ImplConvertToBitmap<ScanlineFormat::N32BitTcAbgr>( aSrcType, rDst, rSrc );
352 case ScanlineFormat::N32BitTcArgb:
353 return ImplConvertToBitmap<ScanlineFormat::N32BitTcArgb>( aSrcType, rDst, rSrc );
354 case ScanlineFormat::N32BitTcBgra:
355 return ImplConvertToBitmap<ScanlineFormat::N32BitTcBgra>( aSrcType, rDst, rSrc );
356 case ScanlineFormat::N32BitTcRgba:
357 return ImplConvertToBitmap<ScanlineFormat::N32BitTcRgba>( aSrcType, rDst, rSrc );
358 default: break;
359 }
360
361 static int nNotAccelerated = 0;
362 SAL_WARN_IF( rSrc.mnWidth * rSrc.mnHeight >= 4000 && ++nNotAccelerated == 100,
363 "vcl.gdi",
364 "ImplConvertFromBitmap for not accelerated case (" << std::hex << static_cast<int>(rSrc.mnFormat) << "->" << static_cast<int>(rDst.mnFormat) << ")" );
365
366 return false;
367 }
368
369 // A universal stretching conversion is overkill in most common situations
370 // => performance benefits for speeding up the non-stretching cases
ImplFastBitmapConversion(BitmapBuffer & rDst,const BitmapBuffer & rSrc,const SalTwoRect & rTR)371 bool ImplFastBitmapConversion( BitmapBuffer& rDst, const BitmapBuffer& rSrc,
372 const SalTwoRect& rTR )
373 {
374 // TODO:horizontal mirroring not implemented yet
375 if( rTR.mnDestWidth < 0 )
376 return false;
377 // vertical mirroring
378 if( rTR.mnDestHeight < 0 )
379 // TODO: rDst.mnFormat ^= ScanlineFormat::TopDown;
380 return false;
381
382 // offsetted conversion is not implemented yet
383 if( rTR.mnSrcX || rTR.mnSrcY )
384 return false;
385 if( rTR.mnDestX || rTR.mnDestY )
386 return false;
387
388 // stretched conversion is not implemented yet
389 if( rTR.mnDestWidth != rTR.mnSrcWidth )
390 return false;
391 if( rTR.mnDestHeight!= rTR.mnSrcHeight )
392 return false;
393
394 // check source image size
395 if( rSrc.mnWidth < rTR.mnSrcX + rTR.mnSrcWidth )
396 return false;
397 if( rSrc.mnHeight < rTR.mnSrcY + rTR.mnSrcHeight )
398 return false;
399
400 // check dest image size
401 if( rDst.mnWidth < rTR.mnDestX + rTR.mnDestWidth )
402 return false;
403 if( rDst.mnHeight < rTR.mnDestY + rTR.mnDestHeight )
404 return false;
405
406 const ScanlineFormat nSrcFormat = RemoveScanline(rSrc.mnFormat);
407 const ScanlineFormat nDstFormat = RemoveScanline(rDst.mnFormat);
408
409 // special handling of trivial cases
410 if( nSrcFormat == nDstFormat )
411 {
412 // accelerated palette conversions not yet implemented
413 if( rSrc.maPalette != rDst.maPalette )
414 return false;
415 return ImplCopyImage( rDst, rSrc );
416 }
417
418 // select the matching instantiation for the source's bitmap format
419 switch( nSrcFormat )
420 {
421 case ScanlineFormat::N1BitMsbPal:
422 case ScanlineFormat::N1BitLsbPal:
423 break;
424
425 case ScanlineFormat::N32BitTcMask:
426 // return ImplConvertFromBitmap<ScanlineFormat::N32BitTcMask>( rDst, rSrc );
427 break;
428
429 case ScanlineFormat::N8BitPal:
430 if(rSrc.maPalette.IsGreyPalette8Bit())
431 return ImplConvertFromBitmap<ScanlineFormat::N8BitPal>( rDst, rSrc );
432 break;
433
434 case ScanlineFormat::N24BitTcBgr:
435 return ImplConvertFromBitmap<ScanlineFormat::N24BitTcBgr>( rDst, rSrc );
436 case ScanlineFormat::N24BitTcRgb:
437 return ImplConvertFromBitmap<ScanlineFormat::N24BitTcRgb>( rDst, rSrc );
438
439 case ScanlineFormat::N32BitTcAbgr:
440 return ImplConvertFromBitmap<ScanlineFormat::N32BitTcAbgr>( rDst, rSrc );
441 case ScanlineFormat::N32BitTcArgb:
442 return ImplConvertFromBitmap<ScanlineFormat::N32BitTcArgb>( rDst, rSrc );
443 case ScanlineFormat::N32BitTcBgra:
444 return ImplConvertFromBitmap<ScanlineFormat::N32BitTcBgra>( rDst, rSrc );
445 case ScanlineFormat::N32BitTcRgba:
446 return ImplConvertFromBitmap<ScanlineFormat::N32BitTcRgba>( rDst, rSrc );
447 default: break;
448 }
449
450 static int nNotAccelerated = 0;
451 SAL_WARN_IF( rSrc.mnWidth * rSrc.mnHeight >= 4000 && ++nNotAccelerated == 100,
452 "vcl.gdi",
453 "ImplFastBitmapConversion for not accelerated case (" << std::hex << static_cast<int>(rSrc.mnFormat) << "->" << static_cast<int>(rDst.mnFormat) << ")" );
454
455 return false;
456 }
457
ImplGetScanline(const BitmapBuffer & rBuf,tools::Long nY)458 static inline ConstScanline ImplGetScanline( const BitmapBuffer& rBuf, tools::Long nY )
459 {
460 if( rBuf.mnFormat & ScanlineFormat::TopDown )
461 return rBuf.mpBits + nY * rBuf.mnScanlineSize;
462 else
463 return rBuf.mpBits + (rBuf.mnHeight - 1 - nY) * rBuf.mnScanlineSize;
464 }
465
ImplGetScanline(BitmapBuffer & rBuf,tools::Long nY)466 static inline Scanline ImplGetScanline( BitmapBuffer& rBuf, tools::Long nY )
467 {
468 return const_cast<Scanline>(ImplGetScanline( const_cast<const BitmapBuffer&>(rBuf), nY ));
469 }
470
471 template <ScanlineFormat DSTFMT, ScanlineFormat SRCFMT>
ImplCopyToScanline(tools::Long nY,BitmapBuffer & rDst,TrueColorPixelPtr<SRCFMT> & rSrcLine,tools::Long nSrcWidth)472 static bool ImplCopyToScanline( tools::Long nY, BitmapBuffer& rDst, TrueColorPixelPtr<SRCFMT>& rSrcLine, tools::Long nSrcWidth )
473 {
474 TrueColorPixelPtr<DSTFMT> aDstType;
475 aDstType.SetRawPtr( ImplGetScanline( rDst, nY ));
476 ImplConvertLine( aDstType, rSrcLine, std::min( nSrcWidth, rDst.mnWidth ));
477 return true;
478 }
479
480 template <ScanlineFormat SRCFMT>
ImplCopyFromScanline(tools::Long nY,BitmapBuffer & rDst,ConstScanline aSrcScanline,tools::Long nSrcWidth)481 static bool ImplCopyFromScanline( tools::Long nY, BitmapBuffer& rDst, ConstScanline aSrcScanline, tools::Long nSrcWidth )
482 {
483 TrueColorPixelPtr<SRCFMT> aSrcType;
484 aSrcType.SetRawPtr( const_cast<Scanline>( aSrcScanline ));
485 // select the matching instantiation for the destination's bitmap format
486 switch( RemoveScanline( rDst.mnFormat ))
487 {
488 case ScanlineFormat::N24BitTcBgr:
489 return ImplCopyToScanline<ScanlineFormat::N24BitTcBgr>( nY, rDst, aSrcType, nSrcWidth );
490 case ScanlineFormat::N24BitTcRgb:
491 return ImplCopyToScanline<ScanlineFormat::N24BitTcRgb>( nY, rDst, aSrcType, nSrcWidth );
492
493 case ScanlineFormat::N32BitTcAbgr:
494 return ImplCopyToScanline<ScanlineFormat::N32BitTcAbgr>( nY, rDst, aSrcType, nSrcWidth );
495 case ScanlineFormat::N32BitTcArgb:
496 return ImplCopyToScanline<ScanlineFormat::N32BitTcArgb>( nY, rDst, aSrcType, nSrcWidth );
497 case ScanlineFormat::N32BitTcBgra:
498 return ImplCopyToScanline<ScanlineFormat::N32BitTcBgra>( nY, rDst, aSrcType, nSrcWidth );
499 case ScanlineFormat::N32BitTcRgba:
500 return ImplCopyToScanline<ScanlineFormat::N32BitTcRgba>( nY, rDst, aSrcType, nSrcWidth );
501 default:
502 break;
503 }
504 return false;
505
506 }
507
ImplFastCopyScanline(tools::Long nY,BitmapBuffer & rDst,ConstScanline aSrcScanline,ScanlineFormat nSrcScanlineFormat,sal_uInt32 nSrcScanlineSize)508 bool ImplFastCopyScanline( tools::Long nY, BitmapBuffer& rDst, ConstScanline aSrcScanline,
509 ScanlineFormat nSrcScanlineFormat, sal_uInt32 nSrcScanlineSize)
510 {
511 if( rDst.mnHeight <= nY )
512 return false;
513
514 const ScanlineFormat nSrcFormat = RemoveScanline(nSrcScanlineFormat);
515 const ScanlineFormat nDstFormat = RemoveScanline(rDst.mnFormat);
516
517 // special handling of trivial cases
518 if( nSrcFormat == nDstFormat )
519 {
520 memcpy( ImplGetScanline( rDst, nY ), aSrcScanline, std::min<tools::Long>(nSrcScanlineSize, rDst.mnScanlineSize));
521 return true;
522 }
523
524 // select the matching instantiation for the source's bitmap format
525 switch( nSrcFormat )
526 {
527 case ScanlineFormat::N24BitTcBgr:
528 return ImplCopyFromScanline<ScanlineFormat::N24BitTcBgr>( nY, rDst, aSrcScanline, nSrcScanlineSize / 3 );
529 case ScanlineFormat::N24BitTcRgb:
530 return ImplCopyFromScanline<ScanlineFormat::N24BitTcRgb>( nY, rDst, aSrcScanline, nSrcScanlineSize / 3 );
531
532 case ScanlineFormat::N32BitTcAbgr:
533 return ImplCopyFromScanline<ScanlineFormat::N32BitTcAbgr>( nY, rDst, aSrcScanline, nSrcScanlineSize / 4 );
534 case ScanlineFormat::N32BitTcArgb:
535 return ImplCopyFromScanline<ScanlineFormat::N32BitTcArgb>( nY, rDst, aSrcScanline, nSrcScanlineSize / 4 );
536 case ScanlineFormat::N32BitTcBgra:
537 return ImplCopyFromScanline<ScanlineFormat::N32BitTcBgra>( nY, rDst, aSrcScanline, nSrcScanlineSize / 4 );
538 case ScanlineFormat::N32BitTcRgba:
539 return ImplCopyFromScanline<ScanlineFormat::N32BitTcRgba>( nY, rDst, aSrcScanline, nSrcScanlineSize / 4 );
540 default:
541 break;
542 }
543 return false;
544 }
545
ImplFastCopyScanline(tools::Long nY,BitmapBuffer & rDst,const BitmapBuffer & rSrc)546 bool ImplFastCopyScanline( tools::Long nY, BitmapBuffer& rDst, const BitmapBuffer& rSrc)
547 {
548 if( nY >= rDst.mnHeight )
549 return false;
550 if( rSrc.maPalette != rDst.maPalette )
551 return false;
552 return ImplFastCopyScanline( nY, rDst, ImplGetScanline( rSrc, nY ), rSrc.mnFormat, rSrc.mnScanlineSize);
553 }
554
555 template <ScanlineFormat DSTFMT, ScanlineFormat SRCFMT> //,sal_uLong MSKFMT>
ImplBlendToBitmap(TrueColorPixelPtr<SRCFMT> & rSrcLine,BitmapBuffer & rDstBuffer,const BitmapBuffer & rSrcBuffer,const BitmapBuffer & rMskBuffer)556 static bool ImplBlendToBitmap( TrueColorPixelPtr<SRCFMT>& rSrcLine,
557 BitmapBuffer& rDstBuffer, const BitmapBuffer& rSrcBuffer,
558 const BitmapBuffer& rMskBuffer )
559 {
560 SAL_WARN_IF(( rMskBuffer.mnFormat & ~ScanlineFormat::TopDown ) != ScanlineFormat::N8BitPal,
561 "vcl.gdi", "FastBmp BlendImage: unusual MSKFMT" );
562
563 const int nSrcLinestep = rSrcBuffer.mnScanlineSize;
564 int nMskLinestep = rMskBuffer.mnScanlineSize;
565 int nDstLinestep = rDstBuffer.mnScanlineSize;
566
567 TrueColorPixelPtr<ScanlineFormat::N8BitPal> aMskLine; aMskLine.SetRawPtr( rMskBuffer.mpBits );
568 TrueColorPixelPtr<DSTFMT> aDstLine; aDstLine.SetRawPtr( rDstBuffer.mpBits );
569
570 // special case for single line masks
571 if( rMskBuffer.mnHeight == 1 )
572 nMskLinestep = 0;
573
574 // source and mask don't match: upside down
575 if( (rSrcBuffer.mnFormat ^ rMskBuffer.mnFormat) & ScanlineFormat::TopDown )
576 {
577 aMskLine.AddByteOffset( (rSrcBuffer.mnHeight - 1) * nMskLinestep );
578 nMskLinestep = -nMskLinestep;
579 }
580
581 // source and destination don't match: upside down
582 if( (rSrcBuffer.mnFormat ^ rDstBuffer.mnFormat) & ScanlineFormat::TopDown )
583 {
584 aDstLine.AddByteOffset( (rDstBuffer.mnHeight - 1) * nDstLinestep );
585 nDstLinestep = -nDstLinestep;
586 }
587
588 assert(rDstBuffer.mnHeight <= rSrcBuffer.mnHeight && "not sure about that?");
589 for (int y = rDstBuffer.mnHeight; --y >= 0;)
590 {
591 ImplBlendLines(aDstLine, rSrcLine, aMskLine, rDstBuffer.mnWidth);
592 aDstLine.AddByteOffset( nDstLinestep );
593 rSrcLine.AddByteOffset( nSrcLinestep );
594 aMskLine.AddByteOffset( nMskLinestep );
595 }
596
597 return true;
598 }
599
600 // some specializations to reduce the code size
601 template <>
ImplBlendToBitmap(TrueColorPixelPtr<ScanlineFormat::N24BitTcBgr> &,BitmapBuffer & rDstBuffer,const BitmapBuffer & rSrcBuffer,const BitmapBuffer & rMskBuffer)602 bool ImplBlendToBitmap<ScanlineFormat::N24BitTcBgr,ScanlineFormat::N24BitTcBgr>(
603 TrueColorPixelPtr<ScanlineFormat::N24BitTcBgr>&,
604 BitmapBuffer& rDstBuffer, const BitmapBuffer& rSrcBuffer,
605 const BitmapBuffer& rMskBuffer )
606 {
607 TrueColorPixelPtr<ScanlineFormat::N24BitTcRgb> aSrcType; aSrcType.SetRawPtr( rSrcBuffer.mpBits );
608 return ImplBlendToBitmap<ScanlineFormat::N24BitTcRgb>( aSrcType, rDstBuffer, rSrcBuffer, rMskBuffer );
609 }
610
611 template <>
ImplBlendToBitmap(TrueColorPixelPtr<ScanlineFormat::N32BitTcAbgr> &,BitmapBuffer & rDstBuffer,const BitmapBuffer & rSrcBuffer,const BitmapBuffer & rMskBuffer)612 bool ImplBlendToBitmap<ScanlineFormat::N32BitTcAbgr,ScanlineFormat::N32BitTcAbgr>(
613 TrueColorPixelPtr<ScanlineFormat::N32BitTcAbgr>&,
614 BitmapBuffer& rDstBuffer, const BitmapBuffer& rSrcBuffer,
615 const BitmapBuffer& rMskBuffer )
616 {
617 TrueColorPixelPtr<ScanlineFormat::N32BitTcArgb> aSrcType; aSrcType.SetRawPtr( rSrcBuffer.mpBits );
618 return ImplBlendToBitmap<ScanlineFormat::N32BitTcArgb>( aSrcType, rDstBuffer, rSrcBuffer, rMskBuffer );
619 }
620
621 template <>
ImplBlendToBitmap(TrueColorPixelPtr<ScanlineFormat::N32BitTcBgra> &,BitmapBuffer & rDstBuffer,const BitmapBuffer & rSrcBuffer,const BitmapBuffer & rMskBuffer)622 bool ImplBlendToBitmap<ScanlineFormat::N32BitTcBgra,ScanlineFormat::N32BitTcBgra>(
623 TrueColorPixelPtr<ScanlineFormat::N32BitTcBgra>&,
624 BitmapBuffer& rDstBuffer, const BitmapBuffer& rSrcBuffer,
625 const BitmapBuffer& rMskBuffer )
626 {
627 TrueColorPixelPtr<ScanlineFormat::N32BitTcRgba> aSrcType; aSrcType.SetRawPtr( rSrcBuffer.mpBits );
628 return ImplBlendToBitmap<ScanlineFormat::N32BitTcRgba>( aSrcType, rDstBuffer, rSrcBuffer, rMskBuffer );
629 }
630
631 template <ScanlineFormat SRCFMT>
ImplBlendFromBitmap(BitmapBuffer & rDst,const BitmapBuffer & rSrc,const BitmapBuffer & rMsk)632 static bool ImplBlendFromBitmap( BitmapBuffer& rDst, const BitmapBuffer& rSrc, const BitmapBuffer& rMsk )
633 {
634 TrueColorPixelPtr<SRCFMT> aSrcType; aSrcType.SetRawPtr( rSrc.mpBits );
635
636 // select the matching instantiation for the destination's bitmap format
637 switch (RemoveScanline(rDst.mnFormat))
638 {
639 case ScanlineFormat::N1BitMsbPal:
640 case ScanlineFormat::N1BitLsbPal:
641 case ScanlineFormat::N8BitPal:
642 break;
643
644 case ScanlineFormat::N32BitTcMask:
645 // return ImplBlendToBitmap<ScanlineFormat::N32BitTcMask>( aSrcType, rDst, rSrc, rMsk );
646 break;
647
648 case ScanlineFormat::N24BitTcBgr:
649 return ImplBlendToBitmap<ScanlineFormat::N24BitTcBgr>( aSrcType, rDst, rSrc, rMsk );
650 case ScanlineFormat::N24BitTcRgb:
651 return ImplBlendToBitmap<ScanlineFormat::N24BitTcRgb>( aSrcType, rDst, rSrc, rMsk );
652
653 case ScanlineFormat::N32BitTcAbgr:
654 return ImplBlendToBitmap<ScanlineFormat::N32BitTcAbgr>( aSrcType, rDst, rSrc, rMsk );
655 case ScanlineFormat::N32BitTcArgb:
656 return ImplBlendToBitmap<ScanlineFormat::N32BitTcArgb>( aSrcType, rDst, rSrc, rMsk );
657 case ScanlineFormat::N32BitTcBgra:
658 return ImplBlendToBitmap<ScanlineFormat::N32BitTcBgra>( aSrcType, rDst, rSrc, rMsk );
659 case ScanlineFormat::N32BitTcRgba:
660 return ImplBlendToBitmap<ScanlineFormat::N32BitTcRgba>( aSrcType, rDst, rSrc, rMsk );
661 default: break;
662 }
663
664 static int nNotAccelerated = 0;
665 SAL_WARN_IF( rSrc.mnWidth * rSrc.mnHeight >= 4000 && ++nNotAccelerated == 100,
666 "vcl.gdi",
667 "ImplBlendFromBitmap for not accelerated case (" << std::hex << static_cast<int>(rSrc.mnFormat) << "*" << static_cast<int>(rMsk.mnFormat) << "->" << static_cast<int>(rDst.mnFormat) );
668 return false;
669 }
670
ImplFastBitmapBlending(BitmapWriteAccess const & rDstWA,const BitmapReadAccess & rSrcRA,const BitmapReadAccess & rMskRA,const SalTwoRect & rTR)671 bool ImplFastBitmapBlending( BitmapWriteAccess const & rDstWA,
672 const BitmapReadAccess& rSrcRA, const BitmapReadAccess& rMskRA,
673 const SalTwoRect& rTR )
674 {
675 // accelerated blending of paletted bitmaps not implemented yet
676 if( rSrcRA.HasPalette() )
677 return false;
678 if( rDstWA.HasPalette() )
679 return false;
680 // TODO: either get rid of mask's use of 8BIT_PAL or check the palette
681
682 // horizontal mirroring not implemented yet
683 if( rTR.mnDestWidth < 0 )
684 return false;
685 // vertical mirroring
686 if( rTR.mnDestHeight < 0 )
687 // TODO: rDst.mnFormat ^= ScanlineFormat::TopDown;
688 return false;
689
690 // offsetted blending is not implemented yet
691 if( rTR.mnSrcX || rTR.mnSrcY )
692 return false;
693 if( rTR.mnDestX || rTR.mnDestY )
694 return false;
695
696 // stretched blending is not implemented yet
697 if( rTR.mnDestWidth != rTR.mnSrcWidth )
698 return false;
699 if( rTR.mnDestHeight!= rTR.mnSrcHeight )
700 return false;
701
702 // check source image size
703 if( rSrcRA.Width() < rTR.mnSrcX + rTR.mnSrcWidth )
704 return false;
705 if( rSrcRA.Height() < rTR.mnSrcY + rTR.mnSrcHeight )
706 return false;
707
708 // check mask image size
709 if( rMskRA.Width() < rTR.mnSrcX + rTR.mnSrcWidth )
710 return false;
711 if( rMskRA.Height() < rTR.mnSrcY + rTR.mnSrcHeight )
712 if( rMskRA.Height() != 1 )
713 return false;
714
715 // check dest image size
716 if( rDstWA.Width() < rTR.mnDestX + rTR.mnDestWidth )
717 return false;
718 if( rDstWA.Height() < rTR.mnDestY + rTR.mnDestHeight )
719 return false;
720
721 BitmapBuffer& rDst = *rDstWA.ImplGetBitmapBuffer();
722 const BitmapBuffer& rSrc = *rSrcRA.ImplGetBitmapBuffer();
723 const BitmapBuffer& rMsk = *rMskRA.ImplGetBitmapBuffer();
724
725 const ScanlineFormat nSrcFormat = RemoveScanline(rSrc.mnFormat);
726
727 // select the matching instantiation for the source's bitmap format
728 switch( nSrcFormat )
729 {
730 case ScanlineFormat::N1BitMsbPal:
731 case ScanlineFormat::N1BitLsbPal:
732 break;
733
734 case ScanlineFormat::N32BitTcMask:
735 // return ImplBlendFromBitmap<ScanlineFormat::N32BitTcMask>( rDst, rSrc );
736 break;
737
738 case ScanlineFormat::N8BitPal:
739 if(rSrc.maPalette.IsGreyPalette8Bit())
740 return ImplBlendFromBitmap<ScanlineFormat::N8BitPal>( rDst, rSrc, rMsk );
741 break;
742
743 case ScanlineFormat::N24BitTcBgr:
744 return ImplBlendFromBitmap<ScanlineFormat::N24BitTcBgr>( rDst, rSrc, rMsk );
745 case ScanlineFormat::N24BitTcRgb:
746 return ImplBlendFromBitmap<ScanlineFormat::N24BitTcRgb>( rDst, rSrc, rMsk );
747
748 case ScanlineFormat::N32BitTcAbgr:
749 return ImplBlendFromBitmap<ScanlineFormat::N32BitTcAbgr>( rDst, rSrc, rMsk );
750 case ScanlineFormat::N32BitTcArgb:
751 return ImplBlendFromBitmap<ScanlineFormat::N32BitTcArgb>( rDst, rSrc, rMsk );
752 case ScanlineFormat::N32BitTcBgra:
753 return ImplBlendFromBitmap<ScanlineFormat::N32BitTcBgra>( rDst, rSrc, rMsk );
754 case ScanlineFormat::N32BitTcRgba:
755 return ImplBlendFromBitmap<ScanlineFormat::N32BitTcRgba>( rDst, rSrc, rMsk );
756 default: break;
757 }
758
759 static int nNotAccelerated = 0;
760 SAL_WARN_IF( rSrc.mnWidth * rSrc.mnHeight >= 4000 && ++nNotAccelerated == 100,
761 "vcl.gdi",
762 "ImplFastBlend for not accelerated case (" << std::hex << static_cast<int>(rSrc.mnFormat) << "*" << static_cast<int>(rMsk.mnFormat) << "->" << static_cast<int>(rDst.mnFormat) << ")" );
763
764 return false;
765 }
766
ImplFastEraseBitmap(BitmapBuffer & rDst,const BitmapColor & rColor)767 bool ImplFastEraseBitmap( BitmapBuffer& rDst, const BitmapColor& rColor )
768 {
769 const ScanlineFormat nDstFormat = RemoveScanline(rDst.mnFormat);
770
771 // erasing a bitmap is often just a byte-wise memory fill
772 bool bByteFill = true;
773 sal_uInt8 nFillByte;
774
775 switch( nDstFormat )
776 {
777 case ScanlineFormat::N1BitMsbPal:
778 case ScanlineFormat::N1BitLsbPal:
779 nFillByte = rColor.GetIndex();
780 nFillByte = static_cast<sal_uInt8>( -(nFillByte & 1) ); // 0x00 or 0xFF
781 break;
782 case ScanlineFormat::N8BitPal:
783 nFillByte = rColor.GetIndex();
784 break;
785
786 case ScanlineFormat::N24BitTcBgr:
787 case ScanlineFormat::N24BitTcRgb:
788 nFillByte = rColor.GetRed();
789 if( (nFillByte != rColor.GetGreen())
790 || (nFillByte != rColor.GetBlue()) )
791 bByteFill = false;
792 break;
793
794 default:
795 bByteFill = false;
796 nFillByte = 0x00;
797 break;
798 }
799
800 if( bByteFill )
801 {
802 tools::Long nByteCount = rDst.mnHeight * rDst.mnScanlineSize;
803 memset( rDst.mpBits, nFillByte, nByteCount );
804 return true;
805 }
806
807 // TODO: handle other bitmap formats
808 switch( nDstFormat )
809 {
810 case ScanlineFormat::N32BitTcMask:
811
812 case ScanlineFormat::N24BitTcBgr:
813 case ScanlineFormat::N24BitTcRgb:
814
815 case ScanlineFormat::N32BitTcAbgr:
816 case ScanlineFormat::N32BitTcArgb:
817 case ScanlineFormat::N32BitTcBgra:
818 case ScanlineFormat::N32BitTcRgba:
819 break;
820
821 default:
822 break;
823 }
824
825 return false;
826 }
827
828 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
829