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