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