Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 :
21 : #include "generic/glyphcache.hxx"
22 : #include <string.h>
23 :
24 :
25 905373 : RawBitmap::RawBitmap()
26 905373 : : mpBits(0), mnAllocated(0)
27 905373 : {}
28 :
29 :
30 3 : RawBitmap::~RawBitmap()
31 : {
32 3 : delete[] mpBits;
33 3 : mpBits = 0;
34 3 : mnAllocated = 0;
35 3 : }
36 :
37 :
38 : // used by 90 and 270 degree rotations on 8 bit deep bitmaps
39 10618 : static void ImplRotate8_90( unsigned char* p1, const unsigned char* p2,
40 : int xmax, int ymax, int dx, int dy, int nPad )
41 : {
42 145021 : for( int y = ymax; --y >= 0; p2 += dy )
43 : {
44 4437769 : for( int x = xmax; --x >= 0; p2 += dx )
45 4303366 : *(p1++) = *p2;
46 401568 : for( int i = nPad; --i >= 0; )
47 132762 : *(p1++) = 0;
48 : }
49 10618 : }
50 :
51 :
52 : // used by inplace 180 degree rotation on 8 bit deep bitmaps
53 0 : static void ImplRotate8_180( unsigned char* p1, int xmax, int ymax, int nPad )
54 : {
55 0 : unsigned char* p2 = p1 + ymax * (xmax + nPad);
56 0 : for( int y = ymax/2; --y >= 0; )
57 : {
58 0 : p2 -= nPad;
59 0 : for( int x = xmax; --x >= 0; )
60 : {
61 0 : unsigned char cTmp = *(--p2);
62 0 : *p2 = *p1;
63 0 : *(p1++) = cTmp;
64 : }
65 0 : p1 += nPad;
66 : }
67 :
68 : // reverse middle line
69 0 : p2 -= nPad;
70 0 : while( p1 < p2 )
71 : {
72 0 : unsigned char cTmp = *(--p2);
73 0 : *p2 = *p1;
74 0 : *(p1++) = cTmp;
75 : }
76 0 : }
77 :
78 :
79 : // used by 90 or 270 degree rotations on 1 bit deep bitmaps
80 0 : static void ImplRotate1_90( unsigned char* p1, const unsigned char* p2,
81 : int xmax, int ymax, int dx, int nShift, int nDeltaShift, int nPad )
82 : {
83 0 : for( int y = ymax; --y >= 0; )
84 : {
85 0 : unsigned nTemp = 1;
86 0 : const unsigned char* p20 = p2;
87 0 : for( int x = xmax; --x >= 0; p2 += dx )
88 : {
89 : // build bitwise and store when byte finished
90 0 : nTemp += nTemp + ((*p2 >> nShift) & 1);
91 0 : if( nTemp >= 0x100U )
92 : {
93 0 : *(p1++) = (unsigned char)nTemp;
94 0 : nTemp = 1;
95 : }
96 : }
97 0 : p2 = p20;
98 :
99 : // store left aligned remainder if needed
100 0 : if( nTemp > 1 )
101 : {
102 0 : for(; nTemp < 0x100U; nTemp += nTemp ) ;
103 0 : *(p1++) = (unsigned char)nTemp;
104 : }
105 : // pad scanline with zeroes
106 0 : for( int i = nPad; --i >= 0;)
107 0 : *(p1++) = 0;
108 :
109 : // increase/decrease shift, but keep bound inside 0 to 7
110 0 : nShift += nDeltaShift;
111 0 : if( nShift != (nShift & 7) )
112 0 : p2 -= nDeltaShift;
113 0 : nShift &= 7;
114 : }
115 0 : }
116 :
117 :
118 : // used by 180 degrees rotations on 1 bit deep bitmaps
119 0 : static void ImplRotate1_180( unsigned char* p1, const unsigned char* p2,
120 : int xmax, int ymax, int nPad )
121 : {
122 0 : --p2;
123 0 : for( int y = ymax; --y >= 0; )
124 : {
125 0 : p2 -= nPad;
126 :
127 0 : unsigned nTemp = 1;
128 0 : unsigned nInp = (0x100 + *p2) >> (-xmax & 7);
129 0 : for( int x = xmax; --x >= 0; )
130 : {
131 : // build bitwise and store when byte finished
132 0 : nTemp += nTemp + (nInp & 1);
133 0 : if( nTemp >= 0x100 )
134 : {
135 0 : *(p1++) = (unsigned char)nTemp;
136 0 : nTemp = 1;
137 : }
138 : // update input byte if needed (and available)
139 0 : if( (nInp >>= 1) <= 1 && ((y != 0) || (x != 0)) )
140 0 : nInp = 0x100 + *(--p2);
141 : }
142 :
143 : // store left aligned remainder if needed
144 0 : if( nTemp > 1 )
145 : {
146 0 : for(; nTemp < 0x100; nTemp += nTemp ) ;
147 0 : *(p1++) = (unsigned char)nTemp;
148 : }
149 : // scanline pad is already clean
150 0 : p1 += nPad;
151 : }
152 0 : }
153 :
154 :
155 10618 : bool RawBitmap::Rotate( int nAngle )
156 : {
157 10618 : sal_uLong nNewScanlineSize = 0;
158 10618 : sal_uLong nNewHeight = 0;
159 10618 : sal_uLong nNewWidth = 0;
160 :
161 : // do inplace rotation or prepare double buffered rotation
162 10618 : switch( nAngle )
163 : {
164 : case 0: // nothing to do
165 : case 3600:
166 0 : return true;
167 : default: // non rectangular angles not allowed
168 0 : return false;
169 : case 1800: // rotate by 180 degrees
170 0 : mnXOffset = -(mnXOffset + mnWidth);
171 0 : mnYOffset = -(mnYOffset + mnHeight);
172 0 : if( mnBitCount == 8 )
173 : {
174 0 : ImplRotate8_180( mpBits, mnWidth, mnHeight, mnScanlineSize-mnWidth );
175 0 : return true;
176 : }
177 0 : nNewWidth = mnWidth;
178 0 : nNewHeight = mnHeight;
179 0 : nNewScanlineSize = mnScanlineSize;
180 0 : break;
181 : case +900: // left by 90 degrees
182 : case -900:
183 : case 2700: // right by 90 degrees
184 10618 : nNewWidth = mnHeight;
185 10618 : nNewHeight = mnWidth;
186 10618 : if( mnBitCount==1 )
187 0 : nNewScanlineSize = (nNewWidth + 7) / 8;
188 : else
189 10618 : nNewScanlineSize = (nNewWidth + 3) & -4;
190 10618 : break;
191 : }
192 :
193 10618 : unsigned int nBufSize = nNewHeight * nNewScanlineSize;
194 10618 : unsigned char* pBuf = new unsigned char[ nBufSize ];
195 10618 : if( !pBuf )
196 0 : return false;
197 :
198 10618 : memset( pBuf, 0, nBufSize );
199 : int i;
200 :
201 : // dispatch non-inplace rotations
202 10618 : switch( nAngle )
203 : {
204 : case 1800: // rotate by 180 degrees
205 : // we know we only need to deal with 1 bit depth
206 0 : ImplRotate1_180( pBuf, mpBits + mnHeight * mnScanlineSize,
207 0 : mnWidth, mnHeight, mnScanlineSize - (mnWidth + 7) / 8 );
208 0 : break;
209 : case +900: // rotate left by 90 degrees
210 7452 : i = mnXOffset;
211 7452 : mnXOffset = mnYOffset;
212 7452 : mnYOffset = -nNewHeight - i;
213 7452 : if( mnBitCount == 8 )
214 7452 : ImplRotate8_90( pBuf, mpBits + mnWidth - 1,
215 7452 : nNewWidth, nNewHeight, +mnScanlineSize, -1-mnHeight*mnScanlineSize,
216 22356 : nNewScanlineSize - nNewWidth );
217 : else
218 0 : ImplRotate1_90( pBuf, mpBits + (mnWidth - 1) / 8,
219 : nNewWidth, nNewHeight, +mnScanlineSize,
220 0 : (-mnWidth & 7), +1, nNewScanlineSize - (nNewWidth + 7) / 8 );
221 7452 : break;
222 : case 2700: // rotate right by 90 degrees
223 : case -900:
224 3166 : i = mnXOffset;
225 3166 : mnXOffset = -(nNewWidth + mnYOffset);
226 3166 : mnYOffset = i;
227 3166 : if( mnBitCount == 8 )
228 3166 : ImplRotate8_90( pBuf, mpBits + mnScanlineSize * (mnHeight-1),
229 3166 : nNewWidth, nNewHeight, -mnScanlineSize, +1+mnHeight*mnScanlineSize,
230 9498 : nNewScanlineSize - nNewWidth );
231 : else
232 0 : ImplRotate1_90( pBuf, mpBits + mnScanlineSize * (mnHeight-1),
233 : nNewWidth, nNewHeight, -mnScanlineSize,
234 0 : +7, -1, nNewScanlineSize - (nNewWidth + 7) / 8 );
235 3166 : break;
236 : }
237 :
238 10618 : mnWidth = nNewWidth;
239 10618 : mnHeight = nNewHeight;
240 10618 : mnScanlineSize = nNewScanlineSize;
241 :
242 10618 : if( nBufSize < mnAllocated )
243 : {
244 10618 : memcpy( mpBits, pBuf, nBufSize );
245 10618 : delete[] pBuf;
246 : }
247 : else
248 : {
249 0 : delete[] mpBits;
250 0 : mpBits = pBuf;
251 0 : mnAllocated = nBufSize;
252 : }
253 :
254 10618 : return true;
255 465 : }
256 :
257 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|