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