gdi32: Add support for 24 bpp brushes.
[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 24:
630     {
631         BYTE *src_start = get_pixel_ptr_24(src, src_rect->left, src_rect->top), *src_pixel;
632
633         for(y = src_rect->top; y < src_rect->bottom; y++)
634         {
635             dst_pixel = dst_start;
636             src_pixel = src_start;
637             for(x = src_rect->left; x < src_rect->right; x++)
638             {
639                 RGBQUAD rgb;
640                 rgb.rgbBlue  = *src_pixel++;
641                 rgb.rgbGreen = *src_pixel++;
642                 rgb.rgbRed   = *src_pixel++;
643
644                 *dst_pixel++ = ((rgb.rgbRed << 16) & 0xff0000) | ((rgb.rgbGreen << 8) & 0x00ff00) | (rgb.rgbBlue & 0x0000ff);
645             }
646             dst_start += dst->stride / 4;
647             src_start += src->stride;
648         }
649         break;
650     }
651
652     case 16:
653     {
654         WORD *src_start = get_pixel_ptr_16(src, src_rect->left, src_rect->top), *src_pixel;
655         if(src->funcs == &funcs_555)
656         {
657             for(y = src_rect->top; y < src_rect->bottom; y++)
658             {
659                 dst_pixel = dst_start;
660                 src_pixel = src_start;
661                 for(x = src_rect->left; x < src_rect->right; x++)
662                 {
663                     src_val = *src_pixel++;
664                     *dst_pixel++ = ((src_val << 9) & 0xf80000) | ((src_val << 4) & 0x070000) |
665                                    ((src_val << 6) & 0x00f800) | ((src_val << 1) & 0x000700) |
666                                    ((src_val << 3) & 0x0000f8) | ((src_val >> 2) & 0x000007);
667                 }
668                 dst_start += dst->stride / 4;
669                 src_start += src->stride / 2;
670             }
671         }
672         else
673         {
674             FIXME("Unsupported conversion: 16 -> 8888\n");
675             return FALSE;
676         }
677         break;
678     }
679
680     case 8:
681     {
682         BYTE *src_start = get_pixel_ptr_8(src, src_rect->left, src_rect->top), *src_pixel;
683         for(y = src_rect->top; y < src_rect->bottom; y++)
684         {
685             dst_pixel = dst_start;
686             src_pixel = src_start;
687             for(x = src_rect->left; x < src_rect->right; x++)
688             {
689                 RGBQUAD rgb;
690                 src_val = *src_pixel++;
691                 if(src_val >= src->color_table_size) src_val = src->color_table_size - 1;
692                 rgb = src->color_table[src_val];
693                 *dst_pixel++ = rgb.rgbRed << 16 | rgb.rgbGreen << 8 | rgb.rgbBlue;
694             }
695             dst_start += dst->stride / 4;
696             src_start += src->stride;
697         }
698         break;
699     }
700
701     case 4:
702     {
703         BYTE *src_start = get_pixel_ptr_4(src, src_rect->left, src_rect->top), *src_pixel;
704         for(y = src_rect->top; y < src_rect->bottom; y++)
705         {
706             dst_pixel = dst_start;
707             src_pixel = src_start;
708             for(x = src_rect->left; x < src_rect->right; x++)
709             {
710                 RGBQUAD rgb;
711                 if(x & 1)
712                     src_val = *src_pixel++ & 0xf;
713                 else
714                     src_val = (*src_pixel >> 4) & 0xf;
715                 if(src_val >= src->color_table_size) src_val = src->color_table_size - 1;
716                 rgb = src->color_table[src_val];
717                 *dst_pixel++ = rgb.rgbRed << 16 | rgb.rgbGreen << 8 | rgb.rgbBlue;
718             }
719             dst_start += dst->stride / 4;
720             src_start += src->stride;
721         }
722         break;
723     }
724
725     default:
726         FIXME("Unsupported conversion: %d -> 8888\n", src->bit_count);
727         return FALSE;
728     }
729
730     return TRUE;
731 }
732
733 static BOOL convert_to_32(dib_info *dst, const dib_info *src, const RECT *src_rect)
734 {
735     DWORD *dst_start = dst->bits, *dst_pixel, src_val;
736     int x, y;
737
738     switch(src->bit_count)
739     {
740     case 32:
741     {
742         DWORD *src_start = get_pixel_ptr_32(src, src_rect->left, src_rect->top), *src_pixel;
743
744         if(src->funcs == &funcs_8888)
745         {
746             for(y = src_rect->top; y < src_rect->bottom; y++)
747             {
748                 dst_pixel = dst_start;
749                 src_pixel = src_start;
750                 for(x = src_rect->left; x < src_rect->right; x++)
751                 {
752                     src_val = *src_pixel++;
753                     *dst_pixel++ = put_field((src_val >> 16) & 0xff, dst->red_shift,   dst->red_len)   |
754                                    put_field((src_val >>  8) & 0xff, dst->green_shift, dst->green_len) |
755                                    put_field( src_val        & 0xff, dst->blue_shift,  dst->blue_len);
756                 }
757                 dst_start += dst->stride / 4;
758                 src_start += src->stride / 4;
759             }
760         }
761         else
762         {
763             FIXME("Unsupported conversion: 32 -> 32\n");
764             return FALSE;
765         }
766         break;
767     }
768
769     case 24:
770     {
771         BYTE *src_start = get_pixel_ptr_24(src, src_rect->left, src_rect->top), *src_pixel;
772
773         for(y = src_rect->top; y < src_rect->bottom; y++)
774         {
775             dst_pixel = dst_start;
776             src_pixel = src_start;
777             for(x = src_rect->left; x < src_rect->right; x++)
778             {
779                 RGBQUAD rgb;
780                 rgb.rgbBlue  = *src_pixel++;
781                 rgb.rgbGreen = *src_pixel++;
782                 rgb.rgbRed   = *src_pixel++;
783
784                 *dst_pixel++ = put_field(rgb.rgbRed,   dst->red_shift,   dst->red_len)   |
785                                put_field(rgb.rgbGreen, dst->green_shift, dst->green_len) |
786                                put_field(rgb.rgbBlue,  dst->blue_shift,  dst->blue_len);
787             }
788             dst_start += dst->stride / 4;
789             src_start += src->stride;
790         }
791         break;
792     }
793
794     case 16:
795     {
796         WORD *src_start = get_pixel_ptr_16(src, src_rect->left, src_rect->top), *src_pixel;
797         if(src->funcs == &funcs_555)
798         {
799             for(y = src_rect->top; y < src_rect->bottom; y++)
800             {
801                 dst_pixel = dst_start;
802                 src_pixel = src_start;
803                 for(x = src_rect->left; x < src_rect->right; x++)
804                 {
805                     src_val = *src_pixel++;
806                     *dst_pixel++ = put_field(((src_val >> 7) & 0xf8) | ((src_val >> 12) & 0x07), dst->red_shift,   dst->red_len) |
807                                    put_field(((src_val >> 2) & 0xf8) | ((src_val >>  7) & 0x07), dst->green_shift, dst->green_len) |
808                                    put_field(((src_val << 3) & 0xf8) | ((src_val >>  2) & 0x07), dst->blue_shift,  dst->blue_len);
809                 }
810                 dst_start += dst->stride / 4;
811                 src_start += src->stride / 2;
812             }
813         }
814         else
815         {
816             FIXME("Unsupported conversion: 16 -> 8888\n");
817             return FALSE;
818         }
819         break;
820     }
821
822     case 8:
823     {
824         BYTE *src_start = get_pixel_ptr_8(src, src_rect->left, src_rect->top), *src_pixel;
825         for(y = src_rect->top; y < src_rect->bottom; y++)
826         {
827             dst_pixel = dst_start;
828             src_pixel = src_start;
829             for(x = src_rect->left; x < src_rect->right; x++)
830             {
831                 RGBQUAD rgb;
832                 src_val = *src_pixel++;
833                 if(src_val >= src->color_table_size) src_val = src->color_table_size - 1;
834                 rgb = src->color_table[src_val];
835                 *dst_pixel++ = put_field(rgb.rgbRed,   dst->red_shift,   dst->red_len) |
836                                put_field(rgb.rgbGreen, dst->green_shift, dst->green_len) |
837                                put_field(rgb.rgbBlue,  dst->blue_shift,  dst->blue_len);
838             }
839             dst_start += dst->stride / 4;
840             src_start += src->stride;
841         }
842         break;
843     }
844
845     case 4:
846     {
847         BYTE *src_start = get_pixel_ptr_4(src, src_rect->left, src_rect->top), *src_pixel;
848         for(y = src_rect->top; y < src_rect->bottom; y++)
849         {
850             dst_pixel = dst_start;
851             src_pixel = src_start;
852             for(x = src_rect->left; x < src_rect->right; x++)
853             {
854                 RGBQUAD rgb;
855                 if(x & 1)
856                     src_val = *src_pixel++ & 0xf;
857                 else
858                     src_val = (*src_pixel >> 4) & 0xf;
859                 if(src_val >= src->color_table_size) src_val = src->color_table_size - 1;
860                 rgb = src->color_table[src_val];
861                 *dst_pixel++ = put_field(rgb.rgbRed,   dst->red_shift,   dst->red_len) |
862                                put_field(rgb.rgbGreen, dst->green_shift, dst->green_len) |
863                                put_field(rgb.rgbBlue,  dst->blue_shift,  dst->blue_len);
864             }
865             dst_start += dst->stride / 4;
866             src_start += src->stride;
867         }
868         break;
869     }
870
871     default:
872         FIXME("Unsupported conversion: %d -> 32\n", src->bit_count);
873         return FALSE;
874     }
875
876     return TRUE;
877 }
878
879 static BOOL convert_to_24(dib_info *dst, const dib_info *src, const RECT *src_rect)
880 {
881     BYTE *dst_start = dst->bits, *dst_pixel;
882     DWORD src_val;
883     int x, y;
884
885     switch(src->bit_count)
886     {
887     case 32:
888     {
889         DWORD *src_start = get_pixel_ptr_32(src, src_rect->left, src_rect->top), *src_pixel;
890         if(src->funcs == &funcs_8888)
891         {
892             for(y = src_rect->top; y < src_rect->bottom; y++)
893             {
894                 dst_pixel = dst_start;
895                 src_pixel = src_start;
896                 for(x = src_rect->left; x < src_rect->right; x++)
897                 {
898                     src_val = *src_pixel++;
899                     *dst_pixel++ =  src_val        & 0xff;
900                     *dst_pixel++ = (src_val >>  8) & 0xff;
901                     *dst_pixel++ = (src_val >> 16) & 0xff;
902                 }
903                 dst_start += dst->stride;
904                 src_start += src->stride / 4;
905             }
906         }
907         else
908         {
909             FIXME("Unsupported conversion: 32 -> 24\n");
910             return FALSE;
911         }
912         break;
913     }
914
915     case 24:
916     {
917         BYTE *src_start = get_pixel_ptr_24(src, src_rect->left, src_rect->top);
918
919         if(src->stride > 0 && dst->stride > 0 && src_rect->left == 0 && src_rect->right == src->width)
920             memcpy(dst->bits, src_start, (src_rect->bottom - src_rect->top) * src->stride);
921         else
922         {
923             for(y = src_rect->top; y < src_rect->bottom; y++)
924             {
925                 memcpy(dst_start, src_start, (src_rect->right - src_rect->left) * 3);
926                 dst_start += dst->stride;
927                 src_start += src->stride;
928             }
929         }
930         break;
931     }
932
933     case 16:
934     {
935         WORD *src_start = get_pixel_ptr_16(src, src_rect->left, src_rect->top), *src_pixel;
936         if(src->funcs == &funcs_555)
937         {
938             for(y = src_rect->top; y < src_rect->bottom; y++)
939             {
940                 dst_pixel = dst_start;
941                 src_pixel = src_start;
942                 for(x = src_rect->left; x < src_rect->right; x++)
943                 {
944                     src_val = *src_pixel++;
945                     *dst_pixel++ = ((src_val << 3) & 0xf8) | ((src_val >>  2) & 0x07);
946                     *dst_pixel++ = ((src_val >> 2) & 0xf8) | ((src_val >>  7) & 0x07);
947                     *dst_pixel++ = ((src_val >> 7) & 0xf8) | ((src_val >> 12) & 0x07);
948                 }
949                 dst_start += dst->stride;
950                 src_start += src->stride / 2;
951             }
952         }
953         else
954         {
955             FIXME("Unsupported conversion: 16 -> 24\n");
956             return FALSE;
957         }
958         break;
959     }
960
961     case 8:
962     {
963         BYTE *src_start = get_pixel_ptr_8(src, src_rect->left, src_rect->top), *src_pixel;
964         for(y = src_rect->top; y < src_rect->bottom; y++)
965         {
966             dst_pixel = dst_start;
967             src_pixel = src_start;
968             for(x = src_rect->left; x < src_rect->right; x++)
969             {
970                 RGBQUAD rgb;
971                 src_val = *src_pixel++;
972                 if(src_val >= src->color_table_size) src_val = src->color_table_size - 1;
973                 rgb = src->color_table[src_val];
974                 *dst_pixel++ = rgb.rgbBlue;
975                 *dst_pixel++ = rgb.rgbGreen;
976                 *dst_pixel++ = rgb.rgbRed;
977             }
978             dst_start += dst->stride;
979             src_start += src->stride;
980         }
981         break;
982     }
983
984     case 4:
985     {
986         BYTE *src_start = get_pixel_ptr_4(src, src_rect->left, src_rect->top), *src_pixel;
987         for(y = src_rect->top; y < src_rect->bottom; y++)
988         {
989             dst_pixel = dst_start;
990             src_pixel = src_start;
991             for(x = src_rect->left; x < src_rect->right; x++)
992             {
993                 RGBQUAD rgb;
994                 if(x & 1)
995                     src_val = *src_pixel++ & 0xf;
996                 else
997                     src_val = (*src_pixel >> 4) & 0xf;
998                 if(src_val >= src->color_table_size) src_val = src->color_table_size - 1;
999                 rgb = src->color_table[src_val];
1000                 *dst_pixel++ = rgb.rgbBlue;
1001                 *dst_pixel++ = rgb.rgbGreen;
1002                 *dst_pixel++ = rgb.rgbRed;
1003             }
1004             dst_start += dst->stride;
1005             src_start += src->stride;
1006         }
1007         break;
1008     }
1009
1010     default:
1011         FIXME("Unsupported conversion: %d -> 24\n", src->bit_count);
1012         return FALSE;
1013     }
1014
1015     return TRUE;
1016 }
1017
1018 static BOOL convert_to_555(dib_info *dst, const dib_info *src, const RECT *src_rect)
1019 {
1020     WORD *dst_start = dst->bits, *dst_pixel;
1021     INT x, y;
1022     DWORD src_val;
1023
1024     switch(src->bit_count)
1025     {
1026     case 32:
1027     {
1028         DWORD *src_start = get_pixel_ptr_32(src, src_rect->left, src_rect->top), *src_pixel;
1029
1030         if(src->funcs == &funcs_8888)
1031         {
1032             for(y = src_rect->top; y < src_rect->bottom; y++)
1033             {
1034                 dst_pixel = dst_start;
1035                 src_pixel = src_start;
1036                 for(x = src_rect->left; x < src_rect->right; x++)
1037                 {
1038                     src_val = *src_pixel++;
1039                     *dst_pixel++ = ((src_val >> 9) & 0x7c00) |
1040                                    ((src_val >> 6) & 0x03e0) |
1041                                    ((src_val >> 3) & 0x001e);
1042                 }
1043                 dst_start += dst->stride / 2;
1044                 src_start += src->stride / 4;
1045             }
1046         }
1047         else
1048         {
1049             FIXME("Unsupported conversion: 32 -> 555\n");
1050             return FALSE;
1051         }
1052         break;
1053     }
1054
1055     case 24:
1056     {
1057         BYTE *src_start = get_pixel_ptr_24(src, src_rect->left, src_rect->top), *src_pixel;
1058
1059         for(y = src_rect->top; y < src_rect->bottom; y++)
1060         {
1061             dst_pixel = dst_start;
1062             src_pixel = src_start;
1063             for(x = src_rect->left; x < src_rect->right; x++)
1064             {
1065                 RGBQUAD rgb;
1066                 rgb.rgbBlue  = *src_pixel++;
1067                 rgb.rgbGreen = *src_pixel++;
1068                 rgb.rgbRed   = *src_pixel++;
1069
1070                 *dst_pixel++ = ((rgb.rgbRed   << 7) & 0x7c00) |
1071                                ((rgb.rgbGreen << 2) & 0x03e0) |
1072                                ((rgb.rgbBlue  >> 3) & 0x001f);
1073             }
1074             dst_start += dst->stride / 2;
1075             src_start += src->stride;
1076         }
1077         break;
1078     }
1079
1080     case 16:
1081     {
1082         WORD *src_start = get_pixel_ptr_16(src, src_rect->left, src_rect->top);
1083         if(src->funcs == &funcs_555)
1084         {
1085             if(src->stride > 0 && dst->stride > 0 && src_rect->left == 0 && src_rect->right == src->width)
1086                 memcpy(dst->bits, src_start, (src_rect->bottom - src_rect->top) * src->stride);
1087             else
1088             {
1089                 for(y = src_rect->top; y < src_rect->bottom; y++)
1090                 {
1091                     memcpy(dst_start, src_start, (src_rect->right - src_rect->left) * 2);
1092                     dst_start += dst->stride / 2;
1093                     src_start += src->stride / 2;
1094                 }
1095             }
1096         }
1097         else
1098         {
1099             FIXME("Unsupported conversion: 16 -> 555\n");
1100             return FALSE;
1101         }
1102         break;
1103     }
1104
1105     case 8:
1106     {
1107         BYTE *src_start = get_pixel_ptr_8(src, src_rect->left, src_rect->top), *src_pixel;
1108         for(y = src_rect->top; y < src_rect->bottom; y++)
1109         {
1110             dst_pixel = dst_start;
1111             src_pixel = src_start;
1112             for(x = src_rect->left; x < src_rect->right; x++)
1113             {
1114                 RGBQUAD rgb;
1115                 src_val = *src_pixel++;
1116                 if(src_val >= src->color_table_size) src_val = src->color_table_size - 1;
1117                 rgb = src->color_table[src_val];
1118                 *dst_pixel++ = ((rgb.rgbRed   << 7) & 0x7c00) |
1119                                ((rgb.rgbGreen << 2) & 0x03e0) |
1120                                ((rgb.rgbBlue  >> 3) & 0x001f);
1121             }
1122             dst_start += dst->stride / 2;
1123             src_start += src->stride;
1124         }
1125         break;
1126     }
1127
1128     case 4:
1129     {
1130         BYTE *src_start = get_pixel_ptr_4(src, src_rect->left, src_rect->top), *src_pixel;
1131         for(y = src_rect->top; y < src_rect->bottom; y++)
1132         {
1133             dst_pixel = dst_start;
1134             src_pixel = src_start;
1135             for(x = src_rect->left; x < src_rect->right; x++)
1136             {
1137                 RGBQUAD rgb;
1138                 if(x & 1)
1139                     src_val = *src_pixel++ & 0xf;
1140                 else
1141                     src_val = (*src_pixel >> 4) & 0xf;
1142                 if(src_val >= src->color_table_size) src_val = src->color_table_size - 1;
1143                 rgb = src->color_table[src_val];
1144                 *dst_pixel++ = ((rgb.rgbRed   << 7) & 0x7c00) |
1145                                ((rgb.rgbGreen << 2) & 0x03e0) |
1146                                ((rgb.rgbBlue  >> 3) & 0x001f);
1147             }
1148             dst_start += dst->stride / 2;
1149             src_start += src->stride;
1150         }
1151         break;
1152     }
1153
1154     default:
1155         FIXME("Unsupported conversion: %d -> 555\n", src->bit_count);
1156         return FALSE;
1157
1158     }
1159     return TRUE;
1160 }
1161
1162 static BOOL convert_to_16(dib_info *dst, const dib_info *src, const RECT *src_rect)
1163 {
1164     WORD *dst_start = dst->bits, *dst_pixel;
1165     INT x, y;
1166     DWORD src_val;
1167
1168     switch(src->bit_count)
1169     {
1170     case 32:
1171     {
1172         DWORD *src_start = get_pixel_ptr_32(src, src_rect->left, src_rect->top), *src_pixel;
1173
1174         if(src->funcs == &funcs_8888)
1175         {
1176             for(y = src_rect->top; y < src_rect->bottom; y++)
1177             {
1178                 dst_pixel = dst_start;
1179                 src_pixel = src_start;
1180                 for(x = src_rect->left; x < src_rect->right; x++)
1181                 {
1182                     src_val = *src_pixel++;
1183                     *dst_pixel++ = put_field((src_val >> 16) & 0xff, dst->red_shift,   dst->red_len)   |
1184                                    put_field((src_val >>  8) & 0xff, dst->green_shift, dst->green_len) |
1185                                    put_field( src_val        & 0xff, dst->blue_shift,  dst->blue_len);
1186                 }
1187                 dst_start += dst->stride / 2;
1188                 src_start += src->stride / 4;
1189             }
1190         }
1191         else
1192         {
1193             FIXME("Unsupported conversion: 32 -> 16\n");
1194             return FALSE;
1195         }
1196         break;
1197     }
1198
1199     case 24:
1200     {
1201         BYTE *src_start = get_pixel_ptr_24(src, src_rect->left, src_rect->top), *src_pixel;
1202
1203         for(y = src_rect->top; y < src_rect->bottom; y++)
1204         {
1205             dst_pixel = dst_start;
1206             src_pixel = src_start;
1207             for(x = src_rect->left; x < src_rect->right; x++)
1208             {
1209                 RGBQUAD rgb;
1210                 rgb.rgbBlue  = *src_pixel++;
1211                 rgb.rgbGreen = *src_pixel++;
1212                 rgb.rgbRed   = *src_pixel++;
1213
1214                 *dst_pixel++ = put_field(rgb.rgbRed,   dst->red_shift,   dst->red_len) |
1215                                put_field(rgb.rgbGreen, dst->green_shift, dst->green_len) |
1216                                put_field(rgb.rgbBlue,  dst->blue_shift,  dst->blue_len);
1217             }
1218             dst_start += dst->stride / 2;
1219             src_start += src->stride;
1220         }
1221         break;
1222     }
1223
1224     case 16:
1225     {
1226         WORD *src_start = get_pixel_ptr_16(src, src_rect->left, src_rect->top), *src_pixel;
1227         if(src->funcs == &funcs_555)
1228         {
1229             for(y = src_rect->top; y < src_rect->bottom; y++)
1230             {
1231                 dst_pixel = dst_start;
1232                 src_pixel = src_start;
1233                 for(x = src_rect->left; x < src_rect->right; x++)
1234                 {
1235                     src_val = *src_pixel++;
1236                     *dst_pixel++ = put_field(((src_val >> 7) & 0xf8) | ((src_val >> 12) & 0x07), dst->red_shift,   dst->red_len) |
1237                                    put_field(((src_val >> 2) & 0xf8) | ((src_val >>  7) & 0x07), dst->green_shift, dst->green_len) |
1238                                    put_field(((src_val << 3) & 0xf8) | ((src_val >>  2) & 0x07), dst->blue_shift,  dst->blue_len);
1239                 }
1240                 dst_start += dst->stride / 2;
1241                 src_start += src->stride / 2;
1242             }
1243         }
1244         else
1245         {
1246             FIXME("Unsupported conversion: 16 -> 16\n");
1247             return FALSE;
1248         }
1249         break;
1250     }
1251
1252     case 8:
1253     {
1254         BYTE *src_start = get_pixel_ptr_8(src, src_rect->left, src_rect->top), *src_pixel;
1255         for(y = src_rect->top; y < src_rect->bottom; y++)
1256         {
1257             dst_pixel = dst_start;
1258             src_pixel = src_start;
1259             for(x = src_rect->left; x < src_rect->right; x++)
1260             {
1261                 RGBQUAD rgb;
1262                 src_val = *src_pixel++;
1263                 if(src_val >= src->color_table_size) src_val = src->color_table_size - 1;
1264                 rgb = src->color_table[src_val];
1265                 *dst_pixel++ = put_field(rgb.rgbRed,   dst->red_shift,   dst->red_len) |
1266                                put_field(rgb.rgbGreen, dst->green_shift, dst->green_len) |
1267                                put_field(rgb.rgbBlue,  dst->blue_shift,  dst->blue_len);
1268             }
1269             dst_start += dst->stride / 2;
1270             src_start += src->stride;
1271         }
1272         break;
1273     }
1274
1275     case 4:
1276     {
1277         BYTE *src_start = get_pixel_ptr_4(src, src_rect->left, src_rect->top), *src_pixel;
1278         for(y = src_rect->top; y < src_rect->bottom; y++)
1279         {
1280             dst_pixel = dst_start;
1281             src_pixel = src_start;
1282             for(x = src_rect->left; x < src_rect->right; x++)
1283             {
1284                 RGBQUAD rgb;
1285                 if(x & 1)
1286                     src_val = *src_pixel++ & 0xf;
1287                 else
1288                     src_val = (*src_pixel >> 4) & 0xf;
1289                 if(src_val >= src->color_table_size) src_val = src->color_table_size - 1;
1290                 rgb = src->color_table[src_val];
1291                 *dst_pixel++ = put_field(rgb.rgbRed,   dst->red_shift,   dst->red_len) |
1292                                put_field(rgb.rgbGreen, dst->green_shift, dst->green_len) |
1293                                put_field(rgb.rgbBlue,  dst->blue_shift,  dst->blue_len);
1294             }
1295             dst_start += dst->stride / 2;
1296             src_start += src->stride;
1297         }
1298         break;
1299     }
1300
1301     default:
1302         FIXME("Unsupported conversion: %d -> 16\n", src->bit_count);
1303         return FALSE;
1304
1305     }
1306     return TRUE;
1307 }
1308
1309 static inline BOOL color_tables_match(const dib_info *d1, const dib_info *d2)
1310 {
1311     assert(d1->color_table_size && d2->color_table_size);
1312
1313     if(d1->color_table_size != d2->color_table_size) return FALSE;
1314     return !memcmp(d1->color_table, d2->color_table, d1->color_table_size * sizeof(d1->color_table[0]));
1315 }
1316
1317 static BOOL convert_to_8(dib_info *dst, const dib_info *src, const RECT *src_rect)
1318 {
1319     BYTE *dst_start = dst->bits, *dst_pixel;
1320     INT x, y;
1321     DWORD src_val;
1322
1323     switch(src->bit_count)
1324     {
1325     case 32:
1326     {
1327         DWORD *src_start = get_pixel_ptr_32(src, src_rect->left, src_rect->top), *src_pixel;
1328
1329         if(src->funcs == &funcs_8888)
1330         {
1331             for(y = src_rect->top; y < src_rect->bottom; y++)
1332             {
1333                 dst_pixel = dst_start;
1334                 src_pixel = src_start;
1335                 for(x = src_rect->left; x < src_rect->right; x++)
1336                 {
1337                     src_val = *src_pixel++;
1338                     *dst_pixel++ = colorref_to_pixel_colortable(dst, ((src_val >> 16) & 0x0000ff) |
1339                                                                      ( src_val        & 0x00ff00) |
1340                                                                      ((src_val << 16) & 0xff0000) );
1341                 }
1342                 dst_start += dst->stride;
1343                 src_start += src->stride / 4;
1344             }
1345         }
1346         else
1347         {
1348             FIXME("Unsupported conversion: 32 -> 8\n");
1349             return FALSE;
1350         }
1351         break;
1352     }
1353
1354     case 24:
1355     {
1356         BYTE *src_start = get_pixel_ptr_24(src, src_rect->left, src_rect->top), *src_pixel;
1357
1358         for(y = src_rect->top; y < src_rect->bottom; y++)
1359         {
1360             dst_pixel = dst_start;
1361             src_pixel = src_start;
1362             for(x = src_rect->left; x < src_rect->right; x++)
1363             {
1364                 RGBQUAD rgb;
1365                 rgb.rgbBlue  = *src_pixel++;
1366                 rgb.rgbGreen = *src_pixel++;
1367                 rgb.rgbRed   = *src_pixel++;
1368
1369                 *dst_pixel++ = colorref_to_pixel_colortable(dst, ( rgb.rgbRed         & 0x0000ff) |
1370                                                                  ((rgb.rgbGreen << 8) & 0x00ff00) |
1371                                                                  ((rgb.rgbBlue << 16) & 0xff0000));
1372             }
1373             dst_start += dst->stride;
1374             src_start += src->stride;
1375         }
1376         break;
1377     }
1378
1379     case 16:
1380     {
1381         WORD *src_start = get_pixel_ptr_16(src, src_rect->left, src_rect->top), *src_pixel;
1382         if(src->funcs == &funcs_555)
1383         {
1384             for(y = src_rect->top; y < src_rect->bottom; y++)
1385             {
1386                 dst_pixel = dst_start;
1387                 src_pixel = src_start;
1388                 for(x = src_rect->left; x < src_rect->right; x++)
1389                 {
1390                     src_val = *src_pixel++;
1391                     *dst_pixel++ = colorref_to_pixel_colortable(dst, ((src_val >>  7) & 0x0000f8) | ((src_val >> 12) & 0x000007) |
1392                                                                      ((src_val <<  6) & 0x00f800) | ((src_val <<  1) & 0x000700) |
1393                                                                      ((src_val << 19) & 0xf80000) | ((src_val << 14) & 0x070000) );
1394                 }
1395                 dst_start += dst->stride;
1396                 src_start += src->stride / 2;
1397             }
1398         }
1399         else
1400         {
1401             FIXME("Unsupported conversion: 16 -> 8\n");
1402             return FALSE;
1403         }
1404         break;
1405     }
1406
1407     case 8:
1408     {
1409         BYTE *src_start = get_pixel_ptr_8(src, src_rect->left, src_rect->top), *src_pixel;
1410
1411         if(color_tables_match(dst, src))
1412         {
1413             if(src->stride > 0 && dst->stride > 0 && src_rect->left == 0 && src_rect->right == src->width)
1414                 memcpy(dst->bits, src_start, (src_rect->bottom - src_rect->top) * src->stride);
1415             else
1416             {
1417                 for(y = src_rect->top; y < src_rect->bottom; y++)
1418                 {
1419                     memcpy(dst_start, src_start, src_rect->right - src_rect->left);
1420                     dst_start += dst->stride;
1421                     src_start += src->stride;
1422                 }
1423             }
1424         }
1425         else
1426         {
1427             for(y = src_rect->top; y < src_rect->bottom; y++)
1428             {
1429                 dst_pixel = dst_start;
1430                 src_pixel = src_start;
1431                 for(x = src_rect->left; x < src_rect->right; x++)
1432                 {
1433                     RGBQUAD rgb;
1434                     src_val = *src_pixel++;
1435                     if(src_val >= src->color_table_size) src_val = src->color_table_size - 1;
1436                     rgb = src->color_table[src_val];
1437                     *dst_pixel++ = colorref_to_pixel_colortable(dst, RGB(rgb.rgbRed, rgb.rgbGreen, rgb.rgbBlue));
1438                 }
1439                 dst_start += dst->stride;
1440                 src_start += src->stride;
1441             }
1442         }
1443         break;
1444     }
1445
1446     case 4:
1447     {
1448         BYTE *src_start = get_pixel_ptr_4(src, src_rect->left, src_rect->top), *src_pixel;
1449         for(y = src_rect->top; y < src_rect->bottom; y++)
1450         {
1451             dst_pixel = dst_start;
1452             src_pixel = src_start;
1453             for(x = src_rect->left; x < src_rect->right; x++)
1454             {
1455                 RGBQUAD rgb;
1456                 if(x & 1)
1457                     src_val = *src_pixel++ & 0xf;
1458                 else
1459                     src_val = (*src_pixel >> 4) & 0xf;
1460                 if(src_val >= src->color_table_size) src_val = src->color_table_size - 1;
1461                 rgb = src->color_table[src_val];
1462                 *dst_pixel++ = colorref_to_pixel_colortable(dst, RGB(rgb.rgbRed, rgb.rgbGreen, rgb.rgbBlue));
1463             }
1464             dst_start += dst->stride;
1465             src_start += src->stride;
1466         }
1467         break;
1468     }
1469
1470     default:
1471         FIXME("Unsupported conversion: %d -> 8\n", src->bit_count);
1472         return FALSE;
1473
1474     }
1475     return TRUE;
1476 }
1477
1478 static BOOL convert_to_4(dib_info *dst, const dib_info *src, const RECT *src_rect)
1479 {
1480     BYTE *dst_start = dst->bits, *dst_pixel, dst_val;
1481     INT x, y;
1482     DWORD src_val;
1483
1484     switch(src->bit_count)
1485     {
1486     case 32:
1487     {
1488         DWORD *src_start = get_pixel_ptr_32(src, src_rect->left, src_rect->top), *src_pixel;
1489
1490         if(src->funcs == &funcs_8888)
1491         {
1492             for(y = src_rect->top; y < src_rect->bottom; y++)
1493             {
1494                 dst_pixel = dst_start;
1495                 src_pixel = src_start;
1496                 for(x = src_rect->left; x < src_rect->right; x++)
1497                 {
1498                     src_val = *src_pixel++;
1499                     dst_val = colorref_to_pixel_colortable(dst, ((src_val >> 16) & 0x0000ff) |
1500                                                                 ( src_val        & 0x00ff00) |
1501                                                                 ((src_val << 16) & 0xff0000) );
1502                     if((x - src_rect->left) & 1)
1503                     {
1504                         *dst_pixel = (dst_val & 0x0f) | (*dst_pixel & 0xf0);
1505                         dst_pixel++;
1506                     }
1507                     else
1508                         *dst_pixel = (dst_val << 4) & 0xf0;
1509                 }
1510                 dst_start += dst->stride;
1511                 src_start += src->stride / 4;
1512             }
1513         }
1514         else
1515         {
1516             FIXME("Unsupported conversion: 32 -> 4\n");
1517             return FALSE;
1518         }
1519         break;
1520     }
1521
1522     case 24:
1523     {
1524         BYTE *src_start = get_pixel_ptr_24(src, src_rect->left, src_rect->top), *src_pixel;
1525
1526         for(y = src_rect->top; y < src_rect->bottom; y++)
1527         {
1528             dst_pixel = dst_start;
1529             src_pixel = src_start;
1530             for(x = src_rect->left; x < src_rect->right; x++)
1531             {
1532                 RGBQUAD rgb;
1533                 rgb.rgbBlue  = *src_pixel++;
1534                 rgb.rgbGreen = *src_pixel++;
1535                 rgb.rgbRed   = *src_pixel++;
1536
1537                 dst_val = colorref_to_pixel_colortable(dst, ( rgb.rgbRed         & 0x0000ff) |
1538                                                             ((rgb.rgbGreen << 8) & 0x00ff00) |
1539                                                             ((rgb.rgbBlue << 16) & 0xff0000));
1540
1541                 if((x - src_rect->left) & 1)
1542                 {
1543                     *dst_pixel = (dst_val & 0x0f) | (*dst_pixel & 0xf0);
1544                     dst_pixel++;
1545                 }
1546                 else
1547                     *dst_pixel = (dst_val << 4) & 0xf0;
1548             }
1549             dst_start += dst->stride;
1550             src_start += src->stride;
1551         }
1552         break;
1553     }
1554
1555     case 16:
1556     {
1557         WORD *src_start = get_pixel_ptr_16(src, src_rect->left, src_rect->top), *src_pixel;
1558         if(src->funcs == &funcs_555)
1559         {
1560             for(y = src_rect->top; y < src_rect->bottom; y++)
1561             {
1562                 dst_pixel = dst_start;
1563                 src_pixel = src_start;
1564                 for(x = src_rect->left; x < src_rect->right; x++)
1565                 {
1566                     src_val = *src_pixel++;
1567                     dst_val = colorref_to_pixel_colortable(dst, ((src_val >>  7) & 0x0000f8) | ((src_val >> 12) & 0x000007) |
1568                                                                 ((src_val <<  6) & 0x00f800) | ((src_val <<  1) & 0x000700) |
1569                                                                 ((src_val << 19) & 0xf80000) | ((src_val << 14) & 0x070000) );
1570                     if((x - src_rect->left) & 1)
1571                     {
1572                         *dst_pixel = (dst_val & 0x0f) | (*dst_pixel & 0xf0);
1573                         dst_pixel++;
1574                     }
1575                     else
1576                         *dst_pixel = (dst_val << 4) & 0xf0;
1577                 }
1578                 dst_start += dst->stride;
1579                 src_start += src->stride / 2;
1580             }
1581         }
1582         else
1583         {
1584             FIXME("Unsupported conversion: 16 -> 4\n");
1585             return FALSE;
1586         }
1587         break;
1588     }
1589
1590     case 8:
1591     {
1592         BYTE *src_start = get_pixel_ptr_8(src, src_rect->left, src_rect->top), *src_pixel;
1593
1594         for(y = src_rect->top; y < src_rect->bottom; y++)
1595         {
1596             dst_pixel = dst_start;
1597             src_pixel = src_start;
1598             for(x = src_rect->left; x < src_rect->right; x++)
1599             {
1600                 RGBQUAD rgb;
1601                 src_val = *src_pixel++;
1602                 if(src_val >= src->color_table_size) src_val = src->color_table_size - 1;
1603                 rgb = src->color_table[src_val];
1604                 dst_val = colorref_to_pixel_colortable(dst, RGB(rgb.rgbRed, rgb.rgbGreen, rgb.rgbBlue));
1605                 if((x - src_rect->left) & 1)
1606                 {
1607                     *dst_pixel = (dst_val & 0x0f) | (*dst_pixel & 0xf0);
1608                     dst_pixel++;
1609                 }
1610                 else
1611                     *dst_pixel = (dst_val << 4) & 0xf0;
1612             }
1613             dst_start += dst->stride;
1614             src_start += src->stride;
1615         }
1616         break;
1617     }
1618
1619     case 4:
1620     {
1621         BYTE *src_start = get_pixel_ptr_4(src, src_rect->left, src_rect->top), *src_pixel;
1622
1623         if(color_tables_match(dst, src) && (src_rect->left & 1) == 0)
1624         {
1625             if(src->stride > 0 && dst->stride > 0 && src_rect->left == 0 && src_rect->right == src->width)
1626                 memcpy(dst->bits, src_start, (src_rect->bottom - src_rect->top) * src->stride);
1627             else
1628             {
1629                 for(y = src_rect->top; y < src_rect->bottom; y++)
1630                 {
1631                     memcpy(dst_start, src_start, (src_rect->right - src_rect->left + 1) / 2);
1632                     dst_start += dst->stride;
1633                     src_start += src->stride;
1634                 }
1635             }
1636         }
1637         else
1638         {
1639             for(y = src_rect->top; y < src_rect->bottom; y++)
1640             {
1641                 dst_pixel = dst_start;
1642                 src_pixel = src_start;
1643                 for(x = src_rect->left; x < src_rect->right; x++)
1644                 {
1645                     RGBQUAD rgb;
1646                     if(x & 1)
1647                         src_val = *src_pixel++ & 0xf;
1648                     else
1649                         src_val = (*src_pixel >> 4) & 0xf;
1650                     if(src_val >= src->color_table_size) src_val = src->color_table_size - 1;
1651                     rgb = src->color_table[src_val];
1652                     dst_val = colorref_to_pixel_colortable(dst, RGB(rgb.rgbRed, rgb.rgbGreen, rgb.rgbBlue));
1653                     if((x - src_rect->left) & 1)
1654                     {
1655                         *dst_pixel = (dst_val & 0x0f) | (*dst_pixel & 0xf0);
1656                         dst_pixel++;
1657                     }
1658                     else
1659                         *dst_pixel = (dst_val << 4) & 0xf0;
1660                 }
1661                 dst_start += dst->stride;
1662                 src_start += src->stride;
1663             }
1664         }
1665         break;
1666     }
1667
1668     default:
1669         FIXME("Unsupported conversion: %d -> 4\n", src->bit_count);
1670         return FALSE;
1671
1672     }
1673
1674     return TRUE;
1675 }
1676
1677 static BOOL convert_to_null(dib_info *dst, const dib_info *src, const RECT *src_rect)
1678 {
1679     return TRUE;
1680 }
1681
1682 const primitive_funcs funcs_8888 =
1683 {
1684     solid_rects_32,
1685     pattern_rects_32,
1686     colorref_to_pixel_888,
1687     convert_to_8888
1688 };
1689
1690 const primitive_funcs funcs_32 =
1691 {
1692     solid_rects_32,
1693     pattern_rects_32,
1694     colorref_to_pixel_masks,
1695     convert_to_32
1696 };
1697
1698 const primitive_funcs funcs_24 =
1699 {
1700     solid_rects_24,
1701     pattern_rects_24,
1702     colorref_to_pixel_888,
1703     convert_to_24
1704 };
1705
1706 const primitive_funcs funcs_555 =
1707 {
1708     solid_rects_16,
1709     pattern_rects_16,
1710     colorref_to_pixel_555,
1711     convert_to_555
1712 };
1713
1714 const primitive_funcs funcs_16 =
1715 {
1716     solid_rects_16,
1717     pattern_rects_16,
1718     colorref_to_pixel_masks,
1719     convert_to_16
1720 };
1721
1722 const primitive_funcs funcs_8 =
1723 {
1724     solid_rects_8,
1725     pattern_rects_8,
1726     colorref_to_pixel_colortable,
1727     convert_to_8
1728 };
1729
1730 const primitive_funcs funcs_4 =
1731 {
1732     solid_rects_4,
1733     pattern_rects_4,
1734     colorref_to_pixel_colortable,
1735     convert_to_4
1736 };
1737
1738 const primitive_funcs funcs_null =
1739 {
1740     solid_rects_null,
1741     pattern_rects_null,
1742     colorref_to_pixel_null,
1743     convert_to_null
1744 };