[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 /* 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 _SEH2_TRY
1047 {
1048 ProbeForRead(BitsInfo, cjMaxInfo, 1);
1049 ProbeForRead(Bits, cjMaxBits, 1);
1050 if (DIB_GetBitmapInfo(&BitsInfo->bmiHeader, &width, &height, &planes, &bpp, &compr, &size) == -1)
1051 {
1052 DPRINT1("Invalid bitmap\n");
1053 _SEH2_YIELD(goto cleanup;)
1054 }
1055 RtlCopyMemory(safeBits, Bits, cjMaxBits);
1056 }
1057 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1058 {
1059 DPRINT1("Error, failed to read the DIB bits\n");
1060 _SEH2_YIELD(goto cleanup;)
1061 }
1062 _SEH2_END
1063
1064 if (width < 0)
1065 {
1066 DPRINT1("Bitmap has a negative width\n");
1067 return 0;
1068 }
1069
1070 hBitmap = NtGdiGetDCObject(hDC, OBJ_BITMAP);
1071
1072 if (!(pdc = DC_LockDc(hDC)))
1073 {
1074 ExFreePoolWithTag(safeBits, TAG_DIB);
1075 EngSetLastError(ERROR_INVALID_HANDLE);
1076 return 0;
1077 }
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 DC_UnlockDc(pdc);
1095 goto cleanup;
1096 }
1097 }
1098
1099 /* slow path - need to use StretchBlt */
1100
1101 hBitmap = DIB_CreateDIBSection(pdc, BitsInfo, Usage, &pvBits, NULL, 0, 0);
1102 DC_UnlockDc(pdc);
1103
1104 hdcMem = NtGdiCreateCompatibleDC(hDC);
1105 if(!hBitmap)
1106 {
1107 DPRINT1("Error, failed to create a DIB section\n");
1108 NtGdiDeleteObjectApp(hdcMem);
1109 goto cleanup;
1110 }
1111
1112 RtlCopyMemory(pvBits, safeBits, cjMaxBits);
1113 hOldBitmap = NtGdiSelectBitmap(hdcMem, hBitmap);
1114
1115 /* Origin for DIBitmap may be bottom left (positive biHeight) or top
1116 left (negative biHeight) */
1117 ret = NtGdiStretchBlt(hDC, XDest, YDest, DestWidth, DestHeight,
1118 hdcMem, XSrc, abs(height) - SrcHeight - YSrc,
1119 SrcWidth, SrcHeight, ROP, 0);
1120
1121 if(ret)
1122 ret = SrcHeight;
1123 NtGdiSelectBitmap(hdcMem, hOldBitmap);
1124 NtGdiDeleteObjectApp(hdcMem);
1125 GreDeleteObject(hBitmap);
1126
1127 cleanup:
1128 ExFreePoolWithTag(safeBits, TAG_DIB);
1129 return ret;
1130 }
1131
1132
1133 HBITMAP
1134 FASTCALL
1135 IntCreateDIBitmap(
1136 PDC Dc,
1137 INT width,
1138 INT height,
1139 UINT bpp,
1140 DWORD init,
1141 LPBYTE bits,
1142 PBITMAPINFO data,
1143 DWORD coloruse)
1144 {
1145 HBITMAP handle;
1146 BOOL fColor;
1147
1148 // Check if we should create a monochrome or color bitmap. We create a monochrome bitmap only if it has exactly 2
1149 // colors, which are black followed by white, nothing else. In all other cases, we create a color bitmap.
1150
1151 if (bpp != 1) fColor = TRUE;
1152 else if ((coloruse != DIB_RGB_COLORS) || (init != CBM_INIT) || !data) fColor = FALSE;
1153 else
1154 {
1155 const RGBQUAD *rgb = (RGBQUAD*)((PBYTE)data + data->bmiHeader.biSize);
1156 DWORD col = RGB(rgb->rgbRed, rgb->rgbGreen, rgb->rgbBlue);
1157
1158 // Check if the first color of the colormap is black
1159 if ((col == RGB(0, 0, 0)))
1160 {
1161 rgb++;
1162 col = RGB(rgb->rgbRed, rgb->rgbGreen, rgb->rgbBlue);
1163
1164 // If the second color is white, create a monochrome bitmap
1165 fColor = (col != RGB(0xff,0xff,0xff));
1166 }
1167 else fColor = TRUE;
1168 }
1169
1170 // Now create the bitmap
1171 if (fColor)
1172 {
1173 handle = IntCreateCompatibleBitmap(Dc, width, height);
1174 }
1175 else
1176 {
1177 handle = GreCreateBitmap(width,
1178 height,
1179 1,
1180 1,
1181 NULL);
1182 }
1183
1184 if (height < 0)
1185 height = -height;
1186
1187 if (NULL != handle && CBM_INIT == init)
1188 {
1189 IntSetDIBits(Dc, handle, 0, height, bits, data, coloruse);
1190 }
1191
1192 return handle;
1193 }
1194
1195 // The CreateDIBitmap function creates a device-dependent bitmap (DDB) from a DIB and, optionally, sets the bitmap bits
1196 // The DDB that is created will be whatever bit depth your reference DC is
1197 HBITMAP
1198 APIENTRY
1199 NtGdiCreateDIBitmapInternal(
1200 IN HDC hDc,
1201 IN INT cx,
1202 IN INT cy,
1203 IN DWORD fInit,
1204 IN OPTIONAL LPBYTE pjInit,
1205 IN OPTIONAL LPBITMAPINFO pbmi,
1206 IN DWORD iUsage,
1207 IN UINT cjMaxInitInfo,
1208 IN UINT cjMaxBits,
1209 IN FLONG fl,
1210 IN HANDLE hcmXform)
1211 {
1212 NTSTATUS Status = STATUS_SUCCESS;
1213 PBYTE safeBits = NULL;
1214 HBITMAP hbmResult = NULL;
1215
1216 if(pjInit && (fInit == CBM_INIT))
1217 {
1218 safeBits = ExAllocatePoolWithTag(PagedPool, cjMaxBits, TAG_DIB);
1219 if(!safeBits)
1220 {
1221 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
1222 return NULL;
1223 }
1224 }
1225
1226 _SEH2_TRY
1227 {
1228 if(pbmi) ProbeForRead(pbmi, cjMaxInitInfo, 1);
1229 if(pjInit && (fInit == CBM_INIT))
1230 {
1231 ProbeForRead(pjInit, cjMaxBits, 1);
1232 RtlCopyMemory(safeBits, pjInit, cjMaxBits);
1233 }
1234 }
1235 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1236 {
1237 Status = _SEH2_GetExceptionCode();
1238 }
1239 _SEH2_END
1240
1241 if(!NT_SUCCESS(Status))
1242 {
1243 SetLastNtError(Status);
1244 goto cleanup;
1245 }
1246
1247 hbmResult = GreCreateDIBitmapInternal(hDc,
1248 cx,
1249 cy,
1250 fInit,
1251 safeBits,
1252 pbmi,
1253 iUsage,
1254 fl,
1255 hcmXform);
1256
1257 cleanup:
1258 if (safeBits) ExFreePoolWithTag(safeBits, TAG_DIB);
1259 return hbmResult;
1260 }
1261
1262 HBITMAP
1263 FASTCALL
1264 GreCreateDIBitmapInternal(
1265 IN HDC hDc,
1266 IN INT cx,
1267 IN INT cy,
1268 IN DWORD fInit,
1269 IN OPTIONAL LPBYTE pjInit,
1270 IN OPTIONAL PBITMAPINFO pbmi,
1271 IN DWORD iUsage,
1272 IN FLONG fl,
1273 IN HANDLE hcmXform)
1274 {
1275 PDC Dc;
1276 HBITMAP Bmp;
1277 WORD bpp;
1278 HDC hdcDest;
1279
1280 if (!hDc) /* 1bpp monochrome bitmap */
1281 { // Should use System Bitmap DC hSystemBM, with CreateCompatibleDC for this.
1282 hdcDest = NtGdiCreateCompatibleDC(0);
1283 if(!hdcDest)
1284 {
1285 return NULL;
1286 }
1287 }
1288 else
1289 {
1290 hdcDest = hDc;
1291 }
1292
1293 Dc = DC_LockDc(hdcDest);
1294 if (!Dc)
1295 {
1296 EngSetLastError(ERROR_INVALID_HANDLE);
1297 return NULL;
1298 }
1299 /* It's OK to set bpp=0 here, as IntCreateDIBitmap will create a compatible Bitmap
1300 * if bpp != 1 and ignore the real value that was passed */
1301 if (pbmi)
1302 bpp = pbmi->bmiHeader.biBitCount;
1303 else
1304 bpp = 0;
1305 Bmp = IntCreateDIBitmap(Dc, cx, cy, bpp, fInit, pjInit, pbmi, iUsage);
1306 DC_UnlockDc(Dc);
1307
1308 if(!hDc)
1309 {
1310 NtGdiDeleteObjectApp(hdcDest);
1311 }
1312 return Bmp;
1313 }
1314
1315
1316 HBITMAP
1317 APIENTRY
1318 NtGdiCreateDIBSection(
1319 IN HDC hDC,
1320 IN OPTIONAL HANDLE hSection,
1321 IN DWORD dwOffset,
1322 IN BITMAPINFO* bmi,
1323 IN DWORD Usage,
1324 IN UINT cjHeader,
1325 IN FLONG fl,
1326 IN ULONG_PTR dwColorSpace,
1327 OUT PVOID *Bits)
1328 {
1329 HBITMAP hbitmap = 0;
1330 DC *dc;
1331 BOOL bDesktopDC = FALSE;
1332 NTSTATUS Status = STATUS_SUCCESS;
1333
1334 if (!bmi) return hbitmap; // Make sure.
1335
1336 _SEH2_TRY
1337 {
1338 ProbeForRead(&bmi->bmiHeader.biSize, sizeof(DWORD), 1);
1339 ProbeForRead(bmi, bmi->bmiHeader.biSize, 1);
1340 ProbeForRead(bmi, DIB_BitmapInfoSize(bmi, Usage), 1);
1341 }
1342 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1343 {
1344 Status = _SEH2_GetExceptionCode();
1345 }
1346 _SEH2_END
1347
1348 if(!NT_SUCCESS(Status))
1349 {
1350 SetLastNtError(Status);
1351 return NULL;
1352 }
1353
1354 // If the reference hdc is null, take the desktop dc
1355 if (hDC == 0)
1356 {
1357 hDC = NtGdiCreateCompatibleDC(0);
1358 bDesktopDC = TRUE;
1359 }
1360
1361 if ((dc = DC_LockDc(hDC)))
1362 {
1363 hbitmap = DIB_CreateDIBSection(dc,
1364 bmi,
1365 Usage,
1366 Bits,
1367 hSection,
1368 dwOffset,
1369 0);
1370 DC_UnlockDc(dc);
1371 }
1372 else
1373 {
1374 EngSetLastError(ERROR_INVALID_HANDLE);
1375 }
1376
1377 if (bDesktopDC)
1378 NtGdiDeleteObjectApp(hDC);
1379
1380 return hbitmap;
1381 }
1382
1383 HBITMAP
1384 APIENTRY
1385 DIB_CreateDIBSection(
1386 PDC dc,
1387 CONST BITMAPINFO *bmi,
1388 UINT usage,
1389 LPVOID *bits,
1390 HANDLE section,
1391 DWORD offset,
1392 DWORD ovr_pitch)
1393 {
1394 HBITMAP res = 0;
1395 SURFACE *bmp = NULL;
1396 void *mapBits = NULL;
1397 HPALETTE hpal ;
1398
1399 // Fill BITMAP32 structure with DIB data
1400 CONST BITMAPINFOHEADER *bi = &bmi->bmiHeader;
1401 INT effHeight;
1402 ULONG totalSize;
1403 BITMAP bm;
1404 SIZEL Size;
1405 HANDLE hSecure;
1406
1407 DPRINT("format (%ld,%ld), planes %d, bpp %d, size %ld, colors %ld (%s)\n",
1408 bi->biWidth, bi->biHeight, bi->biPlanes, bi->biBitCount,
1409 bi->biSizeImage, bi->biClrUsed, usage == DIB_PAL_COLORS? "PAL" : "RGB");
1410
1411 /* CreateDIBSection should fail for compressed formats */
1412 if (bi->biCompression == BI_RLE4 || bi->biCompression == BI_RLE8)
1413 {
1414 return (HBITMAP)NULL;
1415 }
1416
1417 effHeight = bi->biHeight >= 0 ? bi->biHeight : -bi->biHeight;
1418 bm.bmType = 0;
1419 bm.bmWidth = bi->biWidth;
1420 bm.bmHeight = effHeight;
1421 bm.bmWidthBytes = ovr_pitch ? ovr_pitch : WIDTH_BYTES_ALIGN32(bm.bmWidth, bi->biBitCount);
1422
1423 bm.bmPlanes = bi->biPlanes;
1424 bm.bmBitsPixel = bi->biBitCount;
1425 bm.bmBits = NULL;
1426
1427 // Get storage location for DIB bits. Only use biSizeImage if it's valid and
1428 // we're dealing with a compressed bitmap. Otherwise, use width * height.
1429 totalSize = bi->biSizeImage && bi->biCompression != BI_RGB && bi->biCompression != BI_BITFIELDS
1430 ? bi->biSizeImage : (ULONG)(bm.bmWidthBytes * effHeight);
1431
1432 if (section)
1433 {
1434 SYSTEM_BASIC_INFORMATION Sbi;
1435 NTSTATUS Status;
1436 DWORD mapOffset;
1437 LARGE_INTEGER SectionOffset;
1438 SIZE_T mapSize;
1439
1440 Status = ZwQuerySystemInformation(SystemBasicInformation,
1441 &Sbi,
1442 sizeof Sbi,
1443 0);
1444 if (!NT_SUCCESS(Status))
1445 {
1446 return NULL;
1447 }
1448
1449 mapOffset = offset - (offset % Sbi.AllocationGranularity);
1450 mapSize = bi->biSizeImage + (offset - mapOffset);
1451
1452 SectionOffset.LowPart = mapOffset;
1453 SectionOffset.HighPart = 0;
1454
1455 Status = ZwMapViewOfSection(section,
1456 NtCurrentProcess(),
1457 &mapBits,
1458 0,
1459 0,
1460 &SectionOffset,
1461 &mapSize,
1462 ViewShare,
1463 0,
1464 PAGE_READWRITE);
1465 if (!NT_SUCCESS(Status))
1466 {
1467 EngSetLastError(ERROR_INVALID_PARAMETER);
1468 return NULL;
1469 }
1470
1471 if (mapBits) bm.bmBits = (char *)mapBits + (offset - mapOffset);
1472 }
1473 else if (ovr_pitch && offset)
1474 bm.bmBits = (LPVOID) offset;
1475 else
1476 {
1477 offset = 0;
1478 bm.bmBits = EngAllocUserMem(totalSize, 0);
1479 if(!bm.bmBits) goto cleanup;
1480 }
1481
1482 // hSecure = MmSecureVirtualMemory(bm.bmBits, totalSize, PAGE_READWRITE);
1483 hSecure = (HANDLE)0x1; // HACK OF UNIMPLEMENTED KERNEL STUFF !!!!
1484
1485 if (usage == DIB_PAL_COLORS)
1486 {
1487 if(dc)
1488 {
1489 PPALETTE pdcPal ;
1490 pdcPal = PALETTE_LockPalette(dc->dclevel.hpal);
1491 hpal = DIB_MapPaletteColors(pdcPal, bmi);
1492 PALETTE_UnlockPalette(pdcPal);
1493 }
1494 else
1495 {
1496 /* For DIB Brushes */
1497 DPRINT1("FIXME : Unsupported DIB_PAL_COLORS without a DC to map colors.\n");
1498 /* HACK */
1499 hpal = (HPALETTE) 0xFFFFFFFF;
1500 }
1501 }
1502 else
1503 {
1504 hpal = BuildDIBPalette(bmi);
1505 }
1506
1507 if(!hpal)
1508 {
1509 DPRINT1("Error : Could not create a palette for the DIB.\n");
1510 goto cleanup;
1511 }
1512
1513 // Create Device Dependent Bitmap and add DIB pointer
1514 Size.cx = bm.bmWidth;
1515 Size.cy = abs(bm.bmHeight);
1516 res = GreCreateBitmapEx(bm.bmWidth,
1517 abs(bm.bmHeight),
1518 bm.bmWidthBytes,
1519 BitmapFormat(bi->biBitCount * bi->biPlanes, bi->biCompression),
1520 BMF_DONTCACHE | BMF_USERMEM | BMF_NOZEROINIT |
1521 (bi->biHeight < 0 ? BMF_TOPDOWN : 0),
1522 bi->biSizeImage,
1523 bm.bmBits,
1524 0);
1525 if (!res)
1526 {
1527 EngSetLastError(ERROR_NO_SYSTEM_RESOURCES);
1528 goto cleanup;
1529 }
1530 bmp = SURFACE_LockSurface(res);
1531 if (NULL == bmp)
1532 {
1533 EngSetLastError(ERROR_INVALID_HANDLE);
1534 goto cleanup;
1535 }
1536
1537 /* WINE NOTE: WINE makes use of a colormap, which is a color translation
1538 table between the DIB and the X physical device. Obviously,
1539 this is left out of the ReactOS implementation. Instead,
1540 we call NtGdiSetDIBColorTable. */
1541 bmp->hDIBSection = section;
1542 bmp->hSecure = hSecure;
1543 bmp->dwOffset = offset;
1544 bmp->flags = API_BITMAP;
1545 bmp->biClrImportant = bi->biClrImportant;
1546 bmp->SurfObj.fjBitmap &= ~BMF_DONT_FREE;
1547
1548 /* HACK */
1549 if(hpal != (HPALETTE)0xFFFFFFFF)
1550 {
1551 bmp->ppal = PALETTE_ShareLockPalette(hpal);
1552 /* Lazy delete hpal, it will be freed at surface release */
1553 GreDeleteObject(hpal);
1554 }
1555
1556 // Clean up in case of errors
1557 cleanup:
1558 if (!res || !bmp || !bm.bmBits)
1559 {
1560 DPRINT("got an error res=%08x, bmp=%p, bm.bmBits=%p\n", res, bmp, bm.bmBits);
1561 if (bm.bmBits)
1562 {
1563 // MmUnsecureVirtualMemory(hSecure); // FIXME: Implement this!
1564 if (section)
1565 {
1566 ZwUnmapViewOfSection(NtCurrentProcess(), mapBits);
1567 bm.bmBits = NULL;
1568 }
1569 else
1570 if (!offset)
1571 EngFreeUserMem(bm.bmBits), bm.bmBits = NULL;
1572 }
1573
1574 if (bmp)
1575 bmp = NULL;
1576
1577 if (res)
1578 {
1579 SURFACE_FreeSurfaceByHandle(res);
1580 res = 0;
1581 }
1582 }
1583
1584 if (bmp)
1585 {
1586 SURFACE_UnlockSurface(bmp);
1587 }
1588
1589 // Return BITMAP handle and storage location
1590 if (NULL != bm.bmBits && NULL != bits)
1591 {
1592 *bits = bm.bmBits;
1593 }
1594
1595 return res;
1596 }
1597
1598 /***********************************************************************
1599 * DIB_GetBitmapInfo
1600 *
1601 * Get the info from a bitmap header.
1602 * Return 0 for COREHEADER, 1 for INFOHEADER, -1 for error.
1603 */
1604 int
1605 FASTCALL
1606 DIB_GetBitmapInfo( const BITMAPINFOHEADER *header, LONG *width,
1607 LONG *height, WORD *planes, WORD *bpp, DWORD *compr, DWORD *size )
1608 {
1609 if (header->biSize == sizeof(BITMAPCOREHEADER))
1610 {
1611 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)header;
1612 *width = core->bcWidth;
1613 *height = core->bcHeight;
1614 *planes = core->bcPlanes;
1615 *bpp = core->bcBitCount;
1616 *compr = BI_RGB;
1617 *size = 0;
1618 return 0;
1619 }
1620 if (header->biSize >= sizeof(BITMAPINFOHEADER)) /* assume BITMAPINFOHEADER */
1621 {
1622 *width = header->biWidth;
1623 *height = header->biHeight;
1624 *planes = header->biPlanes;
1625 *bpp = header->biBitCount;
1626 *compr = header->biCompression;
1627 *size = header->biSizeImage;
1628 return 1;
1629 }
1630 DPRINT1("(%d): unknown/wrong size for header\n", header->biSize );
1631 return -1;
1632 }
1633
1634 /***********************************************************************
1635 * DIB_GetDIBImageBytes
1636 *
1637 * Return the number of bytes used to hold the image in a DIB bitmap.
1638 * 11/16/1999 (RJJ) lifted from wine
1639 */
1640
1641 INT APIENTRY DIB_GetDIBImageBytes(INT width, INT height, INT depth)
1642 {
1643 return WIDTH_BYTES_ALIGN32(width, depth) * (height < 0 ? -height : height);
1644 }
1645
1646 /***********************************************************************
1647 * DIB_BitmapInfoSize
1648 *
1649 * Return the size of the bitmap info structure including color table.
1650 * 11/16/1999 (RJJ) lifted from wine
1651 */
1652
1653 INT FASTCALL DIB_BitmapInfoSize(const BITMAPINFO * info, WORD coloruse)
1654 {
1655 unsigned int colors, size, masks = 0;
1656
1657 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
1658 {
1659 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
1660 colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
1661 return sizeof(BITMAPCOREHEADER) + colors *
1662 ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
1663 }
1664 else /* assume BITMAPINFOHEADER */
1665 {
1666 colors = info->bmiHeader.biClrUsed;
1667 if (colors > 256) colors = 256;
1668 if (!colors && (info->bmiHeader.biBitCount <= 8))
1669 colors = 1 << info->bmiHeader.biBitCount;
1670 if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3;
1671 size = max( info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD) );
1672 return size + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
1673 }
1674 }
1675
1676 HPALETTE
1677 FASTCALL
1678 DIB_MapPaletteColors(PPALETTE ppal, CONST BITMAPINFO* lpbmi)
1679 {
1680 PALETTEENTRY* ppalEntries;
1681 ULONG nNumColors,i;
1682 USHORT *lpIndex;
1683 HPALETTE hpal;
1684
1685 if (!(ppal->flFlags & PAL_INDEXED))
1686 {
1687 return NULL;
1688 }
1689
1690 nNumColors = 1 << lpbmi->bmiHeader.biBitCount;
1691 if (lpbmi->bmiHeader.biClrUsed)
1692 {
1693 nNumColors = min(nNumColors, lpbmi->bmiHeader.biClrUsed);
1694 }
1695
1696 /* Don't have more colors than we need */
1697 nNumColors = min(ppal->NumColors, nNumColors);
1698
1699 ppalEntries = ExAllocatePoolWithTag(PagedPool, sizeof(PALETTEENTRY) * nNumColors, TAG_COLORMAP);
1700 if (ppalEntries == NULL)
1701 {
1702 DPRINT1("Could not allocate palette entries\n");
1703 return NULL;
1704 }
1705
1706 lpIndex = (USHORT *)((PBYTE)lpbmi + lpbmi->bmiHeader.biSize);
1707
1708 for (i = 0; i < nNumColors; i++)
1709 {
1710 if (*lpIndex < ppal->NumColors)
1711 {
1712 ppalEntries[i] = ppal->IndexedColors[*lpIndex];
1713 }
1714 else
1715 {
1716 ppalEntries[i].peRed = 0;
1717 ppalEntries[i].peGreen = 0;
1718 ppalEntries[i].peBlue = 0;
1719 ppalEntries[i].peFlags = 0;
1720 }
1721
1722 lpIndex++;
1723 }
1724
1725 hpal = PALETTE_AllocPalette(PAL_INDEXED, nNumColors, (ULONG*)ppalEntries, 0, 0, 0);
1726
1727 ExFreePoolWithTag(ppalEntries, TAG_COLORMAP);
1728
1729 return hpal;
1730 }
1731
1732 HPALETTE
1733 FASTCALL
1734 BuildDIBPalette(CONST BITMAPINFO *bmi)
1735 {
1736 BYTE bits;
1737 ULONG ColorCount;
1738 HPALETTE hPal;
1739 ULONG RedMask = 0, GreenMask = 0, BlueMask = 0;
1740 PDWORD pdwColors = (PDWORD)((PBYTE)bmi + bmi->bmiHeader.biSize);
1741 INT paletteType;
1742
1743 // Determine Bits Per Pixel
1744 bits = bmi->bmiHeader.biBitCount;
1745
1746 // Determine paletteType from Bits Per Pixel
1747 if (bits <= 8)
1748 {
1749 paletteType = PAL_INDEXED;
1750 RedMask = GreenMask = BlueMask = 0;
1751 }
1752 else if (bmi->bmiHeader.biCompression == BI_BITFIELDS)
1753 {
1754 paletteType = PAL_BITFIELDS;
1755 if (bmi->bmiHeader.biSize >= sizeof(BITMAPV4HEADER))
1756 {
1757 PBITMAPV4HEADER pV4Header = (PBITMAPV4HEADER)&bmi->bmiHeader;
1758 RedMask = pV4Header->bV4RedMask;
1759 GreenMask = pV4Header->bV4GreenMask;
1760 BlueMask = pV4Header->bV4BlueMask;
1761 }
1762 else
1763 {
1764 RedMask = pdwColors[0];
1765 GreenMask = pdwColors[1];
1766 BlueMask = pdwColors[2];
1767 }
1768 }
1769 else
1770 {
1771 paletteType = PAL_BITFIELDS;
1772 switch (bits)
1773 {
1774 case 15:
1775 paletteType |= PAL_RGB16_555;
1776 RedMask = 0x7C00;
1777 GreenMask = 0x03E0;
1778 BlueMask = 0x001F;
1779 break;
1780
1781 case 16:
1782 paletteType |= PAL_RGB16_565;
1783 RedMask = 0xF800;
1784 GreenMask = 0x07E0;
1785 BlueMask = 0x001F;
1786 break;
1787
1788 case 24:
1789 case 32:
1790 paletteType |= PAL_BGR;
1791 RedMask = 0xFF0000;
1792 GreenMask = 0x00FF00;
1793 BlueMask = 0x0000FF;
1794 break;
1795 }
1796 }
1797
1798 if (bmi->bmiHeader.biClrUsed == 0)
1799 {
1800 ColorCount = 1 << bmi->bmiHeader.biBitCount;
1801 }
1802 else
1803 {
1804 ColorCount = bmi->bmiHeader.biClrUsed;
1805 }
1806
1807 if (PAL_INDEXED == paletteType)
1808 {
1809 hPal = PALETTE_AllocPaletteIndexedRGB(ColorCount, (RGBQUAD*)pdwColors);
1810 }
1811 else
1812 {
1813 hPal = PALETTE_AllocPalette(paletteType, 0,
1814 NULL,
1815 RedMask, GreenMask, BlueMask);
1816 }
1817
1818 return hPal;
1819 }
1820
1821 /* Converts a BITMAPCOREINFO to a BITMAPINFO structure,
1822 * or does nothing if it's already a BITMAPINFO (or V4 or V5) */
1823 BITMAPINFO*
1824 FASTCALL
1825 DIB_ConvertBitmapInfo (CONST BITMAPINFO* pbmi, DWORD Usage)
1826 {
1827 CONST BITMAPCOREINFO* pbmci = (BITMAPCOREINFO*)pbmi;
1828 BITMAPINFO* pNewBmi ;
1829 UINT numColors = 0, ColorsSize = 0;
1830
1831 if(pbmi->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER)) return (BITMAPINFO*)pbmi;
1832 if(pbmi->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) return NULL;
1833
1834 if(pbmci->bmciHeader.bcBitCount <= 8)
1835 {
1836 numColors = 1 << pbmci->bmciHeader.bcBitCount;
1837 if(Usage == DIB_PAL_COLORS)
1838 {
1839 ColorsSize = numColors * sizeof(WORD);
1840 }
1841 else
1842 {
1843 ColorsSize = numColors * sizeof(RGBQUAD);
1844 }
1845 }
1846 else if (Usage == DIB_PAL_COLORS)
1847 {
1848 /* Invalid at high Res */
1849 return NULL;
1850 }
1851
1852 pNewBmi = ExAllocatePoolWithTag(PagedPool, sizeof(BITMAPINFOHEADER) + ColorsSize, TAG_DIB);
1853 if(!pNewBmi) return NULL;
1854
1855 RtlZeroMemory(pNewBmi, sizeof(BITMAPINFOHEADER) + ColorsSize);
1856
1857 pNewBmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1858 pNewBmi->bmiHeader.biBitCount = pbmci->bmciHeader.bcBitCount;
1859 pNewBmi->bmiHeader.biWidth = pbmci->bmciHeader.bcWidth;
1860 pNewBmi->bmiHeader.biHeight = pbmci->bmciHeader.bcHeight;
1861 pNewBmi->bmiHeader.biPlanes = pbmci->bmciHeader.bcPlanes;
1862 pNewBmi->bmiHeader.biCompression = BI_RGB ;
1863 pNewBmi->bmiHeader.biSizeImage = DIB_GetDIBImageBytes(pNewBmi->bmiHeader.biWidth,
1864 pNewBmi->bmiHeader.biHeight,
1865 pNewBmi->bmiHeader.biBitCount);
1866
1867 if(Usage == DIB_PAL_COLORS)
1868 {
1869 RtlCopyMemory(pNewBmi->bmiColors, pbmci->bmciColors, ColorsSize);
1870 }
1871 else
1872 {
1873 UINT i;
1874 for(i=0; i<numColors; i++)
1875 {
1876 pNewBmi->bmiColors[i].rgbRed = pbmci->bmciColors[i].rgbtRed;
1877 pNewBmi->bmiColors[i].rgbGreen = pbmci->bmciColors[i].rgbtGreen;
1878 pNewBmi->bmiColors[i].rgbBlue = pbmci->bmciColors[i].rgbtBlue;
1879 }
1880 }
1881
1882 return pNewBmi ;
1883 }
1884
1885 /* Frees a BITMAPINFO created with DIB_ConvertBitmapInfo */
1886 VOID
1887 FASTCALL
1888 DIB_FreeConvertedBitmapInfo(BITMAPINFO* converted, BITMAPINFO* orig)
1889 {
1890 if(converted != orig)
1891 ExFreePoolWithTag(converted, TAG_DIB);
1892 }
1893
1894
1895
1896
1897
1898
1899 /* EOF */