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