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