xref: /AOO41X/main/vcl/source/gdi/bmpacc.cxx (revision 54628ca40d27d15cc98fe861da7fff7e60c2f7d6)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_vcl.hxx"
26 
27 #include <vcl/salbtype.hxx>
28 #include <vcl/bitmap.hxx>
29 #include <vcl/bmpacc.hxx>
30 
31 #include <impbmp.hxx>
32 
33 #include <string.h>
34 
35 // --------------------
36 // - BitmapReadAccess -
37 // --------------------
38 
39 BitmapReadAccess::BitmapReadAccess( Bitmap& rBitmap, sal_Bool bModify ) :
40             mpBuffer        ( NULL ),
41             mpScanBuf       ( NULL ),
42             mFncGetPixel    ( NULL ),
43             mFncSetPixel    ( NULL ),
44             mbModify        ( bModify )
45 {
46     ImplCreate( rBitmap );
47 }
48 
49 // ------------------------------------------------------------------
50 
51 BitmapReadAccess::BitmapReadAccess( Bitmap& rBitmap ) :
52             mpBuffer        ( NULL ),
53             mpScanBuf       ( NULL ),
54             mFncGetPixel    ( NULL ),
55             mFncSetPixel    ( NULL ),
56             mbModify        ( sal_False )
57 {
58     ImplCreate( rBitmap );
59 }
60 
61 // ------------------------------------------------------------------
62 
63 BitmapReadAccess::~BitmapReadAccess()
64 {
65     ImplDestroy();
66 }
67 
68 // ------------------------------------------------------------------
69 
70 void BitmapReadAccess::ImplCreate( Bitmap& rBitmap )
71 {
72     ImpBitmap* pImpBmp = rBitmap.ImplGetImpBitmap();
73 
74     DBG_ASSERT( pImpBmp, "Forbidden Access to empty bitmap!" );
75 
76     if( pImpBmp )
77     {
78         if( mbModify && !maBitmap.ImplGetImpBitmap() )
79         {
80             rBitmap.ImplMakeUnique();
81             pImpBmp = rBitmap.ImplGetImpBitmap();
82         }
83         else
84         {
85             DBG_ASSERT( !mbModify || pImpBmp->ImplGetRefCount() == 2,
86                         "Unpredictable results: bitmap is referenced more than once!" );
87         }
88 
89         mpBuffer = pImpBmp->ImplAcquireBuffer( !mbModify );
90 
91         if( !mpBuffer )
92         {
93             ImpBitmap* pNewImpBmp = new ImpBitmap;
94 
95             if( pNewImpBmp->ImplCreate( *pImpBmp, rBitmap.GetBitCount()  ) )
96             {
97                 pImpBmp = pNewImpBmp;
98                 rBitmap.ImplSetImpBitmap( pImpBmp );
99                 mpBuffer = pImpBmp->ImplAcquireBuffer( !mbModify );
100             }
101             else
102                 delete pNewImpBmp;
103         }
104 
105         if( mpBuffer )
106         {
107             const long  nHeight = mpBuffer->mnHeight;
108             Scanline    pTmpLine = mpBuffer->mpBits;
109 
110             mpScanBuf = new Scanline[ nHeight ];
111             maColorMask = mpBuffer->maColorMask;
112 
113             if( BMP_SCANLINE_ADJUSTMENT( mpBuffer->mnFormat ) == BMP_FORMAT_TOP_DOWN )
114             {
115                 for( long nY = 0L; nY < nHeight; nY++, pTmpLine += mpBuffer->mnScanlineSize )
116                     mpScanBuf[ nY ] = pTmpLine;
117             }
118             else
119             {
120                 for( long nY = nHeight - 1; nY >= 0; nY--, pTmpLine += mpBuffer->mnScanlineSize )
121                     mpScanBuf[ nY ] = pTmpLine;
122             }
123 
124             if( !ImplSetAccessPointers( BMP_SCANLINE_FORMAT( mpBuffer->mnFormat ) ) )
125             {
126                 delete[] mpScanBuf;
127                 mpScanBuf = NULL;
128 
129                 pImpBmp->ImplReleaseBuffer( mpBuffer, !mbModify );
130                 mpBuffer = NULL;
131             }
132             else
133                 maBitmap = rBitmap;
134         }
135     }
136 }
137 
138 // ------------------------------------------------------------------
139 
140 void BitmapReadAccess::ImplDestroy()
141 {
142     ImpBitmap* pImpBmp = maBitmap.ImplGetImpBitmap();
143 
144     delete[] mpScanBuf;
145     mpScanBuf = NULL;
146 
147     if( mpBuffer && pImpBmp )
148     {
149         pImpBmp->ImplReleaseBuffer( mpBuffer, !mbModify );
150         mpBuffer = NULL;
151     }
152 }
153 
154 // ------------------------------------------------------------------
155 
156 sal_Bool BitmapReadAccess::ImplSetAccessPointers( sal_uLong nFormat )
157 {
158     sal_Bool bRet = sal_True;
159 
160     switch( nFormat )
161     {
162         CASE_FORMAT( _1BIT_MSB_PAL )
163         CASE_FORMAT( _1BIT_LSB_PAL )
164         CASE_FORMAT( _4BIT_MSN_PAL )
165         CASE_FORMAT( _4BIT_LSN_PAL )
166         CASE_FORMAT( _8BIT_PAL )
167         CASE_FORMAT( _8BIT_TC_MASK )
168         CASE_FORMAT( _16BIT_TC_MSB_MASK )
169         CASE_FORMAT( _16BIT_TC_LSB_MASK )
170         CASE_FORMAT( _24BIT_TC_BGR )
171         CASE_FORMAT( _24BIT_TC_RGB )
172         CASE_FORMAT( _24BIT_TC_MASK )
173         CASE_FORMAT( _32BIT_TC_ABGR )
174         CASE_FORMAT( _32BIT_TC_ARGB )
175         CASE_FORMAT( _32BIT_TC_BGRA )
176         CASE_FORMAT( _32BIT_TC_RGBA )
177         CASE_FORMAT( _32BIT_TC_MASK )
178 
179         default:
180             bRet = sal_False;
181         break;
182     }
183 
184     return bRet;
185 }
186 
187 // ------------------------------------------------------------------
188 
189 void BitmapReadAccess::ImplZeroInitUnusedBits()
190 {
191     const sal_uInt32 nWidth = Width(), nHeight = Height(), nScanSize = GetScanlineSize();
192 
193     if( nWidth && nHeight && nScanSize && GetBuffer() )
194     {
195         sal_uInt32 nBits;
196         bool       bMsb;
197 
198         const sal_uLong nScanlineFormat = GetScanlineFormat();
199         switch( nScanlineFormat )
200         {
201             case( BMP_FORMAT_1BIT_MSB_PAL ):
202                 nBits = 1;
203                 bMsb = true;
204                 break;
205 
206             case( BMP_FORMAT_1BIT_LSB_PAL ):
207                 nBits = 1;
208                 bMsb = false;
209                 break;
210 
211             case( BMP_FORMAT_4BIT_MSN_PAL ):
212                 nBits = 4;
213                 bMsb = true;
214                 break;
215 
216             case( BMP_FORMAT_4BIT_LSN_PAL ):
217                 nBits = 4;
218                 bMsb = false;
219                 break;
220 
221             case( BMP_FORMAT_8BIT_PAL ):
222             case( BMP_FORMAT_8BIT_TC_MASK ):
223                 bMsb = true;
224                 nBits = 8;
225             break;
226 
227             case( BMP_FORMAT_16BIT_TC_MSB_MASK ):
228             case( BMP_FORMAT_16BIT_TC_LSB_MASK ):
229                 bMsb = true;
230                 nBits = 16;
231             break;
232 
233             case( BMP_FORMAT_24BIT_TC_BGR ):
234             case( BMP_FORMAT_24BIT_TC_RGB ):
235             case( BMP_FORMAT_24BIT_TC_MASK ):
236                 bMsb = true;
237                 nBits = 24;
238             break;
239 
240             case( BMP_FORMAT_32BIT_TC_ABGR ):
241             case( BMP_FORMAT_32BIT_TC_ARGB ):
242             case( BMP_FORMAT_32BIT_TC_BGRA ):
243             case( BMP_FORMAT_32BIT_TC_RGBA ):
244             case( BMP_FORMAT_32BIT_TC_MASK ):
245                 bMsb = true;
246                 nBits = 32;
247             break;
248 
249             default:
250             {
251                 DBG_ERROR( "BitmapWriteAccess::ZeroInitUnusedBits: Unsupported pixel format");
252                 nBits = 0;
253                 bMsb = true;
254             }
255             break;
256         }
257 
258         nBits *= nWidth;
259         if( nScanSize % 4 || !bMsb )
260         {
261             DBG_ASSERT( 8*nScanSize >= nBits,
262                         "BitmapWriteAccess::ZeroInitUnusedBits: span size smaller than width?!");
263             const sal_uInt32 nLeftOverBits = 8*sizeof(sal_uInt8)*nScanSize - nBits;
264             if( nLeftOverBits != 0 ) // else there is really nothing to do
265             {
266                 const sal_uInt32 nBytes = (nLeftOverBits + 7U) >> 3U;
267                 sal_uInt8        nMask;
268 
269                 if( bMsb )
270                     nMask = static_cast<sal_uInt8>(0xffU << (nLeftOverBits & 3UL));
271                 else
272                     nMask = static_cast<sal_uInt8>(0xffU >> (nLeftOverBits & 3UL));
273 
274                 sal_uInt8* pLastBytes = (sal_uInt8*)GetBuffer() + ( nScanSize - nBytes );
275                 for( sal_uInt32 i = 0; i < nHeight; i++, pLastBytes += nScanSize )
276                 {
277                     *pLastBytes &= nMask;
278                     for( sal_uInt32 j = 1; j < nBytes; j++ )
279                         pLastBytes[j] = 0;
280                 }
281             }
282         }
283         else if( nBits & 0x1f )
284         {
285             sal_uInt32  nMask = 0xffffffff << ( ( nScanSize << 3 ) - nBits );
286             sal_uInt8*      pLast4Bytes = (sal_uInt8*) GetBuffer() + ( nScanSize - 4 );
287 
288 #ifdef OSL_LITENDIAN
289             nMask = SWAPLONG( nMask );
290 #endif
291             for( sal_uInt32 i = 0; i < nHeight; i++, pLast4Bytes += nScanSize )
292                 ( *(sal_uInt32*) pLast4Bytes ) &= nMask;
293         }
294     }
295 }
296 
297 // ------------------------------------------------------------------
298 
299 void BitmapReadAccess::Flush()
300 {
301     ImplDestroy();
302 }
303 
304 // ------------------------------------------------------------------
305 
306 void BitmapReadAccess::ReAccess( sal_Bool bModify )
307 {
308     const ImpBitmap* pImpBmp = maBitmap.ImplGetImpBitmap();
309 
310     DBG_ASSERT( !mpBuffer, "No ReAccess possible while bitmap is being accessed!" );
311     DBG_ASSERT( pImpBmp && ( pImpBmp->ImplGetRefCount() > 1UL ), "Accessed bitmap does not exist anymore!" );
312 
313     if( !mpBuffer && pImpBmp && ( pImpBmp->ImplGetRefCount() > 1UL ) )
314     {
315         mbModify = bModify;
316         ImplCreate( maBitmap );
317     }
318 }
319 
320 // ------------------------------------------------------------------
321 
322 sal_uInt16 BitmapReadAccess::GetBestPaletteIndex( const BitmapColor& rBitmapColor ) const
323 {
324     return( HasPalette() ? mpBuffer->maPalette.GetBestIndex( rBitmapColor ) : 0 );
325 }
326 
327 // ---------------------
328 // - BitmapWriteAccess -
329 // ---------------------
330 
331 BitmapWriteAccess::BitmapWriteAccess( Bitmap& rBitmap ) :
332             BitmapReadAccess( rBitmap, sal_True ),
333             mpLineColor     ( NULL ),
334             mpFillColor     ( NULL )
335 {
336 }
337 
338 // ------------------------------------------------------------------
339 
340 BitmapWriteAccess::~BitmapWriteAccess()
341 {
342     delete mpLineColor;
343     delete mpFillColor;
344 }
345 
346 // ------------------------------------------------------------------
347 
348 void BitmapWriteAccess::CopyScanline( long nY, const BitmapReadAccess& rReadAcc )
349 {
350     DBG_ASSERT( ( nY >= 0 ) && ( nY < mpBuffer->mnHeight ), "y-coordinate in destination out of range!" );
351     DBG_ASSERT( nY < rReadAcc.Height(), "y-coordinate in source out of range!" );
352     DBG_ASSERT( ( HasPalette() && rReadAcc.HasPalette() ) || ( !HasPalette() && !rReadAcc.HasPalette() ), "No copying possible between palette bitmap and TC bitmap!" );
353 
354     if( ( GetScanlineFormat() == rReadAcc.GetScanlineFormat() ) &&
355         ( GetScanlineSize() >= rReadAcc.GetScanlineSize() ) )
356     {
357         memcpy( mpScanBuf[ nY ], rReadAcc.GetScanline( nY ), rReadAcc.GetScanlineSize() );
358     }
359     else
360         // TODO: use fastbmp infrastructure
361         for( long nX = 0L, nWidth = Min( mpBuffer->mnWidth, rReadAcc.Width() ); nX < nWidth; nX++ )
362             SetPixel( nY, nX, rReadAcc.GetPixel( nY, nX ) );
363 }
364 
365 // ------------------------------------------------------------------
366 
367 void BitmapWriteAccess::CopyScanline( long nY, ConstScanline aSrcScanline,
368                                       sal_uLong nSrcScanlineFormat, sal_uLong nSrcScanlineSize )
369 {
370     const sal_uLong nFormat = BMP_SCANLINE_FORMAT( nSrcScanlineFormat );
371 
372     DBG_ASSERT( ( nY >= 0 ) && ( nY < mpBuffer->mnHeight ), "y-coordinate in destination out of range!" );
373     DBG_ASSERT( ( HasPalette() && nFormat <= BMP_FORMAT_8BIT_PAL ) ||
374                 ( !HasPalette() && nFormat > BMP_FORMAT_8BIT_PAL ),
375                 "No copying possible between palette and non palette scanlines!" );
376 
377     const sal_uLong nCount = Min( GetScanlineSize(), nSrcScanlineSize );
378 
379     if( nCount )
380     {
381         if( GetScanlineFormat() == BMP_SCANLINE_FORMAT( nSrcScanlineFormat ) )
382             memcpy( mpScanBuf[ nY ], aSrcScanline, nCount );
383         else
384         {
385             DBG_ASSERT( nFormat != BMP_FORMAT_8BIT_TC_MASK &&
386                         nFormat != BMP_FORMAT_16BIT_TC_MSB_MASK && nFormat != BMP_FORMAT_16BIT_TC_LSB_MASK &&
387                         nFormat != BMP_FORMAT_24BIT_TC_MASK && nFormat != BMP_FORMAT_32BIT_TC_MASK,
388                         "No support for pixel formats with color masks yet!" );
389 
390             // TODO: use fastbmp infrastructure
391             FncGetPixel pFncGetPixel;
392 
393             switch( nFormat )
394             {
395                 case( BMP_FORMAT_1BIT_MSB_PAL ):    pFncGetPixel = GetPixelFor_1BIT_MSB_PAL; break;
396                 case( BMP_FORMAT_1BIT_LSB_PAL ):    pFncGetPixel = GetPixelFor_1BIT_LSB_PAL; break;
397                 case( BMP_FORMAT_4BIT_MSN_PAL ):    pFncGetPixel = GetPixelFor_4BIT_MSN_PAL; break;
398                 case( BMP_FORMAT_4BIT_LSN_PAL ):    pFncGetPixel = GetPixelFor_4BIT_LSN_PAL; break;
399                 case( BMP_FORMAT_8BIT_PAL ):        pFncGetPixel = GetPixelFor_8BIT_PAL; break;
400                 case( BMP_FORMAT_8BIT_TC_MASK ):    pFncGetPixel = GetPixelFor_8BIT_TC_MASK; break;
401                 case( BMP_FORMAT_16BIT_TC_MSB_MASK ):   pFncGetPixel = GetPixelFor_16BIT_TC_MSB_MASK; break;
402                 case( BMP_FORMAT_16BIT_TC_LSB_MASK ):   pFncGetPixel = GetPixelFor_16BIT_TC_LSB_MASK; break;
403                 case( BMP_FORMAT_24BIT_TC_BGR ):    pFncGetPixel = GetPixelFor_24BIT_TC_BGR; break;
404                 case( BMP_FORMAT_24BIT_TC_RGB ):    pFncGetPixel = GetPixelFor_24BIT_TC_RGB; break;
405                 case( BMP_FORMAT_24BIT_TC_MASK ):   pFncGetPixel = GetPixelFor_24BIT_TC_MASK; break;
406                 case( BMP_FORMAT_32BIT_TC_ABGR ):   pFncGetPixel = GetPixelFor_32BIT_TC_ABGR; break;
407                 case( BMP_FORMAT_32BIT_TC_ARGB ):   pFncGetPixel = GetPixelFor_32BIT_TC_ARGB; break;
408                 case( BMP_FORMAT_32BIT_TC_BGRA ):   pFncGetPixel = GetPixelFor_32BIT_TC_BGRA; break;
409                 case( BMP_FORMAT_32BIT_TC_RGBA ):   pFncGetPixel = GetPixelFor_32BIT_TC_RGBA; break;
410                 case( BMP_FORMAT_32BIT_TC_MASK ):   pFncGetPixel = GetPixelFor_32BIT_TC_MASK; break;
411 
412                 default:
413                     pFncGetPixel = NULL;
414                 break;
415             }
416 
417             if( pFncGetPixel )
418             {
419                 const ColorMask aDummyMask;
420 
421                 for( long nX = 0L, nWidth = mpBuffer->mnWidth; nX < nWidth; nX++ )
422                     SetPixel( nY, nX, pFncGetPixel( aSrcScanline, nX, aDummyMask ) );
423             }
424         }
425     }
426 }
427 
428 
429 // ------------------------------------------------------------------
430 
431 void BitmapWriteAccess::CopyBuffer( const BitmapReadAccess& rReadAcc )
432 {
433     DBG_ASSERT( ( HasPalette() && rReadAcc.HasPalette() ) || ( !HasPalette() && !rReadAcc.HasPalette() ), "No copying possible between palette bitmap and TC bitmap!" );
434 
435     if( ( GetScanlineFormat() == rReadAcc.GetScanlineFormat() ) &&
436         ( GetScanlineSize() == rReadAcc.GetScanlineSize() ) )
437     {
438         const long  nHeight = Min( mpBuffer->mnHeight, rReadAcc.Height() );
439         const sal_uLong nCount = nHeight * mpBuffer->mnScanlineSize;
440 
441         memcpy( mpBuffer->mpBits, rReadAcc.GetBuffer(), nCount );
442     }
443     else
444         for( long nY = 0L, nHeight = Min( mpBuffer->mnHeight, rReadAcc.Height() ); nY < nHeight; nY++ )
445             CopyScanline( nY, rReadAcc );
446 }
447