[CMAKE]
[reactos.git] / 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 // 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 PDC_ATTR pdcattr;
265 HBITMAP hbmpOld;
266 PSURFACE psurfNew;
267 HRGN hVisRgn;
268 SIZEL sizlBitmap = {1, 1};
269 HDC hdcOld;
270 ASSERT_NOGDILOCKS();
271
272 /* Verify parameters */
273 if (hdc == NULL || hbmp == NULL) return NULL;
274
275 /* First lock the DC */
276 pdc = DC_LockDc(hdc);
277 if (!pdc)
278 {
279 return NULL;
280 }
281 pdcattr = pdc->pdcattr;
282
283 /* Must be a memory dc to select a bitmap */
284 if (pdc->dctype != DC_TYPE_MEMORY)
285 {
286 DC_UnlockDc(pdc);
287 return NULL;
288 }
289
290 /* Check if there was a bitmap selected before */
291 if (pdc->dclevel.pSurface)
292 {
293 /* Return its handle */
294 hbmpOld = pdc->dclevel.pSurface->BaseObject.hHmgr;
295 }
296 else
297 {
298 /* Return default bitmap */
299 hbmpOld = StockObjects[DEFAULT_BITMAP];
300 }
301
302 /* Check if the default bitmap was passed */
303 if (hbmp == StockObjects[DEFAULT_BITMAP])
304 {
305 psurfNew = NULL;
306
307 // HACK
308 psurfNew = SURFACE_ShareLockSurface(hbmp);
309 }
310 else
311 {
312 /* Reference the new bitmap and check if it's valid */
313 psurfNew = SURFACE_ShareLockSurface(hbmp);
314 if (!psurfNew)
315 {
316 DC_UnlockDc(pdc);
317 return NULL;
318 }
319
320 /* Set the bitmp's hdc */
321 hdcOld = InterlockedCompareExchangePointer((PVOID*)&psurfNew->hdc, hdc, 0);
322 if (hdcOld != NULL && hdcOld != hdc)
323 {
324 /* The bitmap is already selected, fail */
325 SURFACE_ShareUnlockSurface(psurfNew);
326 DC_UnlockDc(pdc);
327 return NULL;
328 }
329
330 /* Get the bitmap size */
331 sizlBitmap = psurfNew->SurfObj.sizlBitmap;
332
333 /* Check if the bitmap is a dibsection */
334 if(psurfNew->hSecure)
335 {
336 /* Set DIBSECTION attribute */
337 pdcattr->ulDirty_ |= DC_DIBSECTION;
338 }
339 else
340 {
341 pdcattr->ulDirty_ &= ~DC_DIBSECTION;
342 }
343 }
344
345 /* Select the new surface, release the old */
346 DC_vSelectSurface(pdc, psurfNew);
347
348 /* Set the new size */
349 pdc->dclevel.sizl = sizlBitmap;
350
351 /* Release one reference we added */
352 SURFACE_ShareUnlockSurface(psurfNew);
353
354 /* Mark the dc brushes invalid */
355 pdcattr->ulDirty_ |= DIRTY_FILL | DIRTY_LINE;
356
357 /* Unlock the DC */
358 DC_UnlockDc(pdc);
359
360 /* FIXME; improve by using a region without a handle and selecting it */
361 hVisRgn = IntSysCreateRectRgn( 0,
362 0,
363 sizlBitmap.cx,
364 sizlBitmap.cy);
365 if (hVisRgn)
366 {
367 GdiSelectVisRgn(hdc, hVisRgn);
368 GreDeleteObject(hVisRgn);
369 }
370
371 /* Return the old bitmap handle */
372 return hbmpOld;
373 }
374
375
376 BOOL
377 APIENTRY
378 NtGdiSelectClipPath(
379 HDC hDC,
380 int Mode)
381 {
382 HRGN hrgnPath;
383 PPATH pPath;
384 BOOL success = FALSE;
385 PDC_ATTR pdcattr;
386 PDC pdc;
387
388 pdc = DC_LockDc(hDC);
389 if (!pdc)
390 {
391 EngSetLastError(ERROR_INVALID_PARAMETER);
392 return FALSE;
393 }
394 pdcattr = pdc->pdcattr;
395
396 pPath = PATH_LockPath(pdc->dclevel.hPath);
397 if (!pPath)
398 {
399 DC_UnlockDc(pdc);
400 return FALSE;
401 }
402
403 /* Check that path is closed */
404 if (pPath->state != PATH_Closed)
405 {
406 EngSetLastError(ERROR_CAN_NOT_COMPLETE);
407 DC_UnlockDc(pdc);
408 return FALSE;
409 }
410
411 /* Construct a region from the path */
412 else if (PATH_PathToRegion(pPath, pdcattr->jFillMode, &hrgnPath))
413 {
414 success = GdiExtSelectClipRgn(pdc, hrgnPath, Mode) != ERROR;
415 GreDeleteObject( hrgnPath );
416
417 /* Empty the path */
418 if (success)
419 PATH_EmptyPath(pPath);
420
421 /* FIXME: Should this function delete the path even if it failed? */
422 }
423
424 PATH_UnlockPath(pPath);
425 DC_UnlockDc(pdc);
426
427 return success;
428 }
429
430 HANDLE
431 APIENTRY
432 NtGdiGetDCObject(HDC hDC, INT ObjectType)
433 {
434 HGDIOBJ SelObject;
435 DC *pdc;
436 PDC_ATTR pdcattr;
437
438 /* From Wine: GetCurrentObject does not SetLastError() on a null object */
439 if(!hDC) return NULL;
440
441 if(!(pdc = DC_LockDc(hDC)))
442 {
443 EngSetLastError(ERROR_INVALID_HANDLE);
444 return NULL;
445 }
446 pdcattr = pdc->pdcattr;
447
448 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
449 DC_vUpdateFillBrush(pdc);
450
451 if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
452 DC_vUpdateLineBrush(pdc);
453
454 switch(ObjectType)
455 {
456 case GDI_OBJECT_TYPE_EXTPEN:
457 case GDI_OBJECT_TYPE_PEN:
458 SelObject = pdcattr->hpen;
459 break;
460
461 case GDI_OBJECT_TYPE_BRUSH:
462 SelObject = pdcattr->hbrush;
463 break;
464
465 case GDI_OBJECT_TYPE_PALETTE:
466 SelObject = pdc->dclevel.hpal;
467 break;
468
469 case GDI_OBJECT_TYPE_FONT:
470 SelObject = pdcattr->hlfntNew;
471 break;
472
473 case GDI_OBJECT_TYPE_BITMAP:
474 {
475 SURFACE *psurf = pdc->dclevel.pSurface;
476 SelObject = psurf ? psurf->BaseObject.hHmgr : NULL;
477 break;
478 }
479
480 case GDI_OBJECT_TYPE_COLORSPACE:
481 DPRINT1("FIXME: NtGdiGetCurrentObject() ObjectType OBJ_COLORSPACE not supported yet!\n");
482 // SelObject = dc->dclevel.pColorSpace.BaseObject.hHmgr; ?
483 SelObject = NULL;
484 break;
485
486 default:
487 SelObject = NULL;
488 EngSetLastError(ERROR_INVALID_PARAMETER);
489 break;
490 }
491
492 DC_UnlockDc(pdc);
493 return SelObject;
494 }
495
496 /* See wine, msdn, osr and Feng Yuan - Windows Graphics Programming Win32 Gdi And Directdraw
497
498 1st: http://www.codeproject.com/gdi/cliprgnguide.asp is wrong!
499
500 The intersection of the clip with the meta region is not Rao it's API!
501 Go back and read 7.2 Clipping pages 418-19:
502 Rao = API & Vis:
503 1) The Rao region is the intersection of the API region and the system region,
504 named after the Microsoft engineer who initially proposed it.
505 2) The Rao region can be calculated from the API region and the system region.
506
507 API:
508 API region is the intersection of the meta region and the clipping region,
509 clearly named after the fact that it is controlled by GDI API calls.
510 */
511 INT
512 APIENTRY
513 NtGdiGetRandomRgn(
514 HDC hdc,
515 HRGN hrgnDest,
516 INT iCode)
517 {
518 INT ret = 0;
519 PDC pdc;
520 HRGN hrgnSrc = NULL;
521 POINTL ptlOrg;
522
523 pdc = DC_LockDc(hdc);
524 if (!pdc)
525 {
526 EngSetLastError(ERROR_INVALID_PARAMETER);
527 return -1;
528 }
529
530 switch (iCode)
531 {
532 case CLIPRGN:
533 hrgnSrc = pdc->rosdc.hClipRgn;
534 // if (pdc->dclevel.prgnClip) hrgnSrc = pdc->dclevel.prgnClip->BaseObject.hHmgr;
535 break;
536 case METARGN:
537 if (pdc->dclevel.prgnMeta)
538 hrgnSrc = pdc->dclevel.prgnMeta->BaseObject.hHmgr;
539 break;
540 case APIRGN:
541 if (pdc->prgnAPI) hrgnSrc = pdc->prgnAPI->BaseObject.hHmgr;
542 // else if (pdc->dclevel.prgnClip) hrgnSrc = pdc->dclevel.prgnClip->BaseObject.hHmgr;
543 else if (pdc->rosdc.hClipRgn) hrgnSrc = pdc->rosdc.hClipRgn;
544 else if (pdc->dclevel.prgnMeta) hrgnSrc = pdc->dclevel.prgnMeta->BaseObject.hHmgr;
545 break;
546 case SYSRGN:
547 if (pdc->prgnVis)
548 {
549 PREGION prgnDest = REGION_LockRgn(hrgnDest);
550 ret = IntGdiCombineRgn(prgnDest, pdc->prgnVis, 0, RGN_COPY) == ERROR ? -1 : 1;
551 REGION_UnlockRgn(prgnDest);
552 }
553 break;
554 default:
555 hrgnSrc = NULL;
556 }
557
558 if (hrgnSrc)
559 {
560 ret = NtGdiCombineRgn(hrgnDest, hrgnSrc, 0, RGN_COPY) == ERROR ? -1 : 1;
561 }
562
563 if (iCode == SYSRGN)
564 {
565 ptlOrg = pdc->ptlDCOrig;
566 NtGdiOffsetRgn(hrgnDest, ptlOrg.x, ptlOrg.y );
567 }
568
569 DC_UnlockDc(pdc);
570
571 return ret;
572 }
573
574 ULONG
575 APIENTRY
576 NtGdiEnumObjects(
577 IN HDC hdc,
578 IN INT iObjectType,
579 IN ULONG cjBuf,
580 OUT OPTIONAL PVOID pvBuf)
581 {
582 UNIMPLEMENTED;
583 return 0;
584 }
585