gdi32: Add support for 24 bpp dibs.
[wine] / dlls / gdi32 / dibdrv / primitives.c
1 /*
2  * DIB driver primitives.
3  *
4  * Copyright 2011 Huw Davies
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <assert.h>
22
23 #include "gdi_private.h"
24 #include "dibdrv.h"
25
26 #include "wine/debug.h"
27
28 WINE_DEFAULT_DEBUG_CHANNEL(dib);
29
30 static inline DWORD *get_pixel_ptr_32(const dib_info *dib, int x, int y)
31 {
32     return (DWORD *)((BYTE*)dib->bits + y * dib->stride + x * 4);
33 }
34
35 static inline DWORD *get_pixel_ptr_24_dword(const dib_info *dib, int x, int y)
36 {
37     return (DWORD *)((BYTE*)dib->bits + y * dib->stride) + x * 3 / 4;
38 }
39
40 static inline BYTE *get_pixel_ptr_24(const dib_info *dib, int x, int y)
41 {
42     return (BYTE*)dib->bits + y * dib->stride + x * 3;
43 }
44
45 static inline WORD *get_pixel_ptr_16(const dib_info *dib, int x, int y)
46 {
47     return (WORD *)((BYTE*)dib->bits + y * dib->stride + x * 2);
48 }
49
50 static inline BYTE *get_pixel_ptr_8(const dib_info *dib, int x, int y)
51 {
52     return (BYTE*)dib->bits + y * dib->stride + x;
53 }
54
55 static inline BYTE *get_pixel_ptr_4(const dib_info *dib, int x, int y)
56 {
57     return (BYTE*)dib->bits + y * dib->stride + x / 2;
58 }
59
60 static inline void do_rop_32(DWORD *ptr, DWORD and, DWORD xor)
61 {
62     *ptr = (*ptr & and) ^ xor;
63 }
64
65 static inline void do_rop_16(WORD *ptr, WORD and, WORD xor)
66 {
67     *ptr = (*ptr & and) ^ xor;
68 }
69
70 static inline void do_rop_8(BYTE *ptr, BYTE and, BYTE xor)
71 {
72     *ptr = (*ptr & and) ^ xor;
73 }
74
75 static void solid_rects_32(const dib_info *dib, int num, const RECT *rc, DWORD and, DWORD xor)
76 {
77     DWORD *ptr, *start;
78     int x, y, i;
79
80     for(i = 0; i < num; i++, rc++)
81     {
82         start = get_pixel_ptr_32(dib, rc->left, rc->top);
83         for(y = rc->top; y < rc->bottom; y++, start += dib->stride / 4)
84             for(x = rc->left, ptr = start; x < rc->right; x++)
85                 do_rop_32(ptr++, and, xor);
86     }
87 }
88
89 static void solid_rects_24(const dib_info *dib, int num, const RECT *rc, DWORD and, DWORD xor)
90 {
91     DWORD *ptr, *start;
92     BYTE *byte_ptr, *byte_start;
93     int x, y, i;
94     DWORD and_masks[3], xor_masks[3];
95
96     and_masks[0] = ( and        & 0x00ffffff) | ((and << 24) & 0xff000000);
97     and_masks[1] = ((and >>  8) & 0x0000ffff) | ((and << 16) & 0xffff0000);
98     and_masks[2] = ((and >> 16) & 0x000000ff) | ((and <<  8) & 0xffffff00);
99     xor_masks[0] = ( xor        & 0x00ffffff) | ((xor << 24) & 0xff000000);
100     xor_masks[1] = ((xor >>  8) & 0x0000ffff) | ((xor << 16) & 0xffff0000);
101     xor_masks[2] = ((xor >> 16) & 0x000000ff) | ((xor <<  8) & 0xffffff00);
102
103     for(i = 0; i < num; i++, rc++)
104     {
105         if(rc->left >= rc->right) continue;
106
107         if((rc->left & ~3) == (rc->right & ~3)) /* Special case for lines that start and end in the same DWORD triplet */
108         {
109             byte_start = get_pixel_ptr_24(dib, rc->left, rc->top);
110             for(y = rc->top; y < rc->bottom; y++, byte_start += dib->stride)
111             {
112                 for(x = rc->left, byte_ptr = byte_start; x < rc->right; x++)
113                 {
114                     do_rop_8(byte_ptr++, and_masks[0] & 0xff, xor_masks[0] & 0xff);
115                     do_rop_8(byte_ptr++, and_masks[1] & 0xff, xor_masks[1] & 0xff);
116                     do_rop_8(byte_ptr++, and_masks[2] & 0xff, xor_masks[2] & 0xff);
117                 }
118             }
119         }
120         else
121         {
122             start = get_pixel_ptr_24_dword(dib, rc->left, rc->top);
123             for(y = rc->top; y < rc->bottom; y++, start += dib->stride / 4)
124             {
125                 ptr = start;
126
127                 switch(rc->left & 3)
128                 {
129                 case 1:
130                     do_rop_32(ptr++, and_masks[0] | 0x00ffffff, xor_masks[0] & 0xff000000);
131                     do_rop_32(ptr++, and_masks[1], xor_masks[1]);
132                     do_rop_32(ptr++, and_masks[2], xor_masks[2]);
133                     break;
134                 case 2:
135                     do_rop_32(ptr++, and_masks[1] | 0x0000ffff, xor_masks[1] & 0xffff0000);
136                     do_rop_32(ptr++, and_masks[2], xor_masks[2]);
137                     break;
138                 case 3:
139                     do_rop_32(ptr++, and_masks[2] | 0x000000ff, xor_masks[2] & 0xffffff00);
140                     break;
141                 }
142
143                 for(x = (rc->left + 3) & ~3; x < (rc->right & ~3); x += 4)
144                 {
145                     do_rop_32(ptr++, and_masks[0], xor_masks[0]);
146                     do_rop_32(ptr++, and_masks[1], xor_masks[1]);
147                     do_rop_32(ptr++, and_masks[2], xor_masks[2]);
148                 }
149
150                 switch(rc->right & 3)
151                 {
152                 case 1:
153                     do_rop_32(ptr, and_masks[0] | 0xff000000, xor_masks[0] & 0x00ffffff);
154                     break;
155                 case 2:
156                     do_rop_32(ptr++, and_masks[0], xor_masks[0]);
157                     do_rop_32(ptr,   and_masks[1] | 0xffff0000, xor_masks[1] & 0x0000ffff);
158                     break;
159                 case 3:
160                     do_rop_32(ptr++, and_masks[0], xor_masks[0]);
161                     do_rop_32(ptr++, and_masks[1], xor_masks[1]);
162                     do_rop_32(ptr,   and_masks[2] | 0xffffff00, xor_masks[2] & 0x000000ff);
163                     break;
164                 }
165             }
166         }
167     }
168 }
169
170 static void solid_rects_16(const dib_info *dib, int num, const RECT *rc, DWORD and, DWORD xor)
171 {
172     WORD *ptr, *start;
173     int x, y, i;
174
175     for(i = 0; i < num; i++, rc++)
176     {
177         start = get_pixel_ptr_16(dib, rc->left, rc->top);
178         for(y = rc->top; y < rc->bottom; y++, start += dib->stride / 2)
179             for(x = rc->left, ptr = start; x < rc->right; x++)
180                 do_rop_16(ptr++, and, xor);
181     }
182 }
183
184 static void solid_rects_8(const dib_info *dib, int num, const RECT *rc, DWORD and, DWORD xor)
185 {
186     BYTE *ptr, *start;
187     int x, y, i;
188
189     for(i = 0; i < num; i++, rc++)
190     {
191         start = get_pixel_ptr_8(dib, rc->left, rc->top);
192         for(y = rc->top; y < rc->bottom; y++, start += dib->stride)
193             for(x = rc->left, ptr = start; x < rc->right; x++)
194                 do_rop_8(ptr++, and, xor);
195     }
196 }
197
198 static void solid_rects_4(const dib_info *dib, int num, const RECT *rc, DWORD and, DWORD xor)
199 {
200     BYTE *ptr, *start;
201     int x, y, i;
202     BYTE byte_and = (and & 0xf) | ((and << 4) & 0xf0);
203     BYTE byte_xor = (xor & 0xf) | ((xor << 4) & 0xf0);
204
205     for(i = 0; i < num; i++, rc++)
206     {
207         if(rc->left >= rc->right) continue;
208         start = get_pixel_ptr_4(dib, rc->left, rc->top);
209         for(y = rc->top; y < rc->bottom; y++, start += dib->stride)
210         {
211             ptr = start;
212             if(rc->left & 1) /* upper nibble untouched */
213                 do_rop_8(ptr++, byte_and | 0xf0, byte_xor & 0x0f);
214
215             for(x = (rc->left + 1) & ~1; x < (rc->right & ~1); x += 2)
216                 do_rop_8(ptr++, byte_and, byte_xor);
217
218             if(rc->right & 1) /* lower nibble untouched */
219                 do_rop_8(ptr, byte_and | 0x0f, byte_xor & 0xf0);
220         }
221     }
222 }
223
224 static void solid_rects_null(const dib_info *dib, int num, const RECT *rc, DWORD and, DWORD xor)
225 {
226     return;
227 }
228
229 static inline INT calc_offset(INT edge, INT size, INT origin)
230 {
231     INT offset;
232
233     if(edge - origin >= 0)
234         offset = (edge - origin) % size;
235     else
236     {
237         offset = (origin - edge) % size;
238         if(offset) offset = size - offset;
239     }
240     return offset;
241 }
242
243 static inline POINT calc_brush_offset(const RECT *rc, const dib_info *brush, const POINT *origin)
244 {
245     POINT offset;
246
247     offset.x = calc_offset(rc->left, brush->width,  origin->x);
248     offset.y = calc_offset(rc->top,  brush->height, origin->y);
249
250     return offset;
251 }
252
253 static void pattern_rects_32(const dib_info *dib, int num, const RECT *rc, const POINT *origin,
254                              const dib_info *brush, void *and_bits, void *xor_bits)
255 {
256     DWORD *ptr, *start, *start_and, *and_ptr, *start_xor, *xor_ptr;
257     int x, y, i;
258     POINT offset;
259
260     for(i = 0; i < num; i++, rc++)
261     {
262         offset = calc_brush_offset(rc, brush, origin);
263
264         start = get_pixel_ptr_32(dib, rc->left, rc->top);
265         start_and = (DWORD*)and_bits + offset.y * brush->stride / 4;
266         start_xor = (DWORD*)xor_bits + offset.y * brush->stride / 4;
267
268         for(y = rc->top; y < rc->bottom; y++, start += dib->stride / 4)
269         {
270             and_ptr = start_and + offset.x;
271             xor_ptr = start_xor + offset.x;
272
273             for(x = rc->left, ptr = start; x < rc->right; x++)
274             {
275                 do_rop_32(ptr++, *and_ptr++, *xor_ptr++);
276                 if(and_ptr == start_and + brush->width)
277                 {
278                     and_ptr = start_and;
279                     xor_ptr = start_xor;
280                 }
281             }
282
283             offset.y++;
284             if(offset.y == brush->height)
285             {
286                 start_and = and_bits;
287                 start_xor = xor_bits;
288                 offset.y = 0;
289             }
290             else
291             {
292                 start_and += brush->stride / 4;
293                 start_xor += brush->stride / 4;
294             }
295         }
296     }
297 }
298
299 static void pattern_rects_24(const dib_info *dib, int num, const RECT *rc, const POINT *origin,
300                              const dib_info *brush, void *and_bits, void *xor_bits)
301 {
302     BYTE *ptr, *start, *start_and, *and_ptr, *start_xor, *xor_ptr;
303     int x, y, i;
304     POINT offset;
305
306     for(i = 0; i < num; i++, rc++)
307     {
308         offset = calc_brush_offset(rc, brush, origin);
309
310         start = get_pixel_ptr_24(dib, rc->left, rc->top);
311         start_and = (BYTE*)and_bits + offset.y * brush->stride;
312         start_xor = (BYTE*)xor_bits + offset.y * brush->stride;
313
314         for(y = rc->top; y < rc->bottom; y++, start += dib->stride)
315         {
316             and_ptr = start_and + offset.x * 3;
317             xor_ptr = start_xor + offset.x * 3;
318
319             for(x = rc->left, ptr = start; x < rc->right; x++)
320             {
321                 do_rop_8(ptr++, *and_ptr++, *xor_ptr++);
322                 do_rop_8(ptr++, *and_ptr++, *xor_ptr++);
323                 do_rop_8(ptr++, *and_ptr++, *xor_ptr++);
324                 if(and_ptr == start_and + brush->width * 3)
325                 {
326                     and_ptr = start_and;
327                     xor_ptr = start_xor;
328                 }
329             }
330
331             offset.y++;
332             if(offset.y == brush->height)
333             {
334                 start_and = and_bits;
335                 start_xor = xor_bits;
336                 offset.y = 0;
337             }
338             else
339             {
340                 start_and += brush->stride;
341                 start_xor += brush->stride;
342             }
343         }
344     }
345 }
346
347 static void pattern_rects_16(const dib_info *dib, int num, const RECT *rc, const POINT *origin,
348                              const dib_info *brush, void *and_bits, void *xor_bits)
349 {
350     WORD *ptr, *start, *start_and, *and_ptr, *start_xor, *xor_ptr;
351     int x, y, i;
352     POINT offset;
353
354     for(i = 0; i < num; i++, rc++)
355     {
356         offset = calc_brush_offset(rc, brush, origin);
357
358         start = get_pixel_ptr_16(dib, rc->left, rc->top);
359         start_and = (WORD*)and_bits + offset.y * brush->stride / 2;
360         start_xor = (WORD*)xor_bits + offset.y * brush->stride / 2;
361
362         for(y = rc->top; y < rc->bottom; y++, start += dib->stride / 2)
363         {
364             and_ptr = start_and + offset.x;
365             xor_ptr = start_xor + offset.x;
366
367             for(x = rc->left, ptr = start; x < rc->right; x++)
368             {
369                 do_rop_16(ptr++, *and_ptr++, *xor_ptr++);
370                 if(and_ptr == start_and + brush->width)
371                 {
372                     and_ptr = start_and;
373                     xor_ptr = start_xor;
374                 }
375             }
376
377             offset.y++;
378             if(offset.y == brush->height)
379             {
380                 start_and = and_bits;
381                 start_xor = xor_bits;
382                 offset.y = 0;
383             }
384             else
385             {
386                 start_and += brush->stride / 2;
387                 start_xor += brush->stride / 2;
388             }
389         }
390     }
391 }
392
393 static void pattern_rects_8(const dib_info *dib, int num, const RECT *rc, const POINT *origin,
394                             const dib_info *brush, void *and_bits, void *xor_bits)
395 {
396     BYTE *ptr, *start, *start_and, *and_ptr, *start_xor, *xor_ptr;
397     int x, y, i;
398     POINT offset;
399
400     for(i = 0; i < num; i++, rc++)
401     {
402         offset = calc_brush_offset(rc, brush, origin);
403
404         start = get_pixel_ptr_8(dib, rc->left, rc->top);
405         start_and = (BYTE*)and_bits + offset.y * brush->stride;
406         start_xor = (BYTE*)xor_bits + offset.y * brush->stride;
407
408         for(y = rc->top; y < rc->bottom; y++, start += dib->stride)
409         {
410             and_ptr = start_and + offset.x;
411             xor_ptr = start_xor + offset.x;
412
413             for(x = rc->left, ptr = start; x < rc->right; x++)
414             {
415                 do_rop_8(ptr++, *and_ptr++, *xor_ptr++);
416                 if(and_ptr == start_and + brush->width)
417                 {
418                     and_ptr = start_and;
419                     xor_ptr = start_xor;
420                 }
421             }
422
423             offset.y++;
424             if(offset.y == brush->height)
425             {
426                 start_and = and_bits;
427                 start_xor = xor_bits;
428                 offset.y = 0;
429             }
430             else
431             {
432                 start_and += brush->stride;
433                 start_xor += brush->stride;
434             }
435         }
436     }
437 }
438
439 static void pattern_rects_4(const dib_info *dib, int num, const RECT *rc, const POINT *origin,
440                             const dib_info *brush, void *and_bits, void *xor_bits)
441 {
442     BYTE *ptr, *start, *start_and, *and_ptr, *start_xor, *xor_ptr;
443     int x, y, i;
444     POINT offset;
445
446     for(i = 0; i < num; i++, rc++)
447     {
448         offset = calc_brush_offset(rc, brush, origin);
449
450         start = get_pixel_ptr_4(dib, rc->left, rc->top);
451         start_and = (BYTE*)and_bits + offset.y * brush->stride;
452         start_xor = (BYTE*)xor_bits + offset.y * brush->stride;
453
454         for(y = rc->top; y < rc->bottom; y++, start += dib->stride)
455         {
456             INT brush_x = offset.x;
457             BYTE byte_and, byte_xor;
458
459             and_ptr = start_and + brush_x / 2;
460             xor_ptr = start_xor + brush_x / 2;
461
462             for(x = rc->left, ptr = start; x < rc->right; x++)
463             {
464                 /* FIXME: Two pixels at a time */
465                 if(x & 1) /* lower dst nibble */
466                 {
467                     if(brush_x & 1) /* lower pat nibble */
468                     {
469                         byte_and = *and_ptr++ | 0xf0;
470                         byte_xor = *xor_ptr++ & 0x0f;
471                     }
472                     else /* upper pat nibble */
473                     {
474                         byte_and = (*and_ptr >> 4) | 0xf0;
475                         byte_xor = (*xor_ptr >> 4) & 0x0f;
476                     }
477                 }
478                 else /* upper dst nibble */
479                 {
480                     if(brush_x & 1) /* lower pat nibble */
481                     {
482                         byte_and = (*and_ptr++ << 4) | 0x0f;
483                         byte_xor = (*xor_ptr++ << 4) & 0xf0;
484                     }
485                     else /* upper pat nibble */
486                     {
487                         byte_and = *and_ptr | 0x0f;
488                         byte_xor = *xor_ptr & 0xf0;
489                     }
490                 }
491                 do_rop_8(ptr, byte_and, byte_xor);
492
493                 if(x & 1) ptr++;
494
495                 if(++brush_x == brush->width)
496                 {
497                     brush_x = 0;
498                     and_ptr = start_and;
499                     xor_ptr = start_xor;
500                 }
501             }
502
503             offset.y++;
504             if(offset.y == brush->height)
505             {
506                 start_and = and_bits;
507                 start_xor = xor_bits;
508                 offset.y = 0;
509             }
510             else
511             {
512                 start_and += brush->stride;
513                 start_xor += brush->stride;
514             }
515         }
516     }
517 }
518
519 static void pattern_rects_null(const dib_info *dib, int num, const RECT *rc, const POINT *origin,
520                                const dib_info *brush, void *and_bits, void *xor_bits)
521 {
522     return;
523 }
524
525 static DWORD colorref_to_pixel_888(const dib_info *dib, COLORREF color)
526 {
527     return ( ((color >> 16) & 0xff) | (color & 0xff00) | ((color << 16) & 0xff0000) );
528 }
529
530 static inline DWORD put_field(DWORD field, int shift, int len)
531 {
532     shift = shift - (8 - len);
533     if (len <= 8)
534         field &= (((1 << len) - 1) << (8 - len));
535     if (shift < 0)
536         field >>= -shift;
537     else
538         field <<= shift;
539     return field;
540 }
541
542 static DWORD colorref_to_pixel_masks(const dib_info *dib, COLORREF colour)
543 {
544     DWORD r,g,b;
545
546     r = GetRValue(colour);
547     g = GetGValue(colour);
548     b = GetBValue(colour);
549
550     return put_field(r, dib->red_shift,   dib->red_len) |
551            put_field(g, dib->green_shift, dib->green_len) |
552            put_field(b, dib->blue_shift,  dib->blue_len);
553 }
554
555 static DWORD colorref_to_pixel_555(const dib_info *dib, COLORREF color)
556 {
557     return ( ((color >> 19) & 0x1f) | ((color >> 6) & 0x03e0) | ((color << 7) & 0x7c00) );
558 }
559
560 static DWORD colorref_to_pixel_colortable(const dib_info *dib, COLORREF color)
561 {
562     int i, best_index = 0;
563     RGBQUAD rgb;
564     DWORD diff, best_diff = 0xffffffff;
565
566     rgb.rgbRed = GetRValue(color);
567     rgb.rgbGreen = GetGValue(color);
568     rgb.rgbBlue = GetBValue(color);
569
570     for(i = 0; i < dib->color_table_size; i++)
571     {
572         RGBQUAD *cur = dib->color_table + i;
573         diff = (rgb.rgbRed - cur->rgbRed) * (rgb.rgbRed - cur->rgbRed)
574             +  (rgb.rgbGreen - cur->rgbGreen) * (rgb.rgbGreen - cur->rgbGreen)
575             +  (rgb.rgbBlue - cur->rgbBlue) * (rgb.rgbBlue - cur->rgbBlue);
576
577         if(diff == 0)
578         {
579             best_index = i;
580             break;
581         }
582
583         if(diff < best_diff)
584         {
585             best_diff = diff;
586             best_index = i;
587         }
588     }
589     return best_index;
590 }
591
592 static DWORD colorref_to_pixel_null(const dib_info *dib, COLORREF color)
593 {
594     return 0;
595 }
596
597 static BOOL convert_to_8888(dib_info *dst, const dib_info *src, const RECT *src_rect)
598 {
599     DWORD *dst_start = dst->bits, *dst_pixel, src_val;
600     int x, y;
601
602     switch(src->bit_count)
603     {
604     case 32:
605     {
606         DWORD *src_start = get_pixel_ptr_32(src, src_rect->left, src_rect->top);
607         if(src->funcs == &funcs_8888)
608         {
609             if(src->stride > 0 && dst->stride > 0 && src_rect->left == 0 && src_rect->right == src->width)
610                 memcpy(dst->bits, src_start, (src_rect->bottom - src_rect->top) * src->stride);
611             else
612             {
613                 for(y = src_rect->top; y < src_rect->bottom; y++)
614                 {
615                     memcpy(dst_start, src_start, (src_rect->right - src_rect->left) * 4);
616                     dst_start += dst->stride / 4;
617                     src_start += src->stride / 4;
618                 }
619             }
620         }
621         else
622         {
623             FIXME("Unsupported conversion: 32 -> 8888\n");
624             return FALSE;
625         }
626         break;
627     }
628
629     case 16:
630     {
631         WORD *src_start = get_pixel_ptr_16(src, src_rect->left, src_rect->top), *src_pixel;
632         if(src->funcs == &funcs_555)
633         {
634             for(y = src_rect->top; y < src_rect->bottom; y++)
635             {
636                 dst_pixel = dst_start;
637                 src_pixel = src_start;
638                 for(x = src_rect->left; x < src_rect->right; x++)
639                 {
640                     src_val = *src_pixel++;
641                     *dst_pixel++ = ((src_val << 9) & 0xf80000) | ((src_val << 4) & 0x070000) |
642                                    ((src_val << 6) & 0x00f800) | ((src_val << 1) & 0x000700) |
643                                    ((src_val << 3) & 0x0000f8) | ((src_val >> 2) & 0x000007);
644                 }
645                 dst_start += dst->stride / 4;
646                 src_start += src->stride / 2;
647             }
648         }
649         else
650         {
651             FIXME("Unsupported conversion: 16 -> 8888\n");
652             return FALSE;
653         }
654         break;
655     }
656
657     case 8:
658     {
659         BYTE *src_start = get_pixel_ptr_8(src, src_rect->left, src_rect->top), *src_pixel;
660         for(y = src_rect->top; y < src_rect->bottom; y++)
661         {
662             dst_pixel = dst_start;
663             src_pixel = src_start;
664             for(x = src_rect->left; x < src_rect->right; x++)
665             {
666                 RGBQUAD rgb;
667                 src_val = *src_pixel++;
668                 if(src_val >= src->color_table_size) src_val = src->color_table_size - 1;
669                 rgb = src->color_table[src_val];
670                 *dst_pixel++ = rgb.rgbRed << 16 | rgb.rgbGreen << 8 | rgb.rgbBlue;
671             }
672             dst_start += dst->stride / 4;
673             src_start += src->stride;
674         }
675         break;
676     }
677
678     case 4:
679     {
680         BYTE *src_start = get_pixel_ptr_4(src, src_rect->left, src_rect->top), *src_pixel;
681         for(y = src_rect->top; y < src_rect->bottom; y++)
682         {
683             dst_pixel = dst_start;
684             src_pixel = src_start;
685             for(x = src_rect->left; x < src_rect->right; x++)
686             {
687                 RGBQUAD rgb;
688                 if(x & 1)
689                     src_val = *src_pixel++ & 0xf;
690                 else
691                     src_val = (*src_pixel >> 4) & 0xf;
692                 if(src_val >= src->color_table_size) src_val = src->color_table_size - 1;
693                 rgb = src->color_table[src_val];
694                 *dst_pixel++ = rgb.rgbRed << 16 | rgb.rgbGreen << 8 | rgb.rgbBlue;
695             }
696             dst_start += dst->stride / 4;
697             src_start += src->stride;
698         }
699         break;
700     }
701
702     default:
703         FIXME("Unsupported conversion: %d -> 8888\n", src->bit_count);
704         return FALSE;
705     }
706
707     return TRUE;
708 }
709
710 static BOOL convert_to_32(dib_info *dst, const dib_info *src, const RECT *src_rect)
711 {
712     DWORD *dst_start = dst->bits, *dst_pixel, src_val;
713     int x, y;
714
715     switch(src->bit_count)
716     {
717     case 32:
718     {
719         DWORD *src_start = get_pixel_ptr_32(src, src_rect->left, src_rect->top), *src_pixel;
720
721         if(src->funcs == &funcs_8888)
722         {
723             for(y = src_rect->top; y < src_rect->bottom; y++)
724             {
725                 dst_pixel = dst_start;
726                 src_pixel = src_start;
727                 for(x = src_rect->left; x < src_rect->right; x++)
728                 {
729                     src_val = *src_pixel++;
730                     *dst_pixel++ = put_field((src_val >> 16) & 0xff, dst->red_shift,   dst->red_len)   |
731                                    put_field((src_val >>  8) & 0xff, dst->green_shift, dst->green_len) |
732                                    put_field( src_val        & 0xff, dst->blue_shift,  dst->blue_len);
733                 }
734                 dst_start += dst->stride / 4;
735                 src_start += src->stride / 4;
736             }
737         }
738         else
739         {
740             FIXME("Unsupported conversion: 32 -> 32\n");
741             return FALSE;
742         }
743         break;
744     }
745
746     case 16:
747     {
748         WORD *src_start = get_pixel_ptr_16(src, src_rect->left, src_rect->top), *src_pixel;
749         if(src->funcs == &funcs_555)
750         {
751             for(y = src_rect->top; y < src_rect->bottom; y++)
752             {
753                 dst_pixel = dst_start;
754                 src_pixel = src_start;
755                 for(x = src_rect->left; x < src_rect->right; x++)
756                 {
757                     src_val = *src_pixel++;
758                     *dst_pixel++ = put_field(((src_val >> 7) & 0xf8) | ((src_val >> 12) & 0x07), dst->red_shift,   dst->red_len) |
759                                    put_field(((src_val >> 2) & 0xf8) | ((src_val >>  7) & 0x07), dst->green_shift, dst->green_len) |
760                                    put_field(((src_val << 3) & 0xf8) | ((src_val >>  2) & 0x07), dst->blue_shift,  dst->blue_len);
761                 }
762                 dst_start += dst->stride / 4;
763                 src_start += src->stride / 2;
764             }
765         }
766         else
767         {
768             FIXME("Unsupported conversion: 16 -> 8888\n");
769             return FALSE;
770         }
771         break;
772     }
773
774     case 8:
775     {
776         BYTE *src_start = get_pixel_ptr_8(src, src_rect->left, src_rect->top), *src_pixel;
777         for(y = src_rect->top; y < src_rect->bottom; y++)
778         {
779             dst_pixel = dst_start;
780             src_pixel = src_start;
781             for(x = src_rect->left; x < src_rect->right; x++)
782             {
783                 RGBQUAD rgb;
784                 src_val = *src_pixel++;
785                 if(src_val >= src->color_table_size) src_val = src->color_table_size - 1;
786                 rgb = src->color_table[src_val];
787                 *dst_pixel++ = put_field(rgb.rgbRed,   dst->red_shift,   dst->red_len) |
788                                put_field(rgb.rgbGreen, dst->green_shift, dst->green_len) |
789                                put_field(rgb.rgbBlue,  dst->blue_shift,  dst->blue_len);
790             }
791             dst_start += dst->stride / 4;
792             src_start += src->stride;
793         }
794         break;
795     }
796
797     case 4:
798     {
799         BYTE *src_start = get_pixel_ptr_4(src, src_rect->left, src_rect->top), *src_pixel;
800         for(y = src_rect->top; y < src_rect->bottom; y++)
801         {
802             dst_pixel = dst_start;
803             src_pixel = src_start;
804             for(x = src_rect->left; x < src_rect->right; x++)
805             {
806                 RGBQUAD rgb;
807                 if(x & 1)
808                     src_val = *src_pixel++ & 0xf;
809                 else
810                     src_val = (*src_pixel >> 4) & 0xf;
811                 if(src_val >= src->color_table_size) src_val = src->color_table_size - 1;
812                 rgb = src->color_table[src_val];
813                 *dst_pixel++ = put_field(rgb.rgbRed,   dst->red_shift,   dst->red_len) |
814                                put_field(rgb.rgbGreen, dst->green_shift, dst->green_len) |
815                                put_field(rgb.rgbBlue,  dst->blue_shift,  dst->blue_len);
816             }
817             dst_start += dst->stride / 4;
818             src_start += src->stride;
819         }
820         break;
821     }
822
823     default:
824         FIXME("Unsupported conversion: %d -> 32\n", src->bit_count);
825         return FALSE;
826     }
827
828     return TRUE;
829 }
830
831 static BOOL convert_to_24(dib_info *dst, const dib_info *src, const RECT *src_rect)
832 {
833     BYTE *dst_start = dst->bits, *dst_pixel;
834     DWORD src_val;
835     int x, y;
836
837     switch(src->bit_count)
838     {
839     case 32:
840     {
841         DWORD *src_start = get_pixel_ptr_32(src, src_rect->left, src_rect->top), *src_pixel;
842         if(src->funcs == &funcs_8888)
843         {
844             for(y = src_rect->top; y < src_rect->bottom; y++)
845             {
846                 dst_pixel = dst_start;
847                 src_pixel = src_start;
848                 for(x = src_rect->left; x < src_rect->right; x++)
849                 {
850                     src_val = *src_pixel++;
851                     *dst_pixel++ =  src_val        & 0xff;
852                     *dst_pixel++ = (src_val >>  8) & 0xff;
853                     *dst_pixel++ = (src_val >> 16) & 0xff;
854                 }
855                 dst_start += dst->stride;
856                 src_start += src->stride / 4;
857             }
858         }
859         else
860         {
861             FIXME("Unsupported conversion: 32 -> 24\n");
862             return FALSE;
863         }
864         break;
865     }
866
867     case 16:
868     {
869         WORD *src_start = get_pixel_ptr_16(src, src_rect->left, src_rect->top), *src_pixel;
870         if(src->funcs == &funcs_555)
871         {
872             for(y = src_rect->top; y < src_rect->bottom; y++)
873             {
874                 dst_pixel = dst_start;
875                 src_pixel = src_start;
876                 for(x = src_rect->left; x < src_rect->right; x++)
877                 {
878                     src_val = *src_pixel++;
879                     *dst_pixel++ = ((src_val << 3) & 0xf8) | ((src_val >>  2) & 0x07);
880                     *dst_pixel++ = ((src_val >> 2) & 0xf8) | ((src_val >>  7) & 0x07);
881                     *dst_pixel++ = ((src_val >> 7) & 0xf8) | ((src_val >> 12) & 0x07);
882                 }
883                 dst_start += dst->stride;
884                 src_start += src->stride / 2;
885             }
886         }
887         else
888         {
889             FIXME("Unsupported conversion: 16 -> 24\n");
890             return FALSE;
891         }
892         break;
893     }
894
895     case 8:
896     {
897         BYTE *src_start = get_pixel_ptr_8(src, src_rect->left, src_rect->top), *src_pixel;
898         for(y = src_rect->top; y < src_rect->bottom; y++)
899         {
900             dst_pixel = dst_start;
901             src_pixel = src_start;
902             for(x = src_rect->left; x < src_rect->right; x++)
903             {
904                 RGBQUAD rgb;
905                 src_val = *src_pixel++;
906                 if(src_val >= src->color_table_size) src_val = src->color_table_size - 1;
907                 rgb = src->color_table[src_val];
908                 *dst_pixel++ = rgb.rgbBlue;
909                 *dst_pixel++ = rgb.rgbGreen;
910                 *dst_pixel++ = rgb.rgbRed;
911             }
912             dst_start += dst->stride;
913             src_start += src->stride;
914         }
915         break;
916     }
917
918     case 4:
919     {
920         BYTE *src_start = get_pixel_ptr_4(src, src_rect->left, src_rect->top), *src_pixel;
921         for(y = src_rect->top; y < src_rect->bottom; y++)
922         {
923             dst_pixel = dst_start;
924             src_pixel = src_start;
925             for(x = src_rect->left; x < src_rect->right; x++)
926             {
927                 RGBQUAD rgb;
928                 if(x & 1)
929                     src_val = *src_pixel++ & 0xf;
930                 else
931                     src_val = (*src_pixel >> 4) & 0xf;
932                 if(src_val >= src->color_table_size) src_val = src->color_table_size - 1;
933                 rgb = src->color_table[src_val];
934                 *dst_pixel++ = rgb.rgbBlue;
935                 *dst_pixel++ = rgb.rgbGreen;
936                 *dst_pixel++ = rgb.rgbRed;
937             }
938             dst_start += dst->stride;
939             src_start += src->stride;
940         }
941         break;
942     }
943
944     default:
945         FIXME("Unsupported conversion: %d -> 24\n", src->bit_count);
946         return FALSE;
947     }
948
949     return TRUE;
950 }
951
952 static BOOL convert_to_555(dib_info *dst, const dib_info *src, const RECT *src_rect)
953 {
954     WORD *dst_start = dst->bits, *dst_pixel;
955     INT x, y;
956     DWORD src_val;
957
958     switch(src->bit_count)
959     {
960     case 32:
961     {
962         DWORD *src_start = get_pixel_ptr_32(src, src_rect->left, src_rect->top), *src_pixel;
963
964         if(src->funcs == &funcs_8888)
965         {
966             for(y = src_rect->top; y < src_rect->bottom; y++)
967             {
968                 dst_pixel = dst_start;
969                 src_pixel = src_start;
970                 for(x = src_rect->left; x < src_rect->right; x++)
971                 {
972                     src_val = *src_pixel++;
973                     *dst_pixel++ = ((src_val >> 9) & 0x7c00) |
974                                    ((src_val >> 6) & 0x03e0) |
975                                    ((src_val >> 3) & 0x001e);
976                 }
977                 dst_start += dst->stride / 2;
978                 src_start += src->stride / 4;
979             }
980         }
981         else
982         {
983             FIXME("Unsupported conversion: 32 -> 555\n");
984             return FALSE;
985         }
986         break;
987     }
988
989     case 16:
990     {
991         WORD *src_start = get_pixel_ptr_16(src, src_rect->left, src_rect->top);
992         if(src->funcs == &funcs_555)
993         {
994             if(src->stride > 0 && dst->stride > 0 && src_rect->left == 0 && src_rect->right == src->width)
995                 memcpy(dst->bits, src_start, (src_rect->bottom - src_rect->top) * src->stride);
996             else
997             {
998                 for(y = src_rect->top; y < src_rect->bottom; y++)
999                 {
1000                     memcpy(dst_start, src_start, (src_rect->right - src_rect->left) * 2);
1001                     dst_start += dst->stride / 2;
1002                     src_start += src->stride / 2;
1003                 }
1004             }
1005         }
1006         else
1007         {
1008             FIXME("Unsupported conversion: 16 -> 555\n");
1009             return FALSE;
1010         }
1011         break;
1012     }
1013
1014     case 8:
1015     {
1016         BYTE *src_start = get_pixel_ptr_8(src, src_rect->left, src_rect->top), *src_pixel;
1017         for(y = src_rect->top; y < src_rect->bottom; y++)
1018         {
1019             dst_pixel = dst_start;
1020             src_pixel = src_start;
1021             for(x = src_rect->left; x < src_rect->right; x++)
1022             {
1023                 RGBQUAD rgb;
1024                 src_val = *src_pixel++;
1025                 if(src_val >= src->color_table_size) src_val = src->color_table_size - 1;
1026                 rgb = src->color_table[src_val];
1027                 *dst_pixel++ = ((rgb.rgbRed   << 7) & 0x7c00) |
1028                                ((rgb.rgbGreen << 2) & 0x03e0) |
1029                                ((rgb.rgbBlue  >> 3) & 0x001f);
1030             }
1031             dst_start += dst->stride / 2;
1032             src_start += src->stride;
1033         }
1034         break;
1035     }
1036
1037     case 4:
1038     {
1039         BYTE *src_start = get_pixel_ptr_4(src, src_rect->left, src_rect->top), *src_pixel;
1040         for(y = src_rect->top; y < src_rect->bottom; y++)
1041         {
1042             dst_pixel = dst_start;
1043             src_pixel = src_start;
1044             for(x = src_rect->left; x < src_rect->right; x++)
1045             {
1046                 RGBQUAD rgb;
1047                 if(x & 1)
1048                     src_val = *src_pixel++ & 0xf;
1049                 else
1050                     src_val = (*src_pixel >> 4) & 0xf;
1051                 if(src_val >= src->color_table_size) src_val = src->color_table_size - 1;
1052                 rgb = src->color_table[src_val];
1053                 *dst_pixel++ = ((rgb.rgbRed   << 7) & 0x7c00) |
1054                                ((rgb.rgbGreen << 2) & 0x03e0) |
1055                                ((rgb.rgbBlue  >> 3) & 0x001f);
1056             }
1057             dst_start += dst->stride / 2;
1058             src_start += src->stride;
1059         }
1060         break;
1061     }
1062
1063     default:
1064         FIXME("Unsupported conversion: %d -> 555\n", src->bit_count);
1065         return FALSE;
1066
1067     }
1068     return TRUE;
1069 }
1070
1071 static BOOL convert_to_16(dib_info *dst, const dib_info *src, const RECT *src_rect)
1072 {
1073     WORD *dst_start = dst->bits, *dst_pixel;
1074     INT x, y;
1075     DWORD src_val;
1076
1077     switch(src->bit_count)
1078     {
1079     case 32:
1080     {
1081         DWORD *src_start = get_pixel_ptr_32(src, src_rect->left, src_rect->top), *src_pixel;
1082
1083         if(src->funcs == &funcs_8888)
1084         {
1085             for(y = src_rect->top; y < src_rect->bottom; y++)
1086             {
1087                 dst_pixel = dst_start;
1088                 src_pixel = src_start;
1089                 for(x = src_rect->left; x < src_rect->right; x++)
1090                 {
1091                     src_val = *src_pixel++;
1092                     *dst_pixel++ = put_field((src_val >> 16) & 0xff, dst->red_shift,   dst->red_len)   |
1093                                    put_field((src_val >>  8) & 0xff, dst->green_shift, dst->green_len) |
1094                                    put_field( src_val        & 0xff, dst->blue_shift,  dst->blue_len);
1095                 }
1096                 dst_start += dst->stride / 2;
1097                 src_start += src->stride / 4;
1098             }
1099         }
1100         else
1101         {
1102             FIXME("Unsupported conversion: 32 -> 16\n");
1103             return FALSE;
1104         }
1105         break;
1106     }
1107
1108     case 16:
1109     {
1110         WORD *src_start = get_pixel_ptr_16(src, src_rect->left, src_rect->top), *src_pixel;
1111         if(src->funcs == &funcs_555)
1112         {
1113             for(y = src_rect->top; y < src_rect->bottom; y++)
1114             {
1115                 dst_pixel = dst_start;
1116                 src_pixel = src_start;
1117                 for(x = src_rect->left; x < src_rect->right; x++)
1118                 {
1119                     src_val = *src_pixel++;
1120                     *dst_pixel++ = put_field(((src_val >> 7) & 0xf8) | ((src_val >> 12) & 0x07), dst->red_shift,   dst->red_len) |
1121                                    put_field(((src_val >> 2) & 0xf8) | ((src_val >>  7) & 0x07), dst->green_shift, dst->green_len) |
1122                                    put_field(((src_val << 3) & 0xf8) | ((src_val >>  2) & 0x07), dst->blue_shift,  dst->blue_len);
1123                 }
1124                 dst_start += dst->stride / 2;
1125                 src_start += src->stride / 2;
1126             }
1127         }
1128         else
1129         {
1130             FIXME("Unsupported conversion: 16 -> 16\n");
1131             return FALSE;
1132         }
1133         break;
1134     }
1135
1136     case 8:
1137     {
1138         BYTE *src_start = get_pixel_ptr_8(src, src_rect->left, src_rect->top), *src_pixel;
1139         for(y = src_rect->top; y < src_rect->bottom; y++)
1140         {
1141             dst_pixel = dst_start;
1142             src_pixel = src_start;
1143             for(x = src_rect->left; x < src_rect->right; x++)
1144             {
1145                 RGBQUAD rgb;
1146                 src_val = *src_pixel++;
1147                 if(src_val >= src->color_table_size) src_val = src->color_table_size - 1;
1148                 rgb = src->color_table[src_val];
1149                 *dst_pixel++ = put_field(rgb.rgbRed,   dst->red_shift,   dst->red_len) |
1150                                put_field(rgb.rgbGreen, dst->green_shift, dst->green_len) |
1151                                put_field(rgb.rgbBlue,  dst->blue_shift,  dst->blue_len);
1152             }
1153             dst_start += dst->stride / 2;
1154             src_start += src->stride;
1155         }
1156         break;
1157     }
1158
1159     case 4:
1160     {
1161         BYTE *src_start = get_pixel_ptr_4(src, src_rect->left, src_rect->top), *src_pixel;
1162         for(y = src_rect->top; y < src_rect->bottom; y++)
1163         {
1164             dst_pixel = dst_start;
1165             src_pixel = src_start;
1166             for(x = src_rect->left; x < src_rect->right; x++)
1167             {
1168                 RGBQUAD rgb;
1169                 if(x & 1)
1170                     src_val = *src_pixel++ & 0xf;
1171                 else
1172                     src_val = (*src_pixel >> 4) & 0xf;
1173                 if(src_val >= src->color_table_size) src_val = src->color_table_size - 1;
1174                 rgb = src->color_table[src_val];
1175                 *dst_pixel++ = put_field(rgb.rgbRed,   dst->red_shift,   dst->red_len) |
1176                                put_field(rgb.rgbGreen, dst->green_shift, dst->green_len) |
1177                                put_field(rgb.rgbBlue,  dst->blue_shift,  dst->blue_len);
1178             }
1179             dst_start += dst->stride / 2;
1180             src_start += src->stride;
1181         }
1182         break;
1183     }
1184
1185     default:
1186         FIXME("Unsupported conversion: %d -> 16\n", src->bit_count);
1187         return FALSE;
1188
1189     }
1190     return TRUE;
1191 }
1192
1193 static inline BOOL color_tables_match(const dib_info *d1, const dib_info *d2)
1194 {
1195     assert(d1->color_table_size && d2->color_table_size);
1196
1197     if(d1->color_table_size != d2->color_table_size) return FALSE;
1198     return !memcmp(d1->color_table, d2->color_table, d1->color_table_size * sizeof(d1->color_table[0]));
1199 }
1200
1201 static BOOL convert_to_8(dib_info *dst, const dib_info *src, const RECT *src_rect)
1202 {
1203     BYTE *dst_start = dst->bits, *dst_pixel;
1204     INT x, y;
1205     DWORD src_val;
1206
1207     switch(src->bit_count)
1208     {
1209     case 32:
1210     {
1211         DWORD *src_start = get_pixel_ptr_32(src, src_rect->left, src_rect->top), *src_pixel;
1212
1213         if(src->funcs == &funcs_8888)
1214         {
1215             for(y = src_rect->top; y < src_rect->bottom; y++)
1216             {
1217                 dst_pixel = dst_start;
1218                 src_pixel = src_start;
1219                 for(x = src_rect->left; x < src_rect->right; x++)
1220                 {
1221                     src_val = *src_pixel++;
1222                     *dst_pixel++ = colorref_to_pixel_colortable(dst, ((src_val >> 16) & 0x0000ff) |
1223                                                                      ( src_val        & 0x00ff00) |
1224                                                                      ((src_val << 16) & 0xff0000) );
1225                 }
1226                 dst_start += dst->stride;
1227                 src_start += src->stride / 4;
1228             }
1229         }
1230         else
1231         {
1232             FIXME("Unsupported conversion: 32 -> 8\n");
1233             return FALSE;
1234         }
1235         break;
1236     }
1237
1238     case 16:
1239     {
1240         WORD *src_start = get_pixel_ptr_16(src, src_rect->left, src_rect->top), *src_pixel;
1241         if(src->funcs == &funcs_555)
1242         {
1243             for(y = src_rect->top; y < src_rect->bottom; y++)
1244             {
1245                 dst_pixel = dst_start;
1246                 src_pixel = src_start;
1247                 for(x = src_rect->left; x < src_rect->right; x++)
1248                 {
1249                     src_val = *src_pixel++;
1250                     *dst_pixel++ = colorref_to_pixel_colortable(dst, ((src_val >>  7) & 0x0000f8) | ((src_val >> 12) & 0x000007) |
1251                                                                      ((src_val <<  6) & 0x00f800) | ((src_val <<  1) & 0x000700) |
1252                                                                      ((src_val << 19) & 0xf80000) | ((src_val << 14) & 0x070000) );
1253                 }
1254                 dst_start += dst->stride;
1255                 src_start += src->stride / 2;
1256             }
1257         }
1258         else
1259         {
1260             FIXME("Unsupported conversion: 16 -> 8\n");
1261             return FALSE;
1262         }
1263         break;
1264     }
1265
1266     case 8:
1267     {
1268         BYTE *src_start = get_pixel_ptr_8(src, src_rect->left, src_rect->top), *src_pixel;
1269
1270         if(color_tables_match(dst, src))
1271         {
1272             if(src->stride > 0 && dst->stride > 0 && src_rect->left == 0 && src_rect->right == src->width)
1273                 memcpy(dst->bits, src_start, (src_rect->bottom - src_rect->top) * src->stride);
1274             else
1275             {
1276                 for(y = src_rect->top; y < src_rect->bottom; y++)
1277                 {
1278                     memcpy(dst_start, src_start, src_rect->right - src_rect->left);
1279                     dst_start += dst->stride;
1280                     src_start += src->stride;
1281                 }
1282             }
1283         }
1284         else
1285         {
1286             for(y = src_rect->top; y < src_rect->bottom; y++)
1287             {
1288                 dst_pixel = dst_start;
1289                 src_pixel = src_start;
1290                 for(x = src_rect->left; x < src_rect->right; x++)
1291                 {
1292                     RGBQUAD rgb;
1293                     src_val = *src_pixel++;
1294                     if(src_val >= src->color_table_size) src_val = src->color_table_size - 1;
1295                     rgb = src->color_table[src_val];
1296                     *dst_pixel++ = colorref_to_pixel_colortable(dst, RGB(rgb.rgbRed, rgb.rgbGreen, rgb.rgbBlue));
1297                 }
1298                 dst_start += dst->stride;
1299                 src_start += src->stride;
1300             }
1301         }
1302         break;
1303     }
1304
1305     case 4:
1306     {
1307         BYTE *src_start = get_pixel_ptr_4(src, src_rect->left, src_rect->top), *src_pixel;
1308         for(y = src_rect->top; y < src_rect->bottom; y++)
1309         {
1310             dst_pixel = dst_start;
1311             src_pixel = src_start;
1312             for(x = src_rect->left; x < src_rect->right; x++)
1313             {
1314                 RGBQUAD rgb;
1315                 if(x & 1)
1316                     src_val = *src_pixel++ & 0xf;
1317                 else
1318                     src_val = (*src_pixel >> 4) & 0xf;
1319                 if(src_val >= src->color_table_size) src_val = src->color_table_size - 1;
1320                 rgb = src->color_table[src_val];
1321                 *dst_pixel++ = colorref_to_pixel_colortable(dst, RGB(rgb.rgbRed, rgb.rgbGreen, rgb.rgbBlue));
1322             }
1323             dst_start += dst->stride;
1324             src_start += src->stride;
1325         }
1326         break;
1327     }
1328
1329     default:
1330         FIXME("Unsupported conversion: %d -> 8\n", src->bit_count);
1331         return FALSE;
1332
1333     }
1334     return TRUE;
1335 }
1336
1337 static BOOL convert_to_4(dib_info *dst, const dib_info *src, const RECT *src_rect)
1338 {
1339     BYTE *dst_start = dst->bits, *dst_pixel, dst_val;
1340     INT x, y;
1341     DWORD src_val;
1342
1343     switch(src->bit_count)
1344     {
1345     case 32:
1346     {
1347         DWORD *src_start = get_pixel_ptr_32(src, src_rect->left, src_rect->top), *src_pixel;
1348
1349         if(src->funcs == &funcs_8888)
1350         {
1351             for(y = src_rect->top; y < src_rect->bottom; y++)
1352             {
1353                 dst_pixel = dst_start;
1354                 src_pixel = src_start;
1355                 for(x = src_rect->left; x < src_rect->right; x++)
1356                 {
1357                     src_val = *src_pixel++;
1358                     dst_val = colorref_to_pixel_colortable(dst, ((src_val >> 16) & 0x0000ff) |
1359                                                                 ( src_val        & 0x00ff00) |
1360                                                                 ((src_val << 16) & 0xff0000) );
1361                     if((x - src_rect->left) & 1)
1362                     {
1363                         *dst_pixel = (dst_val & 0x0f) | (*dst_pixel & 0xf0);
1364                         dst_pixel++;
1365                     }
1366                     else
1367                         *dst_pixel = (dst_val << 4) & 0xf0;
1368                 }
1369                 dst_start += dst->stride;
1370                 src_start += src->stride / 4;
1371             }
1372         }
1373         else
1374         {
1375             FIXME("Unsupported conversion: 32 -> 4\n");
1376             return FALSE;
1377         }
1378         break;
1379     }
1380
1381     case 16:
1382     {
1383         WORD *src_start = get_pixel_ptr_16(src, src_rect->left, src_rect->top), *src_pixel;
1384         if(src->funcs == &funcs_555)
1385         {
1386             for(y = src_rect->top; y < src_rect->bottom; y++)
1387             {
1388                 dst_pixel = dst_start;
1389                 src_pixel = src_start;
1390                 for(x = src_rect->left; x < src_rect->right; x++)
1391                 {
1392                     src_val = *src_pixel++;
1393                     dst_val = colorref_to_pixel_colortable(dst, ((src_val >>  7) & 0x0000f8) | ((src_val >> 12) & 0x000007) |
1394                                                                 ((src_val <<  6) & 0x00f800) | ((src_val <<  1) & 0x000700) |
1395                                                                 ((src_val << 19) & 0xf80000) | ((src_val << 14) & 0x070000) );
1396                     if((x - src_rect->left) & 1)
1397                     {
1398                         *dst_pixel = (dst_val & 0x0f) | (*dst_pixel & 0xf0);
1399                         dst_pixel++;
1400                     }
1401                     else
1402                         *dst_pixel = (dst_val << 4) & 0xf0;
1403                 }
1404                 dst_start += dst->stride;
1405                 src_start += src->stride / 2;
1406             }
1407         }
1408         else
1409         {
1410             FIXME("Unsupported conversion: 16 -> 4\n");
1411             return FALSE;
1412         }
1413         break;
1414     }
1415
1416     case 8:
1417     {
1418         BYTE *src_start = get_pixel_ptr_8(src, src_rect->left, src_rect->top), *src_pixel;
1419
1420         for(y = src_rect->top; y < src_rect->bottom; y++)
1421         {
1422             dst_pixel = dst_start;
1423             src_pixel = src_start;
1424             for(x = src_rect->left; x < src_rect->right; x++)
1425             {
1426                 RGBQUAD rgb;
1427                 src_val = *src_pixel++;
1428                 if(src_val >= src->color_table_size) src_val = src->color_table_size - 1;
1429                 rgb = src->color_table[src_val];
1430                 dst_val = colorref_to_pixel_colortable(dst, RGB(rgb.rgbRed, rgb.rgbGreen, rgb.rgbBlue));
1431                 if((x - src_rect->left) & 1)
1432                 {
1433                     *dst_pixel = (dst_val & 0x0f) | (*dst_pixel & 0xf0);
1434                     dst_pixel++;
1435                 }
1436                 else
1437                     *dst_pixel = (dst_val << 4) & 0xf0;
1438             }
1439             dst_start += dst->stride;
1440             src_start += src->stride;
1441         }
1442         break;
1443     }
1444
1445     case 4:
1446     {
1447         BYTE *src_start = get_pixel_ptr_4(src, src_rect->left, src_rect->top), *src_pixel;
1448
1449         if(color_tables_match(dst, src) && (src_rect->left & 1) == 0)
1450         {
1451             if(src->stride > 0 && dst->stride > 0 && src_rect->left == 0 && src_rect->right == src->width)
1452                 memcpy(dst->bits, src_start, (src_rect->bottom - src_rect->top) * src->stride);
1453             else
1454             {
1455                 for(y = src_rect->top; y < src_rect->bottom; y++)
1456                 {
1457                     memcpy(dst_start, src_start, (src_rect->right - src_rect->left + 1) / 2);
1458                     dst_start += dst->stride;
1459                     src_start += src->stride;
1460                 }
1461             }
1462         }
1463         else
1464         {
1465             for(y = src_rect->top; y < src_rect->bottom; y++)
1466             {
1467                 dst_pixel = dst_start;
1468                 src_pixel = src_start;
1469                 for(x = src_rect->left; x < src_rect->right; x++)
1470                 {
1471                     RGBQUAD rgb;
1472                     if(x & 1)
1473                         src_val = *src_pixel++ & 0xf;
1474                     else
1475                         src_val = (*src_pixel >> 4) & 0xf;
1476                     if(src_val >= src->color_table_size) src_val = src->color_table_size - 1;
1477                     rgb = src->color_table[src_val];
1478                     dst_val = colorref_to_pixel_colortable(dst, RGB(rgb.rgbRed, rgb.rgbGreen, rgb.rgbBlue));
1479                     if((x - src_rect->left) & 1)
1480                     {
1481                         *dst_pixel = (dst_val & 0x0f) | (*dst_pixel & 0xf0);
1482                         dst_pixel++;
1483                     }
1484                     else
1485                         *dst_pixel = (dst_val << 4) & 0xf0;
1486                 }
1487                 dst_start += dst->stride;
1488                 src_start += src->stride;
1489             }
1490         }
1491         break;
1492     }
1493
1494     default:
1495         FIXME("Unsupported conversion: %d -> 4\n", src->bit_count);
1496         return FALSE;
1497
1498     }
1499
1500     return TRUE;
1501 }
1502
1503 static BOOL convert_to_null(dib_info *dst, const dib_info *src, const RECT *src_rect)
1504 {
1505     return TRUE;
1506 }
1507
1508 const primitive_funcs funcs_8888 =
1509 {
1510     solid_rects_32,
1511     pattern_rects_32,
1512     colorref_to_pixel_888,
1513     convert_to_8888
1514 };
1515
1516 const primitive_funcs funcs_32 =
1517 {
1518     solid_rects_32,
1519     pattern_rects_32,
1520     colorref_to_pixel_masks,
1521     convert_to_32
1522 };
1523
1524 const primitive_funcs funcs_24 =
1525 {
1526     solid_rects_24,
1527     pattern_rects_24,
1528     colorref_to_pixel_888,
1529     convert_to_24
1530 };
1531
1532 const primitive_funcs funcs_555 =
1533 {
1534     solid_rects_16,
1535     pattern_rects_16,
1536     colorref_to_pixel_555,
1537     convert_to_555
1538 };
1539
1540 const primitive_funcs funcs_16 =
1541 {
1542     solid_rects_16,
1543     pattern_rects_16,
1544     colorref_to_pixel_masks,
1545     convert_to_16
1546 };
1547
1548 const primitive_funcs funcs_8 =
1549 {
1550     solid_rects_8,
1551     pattern_rects_8,
1552     colorref_to_pixel_colortable,
1553     convert_to_8
1554 };
1555
1556 const primitive_funcs funcs_4 =
1557 {
1558     solid_rects_4,
1559     pattern_rects_4,
1560     colorref_to_pixel_colortable,
1561     convert_to_4
1562 };
1563
1564 const primitive_funcs funcs_null =
1565 {
1566     solid_rects_null,
1567     pattern_rects_null,
1568     colorref_to_pixel_null,
1569     convert_to_null
1570 };