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