DIB Engine: fix MapModes for xxxBlt
[wine/hacks.git] / dlls / winedib.drv / convert.c
blob8ee6ecd2c02d9820b0ab873da9a26187fbf73741
1 /*
2 * DIB Engine conversion routines
3 * Converts DDB <--> DIB
5 * Copyright 2009 Massimo Del Fedele
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "config.h"
23 #include "wine/port.h"
25 #include "dibdrv.h"
27 #include "winuser.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(dibdrv);
31 /***********************************************************************
32 * Creates DDB that is compatible with source hdc.
33 * hdc is the HDC on where the DIB MUST be selected in
34 * srcBmp is the source DIB
35 * startScan and scanLines specify the portion of DIB to convert
36 * in order to avoid unneeded conversion of large DIBs on blitting
38 * NOTE : the srcBmp DIB MUST NOT be selected in any DC */
39 HBITMAP _DIBDRV_ConvertDIBtoDDB( HDC hdc, HBITMAP srcBmp, int startScan, int scanLines )
41 DIBSECTION ds;
42 BITMAPINFO *bmi;
43 HBITMAP hBmp = NULL;
45 int dibWidth, dibHeight;
46 BOOL topDown;
47 void *bits;
48 int stride;
49 UINT colorUsed;
50 int bitFields;
51 HDC tmpHdc;
52 HBITMAP tmpBmp;
53 int res;
55 /* gets DIBSECTION data from source DIB */
56 if(GetObjectW(srcBmp, sizeof(DIBSECTION), &ds) != sizeof(DIBSECTION))
58 ERR("Couldn't get DIBSECTION data\n");
59 return 0;
62 /* gets DIB info */
63 dibWidth = ds.dsBmih.biWidth;
64 dibHeight = ds.dsBmih.biHeight;
65 bits = ds.dsBm.bmBits;
66 stride = ((dibWidth * ds.dsBmih.biBitCount +31) &~31) / 8;
68 /* adjust bits to point at needed starting stripe */
69 if(dibHeight < 0)
71 /* top-down DIB */
72 topDown = TRUE;
73 dibHeight = -dibHeight;
74 bits = (BYTE *)bits + startScan * stride;
76 else
78 topDown = FALSE;
79 bits = (BYTE *)bits + (dibHeight - startScan - scanLines) * stride;
82 /* if requested part is out of source bitmap, returns 0 */
83 if(startScan >= dibHeight)
84 return 0;
85 if(startScan + scanLines >= dibHeight)
86 scanLines = dibHeight - startScan;
88 /* gets the size of DIB palette and bitfields, if any */
89 bitFields = 0;
90 colorUsed = 0;
91 if(ds.dsBmih.biCompression == BI_BITFIELDS)
92 bitFields = 3;
93 else if(ds.dsBmih.biBitCount <= 8)
95 colorUsed = ds.dsBmih.biClrUsed;
96 if(!colorUsed)
97 colorUsed = 1 << ds.dsBmih.biBitCount;
100 /* builds the needed BITMAPINFOHEADER */
101 bmi = HeapAlloc( GetProcessHeap(), 0, sizeof(BITMAPINFOHEADER)+
102 sizeof(RGBQUAD)*colorUsed + sizeof(DWORD) * bitFields );
103 if (!bmi)
105 ERR("HeapAlloc failed\n");
106 return 0;
109 /* copy the header part */
110 memcpy( &bmi->bmiHeader, &ds.dsBmih, sizeof(BITMAPINFOHEADER) );
112 /* gets the color table part, if any */
113 if(colorUsed)
115 /* create a temporary DC, GetDIBColorTable() requests that
116 the DIB is selected in a DC.... */
117 if(!(tmpHdc = CreateCompatibleDC(hdc)))
119 ERR("Couldn't create the temporary HDC\n");
120 HeapFree(GetProcessHeap(), 0, bmi);
121 return 0;
123 /* selects the DIB into the temporary DC */
124 if( !(tmpBmp = SelectObject(tmpHdc, srcBmp)))
126 ERR("Couldn't select source DIB into temporary DC\n");
127 DeleteDC(tmpHdc);
128 HeapFree(GetProcessHeap(), 0, bmi);
129 return 0;
131 if(!GetDIBColorTable(tmpHdc, 0, colorUsed, bmi->bmiColors))
132 ERR("GetDIBColorTable failed\n");
133 SelectObject(tmpHdc, tmpBmp);
134 DeleteDC(tmpHdc);
138 /* fill the bitfields part, if any */
139 if(bitFields)
140 memcpy(bmi->bmiColors, ds.dsBitfields, 3 * sizeof(DWORD));
142 /* adjust dib size for SetDIBits, as it needs it to reverse top-down dibs
143 it must be set to the number of scanLines to transfer */
144 bmi->bmiHeader.biHeight = topDown ? -scanLines : scanLines;
146 /* creates destination compatible bitmap */
147 tmpHdc = GetDC(NULL);
148 hBmp = CreateCompatibleBitmap(tmpHdc, dibWidth, scanLines);
149 ReleaseDC(NULL, tmpHdc);
150 if(!hBmp)
152 ERR("CreateCompatibleBitmap failed\n");
153 HeapFree( GetProcessHeap(), 0, bmi );
154 return 0;
157 /* copies the requested scan lines from DIB to DDB */
158 /* FIXME : still no support for RLE packed DIBs */
159 res = SetDIBits( hdc, hBmp, 0, scanLines, bits, bmi, DIB_RGB_COLORS );
160 HeapFree( GetProcessHeap(), 0, bmi );
161 if(!res)
163 ERR("SetDIBits failed\n");
164 DeleteObject( hBmp );
165 return 0;
168 return hBmp;
171 /***********************************************************************
172 * Creates DIB that is compatible with the target hdc.
173 * startScan and scanLines specify the portion of DDB to convert
174 * in order to avoid unneeded conversion of large DDBs on blitting
176 * NOTE : the srcBmp DDB MUST NOT be selected in any DC */
177 HBITMAP _DIBDRV_ConvertDDBtoDIB( HDC hdc, HBITMAP srcBmp, int startScan, int scanLines )
179 HBITMAP hBmp = NULL;
180 BITMAP bitmap;
181 BITMAPINFO *bi;
182 void *bits = NULL;
184 if (!GetObjectW( srcBmp, sizeof(bitmap), &bitmap ))
186 ERR("Couldn't retrieve source bitmap\n");
187 return 0;
190 if(startScan + scanLines >= bitmap.bmHeight)
191 scanLines = bitmap.bmHeight - startScan;
193 bi = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) /* + 256 * sizeof(RGBQUAD) */);
194 if (!bi)
196 ERR("HeapAlloc failed\n");
197 return 0;
200 bi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
201 bi->bmiHeader.biWidth = bitmap.bmWidth;
202 bi->bmiHeader.biHeight = scanLines;
203 bi->bmiHeader.biPlanes = bitmap.bmPlanes;
204 bi->bmiHeader.biBitCount = 32;
205 bi->bmiHeader.biCompression = BI_RGB;
206 bi->bmiHeader.biSizeImage = 0;
208 /* No need to get the color table or the color masks
209 as we're requesting a 32 bit rgba DIB */
211 /* Create bitmap and fill in bits */
212 hBmp = CreateDIBSection(hdc, bi, DIB_RGB_COLORS, &bits, NULL, 0);
213 if(!hBmp)
215 ERR("Failed to create DIB section\n");
216 HeapFree( GetProcessHeap(), 0, bi );
217 return 0;
219 if (bits)
221 if(!GetDIBits(hdc, srcBmp, startScan, scanLines, bits, bi, DIB_RGB_COLORS))
223 ERR("GetDIBits failed\n");
224 DeleteObject( hBmp );
225 HeapFree( GetProcessHeap(), 0, bi );
226 return 0;
229 else
231 ERR("CreateDibSection couldn't allocate DIB bits\n");
232 DeleteObject( hBmp );
233 HeapFree( GetProcessHeap(), 0, bi );
234 return 0;
236 HeapFree( GetProcessHeap(), 0, bi );
237 return hBmp;
240 /***********************************************************************
241 * BITBLT_ConvertDevDDBtoDIB
243 * Creates DIB that is compatible with the target hdc for a device (non memory) source DC */
244 HBITMAP _DIBDRV_ConvertDevDDBtoDIB( HDC hdcSrc, HDC hdcDst, int xSrc, int ySrc, int width, int height )
246 HBITMAP bmp, dib;
247 HDC memHDC = NULL;
249 /* at first, we create a compatible DC and a bitmap with needed sizes */
250 memHDC = CreateCompatibleDC(hdcSrc);
251 if(!memHDC)
253 ERR("CreateCompatibleDC failed\n");
254 return 0;
256 bmp = CreateCompatibleBitmap(hdcSrc, width, height);
257 if(!bmp)
259 ERR("CreateCompatibleBitmap failed\n");
260 DeleteDC(memHDC);
261 return 0;
264 /* select the newly created DDB into the temporary DC */
265 bmp = SelectObject(memHDC, bmp);
266 if(!bmp)
268 ERR("Failed selecting DDB into temporary DC\n");
269 DeleteObject(bmp);
270 DeleteDC(memHDC);
271 return 0;
274 /* next, we blit pixels from device to the compatible bitmap */
275 if(!BitBlt(memHDC, 0, 0, width, height, hdcSrc, xSrc, ySrc, SRCCOPY))
277 ERR("BitBlt failed\n");
278 DeleteObject(bmp);
279 DeleteDC(memHDC);
280 return 0;
283 /* select out the DDB from the temporary DC */
284 bmp = SelectObject(memHDC, bmp);
285 DeleteDC(memHDC);
286 if(!bmp)
288 ERR("Failed selecting DDB out temporary DC\n");
289 DeleteObject(bmp);
290 return 0;
293 /*now we can convert the bitmap to a DIB */
294 dib = _DIBDRV_ConvertDDBtoDIB( hdcDst, bmp, 0, height );
295 if(!dib)
296 FIXME("ConvertDDBtoDIB failed\n");
298 /* free resources and return the created dib */
299 DeleteObject(bmp);
300 return dib;