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