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