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