1 /*******************************************************
2
3 CoolReader Engine
4
5 lvdrawbuf.cpp: Gray bitmap buffer class
6
7 (c) Vadim Lopatin, 2000-2006
8 This source code is distributed under the terms of
9 GNU General Public License
10
11 See LICENSE file for details
12
13 *******************************************************/
14
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include "../include/lvdrawbuf.h"
19 #include "../include/crlog.h"
20
21 #define GUARD_BYTE 0xa5
22 #define CHECK_GUARD_BYTE \
23 { \
24 if (_bpp != 1 && _bpp != 2 && _bpp !=3 && _bpp != 4 && _bpp != 8 && _bpp != 16 && _bpp != 32) crFatalError(-5, "wrong bpp"); \
25 if (_ownData && _data && _data[_rowsize * _dy] != GUARD_BYTE) crFatalError(-5, "corrupted bitmap buffer"); \
26 }
27
RoundRect(int x0,int y0,int x1,int y1,int borderWidth,int radius,lUInt32 color,int cornerFlags)28 void LVDrawBuf::RoundRect( int x0, int y0, int x1, int y1, int borderWidth, int radius, lUInt32 color, int cornerFlags )
29 {
30 FillRect( x0 + ((cornerFlags&1)?radius:0), y0, x1-1-((cornerFlags&2)?radius:0), y0+borderWidth, color );
31 FillRect( x0, y0 + ((cornerFlags&1)?radius:0), x0+borderWidth, y1-1-((cornerFlags&4)?radius:0), color );
32 FillRect( x1-borderWidth, y0 + ((cornerFlags&2)?radius:0), x1, y1-((cornerFlags&8)?radius:0), color );
33 FillRect( x0 + ((cornerFlags&4)?radius:0), y1-borderWidth, x1-((cornerFlags&8)?radius:0), y1, color );
34 // TODO: draw rounded corners
35 }
36
37 // NOTE: For more accurate (but slightly more costly) conversions, see:
38 // stb does (lUInt8) (((r*77) + (g*150) + (b*29)) >> 8) (That's roughly the Rec601Luma algo)
39 // Qt5 does (lUInt8) (((r*11) + (g*16) + (b*5)) >> 5) (That's closer to Rec601Luminance or Rec709Luminance IIRC)
rgbToGray(lUInt32 color)40 static lUInt32 rgbToGray( lUInt32 color )
41 {
42 lUInt32 r = (0xFF0000 & color) >> 16;
43 lUInt32 g = (0x00FF00 & color) >> 8;
44 lUInt32 b = (0x0000FF & color) >> 0;
45 return ((r + g + g + b)>>2) & 0xFF;
46 }
47
rgbToGray(lUInt32 color,int bpp)48 static lUInt8 rgbToGray( lUInt32 color, int bpp )
49 {
50 lUInt32 r = (0xFF0000 & color) >> 16;
51 lUInt32 g = (0x00FF00 & color) >> 8;
52 lUInt32 b = (0x0000FF & color) >> 0;
53 return (lUInt8)(((r + g + g + b)>>2) & (((1<<bpp)-1)<<(8-bpp)));
54 }
55
rgb565(int r,int g,int b)56 static lUInt16 rgb565(int r, int g, int b) {
57 // rrrr rggg gggb bbbb
58 return (lUInt16)(((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3));
59 }
60
rgbToGrayMask(lUInt32 color,int bpp)61 static lUInt8 rgbToGrayMask( lUInt32 color, int bpp )
62 {
63 switch ( bpp ) {
64 case DRAW_BUF_1_BPP:
65 color = rgbToGray(color) >> 7;
66 color = (color&1) ? 0xFF : 0x00;
67 break;
68 case DRAW_BUF_2_BPP:
69 color = rgbToGray(color) >> 6;
70 color &= 3;
71 color |= (color << 2) | (color << 4) | (color << 6);
72 break;
73 case DRAW_BUF_3_BPP: // 8 colors
74 case DRAW_BUF_4_BPP: // 16 colors
75 case DRAW_BUF_8_BPP: // 256 colors
76 // return 8 bit as is
77 color = rgbToGray(color);
78 color &= ((1<<bpp)-1)<<(8-bpp);
79 return (lUInt8)color;
80 default:
81 color = rgbToGray(color);
82 return (lUInt8)color;
83 }
84 return (lUInt8)color;
85 }
86
ApplyAlphaRGB(lUInt32 & dst,lUInt32 src,lUInt32 alpha)87 static void ApplyAlphaRGB( lUInt32 &dst, lUInt32 src, lUInt32 alpha )
88 {
89 if ( alpha == 0 ) {
90 dst = src;
91 } else if ( alpha < 255 ) {
92 src &= 0xFFFFFF;
93 lUInt32 opaque = alpha ^ 0xFF;
94 lUInt32 n1 = (((dst & 0xFF00FF) * alpha + (src & 0xFF00FF) * opaque) >> 8) & 0xFF00FF;
95 lUInt32 n2 = (((dst & 0x00FF00) * alpha + (src & 0x00FF00) * opaque) >> 8) & 0x00FF00;
96 dst = n1 | n2;
97 }
98 }
99
ApplyAlphaRGB565(lUInt16 & dst,lUInt16 src,lUInt32 alpha)100 static void ApplyAlphaRGB565( lUInt16 &dst, lUInt16 src, lUInt32 alpha )
101 {
102 if ( alpha==0 ) {
103 dst = src;
104 } else if ( alpha < 255 ) {
105 lUInt32 opaque = alpha ^ 0xFF;
106 lUInt32 r = (((dst & 0xF800) * alpha + (src & 0xF800) * opaque) >> 8) & 0xF800;
107 lUInt32 g = (((dst & 0x07E0) * alpha + (src & 0x07E0) * opaque) >> 8) & 0x07E0;
108 lUInt32 b = (((dst & 0x001F) * alpha + (src & 0x001F) * opaque) >> 8) & 0x001F;
109 dst = (lUInt16)(r | g | b);
110 }
111 }
112
ApplyAlphaGray(lUInt8 & dst,lUInt8 src,lUInt32 alpha,int bpp)113 static void ApplyAlphaGray( lUInt8 &dst, lUInt8 src, lUInt32 alpha, int bpp )
114 {
115 if ( alpha==0 ) {
116 dst = src;
117 } else if ( alpha < 255 ) {
118 int mask = ((1 << bpp) - 1) << (8 - bpp);
119 src &= mask;
120 lUInt32 opaque = alpha ^ 0xFF;
121 lUInt32 n1 = ((dst * alpha + src * opaque) >> 8) & mask;
122 dst = (lUInt8)n1;
123 }
124 }
125
126 /*
127 static void ApplyAlphaGray8( lUInt8 &dst, lUInt8 src, lUInt8 alpha )
128 {
129 if ( alpha==0 ) {
130 dst = src;
131 } else if ( alpha < 255 ) {
132 lUInt8 opaque = alpha ^ 0xFF;
133 lUInt8 v = ((dst * alpha + src * opaque) >> 8);
134 dst = (lUInt8) v;
135 }
136 }
137 */
138
139 //static const short dither_2bpp_4x4[] = {
140 // 5, 13, 8, 16,
141 // 9, 1, 12, 4,
142 // 7, 15, 6, 14,
143 // 11, 3, 10, 2,
144 //};
145
146 static const short dither_2bpp_8x8[] = {
147 0, 32, 12, 44, 2, 34, 14, 46,
148 48, 16, 60, 28, 50, 18, 62, 30,
149 8, 40, 4, 36, 10, 42, 6, 38,
150 56, 24, 52, 20, 58, 26, 54, 22,
151 3, 35, 15, 47, 1, 33, 13, 45,
152 51, 19, 63, 31, 49, 17, 61, 29,
153 11, 43, 7, 39, 9, 41, 5, 37,
154 59, 27, 55, 23, 57, 25, 53, 21,
155 };
156
157 // returns byte with higher significant bits, lower bits are 0
DitherNBitColor(lUInt32 color,lUInt32 x,lUInt32 y,int bits)158 lUInt32 DitherNBitColor( lUInt32 color, lUInt32 x, lUInt32 y, int bits )
159 {
160 int mask = ((1<<bits)-1)<<(8-bits);
161 // gray = (r + 2*g + b)>>2
162 //int cl = ((((color>>16) & 255) + ((color>>(8-1)) & (255<<1)) + ((color) & 255)) >> 2) & 255;
163 int cl = ((((color>>16) & 255) + ((color>>(8-1)) & (255<<1)) + ((color) & 255)) >> 2) & 255;
164 int white = (1<<bits) - 1;
165 int precision = white;
166 if (cl<precision)
167 return 0;
168 else if (cl>=255-precision)
169 return mask;
170 //int d = dither_2bpp_4x4[(x&3) | ( (y&3) << 2 )] - 1;
171 // dither = 0..63
172 int d = dither_2bpp_8x8[(x&7) | ( (y&7) << 3 )] - 1;
173 int shift = bits-2;
174 cl = ( (cl<<shift) + d - 32 ) >> shift;
175 if ( cl>255 )
176 cl = 255;
177 if ( cl<0 )
178 cl = 0;
179 return cl & mask;
180 }
181
Dither2BitColor(lUInt32 color,lUInt32 x,lUInt32 y)182 lUInt32 Dither2BitColor( lUInt32 color, lUInt32 x, lUInt32 y )
183 {
184 int cl = ((((color>>16) & 255) + ((color>>8) & 255) + ((color) & 255)) * (256/3)) >> 8;
185 if (cl<5)
186 return 0;
187 else if (cl>=250)
188 return 3;
189 //int d = dither_2bpp_4x4[(x&3) | ( (y&3) << 2 )] - 1;
190 int d = dither_2bpp_8x8[(x&7) | ( (y&7) << 3 )] - 1;
191
192 cl = ( cl + d - 32 );
193 if (cl<5)
194 return 0;
195 else if (cl>=250)
196 return 3;
197 return (cl >> 6) & 3;
198 }
199
Dither1BitColor(lUInt32 color,lUInt32 x,lUInt32 y)200 lUInt32 Dither1BitColor( lUInt32 color, lUInt32 x, lUInt32 y )
201 {
202 int cl = ((((color>>16) & 255) + ((color>>8) & 255) + ((color) & 255)) * (256/3)) >> 8;
203 if (cl<16)
204 return 0;
205 else if (cl>=240)
206 return 1;
207 //int d = dither_2bpp_4x4[(x&3) | ( (y&3) << 2 )] - 1;
208 int d = dither_2bpp_8x8[(x&7) | ( (y&7) << 3 )] - 1;
209
210 cl = ( cl + d - 32 );
211 if (cl<5)
212 return 0;
213 else if (cl>=250)
214 return 1;
215 return (cl >> 7) & 1;
216 }
217
revByteBits1(lUInt8 b)218 static lUInt8 revByteBits1( lUInt8 b )
219 {
220 return ( (b&1)<<7 )
221 | ( (b&2)<<5 )
222 | ( (b&4)<<3 )
223 | ( (b&8)<<1 )
224 | ( (b&16)>>1 )
225 | ( (b&32)>>3 )
226 | ( (b&64)>>4 )
227 | ( (b&128)>>5 );
228 }
229
revByteBits2(lUInt8 b)230 lUInt8 revByteBits2( lUInt8 b )
231 {
232 return ( (b&0x03)<<6 )
233 | ( (b&0x0C)<<2 )
234 | ( (b&0x30)>>2 )
235 | ( (b&0xC0)>>6 );
236 }
237
238 /// rotates buffer contents by specified angle
Rotate(cr_rotate_angle_t angle)239 void LVGrayDrawBuf::Rotate( cr_rotate_angle_t angle )
240 {
241 if ( angle==CR_ROTATE_ANGLE_0 )
242 return;
243 int sz = (_rowsize * _dy);
244 if ( angle==CR_ROTATE_ANGLE_180 ) {
245 if ( _bpp==DRAW_BUF_1_BPP ) {
246 for ( int i=sz/2-1; i>=0; i-- ) {
247 lUInt8 tmp = revByteBits1( _data[i] );
248 _data[i] = revByteBits1( _data[sz-i-1] );
249 _data[sz-i-1] = tmp;
250 }
251 } else if ( _bpp==DRAW_BUF_2_BPP ) {
252 for ( int i=sz/2-1; i>=0; i-- ) {
253 lUInt8 tmp = revByteBits2( _data[i] );
254 _data[i] = revByteBits2( _data[sz-i-1] );
255 _data[sz-i-1] = tmp;
256 }
257 } else { // DRAW_BUF_3_BPP, DRAW_BUF_4_BPP, DRAW_BUF_8_BPP
258 lUInt8 * buf = (lUInt8 *) _data;
259 for ( int i=sz/2-1; i>=0; i-- ) {
260 lUInt8 tmp = buf[i];
261 buf[i] = buf[sz-i-1];
262 buf[sz-i-1] = tmp;
263 }
264 }
265 return;
266 }
267 int newrowsize = _bpp<=2 ? (_dy * _bpp + 7) / 8 : _dy;
268 sz = (newrowsize * _dx);
269 lUInt8 * dst = (lUInt8 *)calloc(sz, sizeof(*dst));
270 for ( int y=0; y<_dy; y++ ) {
271 lUInt8 * src = _data + _rowsize*y;
272 int dstx, dsty;
273 for ( int x=0; x<_dx; x++ ) {
274 if ( angle==CR_ROTATE_ANGLE_90 ) {
275 dstx = _dy-1-y;
276 dsty = x;
277 } else {
278 dstx = y;
279 dsty = _dx-1-x;
280 }
281 if ( _bpp==DRAW_BUF_1_BPP ) {
282 lUInt8 px = (src[ x >> 3 ] << (x&7)) & 0x80;
283 lUInt8 * dstrow = dst + newrowsize * dsty;
284 dstrow[ dstx >> 3 ] |= (px >> (dstx&7));
285 } else if (_bpp==DRAW_BUF_2_BPP ) {
286 lUInt8 px = (src[ x >> 2 ] << ((x&3)<<1)) & 0xC0;
287 lUInt8 * dstrow = dst + newrowsize * dsty;
288 dstrow[ dstx >> 2 ] |= (px >> ((dstx&3)<<1));
289 } else { // DRAW_BUF_3_BPP, DRAW_BUF_4_BPP, DRAW_BUF_8_BPP
290 lUInt8 * dstrow = dst + newrowsize * dsty;
291 dstrow[ dstx ] = src[ x ];
292 }
293 }
294 }
295 free( _data );
296 _data = dst;
297 int tmp = _dx;
298 _dx = _dy;
299 _dy = tmp;
300 _rowsize = newrowsize;
301 }
302
303 /// rotates buffer contents by specified angle
Rotate(cr_rotate_angle_t angle)304 void LVColorDrawBuf::Rotate( cr_rotate_angle_t angle )
305 {
306 if ( angle==CR_ROTATE_ANGLE_0 )
307 return;
308 if ( _bpp==16 ) {
309 int sz = (_dx * _dy);
310 if ( angle==CR_ROTATE_ANGLE_180 ) {
311 lUInt16 * buf = (lUInt16 *) _data;
312 for ( int i=sz/2-1; i>=0; i-- ) {
313 lUInt16 tmp = buf[i];
314 buf[i] = buf[sz-i-1];
315 buf[sz-i-1] = tmp;
316 }
317 return;
318 }
319 int newrowsize = _dy * 2;
320 sz = (_dx * newrowsize);
321 lUInt16 * dst = (lUInt16*) malloc( sz );
322 #if !defined(__SYMBIAN32__) && defined(_WIN32) && !defined(QT_GL)
323 bool cw = angle!=CR_ROTATE_ANGLE_90;
324 #else
325 bool cw = angle==CR_ROTATE_ANGLE_90;
326 #endif
327 for ( int y=0; y<_dy; y++ ) {
328 lUInt16 * src = (lUInt16*)_data + _dx*y;
329 int nx, ny;
330 if ( cw ) {
331 nx = _dy - 1 - y;
332 } else {
333 nx = y;
334 }
335 for ( int x=0; x<_dx; x++ ) {
336 if ( cw ) {
337 ny = x;
338 } else {
339 ny = _dx - 1 - x;
340 }
341 dst[ _dy*ny + nx ] = src[ x ];
342 }
343 }
344 #if !defined(__SYMBIAN32__) && defined(_WIN32) && !defined(QT_GL)
345 memcpy( _data, dst, sz );
346 free( dst );
347 #else
348 free( _data );
349 _data = (lUInt8*)dst;
350 #endif
351 int tmp = _dx;
352 _dx = _dy;
353 _dy = tmp;
354 _rowsize = newrowsize;
355 } else {
356 int sz = (_dx * _dy);
357 if ( angle==CR_ROTATE_ANGLE_180 ) {
358 lUInt32 * buf = (lUInt32 *) _data;
359 for ( int i=sz/2-1; i>=0; i-- ) {
360 lUInt32 tmp = buf[i];
361 buf[i] = buf[sz-i-1];
362 buf[sz-i-1] = tmp;
363 }
364 return;
365 }
366 int newrowsize = _dy * 4;
367 sz = (_dx * newrowsize);
368 lUInt32 * dst = (lUInt32*) malloc( sz );
369 #if !defined(__SYMBIAN32__) && defined(_WIN32) && !defined(QT_GL)
370 bool cw = angle!=CR_ROTATE_ANGLE_90;
371 #else
372 bool cw = angle==CR_ROTATE_ANGLE_90;
373 #endif
374 for ( int y=0; y<_dy; y++ ) {
375 lUInt32 * src = (lUInt32*)_data + _dx*y;
376 int nx, ny;
377 if ( cw ) {
378 nx = _dy - 1 - y;
379 } else {
380 nx = y;
381 }
382 for ( int x=0; x<_dx; x++ ) {
383 if ( cw ) {
384 ny = x;
385 } else {
386 ny = _dx - 1 - x;
387 }
388 dst[ _dy*ny + nx ] = src[ x ];
389 }
390 }
391 #if !defined(__SYMBIAN32__) && defined(_WIN32) && !defined(QT_GL)
392 memcpy( _data, dst, sz );
393 free( dst );
394 #else
395 free( _data );
396 _data = (lUInt8*)dst;
397 #endif
398 int tmp = _dx;
399 _dx = _dy;
400 _dy = tmp;
401 _rowsize = newrowsize;
402 }
403 }
404
405 class LVImageScaledDrawCallback : public LVImageDecoderCallback
406 {
407 private:
408 LVImageSourceRef src;
409 LVBaseDrawBuf * dst;
410 int dst_x;
411 int dst_y;
412 int dst_dx;
413 int dst_dy;
414 int src_dx;
415 int src_dy;
416 int * xmap;
417 int * ymap;
418 bool dither;
419 bool invert;
420 bool smoothscale;
421 lUInt8 * decoded;
422 bool isNinePatch;
423 public:
GenMap(int src_len,int dst_len)424 static int * GenMap( int src_len, int dst_len )
425 {
426 int * map = new int[ dst_len ];
427 for (int i=0; i<dst_len; i++)
428 {
429 map[ i ] = i * src_len / dst_len;
430 }
431 return map;
432 }
GenNinePatchMap(int src_len,int dst_len,int frame1,int frame2)433 static int * GenNinePatchMap( int src_len, int dst_len, int frame1, int frame2)
434 {
435 int * map = new int[ dst_len ];
436 if (frame1 + frame2 > dst_len) {
437 int total = frame1 + frame2;
438 int extra = total - dst_len;
439 int extra1 = frame1 * extra / total;
440 int extra2 = frame2 * extra / total;
441 frame1 -= extra1;
442 frame2 -= extra2;
443 }
444 int srcm = src_len - frame1 - frame2 - 2;
445 int dstm = dst_len - frame1 - frame2;
446 if (srcm < 0)
447 srcm = 0;
448 for (int i=0; i<dst_len; i++)
449 {
450 if (i < frame1) {
451 // start
452 map[ i ] = i + 1;
453 } else if (i >= dst_len - frame2) {
454 // end
455 int rx = i - (dst_len - frame2);
456 map[ i ] = src_len - frame2 + rx - 1;
457 } else {
458 // middle
459 map[ i ] = 1 + frame1 + (i - frame1) * srcm / dstm;
460 }
461 // CRLog::trace("frame[%d, %d] src=%d dst=%d %d -> %d", frame1, frame2, src_len, dst_len, i, map[i]);
462 // if (map[i] >= src_len) {
463 // CRLog::error("Wrong coords");
464 // }
465 }
466 return map;
467 }
LVImageScaledDrawCallback(LVBaseDrawBuf * dstbuf,LVImageSourceRef img,int x,int y,int width,int height,bool dith,bool inv,bool smooth)468 LVImageScaledDrawCallback(LVBaseDrawBuf * dstbuf, LVImageSourceRef img, int x, int y, int width, int height, bool dith, bool inv, bool smooth )
469 : src(img), dst(dstbuf), dst_x(x), dst_y(y), dst_dx(width), dst_dy(height), xmap(0), ymap(0), dither(dith), invert(inv), smoothscale(smooth), decoded(0)
470 {
471 src_dx = img->GetWidth();
472 src_dy = img->GetHeight();
473 const CR9PatchInfo * np = img->GetNinePatchInfo();
474 isNinePatch = false;
475 lvRect ninePatch;
476 if (np) {
477 isNinePatch = true;
478 ninePatch = np->frame;
479 }
480 // If smoothscaling was requested, but no scaling was needed, disable the post-processing pass
481 if (smoothscale && src_dx == dst_dx && src_dy == dst_dy) {
482 smoothscale = false;
483 //fprintf( stderr, "Disabling smoothscale because no scaling was needed (%dx%d -> %dx%d)\n", src_dx, src_dy, dst_dx, dst_dy );
484 }
485 if ( src_dx != dst_dx || isNinePatch) {
486 if (isNinePatch)
487 xmap = GenNinePatchMap(src_dx, dst_dx, ninePatch.left, ninePatch.right);
488 else if (!smoothscale)
489 xmap = GenMap( src_dx, dst_dx );
490 }
491 if ( src_dy != dst_dy || isNinePatch) {
492 if (isNinePatch)
493 ymap = GenNinePatchMap(src_dy, dst_dy, ninePatch.top, ninePatch.bottom);
494 else if (!smoothscale)
495 ymap = GenMap( src_dy, dst_dy );
496 }
497 // If we have a smoothscale post-processing pass, we'll need to build a buffer of the *full* decoded image.
498 if (smoothscale) {
499 // Byte-sized buffer, we're 32bpp, so, 4 bytes per pixel.
500 decoded = new lUInt8[src_dy * (src_dx * 4)];
501 }
502 }
~LVImageScaledDrawCallback()503 virtual ~LVImageScaledDrawCallback()
504 {
505 if (xmap)
506 delete[] xmap;
507 if (ymap)
508 delete[] ymap;
509 if (decoded)
510 delete[] decoded;
511 }
OnStartDecode(LVImageSource *)512 virtual void OnStartDecode( LVImageSource * )
513 {
514 }
OnLineDecoded(LVImageSource *,int y,lUInt32 * data)515 virtual bool OnLineDecoded( LVImageSource *, int y, lUInt32 * data )
516 {
517 //fprintf( stderr, "l_%d ", y );
518 if (isNinePatch) {
519 if (y == 0 || y == src_dy-1) // ignore first and last lines
520 return true;
521 }
522 // Defer everything to the post-process pass for smooth scaling, we just have to store the line in our decoded buffer
523 if (smoothscale) {
524 //fprintf( stderr, "Smoothscale l_%d pass\n", y );
525 memcpy(decoded + (y * (src_dx * 4)), data, (src_dx * 4));
526 return true;
527 }
528 int yy = -1;
529 int yy2 = -1;
530 const lUInt32 rgba_invert = invert ? 0x00FFFFFF : 0;
531 const lUInt8 gray_invert = invert ? 0xFF : 0;
532 if (ymap) {
533 for (int i = 0; i < dst_dy; i++) {
534 if (ymap[i] == y) {
535 if (yy == -1)
536 yy = i;
537 yy2 = i + 1;
538 }
539 }
540 if (yy == -1)
541 return true;
542 } else {
543 yy = y;
544 yy2 = y+1;
545 }
546 // if ( ymap )
547 // {
548 // int yy0 = (y - 1) * dst_dy / src_dy;
549 // yy = y * dst_dy / src_dy;
550 // yy2 = (y+1) * dst_dy / src_dy;
551 // if ( yy == yy0 )
552 // {
553 // //fprintf( stderr, "skip_dup " );
554 // //return true; // skip duplicate drawing
555 // }
556 // if ( yy2 > dst_dy )
557 // yy2 = dst_dy;
558 // }
559 lvRect clip;
560 dst->GetClipRect( &clip );
561 for ( ;yy<yy2; yy++ )
562 {
563 if ( yy+dst_y<clip.top || yy+dst_y>=clip.bottom )
564 continue;
565 int bpp = dst->GetBitsPerPixel();
566 if ( bpp >= 24 )
567 {
568 lUInt32 * row = (lUInt32 *)dst->GetScanLine( yy + dst_y );
569 row += dst_x;
570 for (int x=0; x<dst_dx; x++)
571 {
572 lUInt32 cl = data[xmap ? xmap[x] : x];
573 int xx = x + dst_x;
574 lUInt32 alpha = (cl >> 24)&0xFF;
575
576 if ( xx<clip.left || xx>=clip.right ) {
577 // OOB, don't plot it!
578 continue;
579 }
580
581 // NOTE: Remember that for some mysterious reason, lvimg feeds us inverted alpha
582 // (i.e., 0 is opaque, 0xFF is transparent)...
583 if ( alpha == 0xFF ) {
584 // Transparent, don't plot it...
585 if ( invert ) {
586 // ...unless we're doing night-mode shenanigans, in which case, we need to fake an inverted background
587 // (i.e., a *black* background, so it gets inverted back to white with NightMode, since white is our expected "standard" background color)
588 // c.f., https://github.com/koreader/koreader/issues/4986
589 row[ x ] = 0x00000000;
590 } else {
591 continue;
592 }
593 } else if ( alpha == 0 ) {
594 // Fully opaque, plot it as-is
595 row[ x ] = RevRGB(cl) ^ rgba_invert;
596 } else {
597 if ((row[x] & 0xFF000000) == 0xFF000000) {
598 // Plot it as-is if *buffer* pixel is transparent
599 row[ x ] = RevRGBA(cl) ^ rgba_invert;
600 } else {
601 // NOTE: This *also* has a "fully opaque" shortcut... :/
602 ApplyAlphaRGB( row[x], RevRGB(cl), alpha );
603 // Invert post-blending to avoid potential stupidity...
604 row[ x ] ^= rgba_invert;
605 }
606 }
607 }
608 }
609 else if ( bpp == 16 )
610 {
611 lUInt16 * row = (lUInt16 *)dst->GetScanLine( yy + dst_y );
612 row += dst_x;
613 for (int x=0; x<dst_dx; x++)
614 {
615 lUInt32 cl = data[xmap ? xmap[x] : x];
616 int xx = x + dst_x;
617 lUInt32 alpha = (cl >> 24)&0xFF;
618
619 if ( xx<clip.left || xx>=clip.right ) {
620 // OOB, don't plot it!
621 continue;
622 }
623
624 // NOTE: See final branch of the ladder. Not quite sure why some alpha ranges are treated differently...
625 if ( alpha >= 0xF0 ) {
626 // Transparent, don't plot it...
627 if ( invert ) {
628 // ...unless we're doing night-mode shenanigans, in which case, we need to fake an inverted background
629 // (i.e., a *black* background, so it gets inverted back to white with NightMode, since white is our expected "standard" background color)
630 // c.f., https://github.com/koreader/koreader/issues/4986
631 row[ x ] = 0x0000;
632 } else {
633 continue;
634 }
635 } else if ( alpha < 16 ) {
636 row[ x ] = rgb888to565( cl ^ rgba_invert );
637 } else if ( alpha < 0xF0 ) {
638 lUInt32 v = rgb565to888(row[x]);
639 ApplyAlphaRGB( v, cl, alpha );
640 row[ x ] = rgb888to565(v ^ rgba_invert);
641 }
642 }
643 }
644 else if ( bpp > 2 ) // 3,4,8 bpp
645 {
646 lUInt8 * row = (lUInt8 *)dst->GetScanLine( yy + dst_y );
647 row += dst_x;
648 for (int x=0; x<dst_dx; x++)
649 {
650 int srcx = xmap ? xmap[x] : x;
651 lUInt32 cl = data[srcx];
652 int xx = x + dst_x;
653 lUInt32 alpha = (cl >> 24)&0xFF;
654
655 if ( xx<clip.left || xx>=clip.right ) {
656 // OOB, don't plot it!
657 continue;
658 }
659
660 if ( alpha == 0xFF ) {
661 // Transparent, don't plot it...
662 if ( invert ) {
663 // ...unless we're doing night-mode shenanigans, in which case, we need to fake a white background.
664 cl = 0x00FFFFFF;
665 } else {
666 continue;
667 }
668 } else if ( alpha != 0 ) {
669 lUInt8 origLuma = row[x];
670 // Expand lower bitdepths to Y8
671 if ( bpp == 3 ) {
672 origLuma = origLuma & 0xE0;
673 origLuma = origLuma | (origLuma>>3) | (origLuma>>6);
674 } else if ( bpp == 4 ) {
675 origLuma = origLuma & 0xF0;
676 origLuma = origLuma | (origLuma>>4);
677 }
678 // Expand Y8 to RGB32 (i.e., duplicate, R = G = B = Y)
679 lUInt32 bufColor = origLuma | (origLuma<<8) | (origLuma<<16);
680 ApplyAlphaRGB( bufColor, cl, alpha );
681 cl = bufColor;
682 }
683
684 lUInt8 dcl;
685 if ( dither && bpp < 8 ) {
686 #if (GRAY_INVERSE==1)
687 dcl = (lUInt8)DitherNBitColor( cl^0xFFFFFF, x, yy, bpp );
688 #else
689 dcl = (lUInt8)DitherNBitColor( cl, x, yy, bpp );
690 #endif
691 } else if ( dither && bpp == 8 ) {
692 dcl = rgbToGray( cl );
693 dcl = dither_o8x8( x, yy, dcl );
694 } else {
695 dcl = rgbToGray( cl, bpp );
696 }
697 row[ x ] = dcl ^ gray_invert;
698 // ApplyAlphaGray( row[x], dcl, alpha, bpp );
699 }
700 }
701 else if ( bpp == 2 )
702 {
703 //fprintf( stderr, "." );
704 lUInt8 * row = (lUInt8 *)dst->GetScanLine( yy+dst_y );
705 //row += dst_x;
706 for (int x=0; x<dst_dx; x++)
707 {
708 lUInt32 cl = data[xmap ? xmap[x] : x];
709 int xx = x + dst_x;
710 lUInt32 alpha = (cl >> 24)&0xFF;
711
712 if ( xx<clip.left || xx>=clip.right ) {
713 // OOB, don't plot it!
714 continue;
715 }
716
717 int byteindex = (xx >> 2);
718 int bitindex = (3-(xx & 3))<<1;
719 lUInt8 mask = 0xC0 >> (6 - bitindex);
720
721 if ( alpha == 0xFF ) {
722 // Transparent, don't plot it...
723 if ( invert ) {
724 // ...unless we're doing night-mode shenanigans, in which case, we need to fake a white background.
725 cl = 0x00FFFFFF;
726 } else {
727 continue;
728 }
729 } else if ( alpha != 0 ) {
730 lUInt8 origLuma = (row[ byteindex ] & mask)>>bitindex;
731 origLuma = origLuma | (origLuma<<2);
732 origLuma = origLuma | (origLuma<<4);
733 lUInt32 bufColor = origLuma | (origLuma<<8) | (origLuma<<16);
734 ApplyAlphaRGB( bufColor, cl, alpha );
735 cl = bufColor;
736 }
737
738 lUInt32 dcl = 0;
739 if ( dither ) {
740 #if (GRAY_INVERSE==1)
741 dcl = Dither2BitColor( cl ^ rgba_invert, x, yy ) ^ 3;
742 #else
743 dcl = Dither2BitColor( cl ^ rgba_invert, x, yy );
744 #endif
745 } else {
746 dcl = rgbToGrayMask( cl ^ rgba_invert, 2 ) & 3;
747 }
748 dcl = dcl << bitindex;
749 row[ byteindex ] = (lUInt8)((row[ byteindex ] & (~mask)) | dcl);
750 }
751 }
752 else if ( bpp == 1 )
753 {
754 //fprintf( stderr, "." );
755 lUInt8 * row = (lUInt8 *)dst->GetScanLine( yy+dst_y );
756 //row += dst_x;
757 for (int x=0; x<dst_dx; x++)
758 {
759 lUInt32 cl = data[xmap ? xmap[x] : x];
760 int xx = x + dst_x;
761 lUInt32 alpha = (cl >> 24)&0xFF;
762
763 if ( xx<clip.left || xx>=clip.right ) {
764 // OOB, don't plot it!
765 continue;
766 }
767
768 if ( alpha & 0x80 ) {
769 // Transparent, don't plot it...
770 if ( invert ) {
771 // ...unless we're doing night-mode shenanigans, in which case, we need to fake a white background.
772 cl = 0x00FFFFFF;
773 } else {
774 continue;
775 }
776 }
777
778 lUInt32 dcl = 0;
779 if ( dither ) {
780 #if (GRAY_INVERSE==1)
781 dcl = Dither1BitColor( cl ^ rgba_invert, x, yy ) ^ 1;
782 #else
783 dcl = Dither1BitColor( cl ^ rgba_invert, x, yy ) ^ 0;
784 #endif
785 } else {
786 dcl = rgbToGrayMask( cl ^ rgba_invert, 1 ) & 1;
787 }
788 int byteindex = (xx >> 3);
789 int bitindex = ((xx & 7));
790 lUInt8 mask = 0x80 >> (bitindex);
791 dcl = dcl << (7-bitindex);
792 row[ byteindex ] = (lUInt8)((row[ byteindex ] & (~mask)) | dcl);
793 }
794 }
795 else
796 {
797 return false;
798 }
799 }
800 return true;
801 }
OnEndDecode(LVImageSource * obj,bool)802 virtual void OnEndDecode( LVImageSource * obj, bool )
803 {
804 // If we're not smooth scaling, we're done!
805 #ifndef ANDROID
806 if (!smoothscale)
807 {
808 return;
809 }
810
811 // Scale our decoded data...
812 lUInt8 * sdata = nullptr;
813 //fprintf( stderr, "Requesting smooth scaling (%dx%d -> %dx%d)\n", src_dx, src_dy, dst_dx, dst_dy );
814 sdata = CRe::qSmoothScaleImage(decoded, src_dx, src_dy, false, dst_dx, dst_dy);
815 if (sdata == nullptr) {
816 // Hu oh... Scaling failed! Return *without* drawing anything!
817 // We skipped map generation, so we can't easily fallback to nearest-neighbor...
818 //fprintf( stderr, "Smooth scaling failed :(\n" );
819 return;
820 }
821
822 // Process as usual, with a bit of a hack to avoid code duplication...
823 smoothscale = false;
824 for (int y=0; y < dst_dy; y++) {
825 lUInt8 * row = sdata + (y * (dst_dx * 4));
826 this->OnLineDecoded( obj, y, (lUInt32 *) row );
827 }
828
829 // This prints the unscaled decoded buffer, for debugging purposes ;).
830 /*
831 for (int y=0; y < src_dy; y++) {
832 lUInt8 * row = decoded + (y * (src_dx * 4));
833 this->OnLineDecoded( obj, y, (lUInt32 *) row );
834 }
835 */
836 // And now that it's been rendered we can free the scaled buffer (it was allocated by CRe::qSmoothScaleImage).
837 free(sdata);
838 #endif
839 }
840 };
841
842
GetWidth()843 int LVBaseDrawBuf::GetWidth()
844 {
845 return _dx;
846 }
847
GetHeight()848 int LVBaseDrawBuf::GetHeight()
849 {
850 return _dy;
851 }
852
GetBitsPerPixel()853 int LVGrayDrawBuf::GetBitsPerPixel()
854 {
855 return _bpp;
856 }
857
Draw(LVImageSourceRef img,int x,int y,int width,int height,bool dither)858 void LVGrayDrawBuf::Draw( LVImageSourceRef img, int x, int y, int width, int height, bool dither )
859 {
860 //fprintf( stderr, "LVGrayDrawBuf::Draw( img(%d, %d), %d, %d, %d, %d\n", img->GetWidth(), img->GetHeight(), x, y, width, height );
861 if ( width<=0 || height<=0 )
862 return;
863 LVImageScaledDrawCallback drawcb( this, img, x, y, width, height, _ditherImages, _invertImages, _smoothImages );
864 img->Decode( &drawcb );
865
866 _drawnImagesCount++;
867 _drawnImagesSurface += width*height;
868 }
869
870
871 /// get pixel value
GetPixel(int x,int y)872 lUInt32 LVGrayDrawBuf::GetPixel( int x, int y )
873 {
874 if (x<0 || y<0 || x>=_dx || y>=_dy)
875 return 0;
876 lUInt8 * line = GetScanLine(y);
877 if (_bpp==1) {
878 // 1bpp
879 if ( line[x>>3] & (0x80>>(x&7)) )
880 return 1;
881 else
882 return 0;
883 } else if (_bpp==2) {
884 return (line[x>>2] >> (6-((x&3)<<1))) & 3;
885 } else { // 3, 4, 8
886 return line[x];
887 }
888 }
889
Clear(lUInt32 color)890 void LVGrayDrawBuf::Clear( lUInt32 color )
891 {
892 if (!_data)
893 return;
894 color = rgbToGrayMask( color, _bpp );
895 #if (GRAY_INVERSE==1)
896 color ^= 0xFF;
897 #endif
898 memset( _data, color, _rowsize * _dy );
899 // for (int i = _rowsize * _dy - 1; i>0; i--)
900 // {
901 // _data[i] = (lUInt8)color;
902 // }
903 SetClipRect( NULL );
904 }
905
FillRect(int x0,int y0,int x1,int y1,lUInt32 color32)906 void LVGrayDrawBuf::FillRect( int x0, int y0, int x1, int y1, lUInt32 color32 )
907 {
908 if (x0<_clip.left)
909 x0 = _clip.left;
910 if (y0<_clip.top)
911 y0 = _clip.top;
912 if (x1>_clip.right)
913 x1 = _clip.right;
914 if (y1>_clip.bottom)
915 y1 = _clip.bottom;
916 if (x0>=x1 || y0>=y1)
917 return;
918 lUInt8 color = rgbToGrayMask( color32, _bpp );
919 #if (GRAY_INVERSE==1)
920 color ^= 0xFF;
921 #endif
922 lUInt8 * line = GetScanLine(y0);
923 for (int y=y0; y<y1; y++)
924 {
925 if (_bpp==1) {
926 for (int x=x0; x<x1; x++)
927 {
928 lUInt8 mask = 0x80 >> (x&7);
929 int index = x >> 3;
930 line[index] = (lUInt8)((line[index] & ~mask) | (color & mask));
931 }
932 } else if (_bpp==2) {
933 for (int x=x0; x<x1; x++)
934 {
935 lUInt8 mask = 0xC0 >> ((x&3)<<1);
936 int index = x >> 2;
937 line[index] = (lUInt8)((line[index] & ~mask) | (color & mask));
938 }
939 } else { // 3, 4, 8
940 for (int x=x0; x<x1; x++)
941 line[x] = color;
942 }
943 line += _rowsize;
944 }
945 }
946
FillRectPattern(int x0,int y0,int x1,int y1,lUInt32 color032,lUInt32 color132,lUInt8 * pattern)947 void LVGrayDrawBuf::FillRectPattern( int x0, int y0, int x1, int y1, lUInt32 color032, lUInt32 color132, lUInt8 * pattern )
948 {
949 if (x0<_clip.left)
950 x0 = _clip.left;
951 if (y0<_clip.top)
952 y0 = _clip.top;
953 if (x1>_clip.right)
954 x1 = _clip.right;
955 if (y1>_clip.bottom)
956 y1 = _clip.bottom;
957 if (x0>=x1 || y0>=y1)
958 return;
959 lUInt8 color0 = rgbToGrayMask( color032, _bpp );
960 lUInt8 color1 = rgbToGrayMask( color132, _bpp );
961 lUInt8 * line = GetScanLine(y0);
962 for (int y=y0; y<y1; y++)
963 {
964 lUInt8 patternMask = pattern[y & 3];
965 if (_bpp==1) {
966 for (int x=x0; x<x1; x++)
967 {
968 lUInt8 patternBit = (patternMask << (x&7)) & 0x80;
969 lUInt8 mask = 0x80 >> (x&7);
970 int index = x >> 3;
971 line[index] = (lUInt8)((line[index] & ~mask) | ((patternBit?color1:color0) & mask));
972 }
973 } else if (_bpp==2) {
974 for (int x=x0; x<x1; x++)
975 {
976 lUInt8 patternBit = (patternMask << (x&7)) & 0x80;
977 lUInt8 mask = 0xC0 >> ((x&3)<<1);
978 int index = x >> 2;
979 line[index] = (lUInt8)((line[index] & ~mask) | ((patternBit?color1:color0) & mask));
980 }
981 } else {
982 for (int x=x0; x<x1; x++)
983 {
984 lUInt8 patternBit = (patternMask << (x&7)) & 0x80;
985 line[x] = patternBit ? color1 : color0;
986 }
987 }
988 line += _rowsize;
989 }
990 }
991
992 static const lUInt8 fill_masks1[5] = {0x00, 0x3, 0x0f, 0x3f, 0xff};
993 static const lUInt8 fill_masks2[4] = {0x00, 0xc0, 0xf0, 0xfc};
994
995 #define INVERT_PRSERVE_GRAYS
996
997 #ifdef INVERT_PRSERVE_GRAYS
998 static const lUInt8 inverted_bytes[] = {
999 0xff, 0xfd, 0xfe, 0xfc, 0xf7, 0xf5, 0xf6, 0xf4, 0xfb, 0xf9, 0xfa, 0xf8, 0xf3, 0xf1,
1000 0xf2, 0xf0, 0xdf, 0xdd, 0xde, 0xdc, 0xd7, 0xd5, 0xd6, 0xd4, 0xdb, 0xd9, 0xda, 0xd8,
1001 0xd3, 0xd1, 0xd2, 0xd0, 0xef, 0xed, 0xee, 0xec, 0xe7, 0xe5, 0xe6, 0xe4, 0xeb, 0xe9,
1002 0xea, 0xe8, 0xe3, 0xe1, 0xe2, 0xe0, 0xcf, 0xcd, 0xce, 0xcc, 0xc7, 0xc5, 0xc6, 0xc4,
1003 0xcb, 0xc9, 0xca, 0xc8, 0xc3, 0xc1, 0xc2, 0xc0, 0x7f, 0x7d, 0x7e, 0x7c, 0x77, 0x75,
1004 0x76, 0x74, 0x7b, 0x79, 0x7a, 0x78, 0x73, 0x71, 0x72, 0x70, 0x5f, 0x5d, 0x5e, 0x5c,
1005 0x57, 0x55, 0x56, 0x54, 0x5b, 0x59, 0x5a, 0x58, 0x53, 0x51, 0x52, 0x50, 0x6f, 0x6d,
1006 0x6e, 0x6c, 0x67, 0x65, 0x66, 0x64, 0x6b, 0x69, 0x6a, 0x68, 0x63, 0x61, 0x62, 0x60,
1007 0x4f, 0x4d, 0x4e, 0x4c, 0x47, 0x45, 0x46, 0x44, 0x4b, 0x49, 0x4a, 0x48, 0x43, 0x41,
1008 0x42, 0x40, 0xbf, 0xbd, 0xbe, 0xbc, 0xb7, 0xb5, 0xb6, 0xb4, 0xbb, 0xb9, 0xba, 0xb8,
1009 0xb3, 0xb1, 0xb2, 0xb0, 0x9f, 0x9d, 0x9e, 0x9c, 0x97, 0x95, 0x96, 0x94, 0x9b, 0x99,
1010 0x9a, 0x98, 0x93, 0x91, 0x92, 0x90, 0xaf, 0xad, 0xae, 0xac, 0xa7, 0xa5, 0xa6, 0xa4,
1011 0xab, 0xa9, 0xaa, 0xa8, 0xa3, 0xa1, 0xa2, 0xa0, 0x8f, 0x8d, 0x8e, 0x8c, 0x87, 0x85,
1012 0x86, 0x84, 0x8b, 0x89, 0x8a, 0x88, 0x83, 0x81, 0x82, 0x80, 0x3f, 0x3d, 0x3e, 0x3c,
1013 0x37, 0x35, 0x36, 0x34, 0x3b, 0x39, 0x3a, 0x38, 0x33, 0x31, 0x32, 0x30, 0x1f, 0x1d,
1014 0x1e, 0x1c, 0x17, 0x15, 0x16, 0x14, 0x1b, 0x19, 0x1a, 0x18, 0x13, 0x11, 0x12, 0x10,
1015 0x2f, 0x2d, 0x2e, 0x2c, 0x27, 0x25, 0x26, 0x24, 0x2b, 0x29, 0x2a, 0x28, 0x23, 0x21,
1016 0x22, 0x20, 0xf, 0xd, 0xe, 0xc, 0x7, 0x5, 0x6, 0x4, 0xb, 0x9, 0xa, 0x8,
1017 0x3, 0x1, 0x2, 0x0
1018 };
1019 #define GET_INVERTED_BYTE(x) inverted_bytes[x]
1020 #else
1021 #define GET_INVERTED_BYTE(x) ~(x)
1022 #endif
InvertRect(int x0,int y0,int x1,int y1)1023 void LVGrayDrawBuf::InvertRect(int x0, int y0, int x1, int y1)
1024 {
1025 if (x0<_clip.left)
1026 x0 = _clip.left;
1027 if (y0<_clip.top)
1028 y0 = _clip.top;
1029 if (x1>_clip.right)
1030 x1 = _clip.right;
1031 if (y1>_clip.bottom)
1032 y1 = _clip.bottom;
1033 if (x0>=x1 || y0>=y1)
1034 return;
1035
1036 if (_bpp==1) {
1037 ; //TODO: implement for 1 bit
1038 } else if (_bpp==2) {
1039 lUInt8 * line = GetScanLine(y0) + (x0 >> 2);
1040 lUInt16 before = 4 - (x0 & 3); // number of pixels before byte boundary
1041 if (before == 4)
1042 before = 0;
1043 lUInt16 w = (x1 - x0 - before);
1044 lUInt16 after = (w & 3); // number of pixels after byte boundary
1045 w >>= 2;
1046 before = fill_masks1[before];
1047 after = fill_masks2[after];
1048 for (int y = y0; y < y1; y++) {
1049 lUInt8 *dst = line;
1050 if (before) {
1051 lUInt8 color = GET_INVERTED_BYTE(dst[0]);
1052 dst[0] = ((dst[0] & ~before) | (color & before));
1053 dst++;
1054 }
1055 for (int x = 0; x < w; x++) {
1056 dst[x] = GET_INVERTED_BYTE(dst[x]);
1057 }
1058 dst += w;
1059 if (after) {
1060 lUInt8 color = GET_INVERTED_BYTE(dst[0]);
1061 dst[0] = ((dst[0] & ~after) | (color & after));
1062 }
1063 line += _rowsize;
1064 }
1065 }
1066 #if 0
1067 else if (_bpp == 4) { // 3, 4, 8
1068 lUInt8 * line = GetScanLine(y0);
1069 for (int y=y0; y<y1; y++) {
1070 for (int x=x0; x<x1; x++) {
1071 lUInt8 value = line[x];
1072 if (value == 0 || value == 0xF0)
1073 line[x] = ~value;
1074 }
1075 line += _rowsize;
1076 }
1077 }
1078 #endif
1079 else { // 3, 4, 8
1080 lUInt8 * line = GetScanLine(y0);
1081 for (int y=y0; y<y1; y++) {
1082 for (int x=x0; x<x1; x++)
1083 line[x] ^= 0xFF;
1084 line += _rowsize;
1085 }
1086 }
1087 CHECK_GUARD_BYTE;
1088 }
Resize(int dx,int dy)1089 void LVGrayDrawBuf::Resize( int dx, int dy )
1090 {
1091 if (!_ownData) {
1092 _data = NULL;
1093 _ownData = false;
1094 } else if (_data) {
1095 CHECK_GUARD_BYTE;
1096 free(_data);
1097 _data = NULL;
1098 }
1099 _dx = dx;
1100 _dy = dy;
1101 _rowsize = _bpp<=2 ? (_dx * _bpp + 7) / 8 : _dx;
1102 if (dx > 0 && dy > 0) {
1103 _data = (unsigned char *)calloc(_rowsize * _dy + 1, sizeof(*_data));
1104 _data[_rowsize * _dy] = GUARD_BYTE;
1105 } else {
1106 Clear(0);
1107 }
1108 SetClipRect( NULL );
1109 }
1110
1111 /// returns white pixel value
GetWhiteColor()1112 lUInt32 LVGrayDrawBuf::GetWhiteColor()
1113 {
1114 return 0xFFFFFF;
1115 /*
1116 #if (GRAY_INVERSE==1)
1117 return 0;
1118 #else
1119 return (1<<_bpp) - 1;
1120 #endif
1121 */
1122 }
1123 /// returns black pixel value
GetBlackColor()1124 lUInt32 LVGrayDrawBuf::GetBlackColor()
1125 {
1126 return 0;
1127 /*
1128 #if (GRAY_INVERSE==1)
1129 return (1<<_bpp) - 1;
1130 #else
1131 return 0;
1132 #endif
1133 */
1134 }
1135
LVGrayDrawBuf(int dx,int dy,int bpp,void * auxdata)1136 LVGrayDrawBuf::LVGrayDrawBuf(int dx, int dy, int bpp, void * auxdata )
1137 : LVBaseDrawBuf(), _bpp(bpp), _ownData(true)
1138 {
1139 _dx = dx;
1140 _dy = dy;
1141 _bpp = bpp;
1142 _rowsize = (bpp<=2) ? (_dx * _bpp + 7) / 8 : _dx;
1143
1144 _backgroundColor = GetWhiteColor(); // NOLINT: Call to virtual function during construction
1145 _textColor = GetBlackColor(); // NOLINT
1146
1147 if ( auxdata ) {
1148 _data = (lUInt8 *) auxdata;
1149 _ownData = false;
1150 } else if (_dx && _dy) {
1151 _data = (lUInt8 *) calloc(_rowsize * _dy + 1, sizeof(*_data));
1152 _data[_rowsize * _dy] = GUARD_BYTE;
1153 }
1154 SetClipRect( NULL );
1155 CHECK_GUARD_BYTE;
1156 }
1157
~LVGrayDrawBuf()1158 LVGrayDrawBuf::~LVGrayDrawBuf()
1159 {
1160 if (_data && _ownData ) {
1161 CHECK_GUARD_BYTE;
1162 free( _data );
1163 }
1164 }
DrawLine(int x0,int y0,int x1,int y1,lUInt32 color0,int length1,int length2,int direction)1165 void LVGrayDrawBuf::DrawLine(int x0, int y0, int x1, int y1, lUInt32 color0,int length1,int length2,int direction)
1166 {
1167 if (x0<_clip.left)
1168 x0 = _clip.left;
1169 if (y0<_clip.top)
1170 y0 = _clip.top;
1171 if (x1>_clip.right)
1172 x1 = _clip.right;
1173 if (y1>_clip.bottom)
1174 y1 = _clip.bottom;
1175 if (x0>=x1 || y0>=y1)
1176 return;
1177 lUInt8 color = rgbToGrayMask( color0, _bpp );
1178 #if (GRAY_INVERSE==1)
1179 color ^= 0xFF;
1180 #endif
1181
1182 for (int y=y0; y<y1; y++)
1183 {
1184 if (_bpp==1) {
1185 for (int x=x0; x<x1; x++)
1186 {
1187 lUInt8 * line = GetScanLine(y);
1188 if (direction==0 &&x%(length1+length2)<length1)line[x] = color;
1189 if (direction==1 &&y%(length1+length2)<length1)line[x] = color;
1190 }
1191 } else if (_bpp==2) {
1192 for (int x=x0; x<x1; x++)
1193 {
1194 lUInt8 * line = GetScanLine(y);
1195 if (direction==0 &&x%(length1+length2)<length1)line[x] = color;
1196 if (direction==1 &&y%(length1+length2)<length1)line[x] = color;
1197 }
1198 } else { // 3, 4, 8
1199 for (int x=x0; x<x1; x++)
1200 {
1201 lUInt8 * line = GetScanLine(y);
1202 if (direction==0 &&x%(length1+length2)<length1)line[x] = color;
1203 if (direction==1 &&y%(length1+length2)<length1)line[x] = color;
1204 }
1205 }
1206 }
1207 }
Draw(int x,int y,const lUInt8 * bitmap,int width,int height,lUInt32 *)1208 void LVGrayDrawBuf::Draw( int x, int y, const lUInt8 * bitmap, int width, int height, lUInt32 * )
1209 {
1210 //int buf_width = _dx; /* 2bpp */
1211 int initial_height = height;
1212 int bx = 0;
1213 int by = 0;
1214 int xx;
1215 int bmp_width = width;
1216 lUInt8 * dst;
1217 lUInt8 * dstline;
1218 const lUInt8 * src;
1219 int shift, shift0;
1220
1221 if (x<_clip.left)
1222 {
1223 width += x-_clip.left;
1224 bx -= x-_clip.left;
1225 x = _clip.left;
1226 if (width<=0)
1227 return;
1228 }
1229 if (y<_clip.top)
1230 {
1231 height += y-_clip.top;
1232 by -= y-_clip.top;
1233 y = _clip.top;
1234 if (_hidePartialGlyphs && height<=initial_height/2) // HIDE PARTIAL VISIBLE GLYPHS
1235 return;
1236 if (height<=0)
1237 return;
1238 }
1239 if (x + width > _clip.right)
1240 {
1241 width = _clip.right - x;
1242 }
1243 if (width<=0)
1244 return;
1245 if (y + height > _clip.bottom)
1246 {
1247 if (_hidePartialGlyphs && height<=initial_height/2) // HIDE PARTIAL VISIBLE GLYPHS
1248 return;
1249 int clip_bottom = _clip.bottom;
1250 if ( _hidePartialGlyphs )
1251 clip_bottom = this->_dy;
1252 if ( y+height > clip_bottom)
1253 height = clip_bottom - y;
1254 }
1255 if (height<=0)
1256 return;
1257
1258 int bytesPerRow = _rowsize;
1259 if ( _bpp==2 ) {
1260 dstline = _data + bytesPerRow*y + (x >> 2);
1261 shift0 = (x & 3);
1262 } else if (_bpp==1) {
1263 dstline = _data + bytesPerRow*y + (x >> 3);
1264 shift0 = (x & 7);
1265 } else {
1266 dstline = _data + bytesPerRow*y + x;
1267 shift0 = 0;// not used
1268 }
1269 dst = dstline;
1270
1271 bitmap += bx + by*bmp_width;
1272 shift = shift0;
1273
1274
1275 lUInt8 color = rgbToGrayMask(GetTextColor(), _bpp);
1276 // bool white = (color & 0x80) ?
1277 //#if (GRAY_INVERSE==1)
1278 // false : true;
1279 //#else
1280 // true : false;
1281 //#endif
1282 for (;height;height--)
1283 {
1284 src = bitmap;
1285
1286 if ( _bpp==2 ) {
1287 // foreground color
1288 lUInt8 cl = (lUInt8)(rgbToGray(GetTextColor()) >> 6); // 0..3
1289 //cl ^= 0x03;
1290 for (xx = width; xx>0; --xx)
1291 {
1292 lUInt8 opaque = (*src >> 4) & 0x0F; // 0..15
1293 if ( opaque>0x3 ) {
1294 int shift2 = shift<<1;
1295 int shift2i = 6-shift2;
1296 lUInt8 mask = 0xC0 >> shift2;
1297 lUInt8 dstcolor;
1298 if ( opaque>=0xC ) {
1299 dstcolor = cl;
1300 } else {
1301 lUInt8 bgcolor = ((*dst)>>shift2i)&3; // 0..3
1302 dstcolor = ((opaque*cl + (15-opaque)*bgcolor)>>4)&3;
1303 }
1304 *dst = (*dst & ~mask) | (dstcolor<<shift2i);
1305 }
1306 src++;
1307 /* next pixel */
1308 if (!(++shift & 3))
1309 {
1310 shift = 0;
1311 dst++;
1312 }
1313 }
1314 } else if ( _bpp==1 ) {
1315 for (xx = width; xx>0; --xx)
1316 {
1317 #if (GRAY_INVERSE==1)
1318 *dst |= (( (*src++) & 0x80 ) >> ( shift ));
1319 #else
1320 *dst &= ~(( ((*src++) & 0x80) ) >> ( shift ));
1321 #endif
1322 /* next pixel */
1323 if (!(++shift & 7))
1324 {
1325 shift = 0;
1326 dst++;
1327 }
1328 }
1329 } else { // 3,4,8
1330 int mask = ((1<<_bpp)-1)<<(8-_bpp);
1331 for (xx = width; xx>0; --xx)
1332 {
1333 lUInt8 b = (*src++);
1334 if ( b ) {
1335 if ( b>=mask )
1336 *dst = color;
1337 else {
1338 int alpha = b ^ 0xFF;
1339 ApplyAlphaGray( *dst, color, alpha, _bpp );
1340 }
1341 }
1342 dst++;
1343 }
1344 }
1345 /* new dest line */
1346 bitmap += bmp_width;
1347 dstline += bytesPerRow;
1348 dst = dstline;
1349 shift = shift0;
1350 }
1351 CHECK_GUARD_BYTE;
1352 }
1353
SetClipRect(const lvRect * clipRect)1354 void LVBaseDrawBuf::SetClipRect( const lvRect * clipRect )
1355 {
1356 if (clipRect)
1357 {
1358 _clip = *clipRect;
1359 if (_clip.left<0)
1360 _clip.left = 0;
1361 if (_clip.top<0)
1362 _clip.top = 0;
1363 if (_clip.right>_dx)
1364 _clip.right = _dx;
1365 if (_clip.bottom > _dy)
1366 _clip.bottom = _dy;
1367 }
1368 else
1369 {
1370 _clip.top = 0;
1371 _clip.left = 0;
1372 _clip.right = _dx;
1373 _clip.bottom = _dy;
1374 }
1375 }
1376
GetScanLine(int y)1377 lUInt8 * LVGrayDrawBuf::GetScanLine( int y )
1378 {
1379 return _data + _rowsize*y;
1380 }
1381
Invert()1382 void LVGrayDrawBuf::Invert()
1383 {
1384 int sz = _rowsize * _dy;
1385 for (int i=sz-1; i>=0; i--)
1386 _data[i] = ~_data[i];
1387 }
1388
ConvertToBitmap(bool flgDither)1389 void LVGrayDrawBuf::ConvertToBitmap(bool flgDither)
1390 {
1391 if (_bpp==1)
1392 return;
1393 // TODO: implement for byte per pixel mode
1394 int sz = GetRowSize();
1395 lUInt8 * bitmap = (lUInt8*) calloc(sz, sizeof(*bitmap));
1396 if (flgDither)
1397 {
1398 static const lUInt8 cmap[4][4] = {
1399 { 0, 0, 0, 0},
1400 { 0, 0, 1, 0},
1401 { 0, 1, 0, 1},
1402 { 1, 1, 1, 1},
1403 };
1404 for (int y=0; y<_dy; y++)
1405 {
1406 lUInt8 * src = GetScanLine(y);
1407 lUInt8 * dst = bitmap + ((_dx+7)/8)*y;
1408 for (int x=0; x<_dx; x++) {
1409 int cl = (src[x>>2] >> (6-((x&3)*2)))&3;
1410 cl = cmap[cl][ (x&1) + ((y&1)<<1) ];
1411 if (cmap[cl][ (x&1) + ((y&1)<<1) ])
1412 dst[x>>3] |= 0x80>>(x&7);
1413 }
1414 }
1415 }
1416 else
1417 {
1418 for (int y=0; y<_dy; y++)
1419 {
1420 lUInt8 * src = GetScanLine(y);
1421 lUInt8 * dst = bitmap + ((_dx+7)/8)*y;
1422 for (int x=0; x<_dx; x++) {
1423 int cl = (src[x>>2] >> (7-((x&3)*2)))&1;
1424 if (cl)
1425 dst[x>>3] |= 0x80>>(x&7);
1426 }
1427 }
1428 }
1429 free( _data );
1430 _data = bitmap;
1431 _bpp = 1;
1432 _rowsize = (_dx+7)/8;
1433 CHECK_GUARD_BYTE;
1434 }
1435
1436 //=======================================================
1437 // 32-bit RGB buffer
1438 //=======================================================
1439
1440 /// invert image
Invert()1441 void LVColorDrawBuf::Invert()
1442 {
1443 }
1444
1445 /// get buffer bits per pixel
GetBitsPerPixel()1446 int LVColorDrawBuf::GetBitsPerPixel()
1447 {
1448 return _bpp;
1449 }
1450
Draw(LVImageSourceRef img,int x,int y,int width,int height,bool dither)1451 void LVColorDrawBuf::Draw( LVImageSourceRef img, int x, int y, int width, int height, bool dither )
1452 {
1453 //fprintf( stderr, "LVColorDrawBuf::Draw( img(%d, %d), %d, %d, %d, %d\n", img->GetWidth(), img->GetHeight(), x, y, width, height );
1454 LVImageScaledDrawCallback drawcb( this, img, x, y, width, height, dither, _invertImages, _smoothImages );
1455 img->Decode( &drawcb );
1456 _drawnImagesCount++;
1457 _drawnImagesSurface += width*height;
1458 }
1459
1460 /// fills buffer with specified color
Clear(lUInt32 color)1461 void LVColorDrawBuf::Clear( lUInt32 color )
1462 {
1463 if ( _bpp==16 ) {
1464 lUInt16 cl16 = rgb888to565(color);
1465 for (int y=0; y<_dy; y++)
1466 {
1467 lUInt16 * line = (lUInt16 *)GetScanLine(y);
1468 for (int x=0; x<_dx; x++)
1469 {
1470 line[x] = cl16;
1471 }
1472 }
1473 } else {
1474 for (int y=0; y<_dy; y++)
1475 {
1476 lUInt32 * line = (lUInt32 *)GetScanLine(y);
1477 for (int x=0; x<_dx; x++)
1478 {
1479 line[x] = RevRGBA(color);
1480 }
1481 }
1482 }
1483 }
1484
1485
1486 /// get pixel value
GetPixel(int x,int y)1487 lUInt32 LVColorDrawBuf::GetPixel( int x, int y )
1488 {
1489 if (!_data || y<0 || x<0 || y>=_dy || x>=_dx)
1490 return 0;
1491 if ( _bpp==16 )
1492 return rgb565to888(((lUInt16*)GetScanLine(y))[x]);
1493 return ((lUInt32*)GetScanLine(y))[x];
1494 }
1495
AA(lUInt32 color)1496 inline static lUInt32 AA(lUInt32 color) {
1497 return (color >> 24) & 0xFF;
1498 }
1499
RR(lUInt32 color)1500 inline static lUInt32 RR(lUInt32 color) {
1501 return (color >> 16) & 0xFF;
1502 }
1503
GG(lUInt32 color)1504 inline static lUInt32 GG(lUInt32 color) {
1505 return (color >> 8) & 0xFF;
1506 }
1507
BB(lUInt32 color)1508 inline static lUInt32 BB(lUInt32 color) {
1509 return color & 0xFF;
1510 }
1511
RRGGBB(lUInt32 r,lUInt32 g,lUInt32 b)1512 inline static lUInt32 RRGGBB(lUInt32 r, lUInt32 g, lUInt32 b) {
1513 return ((r & 0xFF) << 16) | ((g & 0xFF) << 8) | (b & 0xFF);
1514 }
1515
AARRGGBB(lUInt32 a,lUInt32 r,lUInt32 g,lUInt32 b)1516 inline static lUInt32 AARRGGBB(lUInt32 a, lUInt32 r, lUInt32 g, lUInt32 b) {
1517 return ((a & 0xFF) << 24) | ((r & 0xFF) << 16) | ((g & 0xFF) << 8) | (b & 0xFF);
1518 }
1519
1520
1521
1522 /// get linearly interpolated pixel value (coordinates are fixed floating points *16)
GetInterpolatedColor(int x16,int y16)1523 lUInt32 LVBaseDrawBuf::GetInterpolatedColor(int x16, int y16)
1524 {
1525 int shx = x16 & 0x0F;
1526 int shy = y16 & 0x0F;
1527 int nshx = 16 - shx;
1528 int nshy = 16 - shy;
1529 int x = x16 >> 4;
1530 int y = y16 >> 4;
1531 int x1 = x + 1;
1532 int y1 = y + 1;
1533 if (x1 >= _dx)
1534 x1 = x;
1535 if (y1 >= _dy)
1536 y1 = y;
1537 lUInt32 cl00 = GetPixel(x, y);
1538 lUInt32 cl01 = GetPixel(x1, y);
1539 lUInt32 cl10 = GetPixel(x, y1);
1540 lUInt32 cl11 = GetPixel(x1, y1);
1541 lUInt32 a = (((AA(cl00) * nshx + AA(cl01) * shx) * nshy +
1542 (AA(cl10) * nshx + AA(cl11) * shx) * shy) >> 8) & 0xFF;
1543 lUInt32 r = (((RR(cl00) * nshx + RR(cl01) * shx) * nshy +
1544 (RR(cl10) * nshx + RR(cl11) * shx) * shy) >> 8) & 0xFF;
1545 lUInt32 g = (((GG(cl00) * nshx + GG(cl01) * shx) * nshy +
1546 (GG(cl10) * nshx + GG(cl11) * shx) * shy) >> 8) & 0xFF;
1547 lUInt32 b = (((BB(cl00) * nshx + BB(cl01) * shx) * nshy +
1548 (BB(cl10) * nshx + BB(cl11) * shx) * shy) >> 8) & 0xFF;
1549 return AARRGGBB(a, r, g, b);
1550 }
1551
1552 /// get average pixel value for area (coordinates are fixed floating points *16)
GetAvgColor(lvRect & rc16)1553 lUInt32 LVBaseDrawBuf::GetAvgColor(lvRect & rc16)
1554 {
1555 if (!_data)
1556 return 0;
1557 int x0 = rc16.left;
1558 int y0 = rc16.top;
1559 int x1 = rc16.right;
1560 int y1 = rc16.bottom;
1561 if (x0 < 0)
1562 x0 = 0;
1563 if (y0 < 0)
1564 y0 = 0;
1565 int maxxx = _dx << 4;
1566 int maxyy = _dy << 4;
1567 if (x1 > maxxx)
1568 x1 = maxxx;
1569 if (y1 > maxyy)
1570 y1 = maxyy;
1571 if (x0 > x1 || y0 > y1)
1572 return 0; // invalid rectangle
1573 int rs = 0;
1574 int gs = 0;
1575 int bs = 0;
1576 int s = 0;
1577 int maxy = ((y1 - 1) >> 4);
1578 int maxx = ((x1 - 1) >> 4);
1579 for (int y = (y0 >> 4); y <= maxy; y++ ) {
1580 int yy0 = y << 4;
1581 int yy1 = (y + 1) << 4;
1582 if (yy0 < y0)
1583 yy0 = y0;
1584 if (yy1 > y1)
1585 yy1 = y1;
1586 int ys = yy1 - yy0; // 0..16
1587 if (ys < 1)
1588 continue;
1589 for (int x = (x0 >> 4); x <= maxx; x++ ) {
1590
1591 int xx0 = x << 4;
1592 int xx1 = (x + 1) << 4;
1593 if (xx0 < x0)
1594 xx0 = x0;
1595 if (xx1 > x1)
1596 xx1 = x1;
1597 int xs = xx1 - xx0; // 0..16
1598 if (xs < 1)
1599 continue;
1600
1601 int mult = xs * ys;
1602
1603 lUInt32 pixel = GetPixel(x, y);
1604 int r = (pixel >> 16) & 0xFF;
1605 int g = (pixel >> 8) & 0xFF;
1606 int b = pixel & 0xFF;
1607
1608 rs += r * mult;
1609 gs += g * mult;
1610 bs += b * mult;
1611 s += mult;
1612 }
1613 }
1614
1615 if (s == 0)
1616 return 0;
1617 rs = (rs / s) & 0xFF;
1618 gs = (gs / s) & 0xFF;
1619 bs = (bs / s) & 0xFF;
1620 return (rs << 16) | (gs << 8) | bs;
1621 }
1622
1623 /// fills rectangle with specified color
FillRect(int x0,int y0,int x1,int y1,lUInt32 color)1624 void LVColorDrawBuf::FillRect( int x0, int y0, int x1, int y1, lUInt32 color )
1625 {
1626 if (x0<_clip.left)
1627 x0 = _clip.left;
1628 if (y0<_clip.top)
1629 y0 = _clip.top;
1630 if (x1>_clip.right)
1631 x1 = _clip.right;
1632 if (y1>_clip.bottom)
1633 y1 = _clip.bottom;
1634 if (x0>=x1 || y0>=y1)
1635 return;
1636 int alpha = (color >> 24) & 0xFF;
1637 if ( _bpp==16 ) {
1638 lUInt16 cl16 = rgb888to565(color);
1639 for (int y=y0; y<y1; y++)
1640 {
1641 lUInt16 * line = (lUInt16 *)GetScanLine(y);
1642 for (int x=x0; x<x1; x++)
1643 {
1644 if (alpha)
1645 ApplyAlphaRGB565(line[x], cl16, alpha);
1646 else
1647 line[x] = cl16;
1648 }
1649 }
1650 } else {
1651 for (int y=y0; y<y1; y++)
1652 {
1653 lUInt32 * line = (lUInt32 *)GetScanLine(y);
1654 for (int x=x0; x<x1; x++)
1655 {
1656 if (alpha)
1657 ApplyAlphaRGB(line[x], RevRGB(color), alpha);
1658 else
1659 line[x] = RevRGBA(color);
1660 }
1661 }
1662 }
1663 }
1664
DrawLine(int x0,int y0,int x1,int y1,lUInt32 color0,int length1,int length2,int direction)1665 void LVColorDrawBuf::DrawLine(int x0,int y0,int x1,int y1,lUInt32 color0 ,int length1,int length2,int direction)
1666 {
1667 if (x0<_clip.left)
1668 x0 = _clip.left;
1669 if (y0<_clip.top)
1670 y0 = _clip.top;
1671 if (x1>_clip.right)
1672 x1 = _clip.right;
1673 if (y1>_clip.bottom)
1674 y1 = _clip.bottom;
1675 if (x0>=x1 || y0>=y1)
1676 return;
1677 if ( _bpp==16 ) {
1678 lUInt16 cl16 = rgb888to565(color0);
1679 for (int y=y0; y<y1; y++)
1680 {
1681 lUInt16 * line = (lUInt16 *)GetScanLine(y);
1682 for (int x=x0; x<x1; x++)
1683 {
1684 if (direction==0 &&x%(length1+length2)<length1)line[x] = cl16;
1685 if (direction==1 &&y%(length1+length2)<length1)line[x] = cl16;
1686 }
1687 }
1688 } else {
1689 for (int y=y0; y<y1; y++)
1690 {
1691 lUInt32 * line = (lUInt32 *)GetScanLine(y);
1692 for (int x=x0; x<x1; x++)
1693 {
1694 if (direction==0 &&x%(length1+length2)<length1)line[x] = RevRGBA(color0);
1695 if (direction==1 &&y%(length1+length2)<length1)line[x] = RevRGBA(color0);
1696 }
1697 }
1698 }
1699 }
1700 /// fills rectangle with specified color
FillRectPattern(int x0,int y0,int x1,int y1,lUInt32 color0,lUInt32 color1,lUInt8 * pattern)1701 void LVColorDrawBuf::FillRectPattern( int x0, int y0, int x1, int y1, lUInt32 color0, lUInt32 color1, lUInt8 * pattern )
1702 {
1703 if (x0<_clip.left)
1704 x0 = _clip.left;
1705 if (y0<_clip.top)
1706 y0 = _clip.top;
1707 if (x1>_clip.right)
1708 x1 = _clip.right;
1709 if (y1>_clip.bottom)
1710 y1 = _clip.bottom;
1711 if (x0>=x1 || y0>=y1)
1712 return;
1713 if ( _bpp==16 ) {
1714 lUInt16 cl16_0 = rgb888to565(color0);
1715 lUInt16 cl16_1 = rgb888to565(color1);
1716 for (int y=y0; y<y1; y++)
1717 {
1718 lUInt8 patternMask = pattern[y & 3];
1719 lUInt16 * line = (lUInt16 *)GetScanLine(y);
1720 for (int x=x0; x<x1; x++)
1721 {
1722 lUInt8 patternBit = (patternMask << (x&7)) & 0x80;
1723 line[x] = patternBit ? cl16_1 : cl16_0;
1724 }
1725 }
1726 } else {
1727 for (int y=y0; y<y1; y++)
1728 {
1729 lUInt8 patternMask = pattern[y & 3];
1730 lUInt32 * line = (lUInt32 *)GetScanLine(y);
1731 for (int x=x0; x<x1; x++)
1732 {
1733 lUInt8 patternBit = (patternMask << (x&7)) & 0x80;
1734 line[x] = patternBit ? RevRGBA(color1) : RevRGBA(color0);
1735 }
1736 }
1737 }
1738 }
1739
1740 /// sets new size
Resize(int dx,int dy)1741 void LVColorDrawBuf::Resize( int dx, int dy )
1742 {
1743 if ( dx==_dx && dy==_dy ) {
1744 //CRLog::trace("LVColorDrawBuf::Resize : no resize, not changed");
1745 return;
1746 }
1747 if ( !_ownData ) {
1748 //CRLog::trace("LVColorDrawBuf::Resize : no resize, own data");
1749 return;
1750 }
1751 //CRLog::trace("LVColorDrawBuf::Resize : resizing %d x %d to %d x %d", _dx, _dy, dx, dy);
1752 // delete old bitmap
1753 if ( _dx>0 && _dy>0 && _data )
1754 {
1755 #if !defined(__SYMBIAN32__) && defined(_WIN32) && !defined(QT_GL)
1756 if (_drawbmp)
1757 DeleteObject( _drawbmp );
1758 if (_drawdc)
1759 DeleteObject( _drawdc );
1760 _drawbmp = NULL;
1761 _drawdc = NULL;
1762 #else
1763 free(_data);
1764 #endif
1765 _data = NULL;
1766 _rowsize = 0;
1767 _dx = 0;
1768 _dy = 0;
1769 }
1770
1771 if (dx>0 && dy>0)
1772 {
1773 // create new bitmap
1774 _dx = dx;
1775 _dy = dy;
1776 _rowsize = dx*(_bpp>>3);
1777 #if !defined(__SYMBIAN32__) && defined(_WIN32) && !defined(QT_GL)
1778 BITMAPINFO bmi = { 0 };
1779 bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
1780 bmi.bmiHeader.biWidth = _dx;
1781 bmi.bmiHeader.biHeight = _dy;
1782 bmi.bmiHeader.biPlanes = 1;
1783 bmi.bmiHeader.biBitCount = 32;
1784 bmi.bmiHeader.biCompression = BI_RGB;
1785 bmi.bmiHeader.biSizeImage = 0;
1786 bmi.bmiHeader.biXPelsPerMeter = 1024;
1787 bmi.bmiHeader.biYPelsPerMeter = 1024;
1788 bmi.bmiHeader.biClrUsed = 0;
1789 bmi.bmiHeader.biClrImportant = 0;
1790
1791 _drawbmp = CreateDIBSection( NULL, &bmi, DIB_RGB_COLORS, (void**)(&_data), NULL, 0 );
1792 _drawdc = CreateCompatibleDC(NULL);
1793 SelectObject(_drawdc, _drawbmp);
1794 memset( _data, 0, _rowsize * _dy );
1795 #else
1796 _data = (lUInt8 *)calloc((_bpp>>3) * _dx * _dy, sizeof(*_data));
1797 #endif
1798 }
1799 SetClipRect( NULL );
1800 }
1801
InvertRect(int x0,int y0,int x1,int y1)1802 void LVColorDrawBuf::InvertRect(int x0, int y0, int x1, int y1)
1803 {
1804 if (x0<_clip.left)
1805 x0 = _clip.left;
1806 if (y0<_clip.top)
1807 y0 = _clip.top;
1808 if (x1>_clip.right)
1809 x1 = _clip.right;
1810 if (y1>_clip.bottom)
1811 y1 = _clip.bottom;
1812 if (x0>=x1 || y0>=y1)
1813 return;
1814
1815 if (_bpp==16) {
1816 for (int y=y0; y<y1; y++) {
1817 lUInt16 * line = (lUInt16 *)GetScanLine(y);
1818 for (int x=x0; x<x1; x++) {
1819 line[x] ^= 0xFFFF;
1820 }
1821 }
1822 }
1823 else {
1824 for (int y=y0; y<y1; y++) {
1825 lUInt32 * line = (lUInt32 *)GetScanLine(y);
1826 for (int x=x0; x<x1; x++) {
1827 line[x] ^= 0x00FFFFFF;
1828 }
1829 }
1830 }
1831 }
1832
1833 /// draws bitmap (1 byte per pixel) using specified palette
Draw(int x,int y,const lUInt8 * bitmap,int width,int height,lUInt32 * palette)1834 void LVColorDrawBuf::Draw( int x, int y, const lUInt8 * bitmap, int width, int height, lUInt32 * palette )
1835 {
1836 if ( !_data )
1837 return;
1838 //int buf_width = _dx; /* 2bpp */
1839 int initial_height = height;
1840 int bx = 0;
1841 int by = 0;
1842 int xx;
1843 int bmp_width = width;
1844 lUInt32 bmpcl = palette?palette[0]:GetTextColor();
1845 const lUInt8 * src;
1846
1847 if (x<_clip.left)
1848 {
1849 width += x-_clip.left;
1850 bx -= x-_clip.left;
1851 x = _clip.left;
1852 if (width<=0)
1853 return;
1854 }
1855 if (y<_clip.top)
1856 {
1857 height += y-_clip.top;
1858 by -= y-_clip.top;
1859 y = _clip.top;
1860 if (_hidePartialGlyphs && height<=initial_height/2) // HIDE PARTIAL VISIBLE GLYPHS
1861 return;
1862 if (height<=0)
1863 return;
1864 }
1865 if (x + width > _clip.right)
1866 {
1867 width = _clip.right - x;
1868 }
1869 if (width<=0)
1870 return;
1871 if (y + height > _clip.bottom)
1872 {
1873 if (_hidePartialGlyphs && height<=initial_height/2) // HIDE PARTIAL VISIBLE GLYPHS
1874 return;
1875 int clip_bottom = _clip.bottom;
1876 if (_hidePartialGlyphs )
1877 clip_bottom = this->_dy;
1878 if ( y+height > clip_bottom)
1879 height = clip_bottom - y;
1880 }
1881 if (height<=0)
1882 return;
1883
1884 bitmap += bx + by*bmp_width;
1885
1886 if ( _bpp==16 ) {
1887
1888 lUInt16 bmpcl16 = rgb888to565(bmpcl);
1889
1890 lUInt16 * dst;
1891 lUInt16 * dstline;
1892
1893
1894 for (;height;height--)
1895 {
1896 src = bitmap;
1897 dstline = ((lUInt16*)GetScanLine(y++)) + x;
1898 dst = dstline;
1899
1900 if ( !dst ) { // Should not happen, but avoid clang-tidy warning below
1901 bitmap += bmp_width;
1902 continue;
1903 }
1904
1905 for (xx = width; xx>0; --xx)
1906 {
1907 lUInt32 opaque = ((*(src++))>>4)&0x0F;
1908 if ( opaque>=0xF )
1909 *dst = bmpcl16;
1910 else if ( opaque>0 ) {
1911 lUInt32 alpha = 0xF-opaque;
1912 lUInt16 cl1 = (lUInt16)(((alpha*((*dst)&0xF81F) + opaque*(bmpcl16&0xF81F))>>4) & 0xF81F);
1913 lUInt16 cl2 = (lUInt16)(((alpha*((*dst)&0x07E0) + opaque*(bmpcl16&0x07E0))>>4) & 0x07E0);
1914 *dst = cl1 | cl2;
1915 }
1916 /* next pixel */
1917 dst++;
1918 }
1919 /* new dest line */
1920 bitmap += bmp_width;
1921 }
1922
1923 } else {
1924
1925
1926 lUInt32 bmpcl32 = RevRGBA(bmpcl);
1927
1928 lUInt32 * dst;
1929 lUInt32 * dstline;
1930
1931
1932 for (;height;height--)
1933 {
1934 src = bitmap;
1935 dstline = ((lUInt32*)GetScanLine(y++)) + x;
1936 dst = dstline;
1937
1938 if ( !dst ) { // Should not happen, but avoid clang-tidy warning below
1939 bitmap += bmp_width;
1940 continue;
1941 }
1942
1943 for (xx = width; xx>0; --xx)
1944 {
1945 lUInt32 opaque = ((*(src++))>>1)&0x7F;
1946 if ( opaque>=0x78 )
1947 *dst = bmpcl32;
1948 else if ( opaque>0 ) {
1949 lUInt32 alpha = 0x7F-opaque;
1950 lUInt32 cl1 = ((alpha*((*dst)&0xFF00FF) + opaque*(bmpcl32&0xFF00FF))>>7) & 0xFF00FF;
1951 lUInt32 cl2 = ((alpha*((*dst)&0x00FF00) + opaque*(bmpcl32&0x00FF00))>>7) & 0x00FF00;
1952 *dst = cl1 | cl2;
1953 }
1954 /* next pixel */
1955 dst++;
1956 }
1957 /* new dest line */
1958 bitmap += bmp_width;
1959 }
1960 }
1961 }
1962
1963 #if !defined(__SYMBIAN32__) && defined(_WIN32) && !defined(QT_GL)
1964 /// draws buffer content to DC doing color conversion if necessary
DrawTo(HDC dc,int x,int y,int options,lUInt32 * palette)1965 void LVGrayDrawBuf::DrawTo( HDC dc, int x, int y, int options, lUInt32 * palette )
1966 {
1967 if (!dc || !_data)
1968 return;
1969 LVColorDrawBuf buf( _dx, 1 );
1970 lUInt32 * dst = (lUInt32 *)buf.GetScanLine(0);
1971 #if (GRAY_INVERSE==1)
1972 static lUInt32 def_pal_1bpp[2] = {0xFFFFFF, 0x000000};
1973 static lUInt32 def_pal_2bpp[4] = {0xFFFFFF, 0xAAAAAA, 0x555555, 0x000000};
1974 #else
1975 static lUInt32 def_pal_1bpp[2] = {0x000000, 0xFFFFFF};
1976 static lUInt32 def_pal_2bpp[4] = {0x000000, 0x555555, 0xAAAAAA, 0xFFFFFF};
1977 #endif
1978 lUInt32 pal[256];
1979 if ( _bpp<=8 ) {
1980 int n = 1<<_bpp;
1981 for ( int i=0; i<n; i++ ) {
1982 int c = 255 * i / (n-1);
1983 pal[i] = c | (c<<8) | (c<<16);
1984 }
1985 }
1986 if (!palette)
1987 palette = (_bpp==1) ? def_pal_1bpp : def_pal_2bpp;
1988 for (int yy=0; yy<_dy; yy++)
1989 {
1990 lUInt8 * src = GetScanLine(yy);
1991 for (int xx=0; xx<_dx; xx++)
1992 {
1993 //
1994 if (_bpp==1)
1995 {
1996 int shift = 7-(xx&7);
1997 int x0 = xx >> 3;
1998 dst[xx] = palette[ (src[x0]>>shift) & 1];
1999 }
2000 else if (_bpp==2)
2001 {
2002 int shift = 6-((xx&3)<<1);
2003 int x0 = xx >> 2;
2004 dst[xx] = palette[ (src[x0]>>shift) & 3];
2005 }
2006 else // 3,4,8
2007 {
2008 int index = (src[xx] >> (8-_bpp)) & ((1<<_bpp)-1);
2009 dst[xx] = pal[ index ];
2010 }
2011 }
2012 BitBlt( dc, x, y+yy, _dx, 1, buf.GetDC(), 0, 0, SRCCOPY );
2013 }
2014 }
2015
2016
2017 /// draws buffer content to DC doing color conversion if necessary
DrawTo(HDC dc,int x,int y,int options,lUInt32 * palette)2018 void LVColorDrawBuf::DrawTo( HDC dc, int x, int y, int options, lUInt32 * palette )
2019 {
2020 if (dc!=NULL && _drawdc!=NULL)
2021 BitBlt( dc, x, y, _dx, _dy, _drawdc, 0, 0, SRCCOPY );
2022 }
2023 #endif
2024
2025 /// draws buffer content to another buffer doing color conversion if necessary
DrawTo(LVDrawBuf * buf,int x,int y,int options,lUInt32 * palette)2026 void LVGrayDrawBuf::DrawTo( LVDrawBuf * buf, int x, int y, int options, lUInt32 * palette )
2027 {
2028 CR_UNUSED2(options, palette);
2029 lvRect clip;
2030 buf->GetClipRect(&clip);
2031
2032 if ( !(!clip.isEmpty() || buf->GetBitsPerPixel()!=GetBitsPerPixel() || GetWidth()!=buf->GetWidth() || GetHeight()!=buf->GetHeight()) ) {
2033 // simple copy
2034 memcpy( buf->GetScanLine(0), GetScanLine(0), GetHeight() * GetRowSize() );
2035 return;
2036 }
2037 int bpp = GetBitsPerPixel();
2038 if (buf->GetBitsPerPixel() == 32) {
2039 // support for 32bpp to Gray drawing
2040 for (int yy=0; yy<_dy; yy++)
2041 {
2042 if (y+yy >= clip.top && y+yy < clip.bottom)
2043 {
2044 lUInt8 * src = (lUInt8 *)GetScanLine(yy);
2045 lUInt32 * dst = ((lUInt32 *)buf->GetScanLine(y+yy)) + x;
2046 if (bpp==1)
2047 {
2048 int shift = x & 7;
2049 for (int xx=0; xx<_dx; xx++)
2050 {
2051 if ( x+xx >= clip.left && x+xx < clip.right )
2052 {
2053 lUInt8 cl = (*src << shift) & 0x80;
2054 *dst = cl ? 0xFFFFFF : 0x000000;
2055 }
2056 dst++;
2057 if (++shift >= 8) {
2058 shift = 0;
2059 src++;
2060 }
2061
2062 }
2063 }
2064 else if (bpp==2)
2065 {
2066 int shift = x & 3;
2067 for (int xx=0; xx<_dx; xx++)
2068 {
2069 if ( x+xx >= clip.left && x+xx < clip.right )
2070 {
2071 lUInt32 cl = (*src << (shift<<1)) & 0xC0;
2072 cl = cl | (cl >> 2) | (cl>>4) | (cl>>6);
2073 *dst = cl | (cl << 8) | (cl << 16);
2074 }
2075 dst++;
2076 if (++shift >= 4) {
2077 shift = 0;
2078 src++;
2079 }
2080
2081 }
2082 }
2083 else
2084 {
2085 // byte per pixel
2086 for (int xx=0; xx<_dx; xx++)
2087 {
2088 if ( x+xx >= clip.left && x+xx < clip.right )
2089 {
2090 lUInt32 cl = *src;
2091 if (bpp == 3) {
2092 cl &= 0xE0;
2093 cl = cl | (cl>>3) | (cl>>6);
2094 } else if (bpp == 4) {
2095 cl &= 0xF0;
2096 cl = cl | (cl>>4);
2097 }
2098 *dst = cl | (cl << 8) | (cl << 16);
2099 }
2100 dst++;
2101 src++;
2102 }
2103 }
2104 }
2105 }
2106 return;
2107 }
2108 if (buf->GetBitsPerPixel() == 16) {
2109 // support for 32bpp to Gray drawing
2110 for (int yy=0; yy<_dy; yy++)
2111 {
2112 if (y+yy >= clip.top && y+yy < clip.bottom)
2113 {
2114 lUInt8 * src = (lUInt8 *)GetScanLine(yy);
2115 lUInt16 * dst = ((lUInt16 *)buf->GetScanLine(y+yy)) + x;
2116 if (bpp==1)
2117 {
2118 int shift = x & 7;
2119 for (int xx=0; xx<_dx; xx++)
2120 {
2121 if ( x+xx >= clip.left && x+xx < clip.right )
2122 {
2123 lUInt8 cl = (*src << shift) & 0x80;
2124 *dst = cl ? 0xFFFF : 0x0000;
2125 }
2126 dst++;
2127 if (++shift >= 8) {
2128 shift = 0;
2129 src++;
2130 }
2131
2132 }
2133 }
2134 else if (bpp==2)
2135 {
2136 int shift = x & 3;
2137 for (int xx=0; xx<_dx; xx++)
2138 {
2139 if ( x+xx >= clip.left && x+xx < clip.right )
2140 {
2141 lUInt16 cl = (*src << (shift<<1)) & 0xC0;
2142 cl = cl | (cl >> 2) | (cl>>4) | (cl>>6);
2143 *dst = rgb565(cl, cl, cl);
2144 }
2145 dst++;
2146 if (++shift >= 4) {
2147 shift = 0;
2148 src++;
2149 }
2150
2151 }
2152 }
2153 else
2154 {
2155 // byte per pixel
2156 for (int xx=0; xx<_dx; xx++)
2157 {
2158 if ( x+xx >= clip.left && x+xx < clip.right )
2159 {
2160 lUInt16 cl = *src;
2161 if (bpp == 3) {
2162 cl &= 0xE0;
2163 cl = cl | (cl>>3) | (cl>>6);
2164 } else if (bpp == 4) {
2165 cl &= 0xF0;
2166 cl = cl | (cl>>4);
2167 }
2168 *dst = rgb565(cl, cl, cl);
2169 }
2170 dst++;
2171 src++;
2172 }
2173 }
2174 }
2175 }
2176 return;
2177 }
2178 if (buf->GetBitsPerPixel() != bpp)
2179 return; // not supported yet
2180 for (int yy=0; yy<_dy; yy++)
2181 {
2182 if (y+yy >= clip.top && y+yy < clip.bottom)
2183 {
2184 lUInt8 * src = (lUInt8 *)GetScanLine(yy);
2185 if (bpp==1)
2186 {
2187 int shift = x & 7;
2188 lUInt8 * dst = buf->GetScanLine(y+yy) + (x>>3);
2189 for (int xx=0; xx<_dx; xx+=8)
2190 {
2191 if ( x+xx >= clip.left && x+xx < clip.right )
2192 {
2193 //lUInt8 mask = ~((lUInt8)0xC0>>shift);
2194 lUInt16 cl = (*src << 8)>>shift;
2195 lUInt16 mask = (0xFF00)>>shift;
2196 lUInt8 c = *dst;
2197 c &= ~(mask>>8);
2198 c |= (cl>>8);
2199 *dst = c;
2200 if (mask & 0xFF) {
2201 c = *(dst+1);
2202 c &= ~(mask&0xFF);
2203 c |= (cl&0xFF);
2204 *(dst+1) = c;
2205 }
2206 }
2207 dst++;
2208 src++;
2209 }
2210 }
2211 else if (bpp==2)
2212 {
2213 int shift = (x & 3) * 2;
2214 lUInt8 * dst = buf->GetScanLine(y+yy) + (x>>2);
2215 for (int xx=0; xx<_dx; xx+=4)
2216 {
2217 if ( x+xx >= clip.left && x+xx < clip.right )
2218 {
2219 //lUInt8 mask = ~((lUInt8)0xC0>>shift);
2220 lUInt16 cl = (*src << 8)>>shift;
2221 lUInt16 mask = (0xFF00)>>shift;
2222 lUInt8 c = *dst;
2223 c &= ~(mask>>8);
2224 c |= (cl>>8);
2225 *dst = c;
2226 if (mask & 0xFF) {
2227 c = *(dst+1);
2228 c &= ~(mask&0xFF);
2229 c |= (cl&0xFF);
2230 *(dst+1) = c;
2231 }
2232 }
2233 dst++;
2234 src++;
2235 }
2236 }
2237 else
2238 {
2239 lUInt8 * dst = buf->GetScanLine(y+yy) + x;
2240 for (int xx=0; xx<_dx; xx++)
2241 {
2242 if ( x+xx >= clip.left && x+xx < clip.right )
2243 {
2244 *dst = *src;
2245 }
2246 dst++;
2247 src++;
2248 }
2249 }
2250 }
2251 }
2252 CHECK_GUARD_BYTE;
2253 }
2254
2255 /// draws buffer content to another buffer doing color conversion if necessary
DrawOnTop(LVDrawBuf * buf,int x,int y)2256 void LVGrayDrawBuf::DrawOnTop( LVDrawBuf * buf, int x, int y )
2257 {
2258
2259 lvRect clip;
2260 buf->GetClipRect(&clip);
2261
2262 if ( !(!clip.isEmpty() || buf->GetBitsPerPixel()!=GetBitsPerPixel() || GetWidth()!=buf->GetWidth() || GetHeight()!=buf->GetHeight()) ) {
2263 // simple copy
2264 memcpy( buf->GetScanLine(0), GetScanLine(0), GetHeight() * GetRowSize() );
2265 return;
2266 }
2267 int bpp = GetBitsPerPixel();
2268 if (buf->GetBitsPerPixel() == 32) {
2269 // support for 32bpp to Gray drawing
2270 for (int yy=0; yy<_dy; yy++)
2271 {
2272 if (y+yy >= clip.top && y+yy < clip.bottom)
2273 {
2274 lUInt8 * src = (lUInt8 *)GetScanLine(yy);
2275 lUInt32 * dst = ((lUInt32 *)buf->GetScanLine(y+yy)) + x;
2276 if (bpp==1)
2277 {
2278 int shift = x & 7;
2279 for (int xx=0; xx<_dx; xx++)
2280 {
2281 if ( x+xx >= clip.left && x+xx < clip.right )
2282 {
2283 lUInt8 cl = (*src << shift) & 0x80;
2284 if(src!=0) *dst = cl ? 0xFFFFFF : 0x000000;
2285 }
2286 dst++;
2287 if (++shift >= 8) {
2288 shift = 0;
2289 src++;
2290 }
2291
2292 }
2293 }
2294 else if (bpp==2)
2295 {
2296 int shift = x & 3;
2297 for (int xx=0; xx<_dx; xx++)
2298 {
2299 if ( x+xx >= clip.left && x+xx < clip.right )
2300 {
2301 lUInt32 cl = (*src << (shift<<1)) & 0xC0;
2302 cl = cl | (cl >> 2) | (cl>>4) | (cl>>6);
2303 if(src!=0) *dst = cl | (cl << 8) | (cl << 16);
2304 }
2305 dst++;
2306 if (++shift >= 4) {
2307 shift = 0;
2308 src++;
2309 }
2310
2311 }
2312 }
2313 else
2314 {
2315 // byte per pixel
2316 for (int xx=0; xx<_dx; xx++)
2317 {
2318 if ( x+xx >= clip.left && x+xx < clip.right )
2319 {
2320 lUInt32 cl = *src;
2321 if (bpp == 3) {
2322 cl &= 0xE0;
2323 cl = cl | (cl>>3) | (cl>>6);
2324 } else if (bpp == 4) {
2325 cl &= 0xF0;
2326 cl = cl | (cl>>4);
2327 }
2328 if(src!=0) *dst = cl | (cl << 8) | (cl << 16);
2329 }
2330 dst++;
2331 src++;
2332 }
2333 }
2334 }
2335 }
2336 return;
2337 }
2338 if (buf->GetBitsPerPixel() == 16) {
2339 // support for 32bpp to Gray drawing
2340 for (int yy=0; yy<_dy; yy++)
2341 {
2342 if (y+yy >= clip.top && y+yy < clip.bottom)
2343 {
2344 lUInt8 * src = (lUInt8 *)GetScanLine(yy);
2345 lUInt16 * dst = ((lUInt16 *)buf->GetScanLine(y+yy)) + x;
2346 if (bpp==1)
2347 {
2348 int shift = x & 7;
2349 for (int xx=0; xx<_dx; xx++)
2350 {
2351 if ( x+xx >= clip.left && x+xx < clip.right )
2352 {
2353 lUInt8 cl = (*src << shift) & 0x80;
2354 if(*src!=0) *dst = cl ? 0xFFFF : 0x0000;
2355 }
2356 dst++;
2357 if (++shift >= 8) {
2358 shift = 0;
2359 src++;
2360 }
2361
2362 }
2363 }
2364 else if (bpp==2)
2365 {
2366 int shift = x & 3;
2367 for (int xx=0; xx<_dx; xx++)
2368 {
2369 if ( x+xx >= clip.left && x+xx < clip.right )
2370 {
2371 lUInt16 cl = (*src << (shift<<1)) & 0xC0;
2372 cl = cl | (cl >> 2) | (cl>>4) | (cl>>6);
2373 if(*src!=0) *dst = rgb565(cl, cl, cl);
2374 }
2375 dst++;
2376 if (++shift >= 4) {
2377 shift = 0;
2378 src++;
2379 }
2380
2381 }
2382 }
2383 else
2384 {
2385 // byte per pixel
2386 for (int xx=0; xx<_dx; xx++)
2387 {
2388 if ( x+xx >= clip.left && x+xx < clip.right )
2389 {
2390 lUInt16 cl = *src;
2391 if (bpp == 3) {
2392 cl &= 0xE0;
2393 cl = cl | (cl>>3) | (cl>>6);
2394 } else if (bpp == 4) {
2395 cl &= 0xF0;
2396 cl = cl | (cl>>4);
2397 }
2398 if(*src!=0) *dst = rgb565(cl, cl, cl);
2399 }
2400 dst++;
2401 src++;
2402 }
2403 }
2404 }
2405 }
2406 return;
2407 }
2408 if (buf->GetBitsPerPixel() != bpp)
2409 return; // not supported yet
2410 for (int yy=0; yy<_dy; yy++)
2411 {
2412 if (y+yy >= clip.top && y+yy < clip.bottom)
2413 {
2414 lUInt8 * src = (lUInt8 *)GetScanLine(yy);
2415 if (bpp==1)
2416 {
2417 int shift = x & 7;
2418 lUInt8 * dst = buf->GetScanLine(y+yy) + (x>>3);
2419 for (int xx=0; xx<_dx; xx+=8)
2420 {
2421 if ( x+xx >= clip.left && x+xx < clip.right )
2422 {
2423 //lUInt8 mask = ~((lUInt8)0xC0>>shift);
2424 lUInt16 cl = (*src << 8)>>shift;
2425 lUInt16 mask = (0xFF00)>>shift;
2426 lUInt8 c = *dst;
2427 c &= ~(mask>>8);
2428 c |= (cl>>8);
2429 if(*src!=0) *dst = c;
2430 if (mask & 0xFF) {
2431 c = *(dst+1);
2432 c &= ~(mask&0xFF);
2433 c |= (cl&0xFF);
2434 if(*src!=0) *(dst+1) = c;
2435 }
2436 }
2437 dst++;
2438 src++;
2439 }
2440 }
2441 else if (bpp==2)
2442 {
2443 int shift = (x & 3) * 2;
2444 lUInt8 * dst = buf->GetScanLine(y+yy) + (x>>2);
2445 for (int xx=0; xx<_dx; xx+=4)
2446 {
2447 if ( x+xx >= clip.left && x+xx < clip.right )
2448 {
2449 //lUInt8 mask = ~((lUInt8)0xC0>>shift);
2450 lUInt16 cl = (*src << 8)>>shift;
2451 lUInt16 mask = (0xFF00)>>shift;
2452 lUInt8 c = *dst;
2453 c &= ~(mask>>8);
2454 c |= (cl>>8);
2455 if(*src!=0) *dst = c;
2456 if (mask & 0xFF) {
2457 c = *(dst+1);
2458 c &= ~(mask&0xFF);
2459 c |= (cl&0xFF);
2460 if(*src!=0) *(dst+1) = c;
2461 }
2462 }
2463 dst++;
2464 src++;
2465 }
2466 }
2467 else
2468 {
2469 lUInt8 * dst = buf->GetScanLine(y+yy) + x;
2470 for (int xx=0; xx<_dx; xx++)
2471 {
2472 if ( x+xx >= clip.left && x+xx < clip.right )
2473 {
2474 if(*src!=0) *dst = *src;
2475 }
2476 dst++;
2477 src++;
2478 }
2479 }
2480 }
2481 }
2482 CHECK_GUARD_BYTE;
2483 }
2484
2485 /// draws buffer content to another buffer doing color conversion if necessary
DrawTo(LVDrawBuf * buf,int x,int y,int options,lUInt32 * palette)2486 void LVColorDrawBuf::DrawTo( LVDrawBuf * buf, int x, int y, int options, lUInt32 * palette )
2487 {
2488 CR_UNUSED(options);
2489 CR_UNUSED(palette);
2490 //
2491 if ( !_data )
2492 return;
2493 lvRect clip;
2494 buf->GetClipRect(&clip);
2495 int bpp = buf->GetBitsPerPixel();
2496 for (int yy=0; yy<_dy; yy++) {
2497 if (y+yy >= clip.top && y+yy < clip.bottom) {
2498 if ( _bpp==16 ) {
2499 lUInt16 * src = (lUInt16 *)GetScanLine(yy);
2500 if (bpp == 1) {
2501 int shift = x & 7;
2502 lUInt8 * dst = buf->GetScanLine(y+yy) + (x>>3);
2503 for (int xx=0; xx<_dx; xx++) {
2504 if (x + xx >= clip.left && x + xx < clip.right) {
2505 //lUInt8 mask = ~((lUInt8)0xC0>>shift);
2506 #if (GRAY_INVERSE==1)
2507 lUInt8 cl = (((lUInt8)(*src)&0x8000)^0x8000) >> (shift+8);
2508 #else
2509 lUInt8 cl = (((lUInt8)(*src)&0x8000)) >> (shift+8);
2510 #endif
2511 *dst |= cl;
2512 }
2513 if (!((shift = (shift + 1) & 7)))
2514 dst++;
2515 src++;
2516 }
2517 } else if (bpp == 2) {
2518 int shift = x & 3;
2519 lUInt8 * dst = buf->GetScanLine(y+yy) + (x>>2);
2520 for (int xx=0; xx < _dx; xx++) {
2521 if ( x+xx >= clip.left && x+xx < clip.right ) {
2522 //lUInt8 mask = ~((lUInt8)0xC0>>shift);
2523 #if (GRAY_INVERSE==1)
2524 lUInt8 cl = (((lUInt8)(*src)&0xC000)^0xC000) >> ((shift<<1) + 8);
2525 #else
2526 lUInt8 cl = (((lUInt8)(*src)&0xC000)) >> ((shift<<1) + 8);
2527 #endif
2528 *dst |= cl;
2529 }
2530 if (!((shift = ((shift + 1) & 3))))
2531 dst++;
2532 src++;
2533 }
2534 } else if (bpp<=8) {
2535 lUInt8 * dst = buf->GetScanLine(y+yy) + x;
2536 for (int xx=0; xx<_dx; xx++) {
2537 if ( x+xx >= clip.left && x+xx < clip.right ) {
2538 //lUInt8 mask = ~((lUInt8)0xC0>>shift);
2539 *dst = (lUInt8)(*src >> 8);
2540 }
2541 dst++;
2542 src++;
2543 }
2544 } else if (bpp == 16) {
2545 lUInt16 * dst = ((lUInt16 *)buf->GetScanLine(y + yy)) + x;
2546 for (int xx=0; xx < _dx; xx++) {
2547 if (x + xx >= clip.left && x + xx < clip.right) {
2548 *dst = *src;
2549 }
2550 dst++;
2551 src++;
2552 }
2553 } else if (bpp == 32) {
2554 lUInt32 * dst = ((lUInt32 *)buf->GetScanLine(y + yy)) + x;
2555 for (int xx=0; xx<_dx; xx++) {
2556 if ( x+xx >= clip.left && x+xx < clip.right ) {
2557 *dst = rgb565to888( *src );
2558 }
2559 dst++;
2560 src++;
2561 }
2562 }
2563 } else {
2564 lUInt32 * src = (lUInt32 *)GetScanLine(yy);
2565 if (bpp==1) {
2566 int shift = x & 7;
2567 lUInt8 * dst = buf->GetScanLine(y+yy) + (x>>3);
2568 for (int xx=0; xx<_dx; xx++) {
2569 if ( x+xx >= clip.left && x+xx < clip.right ) {
2570 //lUInt8 mask = ~((lUInt8)0xC0>>shift);
2571 #if (GRAY_INVERSE==1)
2572 lUInt8 cl = (((lUInt8)(*src)&0x80)^0x80) >> (shift);
2573 #else
2574 lUInt8 cl = (((lUInt8)(*src)&0x80)) >> (shift);
2575 #endif
2576 *dst |= cl;
2577 }
2578 if (!((shift = (shift + 1) & 7)))
2579 dst++;
2580 src++;
2581 }
2582 } else if (bpp==2) {
2583 int shift = x & 3;
2584 lUInt8 * dst = buf->GetScanLine(y+yy) + (x>>2);
2585 for (int xx=0; xx<_dx; xx++) {
2586 if ( x+xx >= clip.left && x+xx < clip.right ) {
2587 //lUInt8 mask = ~((lUInt8)0xC0>>shift);
2588 #if (GRAY_INVERSE==1)
2589 lUInt8 cl = (((lUInt8)(*src)&0xC0)^0xC0) >> (shift<<1);
2590 #else
2591 lUInt8 cl = (((lUInt8)(*src)&0xC0)) >> (shift<<1);
2592 #endif
2593 *dst |= cl;
2594 }
2595 if (!((shift = (shift + 1) & 3)))
2596 dst++;
2597 src++;
2598 }
2599 } else if (bpp<=8) {
2600 lUInt8 * dst = buf->GetScanLine(y + yy) + x;
2601 for (int xx=0; xx<_dx; xx++) {
2602 if (x + xx >= clip.left && x + xx < clip.right) {
2603 //lUInt8 mask = ~((lUInt8)0xC0>>shift);
2604 *dst = (lUInt8)*src;
2605 }
2606 dst++;
2607 src++;
2608 }
2609 } else if (bpp == 32) {
2610 lUInt32 * dst = ((lUInt32 *)buf->GetScanLine(y + yy)) + x;
2611 for (int xx = 0; xx < _dx; xx++) {
2612 if (x+xx >= clip.left && x + xx < clip.right) {
2613 *dst = RevRGBA(*src);
2614 }
2615 dst++;
2616 src++;
2617 }
2618 }
2619 }
2620 }
2621 }
2622 }
2623 /// draws buffer content on top of another buffer doing color conversion if necessary
DrawOnTop(LVDrawBuf * buf,int x,int y)2624 void LVColorDrawBuf::DrawOnTop( LVDrawBuf * buf, int x, int y)
2625 {
2626 //
2627 if ( !_data )
2628 return;
2629 lvRect clip;
2630 buf->GetClipRect(&clip);
2631 int bpp = buf->GetBitsPerPixel();
2632 for (int yy=0; yy<_dy; yy++) {
2633 if (y+yy >= clip.top && y+yy < clip.bottom) {
2634 if ( _bpp==16 ) {
2635 lUInt16 * src = (lUInt16 *)GetScanLine(yy);
2636 if (bpp == 1) {
2637 int shift = x & 7;
2638 lUInt8 * dst = buf->GetScanLine(y+yy) + (x>>3);
2639 for (int xx=0; xx<_dx; xx++) {
2640 if (x + xx >= clip.left && x + xx < clip.right) {
2641 //lUInt8 mask = ~((lUInt8)0xC0>>shift);
2642 #if (GRAY_INVERSE==1)
2643 lUInt8 cl = (((lUInt8)(*src)&0x8000)^0x8000) >> (shift+8);
2644 #else
2645 lUInt8 cl = (((lUInt8)(*src)&0x8000)) >> (shift+8);
2646 #endif
2647 if(cl!=0) *dst |= cl;
2648 }
2649 if (!((shift = (shift + 1) & 7)))
2650 dst++;
2651 src++;
2652 }
2653 } else if (bpp == 2) {
2654 int shift = x & 3;
2655 lUInt8 * dst = buf->GetScanLine(y+yy) + (x>>2);
2656 for (int xx=0; xx < _dx; xx++) {
2657 if ( x+xx >= clip.left && x+xx < clip.right ) {
2658 //lUInt8 mask = ~((lUInt8)0xC0>>shift);
2659 #if (GRAY_INVERSE==1)
2660 lUInt8 cl = (((lUInt8)(*src)&0xC000)^0xC000) >> ((shift<<1) + 8);
2661 #else
2662 lUInt8 cl = (((lUInt8)(*src)&0xC000)) >> ((shift<<1) + 8);
2663 #endif
2664 if(cl!=0) *dst |= cl;
2665 }
2666 if (!((shift = ((shift + 1) & 3))))
2667 dst++;
2668 src++;
2669 }
2670 } else if (bpp<=8) {
2671 lUInt8 * dst = buf->GetScanLine(y+yy) + x;
2672 for (int xx=0; xx<_dx; xx++) {
2673 if ( x+xx >= clip.left && x+xx < clip.right ) {
2674 //lUInt8 mask = ~((lUInt8)0xC0>>shift);
2675 if(src!=0) *dst = (lUInt8)(*src >> 8);
2676 }
2677 dst++;
2678 src++;
2679 }
2680 } else if (bpp == 16) {
2681 lUInt16 * dst = ((lUInt16 *)buf->GetScanLine(y + yy)) + x;
2682 for (int xx=0; xx < _dx; xx++) {
2683 if (x + xx >= clip.left && x + xx < clip.right) {
2684 if(src!=0) *dst = *src;
2685 }
2686 dst++;
2687 src++;
2688 }
2689 } else if (bpp == 32) {
2690 lUInt32 * dst = ((lUInt32 *)buf->GetScanLine(y + yy)) + x;
2691 for (int xx=0; xx<_dx; xx++) {
2692 if ( x+xx >= clip.left && x+xx < clip.right ) {
2693 if(src!=0) *dst = rgb565to888( *src );
2694 }
2695 dst++;
2696 src++;
2697 }
2698 }
2699 } else {
2700 lUInt32 * src = (lUInt32 *)GetScanLine(yy);
2701 if (bpp==1) {
2702 int shift = x & 7;
2703 lUInt8 * dst = buf->GetScanLine(y+yy) + (x>>3);
2704 for (int xx=0; xx<_dx; xx++) {
2705 if ( x+xx >= clip.left && x+xx < clip.right ) {
2706 //lUInt8 mask = ~((lUInt8)0xC0>>shift);
2707 #if (GRAY_INVERSE==1)
2708 lUInt8 cl = (((lUInt8)(*src)&0x80)^0x80) >> (shift);
2709 #else
2710 lUInt8 cl = (((lUInt8)(*src)&0x80)) >> (shift);
2711 #endif
2712 if(*src!=0) *dst |= cl;
2713 }
2714 if (!((shift = (shift + 1) & 7)))
2715 dst++;
2716 src++;
2717 }
2718 } else if (bpp==2) {
2719 int shift = x & 3;
2720 lUInt8 * dst = buf->GetScanLine(y+yy) + (x>>2);
2721 for (int xx=0; xx<_dx; xx++) {
2722 if ( x+xx >= clip.left && x+xx < clip.right ) {
2723 //lUInt8 mask = ~((lUInt8)0xC0>>shift);
2724 #if (GRAY_INVERSE==1)
2725 lUInt8 cl = (((lUInt8)(*src)&0xC0)^0xC0) >> (shift<<1);
2726 #else
2727 lUInt8 cl = (((lUInt8)(*src)&0xC0)) >> (shift<<1);
2728 #endif
2729 if(*src!=0) *dst |= cl;
2730 }
2731 if (!((shift = (shift + 1) & 3)))
2732 dst++;
2733 src++;
2734 }
2735 } else if (bpp<=8) {
2736 lUInt8 * dst = buf->GetScanLine(y + yy) + x;
2737 for (int xx=0; xx<_dx; xx++) {
2738 if (x + xx >= clip.left && x + xx < clip.right) {
2739 //lUInt8 mask = ~((lUInt8)0xC0>>shift);
2740 if(*src!=0) *dst = (lUInt8)*src;
2741 }
2742 dst++;
2743 src++;
2744 }
2745 } else if (bpp == 16) {
2746 lUInt16 * dst = ((lUInt16 *)buf->GetScanLine(y + yy)) + x;
2747 for (int xx=0; xx < _dx; xx++) {
2748 if (x + xx >= clip.left && x + xx < clip.right) {
2749 if(src!=0) *dst = rgb888to565(*src);
2750 }
2751 dst++;
2752 src++;
2753 }
2754 } else if (bpp == 32) {
2755 lUInt32 * dst = ((lUInt32 *)buf->GetScanLine(y + yy)) + x;
2756 for (int xx = 0; xx < _dx; xx++) {
2757 if (x+xx >= clip.left && x + xx < clip.right) {
2758 if(*src!=0) *dst = RevRGBA(*src);
2759 }
2760 dst++;
2761 src++;
2762 }
2763 }
2764 }
2765 }
2766 }
2767 }
2768 /// draws rescaled buffer content to another buffer doing color conversion if necessary
DrawRescaled(LVDrawBuf * src,int x,int y,int dx,int dy,int options)2769 void LVGrayDrawBuf::DrawRescaled(LVDrawBuf * src, int x, int y, int dx, int dy, int options)
2770 {
2771 CR_UNUSED(options);
2772 if (dx < 1 || dy < 1)
2773 return;
2774 lvRect clip;
2775 GetClipRect(&clip);
2776 int srcdx = src->GetWidth();
2777 int srcdy = src->GetHeight();
2778 bool linearInterpolation = (srcdx <= dx || srcdy <= dy);
2779 //CRLog::trace("LVGrayDrawBuf::DrawRescaled bpp=%d %dx%d srcbpp=%d (%d,%d) (%d,%d)", _bpp, GetWidth(), GetHeight(), src->GetBitsPerPixel(), x, y, dx, dy);
2780 CHECK_GUARD_BYTE;
2781 for (int yy=0; yy<dy; yy++)
2782 {
2783 if (y+yy >= clip.top && y+yy < clip.bottom)
2784 {
2785 lUInt8 * dst0 = (lUInt8 *)GetScanLine(y + yy);
2786 if (linearInterpolation) {
2787 // linear interpolation
2788 int srcy16 = srcdy * yy * 16 / dy;
2789 for (int xx=0; xx<dx; xx++) {
2790 if ( x+xx >= clip.left && x+xx < clip.right ) {
2791 int srcx16 = srcdx * xx * 16 / dx;
2792 lUInt32 cl = src->GetInterpolatedColor(srcx16, srcy16);
2793 lUInt32 alpha = (cl >> 24) & 0xFF;
2794 if (_bpp==1)
2795 {
2796 if (alpha >= 128)
2797 continue;
2798 int shift = (xx + x) & 7;
2799 lUInt8 * dst = dst0 + ((x + xx) >> 3);
2800 lUInt32 dithered = Dither1BitColor(cl, xx, yy);
2801 if (dithered)
2802 *dst = (*dst) | (0x80 >> shift);
2803 else
2804 *dst = (*dst) & ~(0x80 >> shift);
2805 }
2806 else if (_bpp==2)
2807 {
2808 if (alpha >= 128)
2809 continue;
2810 lUInt8 * dst = dst0 + ((x + xx) >> 2);
2811 int shift = ((x+xx) & 3) * 2;
2812 lUInt32 dithered = Dither2BitColor(cl, xx, yy) << 6;
2813 lUInt8 b = *dst & ~(0xC0 >> shift);
2814 *dst = (lUInt8)(b | (dithered >> shift));
2815 }
2816 else
2817 {
2818 lUInt8 * dst = dst0 + x + xx;
2819 lUInt32 dithered;
2820 if (_bpp<8)
2821 dithered = DitherNBitColor(cl, xx, yy, _bpp); // << (8 - _bpp);
2822 else
2823 dithered = cl;
2824 if (alpha < 16)
2825 *dst = (lUInt8)dithered;
2826 else if (alpha < 240) {
2827 lUInt32 nalpha = alpha ^ 0xFF;
2828 lUInt32 pixel = *dst;
2829 if (_bpp == 4)
2830 pixel = ((pixel * alpha + dithered * nalpha) >> 8) & 0xF0;
2831 else
2832 pixel = ((pixel * alpha + dithered * nalpha) >> 8) & 0xFF;
2833 *dst = (lUInt8)pixel;
2834 }
2835 }
2836 }
2837 }
2838 #if 1
2839 {
2840 if (_ownData && _data[_rowsize * _dy] != GUARD_BYTE) {
2841 CRLog::error("lin interpolation, corrupted buffer, yy=%d of %d", yy, dy);
2842 crFatalError(-5, "corrupted bitmap buffer");
2843 }
2844 }
2845 #endif
2846 } else {
2847 // area average
2848 lvRect srcRect;
2849 srcRect.top = srcdy * yy * 16 / dy;
2850 srcRect.bottom = srcdy * (yy + 1) * 16 / dy;
2851 for (int xx=0; xx<dx; xx++)
2852 {
2853 if ( x+xx >= clip.left && x+xx < clip.right )
2854 {
2855 srcRect.left = srcdx * xx * 16 / dx;
2856 srcRect.right = srcdx * (xx + 1) * 16 / dx;
2857 lUInt32 cl = src->GetAvgColor(srcRect);
2858 if (_bpp==1)
2859 {
2860 int shift = (x + xx) & 7;
2861 lUInt8 * dst = dst0 + ((x + xx) >> 3);
2862 lUInt32 dithered = Dither1BitColor(cl, xx, yy);
2863 if (dithered)
2864 *dst = (*dst) | (0x80 >> shift);
2865 else
2866 *dst = (*dst) & ~(0x80 >> shift);
2867 }
2868 else if (_bpp==2)
2869 {
2870 lUInt8 * dst = dst0 + ((x + xx) >> 2);
2871 int shift = x & 3;
2872 lUInt32 dithered = Dither2BitColor(cl, xx, yy) << 6;
2873 lUInt8 b = *dst & ~(0xC0 >> shift);
2874 *dst = (lUInt8)(b | (dithered >> (shift * 2)));
2875 }
2876 else
2877 {
2878 lUInt8 * dst = dst0 + x + xx;
2879 lUInt32 dithered;
2880 if (_bpp < 8)
2881 dithered = DitherNBitColor(cl, xx, yy, _bpp);// << (8 - _bpp);
2882 else
2883 dithered = cl;
2884 *dst = (lUInt8)dithered;
2885 }
2886 }
2887 }
2888 #if 1
2889 {
2890 if (_ownData && _data[_rowsize * _dy] != GUARD_BYTE) {
2891 CRLog::error("area avg, corrupted buffer, yy=%d of %d", yy, dy);
2892 crFatalError(-5, "corrupted bitmap buffer");
2893 }
2894 }
2895 #endif
2896 }
2897 }
2898 }
2899 CHECK_GUARD_BYTE;
2900 }
2901
2902
2903
2904 /// draws rescaled buffer content to another buffer doing color conversion if necessary
DrawRescaled(LVDrawBuf * src,int x,int y,int dx,int dy,int options)2905 void LVColorDrawBuf::DrawRescaled(LVDrawBuf * src, int x, int y, int dx, int dy, int options)
2906 {
2907 CR_UNUSED(options);
2908 if (dx < 1 || dy < 1)
2909 return;
2910 lvRect clip;
2911 GetClipRect(&clip);
2912 int srcdx = src->GetWidth();
2913 int srcdy = src->GetHeight();
2914 bool linearInterpolation = (srcdx <= dx || srcdy <= dy);
2915 for (int yy=0; yy<dy; yy++) {
2916 if (y+yy >= clip.top && y+yy < clip.bottom) {
2917 if (linearInterpolation) {
2918 // linear interpolation
2919 int srcy16 = srcdy * yy * 16 / dy;
2920 for (int xx=0; xx<dx; xx++) {
2921 if ( x+xx >= clip.left && x+xx < clip.right ) {
2922 int srcx16 = srcdx * xx * 16 / dx;
2923 lUInt32 cl = src->GetInterpolatedColor(srcx16, srcy16);
2924 if (_bpp == 16) {
2925 lUInt16 * dst = (lUInt16 *)GetScanLine(y + yy);
2926 dst[x + xx] = rgb888to565(cl);
2927 } else {
2928 lUInt32 * dst = (lUInt32 *)GetScanLine(y + yy);
2929 dst[x + xx] = RevRGBA(cl);
2930 }
2931 }
2932 }
2933 } else {
2934 // area average
2935 lvRect srcRect;
2936 srcRect.top = srcdy * yy * 16 / dy;
2937 srcRect.bottom = srcdy * (yy + 1) * 16 / dy;
2938 for (int xx=0; xx<dx; xx++) {
2939 if ( x+xx >= clip.left && x+xx < clip.right ) {
2940 srcRect.left = srcdx * xx * 16 / dx;
2941 srcRect.right = srcdx * (xx + 1) * 16 / dx;
2942 lUInt32 cl = src->GetAvgColor(srcRect);
2943 if (_bpp == 16) {
2944 lUInt16 * dst = (lUInt16 *)GetScanLine(y + yy);
2945 dst[x + xx] = rgb888to565(cl);
2946 } else {
2947 lUInt32 * dst = (lUInt32 *)GetScanLine(y + yy);
2948 dst[x + xx] = RevRGBA(cl);
2949 }
2950 }
2951 }
2952 }
2953 }
2954 }
2955 }
2956
2957 /// returns scanline pointer
GetScanLine(int y)2958 lUInt8 * LVColorDrawBuf::GetScanLine( int y )
2959 {
2960 if (!_data || y<0 || y>=_dy)
2961 return NULL;
2962 #if !defined(__SYMBIAN32__) && defined(_WIN32) && !defined(QT_GL)
2963 return _data + _rowsize * (_dy-1-y);
2964 #else
2965 return _data + _rowsize * y;
2966 #endif
2967 }
2968
2969 /// returns white pixel value
GetWhiteColor()2970 lUInt32 LVColorDrawBuf::GetWhiteColor()
2971 {
2972 return 0xFFFFFF;
2973 }
2974 /// returns black pixel value
GetBlackColor()2975 lUInt32 LVColorDrawBuf::GetBlackColor()
2976 {
2977 return 0x000000;
2978 }
2979
2980
2981 /// constructor
LVColorDrawBuf(int dx,int dy,int bpp)2982 LVColorDrawBuf::LVColorDrawBuf(int dx, int dy, int bpp)
2983 : LVBaseDrawBuf()
2984 #if !defined(__SYMBIAN32__) && defined(_WIN32) && !defined(QT_GL)
2985 ,_drawdc(NULL)
2986 ,_drawbmp(NULL)
2987 #endif
2988 ,_bpp(bpp)
2989 ,_ownData(true)
2990 {
2991 _rowsize = dx*(_bpp>>3);
2992 Resize( dx, dy ); // NOLINT: Call to virtual function during construction
2993 }
2994
2995 /// creates wrapper around external RGBA buffer
LVColorDrawBuf(int dx,int dy,lUInt8 * externalBuffer,int bpp)2996 LVColorDrawBuf::LVColorDrawBuf(int dx, int dy, lUInt8 * externalBuffer, int bpp )
2997 : LVBaseDrawBuf()
2998 #if !defined(__SYMBIAN32__) && defined(_WIN32) && !defined(QT_GL)
2999 ,_drawdc(NULL)
3000 ,_drawbmp(NULL)
3001 #endif
3002 ,_bpp(bpp)
3003 ,_ownData(false)
3004 {
3005 _dx = dx;
3006 _dy = dy;
3007 _rowsize = dx*(_bpp>>3);
3008 _data = externalBuffer;
3009 SetClipRect( NULL );
3010 }
3011
3012 /// destructor
~LVColorDrawBuf()3013 LVColorDrawBuf::~LVColorDrawBuf()
3014 {
3015 if ( !_ownData )
3016 return;
3017 #if !defined(__SYMBIAN32__) && defined(_WIN32) && !defined(QT_GL)
3018 if (_drawdc)
3019 DeleteDC(_drawdc);
3020 if (_drawbmp)
3021 DeleteObject(_drawbmp);
3022 #else
3023 if (_data)
3024 free( _data );
3025 #endif
3026 }
3027
3028 /// convert to 1-bit bitmap
ConvertToBitmap(bool flgDither)3029 void LVColorDrawBuf::ConvertToBitmap(bool flgDither)
3030 {
3031 // not implemented
3032 CR_UNUSED(flgDither);
3033 }
3034
3035