DIB Engine: implement most engine functions
[wine/hacks.git] / dlls / winedib.drv / dibdrvbitmap.c
blob2c8c367a658123638a960c371209fa0102163068
1 /*
2 * DIB Engine DIBDRVBITMAP handling
4 * Copyright 2009 Massimo Del Fedele
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.
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.
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
21 #include "config.h"
22 #include "wine/port.h"
24 #include "dibdrv.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(dibdrv);
28 /* gets human-readable dib format name */
29 const char *_DIBDRVBITMAP_GetFormatName(DIBDRVBITMAP const *bmp)
31 if(!bmp)
33 ERR("Null bitmap\n");
34 return "NULL BITMAP DETECTED";
36 switch(bmp->format)
38 case DIBFMT_DIB1:
39 return "DIBFMT_DIB1";
40 case DIBFMT_DIB4:
41 return "DIBFMT_DIB4";
42 case DIBFMT_DIB4_RLE:
43 return "DIBFMT_DIB4_RLE";
44 case DIBFMT_DIB8:
45 return "DIBFMT_DIB8";
46 case DIBFMT_DIB8_RLE:
47 return "DIBFMT_DIB8_RLE";
48 case DIBFMT_DIB16_RGB:
49 return "DIBFMT_DIB_RGB";
50 case DIBFMT_DIB16_BITFIELDS:
51 return "DIBFMT_DIB16_BITFIELDS";
52 case DIBFMT_DIB24:
53 return "DIBFMT_DIB24";
54 case DIBFMT_DIB32_RGB:
55 return "DIBFMT_DIB32_RGB";
56 case DIBFMT_DIB32_BITFIELDS:
57 return "DIBFMT_DIB32_BITFIELDS";
58 case DIBFMT_UNKNOWN:
59 default:
60 return "DIBFMT_UNKNOWN";
64 /* calculates shift and length given a bit mask */
65 static void CalcShiftAndLen(DWORD mask, int *shift, int *len)
67 int s, l;
69 /* FIXME----*/
70 if(mask == 0)
72 FIXME("color mask == 0 -- problem on init_dib\n");
73 *shift = 0;
74 *len = 0;
75 return;
78 /* calculates bit shift
79 (number of 0's on right of bit field */
80 s = 0;
81 while ((mask & 1) == 0)
83 mask >>= 1;
84 s++;
87 /* calculates bitfield length
88 (number of 1's in bit field */
89 l = 0;
90 while ((mask & 1) == 1)
92 mask >>= 1;
93 l++;
95 *shift = s;
96 *len = l;
99 /* initializes bit fields from bit masks */
100 static void InitBitFields(DIBDRVBITMAP *dib, const DWORD *bit_fields)
102 dib->redMask = bit_fields[0];
103 dib->greenMask = bit_fields[1];
104 dib->blueMask = bit_fields[2];
105 CalcShiftAndLen(dib->redMask, &dib->redShift, &dib->redLen);
106 CalcShiftAndLen(dib->greenMask, &dib->greenShift, &dib->greenLen);
107 CalcShiftAndLen(dib->blueMask, &dib->blueShift, &dib->blueLen);
110 /* initializes dib from a bitmap :
111 dib dib being initialized
112 bi source BITMAPINFOHEADER with required DIB format info
113 bit_fields color masks
114 colorTable color table, if any
115 bits pointer to image data array
116 NOTE : DIBDRVBITMAP doesn't owns bits, but do own color table
118 BOOL _DIBDRVBITMAP_InitFromBMIH(DIBDRVBITMAP *dib, const BITMAPINFOHEADER *bi, const DWORD *bit_fields,
119 const RGBQUAD *colorTable, void *bits)
121 MAYBE(TRACE("dib=%p, bi=%p, bit_fields=%p, colorTable=%p, bits=%p\n", dib, bi, bit_fields, colorTable, bits));
123 /* initializes DIB dimensions and color depth */
124 dib->bitCount = bi->biBitCount;
125 dib->width = bi->biWidth;
126 dib->height = bi->biHeight;
127 dib->stride = ((dib->width * dib->bitCount + 31) >> 3) & ~3;
129 /* initializes image data pointer */
130 dib->bits = bits;
131 dib->ownsBits = FALSE;
133 /* initializes color table */
134 dib->colorTableSize = 0;
135 dib->colorTable = NULL;
136 dib->colorTableGrabbed = FALSE;
138 /* checks whether dib is top-down or bottom-up one */
139 if(dib->height < 0)
141 /* top-down dib */
142 dib->height = -dib->height;
144 else
146 /* bottom-up dib */
147 /* data->bits always points to the top-left corner and the stride is -ve */
148 dib->bits = (BYTE*)dib->bits + (dib->height - 1) * dib->stride;
149 dib->stride = -dib->stride;
152 /* gets and stores bitmap format */
153 switch(dib->bitCount)
155 case 24:
156 dib->format = DIBFMT_DIB24;
157 dib->funcs = &DIBDRV_funcs_DIB24;
158 break;
160 case 32:
162 if(bi->biCompression == BI_RGB)
164 dib->format = DIBFMT_DIB32_RGB;
165 dib->funcs = &DIBDRV_funcs_DIB32_RGB;
167 else
169 InitBitFields(dib, bit_fields);
170 dib->format = DIBFMT_DIB32_BITFIELDS;
171 dib->funcs = &DIBDRV_funcs_DIB32_BITFIELDS;
173 break;
175 case 16:
176 if(bi->biCompression == BI_RGB)
178 dib->format = DIBFMT_DIB16_RGB;
179 dib->funcs = &DIBDRV_funcs_DIB16_RGB;
181 else
183 InitBitFields(dib, bit_fields);
184 dib->format = DIBFMT_DIB16_BITFIELDS;
185 dib->funcs = &DIBDRV_funcs_DIB16_BITFIELDS;
187 break;
189 case 8:
190 dib->format = DIBFMT_DIB8;
191 dib->funcs = &DIBDRV_funcs_DIB8;
192 dib->colorTableSize = 256;
193 if(bi->biClrUsed) dib->colorTableSize = bi->biClrUsed;
194 break;
196 case 4:
197 dib->format = DIBFMT_DIB4;
198 dib->funcs = &DIBDRV_funcs_DIB4;
199 dib->colorTableSize = 16;
200 if(bi->biClrUsed) dib->colorTableSize = bi->biClrUsed;
201 break;
203 case 1:
204 dib->format = DIBFMT_DIB1;
205 dib->funcs = &DIBDRV_funcs_DIB1;
206 dib->colorTableSize = 2;
207 if(bi->biClrUsed) dib->colorTableSize = bi->biClrUsed;
208 break;
210 default:
211 dib->format = DIBFMT_UNKNOWN;
212 dib->funcs = NULL;
213 FIXME("bpp %d not supported\n", dib->bitCount);
214 return FALSE;
216 MAYBE(TRACE("DIB FORMAT : %s\n", _DIBDRVBITMAP_GetFormatName(dib)));
218 /* allocates color table and copy it from source, *if* source is
219 not null */
220 if(dib->colorTableSize && colorTable)
222 if(!(dib->colorTable = HeapAlloc(GetProcessHeap(), 0,
223 dib->colorTableSize * sizeof(dib->colorTable[0]))
226 ERR("HeapAlloc failed\n");
227 return FALSE;
229 memcpy(dib->colorTable, colorTable,
230 dib->colorTableSize * sizeof(dib->colorTable[0]));
231 dib->colorTableGrabbed = TRUE;
233 else if(!dib->colorTableSize)
234 /* no color table on more than 8 bits/pixel */
235 dib->colorTableGrabbed = TRUE;
237 MAYBE(TRACE("END\n"));
238 return TRUE;
241 BOOL _DIBDRVBITMAP_InitFromBitmapinfo(DIBDRVBITMAP *dib, BITMAPINFO *bmi)
243 static const DWORD bit_fields_DIB32_RGB[3] = {0xff0000, 0x00ff00, 0x0000ff};
244 static const DWORD bit_fields_DIB16_RGB[3] = {0x7c00, 0x03e0, 0x001f};
245 BITMAPINFOHEADER *bi = (BITMAPINFOHEADER *)bmi;
246 const DWORD *masks = NULL;
247 RGBQUAD *colorTable = NULL;
248 BYTE *ptr = (BYTE*)bmi + bi->biSize;
249 int num_colors = bi->biClrUsed;
250 BOOL res;
252 MAYBE(TRACE("dib=%p, bmi=%p\n", dib, bmi));
254 if(bi->biCompression == BI_BITFIELDS)
256 masks = (DWORD *)ptr;
257 ptr += 3 * sizeof(DWORD);
259 else if(bi->biBitCount == 32)
260 masks = bit_fields_DIB32_RGB;
261 else if(bi->biBitCount == 16)
262 masks = bit_fields_DIB16_RGB;
264 if(!num_colors && bi->biBitCount <= 8)
265 num_colors = 1 << bi->biBitCount;
266 if(num_colors)
267 colorTable = (RGBQUAD*)ptr;
268 ptr += num_colors * sizeof(*colorTable);
270 res = _DIBDRVBITMAP_InitFromBMIH(dib, bi, masks, colorTable, ptr);
271 MAYBE(TRACE("END\n"));
272 return res;
275 /* initializes a DIBRDVBITMAP copying it from a source one
276 Parameters :
277 dib destination DIBDRVBITMAP
278 src source DIBDRVBITMAP
279 copy TRUE->copy source pixel array FALSE->link to source pixel array
281 BOOL _DIBDRVBITMAP_InitFromDibdrvbitmap(DIBDRVBITMAP *dib, const DIBDRVBITMAP *src, BOOL copy)
283 MAYBE(TRACE("dib=%p, src=%p, copy=%d\n", dib, src, copy));
285 dib->format = src->format;
286 dib->width = src->width;
287 dib->height = src->height;
288 dib->stride = src->stride;
289 dib->bitCount = src->bitCount;
291 dib->redMask = src->redMask;
292 dib->greenMask = src->greenMask;
293 dib->blueMask = src->blueMask;
294 dib->redShift = src->redShift;
295 dib->greenShift = src->greenShift;
296 dib->blueShift = src->blueShift;
297 dib->redLen = src->redLen;
298 dib->greenLen = src->greenLen;
299 dib->blueLen = src->blueLen;
301 dib->funcs = src->funcs;
303 if(copy)
305 int size = dib->height*abs(dib->stride);
306 if(!(dib->bits = HeapAlloc(GetProcessHeap(), 0, size)))
308 ERR("Failed to allocate bits buffer\n");
309 return FALSE;
311 dib->ownsBits = TRUE;
313 /* check for bottom-up DIB */
314 if(dib->stride < 0)
316 /* copy the bitmap array */
317 memcpy(dib->bits, (BYTE *)src->bits + (src->height - 1) * src->stride, size);
319 dib->bits = (BYTE *)dib->bits - (dib->height-1) * dib->stride;
321 else
323 /* copy the bitmap array */
324 memcpy(dib->bits, src->bits, size);
327 else
329 dib->bits = src->bits;
330 dib->ownsBits = FALSE;
333 if(src->colorTable)
335 dib->colorTable = HeapAlloc(GetProcessHeap(), 0, src->colorTableSize * sizeof(src->colorTable[0]));
336 memcpy(dib->colorTable, src->colorTable, src->colorTableSize * sizeof(src->colorTable[0]));
338 else
339 dib->colorTable = NULL;
340 dib->colorTableSize = src->colorTableSize;
341 dib->colorTableGrabbed = TRUE;
342 MAYBE(TRACE("END\n"));
343 return TRUE;
346 /* creates a DIBRDVBITMAP copying format info from a source one
347 Parameters :
348 dib destination DIBDRVBITMAP
349 src source DIBDRVBITMAP
350 widht, height sizes of newly created bitmap
352 BOOL _DIBDRVBITMAP_CreateFromDibdrvbitmap(DIBDRVBITMAP *dib, const DIBDRVBITMAP *src, int width, int height)
354 MAYBE(TRACE("dib=%p, src=%p, width=%d, height=%d\n", dib, src, width, height));
356 /* grab color and format info from source DIB */
357 if(!_DIBDRVBITMAP_InitFromDibdrvbitmap(dib, src, FALSE))
359 ERR("Failed grabbing source dib format\n");
360 return FALSE;
363 /* sets up new DIB dimensions */
364 dib->width = width;
365 dib->height = height;
367 /* calculates new stride basing of new width */
368 dib->stride = ((width * dib->bitCount +31) &~31) / 8;
369 if(src->stride < 0)
370 dib->stride = -dib->stride;
372 /* allocates bits for newly created DIB */
373 if(!(dib->bits = HeapAlloc(GetProcessHeap(), 0, height*abs(dib->stride))))
375 ERR("Failed to allocate bits buffer\n");
376 return FALSE;
378 /* check for bottom-up DIB */
379 if(dib->stride < 0)
380 dib->bits = (BYTE *)dib->bits - (dib->height-1) * dib->stride;
381 dib->ownsBits = TRUE;
383 MAYBE(TRACE("END\n"));
384 return TRUE;
387 /* Clears a DIBDRVBITMAP structure data
388 WARNING : doesn't free anything */
389 void _DIBDRVBITMAP_Clear(DIBDRVBITMAP *bmp)
391 MAYBE(TRACE("bmp=%p\n", bmp));
393 bmp->bits = NULL;
394 bmp->ownsBits = FALSE;
395 bmp->colorTable = NULL;
396 bmp->colorTableSize = 0;
397 bmp->colorTableGrabbed = FALSE;
399 MAYBE(TRACE("END\n"));
402 /* Frees a DIBDRVBITMAP structure data */
403 void _DIBDRVBITMAP_Free(DIBDRVBITMAP *bmp)
405 MAYBE(TRACE("bmp=%p\n", bmp));
407 /* frees bits, if needed */
408 if(bmp->bits && bmp->ownsBits)
410 /* on bottom-up dibs, bits doesn't point to starting
411 of buffer.... bad design choice */
412 if(bmp->stride < 0)
413 bmp->bits = (BYTE *)bmp->bits + bmp->stride * (bmp->height -1);
414 HeapFree(GetProcessHeap(), 0, bmp->bits);
416 bmp->ownsBits = FALSE;
417 bmp->bits = NULL;
419 /* frees color table */
420 if(bmp->colorTable)
421 HeapFree(GetProcessHeap(), 0, bmp->colorTable);
422 bmp->colorTable = NULL;
423 bmp->colorTableSize = 0;
424 bmp->colorTableGrabbed = FALSE;
426 MAYBE(TRACE("END\n"));
430 /* checks whether the format of 2 DIBs are identical
431 it checks the pixel bit count and the color table size
432 and content, if needed */
433 BOOL _DIBDRVBITMAP_FormatMatch(const DIBDRVBITMAP *d1, const DIBDRVBITMAP *d2)
435 /* checks at first the format (bit count and color masks) */
436 if(d1->format != d2->format)
437 return FALSE;
439 /* formats matches, now checks color tables if needed */
440 switch(d1->format)
442 case DIBFMT_DIB32_RGB :
443 case DIBFMT_DIB32_BITFIELDS :
444 case DIBFMT_DIB24 :
445 case DIBFMT_DIB16_RGB :
446 case DIBFMT_DIB16_BITFIELDS :
447 return TRUE;
449 case DIBFMT_DIB1 :
450 case DIBFMT_DIB4 :
451 /*case DIBFMT_DIB4_RLE :*/
452 case DIBFMT_DIB8 :
453 /*case DIBFMT_DIB8_RLE :*/
454 if(d1->colorTableSize != d2->colorTableSize)
455 return FALSE;
456 return !memcmp(d1->colorTable, d2->colorTable, d1->colorTableSize * sizeof(d1->colorTable[0]));
458 default:
459 ERR("Unexpected depth %d\n", d1->bitCount);
460 return FALSE;
464 /* convert a given dib into another format given by 'format' parameter */
465 BOOL _DIBDRVBITMAP_Convert(DIBDRVBITMAP *dst, const DIBDRVBITMAP *src, const DIBDRVBITMAP *format)
467 int width, height;
468 int iLine;
469 void *buf;
470 BOOL res;
472 MAYBE(TRACE("dst=%p, src=%p, format=%p\n", dst, src, format));
474 /* free, if needed, destination bitmap */
475 _DIBDRVBITMAP_Free(dst);
477 /* if format and source bitmaps format match,
478 just copy source on destination */
479 if(_DIBDRVBITMAP_FormatMatch(src, format))
481 res = _DIBDRVBITMAP_InitFromDibdrvbitmap(dst, src, TRUE);
482 MAYBE(TRACE("END - Identical formats\n"));
483 return res;
486 /* formats don't match, we create the dest bitmap with same format as format's one
487 but with source's one dimensions */
488 width = src->width;
489 height = src->height;
490 if(!_DIBDRVBITMAP_CreateFromDibdrvbitmap(dst, format, width, height))
492 ERR("Couldn't create destination bmp\n");
493 return FALSE;
496 /* we now copy/convert from source to dest */
497 if(!(buf = HeapAlloc(GetProcessHeap(), 0, width * 4)))
499 ERR("HeapAlloc failed\n");
500 return FALSE;
503 for(iLine = 0; iLine < height; iLine++)
505 src->funcs->GetLine(src, iLine, 0, width, buf);
506 dst->funcs->PutLine(dst, iLine, 0, width, buf);
508 HeapFree(GetProcessHeap(), 0, buf);
510 MAYBE(TRACE("END - different formats\n"));
511 return TRUE;
514 /* creates a solid-filled DIB of given color and format
515 DIB format is given by 'format' parameter */
516 BOOL _DIBDRVBITMAP_CreateSolid(DIBDRVBITMAP *bmp, DIBDRVBITMAP *format, int width, int height, DWORD Color)
518 DWORD *buf, *bufPnt;
519 int i;
521 MAYBE(TRACE("bmp=%p, format=%p, width=%d, height=%d, Color=%08x\n", bmp, format, width, height, Color));
523 /* swaps color bytes....*/
524 Color = RGB((Color >> 8) & 0xff, (Color >> 16) &0xff, Color &0xff);
526 /* creates the destination bitmap */
527 if(!_DIBDRVBITMAP_CreateFromDibdrvbitmap(bmp, format, width, height))
529 ERR("Couldn't create destination bmp\n");
530 return FALSE;
533 /* creates a temporary line filled with given color */
534 if(!(buf = HeapAlloc(GetProcessHeap(), 0, width * 4)))
536 ERR("HeapAlloc failed\n");
537 return FALSE;
540 for(i = 0, bufPnt = buf; i < width; i++)
541 *bufPnt++ = Color;
543 /* fills the bitmap */
544 for(i = 0; i < height; i++)
545 bmp->funcs->PutLine(bmp, i, 0, width, buf);
547 /* frees temporaty line */
548 HeapFree(GetProcessHeap(), 0, buf);
550 MAYBE(TRACE("END\n"));
551 return TRUE;
554 /* expands horizontally a bitmap to reach a minimum size,
555 keeping its width as a multiple of a base width
556 Used to widen brushes in order to optimize blitting */
557 BOOL _DIBDRVBITMAP_ExpandHoriz(DIBDRVBITMAP *dib, int baseWidth, int minWidth)
559 BYTE *srcBuf, *dstBuf;
560 int chunkSize;
561 int iLine, iCol;
562 DIBDRVBITMAP tmpDib;
563 void *bits;
564 BOOL ownsBits;
566 MAYBE(TRACE("dib=%p, baseWidth=%d, minWidth=%d\n", dib, baseWidth, minWidth));
568 /* if dst dib already wide enough, just do nothing */
569 if(dib->width >= minWidth)
571 MAYBE(TRACE("END - No need to expand\n"));
572 return TRUE;
575 /* source DIB can't be NULL */
576 if(!dib->bits)
578 ERR("Empty source DIB detected\n");
579 return FALSE;
582 /* round up minWidth to be a multiple of source width */
583 minWidth += (baseWidth - (minWidth % baseWidth));
585 /* creates a temporary destination bitmap with required sizes */
586 _DIBDRVBITMAP_Clear(&tmpDib);
587 if(!_DIBDRVBITMAP_CreateFromDibdrvbitmap(&tmpDib, dib, minWidth, dib->height))
589 ERR("Couldn't create the temporary DIB for brush cache\n");
590 return FALSE;
593 /* if format uses almost 1 byte/pixel, fast copy path */
594 if(dib->bitCount >= 8)
596 chunkSize = dib->width * dib->bitCount / 8;
597 for(iLine = 0; iLine < dib->height; iLine++)
599 srcBuf = (BYTE *)dib->bits + iLine * dib->stride;
600 dstBuf = (BYTE *)tmpDib.bits + iLine * tmpDib.stride;
601 for(iCol = 0; iCol < tmpDib.width; iCol += dib->width)
603 memcpy(dstBuf, srcBuf, chunkSize);
604 dstBuf += chunkSize;
608 /* otherwise slow path -- could be optimized */
609 else
611 chunkSize = dib->width * 4;
612 /* allocates a line buffer */
613 if(!(srcBuf = HeapAlloc(GetProcessHeap(), 0, tmpDib.width * 4)))
615 ERR("HeapAlloc failed\n");
616 return FALSE;
619 FIXME("dib:format=%s, funcs=%p, bits=%p, width=%d, height=%d, stride=%d\n",
620 _DIBDRVBITMAP_GetFormatName(dib), dib->funcs, dib->bits, dib->width, dib->height, dib->stride);
621 for(iLine = 0; iLine < dib->height; iLine++)
623 /* fills the line buffer repeating source's line data */
624 dib->funcs->GetLine(dib, iLine, 0, dib->width, srcBuf);
625 dstBuf = srcBuf + chunkSize;
626 for(iCol = dib->width; iCol < tmpDib.width; iCol += dib->width)
628 memcpy(dstBuf, srcBuf, chunkSize);
629 dstBuf += chunkSize;
631 /* stores the line on destination bmp */
632 tmpDib.funcs->PutLine(&tmpDib, iLine, 0, tmpDib.width, srcBuf);
634 HeapFree(GetProcessHeap(), 0, srcBuf);
637 /* swaps temp DIB and source one */
638 bits = dib->bits;
639 ownsBits = dib->ownsBits;
640 dib->bits = tmpDib.bits;
641 dib->ownsBits = tmpDib.ownsBits;
642 tmpDib.bits = bits;
643 tmpDib.ownsBits = ownsBits;
645 /* frees the temporary DIB */
646 _DIBDRVBITMAP_Free(&tmpDib);
648 MAYBE(TRACE("END\n"));
649 return TRUE;