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