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 <glyphcache.hxx>
28 #include <string.h>
29
30 //------------------------------------------------------------------------
31
RawBitmap()32 RawBitmap::RawBitmap()
33 : mpBits(0), mnAllocated(0)
34 {}
35
36 //------------------------------------------------------------------------
37
~RawBitmap()38 RawBitmap::~RawBitmap()
39 {
40 delete[] mpBits;
41 mpBits = 0;
42 mnAllocated = 0;
43 }
44
45 //------------------------------------------------------------------------
46
47 // used by 90 and 270 degree rotations on 8 bit deep bitmaps
ImplRotate8_90(unsigned char * p1,const unsigned char * p2,int xmax,int ymax,int dx,int dy,int nPad)48 static void ImplRotate8_90( unsigned char* p1, const unsigned char* p2,
49 int xmax, int ymax, int dx, int dy, int nPad )
50 {
51 for( int y = ymax; --y >= 0; p2 += dy )
52 {
53 for( int x = xmax; --x >= 0; p2 += dx )
54 *(p1++) = *p2;
55 for( int i = nPad; --i >= 0; )
56 *(p1++) = 0;
57 }
58 }
59
60 //------------------------------------------------------------------------
61
62 // used by inplace 180 degree rotation on 8 bit deep bitmaps
ImplRotate8_180(unsigned char * p1,int xmax,int ymax,int nPad)63 static void ImplRotate8_180( unsigned char* p1, int xmax, int ymax, int nPad )
64 {
65 unsigned char* p2 = p1 + ymax * (xmax + nPad);
66 for( int y = ymax/2; --y >= 0; )
67 {
68 p2 -= nPad;
69 for( int x = xmax; --x >= 0; )
70 {
71 unsigned char cTmp = *(--p2);
72 *p2 = *p1;
73 *(p1++) = cTmp;
74 }
75 p1 += nPad;
76 }
77
78 // reverse middle line
79 p2 -= nPad;
80 while( p1 < p2 )
81 {
82 unsigned char cTmp = *(--p2);
83 *p2 = *p1;
84 *(p1++) = cTmp;
85 }
86 }
87
88 //------------------------------------------------------------------------
89
90 // used by 90 or 270 degree rotations on 1 bit deep bitmaps
ImplRotate1_90(unsigned char * p1,const unsigned char * p2,int xmax,int ymax,int dx,int nShift,int nDeltaShift,int nPad)91 static void ImplRotate1_90( unsigned char* p1, const unsigned char* p2,
92 int xmax, int ymax, int dx, int nShift, int nDeltaShift, int nPad )
93 {
94 for( int y = ymax; --y >= 0; )
95 {
96 unsigned nTemp = 1;
97 const unsigned char* p20 = p2;
98 for( int x = xmax; --x >= 0; p2 += dx )
99 {
100 // build bitwise and store when byte finished
101 nTemp += nTemp + ((*p2 >> nShift) & 1);
102 if( nTemp >= 0x100U )
103 {
104 *(p1++) = (unsigned char)nTemp;
105 nTemp = 1;
106 }
107 }
108 p2 = p20;
109
110 // store left aligned remainder if needed
111 if( nTemp > 1 )
112 {
113 for(; nTemp < 0x100U; nTemp += nTemp ) ;
114 *(p1++) = (unsigned char)nTemp;
115 }
116 // pad scanline with zeroes
117 for( int i = nPad; --i >= 0;)
118 *(p1++) = 0;
119
120 // increase/decrease shift, but keep bound inside 0 to 7
121 nShift += nDeltaShift;
122 if( nShift != (nShift & 7) )
123 p2 -= nDeltaShift;
124 nShift &= 7;
125 }
126 }
127
128 //------------------------------------------------------------------------
129
130 // used by 180 degrees rotations on 1 bit deep bitmaps
ImplRotate1_180(unsigned char * p1,const unsigned char * p2,int xmax,int ymax,int nPad)131 static void ImplRotate1_180( unsigned char* p1, const unsigned char* p2,
132 int xmax, int ymax, int nPad )
133 {
134 --p2;
135 for( int y = ymax; --y >= 0; )
136 {
137 p2 -= nPad;
138
139 unsigned nTemp = 1;
140 unsigned nInp = (0x100 + *p2) >> (-xmax & 7);
141 for( int x = xmax; --x >= 0; )
142 {
143 // build bitwise and store when byte finished
144 nTemp += nTemp + (nInp & 1);
145 if( nTemp >= 0x100 )
146 {
147 *(p1++) = (unsigned char)nTemp;
148 nTemp = 1;
149 }
150 // update input byte if needed (and available)
151 if( (nInp >>= 1) <= 1 && ((y != 0) || (x != 0)) )
152 nInp = 0x100 + *(--p2);
153 }
154
155 // store left aligned remainder if needed
156 if( nTemp > 1 )
157 {
158 for(; nTemp < 0x100; nTemp += nTemp ) ;
159 *(p1++) = (unsigned char)nTemp;
160 }
161 // scanline pad is already clean
162 p1 += nPad;
163 }
164 }
165
166 //------------------------------------------------------------------------
167
Rotate(int nAngle)168 bool RawBitmap::Rotate( int nAngle )
169 {
170 sal_uLong nNewScanlineSize = 0;
171 sal_uLong nNewHeight = 0;
172 sal_uLong nNewWidth = 0;
173
174 // do inplace rotation or prepare double buffered rotation
175 switch( nAngle )
176 {
177 case 0: // nothing to do
178 case 3600:
179 return true;
180 default: // non rectangular angles not allowed
181 return false;
182 case 1800: // rotate by 180 degrees
183 mnXOffset = -(mnXOffset + mnWidth);
184 mnYOffset = -(mnYOffset + mnHeight);
185 if( mnBitCount == 8 )
186 {
187 ImplRotate8_180( mpBits, mnWidth, mnHeight, mnScanlineSize-mnWidth );
188 return true;
189 }
190 nNewWidth = mnWidth;
191 nNewHeight = mnHeight;
192 nNewScanlineSize = mnScanlineSize;
193 break;
194 case +900: // left by 90 degrees
195 case -900:
196 case 2700: // right by 90 degrees
197 nNewWidth = mnHeight;
198 nNewHeight = mnWidth;
199 if( mnBitCount==1 )
200 nNewScanlineSize = (nNewWidth + 7) / 8;
201 else
202 nNewScanlineSize = (nNewWidth + 3) & -4;
203 break;
204 }
205
206 unsigned int nBufSize = nNewHeight * nNewScanlineSize;
207 unsigned char* pBuf = new unsigned char[ nBufSize ];
208 if( !pBuf )
209 return false;
210
211 memset( pBuf, 0, nBufSize );
212 int i;
213
214 // dispatch non-inplace rotations
215 switch( nAngle )
216 {
217 case 1800: // rotate by 180 degrees
218 // we know we only need to deal with 1 bit depth
219 ImplRotate1_180( pBuf, mpBits + mnHeight * mnScanlineSize,
220 mnWidth, mnHeight, mnScanlineSize - (mnWidth + 7) / 8 );
221 break;
222 case +900: // rotate left by 90 degrees
223 i = mnXOffset;
224 mnXOffset = mnYOffset;
225 mnYOffset = -nNewHeight - i;
226 if( mnBitCount == 8 )
227 ImplRotate8_90( pBuf, mpBits + mnWidth - 1,
228 nNewWidth, nNewHeight, +mnScanlineSize, -1-mnHeight*mnScanlineSize,
229 nNewScanlineSize - nNewWidth );
230 else
231 ImplRotate1_90( pBuf, mpBits + (mnWidth - 1) / 8,
232 nNewWidth, nNewHeight, +mnScanlineSize,
233 (-mnWidth & 7), +1, nNewScanlineSize - (nNewWidth + 7) / 8 );
234 break;
235 case 2700: // rotate right by 90 degrees
236 case -900:
237 i = mnXOffset;
238 mnXOffset = -(nNewWidth + mnYOffset);
239 mnYOffset = i;
240 if( mnBitCount == 8 )
241 ImplRotate8_90( pBuf, mpBits + mnScanlineSize * (mnHeight-1),
242 nNewWidth, nNewHeight, -mnScanlineSize, +1+mnHeight*mnScanlineSize,
243 nNewScanlineSize - nNewWidth );
244 else
245 ImplRotate1_90( pBuf, mpBits + mnScanlineSize * (mnHeight-1),
246 nNewWidth, nNewHeight, -mnScanlineSize,
247 +7, -1, nNewScanlineSize - (nNewWidth + 7) / 8 );
248 break;
249 }
250
251 mnWidth = nNewWidth;
252 mnHeight = nNewHeight;
253 mnScanlineSize = nNewScanlineSize;
254
255 if( nBufSize < mnAllocated )
256 {
257 memcpy( mpBits, pBuf, nBufSize );
258 delete[] pBuf;
259 }
260 else
261 {
262 delete[] mpBits;
263 mpBits = pBuf;
264 mnAllocated = nBufSize;
265 }
266
267 return true;
268 }
269
270 //------------------------------------------------------------------------
271