[WIN32K]
[reactos.git] / 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 SetLastWin32Error(ERROR_INVALID_PARAMETER);
140 return 0;
141 }
142
143 if (psurf->hSecure == NULL)
144 {
145 DC_UnlockDc(dc);
146 SetLastWin32Error(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 SetLastWin32Error(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 SetLastWin32Error(ERROR_INVALID_PARAMETER);
212 return 0;
213 }
214
215 if (psurf->hSecure == NULL)
216 {
217 DC_UnlockDc(dc);
218 SetLastWin32Error(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 SetLastWin32Error(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 SetLastWin32Error(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 SetLastWin32Error(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 SetLastWin32Error(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 = DIB_GetDIBWidthBytes(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 SetLastWin32Error(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 SetLastWin32Error(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 SetLastWin32Error(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 SetLastWin32Error(ERROR_INVALID_PARAMETER);
628 return 0;
629 }
630 else if(bitmap_type == 0)
631 {
632 /* We need a BITMAPINFO to create a DIB, but we have to fill
633 * the BITMAPCOREINFO we're provided */
634 pbmci = (BITMAPCOREINFO*)Info;
635 Info = DIB_ConvertBitmapInfo((BITMAPINFO*)pbmci, Usage);
636 if(Info == NULL)
637 {
638 DPRINT1("Error, could not convert the BITMAPCOREINFO!\n");
639 return 0;
640 }
641 rgbQuads = Info->bmiColors;
642 }
643
644 pDC = DC_LockDc(hDC);
645 if (pDC == NULL || pDC->dctype == DC_TYPE_INFO)
646 {
647 ScanLines = 0;
648 goto done;
649 }
650
651 /* Get a pointer to the source bitmap object */
652 psurf = SURFACE_LockSurface(hBitmap);
653 if (psurf == NULL)
654 {
655 ScanLines = 0;
656 goto done;
657 }
658
659 /* Fill in the structure */
660 switch(bpp)
661 {
662 case 0: /* Only info */
663 if(pbmci)
664 {
665 pbmci->bmciHeader.bcWidth = psurf->SurfObj.sizlBitmap.cx;
666 pbmci->bmciHeader.bcHeight = (psurf->SurfObj.fjBitmap & BMF_TOPDOWN) ?
667 -psurf->SurfObj.sizlBitmap.cy :
668 psurf->SurfObj.sizlBitmap.cy;
669 pbmci->bmciHeader.bcPlanes = 1;
670 pbmci->bmciHeader.bcBitCount = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
671 }
672 Info->bmiHeader.biWidth = psurf->SurfObj.sizlBitmap.cx;
673 Info->bmiHeader.biHeight = (psurf->SurfObj.fjBitmap & BMF_TOPDOWN) ?
674 -psurf->SurfObj.sizlBitmap.cy :
675 psurf->SurfObj.sizlBitmap.cy;;
676 Info->bmiHeader.biPlanes = 1;
677 Info->bmiHeader.biBitCount = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
678 Info->bmiHeader.biSizeImage = DIB_GetDIBImageBytes( Info->bmiHeader.biWidth,
679 Info->bmiHeader.biHeight,
680 Info->bmiHeader.biBitCount);
681 if(psurf->hSecure)
682 {
683 switch(Info->bmiHeader.biBitCount)
684 {
685 case 16:
686 case 32:
687 Info->bmiHeader.biCompression = BI_BITFIELDS;
688 break;
689 default:
690 Info->bmiHeader.biCompression = BI_RGB;
691 break;
692 }
693 }
694 else if(Info->bmiHeader.biBitCount > 8)
695 {
696 Info->bmiHeader.biCompression = BI_BITFIELDS;
697 }
698 else
699 {
700 Info->bmiHeader.biCompression = BI_RGB;
701 }
702 Info->bmiHeader.biXPelsPerMeter = 0;
703 Info->bmiHeader.biYPelsPerMeter = 0;
704 Info->bmiHeader.biClrUsed = 0;
705 Info->bmiHeader.biClrImportant = 0;
706 ScanLines = abs(Info->bmiHeader.biHeight);
707 goto done;
708
709 case 1:
710 case 4:
711 case 8:
712 Info->bmiHeader.biClrUsed = 0;
713
714 /* If the bitmap if a DIB section and has the same format than what
715 * we're asked, go ahead! */
716 if((psurf->hSecure) &&
717 (BitsPerFormat(psurf->SurfObj.iBitmapFormat) == bpp))
718 {
719 if(Usage == DIB_RGB_COLORS)
720 {
721 unsigned int colors = min(psurf->ppal->NumColors, 1 << bpp);
722
723 if(pbmci)
724 {
725 for(i=0; i < colors; i++)
726 {
727 rgbTriples[i].rgbtRed = psurf->ppal->IndexedColors[i].peRed;
728 rgbTriples[i].rgbtGreen = psurf->ppal->IndexedColors[i].peGreen;
729 rgbTriples[i].rgbtBlue = psurf->ppal->IndexedColors[i].peBlue;
730 }
731 }
732 if(colors != 1 << bpp) Info->bmiHeader.biClrUsed = colors;
733 for(i=0; i < colors; i++)
734 {
735 rgbQuads[i].rgbRed = psurf->ppal->IndexedColors[i].peRed;
736 rgbQuads[i].rgbGreen = psurf->ppal->IndexedColors[i].peGreen;
737 rgbQuads[i].rgbBlue = psurf->ppal->IndexedColors[i].peBlue;
738 }
739 }
740 else
741 {
742 for(i=0; i < 1 << bpp; i++)
743 {
744 if(pbmci) ((WORD*)rgbTriples)[i] = i;
745 ((WORD*)rgbQuads)[i] = i;
746 }
747 }
748 }
749 else
750 {
751 if(Usage == DIB_PAL_COLORS)
752 {
753 for(i=0; i < 1 << bpp; i++)
754 {
755 if(pbmci) ((WORD*)rgbTriples)[i] = i;
756 ((WORD*)rgbQuads)[i] = i;
757 }
758 }
759 else if(bpp > 1 && bpp == BitsPerFormat(psurf->SurfObj.iBitmapFormat)) {
760 /* For color DDBs in native depth (mono DDBs always have
761 a black/white palette):
762 Generate the color map from the selected palette */
763 PPALETTE pDcPal = PALETTE_LockPalette(pDC->dclevel.hpal);
764 if(!pDcPal)
765 {
766 ScanLines = 0 ;
767 goto done ;
768 }
769 for (i = 0; i < pDcPal->NumColors; i++) {
770 if (pbmci)
771 {
772 rgbTriples[i].rgbtRed = pDcPal->IndexedColors[i].peRed;
773 rgbTriples[i].rgbtGreen = pDcPal->IndexedColors[i].peGreen;
774 rgbTriples[i].rgbtBlue = pDcPal->IndexedColors[i].peBlue;
775 }
776
777 rgbQuads[i].rgbRed = pDcPal->IndexedColors[i].peRed;
778 rgbQuads[i].rgbGreen = pDcPal->IndexedColors[i].peGreen;
779 rgbQuads[i].rgbBlue = pDcPal->IndexedColors[i].peBlue;
780 rgbQuads[i].rgbReserved = 0;
781 }
782 PALETTE_UnlockPalette(pDcPal);
783 } else {
784 switch (bpp) {
785 case 1:
786 if (pbmci)
787 {
788 rgbTriples[0].rgbtRed = rgbTriples[0].rgbtGreen =
789 rgbTriples[0].rgbtBlue = 0;
790 rgbTriples[1].rgbtRed = rgbTriples[1].rgbtGreen =
791 rgbTriples[1].rgbtBlue = 0xff;
792 }
793 rgbQuads[0].rgbRed = rgbQuads[0].rgbGreen =
794 rgbQuads[0].rgbBlue = 0;
795 rgbQuads[0].rgbReserved = 0;
796 rgbQuads[1].rgbRed = rgbQuads[1].rgbGreen =
797 rgbQuads[1].rgbBlue = 0xff;
798 rgbQuads[1].rgbReserved = 0;
799 break;
800
801 case 4:
802 if (pbmci)
803 RtlCopyMemory(rgbTriples, EGAColorsTriples, sizeof(EGAColorsTriples));
804 RtlCopyMemory(rgbQuads, EGAColorsQuads, sizeof(EGAColorsQuads));
805
806 break;
807
808 case 8:
809 {
810 INT r, g, b;
811 RGBQUAD *color;
812 if (pbmci)
813 {
814 RGBTRIPLE *colorTriple;
815
816 RtlCopyMemory(rgbTriples, DefLogPaletteTriples,
817 10 * sizeof(RGBTRIPLE));
818 RtlCopyMemory(rgbTriples + 246, DefLogPaletteTriples + 10,
819 10 * sizeof(RGBTRIPLE));
820 colorTriple = rgbTriples + 10;
821 for(r = 0; r <= 5; r++) /* FIXME */
822 {
823 for(g = 0; g <= 5; g++)
824 {
825 for(b = 0; b <= 5; b++)
826 {
827 colorTriple->rgbtRed = (r * 0xff) / 5;
828 colorTriple->rgbtGreen = (g * 0xff) / 5;
829 colorTriple->rgbtBlue = (b * 0xff) / 5;
830 color++;
831 }
832 }
833 }
834 }
835 memcpy(rgbQuads, DefLogPaletteQuads,
836 10 * sizeof(RGBQUAD));
837 memcpy(rgbQuads + 246, DefLogPaletteQuads + 10,
838 10 * sizeof(RGBQUAD));
839 color = rgbQuads + 10;
840 for(r = 0; r <= 5; r++) /* FIXME */
841 {
842 for(g = 0; g <= 5; g++)
843 {
844 for(b = 0; b <= 5; b++)
845 {
846 color->rgbRed = (r * 0xff) / 5;
847 color->rgbGreen = (g * 0xff) / 5;
848 color->rgbBlue = (b * 0xff) / 5;
849 color->rgbReserved = 0;
850 color++;
851 }
852 }
853 }
854 }
855 }
856 }
857 }
858 break;
859
860 case 15:
861 if (Info->bmiHeader.biCompression == BI_BITFIELDS)
862 {
863 ((PDWORD)Info->bmiColors)[0] = 0x7c00;
864 ((PDWORD)Info->bmiColors)[1] = 0x03e0;
865 ((PDWORD)Info->bmiColors)[2] = 0x001f;
866 }
867 break;
868
869 case 16:
870 if (Info->bmiHeader.biCompression == BI_BITFIELDS)
871 {
872 if (psurf->hSecure)
873 {
874 ((PDWORD)Info->bmiColors)[0] = psurf->ppal->RedMask;
875 ((PDWORD)Info->bmiColors)[1] = psurf->ppal->GreenMask;
876 ((PDWORD)Info->bmiColors)[2] = psurf->ppal->BlueMask;
877 }
878 else
879 {
880 ((PDWORD)Info->bmiColors)[0] = 0xf800;
881 ((PDWORD)Info->bmiColors)[1] = 0x07e0;
882 ((PDWORD)Info->bmiColors)[2] = 0x001f;
883 }
884 }
885 break;
886
887 case 24:
888 case 32:
889 if (Info->bmiHeader.biCompression == BI_BITFIELDS)
890 {
891 if (psurf->hSecure)
892 {
893 ((PDWORD)Info->bmiColors)[0] = psurf->ppal->RedMask;
894 ((PDWORD)Info->bmiColors)[1] = psurf->ppal->GreenMask;
895 ((PDWORD)Info->bmiColors)[2] = psurf->ppal->BlueMask;
896 }
897 else
898 {
899 ((PDWORD)Info->bmiColors)[0] = 0xff0000;
900 ((PDWORD)Info->bmiColors)[1] = 0x00ff00;
901 ((PDWORD)Info->bmiColors)[2] = 0x0000ff;
902 }
903 }
904 break;
905 }
906 Info->bmiHeader.biSizeImage = DIB_GetDIBImageBytes(width, height, bpp);
907
908 if(Bits && ScanLines)
909 {
910 /* Create a DIBSECTION, blt it, profit */
911 PVOID pDIBits ;
912 HBITMAP hBmpDest;
913 PSURFACE psurfDest;
914 EXLATEOBJ exlo;
915 RECT rcDest;
916 POINTL srcPoint;
917 BOOL ret ;
918
919 if (StartScan > psurf->SurfObj.sizlBitmap.cy)
920 {
921 ScanLines = 0;
922 goto done;
923 }
924 else
925 {
926 ScanLines = min(ScanLines, psurf->SurfObj.sizlBitmap.cy - StartScan);
927 }
928
929 /* Fixup values */
930 Info->bmiHeader.biWidth = psurf->SurfObj.sizlBitmap.cx;
931 Info->bmiHeader.biHeight = height < 0 ?
932 -ScanLines : ScanLines;
933 /* Create the DIB */
934 hBmpDest = DIB_CreateDIBSection(pDC, Info, Usage, &pDIBits, NULL, 0, 0);
935 /* Restore them */
936 Info->bmiHeader.biWidth = width;
937 Info->bmiHeader.biHeight = height;
938
939 if(!hBmpDest)
940 {
941 DPRINT1("Unable to create a DIB Section!\n");
942 SetLastWin32Error(ERROR_INVALID_PARAMETER);
943 ScanLines = 0;
944 goto done ;
945 }
946
947 psurfDest = SURFACE_LockSurface(hBmpDest);
948
949 rcDest.left = 0;
950 rcDest.top = 0;
951 rcDest.bottom = ScanLines;
952 rcDest.right = psurf->SurfObj.sizlBitmap.cx;
953
954 srcPoint.x = 0;
955 srcPoint.y = height < 0 ?
956 psurf->SurfObj.sizlBitmap.cy - (StartScan + ScanLines) : StartScan;
957
958 EXLATEOBJ_vInitialize(&exlo, psurf->ppal, psurfDest->ppal, 0, 0, 0);
959
960 ret = IntEngCopyBits(&psurfDest->SurfObj,
961 &psurf->SurfObj,
962 NULL,
963 &exlo.xlo,
964 &rcDest,
965 &srcPoint);
966
967 if(!ret)
968 ScanLines = 0;
969 else
970 {
971 Status = STATUS_SUCCESS;
972 _SEH2_TRY
973 {
974 RtlCopyMemory(Bits, pDIBits, DIB_GetDIBImageBytes (width, height, bpp));
975 }
976 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
977 {
978 Status = _SEH2_GetExceptionCode();
979 }
980 _SEH2_END
981
982 if(!NT_SUCCESS(Status))
983 {
984 DPRINT1("Unable to copy bits to the user provided pointer\n");
985 ScanLines = 0;
986 }
987 }
988
989 GreDeleteObject(hBmpDest);
990 EXLATEOBJ_vCleanup(&exlo);
991 }
992 else ScanLines = abs(height);
993
994 done:
995
996 if(pDC) DC_UnlockDc(pDC);
997 if(psurf) SURFACE_UnlockSurface(psurf);
998 if(pbmci) DIB_FreeConvertedBitmapInfo(Info, (BITMAPINFO*)pbmci);
999
1000 return ScanLines;
1001 }
1002
1003
1004 INT
1005 APIENTRY
1006 NtGdiStretchDIBitsInternal(
1007 HDC hDC,
1008 INT XDest,
1009 INT YDest,
1010 INT DestWidth,
1011 INT DestHeight,
1012 INT XSrc,
1013 INT YSrc,
1014 INT SrcWidth,
1015 INT SrcHeight,
1016 LPBYTE Bits,
1017 LPBITMAPINFO BitsInfo,
1018 DWORD Usage,
1019 DWORD ROP,
1020 UINT cjMaxInfo,
1021 UINT cjMaxBits,
1022 HANDLE hcmXform)
1023 {
1024 HBITMAP hBitmap, hOldBitmap = NULL;
1025 HDC hdcMem = NULL;
1026 NTSTATUS Status = STATUS_SUCCESS;
1027 PVOID pvDIBits;
1028 INT Ret = 0;
1029
1030 if (!Bits || !BitsInfo)
1031 {
1032 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1033 return 0;
1034 }
1035
1036 /* Create a DIB Section, data will be probed there */
1037 hBitmap = NtGdiCreateDIBSection(hDC,
1038 NULL,
1039 0,
1040 BitsInfo,
1041 Usage,
1042 0,
1043 0,
1044 0,
1045 &pvDIBits);
1046
1047 if(!hBitmap)
1048 {
1049 DPRINT1("Failed to create a DIB.\n");
1050 return 0;
1051 }
1052
1053 /* Set bits */
1054 _SEH2_TRY
1055 {
1056 ProbeForRead(Bits, cjMaxBits, 1);
1057 RtlCopyMemory(pvDIBits, Bits, DIB_GetDIBImageBytes(BitsInfo->bmiHeader.biWidth,
1058 BitsInfo->bmiHeader.biHeight,
1059 BitsInfo->bmiHeader.biBitCount));
1060 }
1061 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1062 {
1063 Status = _SEH2_GetExceptionCode();
1064 }
1065 _SEH2_END
1066
1067 if(!NT_SUCCESS(Status))
1068 {
1069 DPRINT1("Error : Could not read DIB bits\n");
1070 SetLastNtError(Status);
1071 goto cleanup;
1072 }
1073
1074 hdcMem = NtGdiCreateCompatibleDC(0);
1075 if(!hdcMem)
1076 {
1077 DPRINT1("Failed to create a memory DC!");
1078 goto cleanup;
1079 }
1080
1081 hOldBitmap = NtGdiSelectBitmap(hdcMem, hBitmap);
1082 if(!hOldBitmap)
1083 {
1084 DPRINT1("Could not select the DIB into the memory DC\n");
1085 goto cleanup;
1086 }
1087
1088 /* Do we want to stretch ? */
1089 if((SrcWidth == DestWidth) && (SrcHeight == DestHeight))
1090 {
1091 Ret = NtGdiBitBlt(hDC, XDest, YDest, XDest + DestWidth, YDest + DestHeight,
1092 hdcMem, XSrc, YSrc, ROP, 0, 0);
1093 }
1094 else
1095 {
1096 Ret = NtGdiStretchBlt(hDC, XDest, YDest, XDest + DestWidth, YDest + DestHeight,
1097 hdcMem, XSrc, YSrc, XSrc + SrcWidth, YSrc + SrcHeight,
1098 ROP, 0);
1099 }
1100
1101 if(Ret)
1102 Ret = SrcHeight ;
1103
1104 cleanup:
1105 if(hdcMem)
1106 {
1107 if(hOldBitmap) NtGdiSelectBitmap(hdcMem, hOldBitmap);
1108 NtGdiDeleteObjectApp(hdcMem);
1109 }
1110 GreDeleteObject(hBitmap);
1111
1112 return Ret;
1113 }
1114
1115
1116 HBITMAP
1117 FASTCALL
1118 IntCreateDIBitmap(
1119 PDC Dc,
1120 INT width,
1121 INT height,
1122 UINT bpp,
1123 DWORD init,
1124 LPBYTE bits,
1125 PBITMAPINFO data,
1126 DWORD coloruse)
1127 {
1128 HBITMAP handle;
1129 BOOL fColor;
1130
1131 // Check if we should create a monochrome or color bitmap. We create a monochrome bitmap only if it has exactly 2
1132 // colors, which are black followed by white, nothing else. In all other cases, we create a color bitmap.
1133
1134 if (bpp != 1) fColor = TRUE;
1135 else if ((coloruse != DIB_RGB_COLORS) || (init != CBM_INIT) || !data) fColor = FALSE;
1136 else
1137 {
1138 const RGBQUAD *rgb = (RGBQUAD*)((PBYTE)data + data->bmiHeader.biSize);
1139 DWORD col = RGB(rgb->rgbRed, rgb->rgbGreen, rgb->rgbBlue);
1140
1141 // Check if the first color of the colormap is black
1142 if ((col == RGB(0, 0, 0)))
1143 {
1144 rgb++;
1145 col = RGB(rgb->rgbRed, rgb->rgbGreen, rgb->rgbBlue);
1146
1147 // If the second color is white, create a monochrome bitmap
1148 fColor = (col != RGB(0xff,0xff,0xff));
1149 }
1150 else fColor = TRUE;
1151 }
1152
1153 // Now create the bitmap
1154 if (fColor)
1155 {
1156 handle = IntCreateCompatibleBitmap(Dc, width, height);
1157 }
1158 else
1159 {
1160 handle = GreCreateBitmap(width,
1161 height,
1162 1,
1163 1,
1164 NULL);
1165 }
1166
1167 if (height < 0)
1168 height = -height;
1169
1170 if (NULL != handle && CBM_INIT == init)
1171 {
1172 IntSetDIBits(Dc, handle, 0, height, bits, data, coloruse);
1173 }
1174
1175 return handle;
1176 }
1177
1178 // The CreateDIBitmap function creates a device-dependent bitmap (DDB) from a DIB and, optionally, sets the bitmap bits
1179 // The DDB that is created will be whatever bit depth your reference DC is
1180 HBITMAP
1181 APIENTRY
1182 NtGdiCreateDIBitmapInternal(
1183 IN HDC hDc,
1184 IN INT cx,
1185 IN INT cy,
1186 IN DWORD fInit,
1187 IN OPTIONAL LPBYTE pjInit,
1188 IN OPTIONAL LPBITMAPINFO pbmi,
1189 IN DWORD iUsage,
1190 IN UINT cjMaxInitInfo,
1191 IN UINT cjMaxBits,
1192 IN FLONG fl,
1193 IN HANDLE hcmXform)
1194 {
1195 NTSTATUS Status = STATUS_SUCCESS;
1196
1197 _SEH2_TRY
1198 {
1199 if(pbmi) ProbeForRead(pbmi, cjMaxInitInfo, 1);
1200 if(pjInit && (fInit == CBM_INIT)) ProbeForRead(pjInit, cjMaxBits, 1);
1201 }
1202 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1203 {
1204 Status = _SEH2_GetExceptionCode();
1205 }
1206 _SEH2_END
1207
1208 if(!NT_SUCCESS(Status))
1209 {
1210 SetLastNtError(Status);
1211 return NULL;
1212 }
1213
1214 return GreCreateDIBitmapInternal(hDc,
1215 cx,
1216 cy,
1217 fInit,
1218 pjInit,
1219 pbmi,
1220 iUsage,
1221 fl,
1222 hcmXform);
1223 }
1224
1225 HBITMAP
1226 FASTCALL
1227 GreCreateDIBitmapInternal(
1228 IN HDC hDc,
1229 IN INT cx,
1230 IN INT cy,
1231 IN DWORD fInit,
1232 IN OPTIONAL LPBYTE pjInit,
1233 IN OPTIONAL PBITMAPINFO pbmi,
1234 IN DWORD iUsage,
1235 IN FLONG fl,
1236 IN HANDLE hcmXform)
1237 {
1238 PDC Dc;
1239 HBITMAP Bmp;
1240 WORD bpp;
1241 HDC hdcDest;
1242
1243 if (!hDc) /* 1bpp monochrome bitmap */
1244 { // Should use System Bitmap DC hSystemBM, with CreateCompatibleDC for this.
1245 hdcDest = NtGdiCreateCompatibleDC(0);
1246 if(!hdcDest)
1247 {
1248 return NULL;
1249 }
1250 }
1251 else
1252 {
1253 hdcDest = hDc;
1254 }
1255
1256 Dc = DC_LockDc(hdcDest);
1257 if (!Dc)
1258 {
1259 SetLastWin32Error(ERROR_INVALID_HANDLE);
1260 return NULL;
1261 }
1262 /* It's OK to set bpp=0 here, as IntCreateDIBitmap will create a compatible Bitmap
1263 * if bpp != 1 and ignore the real value that was passed */
1264 if (pbmi)
1265 bpp = pbmi->bmiHeader.biBitCount;
1266 else
1267 bpp = 0;
1268 Bmp = IntCreateDIBitmap(Dc, cx, cy, bpp, fInit, pjInit, pbmi, iUsage);
1269 DC_UnlockDc(Dc);
1270
1271 if(!hDc)
1272 {
1273 NtGdiDeleteObjectApp(hdcDest);
1274 }
1275 return Bmp;
1276 }
1277
1278
1279 HBITMAP
1280 APIENTRY
1281 NtGdiCreateDIBSection(
1282 IN HDC hDC,
1283 IN OPTIONAL HANDLE hSection,
1284 IN DWORD dwOffset,
1285 IN BITMAPINFO* bmi,
1286 IN DWORD Usage,
1287 IN UINT cjHeader,
1288 IN FLONG fl,
1289 IN ULONG_PTR dwColorSpace,
1290 OUT PVOID *Bits)
1291 {
1292 HBITMAP hbitmap = 0;
1293 DC *dc;
1294 BOOL bDesktopDC = FALSE;
1295 NTSTATUS Status = STATUS_SUCCESS;
1296
1297 if (!bmi) return hbitmap; // Make sure.
1298
1299 _SEH2_TRY
1300 {
1301 ProbeForRead(&bmi->bmiHeader.biSize, sizeof(DWORD), 1);
1302 ProbeForRead(bmi, bmi->bmiHeader.biSize, 1);
1303 ProbeForRead(bmi, DIB_BitmapInfoSize(bmi, Usage), 1);
1304 }
1305 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1306 {
1307 Status = _SEH2_GetExceptionCode();
1308 }
1309 _SEH2_END
1310
1311 if(!NT_SUCCESS(Status))
1312 {
1313 SetLastNtError(Status);
1314 return NULL;
1315 }
1316
1317 // If the reference hdc is null, take the desktop dc
1318 if (hDC == 0)
1319 {
1320 hDC = NtGdiCreateCompatibleDC(0);
1321 bDesktopDC = TRUE;
1322 }
1323
1324 if ((dc = DC_LockDc(hDC)))
1325 {
1326 hbitmap = DIB_CreateDIBSection(dc,
1327 bmi,
1328 Usage,
1329 Bits,
1330 hSection,
1331 dwOffset,
1332 0);
1333 DC_UnlockDc(dc);
1334 }
1335 else
1336 {
1337 SetLastWin32Error(ERROR_INVALID_HANDLE);
1338 }
1339
1340 if (bDesktopDC)
1341 NtGdiDeleteObjectApp(hDC);
1342
1343 return hbitmap;
1344 }
1345
1346 HBITMAP
1347 APIENTRY
1348 DIB_CreateDIBSection(
1349 PDC dc,
1350 CONST BITMAPINFO *bmi,
1351 UINT usage,
1352 LPVOID *bits,
1353 HANDLE section,
1354 DWORD offset,
1355 DWORD ovr_pitch)
1356 {
1357 HBITMAP res = 0;
1358 SURFACE *bmp = NULL;
1359 void *mapBits = NULL;
1360 HPALETTE hpal ;
1361
1362 // Fill BITMAP32 structure with DIB data
1363 CONST BITMAPINFOHEADER *bi = &bmi->bmiHeader;
1364 INT effHeight;
1365 ULONG totalSize;
1366 BITMAP bm;
1367 SIZEL Size;
1368 HANDLE hSecure;
1369
1370 DPRINT("format (%ld,%ld), planes %d, bpp %d, size %ld, colors %ld (%s)\n",
1371 bi->biWidth, bi->biHeight, bi->biPlanes, bi->biBitCount,
1372 bi->biSizeImage, bi->biClrUsed, usage == DIB_PAL_COLORS? "PAL" : "RGB");
1373
1374 /* CreateDIBSection should fail for compressed formats */
1375 if (bi->biCompression == BI_RLE4 || bi->biCompression == BI_RLE8)
1376 {
1377 return (HBITMAP)NULL;
1378 }
1379
1380 effHeight = bi->biHeight >= 0 ? bi->biHeight : -bi->biHeight;
1381 bm.bmType = 0;
1382 bm.bmWidth = bi->biWidth;
1383 bm.bmHeight = effHeight;
1384 bm.bmWidthBytes = ovr_pitch ? ovr_pitch : (ULONG) DIB_GetDIBWidthBytes(bm.bmWidth, bi->biBitCount);
1385
1386 bm.bmPlanes = bi->biPlanes;
1387 bm.bmBitsPixel = bi->biBitCount;
1388 bm.bmBits = NULL;
1389
1390 // Get storage location for DIB bits. Only use biSizeImage if it's valid and
1391 // we're dealing with a compressed bitmap. Otherwise, use width * height.
1392 totalSize = bi->biSizeImage && bi->biCompression != BI_RGB
1393 ? bi->biSizeImage : (ULONG)(bm.bmWidthBytes * effHeight);
1394
1395 if (section)
1396 {
1397 SYSTEM_BASIC_INFORMATION Sbi;
1398 NTSTATUS Status;
1399 DWORD mapOffset;
1400 LARGE_INTEGER SectionOffset;
1401 SIZE_T mapSize;
1402
1403 Status = ZwQuerySystemInformation(SystemBasicInformation,
1404 &Sbi,
1405 sizeof Sbi,
1406 0);
1407 if (!NT_SUCCESS(Status))
1408 {
1409 return NULL;
1410 }
1411
1412 mapOffset = offset - (offset % Sbi.AllocationGranularity);
1413 mapSize = bi->biSizeImage + (offset - mapOffset);
1414
1415 SectionOffset.LowPart = mapOffset;
1416 SectionOffset.HighPart = 0;
1417
1418 Status = ZwMapViewOfSection(section,
1419 NtCurrentProcess(),
1420 &mapBits,
1421 0,
1422 0,
1423 &SectionOffset,
1424 &mapSize,
1425 ViewShare,
1426 0,
1427 PAGE_READWRITE);
1428 if (!NT_SUCCESS(Status))
1429 {
1430 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1431 return NULL;
1432 }
1433
1434 if (mapBits) bm.bmBits = (char *)mapBits + (offset - mapOffset);
1435 }
1436 else if (ovr_pitch && offset)
1437 bm.bmBits = (LPVOID) offset;
1438 else
1439 {
1440 offset = 0;
1441 bm.bmBits = EngAllocUserMem(totalSize, 0);
1442 if(!bm.bmBits) goto cleanup;
1443 }
1444
1445 // hSecure = MmSecureVirtualMemory(bm.bmBits, totalSize, PAGE_READWRITE);
1446 hSecure = (HANDLE)0x1; // HACK OF UNIMPLEMENTED KERNEL STUFF !!!!
1447
1448 if (usage == DIB_PAL_COLORS)
1449 {
1450 if(dc)
1451 {
1452 PPALETTE pdcPal ;
1453 pdcPal = PALETTE_LockPalette(dc->dclevel.hpal);
1454 hpal = DIB_MapPaletteColors(pdcPal, bmi);
1455 PALETTE_UnlockPalette(pdcPal);
1456 }
1457 else
1458 {
1459 /* For DIB Brushes */
1460 DPRINT1("FIXME : Unsupported DIB_PAL_COLORS without a DC to map colors.\n");
1461 /* HACK */
1462 hpal = (HPALETTE) 0xFFFFFFFF;
1463 }
1464 }
1465 else
1466 {
1467 hpal = BuildDIBPalette(bmi);
1468 }
1469
1470 if(!hpal)
1471 {
1472 DPRINT1("Error : Could not create a palette for the DIB.\n");
1473 goto cleanup;
1474 }
1475
1476 // Create Device Dependent Bitmap and add DIB pointer
1477 Size.cx = bm.bmWidth;
1478 Size.cy = abs(bm.bmHeight);
1479 res = GreCreateBitmapEx(bm.bmWidth,
1480 abs(bm.bmHeight),
1481 bm.bmWidthBytes,
1482 BitmapFormat(bi->biBitCount * bi->biPlanes, bi->biCompression),
1483 BMF_DONTCACHE | BMF_USERMEM | BMF_NOZEROINIT |
1484 (bi->biHeight < 0 ? BMF_TOPDOWN : 0),
1485 bi->biSizeImage,
1486 bm.bmBits,
1487 0);
1488 if (!res)
1489 {
1490 SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
1491 goto cleanup;
1492 }
1493 bmp = SURFACE_LockSurface(res);
1494 if (NULL == bmp)
1495 {
1496 SetLastWin32Error(ERROR_INVALID_HANDLE);
1497 goto cleanup;
1498 }
1499
1500 /* WINE NOTE: WINE makes use of a colormap, which is a color translation
1501 table between the DIB and the X physical device. Obviously,
1502 this is left out of the ReactOS implementation. Instead,
1503 we call NtGdiSetDIBColorTable. */
1504 bmp->hDIBSection = section;
1505 bmp->hSecure = hSecure;
1506 bmp->dwOffset = offset;
1507 bmp->flags = API_BITMAP;
1508 bmp->biClrImportant = bi->biClrImportant;
1509
1510 /* HACK */
1511 if(hpal != (HPALETTE)0xFFFFFFFF)
1512 {
1513 bmp->ppal = PALETTE_ShareLockPalette(hpal);
1514 /* Lazy delete hpal, it will be freed at surface release */
1515 GreDeleteObject(hpal);
1516 }
1517
1518 // Clean up in case of errors
1519 cleanup:
1520 if (!res || !bmp || !bm.bmBits)
1521 {
1522 DPRINT("got an error res=%08x, bmp=%p, bm.bmBits=%p\n", res, bmp, bm.bmBits);
1523 if (bm.bmBits)
1524 {
1525 // MmUnsecureVirtualMemory(hSecure); // FIXME: Implement this!
1526 if (section)
1527 {
1528 ZwUnmapViewOfSection(NtCurrentProcess(), mapBits);
1529 bm.bmBits = NULL;
1530 }
1531 else
1532 if (!offset)
1533 EngFreeUserMem(bm.bmBits), bm.bmBits = NULL;
1534 }
1535
1536 if (bmp)
1537 bmp = NULL;
1538
1539 if (res)
1540 {
1541 SURFACE_FreeSurfaceByHandle(res);
1542 res = 0;
1543 }
1544 }
1545
1546 if (bmp)
1547 {
1548 SURFACE_UnlockSurface(bmp);
1549 }
1550
1551 // Return BITMAP handle and storage location
1552 if (NULL != bm.bmBits && NULL != bits)
1553 {
1554 *bits = bm.bmBits;
1555 }
1556
1557 return res;
1558 }
1559
1560 /***********************************************************************
1561 * DIB_GetBitmapInfo
1562 *
1563 * Get the info from a bitmap header.
1564 * Return 0 for COREHEADER, 1 for INFOHEADER, -1 for error.
1565 */
1566 int
1567 FASTCALL
1568 DIB_GetBitmapInfo( const BITMAPINFOHEADER *header, LONG *width,
1569 LONG *height, WORD *planes, WORD *bpp, DWORD *compr, DWORD *size )
1570 {
1571 if (header->biSize == sizeof(BITMAPCOREHEADER))
1572 {
1573 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)header;
1574 *width = core->bcWidth;
1575 *height = core->bcHeight;
1576 *planes = core->bcPlanes;
1577 *bpp = core->bcBitCount;
1578 *compr = 0;
1579 *size = 0;
1580 return 0;
1581 }
1582 if (header->biSize >= sizeof(BITMAPINFOHEADER)) /* assume BITMAPINFOHEADER */
1583 {
1584 *width = header->biWidth;
1585 *height = header->biHeight;
1586 *planes = header->biPlanes;
1587 *bpp = header->biBitCount;
1588 *compr = header->biCompression;
1589 *size = header->biSizeImage;
1590 return 1;
1591 }
1592 DPRINT1("(%d): unknown/wrong size for header\n", header->biSize );
1593 return -1;
1594 }
1595
1596 /***********************************************************************
1597 * DIB_GetDIBWidthBytes
1598 *
1599 * Return the width of a DIB bitmap in bytes. DIB bitmap data is 32-bit aligned.
1600 * http://www.microsoft.com/msdn/sdk/platforms/doc/sdk/win32/struc/src/str01.htm
1601 * 11/16/1999 (RJJ) lifted from wine
1602 */
1603 INT FASTCALL DIB_GetDIBWidthBytes(INT width, INT depth)
1604 {
1605 return ((width * depth + 31) & ~31) >> 3;
1606 }
1607
1608 /***********************************************************************
1609 * DIB_GetDIBImageBytes
1610 *
1611 * Return the number of bytes used to hold the image in a DIB bitmap.
1612 * 11/16/1999 (RJJ) lifted from wine
1613 */
1614
1615 INT APIENTRY DIB_GetDIBImageBytes(INT width, INT height, INT depth)
1616 {
1617 return DIB_GetDIBWidthBytes(width, depth) * (height < 0 ? -height : height);
1618 }
1619
1620 /***********************************************************************
1621 * DIB_BitmapInfoSize
1622 *
1623 * Return the size of the bitmap info structure including color table.
1624 * 11/16/1999 (RJJ) lifted from wine
1625 */
1626
1627 INT FASTCALL DIB_BitmapInfoSize(const BITMAPINFO * info, WORD coloruse)
1628 {
1629 unsigned int colors, size, masks = 0;
1630
1631 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
1632 {
1633 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
1634 colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
1635 return sizeof(BITMAPCOREHEADER) + colors *
1636 ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
1637 }
1638 else /* assume BITMAPINFOHEADER */
1639 {
1640 colors = info->bmiHeader.biClrUsed;
1641 if (colors > 256) colors = 256;
1642 if (!colors && (info->bmiHeader.biBitCount <= 8))
1643 colors = 1 << info->bmiHeader.biBitCount;
1644 if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3;
1645 size = max( info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD) );
1646 return size + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
1647 }
1648 }
1649
1650 HPALETTE
1651 FASTCALL
1652 DIB_MapPaletteColors(PPALETTE ppal, CONST BITMAPINFO* lpbmi)
1653 {
1654 PALETTEENTRY* ppalEntries;
1655 ULONG nNumColors,i;
1656 USHORT *lpIndex;
1657 HPALETTE hpal;
1658
1659 if (ppal->Mode != PAL_INDEXED)
1660 {
1661 return NULL;
1662 }
1663
1664 nNumColors = 1 << lpbmi->bmiHeader.biBitCount;
1665 if (lpbmi->bmiHeader.biClrUsed)
1666 {
1667 nNumColors = min(nNumColors, lpbmi->bmiHeader.biClrUsed);
1668 }
1669
1670 /* Don't have more colors than we need */
1671 nNumColors = min(ppal->NumColors, nNumColors);
1672
1673 ppalEntries = ExAllocatePoolWithTag(PagedPool, sizeof(PALETTEENTRY) * nNumColors, TAG_COLORMAP);
1674 if (ppalEntries == NULL)
1675 {
1676 DPRINT1("Could not allocate palette entries\n");
1677 return NULL;
1678 }
1679
1680 lpIndex = (USHORT *)((PBYTE)lpbmi + lpbmi->bmiHeader.biSize);
1681
1682 for (i = 0; i < nNumColors; i++)
1683 {
1684 if (*lpIndex < ppal->NumColors)
1685 {
1686 ppalEntries[i] = ppal->IndexedColors[*lpIndex];
1687 }
1688 else
1689 {
1690 ppalEntries[i].peRed = 0;
1691 ppalEntries[i].peGreen = 0;
1692 ppalEntries[i].peBlue = 0;
1693 ppalEntries[i].peFlags = 0;
1694 }
1695
1696 lpIndex++;
1697 }
1698
1699 hpal = PALETTE_AllocPalette(PAL_INDEXED, nNumColors, (ULONG*)ppalEntries, 0, 0, 0);
1700
1701 ExFreePoolWithTag(ppalEntries, TAG_COLORMAP);
1702
1703 return hpal;
1704 }
1705
1706 HPALETTE
1707 FASTCALL
1708 BuildDIBPalette(CONST BITMAPINFO *bmi)
1709 {
1710 BYTE bits;
1711 ULONG ColorCount;
1712 HPALETTE hPal;
1713 ULONG RedMask = 0, GreenMask = 0, BlueMask = 0;
1714 PDWORD pdwColors = (PDWORD)((PBYTE)bmi + bmi->bmiHeader.biSize);
1715 INT paletteType;
1716
1717 // Determine Bits Per Pixel
1718 bits = bmi->bmiHeader.biBitCount;
1719
1720 // Determine paletteType from Bits Per Pixel
1721 if (bits <= 8)
1722 {
1723 paletteType = PAL_INDEXED;
1724 RedMask = GreenMask = BlueMask = 0;
1725 }
1726 else if (bmi->bmiHeader.biCompression == BI_BITFIELDS)
1727 {
1728 paletteType = PAL_BITFIELDS;
1729 RedMask = pdwColors[0];
1730 GreenMask = pdwColors[1];
1731 BlueMask = pdwColors[2];
1732 }
1733 else if (bits == 15)
1734 {
1735 paletteType = PAL_RGB16_555;
1736 }
1737 else if (bits == 16)
1738 {
1739 paletteType = PAL_RGB16_565;
1740 }
1741 else
1742 {
1743 paletteType = PAL_BGR;
1744 }
1745
1746 if (bmi->bmiHeader.biClrUsed == 0)
1747 {
1748 ColorCount = 1 << bmi->bmiHeader.biBitCount;
1749 }
1750 else
1751 {
1752 ColorCount = bmi->bmiHeader.biClrUsed;
1753 }
1754
1755 if (PAL_INDEXED == paletteType)
1756 {
1757 hPal = PALETTE_AllocPaletteIndexedRGB(ColorCount, (RGBQUAD*)pdwColors);
1758 }
1759 else
1760 {
1761 hPal = PALETTE_AllocPalette(paletteType, 0,
1762 NULL,
1763 RedMask, GreenMask, BlueMask);
1764 }
1765
1766 return hPal;
1767 }
1768
1769 /* Converts a BITMAPCOREINFO to a BITMAPINFO structure,
1770 * or does nothing if it's already a BITMAPINFO (or V4 or V5) */
1771 BITMAPINFO*
1772 FASTCALL
1773 DIB_ConvertBitmapInfo (CONST BITMAPINFO* pbmi, DWORD Usage)
1774 {
1775 CONST BITMAPCOREINFO* pbmci = (BITMAPCOREINFO*)pbmi;
1776 BITMAPINFO* pNewBmi ;
1777 UINT numColors = 0, ColorsSize = 0;
1778
1779 if(pbmi->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER)) return (BITMAPINFO*)pbmi;
1780 if(pbmi->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) return NULL;
1781
1782 if(pbmci->bmciHeader.bcBitCount <= 8)
1783 {
1784 numColors = 1 << pbmci->bmciHeader.bcBitCount;
1785 if(Usage == DIB_PAL_COLORS)
1786 {
1787 ColorsSize = numColors * sizeof(WORD);
1788 }
1789 else
1790 {
1791 ColorsSize = numColors * sizeof(RGBQUAD);
1792 }
1793 }
1794 else if (Usage == DIB_PAL_COLORS)
1795 {
1796 /* Invalid at high Res */
1797 return NULL;
1798 }
1799
1800 pNewBmi = ExAllocatePoolWithTag(PagedPool, sizeof(BITMAPINFOHEADER) + ColorsSize, TAG_DIB);
1801 if(!pNewBmi) return NULL;
1802
1803 RtlZeroMemory(pNewBmi, sizeof(BITMAPINFOHEADER) + ColorsSize);
1804
1805 pNewBmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1806 pNewBmi->bmiHeader.biBitCount = pbmci->bmciHeader.bcBitCount;
1807 pNewBmi->bmiHeader.biWidth = pbmci->bmciHeader.bcWidth;
1808 pNewBmi->bmiHeader.biHeight = pbmci->bmciHeader.bcHeight;
1809 pNewBmi->bmiHeader.biPlanes = pbmci->bmciHeader.bcPlanes;
1810 pNewBmi->bmiHeader.biCompression = BI_RGB ;
1811 pNewBmi->bmiHeader.biSizeImage = DIB_GetDIBImageBytes(pNewBmi->bmiHeader.biWidth,
1812 pNewBmi->bmiHeader.biHeight,
1813 pNewBmi->bmiHeader.biBitCount);
1814
1815 if(Usage == DIB_PAL_COLORS)
1816 {
1817 RtlCopyMemory(pNewBmi->bmiColors, pbmci->bmciColors, ColorsSize);
1818 }
1819 else
1820 {
1821 UINT i;
1822 for(i=0; i<numColors; i++)
1823 {
1824 pNewBmi->bmiColors[i].rgbRed = pbmci->bmciColors[i].rgbtRed;
1825 pNewBmi->bmiColors[i].rgbGreen = pbmci->bmciColors[i].rgbtGreen;
1826 pNewBmi->bmiColors[i].rgbBlue = pbmci->bmciColors[i].rgbtBlue;
1827 }
1828 }
1829
1830 return pNewBmi ;
1831 }
1832
1833 /* Frees a BITMAPINFO created with DIB_ConvertBitmapInfo */
1834 VOID
1835 FASTCALL
1836 DIB_FreeConvertedBitmapInfo(BITMAPINFO* converted, BITMAPINFO* orig)
1837 {
1838 if(converted != orig)
1839 ExFreePoolWithTag(converted, TAG_DIB);
1840 }
1841
1842
1843
1844
1845
1846
1847 /* EOF */