- Unlock surface in error case of EngModifySurface.
[reactos.git] / reactos / subsys / win32k / eng / surface.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
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id: surface.c,v 1.35 2004/03/20 17:33:10 navaraf Exp $
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * PURPOSE: GDI Driver Surace Functions
24 * FILE: subsys/win32k/eng/surface.c
25 * PROGRAMER: Jason Filby
26 * REVISION HISTORY:
27 * 3/7/1999: Created
28 * 9/11/2000: Updated to handle real pixel packed bitmaps (UPDATE TO DATE COMPLETED)
29 * TESTING TO BE DONE:
30 * - Create a GDI bitmap with all formats, perform all drawing operations on them, render to VGA surface
31 * refer to \test\microwin\src\engine\devdraw.c for info on correct pixel plotting for various formats
32 */
33
34 #include <ddk/winddi.h>
35 #include <win32k/dc.h>
36 #include <win32k/gdiobj.h>
37 #include <include/dib.h>
38 #include <include/object.h>
39 #include <include/paint.h>
40 #include "handle.h"
41 #include "../dib/dib.h"
42
43 #define NDEBUG
44 #include <win32k/debug1.h>
45
46 enum Rle_EscapeCodes
47 {
48 RLE_EOL = 0, /* End of line */
49 RLE_END = 1, /* End of bitmap */
50 RLE_DELTA = 2 /* Delta */
51 };
52
53 INT FASTCALL BitsPerFormat(ULONG Format)
54 {
55 switch(Format)
56 {
57 case BMF_1BPP: return 1;
58 case BMF_4BPP:
59 case BMF_4RLE: return 4;
60 case BMF_8BPP:
61 case BMF_8RLE: return 8;
62 case BMF_16BPP: return 16;
63 case BMF_24BPP: return 24;
64 case BMF_32BPP: return 32;
65 default: return 0;
66 }
67 }
68
69 ULONG FASTCALL BitmapFormat(WORD Bits, DWORD Compression)
70 {
71 switch(Compression)
72 {
73 case BI_RGB:
74 switch(Bits)
75 {
76 case 1: return BMF_1BPP;
77 case 4: return BMF_4BPP;
78 case 8: return BMF_8BPP;
79 case 16: return BMF_16BPP;
80 case 24: return BMF_24BPP;
81 case 32: return BMF_32BPP;
82 }
83
84 case BI_RLE4: return BMF_4RLE;
85 case BI_RLE8: return BMF_8RLE;
86
87 default: return 0;
88 }
89 }
90
91 static VOID Dummy_PutPixel(SURFOBJ* SurfObj, LONG x, LONG y, ULONG c)
92 {
93 return;
94 }
95
96 static ULONG Dummy_GetPixel(SURFOBJ* SurfObj, LONG x, LONG y)
97 {
98 return 0;
99 }
100
101 static VOID Dummy_HLine(SURFOBJ* SurfObj, LONG x1, LONG x2, LONG y, ULONG c)
102 {
103 return;
104 }
105
106 static VOID Dummy_VLine(SURFOBJ* SurfObj, LONG x, LONG y1, LONG y2, ULONG c)
107 {
108 return;
109 }
110
111 static BOOLEAN Dummy_BitBlt(SURFOBJ *DestSurf, SURFOBJ *SourceSurf,
112 SURFGDI *DestGDI, SURFGDI *SourceGDI,
113 RECTL* DestRect, POINTL *SourcePoint,
114 BRUSHOBJ* BrushObj, POINTL* BrushOrign,
115 XLATEOBJ *ColorTranslation, ULONG Rop4)
116 {
117 return FALSE;
118 }
119
120 static BOOLEAN Dummy_StretchBlt(SURFOBJ *DestSurf, SURFOBJ *SourceSurf,
121 SURFGDI *DestGDI, SURFGDI *SourceGDI,
122 RECTL* DestRect, RECTL *SourceRect,
123 POINTL* MaskOrigin, POINTL* BrushOrign,
124 XLATEOBJ *ColorTranslation, ULONG Mode)
125 {
126 return FALSE;
127 }
128
129
130 #define SURF_METHOD(c,n) DIB_##c##_##n
131 #define SET_SURFGDI(c)\
132 SurfGDI->DIB_PutPixel=SURF_METHOD(c,PutPixel);\
133 SurfGDI->DIB_GetPixel=SURF_METHOD(c,GetPixel);\
134 SurfGDI->DIB_HLine=SURF_METHOD(c,HLine);\
135 SurfGDI->DIB_VLine=SURF_METHOD(c,VLine);\
136 SurfGDI->DIB_BitBlt=SURF_METHOD(c,BitBlt);\
137 SurfGDI->DIB_StretchBlt=SURF_METHOD(c,StretchBlt);
138
139 VOID FASTCALL InitializeFuncs(SURFGDI *SurfGDI, ULONG BitmapFormat)
140 {
141 SurfGDI->BitBlt = NULL;
142 SurfGDI->StretchBlt = NULL;
143 SurfGDI->CopyBits = NULL;
144 SurfGDI->CreateDeviceBitmap = NULL;
145 SurfGDI->SetPalette = NULL;
146 SurfGDI->TransparentBlt = NULL;
147
148 switch(BitmapFormat)
149 {
150 case BMF_1BPP: SET_SURFGDI(1BPP) break;
151 case BMF_4BPP: SET_SURFGDI(4BPP) break;
152 case BMF_8BPP: SET_SURFGDI(8BPP) break;
153 case BMF_16BPP: SET_SURFGDI(16BPP) break;
154 case BMF_24BPP: SET_SURFGDI(24BPP) break;
155 case BMF_32BPP: SET_SURFGDI(32BPP) break;
156 case BMF_4RLE:
157 case BMF_8RLE:
158 /* Not supported yet, fall through to unrecognized case */
159 default:
160 DPRINT1("InitializeFuncs: unsupported DIB format %d\n",
161 BitmapFormat);
162
163 SurfGDI->DIB_PutPixel = Dummy_PutPixel;
164 SurfGDI->DIB_GetPixel = Dummy_GetPixel;
165 SurfGDI->DIB_HLine = Dummy_HLine;
166 SurfGDI->DIB_VLine = Dummy_VLine;
167 SurfGDI->DIB_BitBlt = Dummy_BitBlt;
168 SurfGDI->DIB_StretchBlt = Dummy_StretchBlt;
169 break;
170 }
171 }
172
173 /*
174 * @implemented
175 */
176 HBITMAP STDCALL
177 EngCreateDeviceBitmap(IN DHSURF dhsurf,
178 IN SIZEL Size,
179 IN ULONG Format)
180 {
181 HBITMAP NewBitmap;
182 SURFOBJ *SurfObj;
183
184 NewBitmap = EngCreateBitmap(Size, DIB_GetDIBWidthBytes(Size.cx, BitsPerFormat(Format)), Format, 0, NULL);
185 SurfObj = (PVOID)AccessUserObject((ULONG)NewBitmap);
186 SurfObj->dhsurf = dhsurf;
187
188 return NewBitmap;
189 }
190
191 VOID Decompress4bpp(SIZEL Size, BYTE *CompressedBits, BYTE *UncompressedBits, LONG Delta)
192 {
193 int x = 0;
194 int y = Size.cy - 1;
195 int c;
196 int length;
197 int width = ((Size.cx+1)/2);
198 int height = Size.cy - 1;
199 BYTE *begin = CompressedBits;
200 BYTE *bits = CompressedBits;
201 BYTE *temp;
202 while (y >= 0)
203 {
204 length = *bits++ / 2;
205 if (length)
206 {
207 c = *bits++;
208 while (length--)
209 {
210 if (x >= width) break;
211 temp = UncompressedBits + (((height - y) * Delta) + x);
212 x++;
213 *temp = c;
214 }
215 } else {
216 length = *bits++;
217 switch (length)
218 {
219 case RLE_EOL:
220 x = 0;
221 y--;
222 break;
223 case RLE_END:
224 return;
225 case RLE_DELTA:
226 x += (*bits++)/2;
227 y -= (*bits++)/2;
228 break;
229 default:
230 length /= 2;
231 while (length--)
232 {
233 c = *bits++;
234 if (x < width)
235 {
236 temp = UncompressedBits + (((height - y) * Delta) + x);
237 x++;
238 *temp = c;
239 }
240 }
241 if ((bits - begin) & 1)
242 bits++;
243 }
244 }
245 }
246 }
247
248 VOID Decompress8bpp(SIZEL Size, BYTE *CompressedBits, BYTE *UncompressedBits, LONG Delta)
249 {
250 int x = 0;
251 int y = Size.cy - 1;
252 int c;
253 int length;
254 int width = Size.cx;
255 int height = Size.cy - 1;
256 BYTE *begin = CompressedBits;
257 BYTE *bits = CompressedBits;
258 BYTE *temp;
259 while (y >= 0)
260 {
261 length = *bits++;
262 if (length)
263 {
264 c = *bits++;
265 while (length--)
266 {
267 if (x >= width) break;
268 temp = UncompressedBits + (((height - y) * Delta) + x);
269 x++;
270 *temp = c;
271 }
272 } else {
273 length = *bits++;
274 switch (length)
275 {
276 case RLE_EOL:
277 x = 0;
278 y--;
279 break;
280 case RLE_END:
281 return;
282 case RLE_DELTA:
283 x += *bits++;
284 y -= *bits++;
285 break;
286 default:
287 while (length--)
288 {
289 c = *bits++;
290 if (x < width)
291 {
292 temp = UncompressedBits + (((height - y) * Delta) + x);
293 x++;
294 *temp = c;
295 }
296 }
297 if ((bits - begin) & 1)
298 bits++;
299 }
300 }
301 }
302 }
303
304 /*
305 * @implemented
306 */
307 HBITMAP STDCALL
308 EngCreateBitmap(IN SIZEL Size,
309 IN LONG Width,
310 IN ULONG Format,
311 IN ULONG Flags,
312 IN PVOID Bits)
313 {
314 HBITMAP NewBitmap;
315 SURFOBJ *SurfObj;
316 SURFGDI *SurfGDI;
317 PVOID UncompressedBits;
318 ULONG UncompressedFormat;
319
320 NewBitmap = (PVOID)CreateGDIHandle(sizeof(SURFGDI), sizeof(SURFOBJ));
321 if( !ValidEngHandle( NewBitmap ) )
322 return 0;
323
324 SurfObj = (SURFOBJ*) AccessUserObject( (ULONG) NewBitmap );
325 SurfGDI = (SURFGDI*) AccessInternalObject( (ULONG) NewBitmap );
326 ASSERT( SurfObj );
327 ASSERT( SurfGDI );
328 SurfGDI->BitsPerPixel = BitsPerFormat(Format);
329 if (Format == BMF_4RLE) {
330 SurfObj->lDelta = DIB_GetDIBWidthBytes(Size.cx, BitsPerFormat(BMF_4BPP));
331 SurfObj->cjBits = SurfObj->lDelta * Size.cy;
332 UncompressedFormat = BMF_4BPP;
333 UncompressedBits = EngAllocMem(FL_ZERO_MEMORY, SurfObj->cjBits, 0);
334 Decompress4bpp(Size, (BYTE *)Bits, (BYTE *)UncompressedBits, SurfObj->lDelta);
335 } else {
336 if (Format == BMF_8RLE) {
337 SurfObj->lDelta = DIB_GetDIBWidthBytes(Size.cx, BitsPerFormat(BMF_8BPP));
338 SurfObj->cjBits = SurfObj->lDelta * Size.cy;
339 UncompressedFormat = BMF_8BPP;
340 UncompressedBits = EngAllocMem(FL_ZERO_MEMORY, SurfObj->cjBits, 0);
341 Decompress8bpp(Size, (BYTE *)Bits, (BYTE *)UncompressedBits, SurfObj->lDelta);
342 } else {
343 SurfObj->lDelta = Width;
344 SurfObj->cjBits = SurfObj->lDelta * Size.cy;
345 UncompressedBits = Bits;
346 UncompressedFormat = Format;
347 }
348 }
349 if(UncompressedBits!=NULL)
350 {
351 SurfObj->pvBits = UncompressedBits;
352 } else
353 {
354 if (SurfObj->cjBits == 0)
355 {
356 SurfObj->pvBits = NULL;
357 }
358 else
359 {
360 if(Flags & BMF_USERMEM)
361 {
362 SurfObj->pvBits = EngAllocUserMem(SurfObj->cjBits, 0);
363 } else {
364 if(Flags & BMF_NOZEROINIT)
365 {
366 SurfObj->pvBits = EngAllocMem(0, SurfObj->cjBits, 0);
367 } else {
368 SurfObj->pvBits = EngAllocMem(FL_ZERO_MEMORY, SurfObj->cjBits, 0);
369 }
370 }
371 }
372 }
373
374 SurfObj->dhsurf = 0; // device managed surface
375 SurfObj->hsurf = 0;
376 SurfObj->dhpdev = NULL;
377 SurfObj->hdev = NULL;
378 SurfObj->sizlBitmap = Size;
379 SurfObj->iBitmapFormat = UncompressedFormat;
380 SurfObj->iType = STYPE_BITMAP;
381 SurfObj->fjBitmap = Flags & (BMF_TOPDOWN | BMF_NOZEROINIT);
382 SurfObj->pvScan0 = SurfObj->pvBits;
383 SurfObj->iUniq = 0;
384
385 InitializeFuncs(SurfGDI, UncompressedFormat);
386
387 // Use flags to determine bitmap type -- TOP_DOWN or whatever
388
389 return NewBitmap;
390 }
391
392 /*
393 * @unimplemented
394 */
395 HSURF STDCALL
396 EngCreateDeviceSurface(IN DHSURF dhsurf,
397 IN SIZEL Size,
398 IN ULONG Format)
399 {
400 HSURF NewSurface;
401 SURFOBJ *SurfObj;
402 SURFGDI *SurfGDI;
403
404 NewSurface = (HSURF)CreateGDIHandle(sizeof( SURFGDI ), sizeof( SURFOBJ ));
405 if( !ValidEngHandle( NewSurface ) )
406 return 0;
407
408 SurfObj = (SURFOBJ*) AccessUserObject( (ULONG) NewSurface );
409 SurfGDI = (SURFGDI*) AccessInternalObject( (ULONG) NewSurface );
410 ASSERT( SurfObj );
411 ASSERT( SurfGDI );
412
413 SurfGDI->BitsPerPixel = BitsPerFormat(Format);
414 SurfObj->dhsurf = dhsurf;
415 SurfObj->hsurf = (HSURF) dhsurf; // FIXME: Is this correct??
416 SurfObj->sizlBitmap = Size;
417 SurfObj->iBitmapFormat = Format;
418 SurfObj->lDelta = DIB_GetDIBWidthBytes(Size.cx, BitsPerFormat(Format));
419 SurfObj->iType = STYPE_DEVICE;
420 SurfObj->iUniq = 0;
421
422 InitializeFuncs(SurfGDI, Format);
423
424 return NewSurface;
425 }
426
427 PFN FASTCALL DriverFunction(DRVENABLEDATA *DED, ULONG DriverFunc)
428 {
429 ULONG i;
430
431 for(i=0; i<DED->c; i++)
432 {
433 if(DED->pdrvfn[i].iFunc == DriverFunc)
434 return DED->pdrvfn[i].pfn;
435 }
436 return NULL;
437 }
438
439 /*
440 * @implemented
441 */
442 BOOL STDCALL
443 EngAssociateSurface(IN HSURF Surface,
444 IN HDEV Dev,
445 IN ULONG Hooks)
446 {
447 SURFOBJ *SurfObj;
448 SURFGDI *SurfGDI;
449 GDIDEVICE* Device;
450
451 Device = (GDIDEVICE*)Dev;
452
453 SurfGDI = (PVOID)AccessInternalObject((ULONG)Surface);
454 SurfObj = (PVOID)AccessUserObject((ULONG)Surface);
455
456 // Associate the hdev
457 SurfObj->hdev = Dev;
458 SurfObj->dhpdev = Device->PDev;
459
460 // Hook up specified functions
461 if(Hooks & HOOK_BITBLT) SurfGDI->BitBlt = Device->DriverFunctions.BitBlt;
462 if(Hooks & HOOK_TRANSPARENTBLT) SurfGDI->TransparentBlt = Device->DriverFunctions.TransparentBlt;
463 if(Hooks & HOOK_STRETCHBLT) SurfGDI->StretchBlt = (PFN_StretchBlt)Device->DriverFunctions.StretchBlt;
464 if(Hooks & HOOK_TEXTOUT) SurfGDI->TextOut = Device->DriverFunctions.TextOut;
465 if(Hooks & HOOK_PAINT) SurfGDI->Paint = Device->DriverFunctions.Paint;
466 if(Hooks & HOOK_STROKEPATH) SurfGDI->StrokePath = Device->DriverFunctions.StrokePath;
467 if(Hooks & HOOK_FILLPATH) SurfGDI->FillPath = Device->DriverFunctions.FillPath;
468 if(Hooks & HOOK_STROKEANDFILLPATH) SurfGDI->StrokeAndFillPath = Device->DriverFunctions.StrokeAndFillPath;
469 if(Hooks & HOOK_LINETO) SurfGDI->LineTo = Device->DriverFunctions.LineTo;
470 if(Hooks & HOOK_COPYBITS) SurfGDI->CopyBits = Device->DriverFunctions.CopyBits;
471 if(Hooks & HOOK_SYNCHRONIZE) SurfGDI->Synchronize = Device->DriverFunctions.Synchronize;
472 if(Hooks & HOOK_SYNCHRONIZEACCESS) SurfGDI->SynchronizeAccess = TRUE;
473 if(Hooks & HOOK_GRADIENTFILL) SurfGDI->GradientFill = Device->DriverFunctions.GradientFill;
474
475 SurfGDI->CreateDeviceBitmap = Device->DriverFunctions.CreateDeviceBitmap;
476 SurfGDI->SetPalette = Device->DriverFunctions.SetPalette;
477 SurfGDI->MovePointer = Device->DriverFunctions.MovePointer;
478 SurfGDI->SetPointerShape = (PFN_SetPointerShape)Device->DriverFunctions.SetPointerShape;
479
480 SurfGDI->DriverLock = &Device->DriverLock;
481
482 return TRUE;
483 }
484
485 /*
486 * @implemented
487 */
488 BOOL STDCALL
489 EngModifySurface(
490 IN HSURF hsurf,
491 IN HDEV hdev,
492 IN FLONG flHooks,
493 IN FLONG flSurface,
494 IN DHSURF dhsurf,
495 OUT VOID *pvScan0,
496 IN LONG lDelta,
497 IN VOID *pvReserved)
498 {
499 SURFOBJ *pso;
500
501 pso = EngLockSurface(hsurf);
502 if (pso == NULL)
503 {
504 return FALSE;
505 }
506
507 if (!EngAssociateSurface(hsurf, hdev, flHooks))
508 {
509 EngUnlockSurface(pso);
510
511 return FALSE;
512 }
513
514 pso->dhsurf = dhsurf;
515 pso->lDelta = lDelta;
516 pso->pvScan0 = pvScan0;
517
518 EngUnlockSurface(pso);
519
520 return TRUE;
521 }
522
523 /*
524 * @implemented
525 */
526 BOOL STDCALL
527 EngDeleteSurface(IN HSURF Surface)
528 {
529 FreeGDIHandle((ULONG)Surface);
530 return TRUE;
531 }
532
533 /*
534 * @implemented
535 */
536 BOOL STDCALL
537 EngEraseSurface(SURFOBJ *Surface,
538 RECTL *Rect,
539 ULONG iColor)
540 {
541 return FillSolid(Surface, Rect, iColor);
542 }
543
544 /*
545 * @unimplemented
546 */
547 SURFOBJ * STDCALL
548 EngLockSurface(IN HSURF Surface)
549 {
550 /*
551 * FIXME - don't know if GDIOBJ_LockObj's return value is a SURFOBJ or not...
552 * also, what is HSURF's correct magic #?
553 */
554 #ifdef TODO
555 GDIOBJ_LockObj ( Surface, GDI_OBJECT_TYPE_DONTCARE );
556 #endif
557 return (SURFOBJ*)AccessUserObject((ULONG)Surface);
558 }
559
560 /*
561 * @unimplemented
562 */
563 VOID STDCALL
564 EngUnlockSurface(IN SURFOBJ *Surface)
565 {
566 /*
567 * FIXME what is HSURF's correct magic #?
568 */
569 #ifdef TODO
570 GDIOBJ_UnlockObj ( Surface->hsurf, GDI_OBJECT_TYPE_DONTCARE );
571 #endif
572 }
573 /* EOF */