e5aac6035b7a8e881b770dca214a8c447c123d4a
[reactos.git] / reactos / subsystems / win32 / win32k / objects / dibobj.c
1 /*
2 * $Id$
3 *
4 * ReactOS W32 Subsystem
5 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program 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
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include <w32k.h>
23
24 #define NDEBUG
25 #include <debug.h>
26
27 static const RGBQUAD EGAColorsQuads[16] = {
28 /* rgbBlue, rgbGreen, rgbRed, rgbReserved */
29 { 0x00, 0x00, 0x00, 0x00 },
30 { 0x00, 0x00, 0x80, 0x00 },
31 { 0x00, 0x80, 0x00, 0x00 },
32 { 0x00, 0x80, 0x80, 0x00 },
33 { 0x80, 0x00, 0x00, 0x00 },
34 { 0x80, 0x00, 0x80, 0x00 },
35 { 0x80, 0x80, 0x00, 0x00 },
36 { 0x80, 0x80, 0x80, 0x00 },
37 { 0xc0, 0xc0, 0xc0, 0x00 },
38 { 0x00, 0x00, 0xff, 0x00 },
39 { 0x00, 0xff, 0x00, 0x00 },
40 { 0x00, 0xff, 0xff, 0x00 },
41 { 0xff, 0x00, 0x00, 0x00 },
42 { 0xff, 0x00, 0xff, 0x00 },
43 { 0xff, 0xff, 0x00, 0x00 },
44 { 0xff, 0xff, 0xff, 0x00 }
45 };
46
47 static const RGBQUAD DefLogPaletteQuads[20] = { /* Copy of Default Logical Palette */
48 /* rgbBlue, rgbGreen, rgbRed, rgbReserved */
49 { 0x00, 0x00, 0x00, 0x00 },
50 { 0x00, 0x00, 0x80, 0x00 },
51 { 0x00, 0x80, 0x00, 0x00 },
52 { 0x00, 0x80, 0x80, 0x00 },
53 { 0x80, 0x00, 0x00, 0x00 },
54 { 0x80, 0x00, 0x80, 0x00 },
55 { 0x80, 0x80, 0x00, 0x00 },
56 { 0xc0, 0xc0, 0xc0, 0x00 },
57 { 0xc0, 0xdc, 0xc0, 0x00 },
58 { 0xf0, 0xca, 0xa6, 0x00 },
59 { 0xf0, 0xfb, 0xff, 0x00 },
60 { 0xa4, 0xa0, 0xa0, 0x00 },
61 { 0x80, 0x80, 0x80, 0x00 },
62 { 0x00, 0x00, 0xf0, 0x00 },
63 { 0x00, 0xff, 0x00, 0x00 },
64 { 0x00, 0xff, 0xff, 0x00 },
65 { 0xff, 0x00, 0x00, 0x00 },
66 { 0xff, 0x00, 0xff, 0x00 },
67 { 0xff, 0xff, 0x00, 0x00 },
68 { 0xff, 0xff, 0xff, 0x00 }
69 };
70
71
72 UINT
73 APIENTRY
74 IntSetDIBColorTable(
75 HDC hDC,
76 UINT StartIndex,
77 UINT Entries,
78 CONST RGBQUAD *Colors)
79 {
80 PDC dc;
81 PSURFACE psurf;
82 PPALETTE PalGDI;
83 UINT Index;
84 ULONG biBitCount;
85
86 if (!(dc = DC_LockDc(hDC))) return 0;
87 if (dc->dctype == DC_TYPE_INFO)
88 {
89 DC_UnlockDc(dc);
90 return 0;
91 }
92
93 psurf = dc->dclevel.pSurface;
94 if (psurf == NULL)
95 {
96 DC_UnlockDc(dc);
97 SetLastWin32Error(ERROR_INVALID_PARAMETER);
98 return 0;
99 }
100
101 if (psurf->hSecure == NULL)
102 {
103 DC_UnlockDc(dc);
104 SetLastWin32Error(ERROR_INVALID_PARAMETER);
105 return 0;
106 }
107
108 biBitCount = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
109 if (biBitCount <= 8 && StartIndex < (1 << biBitCount))
110 {
111 if (StartIndex + Entries > (1 << biBitCount))
112 Entries = (1 << biBitCount) - StartIndex;
113
114 PalGDI = PALETTE_LockPalette(psurf->hDIBPalette);
115 if (PalGDI == NULL)
116 {
117 DC_UnlockDc(dc);
118 SetLastWin32Error(ERROR_INVALID_HANDLE);
119 return 0;
120 }
121
122 for (Index = StartIndex;
123 Index < StartIndex + Entries && Index < PalGDI->NumColors;
124 Index++)
125 {
126 PalGDI->IndexedColors[Index].peRed = Colors[Index - StartIndex].rgbRed;
127 PalGDI->IndexedColors[Index].peGreen = Colors[Index - StartIndex].rgbGreen;
128 PalGDI->IndexedColors[Index].peBlue = Colors[Index - StartIndex].rgbBlue;
129 }
130 PALETTE_UnlockPalette(PalGDI);
131 }
132 else
133 Entries = 0;
134
135 /* Mark the brushes invalid */
136 dc->pdcattr->ulDirty_ |= DIRTY_FILL|DIRTY_LINE|DIRTY_BACKGROUND|DIRTY_TEXT;
137
138 DC_UnlockDc(dc);
139
140 return Entries;
141 }
142
143 UINT
144 APIENTRY
145 IntGetDIBColorTable(
146 HDC hDC,
147 UINT StartIndex,
148 UINT Entries,
149 RGBQUAD *Colors)
150 {
151 PDC dc;
152 PSURFACE psurf;
153 PPALETTE PalGDI;
154 UINT Index;
155 ULONG biBitCount;
156
157 if (!(dc = DC_LockDc(hDC))) return 0;
158 if (dc->dctype == DC_TYPE_INFO)
159 {
160 DC_UnlockDc(dc);
161 return 0;
162 }
163
164 psurf = dc->dclevel.pSurface;
165 if (psurf == NULL)
166 {
167 DC_UnlockDc(dc);
168 SetLastWin32Error(ERROR_INVALID_PARAMETER);
169 return 0;
170 }
171
172 if (psurf->hSecure == NULL)
173 {
174 DC_UnlockDc(dc);
175 SetLastWin32Error(ERROR_INVALID_PARAMETER);
176 return 0;
177 }
178
179 biBitCount = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
180 if (biBitCount <= 8 &&
181 StartIndex < (1 << biBitCount))
182 {
183 if (StartIndex + Entries > (1 << biBitCount))
184 Entries = (1 << biBitCount) - StartIndex;
185
186 PalGDI = PALETTE_LockPalette(psurf->hDIBPalette);
187 if (PalGDI == NULL)
188 {
189 DC_UnlockDc(dc);
190 SetLastWin32Error(ERROR_INVALID_HANDLE);
191 return 0;
192 }
193
194 for (Index = StartIndex;
195 Index < StartIndex + Entries && Index < PalGDI->NumColors;
196 Index++)
197 {
198 Colors[Index - StartIndex].rgbRed = PalGDI->IndexedColors[Index].peRed;
199 Colors[Index - StartIndex].rgbGreen = PalGDI->IndexedColors[Index].peGreen;
200 Colors[Index - StartIndex].rgbBlue = PalGDI->IndexedColors[Index].peBlue;
201 Colors[Index - StartIndex].rgbReserved = 0;
202 }
203 PALETTE_UnlockPalette(PalGDI);
204 }
205 else
206 Entries = 0;
207
208 DC_UnlockDc(dc);
209
210 return Entries;
211 }
212
213 // Converts a DIB to a device-dependent bitmap
214 static INT
215 FASTCALL
216 IntSetDIBits(
217 PDC DC,
218 HBITMAP hBitmap,
219 UINT StartScan,
220 UINT ScanLines,
221 CONST VOID *Bits,
222 CONST BITMAPINFO *bmi,
223 UINT ColorUse)
224 {
225 SURFACE *bitmap;
226 HBITMAP SourceBitmap;
227 INT result = 0;
228 BOOL copyBitsResult;
229 SURFOBJ *DestSurf, *SourceSurf;
230 SIZEL SourceSize;
231 POINTL ZeroPoint;
232 RECTL DestRect;
233 EXLATEOBJ exlo;
234 PPALETTE ppalDDB, ppalDIB;
235 //RGBQUAD *lpRGB;
236 HPALETTE DDB_Palette, DIB_Palette;
237 ULONG DIB_Palette_Type;
238 INT DIBWidth;
239
240 // Check parameters
241 if (!(bitmap = SURFACE_LockSurface(hBitmap)))
242 {
243 return 0;
244 }
245
246 // Get RGB values
247 //if (ColorUse == DIB_PAL_COLORS)
248 // lpRGB = DIB_MapPaletteColors(hDC, bmi);
249 //else
250 // lpRGB = &bmi->bmiColors;
251
252 DestSurf = &bitmap->SurfObj;
253
254 // Create source surface
255 SourceSize.cx = bmi->bmiHeader.biWidth;
256 SourceSize.cy = ScanLines;
257
258 // Determine width of DIB
259 DIBWidth = DIB_GetDIBWidthBytes(SourceSize.cx, bmi->bmiHeader.biBitCount);
260
261 SourceBitmap = EngCreateBitmap(SourceSize,
262 DIBWidth,
263 BitmapFormat(bmi->bmiHeader.biBitCount, bmi->bmiHeader.biCompression),
264 bmi->bmiHeader.biHeight < 0 ? BMF_TOPDOWN : 0,
265 (PVOID) Bits);
266 if (0 == SourceBitmap)
267 {
268 SURFACE_UnlockSurface(bitmap);
269 SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
270 return 0;
271 }
272
273 SourceSurf = EngLockSurface((HSURF)SourceBitmap);
274 if (NULL == SourceSurf)
275 {
276 EngDeleteSurface((HSURF)SourceBitmap);
277 SURFACE_UnlockSurface(bitmap);
278 SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
279 return 0;
280 }
281
282 // Use hDIBPalette if it exists
283 if (bitmap->hDIBPalette)
284 {
285 DDB_Palette = bitmap->hDIBPalette;
286 }
287 else
288 {
289 // Destination palette obtained from the hDC
290 DDB_Palette = DC->ppdev->DevInfo.hpalDefault;
291 }
292
293 ppalDDB = PALETTE_LockPalette(DDB_Palette);
294 if (NULL == ppalDDB)
295 {
296 EngUnlockSurface(SourceSurf);
297 EngDeleteSurface((HSURF)SourceBitmap);
298 SURFACE_UnlockSurface(bitmap);
299 SetLastWin32Error(ERROR_INVALID_HANDLE);
300 return 0;
301 }
302
303 // Source palette obtained from the BITMAPINFO
304 DIB_Palette = BuildDIBPalette((PBITMAPINFO)bmi, (PINT)&DIB_Palette_Type);
305 if (NULL == DIB_Palette)
306 {
307 EngUnlockSurface(SourceSurf);
308 EngDeleteSurface((HSURF)SourceBitmap);
309 SURFACE_UnlockSurface(bitmap);
310 SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
311 return 0;
312 }
313
314 ppalDIB = PALETTE_LockPalette(DIB_Palette);
315
316 /* Initialize XLATEOBJ for color translation */
317 EXLATEOBJ_vInitialize(&exlo, ppalDIB, ppalDDB, 0, 0, 0);
318
319 // Zero point
320 ZeroPoint.x = 0;
321 ZeroPoint.y = 0;
322
323 // Determine destination rectangle
324 DestRect.left = 0;
325 DestRect.top = abs(bmi->bmiHeader.biHeight) - StartScan - ScanLines;
326 DestRect.right = SourceSize.cx;
327 DestRect.bottom = DestRect.top + ScanLines;
328
329 copyBitsResult = IntEngCopyBits(DestSurf, SourceSurf, NULL, &exlo.xlo, &DestRect, &ZeroPoint);
330
331 // If it succeeded, return number of scanlines copies
332 if (copyBitsResult == TRUE)
333 {
334 result = SourceSize.cy;
335 // or
336 // result = abs(bmi->bmiHeader.biHeight) - StartScan;
337 }
338
339 // Clean up
340 EXLATEOBJ_vCleanup(&exlo);
341 PALETTE_UnlockPalette(ppalDIB);
342 PALETTE_UnlockPalette(ppalDDB);
343 PALETTE_FreePaletteByHandle(DIB_Palette);
344 EngUnlockSurface(SourceSurf);
345 EngDeleteSurface((HSURF)SourceBitmap);
346
347 // if (ColorUse == DIB_PAL_COLORS)
348 // WinFree((LPSTR)lpRGB);
349
350 SURFACE_UnlockSurface(bitmap);
351
352 return result;
353 }
354
355 // FIXME by Removing NtGdiSetDIBits!!!
356 // This is a victim of the Win32k Initialization BUG!!!!!
357 // Converts a DIB to a device-dependent bitmap
358 INT
359 APIENTRY
360 NtGdiSetDIBits(
361 HDC hDC,
362 HBITMAP hBitmap,
363 UINT StartScan,
364 UINT ScanLines,
365 CONST VOID *Bits,
366 CONST BITMAPINFO *bmi,
367 UINT ColorUse)
368 {
369 PDC Dc;
370 INT Ret;
371 NTSTATUS Status = STATUS_SUCCESS;
372 UINT cjBits;
373
374 if (!Bits) return 0;
375
376 _SEH2_TRY
377 { // FYI: We converted from CORE in gdi.
378 ProbeForRead(bmi, sizeof(BITMAPINFO), 1);
379 cjBits = bmi->bmiHeader.biBitCount * bmi->bmiHeader.biPlanes * bmi->bmiHeader.biWidth;
380 cjBits = ((cjBits + 31) & ~31) / 8;
381 cjBits *= ScanLines;
382 ProbeForRead(Bits, cjBits, 1);
383 }
384 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
385 {
386 Status = _SEH2_GetExceptionCode();
387 }
388 _SEH2_END
389
390 if (!NT_SUCCESS(Status))
391 {
392 return 0;
393 }
394
395 Dc = DC_LockDc(hDC);
396 if (NULL == Dc)
397 {
398 SetLastWin32Error(ERROR_INVALID_HANDLE);
399 return 0;
400 }
401 if (Dc->dctype == DC_TYPE_INFO)
402 {
403 DC_UnlockDc(Dc);
404 return 0;
405 }
406
407 Ret = IntSetDIBits(Dc, hBitmap, StartScan, ScanLines, Bits, bmi, ColorUse);
408
409 DC_UnlockDc(Dc);
410
411 return Ret;
412 }
413
414 W32KAPI
415 INT
416 APIENTRY
417 NtGdiSetDIBitsToDeviceInternal(
418 IN HDC hDC,
419 IN INT XDest,
420 IN INT YDest,
421 IN DWORD Width,
422 IN DWORD Height,
423 IN INT XSrc,
424 IN INT YSrc,
425 IN DWORD StartScan,
426 IN DWORD ScanLines,
427 IN LPBYTE Bits,
428 IN LPBITMAPINFO bmi,
429 IN DWORD ColorUse,
430 IN UINT cjMaxBits,
431 IN UINT cjMaxInfo,
432 IN BOOL bTransformCoordinates,
433 IN OPTIONAL HANDLE hcmXform)
434 {
435 INT ret = 0;
436 NTSTATUS Status = STATUS_SUCCESS;
437 PDC pDC;
438 HBITMAP hSourceBitmap = NULL;
439 SURFOBJ *pDestSurf, *pSourceSurf = NULL;
440 SURFACE *pSurf;
441 RECTL rcDest;
442 POINTL ptSource;
443 INT DIBWidth;
444 SIZEL SourceSize;
445 EXLATEOBJ exlo;
446 PPALETTE ppalDDB = NULL, ppalDIB = NULL;
447 HPALETTE DDBPalette, DIBPalette = NULL;
448 ULONG DIBPaletteType;
449
450 if (!Bits) return 0;
451
452 _SEH2_TRY
453 {
454 ProbeForRead(bmi, cjMaxInfo , 1);
455 ProbeForRead(Bits, cjMaxBits, 1);
456 }
457 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
458 {
459 Status = _SEH2_GetExceptionCode();
460 }
461 _SEH2_END
462
463 if (!NT_SUCCESS(Status))
464 {
465 return 0;
466 }
467
468 pDC = DC_LockDc(hDC);
469 if (!pDC)
470 {
471 SetLastWin32Error(ERROR_INVALID_HANDLE);
472 return 0;
473 }
474 if (pDC->dctype == DC_TYPE_INFO)
475 {
476 DC_UnlockDc(pDC);
477 return 0;
478 }
479
480 /* Use destination palette obtained from the DC by default */
481 DDBPalette = pDC->ppdev->DevInfo.hpalDefault;
482
483 /* Try to use hDIBPalette if it exists */
484 pSurf = pDC->dclevel.pSurface;
485 if (pSurf && pSurf->hDIBPalette)
486 {
487 DDBPalette = pSurf->hDIBPalette;
488 }
489
490 pDestSurf = pSurf ? &pSurf->SurfObj : NULL;
491
492 rcDest.left = XDest;
493 rcDest.top = YDest;
494 if (bTransformCoordinates)
495 {
496 CoordLPtoDP(pDC, (LPPOINT)&rcDest);
497 }
498 rcDest.left += pDC->ptlDCOrig.x;
499 rcDest.top += pDC->ptlDCOrig.y;
500 rcDest.right = rcDest.left + Width;
501 rcDest.bottom = rcDest.top + Height;
502 ptSource.x = XSrc;
503 ptSource.y = YSrc;
504
505 SourceSize.cx = bmi->bmiHeader.biWidth;
506 SourceSize.cy = ScanLines; // this one --> abs(bmi->bmiHeader.biHeight) - StartScan
507 DIBWidth = DIB_GetDIBWidthBytes(SourceSize.cx, bmi->bmiHeader.biBitCount);
508
509 hSourceBitmap = EngCreateBitmap(SourceSize,
510 DIBWidth,
511 BitmapFormat(bmi->bmiHeader.biBitCount, bmi->bmiHeader.biCompression),
512 bmi->bmiHeader.biHeight < 0 ? BMF_TOPDOWN : 0,
513 (PVOID) Bits);
514 if (!hSourceBitmap)
515 {
516 SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
517 Status = STATUS_NO_MEMORY;
518 goto Exit;
519 }
520
521 pSourceSurf = EngLockSurface((HSURF)hSourceBitmap);
522 if (!pSourceSurf)
523 {
524 Status = STATUS_UNSUCCESSFUL;
525 goto Exit;
526 }
527
528 /* Obtain destination palette */
529 ppalDDB = PALETTE_LockPalette(DDBPalette);
530 if (!ppalDDB)
531 {
532 SetLastWin32Error(ERROR_INVALID_HANDLE);
533 Status = STATUS_UNSUCCESSFUL;
534 goto Exit;
535 }
536
537 DIBPalette = BuildDIBPalette(bmi, (PINT)&DIBPaletteType);
538 if (!DIBPalette)
539 {
540 SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
541 Status = STATUS_NO_MEMORY;
542 goto Exit;
543 }
544
545 /* Initialize EXLATEOBJ */
546 EXLATEOBJ_vInitialize(&exlo, ppalDIB, ppalDDB, 0, 0, 0);
547
548 /* Copy the bits */
549 Status = IntEngBitBlt(pDestSurf,
550 pSourceSurf,
551 NULL,
552 pDC->rosdc.CombinedClip,
553 &exlo.xlo,
554 &rcDest,
555 &ptSource,
556 NULL,
557 NULL,
558 NULL,
559 ROP3_TO_ROP4(SRCCOPY));
560
561 /* Cleanup EXLATEOBJ */
562 EXLATEOBJ_vCleanup(&exlo);
563
564 Exit:
565 if (NT_SUCCESS(Status))
566 {
567 /* FIXME: Should probably be only the number of lines actually copied */
568 ret = ScanLines; // this one --> abs(Info->bmiHeader.biHeight) - StartScan;
569 }
570
571 if (ppalDIB) PALETTE_UnlockPalette(ppalDIB);
572 if (ppalDDB) PALETTE_UnlockPalette(ppalDDB);
573
574 if (pSourceSurf) EngUnlockSurface(pSourceSurf);
575 if (hSourceBitmap) EngDeleteSurface((HSURF)hSourceBitmap);
576 if (DIBPalette) PALETTE_FreePaletteByHandle(DIBPalette);
577 DC_UnlockDc(pDC);
578
579 return ret;
580 }
581
582
583 /* Converts a device-dependent bitmap to a DIB */
584 INT
585 APIENTRY
586 NtGdiGetDIBitsInternal(
587 HDC hDC,
588 HBITMAP hBitmap,
589 UINT StartScan,
590 UINT ScanLines,
591 LPBYTE Bits,
592 LPBITMAPINFO Info,
593 UINT Usage,
594 UINT MaxBits,
595 UINT MaxInfo)
596 {
597 PDC Dc;
598 SURFACE *psurf = NULL;
599 HBITMAP hDestBitmap = NULL;
600 HPALETTE hSourcePalette = NULL;
601 HPALETTE hDestPalette = NULL;
602 PPALETTE ppalSrc = NULL;
603 PPALETTE ppalDst = NULL;
604 NTSTATUS Status = STATUS_SUCCESS;
605 ULONG Result = 0;
606 BOOL bPaletteMatch = FALSE;
607 PBYTE ChkBits = Bits;
608 PVOID ColorPtr;
609 RGBQUAD *rgbQuads;
610 ULONG DestPaletteType;
611 ULONG Index;
612
613 DPRINT("Entered NtGdiGetDIBitsInternal()\n");
614
615 if ((Usage && Usage != DIB_PAL_COLORS) || !Info || !hBitmap)
616 return 0;
617
618 // if ScanLines == 0, no need to copy Bits.
619 if (!ScanLines)
620 ChkBits = NULL;
621
622 _SEH2_TRY
623 {
624 ProbeForRead(&Info->bmiHeader.biSize, sizeof(DWORD), 1);
625
626 ProbeForWrite(Info, Info->bmiHeader.biSize, 1); // Comp for Core.
627 if (ChkBits) ProbeForWrite(ChkBits, MaxBits, 1);
628 }
629 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
630 {
631 Status = _SEH2_GetExceptionCode();
632 }
633 _SEH2_END
634
635 if (!NT_SUCCESS(Status))
636 {
637 return 0;
638 }
639
640 Dc = DC_LockDc(hDC);
641 if (Dc == NULL) return 0;
642 if (Dc->dctype == DC_TYPE_INFO)
643 {
644 DC_UnlockDc(Dc);
645 return 0;
646 }
647 DC_UnlockDc(Dc);
648
649 /* Get a pointer to the source bitmap object */
650 psurf = SURFACE_LockSurface(hBitmap);
651 if (psurf == NULL)
652 return 0;
653
654 hSourcePalette = psurf->hDIBPalette;
655 if (!hSourcePalette)
656 {
657 hSourcePalette = pPrimarySurface->DevInfo.hpalDefault;
658 }
659
660 ColorPtr = ((PBYTE)Info + Info->bmiHeader.biSize);
661 rgbQuads = (RGBQUAD *)ColorPtr;
662
663 /* Copy palette information
664 * Always create a palette for 15 & 16 bit. */
665 if ((Info->bmiHeader.biBitCount == BitsPerFormat(psurf->SurfObj.iBitmapFormat) &&
666 Info->bmiHeader.biBitCount != 15 && Info->bmiHeader.biBitCount != 16) ||
667 !ChkBits)
668 {
669 hDestPalette = hSourcePalette;
670 bPaletteMatch = TRUE;
671 }
672 else
673 hDestPalette = BuildDIBPalette(Info, (PINT)&DestPaletteType); //hDestPalette = Dc->DevInfo->hpalDefault;
674
675 ppalSrc = PALETTE_LockPalette(hSourcePalette);
676 /* FIXME - ppalSrc can be NULL!!! Don't assert here! */
677 ASSERT(ppalSrc);
678
679 if (!bPaletteMatch)
680 {
681 ppalDst = PALETTE_LockPalette(hDestPalette);
682 /* FIXME - ppalDst can be NULL!!!! Don't assert here!!! */
683 DPRINT("ppalDst : %p\n", ppalDst);
684 ASSERT(ppalDst);
685 }
686 else
687 {
688 ppalDst = ppalSrc;
689 }
690
691 /* Copy palette. */
692 /* FIXME: This is largely incomplete. ATM no Core!*/
693 switch (Info->bmiHeader.biBitCount)
694 {
695 case 1:
696 case 4:
697 case 8:
698 Info->bmiHeader.biClrUsed = 0;
699 if (psurf->hSecure &&
700 BitsPerFormat(psurf->SurfObj.iBitmapFormat) == Info->bmiHeader.biBitCount)
701 {
702 if (Usage == DIB_RGB_COLORS)
703 {
704 if (ppalDst->NumColors != 1 << Info->bmiHeader.biBitCount)
705 Info->bmiHeader.biClrUsed = ppalDst->NumColors;
706 for (Index = 0;
707 Index < (1 << Info->bmiHeader.biBitCount) && Index < ppalDst->NumColors;
708 Index++)
709 {
710 rgbQuads[Index].rgbRed = ppalDst->IndexedColors[Index].peRed;
711 rgbQuads[Index].rgbGreen = ppalDst->IndexedColors[Index].peGreen;
712 rgbQuads[Index].rgbBlue = ppalDst->IndexedColors[Index].peBlue;
713 rgbQuads[Index].rgbReserved = 0;
714 }
715 }
716 else
717 {
718 PWORD Ptr = ColorPtr;
719 for (Index = 0;
720 Index < (1 << Info->bmiHeader.biBitCount);
721 Index++)
722 {
723 Ptr[Index] = (WORD)Index;
724 }
725 }
726 }
727 else
728 {
729 if (Usage == DIB_PAL_COLORS)
730 {
731 PWORD Ptr = ColorPtr;
732 for (Index = 0;
733 Index < (1 << Info->bmiHeader.biBitCount);
734 Index++)
735 {
736 Ptr[Index] = (WORD)Index;
737 }
738 }
739 else if (Info->bmiHeader.biBitCount > 1 && bPaletteMatch)
740 {
741 for (Index = 0;
742 Index < (1 << Info->bmiHeader.biBitCount) && Index < ppalDst->NumColors;
743 Index++)
744 {
745 Info->bmiColors[Index].rgbRed = ppalDst->IndexedColors[Index].peRed;
746 Info->bmiColors[Index].rgbGreen = ppalDst->IndexedColors[Index].peGreen;
747 Info->bmiColors[Index].rgbBlue = ppalDst->IndexedColors[Index].peBlue;
748 Info->bmiColors[Index].rgbReserved = 0;
749 }
750 }
751 else
752 {
753 switch (Info->bmiHeader.biBitCount)
754 {
755 case 1:
756 rgbQuads[0].rgbRed = rgbQuads[0].rgbGreen = rgbQuads[0].rgbBlue = 0;
757 rgbQuads[0].rgbReserved = 0;
758 rgbQuads[1].rgbRed = rgbQuads[1].rgbGreen = rgbQuads[1].rgbBlue = 0xff;
759 rgbQuads[1].rgbReserved = 0;
760 break;
761 case 4:
762 RtlCopyMemory(ColorPtr, EGAColorsQuads, sizeof(EGAColorsQuads));
763 break;
764 case 8:
765 {
766 INT r, g, b;
767 RGBQUAD *color;
768
769 RtlCopyMemory(rgbQuads, DefLogPaletteQuads, 10 * sizeof(RGBQUAD));
770 RtlCopyMemory(rgbQuads + 246, DefLogPaletteQuads + 10, 10 * sizeof(RGBQUAD));
771 color = rgbQuads + 10;
772 for (r = 0; r <= 5; r++) /* FIXME */
773 for (g = 0; g <= 5; g++)
774 for (b = 0; b <= 5; b++)
775 {
776 color->rgbRed = (r * 0xff) / 5;
777 color->rgbGreen = (g * 0xff) / 5;
778 color->rgbBlue = (b * 0xff) / 5;
779 color->rgbReserved = 0;
780 color++;
781 }
782 }
783 break;
784 }
785 }
786 }
787
788 case 15:
789 if (Info->bmiHeader.biCompression == BI_BITFIELDS)
790 {
791 ((PDWORD)Info->bmiColors)[0] = 0x7c00;
792 ((PDWORD)Info->bmiColors)[1] = 0x03e0;
793 ((PDWORD)Info->bmiColors)[2] = 0x001f;
794 }
795 break;
796
797 case 16:
798 if (Info->bmiHeader.biCompression == BI_BITFIELDS)
799 {
800 ((PDWORD)Info->bmiColors)[0] = 0xf800;
801 ((PDWORD)Info->bmiColors)[1] = 0x07e0;
802 ((PDWORD)Info->bmiColors)[2] = 0x001f;
803 }
804 break;
805
806 case 24:
807 case 32:
808 if (Info->bmiHeader.biCompression == BI_BITFIELDS)
809 {
810 ((PDWORD)Info->bmiColors)[0] = 0xff0000;
811 ((PDWORD)Info->bmiColors)[1] = 0x00ff00;
812 ((PDWORD)Info->bmiColors)[2] = 0x0000ff;
813 }
814 break;
815 }
816
817 if (!bPaletteMatch)
818 PALETTE_UnlockPalette(ppalDst);
819
820 /* fill out the BITMAPINFO struct */
821 if (!ChkBits)
822 { // Core or not to Core? We have converted from Core in Gdi~ so?
823 if (Info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
824 {
825 BITMAPCOREHEADER* coreheader = (BITMAPCOREHEADER*) Info;
826 coreheader->bcWidth = psurf->SurfObj.sizlBitmap.cx;
827 coreheader->bcPlanes = 1;
828 coreheader->bcBitCount = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
829 coreheader->bcHeight = psurf->SurfObj.sizlBitmap.cy;
830 if (psurf->SurfObj.lDelta > 0)
831 coreheader->bcHeight = -coreheader->bcHeight;
832 }
833
834 if (Info->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER))
835 {
836 Info->bmiHeader.biWidth = psurf->SurfObj.sizlBitmap.cx;
837 Info->bmiHeader.biHeight = psurf->SurfObj.sizlBitmap.cy;
838 Info->bmiHeader.biPlanes = 1;
839 Info->bmiHeader.biBitCount = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
840 switch (psurf->SurfObj.iBitmapFormat)
841 {
842 /* FIXME: What about BI_BITFIELDS? */
843 case BMF_1BPP:
844 case BMF_4BPP:
845 case BMF_8BPP:
846 case BMF_16BPP:
847 case BMF_24BPP:
848 case BMF_32BPP:
849 Info->bmiHeader.biCompression = BI_RGB;
850 break;
851 case BMF_4RLE:
852 Info->bmiHeader.biCompression = BI_RLE4;
853 break;
854 case BMF_8RLE:
855 Info->bmiHeader.biCompression = BI_RLE8;
856 break;
857 case BMF_JPEG:
858 Info->bmiHeader.biCompression = BI_JPEG;
859 break;
860 case BMF_PNG:
861 Info->bmiHeader.biCompression = BI_PNG;
862 break;
863 }
864 /* Image size has to be calculated */
865 Info->bmiHeader.biSizeImage = DIB_GetDIBWidthBytes(Info->bmiHeader.biWidth,
866 Info->bmiHeader.biBitCount) * Info->bmiHeader.biHeight;
867 Info->bmiHeader.biXPelsPerMeter = 0; /* FIXME */
868 Info->bmiHeader.biYPelsPerMeter = 0; /* FIXME */
869 Info->bmiHeader.biClrUsed = 0;
870 Info->bmiHeader.biClrImportant = 1 << Info->bmiHeader.biBitCount; /* FIXME */
871 /* Report negtive height for top-down bitmaps. */
872 if (psurf->SurfObj.lDelta > 0)
873 Info->bmiHeader.biHeight = -Info->bmiHeader.biHeight;
874 }
875 Result = psurf->SurfObj.sizlBitmap.cy;
876 }
877 else
878 {
879 SIZEL DestSize;
880 POINTL SourcePoint;
881
882 //
883 // If we have a good dib pointer, why not just copy bits from there w/o XLATE'ing them.
884 //
885 /* Create the destination bitmap too for the copy operation */
886 if (StartScan > psurf->SurfObj.sizlBitmap.cy)
887 {
888 goto cleanup;
889 }
890 else
891 {
892 ScanLines = min(ScanLines, psurf->SurfObj.sizlBitmap.cy - StartScan);
893 DestSize.cx = psurf->SurfObj.sizlBitmap.cx;
894 DestSize.cy = ScanLines;
895
896 hDestBitmap = NULL;
897
898 if (Info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
899 {
900 BITMAPCOREHEADER* coreheader = (BITMAPCOREHEADER*) Info;
901 hDestBitmap = EngCreateBitmap(DestSize,
902 DIB_GetDIBWidthBytes(DestSize.cx, coreheader->bcBitCount),
903 BitmapFormat(coreheader->bcBitCount, BI_RGB),
904 0 < coreheader->bcHeight ? 0 : BMF_TOPDOWN,
905 Bits);
906 }
907
908 if (Info->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER))
909 {
910 Info->bmiHeader.biSizeImage = DIB_GetDIBWidthBytes(DestSize.cx,
911 Info->bmiHeader.biBitCount) * DestSize.cy;
912
913 hDestBitmap = EngCreateBitmap(DestSize,
914 DIB_GetDIBWidthBytes(DestSize.cx, Info->bmiHeader.biBitCount),
915 BitmapFormat(Info->bmiHeader.biBitCount, Info->bmiHeader.biCompression),
916 0 < Info->bmiHeader.biHeight ? 0 : BMF_TOPDOWN,
917 Bits);
918 }
919
920 if (hDestBitmap == NULL)
921 goto cleanup;
922 }
923
924 if (NT_SUCCESS(Status))
925 {
926 EXLATEOBJ exlo;
927 SURFOBJ *DestSurfObj;
928 RECTL DestRect;
929
930 EXLATEOBJ_vInitialize(&exlo, ppalSrc, ppalDst, 0, 0, 0);
931
932 SourcePoint.x = 0;
933 SourcePoint.y = psurf->SurfObj.sizlBitmap.cy - (StartScan + ScanLines);
934
935 /* Determine destination rectangle */
936 DestRect.top = 0;
937 DestRect.left = 0;
938 DestRect.right = DestSize.cx;
939 DestRect.bottom = DestSize.cy;
940
941 DestSurfObj = EngLockSurface((HSURF)hDestBitmap);
942
943 if (IntEngCopyBits(DestSurfObj,
944 &psurf->SurfObj,
945 NULL,
946 &exlo.xlo,
947 &DestRect,
948 &SourcePoint))
949 {
950 DPRINT("GetDIBits %d \n",abs(Info->bmiHeader.biHeight) - StartScan);
951 Result = ScanLines;
952 }
953
954 EXLATEOBJ_vCleanup(&exlo);
955 EngUnlockSurface(DestSurfObj);
956 }
957 }
958 cleanup:
959 PALETTE_UnlockPalette(ppalSrc);
960
961 if (hDestBitmap != NULL)
962 EngDeleteSurface((HSURF)hDestBitmap);
963
964 if (hDestPalette != NULL && bPaletteMatch == FALSE)
965 PALETTE_FreePaletteByHandle(hDestPalette);
966
967 SURFACE_UnlockSurface(psurf);
968
969 DPRINT("leaving NtGdiGetDIBitsInternal\n");
970
971 return Result;
972 }
973
974 INT
975 APIENTRY
976 NtGdiStretchDIBitsInternal(
977 HDC hDC,
978 INT XDest,
979 INT YDest,
980 INT DestWidth,
981 INT DestHeight,
982 INT XSrc,
983 INT YSrc,
984 INT SrcWidth,
985 INT SrcHeight,
986 LPBYTE Bits,
987 LPBITMAPINFO BitsInfo,
988 DWORD Usage,
989 DWORD ROP,
990 UINT cjMaxInfo,
991 UINT cjMaxBits,
992 HANDLE hcmXform)
993 {
994 HBITMAP hBitmap, hOldBitmap = NULL;
995 HDC hdcMem;
996 HPALETTE hPal = NULL;
997 PDC pDC;
998 BOOL Hit = FALSE;
999
1000 if (!Bits || !BitsInfo)
1001 {
1002 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1003 return 0;
1004 }
1005
1006 _SEH2_TRY
1007 {
1008 ProbeForRead(BitsInfo, cjMaxInfo, 1);
1009 ProbeForRead(Bits, cjMaxBits, 1);
1010 }
1011 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1012 {
1013 Hit = TRUE;
1014 }
1015 _SEH2_END
1016
1017 if (Hit)
1018 {
1019 DPRINT1("NtGdiStretchDIBitsInternal fail to read BitMapInfo: %x or Bits: %x\n",BitsInfo,Bits);
1020 return 0;
1021 }
1022
1023 hdcMem = NtGdiCreateCompatibleDC(hDC);
1024 if (hdcMem == NULL)
1025 {
1026 DPRINT1("NtGdiCreateCompatibleDC fail create hdc\n");
1027 return 0;
1028 }
1029
1030 hBitmap = NtGdiCreateCompatibleBitmap(hDC,
1031 abs(BitsInfo->bmiHeader.biWidth),
1032 abs(BitsInfo->bmiHeader.biHeight));
1033 if (hBitmap == NULL)
1034 {
1035 DPRINT1("NtGdiCreateCompatibleBitmap fail create bitmap\n");
1036 DPRINT1("hDC : 0x%08x \n", hDC);
1037 DPRINT1("BitsInfo->bmiHeader.biWidth : 0x%08x \n", BitsInfo->bmiHeader.biWidth);
1038 DPRINT1("BitsInfo->bmiHeader.biHeight : 0x%08x \n", BitsInfo->bmiHeader.biHeight);
1039 return 0;
1040 }
1041
1042 /* Select the bitmap into hdcMem, and save a handle to the old bitmap */
1043 hOldBitmap = NtGdiSelectBitmap(hdcMem, hBitmap);
1044
1045 if (Usage == DIB_PAL_COLORS)
1046 {
1047 hPal = NtGdiGetDCObject(hDC, GDI_OBJECT_TYPE_PALETTE);
1048 hPal = GdiSelectPalette(hdcMem, hPal, FALSE);
1049 }
1050
1051 if (BitsInfo->bmiHeader.biCompression == BI_RLE4 ||
1052 BitsInfo->bmiHeader.biCompression == BI_RLE8)
1053 {
1054 /* copy existing bitmap from destination dc */
1055 if (SrcWidth == DestWidth && SrcHeight == DestHeight)
1056 NtGdiBitBlt(hdcMem, XSrc, abs(BitsInfo->bmiHeader.biHeight) - SrcHeight - YSrc,
1057 SrcWidth, SrcHeight, hDC, XDest, YDest, ROP, 0, 0);
1058 else
1059 NtGdiStretchBlt(hdcMem, XSrc, abs(BitsInfo->bmiHeader.biHeight) - SrcHeight - YSrc,
1060 SrcWidth, SrcHeight, hDC, XDest, YDest, DestWidth, DestHeight,
1061 ROP, 0);
1062 }
1063
1064 pDC = DC_LockDc(hdcMem);
1065 if (pDC != NULL)
1066 {
1067 /* Note BitsInfo->bmiHeader.biHeight is the number of scanline,
1068 * if it negitve we getting to many scanline for scanline is UINT not
1069 * a INT, so we need make the negtive value to positve and that make the
1070 * count correct for negtive bitmap, TODO : we need testcase for this api */
1071 IntSetDIBits(pDC, hBitmap, 0, abs(BitsInfo->bmiHeader.biHeight), Bits,
1072 BitsInfo, Usage);
1073
1074 DC_UnlockDc(pDC);
1075 }
1076
1077
1078 /* Origin for DIBitmap may be bottom left (positive biHeight) or top
1079 left (negative biHeight) */
1080 if (SrcWidth == DestWidth && SrcHeight == DestHeight)
1081 NtGdiBitBlt(hDC, XDest, YDest, DestWidth, DestHeight,
1082 hdcMem, XSrc, abs(BitsInfo->bmiHeader.biHeight) - SrcHeight - YSrc,
1083 ROP, 0, 0);
1084 else
1085 NtGdiStretchBlt(hDC, XDest, YDest, DestWidth, DestHeight,
1086 hdcMem, XSrc, abs(BitsInfo->bmiHeader.biHeight) - SrcHeight - YSrc,
1087 SrcWidth, SrcHeight, ROP, 0);
1088
1089 /* cleanup */
1090 if (hPal)
1091 GdiSelectPalette(hdcMem, hPal, FALSE);
1092
1093 if (hOldBitmap)
1094 NtGdiSelectBitmap(hdcMem, hOldBitmap);
1095
1096 NtGdiDeleteObjectApp(hdcMem);
1097
1098 GreDeleteObject(hBitmap);
1099
1100 return SrcHeight;
1101 }
1102
1103
1104 HBITMAP
1105 FASTCALL
1106 IntCreateDIBitmap(
1107 PDC Dc,
1108 INT width,
1109 INT height,
1110 UINT bpp,
1111 DWORD init,
1112 LPBYTE bits,
1113 PBITMAPINFO data,
1114 DWORD coloruse)
1115 {
1116 HBITMAP handle;
1117 BOOL fColor;
1118
1119 // Check if we should create a monochrome or color bitmap. We create a monochrome bitmap only if it has exactly 2
1120 // colors, which are black followed by white, nothing else. In all other cases, we create a color bitmap.
1121
1122 if (bpp != 1) fColor = TRUE;
1123 else if ((coloruse != DIB_RGB_COLORS) || (init != CBM_INIT) || !data) fColor = FALSE;
1124 else
1125 {
1126 if (data->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))
1127 {
1128 const RGBQUAD *rgb = data->bmiColors;
1129 DWORD col = RGB(rgb->rgbRed, rgb->rgbGreen, rgb->rgbBlue);
1130
1131 // Check if the first color of the colormap is black
1132 if ((col == RGB(0, 0, 0)))
1133 {
1134 rgb++;
1135 col = RGB(rgb->rgbRed, rgb->rgbGreen, rgb->rgbBlue);
1136
1137 // If the second color is white, create a monochrome bitmap
1138 fColor = (col != RGB(0xff,0xff,0xff));
1139 }
1140 else fColor = TRUE;
1141 }
1142 else if (data->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
1143 {
1144 RGBTRIPLE *rgb = ((BITMAPCOREINFO *)data)->bmciColors;
1145 DWORD col = RGB(rgb->rgbtRed, rgb->rgbtGreen, rgb->rgbtBlue);
1146
1147 if ((col == RGB(0,0,0)))
1148 {
1149 rgb++;
1150 col = RGB(rgb->rgbtRed, rgb->rgbtGreen, rgb->rgbtBlue);
1151 fColor = (col != RGB(0xff,0xff,0xff));
1152 }
1153 else fColor = TRUE;
1154 }
1155 else
1156 {
1157 DPRINT("(%ld): wrong size for data\n", data->bmiHeader.biSize);
1158 return 0;
1159 }
1160 }
1161
1162 // Now create the bitmap
1163 if (fColor)
1164 {
1165 handle = IntCreateCompatibleBitmap(Dc, width, height);
1166 }
1167 else
1168 {
1169 handle = IntGdiCreateBitmap(width,
1170 height,
1171 1,
1172 1,
1173 NULL);
1174 }
1175
1176 if (height < 0)
1177 height = -height;
1178
1179 if (NULL != handle && CBM_INIT == init)
1180 {
1181 IntSetDIBits(Dc, handle, 0, height, bits, data, coloruse);
1182 }
1183
1184 return handle;
1185 }
1186
1187 // The CreateDIBitmap function creates a device-dependent bitmap (DDB) from a DIB and, optionally, sets the bitmap bits
1188 // The DDB that is created will be whatever bit depth your reference DC is
1189 HBITMAP
1190 APIENTRY
1191 NtGdiCreateDIBitmapInternal(
1192 IN HDC hDc,
1193 IN INT cx,
1194 IN INT cy,
1195 IN DWORD fInit,
1196 IN OPTIONAL LPBYTE pjInit,
1197 IN OPTIONAL LPBITMAPINFO pbmi,
1198 IN DWORD iUsage,
1199 IN UINT cjMaxInitInfo,
1200 IN UINT cjMaxBits,
1201 IN FLONG fl,
1202 IN HANDLE hcmXform)
1203 {
1204 PDC Dc;
1205 HBITMAP Bmp;
1206 UINT bpp;
1207
1208 if (!hDc) // CreateBitmap
1209 { // Should use System Bitmap DC hSystemBM, with CreateCompatibleDC for this.
1210 hDc = IntGdiCreateDC(NULL, NULL, NULL, NULL,FALSE);
1211 if (!hDc)
1212 {
1213 SetLastWin32Error(ERROR_INVALID_HANDLE);
1214 return NULL;
1215 }
1216
1217 Dc = DC_LockDc(hDc);
1218 if (!Dc)
1219 {
1220 NtGdiDeleteObjectApp(hDc);
1221 SetLastWin32Error(ERROR_INVALID_HANDLE);
1222 return NULL;
1223 }
1224 bpp = 1;
1225 Bmp = IntCreateDIBitmap(Dc, cx, cy, bpp, fInit, pjInit, pbmi, iUsage);
1226
1227 DC_UnlockDc(Dc);
1228 NtGdiDeleteObjectApp(hDc);
1229 }
1230 else // CreateCompatibleBitmap
1231 {
1232 Dc = DC_LockDc(hDc);
1233 if (!Dc)
1234 {
1235 SetLastWin32Error(ERROR_INVALID_HANDLE);
1236 return NULL;
1237 }
1238 /* pbmi == null
1239 First create an un-initialised bitmap. The depth of the bitmap
1240 should match that of the hdc and not that supplied in bmih.
1241 */
1242 if (pbmi)
1243 bpp = pbmi->bmiHeader.biBitCount;
1244 else
1245 {
1246 if (Dc->dctype != DC_TYPE_MEMORY)
1247 bpp = IntGdiGetDeviceCaps(Dc, BITSPIXEL);
1248 else
1249 {
1250 DIBSECTION dibs;
1251 INT Count;
1252 SURFACE *psurf = Dc->dclevel.pSurface;
1253 Count = BITMAP_GetObject(psurf, sizeof(dibs), &dibs);
1254 if (!Count)
1255 bpp = 1;
1256 else
1257 {
1258 if (Count == sizeof(BITMAP))
1259 /* A device-dependent bitmap is selected in the DC */
1260 bpp = dibs.dsBm.bmBitsPixel;
1261 else
1262 /* A DIB section is selected in the DC */
1263 bpp = dibs.dsBmih.biBitCount;
1264 }
1265 }
1266 }
1267 Bmp = IntCreateDIBitmap(Dc, cx, cy, bpp, fInit, pjInit, pbmi, iUsage);
1268 DC_UnlockDc(Dc);
1269 }
1270 return Bmp;
1271 }
1272
1273
1274 HBITMAP
1275 APIENTRY
1276 NtGdiCreateDIBSection(
1277 IN HDC hDC,
1278 IN OPTIONAL HANDLE hSection,
1279 IN DWORD dwOffset,
1280 IN LPBITMAPINFO bmi,
1281 IN DWORD Usage,
1282 IN UINT cjHeader,
1283 IN FLONG fl,
1284 IN ULONG_PTR dwColorSpace,
1285 OUT PVOID *Bits)
1286 {
1287 HBITMAP hbitmap = 0;
1288 DC *dc;
1289 BOOL bDesktopDC = FALSE;
1290
1291 if (!bmi) return hbitmap; // Make sure.
1292
1293 // If the reference hdc is null, take the desktop dc
1294 if (hDC == 0)
1295 {
1296 hDC = NtGdiCreateCompatibleDC(0);
1297 bDesktopDC = TRUE;
1298 }
1299
1300 if ((dc = DC_LockDc(hDC)))
1301 {
1302 hbitmap = DIB_CreateDIBSection(dc,
1303 (BITMAPINFO*)bmi,
1304 Usage,
1305 Bits,
1306 hSection,
1307 dwOffset,
1308 0);
1309 DC_UnlockDc(dc);
1310 }
1311 else
1312 {
1313 SetLastWin32Error(ERROR_INVALID_HANDLE);
1314 }
1315
1316 if (bDesktopDC)
1317 NtGdiDeleteObjectApp(hDC);
1318
1319 return hbitmap;
1320 }
1321
1322 HBITMAP
1323 APIENTRY
1324 DIB_CreateDIBSection(
1325 PDC dc,
1326 BITMAPINFO *bmi,
1327 UINT usage,
1328 LPVOID *bits,
1329 HANDLE section,
1330 DWORD offset,
1331 DWORD ovr_pitch)
1332 {
1333 HBITMAP res = 0;
1334 SURFACE *bmp = NULL;
1335 void *mapBits = NULL;
1336 PDC_ATTR pdcattr;
1337
1338 // Fill BITMAP32 structure with DIB data
1339 BITMAPINFOHEADER *bi = &bmi->bmiHeader;
1340 INT effHeight;
1341 ULONG totalSize;
1342 BITMAP bm;
1343 SIZEL Size;
1344 RGBQUAD *lpRGB;
1345 HANDLE hSecure;
1346 DWORD dsBitfields[3] = {0};
1347
1348 DPRINT("format (%ld,%ld), planes %d, bpp %d, size %ld, colors %ld (%s)\n",
1349 bi->biWidth, bi->biHeight, bi->biPlanes, bi->biBitCount,
1350 bi->biSizeImage, bi->biClrUsed, usage == DIB_PAL_COLORS? "PAL" : "RGB");
1351
1352 /* CreateDIBSection should fail for compressed formats */
1353 if (bi->biCompression == BI_RLE4 || bi->biCompression == BI_RLE8)
1354 {
1355 return (HBITMAP)NULL;
1356 }
1357
1358 pdcattr = dc->pdcattr;
1359
1360 effHeight = bi->biHeight >= 0 ? bi->biHeight : -bi->biHeight;
1361 bm.bmType = 0;
1362 bm.bmWidth = bi->biWidth;
1363 bm.bmHeight = effHeight;
1364 bm.bmWidthBytes = ovr_pitch ? ovr_pitch : (ULONG) DIB_GetDIBWidthBytes(bm.bmWidth, bi->biBitCount);
1365
1366 bm.bmPlanes = bi->biPlanes;
1367 bm.bmBitsPixel = bi->biBitCount;
1368 bm.bmBits = NULL;
1369
1370 // Get storage location for DIB bits. Only use biSizeImage if it's valid and
1371 // we're dealing with a compressed bitmap. Otherwise, use width * height.
1372 totalSize = bi->biSizeImage && bi->biCompression != BI_RGB
1373 ? bi->biSizeImage : (ULONG)(bm.bmWidthBytes * effHeight);
1374
1375 if (section)
1376 {
1377 SYSTEM_BASIC_INFORMATION Sbi;
1378 NTSTATUS Status;
1379 DWORD mapOffset;
1380 LARGE_INTEGER SectionOffset;
1381 SIZE_T mapSize;
1382
1383 Status = ZwQuerySystemInformation(SystemBasicInformation,
1384 &Sbi,
1385 sizeof Sbi,
1386 0);
1387 if (!NT_SUCCESS(Status))
1388 {
1389 return NULL;
1390 }
1391
1392 mapOffset = offset - (offset % Sbi.AllocationGranularity);
1393 mapSize = bi->biSizeImage + (offset - mapOffset);
1394
1395 SectionOffset.LowPart = mapOffset;
1396 SectionOffset.HighPart = 0;
1397
1398 Status = ZwMapViewOfSection(section,
1399 NtCurrentProcess(),
1400 &mapBits,
1401 0,
1402 0,
1403 &SectionOffset,
1404 &mapSize,
1405 ViewShare,
1406 0,
1407 PAGE_READWRITE);
1408 if (!NT_SUCCESS(Status))
1409 {
1410 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1411 return NULL;
1412 }
1413
1414 if (mapBits) bm.bmBits = (char *)mapBits + (offset - mapOffset);
1415 }
1416 else if (ovr_pitch && offset)
1417 bm.bmBits = (LPVOID) offset;
1418 else
1419 {
1420 offset = 0;
1421 bm.bmBits = EngAllocUserMem(totalSize, 0);
1422 }
1423
1424 // hSecure = MmSecureVirtualMemory(bm.bmBits, totalSize, PAGE_READWRITE);
1425 hSecure = (HANDLE)0x1; // HACK OF UNIMPLEMENTED KERNEL STUFF !!!!
1426
1427 if (usage == DIB_PAL_COLORS)
1428 lpRGB = DIB_MapPaletteColors(dc, bmi);
1429 else
1430 lpRGB = bmi->bmiColors;
1431
1432 /* Set dsBitfields values */
1433 if (usage == DIB_PAL_COLORS || bi->biBitCount <= 8)
1434 {
1435 dsBitfields[0] = dsBitfields[1] = dsBitfields[2] = 0;
1436 }
1437 else if (bi->biCompression == BI_RGB)
1438 {
1439 switch (bi->biBitCount)
1440 {
1441 case 15:
1442 case 16:
1443 dsBitfields[0] = (bi->biCompression == BI_BITFIELDS) ? *(DWORD *)lpRGB : 0x7c00;
1444 dsBitfields[1] = (bi->biCompression == BI_BITFIELDS) ? *((DWORD *)lpRGB + 1) : 0x03e0;
1445 dsBitfields[2] = (bi->biCompression == BI_BITFIELDS) ? *((DWORD *)lpRGB + 2) : 0x001f;
1446 break;
1447
1448 case 24:
1449 case 32:
1450 dsBitfields[0] = (bi->biCompression == BI_BITFIELDS) ? *(DWORD *)lpRGB : 0xff0000;
1451 dsBitfields[1] = (bi->biCompression == BI_BITFIELDS) ? *((DWORD *)lpRGB + 1) : 0x00ff00;
1452 dsBitfields[2] = (bi->biCompression == BI_BITFIELDS) ? *((DWORD *)lpRGB + 2) : 0x0000ff;
1453 break;
1454 }
1455 }
1456 else
1457 {
1458 dsBitfields[0] = ((DWORD*)bmi->bmiColors)[0];
1459 dsBitfields[1] = ((DWORD*)bmi->bmiColors)[1];
1460 dsBitfields[2] = ((DWORD*)bmi->bmiColors)[2];
1461 }
1462
1463 // Create Device Dependent Bitmap and add DIB pointer
1464 Size.cx = bm.bmWidth;
1465 Size.cy = abs(bm.bmHeight);
1466 res = IntCreateBitmap(Size,
1467 bm.bmWidthBytes,
1468 BitmapFormat(bi->biBitCount * bi->biPlanes, bi->biCompression),
1469 BMF_DONTCACHE | BMF_USERMEM | BMF_NOZEROINIT |
1470 (bi->biHeight < 0 ? BMF_TOPDOWN : 0),
1471 bm.bmBits);
1472 if (!res)
1473 {
1474 if (lpRGB != bmi->bmiColors)
1475 {
1476 ExFreePoolWithTag(lpRGB, TAG_COLORMAP);
1477 }
1478 SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
1479 return NULL;
1480 }
1481 bmp = SURFACE_LockSurface(res);
1482 if (NULL == bmp)
1483 {
1484 if (lpRGB != bmi->bmiColors)
1485 {
1486 ExFreePoolWithTag(lpRGB, TAG_COLORMAP);
1487 }
1488 SetLastWin32Error(ERROR_INVALID_HANDLE);
1489 GreDeleteObject(bmp);
1490 return NULL;
1491 }
1492
1493 /* WINE NOTE: WINE makes use of a colormap, which is a color translation
1494 table between the DIB and the X physical device. Obviously,
1495 this is left out of the ReactOS implementation. Instead,
1496 we call NtGdiSetDIBColorTable. */
1497 bi->biClrUsed = 0;
1498 /* set number of entries in bmi.bmiColors table */
1499 if (bi->biBitCount == 1) {
1500 bi->biClrUsed = 2;
1501 } else
1502 if (bi->biBitCount == 4) {
1503 bi->biClrUsed = 16;
1504 } else
1505 if (bi->biBitCount == 8) {
1506 bi->biClrUsed = 256;
1507 }
1508
1509 bmp->hDIBSection = section;
1510 bmp->hSecure = hSecure;
1511 bmp->dwOffset = offset;
1512 bmp->flFlags = BITMAPOBJ_IS_APIBITMAP;
1513 bmp->dsBitfields[0] = dsBitfields[0];
1514 bmp->dsBitfields[1] = dsBitfields[1];
1515 bmp->dsBitfields[2] = dsBitfields[2];
1516 bmp->biClrUsed = bi->biClrUsed;
1517 bmp->biClrImportant = bi->biClrImportant;
1518
1519 if (bi->biClrUsed != 0)
1520 bmp->hDIBPalette = PALETTE_AllocPaletteIndexedRGB(bi->biClrUsed, lpRGB);
1521 else
1522 bmp->hDIBPalette = PALETTE_AllocPalette(PAL_BITFIELDS, 0, NULL,
1523 dsBitfields[0],
1524 dsBitfields[1],
1525 dsBitfields[2]);
1526
1527 // Clean up in case of errors
1528 if (!res || !bmp || !bm.bmBits)
1529 {
1530 DPRINT("got an error res=%08x, bmp=%p, bm.bmBits=%p\n", res, bmp, bm.bmBits);
1531 if (bm.bmBits)
1532 {
1533 // MmUnsecureVirtualMemory(hSecure); // FIXME: Implement this!
1534 if (section)
1535 {
1536 ZwUnmapViewOfSection(NtCurrentProcess(), mapBits);
1537 bm.bmBits = NULL;
1538 }
1539 else
1540 if (!offset)
1541 EngFreeUserMem(bm.bmBits), bm.bmBits = NULL;
1542 }
1543
1544 if (bmp)
1545 bmp = NULL;
1546
1547 if (res)
1548 {
1549 SURFACE_FreeSurfaceByHandle(res);
1550 res = 0;
1551 }
1552 }
1553
1554 if (lpRGB != bmi->bmiColors)
1555 {
1556 ExFreePoolWithTag(lpRGB, TAG_COLORMAP);
1557 }
1558
1559 if (bmp)
1560 {
1561 SURFACE_UnlockSurface(bmp);
1562 }
1563
1564 // Return BITMAP handle and storage location
1565 if (NULL != bm.bmBits && NULL != bits)
1566 {
1567 *bits = bm.bmBits;
1568 }
1569
1570 if (res) pdcattr->ulDirty_ |= DC_DIBSECTION;
1571
1572 return res;
1573 }
1574
1575 /***********************************************************************
1576 * DIB_GetDIBWidthBytes
1577 *
1578 * Return the width of a DIB bitmap in bytes. DIB bitmap data is 32-bit aligned.
1579 * http://www.microsoft.com/msdn/sdk/platforms/doc/sdk/win32/struc/src/str01.htm
1580 * 11/16/1999 (RJJ) lifted from wine
1581 */
1582 INT FASTCALL DIB_GetDIBWidthBytes(INT width, INT depth)
1583 {
1584 return ((width * depth + 31) & ~31) >> 3;
1585 }
1586
1587 /***********************************************************************
1588 * DIB_GetDIBImageBytes
1589 *
1590 * Return the number of bytes used to hold the image in a DIB bitmap.
1591 * 11/16/1999 (RJJ) lifted from wine
1592 */
1593
1594 INT APIENTRY DIB_GetDIBImageBytes(INT width, INT height, INT depth)
1595 {
1596 return DIB_GetDIBWidthBytes(width, depth) * (height < 0 ? -height : height);
1597 }
1598
1599 /***********************************************************************
1600 * DIB_BitmapInfoSize
1601 *
1602 * Return the size of the bitmap info structure including color table.
1603 * 11/16/1999 (RJJ) lifted from wine
1604 */
1605
1606 INT FASTCALL DIB_BitmapInfoSize(const BITMAPINFO * info, WORD coloruse)
1607 {
1608 int colors;
1609
1610 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
1611 {
1612 BITMAPCOREHEADER *core = (BITMAPCOREHEADER *)info;
1613 colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
1614 return sizeof(BITMAPCOREHEADER) + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
1615 }
1616 else /* assume BITMAPINFOHEADER */
1617 {
1618 colors = info->bmiHeader.biClrUsed;
1619 if (!colors && (info->bmiHeader.biBitCount <= 8)) colors = 1 << info->bmiHeader.biBitCount;
1620 return sizeof(BITMAPINFOHEADER) + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
1621 }
1622 }
1623
1624 RGBQUAD *
1625 FASTCALL
1626 DIB_MapPaletteColors(PDC dc, CONST BITMAPINFO* lpbmi)
1627 {
1628 RGBQUAD *lpRGB;
1629 ULONG nNumColors,i;
1630 USHORT *lpIndex;
1631 PPALETTE palGDI;
1632
1633 palGDI = PALETTE_LockPalette(dc->dclevel.hpal);
1634
1635 if (NULL == palGDI)
1636 {
1637 return NULL;
1638 }
1639
1640 if (palGDI->Mode != PAL_INDEXED)
1641 {
1642 PALETTE_UnlockPalette(palGDI);
1643 return NULL;
1644 }
1645
1646 nNumColors = 1 << lpbmi->bmiHeader.biBitCount;
1647 if (lpbmi->bmiHeader.biClrUsed)
1648 {
1649 nNumColors = min(nNumColors, lpbmi->bmiHeader.biClrUsed);
1650 }
1651
1652 lpRGB = (RGBQUAD *)ExAllocatePoolWithTag(PagedPool, sizeof(RGBQUAD) * nNumColors, TAG_COLORMAP);
1653 if (lpRGB == NULL)
1654 {
1655 PALETTE_UnlockPalette(palGDI);
1656 return NULL;
1657 }
1658
1659 lpIndex = (USHORT *)&lpbmi->bmiColors[0];
1660
1661 for (i = 0; i < nNumColors; i++)
1662 {
1663 lpRGB[i].rgbRed = palGDI->IndexedColors[*lpIndex].peRed;
1664 lpRGB[i].rgbGreen = palGDI->IndexedColors[*lpIndex].peGreen;
1665 lpRGB[i].rgbBlue = palGDI->IndexedColors[*lpIndex].peBlue;
1666 lpRGB[i].rgbReserved = 0;
1667 lpIndex++;
1668 }
1669 PALETTE_UnlockPalette(palGDI);
1670
1671 return lpRGB;
1672 }
1673
1674 HPALETTE
1675 FASTCALL
1676 BuildDIBPalette(CONST BITMAPINFO *bmi, PINT paletteType)
1677 {
1678 BYTE bits;
1679 ULONG ColorCount;
1680 PALETTEENTRY *palEntries = NULL;
1681 HPALETTE hPal;
1682 ULONG RedMask, GreenMask, BlueMask;
1683
1684 // Determine Bits Per Pixel
1685 bits = bmi->bmiHeader.biBitCount;
1686
1687 // Determine paletteType from Bits Per Pixel
1688 if (bits <= 8)
1689 {
1690 *paletteType = PAL_INDEXED;
1691 RedMask = GreenMask = BlueMask = 0;
1692 }
1693 else if (bmi->bmiHeader.biCompression == BI_BITFIELDS)
1694 {
1695 *paletteType = PAL_BITFIELDS;
1696 RedMask = ((ULONG *)bmi->bmiColors)[0];
1697 GreenMask = ((ULONG *)bmi->bmiColors)[1];
1698 BlueMask = ((ULONG *)bmi->bmiColors)[2];
1699 }
1700 else if (bits < 24)
1701 {
1702 *paletteType = PAL_BITFIELDS;
1703 RedMask = 0x7c00;
1704 GreenMask = 0x03e0;
1705 BlueMask = 0x001f;
1706 }
1707 else
1708 {
1709 *paletteType = PAL_BGR;
1710 RedMask = 0xff0000;
1711 GreenMask = 0x00ff00;
1712 BlueMask = 0x0000ff;
1713 }
1714
1715 if (bmi->bmiHeader.biClrUsed == 0)
1716 {
1717 ColorCount = 1 << bmi->bmiHeader.biBitCount;
1718 }
1719 else
1720 {
1721 ColorCount = bmi->bmiHeader.biClrUsed;
1722 }
1723
1724 if (PAL_INDEXED == *paletteType)
1725 {
1726 hPal = PALETTE_AllocPaletteIndexedRGB(ColorCount, (RGBQUAD*)bmi->bmiColors);
1727 }
1728 else
1729 {
1730 hPal = PALETTE_AllocPalette(*paletteType, ColorCount,
1731 (ULONG*) palEntries,
1732 RedMask, GreenMask, BlueMask);
1733 }
1734
1735 return hPal;
1736 }
1737
1738 /* EOF */