DIB Engine: fix vertically mirrored images caused by GetObject() changes
[wine/hacks.git] / dlls / winedib.drv / dibdrvbitmap.c
blob1b2c959ed2f32a2e57ca0f8e1c3fa5f40d96bc9d
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 /* sets/gets bits of a DIBDRVBITMAP taking in account if it's a top down
111 or a bottom-up DIB */
112 void _DIBDRVBITMAP_Set_Bits(DIBDRVBITMAP *dib, void *bits, BOOL owns)
114 /* checks whether dib is top-down or bottom-up one */
115 if(dib->stride > 0)
117 /* top-down dib */
118 dib->bits = bits;
120 else
122 /* bottom-up dib */
123 /* data->bits always points to the top-left corner and the stride is -ve */
124 dib->bits = (BYTE*)bits - (dib->height - 1) * dib->stride;
126 dib->ownsBits = owns;
129 void *_DIBDRVBITMAP_Get_Bits(DIBDRVBITMAP * dib)
131 /* checks whether dib is top-down or bottom-up one */
132 if(dib->stride > 0)
134 /* top-down dib */
135 return dib->bits;
137 else
139 /* bottom-up dib */
140 /* data->bits always points to the top-left corner and the stride is -ve */
141 return (BYTE*)dib->bits + (dib->height - 1) * dib->stride;
145 /* calculates and sets the lightest color for monochrome bitmaps */
146 int _DIBDRVBITMAP_GetLightestColorIndex(DIBDRVBITMAP *dib)
148 DWORD foreRed, foreGreen, foreBlue;
149 DWORD backRed, backGreen, backBlue;
150 RGBQUAD *fore, *back;
152 /* zero for non-monochrome bitmaps */
153 if(dib->bitCount != 1)
154 return 0;
155 /* just in case color table hasn't been grabbed yet */
156 if(!dib->colorTableGrabbed)
157 return 1;
158 back = dib->colorTable;
159 fore = back + 1;
160 foreRed = fore->rgbRed; foreGreen = fore->rgbGreen; foreBlue = fore->rgbBlue;
161 backRed = back->rgbRed; backGreen = back->rgbGreen; backBlue = back->rgbBlue;
162 if(foreRed*foreRed + foreGreen*foreGreen + foreBlue*foreBlue >
163 backRed*backRed + backGreen*backGreen + backBlue*backBlue)
165 dib->lightColor = 1;
166 return 1;
168 dib->lightColor = 0;
169 return 0;
172 /* initializes dib from a bitmap :
173 dib dib being initialized
174 bi source BITMAPINFOHEADER with required DIB format info
175 bit_fields color masks
176 colorTable color table, if any
177 bits pointer to image data array
178 NOTE : DIBDRVBITMAP doesn't owns bits, but do own color table
180 BOOL _DIBDRVBITMAP_InitFromBMIH(DIBDRVBITMAP *dib, const BITMAPINFOHEADER *bi, const DWORD *bit_fields,
181 const RGBQUAD *colorTable, void *bits)
183 MAYBE(TRACE("dib=%p, bi=%p, bit_fields=%p, colorTable=%p, bits=%p\n", dib, bi, bit_fields, colorTable, bits));
185 /* initializes DIB dimensions and color depth */
186 dib->bitCount = bi->biBitCount;
187 dib->width = bi->biWidth;
188 dib->height = bi->biHeight;
189 dib->stride = ((dib->width * dib->bitCount + 31) >> 3) & ~3;
191 /* initializes image data pointer */
192 dib->bits = bits;
193 dib->ownsBits = FALSE;
195 /* initializes color table */
196 dib->colorTableSize = 0;
197 dib->colorTable = NULL;
198 dib->colorTableGrabbed = FALSE;
200 /* checks whether dib is top-down or bottom-up one */
201 if(dib->height < 0)
203 /* top-down dib */
204 dib->height = -dib->height;
205 dib->topdown = TRUE;
207 else
209 /* bottom-up dib */
210 /* data->bits always points to the top-left corner and the stride is -ve */
211 dib->bits = (BYTE*)dib->bits + (dib->height - 1) * dib->stride;
212 dib->stride = -dib->stride;
213 dib->topdown = FALSE;
216 /* gets and stores bitmap format */
217 switch(dib->bitCount)
219 case 24:
220 dib->format = DIBFMT_DIB24;
221 dib->funcs = &DIBDRV_funcs_DIB24;
222 break;
224 case 32:
226 if(bi->biCompression == BI_RGB)
228 dib->format = DIBFMT_DIB32_RGB;
229 dib->funcs = &DIBDRV_funcs_DIB32_RGB;
231 else
233 InitBitFields(dib, bit_fields);
234 dib->format = DIBFMT_DIB32_BITFIELDS;
235 dib->funcs = &DIBDRV_funcs_DIB32_BITFIELDS;
237 break;
239 case 16:
240 if(bi->biCompression == BI_RGB)
242 dib->format = DIBFMT_DIB16_RGB;
243 dib->funcs = &DIBDRV_funcs_DIB16_RGB;
245 else
247 InitBitFields(dib, bit_fields);
248 dib->format = DIBFMT_DIB16_BITFIELDS;
249 dib->funcs = &DIBDRV_funcs_DIB16_BITFIELDS;
251 break;
253 case 8:
254 dib->format = DIBFMT_DIB8;
255 dib->funcs = &DIBDRV_funcs_DIB8;
256 dib->colorTableSize = 256;
257 if(bi->biClrUsed) dib->colorTableSize = bi->biClrUsed;
258 break;
260 case 4:
261 dib->format = DIBFMT_DIB4;
262 dib->funcs = &DIBDRV_funcs_DIB4;
263 dib->colorTableSize = 16;
264 if(bi->biClrUsed) dib->colorTableSize = bi->biClrUsed;
265 break;
267 case 1:
268 dib->format = DIBFMT_DIB1;
269 dib->funcs = &DIBDRV_funcs_DIB1;
270 dib->colorTableSize = 2;
271 if(bi->biClrUsed) dib->colorTableSize = bi->biClrUsed;
272 break;
274 default:
275 dib->format = DIBFMT_UNKNOWN;
276 dib->funcs = NULL;
277 FIXME("bpp %d not supported\n", dib->bitCount);
278 return FALSE;
280 MAYBE(TRACE("DIB FORMAT : %s\n", _DIBDRVBITMAP_GetFormatName(dib)));
282 /* allocates color table and copy it from source, *if* source is
283 not null */
284 if(dib->colorTableSize && colorTable)
286 if(!(dib->colorTable = HeapAlloc(GetProcessHeap(), 0,
287 dib->colorTableSize * sizeof(dib->colorTable[0]))
290 ERR("HeapAlloc failed\n");
291 return FALSE;
293 memcpy(dib->colorTable, colorTable,
294 dib->colorTableSize * sizeof(dib->colorTable[0]));
295 dib->colorTableGrabbed = TRUE;
297 /* for monochrome bitmaps, we need the 'lightest' color */
298 _DIBDRVBITMAP_GetLightestColorIndex(dib);
300 else if(!dib->colorTableSize)
301 /* no color table on more than 8 bits/pixel */
302 dib->colorTableGrabbed = TRUE;
304 MAYBE(TRACE("END\n"));
305 return TRUE;
308 DIBDRVBITMAP *_DIBDRVBITMAP_CreateFromBMIH(const BITMAPINFOHEADER *bi, const DWORD *bit_fields,
309 const RGBQUAD *colorTable, void *bits)
311 DIBDRVBITMAP *bmp = _DIBDRVBITMAP_New();
312 if(bmp && !_DIBDRVBITMAP_InitFromBMIH(bmp, bi, bit_fields, colorTable, bits))
314 _DIBDRVBITMAP_Free(bmp);
315 bmp = NULL;
317 return bmp;
320 /* gets a BITMAPINFOHEADER from a soure BITMAPINFO- or BITMAPCORE-header */
321 static BITMAPINFOHEADER *GetBitmapInfoHeader(BITMAPINFO const *bmi)
323 BITMAPINFOHEADER *res = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
325 int size = bmi->bmiHeader.biSize;
326 if(size >= sizeof(BITMAPINFOHEADER))
328 memcpy(res, bmi, sizeof(BITMAPINFOHEADER));
329 res->biSize = sizeof(BITMAPINFOHEADER);
331 else if(size == sizeof(BITMAPCOREHEADER))
333 BITMAPCOREHEADER *core = (BITMAPCOREHEADER *)bmi;
334 res->biSize = sizeof(BITMAPINFOHEADER);
335 res->biWidth = core->bcWidth;
336 res->biHeight = core->bcHeight;
337 res->biPlanes = core->bcPlanes;
338 res->biBitCount = core->bcBitCount;
340 else
342 HeapFree(GetProcessHeap(), 0, res);
343 ERR("Bad/unknown header size %d\n", size);
344 res = NULL;
346 return res;
349 BOOL _DIBDRVBITMAP_InitFromBitmapinfo(DIBDRVBITMAP *dib, const BITMAPINFO *bmi, void *bits)
351 static const DWORD bit_fields_DIB32_RGB[3] = {0xff0000, 0x00ff00, 0x0000ff};
352 static const DWORD bit_fields_DIB16_RGB[3] = {0x7c00, 0x03e0, 0x001f};
353 const DWORD *masks = NULL;
354 RGBQUAD *colorTable = NULL;
355 BITMAPINFOHEADER *bi;
356 BYTE *ptr;
357 int num_colors;
358 BOOL res;
360 /* gets info header */
361 if(!(bi = GetBitmapInfoHeader(bmi)))
362 return FALSE;
364 ptr = (BYTE*)bmi + bmi->bmiHeader.biSize;
365 num_colors = bi->biClrUsed;
367 MAYBE(TRACE("dib=%p, bmi=%p\n", dib, bmi));
369 if(bi->biCompression == BI_BITFIELDS)
371 masks = (DWORD *)ptr;
372 ptr += 3 * sizeof(DWORD);
374 else if(bi->biBitCount == 32)
375 masks = bit_fields_DIB32_RGB;
376 else if(bi->biBitCount == 16)
377 masks = bit_fields_DIB16_RGB;
379 if(!num_colors && bi->biBitCount <= 8)
380 num_colors = 1 << bi->biBitCount;
381 if(num_colors)
382 colorTable = (RGBQUAD*)ptr;
383 ptr += num_colors * sizeof(*colorTable);
385 res = _DIBDRVBITMAP_InitFromBMIH(dib, bi, masks, colorTable, bits ? bits : ptr);
386 HeapFree(GetProcessHeap(), 0, bi);
387 MAYBE(TRACE("END\n"));
388 return res;
391 DIBDRVBITMAP *_DIBDRVBITMAP_CreateFromBitmapinfo(const BITMAPINFO *bmi, void *bits)
393 DIBDRVBITMAP *bmp = _DIBDRVBITMAP_New();
394 if(bmp && !_DIBDRVBITMAP_InitFromBitmapinfo(bmp, bmi, bits))
396 _DIBDRVBITMAP_Free(bmp);
397 bmp = NULL;
399 return bmp;
402 /* initializes a DIBRDVBITMAP copying it from a source one
403 Parameters :
404 dib destination DIBDRVBITMAP
405 src source DIBDRVBITMAP
406 copy TRUE->copy source pixel array FALSE->link to source pixel array
408 BOOL _DIBDRVBITMAP_InitFromDibdrvbitmap(DIBDRVBITMAP *dib, const DIBDRVBITMAP *src, BOOL copy)
410 MAYBE(TRACE("dib=%p, src=%p, copy=%d\n", dib, src, copy));
412 dib->format = src->format;
413 dib->width = src->width;
414 dib->height = src->height;
415 dib->stride = src->stride;
416 dib->bitCount = src->bitCount;
418 dib->redMask = src->redMask;
419 dib->greenMask = src->greenMask;
420 dib->blueMask = src->blueMask;
421 dib->redShift = src->redShift;
422 dib->greenShift = src->greenShift;
423 dib->blueShift = src->blueShift;
424 dib->redLen = src->redLen;
425 dib->greenLen = src->greenLen;
426 dib->blueLen = src->blueLen;
428 dib->funcs = src->funcs;
430 dib->lightColor = src->lightColor;
432 dib->topdown = src->topdown;
434 if(copy)
436 int size = dib->height*abs(dib->stride);
437 if(!(dib->bits = HeapAlloc(GetProcessHeap(), 0, size)))
439 ERR("Failed to allocate bits buffer\n");
440 return FALSE;
442 dib->ownsBits = TRUE;
444 /* check for bottom-up DIB */
445 if(dib->stride < 0)
447 /* copy the bitmap array */
448 memcpy(dib->bits, (BYTE *)src->bits + (src->height - 1) * src->stride, size);
450 dib->bits = (BYTE *)dib->bits - (dib->height-1) * dib->stride;
452 else
454 /* copy the bitmap array */
455 memcpy(dib->bits, src->bits, size);
458 else
460 dib->bits = src->bits;
461 dib->ownsBits = FALSE;
464 if(src->colorTable)
466 dib->colorTable = HeapAlloc(GetProcessHeap(), 0, src->colorTableSize * sizeof(src->colorTable[0]));
467 memcpy(dib->colorTable, src->colorTable, src->colorTableSize * sizeof(src->colorTable[0]));
469 else
470 dib->colorTable = NULL;
471 dib->colorTableSize = src->colorTableSize;
472 dib->colorTableGrabbed = TRUE;
473 MAYBE(TRACE("END\n"));
474 return TRUE;
478 /* creates a DIBRDVBITMAP copying format info from a source one
479 Parameters :
480 dib destination DIBDRVBITMAP
481 src source DIBDRVBITMAP
482 widht, height sizes of newly created bitmap
484 BOOL _DIBDRVBITMAP_CreateFromDibdrvbitmap(DIBDRVBITMAP *dib, const DIBDRVBITMAP *src, int width, int height)
486 MAYBE(TRACE("dib=%p, src=%p, width=%d, height=%d\n", dib, src, width, height));
488 /* grab color and format info from source DIB */
489 if(!_DIBDRVBITMAP_InitFromDibdrvbitmap(dib, src, FALSE))
491 ERR("Failed grabbing source dib format\n");
492 return FALSE;
495 /* sets up new DIB dimensions */
496 dib->width = width;
497 dib->height = height;
499 /* calculates new stride basing of new width */
500 dib->stride = ((width * dib->bitCount +31) &~31) / 8;
501 if(src->stride < 0)
502 dib->stride = -dib->stride;
503 dib->topdown = src->topdown;
505 /* allocates bits for newly created DIB */
506 if(!(dib->bits = HeapAlloc(GetProcessHeap(), 0, height*abs(dib->stride))))
508 ERR("Failed to allocate bits buffer\n");
509 return FALSE;
511 /* check for bottom-up DIB */
512 if(dib->stride < 0)
513 dib->bits = (BYTE *)dib->bits - (dib->height-1) * dib->stride;
514 dib->ownsBits = TRUE;
516 MAYBE(TRACE("END\n"));
517 return TRUE;
520 /* Clears a DIBDRVBITMAP structure data
521 WARNING : doesn't free anything */
522 void _DIBDRVBITMAP_Clear(DIBDRVBITMAP *bmp)
524 MAYBE(TRACE("bmp=%p\n", bmp));
526 if(!bmp)
527 return;
528 bmp->bits = NULL;
529 bmp->ownsBits = FALSE;
530 bmp->colorTable = NULL;
531 bmp->colorTableSize = 0;
532 bmp->colorTableGrabbed = FALSE;
534 MAYBE(TRACE("END\n"));
537 /* allocates a new DIBDTVBITMAP */
538 DIBDRVBITMAP *_DIBDRVBITMAP_New(void)
540 DIBDRVBITMAP *bmp = HeapAlloc(GetProcessHeap(), 0, sizeof(DIBDRVBITMAP));
541 if(!bmp)
542 return NULL;
543 _DIBDRVBITMAP_Clear(bmp);
544 return bmp;
547 /* Frees a DIBDRVBITMAP structure data */
548 void _DIBDRVBITMAP_Free(DIBDRVBITMAP *bmp)
550 MAYBE(TRACE("bmp=%p\n", bmp));
552 if(!bmp)
553 return;
554 /* frees bits, if needed */
555 if(bmp->bits && bmp->ownsBits)
557 /* on bottom-up dibs, bits doesn't point to starting
558 of buffer.... bad design choice */
559 if(bmp->stride < 0)
560 bmp->bits = (BYTE *)bmp->bits + bmp->stride * (bmp->height -1);
561 HeapFree(GetProcessHeap(), 0, bmp->bits);
563 /* frees color table */
564 if(bmp->colorTable)
565 HeapFree(GetProcessHeap(), 0, bmp->colorTable);
567 HeapFree(GetProcessHeap(), 0, bmp);
572 /* checks whether the format of 2 DIBs are identical
573 it checks the pixel bit count and the color table size
574 and content, if needed */
575 BOOL _DIBDRVBITMAP_FormatMatch(const DIBDRVBITMAP *d1, const DIBDRVBITMAP *d2)
577 /* checks at first the format (bit count and color masks) */
578 if(d1->format != d2->format)
579 return FALSE;
581 /* formats matches, now checks color tables if needed */
582 switch(d1->format)
584 case DIBFMT_DIB32_RGB :
585 case DIBFMT_DIB32_BITFIELDS :
586 case DIBFMT_DIB24 :
587 case DIBFMT_DIB16_RGB :
588 case DIBFMT_DIB16_BITFIELDS :
589 return TRUE;
591 case DIBFMT_DIB1 :
592 case DIBFMT_DIB4 :
593 /*case DIBFMT_DIB4_RLE :*/
594 case DIBFMT_DIB8 :
595 /*case DIBFMT_DIB8_RLE :*/
596 if(d1->colorTableSize != d2->colorTableSize)
597 return FALSE;
598 return !memcmp(d1->colorTable, d2->colorTable, d1->colorTableSize * sizeof(d1->colorTable[0]));
600 default:
601 ERR("Unexpected depth %d\n", d1->bitCount);
602 return FALSE;
606 /* convert a given dib into another format given by 'format' parameter */
607 BOOL _DIBDRVBITMAP_Convert(DIBDRVBITMAP *dst, const DIBDRVBITMAP *src, const DIBDRVBITMAP *format)
609 int width, height;
610 int iLine;
611 void *buf;
612 BOOL res;
614 MAYBE(TRACE("dst=%p, src=%p, format=%p\n", dst, src, format));
616 /* free, if needed, destination bitmap */
617 _DIBDRVBITMAP_Free(dst);
619 /* if format and source bitmaps format match,
620 just copy source on destination */
621 if(_DIBDRVBITMAP_FormatMatch(src, format))
623 res = _DIBDRVBITMAP_InitFromDibdrvbitmap(dst, src, TRUE);
624 MAYBE(TRACE("END - Identical formats\n"));
625 return res;
628 /* formats don't match, we create the dest bitmap with same format as format's one
629 but with source's one dimensions */
630 width = src->width;
631 height = src->height;
632 if(!_DIBDRVBITMAP_CreateFromDibdrvbitmap(dst, format, width, height))
634 ERR("Couldn't create destination bmp\n");
635 return FALSE;
638 /* we now copy/convert from source to dest */
639 if(!(buf = HeapAlloc(GetProcessHeap(), 0, width * 4)))
641 ERR("HeapAlloc failed\n");
642 return FALSE;
645 for(iLine = 0; iLine < height; iLine++)
647 src->funcs->GetLine(src, iLine, 0, width, buf);
648 dst->funcs->PutLine(dst, iLine, 0, width, buf);
650 HeapFree(GetProcessHeap(), 0, buf);
652 MAYBE(TRACE("END - different formats\n"));
653 return TRUE;
656 /* creates a solid-filled DIB of given color and format
657 DIB format is given by 'format' parameter */
658 BOOL _DIBDRVBITMAP_CreateSolid(DIBDRVBITMAP *bmp, DIBDRVBITMAP *format, int width, int height, DWORD Color)
660 DWORD *buf, *bufPnt;
661 int i;
663 MAYBE(TRACE("bmp=%p, format=%p, width=%d, height=%d, Color=%08x\n", bmp, format, width, height, Color));
665 /* swaps color bytes....*/
666 Color = RGB((Color >> 8) & 0xff, (Color >> 16) &0xff, Color &0xff);
668 /* creates the destination bitmap */
669 if(!_DIBDRVBITMAP_CreateFromDibdrvbitmap(bmp, format, width, height))
671 ERR("Couldn't create destination bmp\n");
672 return FALSE;
675 /* creates a temporary line filled with given color */
676 if(!(buf = HeapAlloc(GetProcessHeap(), 0, width * 4)))
678 ERR("HeapAlloc failed\n");
679 return FALSE;
682 for(i = 0, bufPnt = buf; i < width; i++)
683 *bufPnt++ = Color;
685 /* fills the bitmap */
686 for(i = 0; i < height; i++)
687 bmp->funcs->PutLine(bmp, i, 0, width, buf);
689 /* frees temporaty line */
690 HeapFree(GetProcessHeap(), 0, buf);
692 MAYBE(TRACE("END\n"));
693 return TRUE;
696 /* expands horizontally a bitmap to reach a minimum size,
697 keeping its width as a multiple of a base width
698 Used to widen brushes in order to optimize blitting */
699 BOOL _DIBDRVBITMAP_ExpandHoriz(DIBDRVBITMAP *dib, int baseWidth, int minWidth)
701 BYTE *srcBuf, *dstBuf;
702 int chunkSize;
703 int iLine, iCol;
704 DIBDRVBITMAP tmpDib;
705 void *bits;
706 BOOL ownsBits;
708 MAYBE(TRACE("dib=%p, baseWidth=%d, minWidth=%d\n", dib, baseWidth, minWidth));
710 /* if dst dib already wide enough, just do nothing */
711 if(dib->width >= minWidth)
713 MAYBE(TRACE("END - No need to expand\n"));
714 return TRUE;
717 /* source DIB can't be NULL */
718 if(!dib->bits)
720 ERR("Empty source DIB detected\n");
721 return FALSE;
724 /* round up minWidth to be a multiple of source width */
725 minWidth += (baseWidth - (minWidth % baseWidth));
727 /* creates a temporary destination bitmap with required sizes */
728 _DIBDRVBITMAP_Clear(&tmpDib);
729 if(!_DIBDRVBITMAP_CreateFromDibdrvbitmap(&tmpDib, dib, minWidth, dib->height))
731 ERR("Couldn't create the temporary DIB for brush cache\n");
732 return FALSE;
735 /* if format uses almost 1 byte/pixel, fast copy path */
736 if(dib->bitCount >= 8)
738 chunkSize = dib->width * dib->bitCount / 8;
739 for(iLine = 0; iLine < dib->height; iLine++)
741 srcBuf = (BYTE *)dib->bits + iLine * dib->stride;
742 dstBuf = (BYTE *)tmpDib.bits + iLine * tmpDib.stride;
743 for(iCol = 0; iCol < tmpDib.width; iCol += dib->width)
745 memcpy(dstBuf, srcBuf, chunkSize);
746 dstBuf += chunkSize;
750 /* otherwise slow path -- could be optimized */
751 else
753 chunkSize = dib->width * 4;
754 /* allocates a line buffer */
755 if(!(srcBuf = HeapAlloc(GetProcessHeap(), 0, tmpDib.width * 4)))
757 ERR("HeapAlloc failed\n");
758 return FALSE;
761 FIXME("dib:format=%s, funcs=%p, bits=%p, width=%d, height=%d, stride=%d\n",
762 _DIBDRVBITMAP_GetFormatName(dib), dib->funcs, dib->bits, dib->width, dib->height, dib->stride);
763 for(iLine = 0; iLine < dib->height; iLine++)
765 /* fills the line buffer repeating source's line data */
766 dib->funcs->GetLine(dib, iLine, 0, dib->width, srcBuf);
767 dstBuf = srcBuf + chunkSize;
768 for(iCol = dib->width; iCol < tmpDib.width; iCol += dib->width)
770 memcpy(dstBuf, srcBuf, chunkSize);
771 dstBuf += chunkSize;
773 /* stores the line on destination bmp */
774 tmpDib.funcs->PutLine(&tmpDib, iLine, 0, tmpDib.width, srcBuf);
776 HeapFree(GetProcessHeap(), 0, srcBuf);
779 /* swaps temp DIB and source one */
780 bits = dib->bits;
781 ownsBits = dib->ownsBits;
782 dib->bits = tmpDib.bits;
783 dib->ownsBits = tmpDib.ownsBits;
784 tmpDib.bits = bits;
785 tmpDib.ownsBits = ownsBits;
787 /* frees the temporary DIB */
788 _DIBDRVBITMAP_Free(&tmpDib);
790 MAYBE(TRACE("END\n"));
791 return TRUE;