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