41fb158a2daddac94caef77adce200708c347a84
[wine/hacks.git] / dlls / winedib.drv / dib.c
blob41fb158a2daddac94caef77adce200708c347a84
1 /*
2 * DIBDRV device-independent bitmaps
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 /* Default 1 BPP palette */
29 static DWORD pal1[] =
31 0x000000,
32 0xffffff
35 /* Default 4 BPP palette */
36 static DWORD pal4[] =
38 0x000000,0x800000,0x008000,0x808000,
39 0x000080,0x800080,0x008080,0x808080,
40 0xc0c0c0,0xff0000,0x00ff00,0xffff00,
41 0x0000ff,0xff00ff,0x00ffff,0xffffff
44 /* Default 8 BPP palette */
45 static DWORD pal8[] =
47 0x000000,0x800000,0x008000,0x808000,0x000080,0x800080,0x008080,0xc0c0c0,0xc0dcc0,0xa6caf0,0x000000,0x000033,0x000066,0x000099,0x0000cc,0x0000ff,
48 0x003300,0x003333,0x003366,0x003399,0x0033cc,0x0033ff,0x006600,0x006633,0x006666,0x006699,0x0066cc,0x0066ff,0x009900,0x009933,0x009966,0x009999,
49 0x0099cc,0x0099ff,0x00cc00,0x00cc33,0x00cc66,0x00cc99,0x00cccc,0x00ccff,0x00ff00,0x00ff33,0x00ff66,0x00ff99,0x00ffcc,0x00ffff,0x330000,0x330033,
50 0x330066,0x330099,0x3300cc,0x3300ff,0x333300,0x333333,0x333366,0x333399,0x3333cc,0x3333ff,0x336600,0x336633,0x336666,0x336699,0x3366cc,0x3366ff,
51 0x339900,0x339933,0x339966,0x339999,0x3399cc,0x3399ff,0x33cc00,0x33cc33,0x33cc66,0x33cc99,0x33cccc,0x33ccff,0x33ff00,0x33ff33,0x33ff66,0x33ff99,
52 0x33ffcc,0x33ffff,0x660000,0x660033,0x660066,0x660099,0x6600cc,0x6600ff,0x663300,0x663333,0x663366,0x663399,0x6633cc,0x6633ff,0x666600,0x666633,
53 0x666666,0x666699,0x6666cc,0x6666ff,0x669900,0x669933,0x669966,0x669999,0x6699cc,0x6699ff,0x66cc00,0x66cc33,0x66cc66,0x66cc99,0x66cccc,0x66ccff,
54 0x66ff00,0x66ff33,0x66ff66,0x66ff99,0x66ffcc,0x66ffff,0x990000,0x990033,0x990066,0x990099,0x9900cc,0x9900ff,0x993300,0x993333,0x993366,0x993399,
55 0x9933cc,0x9933ff,0x996600,0x996633,0x996666,0x996699,0x9966cc,0x9966ff,0x999900,0x999933,0x999966,0x999999,0x9999cc,0x9999ff,0x99cc00,0x99cc33,
56 0x99cc66,0x99cc99,0x99cccc,0x99ccff,0x99ff00,0x99ff33,0x99ff66,0x99ff99,0x99ffcc,0x99ffff,0xcc0000,0xcc0033,0xcc0066,0xcc0099,0xcc00cc,0xcc00ff,
57 0xcc3300,0xcc3333,0xcc3366,0xcc3399,0xcc33cc,0xcc33ff,0xcc6600,0xcc6633,0xcc6666,0xcc6699,0xcc66cc,0xcc66ff,0xcc9900,0xcc9933,0xcc9966,0xcc9999,
58 0xcc99cc,0xcc99ff,0xcccc00,0xcccc33,0xcccc66,0xcccc99,0xcccccc,0xccccff,0xccff00,0xccff33,0xccff66,0xccff99,0xccffcc,0xccffff,0xff0000,0xff0033,
59 0xff0066,0xff0099,0xff00cc,0xff00ff,0xff3300,0xff3333,0xff3366,0xff3399,0xff33cc,0xff33ff,0xff6600,0xff6633,0xff6666,0xff6699,0xff66cc,0xff66ff,
60 0xff9900,0xff9933,0xff9966,0xff9999,0xff99cc,0xff99ff,0xffcc00,0xffcc33,0xffcc66,0xffcc99,0xffcccc,0xffccff,0xffff00,0xffff33,0xffff66,0xffff99,
61 0xffffcc,0xffffff,0x050500,0x050501,0x050502,0x050503,0x050504,0x050505,0xe8e8e8,0xe9e9e9,0xeaeaea,0xebebeb,0xececec,0xededed,0xeeeeee,0xefefef,
62 0xf0f0f0,0xf1f1f1,0xf2f2f2,0xf3f3f3,0xf4f4f4,0xf5f5f5,0xfffbf0,0xa0a0a4,0x808080,0xf00000,0x00ff00,0xffff00,0x0000ff,0xff00ff,0x00ffff,0xffffff
65 /***********************************************************************
66 * DIBDRV_CreateDIBSection
68 HBITMAP DIBDRV_CreateDIBSection( DIBDRVPHYSDEV *physDev, HBITMAP hbitmap,
69 const BITMAPINFO *bmi, UINT usage )
71 HBITMAP res;
73 MAYBE(TRACE("physDev:%p, hbitmap:%p, bmi:%p, usage:%d\n", physDev, hbitmap, bmi, usage));
75 /* createDIBSection is only DIB-related, so we just use the engine */
76 ONCE(FIXME("STUB\n"));
77 res = hbitmap;
79 return res;
82 /***********************************************************************
83 * DIBDRV_GetDIBits
85 INT DIBDRV_GetDIBits( DIBDRVPHYSDEV *physDev, HBITMAP hbitmap, UINT startscan,
86 UINT lines, LPVOID bits, BITMAPINFO *info, UINT coloruse )
88 INT res;
89 DIBSECTION ds;
90 DIBDRVBITMAP sBmp, dBmp;
91 DWORD *buf;
92 int iLine;
93 int size;
94 BOOL justInfo, justInfoHeader;
95 int requestedBpp;
96 RGBQUAD *colorTable;
97 int colorTableSize;
98 BITMAPINFO *sourceInfo;
100 MAYBE(TRACE("physDev:%p, hbitmap:%p, startscan:%d, lines:%d, bits:%p, info:%p, coloruse:%d\n",
101 physDev, hbitmap, startscan, lines, bits, info, coloruse));
102 if(GetObjectW(hbitmap, sizeof(DIBSECTION), &ds) == sizeof(DIBSECTION))
104 /* GetDIBits reads bits from a DIB, so we should use the engine driver */
106 /* for the moment, we don't support startscan != 0 */
107 if(startscan != 0)
109 FIXME("startscan != 0 still not supported\n");
110 return 0;
113 /* sanity check */
114 size = info->bmiHeader.biSize;
115 if(size != sizeof(BITMAPINFOHEADER) && size != sizeof(BITMAPCOREHEADER))
117 ERR("Unknown header size %d\n", size);
118 return 0;
121 /* get requested BPP */
122 requestedBpp = info->bmiHeader.biBitCount;
124 /* check wetrher we wants just the BITMAPINFO data */
125 justInfo = (bits == NULL);
127 /* check wether we wants just to get BITMAPINFOHEADER data */
128 justInfoHeader = (requestedBpp == 0);
130 if(!justInfo && justInfoHeader)
132 ERR("Bad requested BPP\n");
133 return 0;
136 /* copy / set missing DIB info */
137 if(justInfo)
139 info->bmiHeader.biWidth = ds.dsBmih.biWidth;
140 info->bmiHeader.biHeight = ds.dsBmih.biHeight;
142 info->bmiHeader.biPlanes = 1;
143 if(justInfoHeader)
144 info->bmiHeader.biBitCount = ds.dsBmih.biBitCount;
145 if(size == sizeof(BITMAPINFOHEADER))
147 if(justInfoHeader)
149 info->bmiHeader.biCompression = ds.dsBmih.biCompression;
150 info->bmiHeader.biXPelsPerMeter = ds.dsBmih.biXPelsPerMeter;
151 info->bmiHeader.biYPelsPerMeter = ds.dsBmih.biYPelsPerMeter;
152 info->bmiHeader.biClrUsed = ds.dsBmih.biClrUsed;
153 info->bmiHeader.biClrImportant = ds.dsBmih.biClrImportant;
155 info->bmiHeader.biSizeImage = ds.dsBmih.biSizeImage;
158 /* width and height *must* match source's ones */
159 if(info->bmiHeader.biWidth != ds.dsBmih.biWidth ||
160 abs(info->bmiHeader.biHeight) != abs(ds.dsBmih.biHeight))
162 ERR("Size of requested bitmap data don't match source's ones\n");
163 return 0;
166 /* if we just wants the BITMAPINFOHEADER data, we're done */
167 if(justInfoHeader || (justInfo && ds.dsBmih.biBitCount > 8))
168 return abs(info->bmiHeader.biHeight);
170 /* we now have to get source data -- we need it for palette, for example */
171 colorTableSize = 0;
172 if(ds.dsBmih.biBitCount <= 8)
173 colorTableSize = (1 << ds.dsBmih.biBitCount);
174 else if(ds.dsBmih.biCompression == BI_BITFIELDS)
175 colorTableSize = 3;
176 sourceInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(BITMAPINFOHEADER) + colorTableSize * sizeof(RGBQUAD));
177 if(!sourceInfo)
179 ERR("HeapAlloc failed\n");
180 return 0;
182 memcpy(sourceInfo, &ds.dsBmih, sizeof(BITMAPINFOHEADER));
183 if(ds.dsBmih.biBitCount <= 8)
185 /* grab palette - well, we should. No way to do it by now....
186 we should add a list HBITMAP <--> DIBDRVBITMAP and fiddle to many
187 , many parts of the engine. Not worth the effort by now.
188 So, we just synthesize the table */
189 switch(requestedBpp)
191 case 1:
192 memcpy((BYTE *)sourceInfo + sizeof(BITMAPINFOHEADER), pal1, 2*sizeof(DWORD));
193 break;
195 case 4:
196 memcpy((BYTE *)sourceInfo + sizeof(BITMAPINFOHEADER), pal4, 16*sizeof(DWORD));
197 break;
199 case 8:
200 memcpy((BYTE *)sourceInfo + sizeof(BITMAPINFOHEADER), pal8, 256*sizeof(DWORD));
201 break;
203 default:
204 ERR("Unknown requested bith depth %d\n", requestedBpp);
205 _DIBDRVBITMAP_Free(&sBmp);
206 return 0;
209 else if(ds.dsBmih.biCompression == BI_BITFIELDS)
210 memcpy((BYTE *)sourceInfo + sizeof(BITMAPINFOHEADER), ds.dsBitfields, 3 * sizeof(RGBQUAD));
211 _DIBDRVBITMAP_Clear(&sBmp);
212 if(!_DIBDRVBITMAP_InitFromBitmapinfo(&sBmp, sourceInfo))
214 ERR("_DIBDRVBITMAP_InitFromBitmapinfo failed\n");
215 HeapFree(GetProcessHeap(), 0, sourceInfo);
216 return 0;
218 _DIBDRVBITMAP_Set_Bits(&sBmp, ds.dsBm.bmBits, FALSE);
219 HeapFree(GetProcessHeap(), 0, sourceInfo);
221 /* now grab / synthesize the color table if needed */
222 if(requestedBpp <= 8)
224 colorTable = (RGBQUAD *)((BYTE *)info + size);
225 if(requestedBpp == ds.dsBmih.biBitCount)
227 /* same source and dest format - copy color tables */
228 memcpy(colorTable, sBmp.colorTable, colorTableSize);
230 else
232 /* different formats -- synthesize color table */
233 switch(requestedBpp)
235 case 1:
236 memcpy(colorTable, pal1, 2*sizeof(DWORD));
237 break;
239 case 4:
240 memcpy(colorTable, pal4, 16*sizeof(DWORD));
241 break;
243 case 8:
244 memcpy(colorTable, pal8, 256*sizeof(DWORD));
245 break;
247 default:
248 ERR("Unknown requested bith depth %d\n", requestedBpp);
249 _DIBDRVBITMAP_Free(&sBmp);
250 return 0;
255 /* if we just wanted DIB info, job is done */
256 if(justInfo)
258 _DIBDRVBITMAP_Free(&sBmp);
259 return abs(info->bmiHeader.biHeight);
262 /* Creates a DIBDRVBITMAP from dest dib */
263 _DIBDRVBITMAP_Clear(&dBmp);
264 if(!_DIBDRVBITMAP_InitFromBitmapinfo(&dBmp, info))
266 ERR("_DIBDRVBITMAP_InitFromBitmapinfo failed\n");
267 _DIBDRVBITMAP_Free(&sBmp);
268 return 0;
270 _DIBDRVBITMAP_Set_Bits(&dBmp, bits, FALSE);
272 /* now we can do the bit conversion */
273 buf = HeapAlloc(GetProcessHeap(), 0, ds.dsBmih.biWidth * sizeof(RGBQUAD));
274 for(iLine = 0; iLine < lines; iLine++)
276 sBmp.funcs->GetLine(&sBmp, iLine, 0, ds.dsBmih.biWidth, buf);
277 dBmp.funcs->PutLine(&dBmp, iLine, 0, ds.dsBmih.biWidth, buf);
279 _DIBDRVBITMAP_Free(&sBmp);
280 _DIBDRVBITMAP_Free(&dBmp);
281 return lines;
283 else
284 /* GetDIBits reads bits from a DDB, use X11 driver */
285 res = _DIBDRV_GetDisplayDriver()->pGetDIBits(physDev->X11PhysDev, hbitmap, startscan, lines, bits, info, coloruse);
287 return res;
290 /***********************************************************************
291 * DIBDRV_SetDIBColorTable
293 UINT DIBDRV_SetDIBColorTable( DIBDRVPHYSDEV *physDev, UINT start, UINT count,
294 const RGBQUAD *colors )
296 DIBDRVBITMAP *dib = &physDev->physBitmap;
297 #if 0
298 HBITMAP thisDIB;
299 #endif
301 MAYBE(TRACE("physDev:%p, start:%d, count:%d, colors:%p\n", physDev, start, count, colors));
303 /* SetDIBColorTable operates on a DIB, so we use the engine */
305 /* if bpp > 8, some error occurred... */
306 if(dib->bitCount > 8)
308 ERR("Called for BPP > 8\n");
309 return 0;
312 /* if dib hasn't a color table, or has a small one, we must before
313 create/extend it */
314 if(!dib->colorTable)
316 dib->colorTableSize = (1 << dib->bitCount);
317 dib->colorTable = HeapAlloc(GetProcessHeap(), 0, sizeof(RGBQUAD) * dib->colorTableSize);
319 else if(dib->colorTableSize < (1 << dib->bitCount))
321 int newSize = (1 << dib->bitCount);
322 RGBQUAD *newTable = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RGBQUAD) * newSize);
323 memcpy(newTable, dib->colorTable, sizeof(RGBQUAD) * dib->colorTableSize);
324 HeapFree(GetProcessHeap(), 0, dib->colorTable);
325 dib->colorTable = newTable;
326 dib->colorTableSize = newSize;
329 /* sanity check */
330 if(start + count > dib->colorTableSize)
332 ERR("Out of range setting color table, size is %d, requested is %d\n", dib->colorTableSize, start+count);
333 return 0;
335 memcpy(dib->colorTable + start, colors, sizeof(RGBQUAD) * count);
336 dib->colorTableGrabbed = TRUE;
338 /* hack to make GDI32 sense the DIB color table change
339 (fixes a couple of todos in bitmap test suite */
340 #if 0
341 thisDIB = SelectObject(physDev->hdc, GetStockObject(OBJ_BITMAP));
342 SelectObject(physDev->hdc, thisDIB);
343 #endif
345 return TRUE;
348 /***********************************************************************
349 * DIBDRV_SetDIBits
351 INT DIBDRV_SetDIBits( DIBDRVPHYSDEV *physDev, HBITMAP hbitmap, UINT startscan,
352 UINT lines, LPCVOID bits, const BITMAPINFO *info, UINT coloruse )
354 INT res;
355 DIBSECTION ds;
356 DIBDRVBITMAP sBmp, dBmp;
357 DWORD *buf;
358 int iLine;
360 MAYBE(TRACE("physDev:%p, hbitmap:%p, startscan:%d, lines:%d, bits:%p, bmi:%p, coloruse:%d\n",
361 physDev, hbitmap, startscan, lines, bits, info, coloruse));
364 if(GetObjectW(hbitmap, sizeof(DIBSECTION), &ds) == sizeof(DIBSECTION))
366 /* SetDIBits writes bits to a DIB, so we should use the engine driver */
368 /* for the moment, we don't support startscan != 0 */
369 if(startscan != 0)
371 FIXME("startscan != 0 still not supported\n");
372 return 0;
375 /* Creates a DIBDRVBITMAP from source dib */
376 _DIBDRVBITMAP_Clear(&sBmp);
377 if(!_DIBDRVBITMAP_InitFromBitmapinfo(&sBmp, info))
379 ERR("_DIBDRVBITMAP_InitFromBitmapinfo failed\n");
380 return 0;
382 _DIBDRVBITMAP_Set_Bits(&sBmp, (LPVOID)bits, FALSE);
384 /* same for destination dib */
385 if(!_DIBDRVBITMAP_InitFromHBITMAP(&dBmp, hbitmap, FALSE))
387 ERR("_DIBDRVBITMAP_InitFromHBITMAP failed\n");
388 _DIBDRVBITMAP_Free(&sBmp);
389 return 0;
392 /* now we can do the bit conversion */
393 buf = HeapAlloc(GetProcessHeap(), 0, ds.dsBmih.biWidth * sizeof(RGBQUAD));
394 for(iLine = 0; iLine < lines; iLine++)
396 sBmp.funcs->GetLine(&sBmp, iLine, 0, ds.dsBmih.biWidth, buf);
397 dBmp.funcs->PutLine(&dBmp, iLine, 0, ds.dsBmih.biWidth, buf);
399 _DIBDRVBITMAP_Free(&sBmp);
400 _DIBDRVBITMAP_Free(&dBmp);
401 return lines;
403 else
405 /* SetDIBits writes bits to a DDB, so we should use the X11 driver */
406 res = _DIBDRV_GetDisplayDriver()->pSetDIBits(physDev->X11PhysDev, hbitmap, startscan, lines, bits, info, coloruse);
408 return res;
411 /*************************************************************************
412 * DIBDRV_SetDIBitsToDevice
414 INT DIBDRV_SetDIBitsToDevice( DIBDRVPHYSDEV *physDev, INT xDest, INT yDest, DWORD cx,
415 DWORD cy, INT xSrc, INT ySrc,
416 UINT startscan, UINT lines, LPCVOID bits,
417 const BITMAPINFO *info, UINT coloruse )
419 BITMAPINFO *bitmapInfo;
420 int bmInfoSize;
421 int dibHeight, dibWidth;
422 DIBDRVBITMAP sBmp;
423 int sLine, dLine, iLine;
424 void *buf;
426 MAYBE(TRACE("physDev:%p, xDest:%d, yDest:%d, cx:%x, cy:%x, xSrc:%d, ySrc:%d, startscan:%d, lines:%d, bits:%p, info:%p, coloruse:%d\n",
427 physDev, xDest, yDest, cx, cy, xSrc, ySrc, startscan, lines, bits, info, coloruse));
429 if(physDev->hasDIB)
431 /* DIB section selected in, use DIB Engine */
433 /* inverts y on source -- FIXME: check if right with some tests, it seems so */
434 ySrc = abs(info->bmiHeader.biHeight) - ySrc - cy;
436 dibHeight = info->bmiHeader.biHeight;
437 dibWidth = info->bmiHeader.biWidth;
439 /* sanity check and source clipping on physical sizes */
440 if(startscan >= abs(dibHeight))
441 return 0;
442 if(startscan + lines > abs(dibHeight))
443 lines = abs(dibHeight) - startscan;
445 /* adjust height because of startscan */
446 dibHeight += (dibHeight > 0 ? -startscan : startscan);
448 if(xSrc >= dibWidth)
449 return 0;
450 if(xSrc + cx > dibWidth)
451 cx = dibWidth - xSrc;
452 if(ySrc > abs(dibHeight))
453 return 0;
454 if(ySrc + cy > abs(dibHeight))
455 cy = abs(dibHeight) - ySrc;
457 ySrc -= startscan;
458 cy -= startscan;
459 if(cy <= 0)
460 return 0;
461 if(ySrc < 0)
463 yDest += ySrc;
464 cy += ySrc;
465 ySrc = 0;
467 if(cy <= 0)
468 return 0;
470 /* grab a copy of BITMAPINFO */
471 bmInfoSize = sizeof(BITMAPINFOHEADER);
472 if(info->bmiHeader.biCompression == BI_BITFIELDS)
473 bmInfoSize += 3 * sizeof(RGBQUAD);
474 else if (info->bmiHeader.biBitCount <= 8)
476 if(info->bmiHeader.biClrUsed)
477 bmInfoSize += info->bmiHeader.biClrUsed * sizeof(RGBQUAD);
478 else
479 bmInfoSize += (1 << info->bmiHeader.biBitCount) * sizeof(RGBQUAD);
481 if(!(bitmapInfo = HeapAlloc(GetProcessHeap(), 0, bmInfoSize)))
483 ERR("HeapAlloc failed\n");
484 return 0;
486 memcpy(bitmapInfo, info, bmInfoSize);
487 bitmapInfo->bmiHeader.biHeight = dibHeight;
489 /* create a DIBDRVBITMAP from BITMAPINFO data */
490 _DIBDRVBITMAP_Clear(&sBmp);
491 if(!_DIBDRVBITMAP_InitFromBitmapinfo(&sBmp, bitmapInfo))
493 ERR("_DIBDRVBITMAP_InitFromBitmapinfo failed\n");
494 HeapFree(GetProcessHeap, 0, bitmapInfo);
495 return 0;
497 HeapFree(GetProcessHeap(), 0, bitmapInfo);
498 _DIBDRVBITMAP_Set_Bits(&sBmp, (LPVOID)bits, FALSE);
500 /* transfer lines to dest bitmap */
501 if(!(buf = HeapAlloc(GetProcessHeap(), 0, cx * sizeof(RGBQUAD))))
503 ERR("HeapAlloc failed\n");
504 return 0;
506 for(sLine = ySrc, dLine = yDest, iLine = 0; iLine < cy; sLine++, dLine++, iLine++)
508 sBmp.funcs->GetLine(&sBmp, sLine, xSrc, cx, buf);
509 physDev->physBitmap.funcs->PutLine(&physDev->physBitmap, dLine, xDest, cx, buf);
511 HeapFree(GetProcessHeap(), 0, buf);
513 return cy;
515 else
517 return _DIBDRV_GetDisplayDriver()->pSetDIBitsToDevice(physDev->X11PhysDev, xDest, yDest, cx, cy, xSrc, ySrc,
518 startscan, lines, bits, info, coloruse);