blob: 30c90c93cb8ae3f9203f541317ac933a6e1d9ae0 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_vcl.hxx"
#include <glyphcache.hxx>
#include <string.h>
//------------------------------------------------------------------------
RawBitmap::RawBitmap()
: mpBits(0), mnAllocated(0)
{}
//------------------------------------------------------------------------
RawBitmap::~RawBitmap()
{
delete[] mpBits;
mpBits = 0;
mnAllocated = 0;
}
//------------------------------------------------------------------------
// used by 90 and 270 degree rotations on 8 bit deep bitmaps
static void ImplRotate8_90( unsigned char* p1, const unsigned char* p2,
int xmax, int ymax, int dx, int dy, int nPad )
{
for( int y = ymax; --y >= 0; p2 += dy )
{
for( int x = xmax; --x >= 0; p2 += dx )
*(p1++) = *p2;
for( int i = nPad; --i >= 0; )
*(p1++) = 0;
}
}
//------------------------------------------------------------------------
// used by inplace 180 degree rotation on 8 bit deep bitmaps
static void ImplRotate8_180( unsigned char* p1, int xmax, int ymax, int nPad )
{
unsigned char* p2 = p1 + ymax * (xmax + nPad);
for( int y = ymax/2; --y >= 0; )
{
p2 -= nPad;
for( int x = xmax; --x >= 0; )
{
unsigned char cTmp = *(--p2);
*p2 = *p1;
*(p1++) = cTmp;
}
p1 += nPad;
}
// reverse middle line
p2 -= nPad;
while( p1 < p2 )
{
unsigned char cTmp = *(--p2);
*p2 = *p1;
*(p1++) = cTmp;
}
}
//------------------------------------------------------------------------
// used by 90 or 270 degree rotations on 1 bit deep bitmaps
static void ImplRotate1_90( unsigned char* p1, const unsigned char* p2,
int xmax, int ymax, int dx, int nShift, int nDeltaShift, int nPad )
{
for( int y = ymax; --y >= 0; )
{
unsigned nTemp = 1;
const unsigned char* p20 = p2;
for( int x = xmax; --x >= 0; p2 += dx )
{
// build bitwise and store when byte finished
nTemp += nTemp + ((*p2 >> nShift) & 1);
if( nTemp >= 0x100U )
{
*(p1++) = (unsigned char)nTemp;
nTemp = 1;
}
}
p2 = p20;
// store left aligned remainder if needed
if( nTemp > 1 )
{
for(; nTemp < 0x100U; nTemp += nTemp ) ;
*(p1++) = (unsigned char)nTemp;
}
// pad scanline with zeroes
for( int i = nPad; --i >= 0;)
*(p1++) = 0;
// increase/decrease shift, but keep bound inside 0 to 7
nShift += nDeltaShift;
if( nShift != (nShift & 7) )
p2 -= nDeltaShift;
nShift &= 7;
}
}
//------------------------------------------------------------------------
// used by 180 degrees rotations on 1 bit deep bitmaps
static void ImplRotate1_180( unsigned char* p1, const unsigned char* p2,
int xmax, int ymax, int nPad )
{
--p2;
for( int y = ymax; --y >= 0; )
{
p2 -= nPad;
unsigned nTemp = 1;
unsigned nInp = (0x100 + *p2) >> (-xmax & 7);
for( int x = xmax; --x >= 0; )
{
// build bitwise and store when byte finished
nTemp += nTemp + (nInp & 1);
if( nTemp >= 0x100 )
{
*(p1++) = (unsigned char)nTemp;
nTemp = 1;
}
// update input byte if needed (and available)
if( (nInp >>= 1) <= 1 && ((y != 0) || (x != 0)) )
nInp = 0x100 + *(--p2);
}
// store left aligned remainder if needed
if( nTemp > 1 )
{
for(; nTemp < 0x100; nTemp += nTemp ) ;
*(p1++) = (unsigned char)nTemp;
}
// scanline pad is already clean
p1 += nPad;
}
}
//------------------------------------------------------------------------
bool RawBitmap::Rotate( int nAngle )
{
sal_uLong nNewScanlineSize = 0;
sal_uLong nNewHeight = 0;
sal_uLong nNewWidth = 0;
// do inplace rotation or prepare double buffered rotation
switch( nAngle )
{
case 0: // nothing to do
case 3600:
return true;
default: // non rectangular angles not allowed
return false;
case 1800: // rotate by 180 degrees
mnXOffset = -(mnXOffset + mnWidth);
mnYOffset = -(mnYOffset + mnHeight);
if( mnBitCount == 8 )
{
ImplRotate8_180( mpBits, mnWidth, mnHeight, mnScanlineSize-mnWidth );
return true;
}
nNewWidth = mnWidth;
nNewHeight = mnHeight;
nNewScanlineSize = mnScanlineSize;
break;
case +900: // left by 90 degrees
case -900:
case 2700: // right by 90 degrees
nNewWidth = mnHeight;
nNewHeight = mnWidth;
if( mnBitCount==1 )
nNewScanlineSize = (nNewWidth + 7) / 8;
else
nNewScanlineSize = (nNewWidth + 3) & -4;
break;
}
unsigned int nBufSize = nNewHeight * nNewScanlineSize;
unsigned char* pBuf = new unsigned char[ nBufSize ];
if( !pBuf )
return false;
memset( pBuf, 0, nBufSize );
int i;
// dispatch non-inplace rotations
switch( nAngle )
{
case 1800: // rotate by 180 degrees
// we know we only need to deal with 1 bit depth
ImplRotate1_180( pBuf, mpBits + mnHeight * mnScanlineSize,
mnWidth, mnHeight, mnScanlineSize - (mnWidth + 7) / 8 );
break;
case +900: // rotate left by 90 degrees
i = mnXOffset;
mnXOffset = mnYOffset;
mnYOffset = -nNewHeight - i;
if( mnBitCount == 8 )
ImplRotate8_90( pBuf, mpBits + mnWidth - 1,
nNewWidth, nNewHeight, +mnScanlineSize, -1-mnHeight*mnScanlineSize,
nNewScanlineSize - nNewWidth );
else
ImplRotate1_90( pBuf, mpBits + (mnWidth - 1) / 8,
nNewWidth, nNewHeight, +mnScanlineSize,
(-mnWidth & 7), +1, nNewScanlineSize - (nNewWidth + 7) / 8 );
break;
case 2700: // rotate right by 90 degrees
case -900:
i = mnXOffset;
mnXOffset = -(nNewWidth + mnYOffset);
mnYOffset = i;
if( mnBitCount == 8 )
ImplRotate8_90( pBuf, mpBits + mnScanlineSize * (mnHeight-1),
nNewWidth, nNewHeight, -mnScanlineSize, +1+mnHeight*mnScanlineSize,
nNewScanlineSize - nNewWidth );
else
ImplRotate1_90( pBuf, mpBits + mnScanlineSize * (mnHeight-1),
nNewWidth, nNewHeight, -mnScanlineSize,
+7, -1, nNewScanlineSize - (nNewWidth + 7) / 8 );
break;
}
mnWidth = nNewWidth;
mnHeight = nNewHeight;
mnScanlineSize = nNewScanlineSize;
if( nBufSize < mnAllocated )
{
memcpy( mpBits, pBuf, nBufSize );
delete[] pBuf;
}
else
{
delete[] mpBits;
mpBits = pBuf;
mnAllocated = nBufSize;
}
return true;
}
//------------------------------------------------------------------------