[WIN32SS]
[reactos.git] / reactos / subsystems / win32 / win32k / objects / dcobjs.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: Functions for creation and destruction of DCs
5 * FILE: subsystems/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 // This didn't work anyway
185 //IntGdiRealizePalette(hDC);
186 }
187
188 PALETTE_ShareUnlockPalette(ppal);
189 DC_UnlockDc(pdc);
190
191 return oldPal;
192 }
193
194 /*
195 * @implemented
196 */
197 HBRUSH
198 APIENTRY
199 NtGdiSelectBrush(
200 IN HDC hDC,
201 IN HBRUSH hBrush)
202 {
203 PDC pDC;
204 HBRUSH hOrgBrush;
205
206 if (hDC == NULL || hBrush == NULL) return NULL;
207
208 pDC = DC_LockDc(hDC);
209 if (!pDC)
210 {
211 return NULL;
212 }
213
214 /* Simply return the user mode value, without checking */
215 hOrgBrush = pDC->pdcattr->hbrush;
216 pDC->pdcattr->hbrush = hBrush;
217 DC_vUpdateFillBrush(pDC);
218
219 DC_UnlockDc(pDC);
220
221 return hOrgBrush;
222 }
223
224 /*
225 * @implemented
226 */
227 HPEN
228 APIENTRY
229 NtGdiSelectPen(
230 IN HDC hDC,
231 IN HPEN hPen)
232 {
233 PDC pDC;
234 HPEN hOrgPen;
235
236 if (hDC == NULL || hPen == NULL) return NULL;
237
238 pDC = DC_LockDc(hDC);
239 if (!pDC)
240 {
241 return NULL;
242 }
243
244 /* Simply return the user mode value, without checking */
245 hOrgPen = pDC->pdcattr->hpen;
246 pDC->pdcattr->hpen = hPen;
247 DC_vUpdateLineBrush(pDC);
248
249 DC_UnlockDc(pDC);
250
251 return hOrgPen;
252 }
253
254 /*
255 * @implemented
256 */
257 HBITMAP
258 APIENTRY
259 NtGdiSelectBitmap(
260 IN HDC hdc,
261 IN HBITMAP hbmp)
262 {
263 PDC pdc;
264 HBITMAP hbmpOld;
265 PSURFACE psurfNew, psurfOld;
266 HRGN hVisRgn;
267 HDC hdcOld;
268 ASSERT_NOGDILOCKS();
269
270 /* Verify parameters */
271 if (hdc == NULL || hbmp == NULL) return NULL;
272
273 /* First lock the DC */
274 pdc = DC_LockDc(hdc);
275 if (!pdc)
276 {
277 return NULL;
278 }
279
280 /* Must be a memory dc to select a bitmap */
281 if (pdc->dctype != DC_TYPE_MEMORY)
282 {
283 DC_UnlockDc(pdc);
284 return NULL;
285 }
286
287 /* Save the old bitmap */
288 psurfOld = pdc->dclevel.pSurface;
289
290 /* Check if there is a bitmap selected */
291 if (psurfOld)
292 {
293 /* Get the old bitmap's handle */
294 hbmpOld = psurfOld->BaseObject.hHmgr;
295 }
296 else
297 {
298 /* Use the default bitmap */
299 hbmpOld = StockObjects[DEFAULT_BITMAP];
300 }
301
302 /* Check if the new bitmap is already selected */
303 if (hbmp == hbmpOld)
304 {
305 /* Unlock the DC and return the old bitmap */
306 DC_UnlockDc(pdc);
307 return hbmpOld;
308 }
309
310 /* Check if the default bitmap was passed */
311 if (hbmp == StockObjects[DEFAULT_BITMAP])
312 {
313 psurfNew = NULL;
314
315 /* Default bitmap is 1x1 pixel */
316 pdc->dclevel.sizl.cx = 1;
317 pdc->dclevel.sizl.cy = 1;
318
319 // HACK
320 psurfNew = SURFACE_ShareLockSurface(hbmp);
321 }
322 else
323 {
324 /* Reference the new bitmap and check if it's valid */
325 psurfNew = SURFACE_ShareLockSurface(hbmp);
326 if (!psurfNew)
327 {
328 DC_UnlockDc(pdc);
329 return NULL;
330 }
331
332 /* Set the bitmap's hdc and check if it was set before */
333 hdcOld = InterlockedCompareExchangePointer((PVOID*)&psurfNew->hdc, hdc, 0);
334 if (hdcOld != NULL)
335 {
336 /* The bitmap is already selected into a different DC */
337 ASSERT(hdcOld != hdc);
338
339 /* Dereference the bitmap, unlock the DC and fail. */
340 SURFACE_ShareUnlockSurface(psurfNew);
341 DC_UnlockDc(pdc);
342 return NULL;
343 }
344
345 /* Copy the bitmap size */
346 pdc->dclevel.sizl = psurfNew->SurfObj.sizlBitmap;
347
348 /* Check if the bitmap is a dibsection */
349 if(psurfNew->hSecure)
350 {
351 /* Set DIBSECTION attribute */
352 pdc->pdcattr->ulDirty_ |= DC_DIBSECTION;
353 }
354 else
355 {
356 /* Remove DIBSECTION attribute */
357 pdc->pdcattr->ulDirty_ &= ~DC_DIBSECTION;
358 }
359 }
360
361 /* Select the new bitmap */
362 pdc->dclevel.pSurface = psurfNew;
363
364 /* Check if there was a bitmap selected before */
365 if (psurfOld)
366 {
367 /* Reset hdc of the old bitmap, it isn't selected anymore */
368 psurfOld->hdc = NULL;
369
370 /* Dereference the old bitmap */
371 SURFACE_ShareUnlockSurface(psurfOld);
372 }
373
374 /* Mark the dc brushes invalid */
375 pdc->pdcattr->ulDirty_ |= DIRTY_FILL | DIRTY_LINE;
376
377 /* FIXME: Improve by using a region without a handle and selecting it */
378 hVisRgn = IntSysCreateRectRgn( 0,
379 0,
380 pdc->dclevel.sizl.cx,
381 pdc->dclevel.sizl.cy);
382
383 if (hVisRgn)
384 {
385 GdiSelectVisRgn(hdc, hVisRgn);
386 GreDeleteObject(hVisRgn);
387 }
388
389 /* Unlock the DC */
390 DC_UnlockDc(pdc);
391
392 /* Return the old bitmap handle */
393 return hbmpOld;
394 }
395
396
397 BOOL
398 APIENTRY
399 NtGdiSelectClipPath(
400 HDC hDC,
401 int Mode)
402 {
403 HRGN hrgnPath;
404 PPATH pPath;
405 BOOL success = FALSE;
406 PDC_ATTR pdcattr;
407 PDC pdc;
408
409 pdc = DC_LockDc(hDC);
410 if (!pdc)
411 {
412 EngSetLastError(ERROR_INVALID_PARAMETER);
413 return FALSE;
414 }
415 pdcattr = pdc->pdcattr;
416
417 pPath = PATH_LockPath(pdc->dclevel.hPath);
418 if (!pPath)
419 {
420 DC_UnlockDc(pdc);
421 return FALSE;
422 }
423
424 /* Check that path is closed */
425 if (pPath->state != PATH_Closed)
426 {
427 EngSetLastError(ERROR_CAN_NOT_COMPLETE);
428 DC_UnlockDc(pdc);
429 return FALSE;
430 }
431
432 /* Construct a region from the path */
433 else if (PATH_PathToRegion(pPath, pdcattr->jFillMode, &hrgnPath))
434 {
435 success = GdiExtSelectClipRgn(pdc, hrgnPath, Mode) != ERROR;
436 GreDeleteObject( hrgnPath );
437
438 /* Empty the path */
439 if (success)
440 PATH_EmptyPath(pPath);
441
442 /* FIXME: Should this function delete the path even if it failed? */
443 }
444
445 PATH_UnlockPath(pPath);
446 DC_UnlockDc(pdc);
447
448 return success;
449 }
450
451 HANDLE
452 APIENTRY
453 NtGdiGetDCObject(HDC hDC, INT ObjectType)
454 {
455 HGDIOBJ SelObject;
456 DC *pdc;
457 PDC_ATTR pdcattr;
458
459 /* From Wine: GetCurrentObject does not SetLastError() on a null object */
460 if(!hDC) return NULL;
461
462 if(!(pdc = DC_LockDc(hDC)))
463 {
464 EngSetLastError(ERROR_INVALID_HANDLE);
465 return NULL;
466 }
467 pdcattr = pdc->pdcattr;
468
469 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
470 DC_vUpdateFillBrush(pdc);
471
472 if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
473 DC_vUpdateLineBrush(pdc);
474
475 switch(ObjectType)
476 {
477 case GDI_OBJECT_TYPE_EXTPEN:
478 case GDI_OBJECT_TYPE_PEN:
479 SelObject = pdcattr->hpen;
480 break;
481
482 case GDI_OBJECT_TYPE_BRUSH:
483 SelObject = pdcattr->hbrush;
484 break;
485
486 case GDI_OBJECT_TYPE_PALETTE:
487 SelObject = pdc->dclevel.hpal;
488 break;
489
490 case GDI_OBJECT_TYPE_FONT:
491 SelObject = pdcattr->hlfntNew;
492 break;
493
494 case GDI_OBJECT_TYPE_BITMAP:
495 {
496 SURFACE *psurf = pdc->dclevel.pSurface;
497 SelObject = psurf ? psurf->BaseObject.hHmgr : NULL;
498 break;
499 }
500
501 case GDI_OBJECT_TYPE_COLORSPACE:
502 DPRINT1("FIXME: NtGdiGetCurrentObject() ObjectType OBJ_COLORSPACE not supported yet!\n");
503 // SelObject = dc->dclevel.pColorSpace.BaseObject.hHmgr; ?
504 SelObject = NULL;
505 break;
506
507 default:
508 SelObject = NULL;
509 EngSetLastError(ERROR_INVALID_PARAMETER);
510 break;
511 }
512
513 DC_UnlockDc(pdc);
514 return SelObject;
515 }
516
517 /* See WINE, MSDN, OSR and Feng Yuan - Windows Graphics Programming Win32 GDI and DirectDraw
518 *
519 * 1st: http://www.codeproject.com/gdi/cliprgnguide.asp is wrong!
520 *
521 * The intersection of the clip with the meta region is not Rao it's API!
522 * Go back and read 7.2 Clipping pages 418-19:
523 * Rao = API & Vis:
524 * 1) The Rao region is the intersection of the API region and the system region,
525 * named after the Microsoft engineer who initially proposed it.
526 * 2) The Rao region can be calculated from the API region and the system region.
527 *
528 * API:
529 * API region is the intersection of the meta region and the clipping region,
530 * clearly named after the fact that it is controlled by GDI API calls.
531 */
532 INT
533 APIENTRY
534 NtGdiGetRandomRgn(
535 HDC hdc,
536 HRGN hrgnDest,
537 INT iCode)
538 {
539 INT ret = 0;
540 PDC pdc;
541 HRGN hrgnSrc = NULL;
542 POINTL ptlOrg;
543
544 pdc = DC_LockDc(hdc);
545 if (!pdc)
546 {
547 EngSetLastError(ERROR_INVALID_PARAMETER);
548 return -1;
549 }
550
551 switch (iCode)
552 {
553 case CLIPRGN:
554 hrgnSrc = pdc->rosdc.hClipRgn;
555 // if (pdc->dclevel.prgnClip) hrgnSrc = pdc->dclevel.prgnClip->BaseObject.hHmgr;
556 break;
557 case METARGN:
558 if (pdc->dclevel.prgnMeta)
559 hrgnSrc = pdc->dclevel.prgnMeta->BaseObject.hHmgr;
560 break;
561 case APIRGN:
562 if (pdc->prgnAPI) hrgnSrc = pdc->prgnAPI->BaseObject.hHmgr;
563 // else if (pdc->dclevel.prgnClip) hrgnSrc = pdc->dclevel.prgnClip->BaseObject.hHmgr;
564 else if (pdc->rosdc.hClipRgn) hrgnSrc = pdc->rosdc.hClipRgn;
565 else if (pdc->dclevel.prgnMeta) hrgnSrc = pdc->dclevel.prgnMeta->BaseObject.hHmgr;
566 break;
567 case SYSRGN:
568 if (pdc->prgnVis)
569 {
570 PREGION prgnDest = REGION_LockRgn(hrgnDest);
571 ret = IntGdiCombineRgn(prgnDest, pdc->prgnVis, 0, RGN_COPY) == ERROR ? -1 : 1;
572 REGION_UnlockRgn(prgnDest);
573 }
574 break;
575 default:
576 hrgnSrc = NULL;
577 }
578
579 if (hrgnSrc)
580 {
581 ret = NtGdiCombineRgn(hrgnDest, hrgnSrc, 0, RGN_COPY) == ERROR ? -1 : 1;
582 }
583
584 if (iCode == SYSRGN)
585 {
586 ptlOrg = pdc->ptlDCOrig;
587 NtGdiOffsetRgn(hrgnDest, ptlOrg.x, ptlOrg.y );
588 }
589
590 DC_UnlockDc(pdc);
591
592 return ret;
593 }
594
595 ULONG
596 APIENTRY
597 NtGdiEnumObjects(
598 IN HDC hdc,
599 IN INT iObjectType,
600 IN ULONG cjBuf,
601 OUT OPTIONAL PVOID pvBuf)
602 {
603 UNIMPLEMENTED;
604 return 0;
605 }
606
607 /* EOF */