[WIN32K]
[reactos.git] / reactos / subsystems / win32 / win32k / objects / dcobjs.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Functions for creation and destruction of DCs
5 * FILE: subsystem/win32/win32k/objects/dcobjs.c
6 * PROGRAMER: Timo Kreuzer (timo.kreuzer@rectos.org)
7 */
8
9 #include <win32k.h>
10
11 #define NDEBUG
12 #include <debug.h>
13
14 VOID
15 FASTCALL
16 DC_vUpdateFillBrush(PDC pdc)
17 {
18 PDC_ATTR pdcattr = pdc->pdcattr;
19 PBRUSH pbrFill;
20
21 /* Check if the brush handle has changed */
22 if (pdcattr->hbrush != pdc->dclevel.pbrFill->BaseObject.hHmgr)
23 {
24 /* Try to lock the new brush */
25 pbrFill = BRUSH_ShareLockBrush(pdcattr->hbrush);
26 if (pbrFill)
27 {
28 /* Unlock old brush, set new brush */
29 BRUSH_ShareUnlockBrush(pdc->dclevel.pbrFill);
30 pdc->dclevel.pbrFill = pbrFill;
31
32 /* Mark eboFill as dirty */
33 pdcattr->ulDirty_ |= DIRTY_FILL;
34 }
35 else
36 {
37 /* Invalid brush handle, restore old one */
38 pdcattr->hbrush = pdc->dclevel.pbrFill->BaseObject.hHmgr;
39 }
40 }
41
42 /* Check if the EBRUSHOBJ needs update */
43 if (pdcattr->ulDirty_ & DIRTY_FILL)
44 {
45 /* Update eboFill */
46 EBRUSHOBJ_vUpdate(&pdc->eboFill, pdc->dclevel.pbrFill, pdc);
47 }
48
49 /* Check for DC brush */
50 if (pdcattr->hbrush == StockObjects[DC_BRUSH])
51 {
52 /* ROS HACK, should use surf xlate */
53 /* Update the eboFill's solid color */
54 EBRUSHOBJ_vSetSolidBrushColor(&pdc->eboFill, pdcattr->crPenClr);
55 }
56
57 /* Clear flags */
58 pdcattr->ulDirty_ &= ~(DIRTY_FILL | DC_BRUSH_DIRTY);
59 }
60
61 VOID
62 FASTCALL
63 DC_vUpdateLineBrush(PDC pdc)
64 {
65 PDC_ATTR pdcattr = pdc->pdcattr;
66 PBRUSH pbrLine;
67
68 /* Check if the pen handle has changed */
69 if (pdcattr->hpen != pdc->dclevel.pbrLine->BaseObject.hHmgr)
70 {
71 /* Try to lock the new pen */
72 pbrLine = PEN_ShareLockPen(pdcattr->hpen);
73 if (pbrLine)
74 {
75 /* Unlock old brush, set new brush */
76 BRUSH_ShareUnlockBrush(pdc->dclevel.pbrLine);
77 pdc->dclevel.pbrLine = pbrLine;
78
79 /* Mark eboLine as dirty */
80 pdcattr->ulDirty_ |= DIRTY_LINE;
81 }
82 else
83 {
84 /* Invalid pen handle, restore old one */
85 pdcattr->hpen = pdc->dclevel.pbrLine->BaseObject.hHmgr;
86 }
87 }
88
89 /* Check if the EBRUSHOBJ needs update */
90 if (pdcattr->ulDirty_ & DIRTY_LINE)
91 {
92 /* Update eboLine */
93 EBRUSHOBJ_vUpdate(&pdc->eboLine, pdc->dclevel.pbrLine, pdc);
94 }
95
96 /* Check for DC pen */
97 if (pdcattr->hpen == StockObjects[DC_PEN])
98 {
99 /* Update the eboLine's solid color */
100 EBRUSHOBJ_vSetSolidBrushColor(&pdc->eboLine, pdcattr->crPenClr);
101 }
102
103 /* Clear flags */
104 pdcattr->ulDirty_ &= ~(DIRTY_LINE | DC_PEN_DIRTY);
105 }
106
107 VOID
108 FASTCALL
109 DC_vUpdateTextBrush(PDC pdc)
110 {
111 PDC_ATTR pdcattr = pdc->pdcattr;
112
113 /* Timo : The text brush should never be changed.
114 * Jérôme : Yeah, but its palette must be updated anyway! */
115 if(pdcattr->ulDirty_ & DIRTY_TEXT)
116 EBRUSHOBJ_vUpdate(&pdc->eboText, pbrDefaultBrush, pdc);
117
118 /* Update the eboText's solid color */
119 EBRUSHOBJ_vSetSolidBrushColor(&pdc->eboText, pdcattr->crForegroundClr);
120
121 /* Clear flag */
122 pdcattr->ulDirty_ &= ~DIRTY_TEXT;
123 }
124
125 VOID
126 FASTCALL
127 DC_vUpdateBackgroundBrush(PDC pdc)
128 {
129 PDC_ATTR pdcattr = pdc->pdcattr;
130
131 if(pdcattr->ulDirty_ & DIRTY_BACKGROUND)
132 EBRUSHOBJ_vUpdate(&pdc->eboBackground, pbrDefaultBrush, pdc);
133
134 /* Update the eboBackground's solid color */
135 EBRUSHOBJ_vSetSolidBrushColor(&pdc->eboBackground, pdcattr->crBackgroundClr);
136
137 /* Clear flag */
138 pdcattr->ulDirty_ &= ~DIRTY_BACKGROUND;
139 }
140
141 HPALETTE
142 FASTCALL
143 GdiSelectPalette(
144 HDC hDC,
145 HPALETTE hpal,
146 BOOL ForceBackground)
147 {
148 PDC pdc;
149 HPALETTE oldPal = NULL;
150 PPALETTE ppal;
151
152 // FIXME: mark the palette as a [fore\back]ground pal
153 pdc = DC_LockDc(hDC);
154 if (!pdc)
155 {
156 return NULL;
157 }
158
159 /* Check if this is a valid palette handle */
160 ppal = PALETTE_ShareLockPalette(hpal);
161 if (!ppal)
162 {
163 DC_UnlockDc(pdc);
164 return NULL;
165 }
166
167 /* Is this a valid palette for this depth? */
168 if ((BitsPerFormat(pdc->dclevel.pSurface->SurfObj.iBitmapFormat) <= 8
169 && (ppal->flFlags & PAL_INDEXED)) ||
170 (BitsPerFormat(pdc->dclevel.pSurface->SurfObj.iBitmapFormat) > 8))
171 {
172 /* Get old palette, set new one */
173 oldPal = pdc->dclevel.hpal;
174 pdc->dclevel.hpal = hpal;
175 DC_vSelectPalette(pdc, ppal);
176
177 /* Mark the brushes invalid */
178 pdc->pdcattr->ulDirty_ |= DIRTY_FILL | DIRTY_LINE |
179 DIRTY_BACKGROUND | DIRTY_TEXT;
180 }
181
182 if(pdc->dctype == DCTYPE_MEMORY)
183 {
184 IntGdiRealizePalette(pdc);
185 }
186
187 PALETTE_ShareUnlockPalette(ppal);
188 DC_UnlockDc(pdc);
189
190 return oldPal;
191 }
192
193 /*
194 * @implemented
195 */
196 HBRUSH
197 APIENTRY
198 NtGdiSelectBrush(
199 IN HDC hDC,
200 IN HBRUSH hBrush)
201 {
202 PDC pDC;
203 HBRUSH hOrgBrush;
204
205 if (hDC == NULL || hBrush == NULL) return NULL;
206
207 pDC = DC_LockDc(hDC);
208 if (!pDC)
209 {
210 return NULL;
211 }
212
213 /* Simply return the user mode value, without checking */
214 hOrgBrush = pDC->pdcattr->hbrush;
215 pDC->pdcattr->hbrush = hBrush;
216 DC_vUpdateFillBrush(pDC);
217
218 DC_UnlockDc(pDC);
219
220 return hOrgBrush;
221 }
222
223 /*
224 * @implemented
225 */
226 HPEN
227 APIENTRY
228 NtGdiSelectPen(
229 IN HDC hDC,
230 IN HPEN hPen)
231 {
232 PDC pDC;
233 HPEN hOrgPen;
234
235 if (hDC == NULL || hPen == NULL) return NULL;
236
237 pDC = DC_LockDc(hDC);
238 if (!pDC)
239 {
240 return NULL;
241 }
242
243 /* Simply return the user mode value, without checking */
244 hOrgPen = pDC->pdcattr->hpen;
245 pDC->pdcattr->hpen = hPen;
246 DC_vUpdateLineBrush(pDC);
247
248 DC_UnlockDc(pDC);
249
250 return hOrgPen;
251 }
252
253 /*
254 * @implemented
255 */
256 HBITMAP
257 APIENTRY
258 NtGdiSelectBitmap(
259 IN HDC hdc,
260 IN HBITMAP hbmp)
261 {
262 PDC pdc;
263 PDC_ATTR pdcattr;
264 HBITMAP hbmpOld;
265 PSURFACE psurfNew;
266 HRGN hVisRgn;
267 SIZEL sizlBitmap = {1, 1};
268 HDC hdcOld;
269 ASSERT_NOGDILOCKS();
270
271 /* Verify parameters */
272 if (hdc == NULL || hbmp == NULL) return NULL;
273
274 /* First lock the DC */
275 pdc = DC_LockDc(hdc);
276 if (!pdc)
277 {
278 return NULL;
279 }
280 pdcattr = pdc->pdcattr;
281
282 /* Must be a memory dc to select a bitmap */
283 if (pdc->dctype != DC_TYPE_MEMORY)
284 {
285 DC_UnlockDc(pdc);
286 return NULL;
287 }
288
289 /* Check if there was a bitmap selected before */
290 if (pdc->dclevel.pSurface)
291 {
292 /* Return its handle */
293 hbmpOld = pdc->dclevel.pSurface->BaseObject.hHmgr;
294 }
295 else
296 {
297 /* Return default bitmap */
298 hbmpOld = StockObjects[DEFAULT_BITMAP];
299 }
300
301 /* Check if the default bitmap was passed */
302 if (hbmp == StockObjects[DEFAULT_BITMAP])
303 {
304 psurfNew = NULL;
305
306 // HACK
307 psurfNew = SURFACE_ShareLockSurface(hbmp);
308 }
309 else
310 {
311 /* Reference the new bitmap and check if it's valid */
312 psurfNew = SURFACE_ShareLockSurface(hbmp);
313 if (!psurfNew)
314 {
315 DC_UnlockDc(pdc);
316 return NULL;
317 }
318
319 /* Set the bitmp's hdc */
320 hdcOld = InterlockedCompareExchangePointer((PVOID*)&psurfNew->hdc, hdc, 0);
321 if (hdcOld != NULL && hdcOld != hdc)
322 {
323 /* The bitmap is already selected, fail */
324 SURFACE_ShareUnlockSurface(psurfNew);
325 DC_UnlockDc(pdc);
326 return NULL;
327 }
328
329 /* Get the bitmap size */
330 sizlBitmap = psurfNew->SurfObj.sizlBitmap;
331
332 /* Check if the bitmap is a dibsection */
333 if(psurfNew->hSecure)
334 {
335 /* Set DIBSECTION attribute */
336 pdcattr->ulDirty_ |= DC_DIBSECTION;
337 }
338 else
339 {
340 pdcattr->ulDirty_ &= ~DC_DIBSECTION;
341 }
342 }
343
344 /* Select the new surface, release the old */
345 DC_vSelectSurface(pdc, psurfNew);
346
347 /* Set the new size */
348 pdc->dclevel.sizl = sizlBitmap;
349
350 /* Release one reference we added */
351 SURFACE_ShareUnlockSurface(psurfNew);
352
353 /* Mark the dc brushes invalid */
354 pdcattr->ulDirty_ |= DIRTY_FILL | DIRTY_LINE;
355
356 /* Unlock the DC */
357 DC_UnlockDc(pdc);
358
359 /* FIXME; improve by using a region without a handle and selecting it */
360 hVisRgn = IntSysCreateRectRgn( 0,
361 0,
362 sizlBitmap.cx,
363 sizlBitmap.cy);
364 if (hVisRgn)
365 {
366 GdiSelectVisRgn(hdc, hVisRgn);
367 REGION_FreeRgnByHandle(hVisRgn);
368 }
369
370 /* Return the old bitmp handle */
371 return hbmpOld;
372 }
373
374
375 BOOL
376 APIENTRY
377 NtGdiSelectClipPath(
378 HDC hDC,
379 int Mode)
380 {
381 HRGN hrgnPath;
382 PPATH pPath;
383 BOOL success = FALSE;
384 PDC_ATTR pdcattr;
385 PDC pdc;
386
387 pdc = DC_LockDc(hDC);
388 if (!pdc)
389 {
390 EngSetLastError(ERROR_INVALID_PARAMETER);
391 return FALSE;
392 }
393 pdcattr = pdc->pdcattr;
394
395 pPath = PATH_LockPath(pdc->dclevel.hPath);
396 if (!pPath)
397 {
398 DC_UnlockDc(pdc);
399 return FALSE;
400 }
401
402 /* Check that path is closed */
403 if (pPath->state != PATH_Closed)
404 {
405 EngSetLastError(ERROR_CAN_NOT_COMPLETE);
406 DC_UnlockDc(pdc);
407 return FALSE;
408 }
409
410 /* Construct a region from the path */
411 else if (PATH_PathToRegion(pPath, pdcattr->jFillMode, &hrgnPath))
412 {
413 success = GdiExtSelectClipRgn(pdc, hrgnPath, Mode) != ERROR;
414 GreDeleteObject( hrgnPath );
415
416 /* Empty the path */
417 if (success)
418 PATH_EmptyPath(pPath);
419
420 /* FIXME: Should this function delete the path even if it failed? */
421 }
422
423 PATH_UnlockPath(pPath);
424 DC_UnlockDc(pdc);
425
426 return success;
427 }
428
429 HANDLE
430 APIENTRY
431 NtGdiGetDCObject(HDC hDC, INT ObjectType)
432 {
433 HGDIOBJ SelObject;
434 DC *pdc;
435 PDC_ATTR pdcattr;
436
437 /* From Wine: GetCurrentObject does not SetLastError() on a null object */
438 if(!hDC) return NULL;
439
440 if(!(pdc = DC_LockDc(hDC)))
441 {
442 EngSetLastError(ERROR_INVALID_HANDLE);
443 return NULL;
444 }
445 pdcattr = pdc->pdcattr;
446
447 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
448 DC_vUpdateFillBrush(pdc);
449
450 if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
451 DC_vUpdateLineBrush(pdc);
452
453 switch(ObjectType)
454 {
455 case GDI_OBJECT_TYPE_EXTPEN:
456 case GDI_OBJECT_TYPE_PEN:
457 SelObject = pdcattr->hpen;
458 break;
459
460 case GDI_OBJECT_TYPE_BRUSH:
461 SelObject = pdcattr->hbrush;
462 break;
463
464 case GDI_OBJECT_TYPE_PALETTE:
465 SelObject = pdc->dclevel.hpal;
466 break;
467
468 case GDI_OBJECT_TYPE_FONT:
469 SelObject = pdcattr->hlfntNew;
470 break;
471
472 case GDI_OBJECT_TYPE_BITMAP:
473 {
474 SURFACE *psurf = pdc->dclevel.pSurface;
475 SelObject = psurf ? psurf->BaseObject.hHmgr : NULL;
476 break;
477 }
478
479 case GDI_OBJECT_TYPE_COLORSPACE:
480 DPRINT1("FIXME: NtGdiGetCurrentObject() ObjectType OBJ_COLORSPACE not supported yet!\n");
481 // SelObject = dc->dclevel.pColorSpace.BaseObject.hHmgr; ?
482 SelObject = NULL;
483 break;
484
485 default:
486 SelObject = NULL;
487 EngSetLastError(ERROR_INVALID_PARAMETER);
488 break;
489 }
490
491 DC_UnlockDc(pdc);
492 return SelObject;
493 }
494
495 /* See wine, msdn, osr and Feng Yuan - Windows Graphics Programming Win32 Gdi And Directdraw
496
497 1st: http://www.codeproject.com/gdi/cliprgnguide.asp is wrong!
498
499 The intersection of the clip with the meta region is not Rao it's API!
500 Go back and read 7.2 Clipping pages 418-19:
501 Rao = API & Vis:
502 1) The Rao region is the intersection of the API region and the system region,
503 named after the Microsoft engineer who initially proposed it.
504 2) The Rao region can be calculated from the API region and the system region.
505
506 API:
507 API region is the intersection of the meta region and the clipping region,
508 clearly named after the fact that it is controlled by GDI API calls.
509 */
510 INT
511 APIENTRY
512 NtGdiGetRandomRgn(
513 HDC hdc,
514 HRGN hrgnDest,
515 INT iCode)
516 {
517 INT ret = 0;
518 PDC pdc;
519 HRGN hrgnSrc = NULL;
520 POINTL ptlOrg;
521
522 pdc = DC_LockDc(hdc);
523 if (!pdc)
524 {
525 EngSetLastError(ERROR_INVALID_HANDLE);
526 return -1;
527 }
528
529 switch (iCode)
530 {
531 case CLIPRGN:
532 hrgnSrc = pdc->rosdc.hClipRgn;
533 // if (pdc->dclevel.prgnClip) hrgnSrc = pdc->dclevel.prgnClip->BaseObject.hHmgr;
534 break;
535 case METARGN:
536 if (pdc->dclevel.prgnMeta)
537 hrgnSrc = pdc->dclevel.prgnMeta->BaseObject.hHmgr;
538 break;
539 case APIRGN:
540 if (pdc->prgnAPI) hrgnSrc = pdc->prgnAPI->BaseObject.hHmgr;
541 // else if (pdc->dclevel.prgnClip) hrgnSrc = pdc->dclevel.prgnClip->BaseObject.hHmgr;
542 else if (pdc->rosdc.hClipRgn) hrgnSrc = pdc->rosdc.hClipRgn;
543 else if (pdc->dclevel.prgnMeta) hrgnSrc = pdc->dclevel.prgnMeta->BaseObject.hHmgr;
544 break;
545 case SYSRGN:
546 if (pdc->prgnVis) hrgnSrc = pdc->prgnVis->BaseObject.hHmgr;
547 break;
548 default:
549 hrgnSrc = NULL;
550 }
551
552 if (hrgnSrc)
553 {
554 ret = NtGdiCombineRgn(hrgnDest, hrgnSrc, 0, RGN_COPY) == ERROR ? -1 : 1;
555 }
556
557 if (iCode == SYSRGN)
558 {
559 ptlOrg = pdc->ptlDCOrig;
560 NtGdiOffsetRgn(hrgnDest, ptlOrg.x, ptlOrg.y );
561 }
562
563 DC_UnlockDc(pdc);
564
565 return ret;
566 }
567
568 ULONG
569 APIENTRY
570 NtGdiEnumObjects(
571 IN HDC hdc,
572 IN INT iObjectType,
573 IN ULONG cjBuf,
574 OUT OPTIONAL PVOID pvBuf)
575 {
576 UNIMPLEMENTED;
577 return 0;
578 }
579