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