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