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