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