gdi32: Add support for 4 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 WORD *get_pixel_ptr_16(const dib_info *dib, int x, int y)
36 {
37     return (WORD *)((BYTE*)dib->bits + y * dib->stride + x * 2);
38 }
39
40 static inline BYTE *get_pixel_ptr_8(const dib_info *dib, int x, int y)
41 {
42     return (BYTE*)dib->bits + y * dib->stride + x;
43 }
44
45 static inline BYTE *get_pixel_ptr_4(const dib_info *dib, int x, int y)
46 {
47     return (BYTE*)dib->bits + y * dib->stride + x / 2;
48 }
49
50 static inline void do_rop_32(DWORD *ptr, DWORD and, DWORD xor)
51 {
52     *ptr = (*ptr & and) ^ xor;
53 }
54
55 static inline void do_rop_16(WORD *ptr, WORD and, WORD xor)
56 {
57     *ptr = (*ptr & and) ^ xor;
58 }
59
60 static inline void do_rop_8(BYTE *ptr, BYTE and, BYTE xor)
61 {
62     *ptr = (*ptr & and) ^ xor;
63 }
64
65 static void solid_rects_32(const dib_info *dib, int num, const RECT *rc, DWORD and, DWORD xor)
66 {
67     DWORD *ptr, *start;
68     int x, y, i;
69
70     for(i = 0; i < num; i++, rc++)
71     {
72         start = get_pixel_ptr_32(dib, rc->left, rc->top);
73         for(y = rc->top; y < rc->bottom; y++, start += dib->stride / 4)
74             for(x = rc->left, ptr = start; x < rc->right; x++)
75                 do_rop_32(ptr++, and, xor);
76     }
77 }
78
79 static void solid_rects_16(const dib_info *dib, int num, const RECT *rc, DWORD and, DWORD xor)
80 {
81     WORD *ptr, *start;
82     int x, y, i;
83
84     for(i = 0; i < num; i++, rc++)
85     {
86         start = get_pixel_ptr_16(dib, rc->left, rc->top);
87         for(y = rc->top; y < rc->bottom; y++, start += dib->stride / 2)
88             for(x = rc->left, ptr = start; x < rc->right; x++)
89                 do_rop_16(ptr++, and, xor);
90     }
91 }
92
93 static void solid_rects_8(const dib_info *dib, int num, const RECT *rc, DWORD and, DWORD xor)
94 {
95     BYTE *ptr, *start;
96     int x, y, i;
97
98     for(i = 0; i < num; i++, rc++)
99     {
100         start = get_pixel_ptr_8(dib, rc->left, rc->top);
101         for(y = rc->top; y < rc->bottom; y++, start += dib->stride)
102             for(x = rc->left, ptr = start; x < rc->right; x++)
103                 do_rop_8(ptr++, and, xor);
104     }
105 }
106
107 static void solid_rects_4(const dib_info *dib, int num, const RECT *rc, DWORD and, DWORD xor)
108 {
109     BYTE *ptr, *start;
110     int x, y, i;
111     BYTE byte_and = (and & 0xf) | ((and << 4) & 0xf0);
112     BYTE byte_xor = (xor & 0xf) | ((xor << 4) & 0xf0);
113
114     for(i = 0; i < num; i++, rc++)
115     {
116         if(rc->left >= rc->right) continue;
117         start = get_pixel_ptr_4(dib, rc->left, rc->top);
118         for(y = rc->top; y < rc->bottom; y++, start += dib->stride)
119         {
120             ptr = start;
121             if(rc->left & 1) /* upper nibble untouched */
122                 do_rop_8(ptr++, byte_and | 0xf0, byte_xor & 0x0f);
123
124             for(x = (rc->left + 1) & ~1; x < (rc->right & ~1); x += 2)
125                 do_rop_8(ptr++, byte_and, byte_xor);
126
127             if(rc->right & 1) /* lower nibble untouched */
128                 do_rop_8(ptr, byte_and | 0x0f, byte_xor & 0xf0);
129         }
130     }
131 }
132
133 static void solid_rects_null(const dib_info *dib, int num, const RECT *rc, DWORD and, DWORD xor)
134 {
135     return;
136 }
137
138 static inline INT calc_offset(INT edge, INT size, INT origin)
139 {
140     INT offset;
141
142     if(edge - origin >= 0)
143         offset = (edge - origin) % size;
144     else
145     {
146         offset = (origin - edge) % size;
147         if(offset) offset = size - offset;
148     }
149     return offset;
150 }
151
152 static inline POINT calc_brush_offset(const RECT *rc, const dib_info *brush, const POINT *origin)
153 {
154     POINT offset;
155
156     offset.x = calc_offset(rc->left, brush->width,  origin->x);
157     offset.y = calc_offset(rc->top,  brush->height, origin->y);
158
159     return offset;
160 }
161
162 static void pattern_rects_32(const dib_info *dib, int num, const RECT *rc, const POINT *origin,
163                              const dib_info *brush, void *and_bits, void *xor_bits)
164 {
165     DWORD *ptr, *start, *start_and, *and_ptr, *start_xor, *xor_ptr;
166     int x, y, i;
167     POINT offset;
168
169     for(i = 0; i < num; i++, rc++)
170     {
171         offset = calc_brush_offset(rc, brush, origin);
172
173         start = get_pixel_ptr_32(dib, rc->left, rc->top);
174         start_and = (DWORD*)and_bits + offset.y * brush->stride / 4;
175         start_xor = (DWORD*)xor_bits + offset.y * brush->stride / 4;
176
177         for(y = rc->top; y < rc->bottom; y++, start += dib->stride / 4)
178         {
179             and_ptr = start_and + offset.x;
180             xor_ptr = start_xor + offset.x;
181
182             for(x = rc->left, ptr = start; x < rc->right; x++)
183             {
184                 do_rop_32(ptr++, *and_ptr++, *xor_ptr++);
185                 if(and_ptr == start_and + brush->width)
186                 {
187                     and_ptr = start_and;
188                     xor_ptr = start_xor;
189                 }
190             }
191
192             offset.y++;
193             if(offset.y == brush->height)
194             {
195                 start_and = and_bits;
196                 start_xor = xor_bits;
197                 offset.y = 0;
198             }
199             else
200             {
201                 start_and += brush->stride / 4;
202                 start_xor += brush->stride / 4;
203             }
204         }
205     }
206 }
207
208 static void pattern_rects_16(const dib_info *dib, int num, const RECT *rc, const POINT *origin,
209                              const dib_info *brush, void *and_bits, void *xor_bits)
210 {
211     WORD *ptr, *start, *start_and, *and_ptr, *start_xor, *xor_ptr;
212     int x, y, i;
213     POINT offset;
214
215     for(i = 0; i < num; i++, rc++)
216     {
217         offset = calc_brush_offset(rc, brush, origin);
218
219         start = get_pixel_ptr_16(dib, rc->left, rc->top);
220         start_and = (WORD*)and_bits + offset.y * brush->stride / 2;
221         start_xor = (WORD*)xor_bits + offset.y * brush->stride / 2;
222
223         for(y = rc->top; y < rc->bottom; y++, start += dib->stride / 2)
224         {
225             and_ptr = start_and + offset.x;
226             xor_ptr = start_xor + offset.x;
227
228             for(x = rc->left, ptr = start; x < rc->right; x++)
229             {
230                 do_rop_16(ptr++, *and_ptr++, *xor_ptr++);
231                 if(and_ptr == start_and + brush->width)
232                 {
233                     and_ptr = start_and;
234                     xor_ptr = start_xor;
235                 }
236             }
237
238             offset.y++;
239             if(offset.y == brush->height)
240             {
241                 start_and = and_bits;
242                 start_xor = xor_bits;
243                 offset.y = 0;
244             }
245             else
246             {
247                 start_and += brush->stride / 2;
248                 start_xor += brush->stride / 2;
249             }
250         }
251     }
252 }
253
254 static void pattern_rects_8(const dib_info *dib, int num, const RECT *rc, const POINT *origin,
255                             const dib_info *brush, void *and_bits, void *xor_bits)
256 {
257     BYTE *ptr, *start, *start_and, *and_ptr, *start_xor, *xor_ptr;
258     int x, y, i;
259     POINT offset;
260
261     for(i = 0; i < num; i++, rc++)
262     {
263         offset = calc_brush_offset(rc, brush, origin);
264
265         start = get_pixel_ptr_8(dib, rc->left, rc->top);
266         start_and = (BYTE*)and_bits + offset.y * brush->stride;
267         start_xor = (BYTE*)xor_bits + offset.y * brush->stride;
268
269         for(y = rc->top; y < rc->bottom; y++, start += dib->stride)
270         {
271             and_ptr = start_and + offset.x;
272             xor_ptr = start_xor + offset.x;
273
274             for(x = rc->left, ptr = start; x < rc->right; x++)
275             {
276                 do_rop_8(ptr++, *and_ptr++, *xor_ptr++);
277                 if(and_ptr == start_and + brush->width)
278                 {
279                     and_ptr = start_and;
280                     xor_ptr = start_xor;
281                 }
282             }
283
284             offset.y++;
285             if(offset.y == brush->height)
286             {
287                 start_and = and_bits;
288                 start_xor = xor_bits;
289                 offset.y = 0;
290             }
291             else
292             {
293                 start_and += brush->stride;
294                 start_xor += brush->stride;
295             }
296         }
297     }
298 }
299
300 static void pattern_rects_4(const dib_info *dib, int num, const RECT *rc, const POINT *origin,
301                             const dib_info *brush, void *and_bits, void *xor_bits)
302 {
303     BYTE *ptr, *start, *start_and, *and_ptr, *start_xor, *xor_ptr;
304     int x, y, i;
305     POINT offset;
306
307     for(i = 0; i < num; i++, rc++)
308     {
309         offset = calc_brush_offset(rc, brush, origin);
310
311         start = get_pixel_ptr_4(dib, rc->left, rc->top);
312         start_and = (BYTE*)and_bits + offset.y * brush->stride;
313         start_xor = (BYTE*)xor_bits + offset.y * brush->stride;
314
315         for(y = rc->top; y < rc->bottom; y++, start += dib->stride)
316         {
317             INT brush_x = offset.x;
318             BYTE byte_and, byte_xor;
319
320             and_ptr = start_and + brush_x / 2;
321             xor_ptr = start_xor + brush_x / 2;
322
323             for(x = rc->left, ptr = start; x < rc->right; x++)
324             {
325                 /* FIXME: Two pixels at a time */
326                 if(x & 1) /* lower dst nibble */
327                 {
328                     if(brush_x & 1) /* lower pat nibble */
329                     {
330                         byte_and = *and_ptr++ | 0xf0;
331                         byte_xor = *xor_ptr++ & 0x0f;
332                     }
333                     else /* upper pat nibble */
334                     {
335                         byte_and = (*and_ptr >> 4) | 0xf0;
336                         byte_xor = (*xor_ptr >> 4) & 0x0f;
337                     }
338                 }
339                 else /* upper dst nibble */
340                 {
341                     if(brush_x & 1) /* lower pat nibble */
342                     {
343                         byte_and = (*and_ptr++ << 4) | 0x0f;
344                         byte_xor = (*xor_ptr++ << 4) & 0xf0;
345                     }
346                     else /* upper pat nibble */
347                     {
348                         byte_and = *and_ptr | 0x0f;
349                         byte_xor = *xor_ptr & 0xf0;
350                     }
351                 }
352                 do_rop_8(ptr, byte_and, byte_xor);
353
354                 if(x & 1) ptr++;
355
356                 if(++brush_x == brush->width)
357                 {
358                     brush_x = 0;
359                     and_ptr = start_and;
360                     xor_ptr = start_xor;
361                 }
362             }
363
364             offset.y++;
365             if(offset.y == brush->height)
366             {
367                 start_and = and_bits;
368                 start_xor = xor_bits;
369                 offset.y = 0;
370             }
371             else
372             {
373                 start_and += brush->stride;
374                 start_xor += brush->stride;
375             }
376         }
377     }
378 }
379
380 static void pattern_rects_null(const dib_info *dib, int num, const RECT *rc, const POINT *origin,
381                                const dib_info *brush, void *and_bits, void *xor_bits)
382 {
383     return;
384 }
385
386 static DWORD colorref_to_pixel_888(const dib_info *dib, COLORREF color)
387 {
388     return ( ((color >> 16) & 0xff) | (color & 0xff00) | ((color << 16) & 0xff0000) );
389 }
390
391 static inline DWORD put_field(DWORD field, int shift, int len)
392 {
393     shift = shift - (8 - len);
394     if (len <= 8)
395         field &= (((1 << len) - 1) << (8 - len));
396     if (shift < 0)
397         field >>= -shift;
398     else
399         field <<= shift;
400     return field;
401 }
402
403 static DWORD colorref_to_pixel_masks(const dib_info *dib, COLORREF colour)
404 {
405     DWORD r,g,b;
406
407     r = GetRValue(colour);
408     g = GetGValue(colour);
409     b = GetBValue(colour);
410
411     return put_field(r, dib->red_shift,   dib->red_len) |
412            put_field(g, dib->green_shift, dib->green_len) |
413            put_field(b, dib->blue_shift,  dib->blue_len);
414 }
415
416 static DWORD colorref_to_pixel_555(const dib_info *dib, COLORREF color)
417 {
418     return ( ((color >> 19) & 0x1f) | ((color >> 6) & 0x03e0) | ((color << 7) & 0x7c00) );
419 }
420
421 static DWORD colorref_to_pixel_colortable(const dib_info *dib, COLORREF color)
422 {
423     int i, best_index = 0;
424     RGBQUAD rgb;
425     DWORD diff, best_diff = 0xffffffff;
426
427     rgb.rgbRed = GetRValue(color);
428     rgb.rgbGreen = GetGValue(color);
429     rgb.rgbBlue = GetBValue(color);
430
431     for(i = 0; i < dib->color_table_size; i++)
432     {
433         RGBQUAD *cur = dib->color_table + i;
434         diff = (rgb.rgbRed - cur->rgbRed) * (rgb.rgbRed - cur->rgbRed)
435             +  (rgb.rgbGreen - cur->rgbGreen) * (rgb.rgbGreen - cur->rgbGreen)
436             +  (rgb.rgbBlue - cur->rgbBlue) * (rgb.rgbBlue - cur->rgbBlue);
437
438         if(diff == 0)
439         {
440             best_index = i;
441             break;
442         }
443
444         if(diff < best_diff)
445         {
446             best_diff = diff;
447             best_index = i;
448         }
449     }
450     return best_index;
451 }
452
453 static DWORD colorref_to_pixel_null(const dib_info *dib, COLORREF color)
454 {
455     return 0;
456 }
457
458 static BOOL convert_to_8888(dib_info *dst, const dib_info *src, const RECT *src_rect)
459 {
460     DWORD *dst_start = dst->bits, *dst_pixel, src_val;
461     int x, y;
462
463     switch(src->bit_count)
464     {
465     case 32:
466     {
467         DWORD *src_start = get_pixel_ptr_32(src, src_rect->left, src_rect->top);
468         if(src->funcs == &funcs_8888)
469         {
470             if(src->stride > 0 && dst->stride > 0 && src_rect->left == 0 && src_rect->right == src->width)
471                 memcpy(dst->bits, src_start, (src_rect->bottom - src_rect->top) * src->stride);
472             else
473             {
474                 for(y = src_rect->top; y < src_rect->bottom; y++)
475                 {
476                     memcpy(dst_start, src_start, (src_rect->right - src_rect->left) * 4);
477                     dst_start += dst->stride / 4;
478                     src_start += src->stride / 4;
479                 }
480             }
481         }
482         else
483         {
484             FIXME("Unsupported conversion: 32 -> 8888\n");
485             return FALSE;
486         }
487         break;
488     }
489
490     case 16:
491     {
492         WORD *src_start = get_pixel_ptr_16(src, src_rect->left, src_rect->top), *src_pixel;
493         if(src->funcs == &funcs_555)
494         {
495             for(y = src_rect->top; y < src_rect->bottom; y++)
496             {
497                 dst_pixel = dst_start;
498                 src_pixel = src_start;
499                 for(x = src_rect->left; x < src_rect->right; x++)
500                 {
501                     src_val = *src_pixel++;
502                     *dst_pixel++ = ((src_val << 9) & 0xf80000) | ((src_val << 4) & 0x070000) |
503                                    ((src_val << 6) & 0x00f800) | ((src_val << 1) & 0x000700) |
504                                    ((src_val << 3) & 0x0000f8) | ((src_val >> 2) & 0x000007);
505                 }
506                 dst_start += dst->stride / 4;
507                 src_start += src->stride / 2;
508             }
509         }
510         else
511         {
512             FIXME("Unsupported conversion: 16 -> 8888\n");
513             return FALSE;
514         }
515         break;
516     }
517
518     case 8:
519     {
520         BYTE *src_start = get_pixel_ptr_8(src, src_rect->left, src_rect->top), *src_pixel;
521         for(y = src_rect->top; y < src_rect->bottom; y++)
522         {
523             dst_pixel = dst_start;
524             src_pixel = src_start;
525             for(x = src_rect->left; x < src_rect->right; x++)
526             {
527                 RGBQUAD rgb;
528                 src_val = *src_pixel++;
529                 if(src_val >= src->color_table_size) src_val = src->color_table_size - 1;
530                 rgb = src->color_table[src_val];
531                 *dst_pixel++ = rgb.rgbRed << 16 | rgb.rgbGreen << 8 | rgb.rgbBlue;
532             }
533             dst_start += dst->stride / 4;
534             src_start += src->stride;
535         }
536         break;
537     }
538
539     case 4:
540     {
541         BYTE *src_start = get_pixel_ptr_4(src, src_rect->left, src_rect->top), *src_pixel;
542         for(y = src_rect->top; y < src_rect->bottom; y++)
543         {
544             dst_pixel = dst_start;
545             src_pixel = src_start;
546             for(x = src_rect->left; x < src_rect->right; x++)
547             {
548                 RGBQUAD rgb;
549                 if(x & 1)
550                     src_val = *src_pixel++ & 0xf;
551                 else
552                     src_val = (*src_pixel >> 4) & 0xf;
553                 if(src_val >= src->color_table_size) src_val = src->color_table_size - 1;
554                 rgb = src->color_table[src_val];
555                 *dst_pixel++ = rgb.rgbRed << 16 | rgb.rgbGreen << 8 | rgb.rgbBlue;
556             }
557             dst_start += dst->stride / 4;
558             src_start += src->stride;
559         }
560         break;
561     }
562
563     default:
564         FIXME("Unsupported conversion: %d -> 8888\n", src->bit_count);
565         return FALSE;
566     }
567
568     return TRUE;
569 }
570
571 static BOOL convert_to_32(dib_info *dst, const dib_info *src, const RECT *src_rect)
572 {
573     DWORD *dst_start = dst->bits, *dst_pixel, src_val;
574     int x, y;
575
576     switch(src->bit_count)
577     {
578     case 32:
579     {
580         DWORD *src_start = get_pixel_ptr_32(src, src_rect->left, src_rect->top), *src_pixel;
581
582         if(src->funcs == &funcs_8888)
583         {
584             for(y = src_rect->top; y < src_rect->bottom; y++)
585             {
586                 dst_pixel = dst_start;
587                 src_pixel = src_start;
588                 for(x = src_rect->left; x < src_rect->right; x++)
589                 {
590                     src_val = *src_pixel++;
591                     *dst_pixel++ = put_field((src_val >> 16) & 0xff, dst->red_shift,   dst->red_len)   |
592                                    put_field((src_val >>  8) & 0xff, dst->green_shift, dst->green_len) |
593                                    put_field( src_val        & 0xff, dst->blue_shift,  dst->blue_len);
594                 }
595                 dst_start += dst->stride / 4;
596                 src_start += src->stride / 4;
597             }
598         }
599         else
600         {
601             FIXME("Unsupported conversion: 32 -> 32\n");
602             return FALSE;
603         }
604         break;
605     }
606
607     case 16:
608     {
609         WORD *src_start = get_pixel_ptr_16(src, src_rect->left, src_rect->top), *src_pixel;
610         if(src->funcs == &funcs_555)
611         {
612             for(y = src_rect->top; y < src_rect->bottom; y++)
613             {
614                 dst_pixel = dst_start;
615                 src_pixel = src_start;
616                 for(x = src_rect->left; x < src_rect->right; x++)
617                 {
618                     src_val = *src_pixel++;
619                     *dst_pixel++ = put_field(((src_val >> 7) & 0xf8) | ((src_val >> 12) & 0x07), dst->red_shift,   dst->red_len) |
620                                    put_field(((src_val >> 2) & 0xf8) | ((src_val >>  7) & 0x07), dst->green_shift, dst->green_len) |
621                                    put_field(((src_val << 3) & 0xf8) | ((src_val >>  2) & 0x07), dst->blue_shift,  dst->blue_len);
622                 }
623                 dst_start += dst->stride / 4;
624                 src_start += src->stride / 2;
625             }
626         }
627         else
628         {
629             FIXME("Unsupported conversion: 16 -> 8888\n");
630             return FALSE;
631         }
632         break;
633     }
634
635     case 8:
636     {
637         BYTE *src_start = get_pixel_ptr_8(src, src_rect->left, src_rect->top), *src_pixel;
638         for(y = src_rect->top; y < src_rect->bottom; y++)
639         {
640             dst_pixel = dst_start;
641             src_pixel = src_start;
642             for(x = src_rect->left; x < src_rect->right; x++)
643             {
644                 RGBQUAD rgb;
645                 src_val = *src_pixel++;
646                 if(src_val >= src->color_table_size) src_val = src->color_table_size - 1;
647                 rgb = src->color_table[src_val];
648                 *dst_pixel++ = put_field(rgb.rgbRed,   dst->red_shift,   dst->red_len) |
649                                put_field(rgb.rgbGreen, dst->green_shift, dst->green_len) |
650                                put_field(rgb.rgbBlue,  dst->blue_shift,  dst->blue_len);
651             }
652             dst_start += dst->stride / 4;
653             src_start += src->stride;
654         }
655         break;
656     }
657
658     case 4:
659     {
660         BYTE *src_start = get_pixel_ptr_4(src, src_rect->left, src_rect->top), *src_pixel;
661         for(y = src_rect->top; y < src_rect->bottom; y++)
662         {
663             dst_pixel = dst_start;
664             src_pixel = src_start;
665             for(x = src_rect->left; x < src_rect->right; x++)
666             {
667                 RGBQUAD rgb;
668                 if(x & 1)
669                     src_val = *src_pixel++ & 0xf;
670                 else
671                     src_val = (*src_pixel >> 4) & 0xf;
672                 if(src_val >= src->color_table_size) src_val = src->color_table_size - 1;
673                 rgb = src->color_table[src_val];
674                 *dst_pixel++ = put_field(rgb.rgbRed,   dst->red_shift,   dst->red_len) |
675                                put_field(rgb.rgbGreen, dst->green_shift, dst->green_len) |
676                                put_field(rgb.rgbBlue,  dst->blue_shift,  dst->blue_len);
677             }
678             dst_start += dst->stride / 4;
679             src_start += src->stride;
680         }
681         break;
682     }
683
684     default:
685         FIXME("Unsupported conversion: %d -> 32\n", src->bit_count);
686         return FALSE;
687     }
688
689     return TRUE;
690 }
691
692 static BOOL convert_to_555(dib_info *dst, const dib_info *src, const RECT *src_rect)
693 {
694     WORD *dst_start = dst->bits, *dst_pixel;
695     INT x, y;
696     DWORD src_val;
697
698     switch(src->bit_count)
699     {
700     case 32:
701     {
702         DWORD *src_start = get_pixel_ptr_32(src, src_rect->left, src_rect->top), *src_pixel;
703
704         if(src->funcs == &funcs_8888)
705         {
706             for(y = src_rect->top; y < src_rect->bottom; y++)
707             {
708                 dst_pixel = dst_start;
709                 src_pixel = src_start;
710                 for(x = src_rect->left; x < src_rect->right; x++)
711                 {
712                     src_val = *src_pixel++;
713                     *dst_pixel++ = ((src_val >> 9) & 0x7c00) |
714                                    ((src_val >> 6) & 0x03e0) |
715                                    ((src_val >> 3) & 0x001e);
716                 }
717                 dst_start += dst->stride / 2;
718                 src_start += src->stride / 4;
719             }
720         }
721         else
722         {
723             FIXME("Unsupported conversion: 32 -> 555\n");
724             return FALSE;
725         }
726         break;
727     }
728
729     case 16:
730     {
731         WORD *src_start = get_pixel_ptr_16(src, src_rect->left, src_rect->top);
732         if(src->funcs == &funcs_555)
733         {
734             if(src->stride > 0 && dst->stride > 0 && src_rect->left == 0 && src_rect->right == src->width)
735                 memcpy(dst->bits, src_start, (src_rect->bottom - src_rect->top) * src->stride);
736             else
737             {
738                 for(y = src_rect->top; y < src_rect->bottom; y++)
739                 {
740                     memcpy(dst_start, src_start, (src_rect->right - src_rect->left) * 2);
741                     dst_start += dst->stride / 2;
742                     src_start += src->stride / 2;
743                 }
744             }
745         }
746         else
747         {
748             FIXME("Unsupported conversion: 16 -> 555\n");
749             return FALSE;
750         }
751         break;
752     }
753
754     case 8:
755     {
756         BYTE *src_start = get_pixel_ptr_8(src, src_rect->left, src_rect->top), *src_pixel;
757         for(y = src_rect->top; y < src_rect->bottom; y++)
758         {
759             dst_pixel = dst_start;
760             src_pixel = src_start;
761             for(x = src_rect->left; x < src_rect->right; x++)
762             {
763                 RGBQUAD rgb;
764                 src_val = *src_pixel++;
765                 if(src_val >= src->color_table_size) src_val = src->color_table_size - 1;
766                 rgb = src->color_table[src_val];
767                 *dst_pixel++ = ((rgb.rgbRed   << 7) & 0x7c00) |
768                                ((rgb.rgbGreen << 2) & 0x03e0) |
769                                ((rgb.rgbBlue  >> 3) & 0x001f);
770             }
771             dst_start += dst->stride / 2;
772             src_start += src->stride;
773         }
774         break;
775     }
776
777     case 4:
778     {
779         BYTE *src_start = get_pixel_ptr_4(src, src_rect->left, src_rect->top), *src_pixel;
780         for(y = src_rect->top; y < src_rect->bottom; y++)
781         {
782             dst_pixel = dst_start;
783             src_pixel = src_start;
784             for(x = src_rect->left; x < src_rect->right; x++)
785             {
786                 RGBQUAD rgb;
787                 if(x & 1)
788                     src_val = *src_pixel++ & 0xf;
789                 else
790                     src_val = (*src_pixel >> 4) & 0xf;
791                 if(src_val >= src->color_table_size) src_val = src->color_table_size - 1;
792                 rgb = src->color_table[src_val];
793                 *dst_pixel++ = ((rgb.rgbRed   << 7) & 0x7c00) |
794                                ((rgb.rgbGreen << 2) & 0x03e0) |
795                                ((rgb.rgbBlue  >> 3) & 0x001f);
796             }
797             dst_start += dst->stride / 2;
798             src_start += src->stride;
799         }
800         break;
801     }
802
803     default:
804         FIXME("Unsupported conversion: %d -> 555\n", src->bit_count);
805         return FALSE;
806
807     }
808     return TRUE;
809 }
810
811 static BOOL convert_to_16(dib_info *dst, const dib_info *src, const RECT *src_rect)
812 {
813     WORD *dst_start = dst->bits, *dst_pixel;
814     INT x, y;
815     DWORD src_val;
816
817     switch(src->bit_count)
818     {
819     case 32:
820     {
821         DWORD *src_start = get_pixel_ptr_32(src, src_rect->left, src_rect->top), *src_pixel;
822
823         if(src->funcs == &funcs_8888)
824         {
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                     src_val = *src_pixel++;
832                     *dst_pixel++ = put_field((src_val >> 16) & 0xff, dst->red_shift,   dst->red_len)   |
833                                    put_field((src_val >>  8) & 0xff, dst->green_shift, dst->green_len) |
834                                    put_field( src_val        & 0xff, dst->blue_shift,  dst->blue_len);
835                 }
836                 dst_start += dst->stride / 2;
837                 src_start += src->stride / 4;
838             }
839         }
840         else
841         {
842             FIXME("Unsupported conversion: 32 -> 16\n");
843             return FALSE;
844         }
845         break;
846     }
847
848     case 16:
849     {
850         WORD *src_start = get_pixel_ptr_16(src, src_rect->left, src_rect->top), *src_pixel;
851         if(src->funcs == &funcs_555)
852         {
853             for(y = src_rect->top; y < src_rect->bottom; y++)
854             {
855                 dst_pixel = dst_start;
856                 src_pixel = src_start;
857                 for(x = src_rect->left; x < src_rect->right; x++)
858                 {
859                     src_val = *src_pixel++;
860                     *dst_pixel++ = put_field(((src_val >> 7) & 0xf8) | ((src_val >> 12) & 0x07), dst->red_shift,   dst->red_len) |
861                                    put_field(((src_val >> 2) & 0xf8) | ((src_val >>  7) & 0x07), dst->green_shift, dst->green_len) |
862                                    put_field(((src_val << 3) & 0xf8) | ((src_val >>  2) & 0x07), dst->blue_shift,  dst->blue_len);
863                 }
864                 dst_start += dst->stride / 2;
865                 src_start += src->stride / 2;
866             }
867         }
868         else
869         {
870             FIXME("Unsupported conversion: 16 -> 16\n");
871             return FALSE;
872         }
873         break;
874     }
875
876     case 8:
877     {
878         BYTE *src_start = get_pixel_ptr_8(src, src_rect->left, src_rect->top), *src_pixel;
879         for(y = src_rect->top; y < src_rect->bottom; y++)
880         {
881             dst_pixel = dst_start;
882             src_pixel = src_start;
883             for(x = src_rect->left; x < src_rect->right; x++)
884             {
885                 RGBQUAD rgb;
886                 src_val = *src_pixel++;
887                 if(src_val >= src->color_table_size) src_val = src->color_table_size - 1;
888                 rgb = src->color_table[src_val];
889                 *dst_pixel++ = put_field(rgb.rgbRed,   dst->red_shift,   dst->red_len) |
890                                put_field(rgb.rgbGreen, dst->green_shift, dst->green_len) |
891                                put_field(rgb.rgbBlue,  dst->blue_shift,  dst->blue_len);
892             }
893             dst_start += dst->stride / 2;
894             src_start += src->stride;
895         }
896         break;
897     }
898
899     case 4:
900     {
901         BYTE *src_start = get_pixel_ptr_4(src, src_rect->left, src_rect->top), *src_pixel;
902         for(y = src_rect->top; y < src_rect->bottom; y++)
903         {
904             dst_pixel = dst_start;
905             src_pixel = src_start;
906             for(x = src_rect->left; x < src_rect->right; x++)
907             {
908                 RGBQUAD rgb;
909                 if(x & 1)
910                     src_val = *src_pixel++ & 0xf;
911                 else
912                     src_val = (*src_pixel >> 4) & 0xf;
913                 if(src_val >= src->color_table_size) src_val = src->color_table_size - 1;
914                 rgb = src->color_table[src_val];
915                 *dst_pixel++ = put_field(rgb.rgbRed,   dst->red_shift,   dst->red_len) |
916                                put_field(rgb.rgbGreen, dst->green_shift, dst->green_len) |
917                                put_field(rgb.rgbBlue,  dst->blue_shift,  dst->blue_len);
918             }
919             dst_start += dst->stride / 2;
920             src_start += src->stride;
921         }
922         break;
923     }
924
925     default:
926         FIXME("Unsupported conversion: %d -> 16\n", src->bit_count);
927         return FALSE;
928
929     }
930     return TRUE;
931 }
932
933 static inline BOOL color_tables_match(const dib_info *d1, const dib_info *d2)
934 {
935     assert(d1->color_table_size && d2->color_table_size);
936
937     if(d1->color_table_size != d2->color_table_size) return FALSE;
938     return !memcmp(d1->color_table, d2->color_table, d1->color_table_size * sizeof(d1->color_table[0]));
939 }
940
941 static BOOL convert_to_8(dib_info *dst, const dib_info *src, const RECT *src_rect)
942 {
943     BYTE *dst_start = dst->bits, *dst_pixel;
944     INT x, y;
945     DWORD src_val;
946
947     switch(src->bit_count)
948     {
949     case 32:
950     {
951         DWORD *src_start = get_pixel_ptr_32(src, src_rect->left, src_rect->top), *src_pixel;
952
953         if(src->funcs == &funcs_8888)
954         {
955             for(y = src_rect->top; y < src_rect->bottom; y++)
956             {
957                 dst_pixel = dst_start;
958                 src_pixel = src_start;
959                 for(x = src_rect->left; x < src_rect->right; x++)
960                 {
961                     src_val = *src_pixel++;
962                     *dst_pixel++ = colorref_to_pixel_colortable(dst, ((src_val >> 16) & 0x0000ff) |
963                                                                      ( src_val        & 0x00ff00) |
964                                                                      ((src_val << 16) & 0xff0000) );
965                 }
966                 dst_start += dst->stride;
967                 src_start += src->stride / 4;
968             }
969         }
970         else
971         {
972             FIXME("Unsupported conversion: 32 -> 8\n");
973             return FALSE;
974         }
975         break;
976     }
977
978     case 16:
979     {
980         WORD *src_start = get_pixel_ptr_16(src, src_rect->left, src_rect->top), *src_pixel;
981         if(src->funcs == &funcs_555)
982         {
983             for(y = src_rect->top; y < src_rect->bottom; y++)
984             {
985                 dst_pixel = dst_start;
986                 src_pixel = src_start;
987                 for(x = src_rect->left; x < src_rect->right; x++)
988                 {
989                     src_val = *src_pixel++;
990                     *dst_pixel++ = colorref_to_pixel_colortable(dst, ((src_val >>  7) & 0x0000f8) | ((src_val >> 12) & 0x000007) |
991                                                                      ((src_val <<  6) & 0x00f800) | ((src_val <<  1) & 0x000700) |
992                                                                      ((src_val << 19) & 0xf80000) | ((src_val << 14) & 0x070000) );
993                 }
994                 dst_start += dst->stride;
995                 src_start += src->stride / 2;
996             }
997         }
998         else
999         {
1000             FIXME("Unsupported conversion: 16 -> 8\n");
1001             return FALSE;
1002         }
1003         break;
1004     }
1005
1006     case 8:
1007     {
1008         BYTE *src_start = get_pixel_ptr_8(src, src_rect->left, src_rect->top), *src_pixel;
1009
1010         if(color_tables_match(dst, src))
1011         {
1012             if(src->stride > 0 && dst->stride > 0 && src_rect->left == 0 && src_rect->right == src->width)
1013                 memcpy(dst->bits, src_start, (src_rect->bottom - src_rect->top) * src->stride);
1014             else
1015             {
1016                 for(y = src_rect->top; y < src_rect->bottom; y++)
1017                 {
1018                     memcpy(dst_start, src_start, src_rect->right - src_rect->left);
1019                     dst_start += dst->stride;
1020                     src_start += src->stride;
1021                 }
1022             }
1023         }
1024         else
1025         {
1026             for(y = src_rect->top; y < src_rect->bottom; y++)
1027             {
1028                 dst_pixel = dst_start;
1029                 src_pixel = src_start;
1030                 for(x = src_rect->left; x < src_rect->right; x++)
1031                 {
1032                     RGBQUAD rgb;
1033                     src_val = *src_pixel++;
1034                     if(src_val >= src->color_table_size) src_val = src->color_table_size - 1;
1035                     rgb = src->color_table[src_val];
1036                     *dst_pixel++ = colorref_to_pixel_colortable(dst, RGB(rgb.rgbRed, rgb.rgbGreen, rgb.rgbBlue));
1037                 }
1038                 dst_start += dst->stride;
1039                 src_start += src->stride;
1040             }
1041         }
1042         break;
1043     }
1044
1045     case 4:
1046     {
1047         BYTE *src_start = get_pixel_ptr_4(src, src_rect->left, src_rect->top), *src_pixel;
1048         for(y = src_rect->top; y < src_rect->bottom; y++)
1049         {
1050             dst_pixel = dst_start;
1051             src_pixel = src_start;
1052             for(x = src_rect->left; x < src_rect->right; x++)
1053             {
1054                 RGBQUAD rgb;
1055                 if(x & 1)
1056                     src_val = *src_pixel++ & 0xf;
1057                 else
1058                     src_val = (*src_pixel >> 4) & 0xf;
1059                 if(src_val >= src->color_table_size) src_val = src->color_table_size - 1;
1060                 rgb = src->color_table[src_val];
1061                 *dst_pixel++ = colorref_to_pixel_colortable(dst, RGB(rgb.rgbRed, rgb.rgbGreen, rgb.rgbBlue));
1062             }
1063             dst_start += dst->stride;
1064             src_start += src->stride;
1065         }
1066         break;
1067     }
1068
1069     default:
1070         FIXME("Unsupported conversion: %d -> 8\n", src->bit_count);
1071         return FALSE;
1072
1073     }
1074     return TRUE;
1075 }
1076
1077 static BOOL convert_to_4(dib_info *dst, const dib_info *src, const RECT *src_rect)
1078 {
1079     BYTE *dst_start = dst->bits, *dst_pixel, dst_val;
1080     INT x, y;
1081     DWORD src_val;
1082
1083     switch(src->bit_count)
1084     {
1085     case 32:
1086     {
1087         DWORD *src_start = get_pixel_ptr_32(src, src_rect->left, src_rect->top), *src_pixel;
1088
1089         if(src->funcs == &funcs_8888)
1090         {
1091             for(y = src_rect->top; y < src_rect->bottom; y++)
1092             {
1093                 dst_pixel = dst_start;
1094                 src_pixel = src_start;
1095                 for(x = src_rect->left; x < src_rect->right; x++)
1096                 {
1097                     src_val = *src_pixel++;
1098                     dst_val = colorref_to_pixel_colortable(dst, ((src_val >> 16) & 0x0000ff) |
1099                                                                 ( src_val        & 0x00ff00) |
1100                                                                 ((src_val << 16) & 0xff0000) );
1101                     if((x - src_rect->left) & 1)
1102                     {
1103                         *dst_pixel = (dst_val & 0x0f) | (*dst_pixel & 0xf0);
1104                         dst_pixel++;
1105                     }
1106                     else
1107                         *dst_pixel = (dst_val << 4) & 0xf0;
1108                 }
1109                 dst_start += dst->stride;
1110                 src_start += src->stride / 4;
1111             }
1112         }
1113         else
1114         {
1115             FIXME("Unsupported conversion: 32 -> 4\n");
1116             return FALSE;
1117         }
1118         break;
1119     }
1120
1121     case 16:
1122     {
1123         WORD *src_start = get_pixel_ptr_16(src, src_rect->left, src_rect->top), *src_pixel;
1124         if(src->funcs == &funcs_555)
1125         {
1126             for(y = src_rect->top; y < src_rect->bottom; y++)
1127             {
1128                 dst_pixel = dst_start;
1129                 src_pixel = src_start;
1130                 for(x = src_rect->left; x < src_rect->right; x++)
1131                 {
1132                     src_val = *src_pixel++;
1133                     dst_val = colorref_to_pixel_colortable(dst, ((src_val >>  7) & 0x0000f8) | ((src_val >> 12) & 0x000007) |
1134                                                                 ((src_val <<  6) & 0x00f800) | ((src_val <<  1) & 0x000700) |
1135                                                                 ((src_val << 19) & 0xf80000) | ((src_val << 14) & 0x070000) );
1136                     if((x - src_rect->left) & 1)
1137                     {
1138                         *dst_pixel = (dst_val & 0x0f) | (*dst_pixel & 0xf0);
1139                         dst_pixel++;
1140                     }
1141                     else
1142                         *dst_pixel = (dst_val << 4) & 0xf0;
1143                 }
1144                 dst_start += dst->stride;
1145                 src_start += src->stride / 2;
1146             }
1147         }
1148         else
1149         {
1150             FIXME("Unsupported conversion: 16 -> 4\n");
1151             return FALSE;
1152         }
1153         break;
1154     }
1155
1156     case 8:
1157     {
1158         BYTE *src_start = get_pixel_ptr_8(src, src_rect->left, src_rect->top), *src_pixel;
1159
1160         for(y = src_rect->top; y < src_rect->bottom; y++)
1161         {
1162             dst_pixel = dst_start;
1163             src_pixel = src_start;
1164             for(x = src_rect->left; x < src_rect->right; x++)
1165             {
1166                 RGBQUAD rgb;
1167                 src_val = *src_pixel++;
1168                 if(src_val >= src->color_table_size) src_val = src->color_table_size - 1;
1169                 rgb = src->color_table[src_val];
1170                 dst_val = colorref_to_pixel_colortable(dst, RGB(rgb.rgbRed, rgb.rgbGreen, rgb.rgbBlue));
1171                 if((x - src_rect->left) & 1)
1172                 {
1173                     *dst_pixel = (dst_val & 0x0f) | (*dst_pixel & 0xf0);
1174                     dst_pixel++;
1175                 }
1176                 else
1177                     *dst_pixel = (dst_val << 4) & 0xf0;
1178             }
1179             dst_start += dst->stride;
1180             src_start += src->stride;
1181         }
1182         break;
1183     }
1184
1185     case 4:
1186     {
1187         BYTE *src_start = get_pixel_ptr_4(src, src_rect->left, src_rect->top), *src_pixel;
1188
1189         if(color_tables_match(dst, src) && (src_rect->left & 1) == 0)
1190         {
1191             if(src->stride > 0 && dst->stride > 0 && src_rect->left == 0 && src_rect->right == src->width)
1192                 memcpy(dst->bits, src_start, (src_rect->bottom - src_rect->top) * src->stride);
1193             else
1194             {
1195                 for(y = src_rect->top; y < src_rect->bottom; y++)
1196                 {
1197                     memcpy(dst_start, src_start, (src_rect->right - src_rect->left + 1) / 2);
1198                     dst_start += dst->stride;
1199                     src_start += src->stride;
1200                 }
1201             }
1202         }
1203         else
1204         {
1205             for(y = src_rect->top; y < src_rect->bottom; y++)
1206             {
1207                 dst_pixel = dst_start;
1208                 src_pixel = src_start;
1209                 for(x = src_rect->left; x < src_rect->right; x++)
1210                 {
1211                     RGBQUAD rgb;
1212                     if(x & 1)
1213                         src_val = *src_pixel++ & 0xf;
1214                     else
1215                         src_val = (*src_pixel >> 4) & 0xf;
1216                     if(src_val >= src->color_table_size) src_val = src->color_table_size - 1;
1217                     rgb = src->color_table[src_val];
1218                     dst_val = colorref_to_pixel_colortable(dst, RGB(rgb.rgbRed, rgb.rgbGreen, rgb.rgbBlue));
1219                     if((x - src_rect->left) & 1)
1220                     {
1221                         *dst_pixel = (dst_val & 0x0f) | (*dst_pixel & 0xf0);
1222                         dst_pixel++;
1223                     }
1224                     else
1225                         *dst_pixel = (dst_val << 4) & 0xf0;
1226                 }
1227                 dst_start += dst->stride;
1228                 src_start += src->stride;
1229             }
1230         }
1231         break;
1232     }
1233
1234     default:
1235         FIXME("Unsupported conversion: %d -> 4\n", src->bit_count);
1236         return FALSE;
1237
1238     }
1239
1240     return TRUE;
1241 }
1242
1243 static BOOL convert_to_null(dib_info *dst, const dib_info *src, const RECT *src_rect)
1244 {
1245     return TRUE;
1246 }
1247
1248 const primitive_funcs funcs_8888 =
1249 {
1250     solid_rects_32,
1251     pattern_rects_32,
1252     colorref_to_pixel_888,
1253     convert_to_8888
1254 };
1255
1256 const primitive_funcs funcs_32 =
1257 {
1258     solid_rects_32,
1259     pattern_rects_32,
1260     colorref_to_pixel_masks,
1261     convert_to_32
1262 };
1263
1264 const primitive_funcs funcs_555 =
1265 {
1266     solid_rects_16,
1267     pattern_rects_16,
1268     colorref_to_pixel_555,
1269     convert_to_555
1270 };
1271
1272 const primitive_funcs funcs_16 =
1273 {
1274     solid_rects_16,
1275     pattern_rects_16,
1276     colorref_to_pixel_masks,
1277     convert_to_16
1278 };
1279
1280 const primitive_funcs funcs_8 =
1281 {
1282     solid_rects_8,
1283     pattern_rects_8,
1284     colorref_to_pixel_colortable,
1285     convert_to_8
1286 };
1287
1288 const primitive_funcs funcs_4 =
1289 {
1290     solid_rects_4,
1291     pattern_rects_4,
1292     colorref_to_pixel_colortable,
1293     convert_to_4
1294 };
1295
1296 const primitive_funcs funcs_null =
1297 {
1298     solid_rects_null,
1299     pattern_rects_null,
1300     colorref_to_pixel_null,
1301     convert_to_null
1302 };