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)
16 DC_vUpdateFillBrush(PDC pdc
)
18 PDC_ATTR pdcattr
= pdc
->pdcattr
;
21 /* Check if the brush handle has changed */
22 if (pdcattr
->hbrush
!= pdc
->dclevel
.pbrFill
->BaseObject
.hHmgr
)
24 /* Try to lock the new brush */
25 pbrFill
= BRUSH_ShareLockBrush(pdcattr
->hbrush
);
28 /* Unlock old brush, set new brush */
29 BRUSH_ShareUnlockBrush(pdc
->dclevel
.pbrFill
);
30 pdc
->dclevel
.pbrFill
= pbrFill
;
32 /* Mark eboFill as dirty */
33 pdcattr
->ulDirty_
|= DIRTY_FILL
;
37 /* Invalid brush handle, restore old one */
38 pdcattr
->hbrush
= pdc
->dclevel
.pbrFill
->BaseObject
.hHmgr
;
42 /* Check if the EBRUSHOBJ needs update */
43 if (pdcattr
->ulDirty_
& DIRTY_FILL
)
46 EBRUSHOBJ_vUpdateFromDC(&pdc
->eboFill
, pdc
->dclevel
.pbrFill
, pdc
);
49 /* Check for DC brush */
50 if (pdcattr
->hbrush
== StockObjects
[DC_BRUSH
])
52 /* ROS HACK, should use surf xlate */
53 /* Update the eboFill's solid color */
54 EBRUSHOBJ_vSetSolidRGBColor(&pdc
->eboFill
, pdcattr
->crPenClr
);
58 pdcattr
->ulDirty_
&= ~(DIRTY_FILL
| DC_BRUSH_DIRTY
);
63 DC_vUpdateLineBrush(PDC pdc
)
65 PDC_ATTR pdcattr
= pdc
->pdcattr
;
68 /* Check if the pen handle has changed */
69 if (pdcattr
->hpen
!= pdc
->dclevel
.pbrLine
->BaseObject
.hHmgr
)
71 /* Try to lock the new pen */
72 pbrLine
= PEN_ShareLockPen(pdcattr
->hpen
);
75 /* Unlock old brush, set new brush */
76 BRUSH_ShareUnlockBrush(pdc
->dclevel
.pbrLine
);
77 pdc
->dclevel
.pbrLine
= pbrLine
;
79 /* Mark eboLine as dirty */
80 pdcattr
->ulDirty_
|= DIRTY_LINE
;
84 /* Invalid pen handle, restore old one */
85 pdcattr
->hpen
= pdc
->dclevel
.pbrLine
->BaseObject
.hHmgr
;
89 /* Check if the EBRUSHOBJ needs update */
90 if (pdcattr
->ulDirty_
& DIRTY_LINE
)
93 EBRUSHOBJ_vUpdateFromDC(&pdc
->eboLine
, pdc
->dclevel
.pbrLine
, pdc
);
96 /* Check for DC pen */
97 if (pdcattr
->hpen
== StockObjects
[DC_PEN
])
99 /* Update the eboLine's solid color */
100 EBRUSHOBJ_vSetSolidRGBColor(&pdc
->eboLine
, pdcattr
->crPenClr
);
104 pdcattr
->ulDirty_
&= ~(DIRTY_LINE
| DC_PEN_DIRTY
);
109 DC_vUpdateTextBrush(PDC pdc
)
111 PDC_ATTR pdcattr
= pdc
->pdcattr
;
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_vUpdateFromDC(&pdc
->eboText
, pbrDefaultBrush
, pdc
);
118 /* Update the eboText's solid color */
119 EBRUSHOBJ_vSetSolidRGBColor(&pdc
->eboText
, pdcattr
->crForegroundClr
);
122 pdcattr
->ulDirty_
&= ~DIRTY_TEXT
;
127 DC_vUpdateBackgroundBrush(PDC pdc
)
129 PDC_ATTR pdcattr
= pdc
->pdcattr
;
131 if(pdcattr
->ulDirty_
& DIRTY_BACKGROUND
)
132 EBRUSHOBJ_vUpdateFromDC(&pdc
->eboBackground
, pbrDefaultBrush
, pdc
);
134 /* Update the eboBackground's solid color */
135 EBRUSHOBJ_vSetSolidRGBColor(&pdc
->eboBackground
, pdcattr
->crBackgroundClr
);
138 pdcattr
->ulDirty_
&= ~DIRTY_BACKGROUND
;
143 DC_vSetBrushOrigin(PDC pdc
, LONG x
, LONG y
)
145 /* Set the brush origin */
146 pdc
->dclevel
.ptlBrushOrigin
.x
= x
;
147 pdc
->dclevel
.ptlBrushOrigin
.y
= y
;
149 /* Set the fill origin */
150 pdc
->ptlFillOrigin
.x
= x
+ pdc
->ptlDCOrig
.x
;
151 pdc
->ptlFillOrigin
.y
= y
+ pdc
->ptlDCOrig
.y
;
155 * \name NtGdiSetBrushOrg
157 * \brief Sets the brush origin that GDI uses when drawing with pattern
158 * brushes. The brush origin is relative to the DC origin.
162 _Success_(return != FALSE
)
169 _Out_opt_ LPPOINT pptOut
)
174 pdc
= DC_LockDc(hdc
);
177 EngSetLastError(ERROR_INVALID_HANDLE
);
181 /* Check if the old origin was requested */
184 /* Enter SEH for buffer transfer */
187 /* Probe and copy the old origin */
188 ProbeForWrite(pptOut
, sizeof(POINT
), 1);
189 *pptOut
= pdc
->pdcattr
->ptlBrushOrigin
;
191 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
194 _SEH2_YIELD(return FALSE
);
199 /* Call the internal function */
200 DC_vSetBrushOrigin(pdc
, x
, y
);
202 /* Unlock the DC and return success */
212 BOOL ForceBackground
)
215 HPALETTE oldPal
= NULL
;
218 // FIXME: Mark the palette as a [fore\back]ground pal
219 pdc
= DC_LockDc(hDC
);
225 /* Check if this is a valid palette handle */
226 ppal
= PALETTE_ShareLockPalette(hpal
);
233 /* Is this a valid palette for this depth? */
234 if ((!pdc
->dclevel
.pSurface
) ||
235 (BitsPerFormat(pdc
->dclevel
.pSurface
->SurfObj
.iBitmapFormat
) <= 8
236 && (ppal
->flFlags
& PAL_INDEXED
)) ||
237 (BitsPerFormat(pdc
->dclevel
.pSurface
->SurfObj
.iBitmapFormat
) > 8))
239 /* Get old palette, set new one */
240 oldPal
= pdc
->dclevel
.hpal
;
241 pdc
->dclevel
.hpal
= hpal
;
242 DC_vSelectPalette(pdc
, ppal
);
244 /* Mark the brushes invalid */
245 pdc
->pdcattr
->ulDirty_
|= DIRTY_FILL
| DIRTY_LINE
|
246 DIRTY_BACKGROUND
| DIRTY_TEXT
;
249 if(pdc
->dctype
== DCTYPE_MEMORY
)
251 // This didn't work anyway
252 //IntGdiRealizePalette(hDC);
255 PALETTE_ShareUnlockPalette(ppal
);
273 if (hDC
== NULL
|| hBrush
== NULL
) return NULL
;
275 pDC
= DC_LockDc(hDC
);
281 /* Simply return the user mode value, without checking */
282 hOrgBrush
= pDC
->pdcattr
->hbrush
;
283 pDC
->pdcattr
->hbrush
= hBrush
;
284 DC_vUpdateFillBrush(pDC
);
303 if (hDC
== NULL
|| hPen
== NULL
) return NULL
;
305 pDC
= DC_LockDc(hDC
);
311 /* Simply return the user mode value, without checking */
312 hOrgPen
= pDC
->pdcattr
->hpen
;
313 pDC
->pdcattr
->hpen
= hPen
;
314 DC_vUpdateLineBrush(pDC
);
332 PSURFACE psurfNew
, psurfOld
;
338 /* Verify parameters */
339 if (hdc
== NULL
|| hbmp
== NULL
) return NULL
;
341 /* First lock the DC */
342 pdc
= DC_LockDc(hdc
);
348 /* Must be a memory dc to select a bitmap */
349 if (pdc
->dctype
!= DC_TYPE_MEMORY
)
355 /* Save the old bitmap */
356 psurfOld
= pdc
->dclevel
.pSurface
;
358 /* Check if there is a bitmap selected */
361 /* Get the old bitmap's handle */
362 hbmpOld
= psurfOld
->BaseObject
.hHmgr
;
366 /* Use the default bitmap */
367 hbmpOld
= StockObjects
[DEFAULT_BITMAP
];
370 /* Check if the new bitmap is already selected */
373 /* Unlock the DC and return the old bitmap */
378 /* Check if the default bitmap was passed */
379 if (hbmp
== StockObjects
[DEFAULT_BITMAP
])
383 /* Default bitmap is 1x1 pixel */
384 pdc
->dclevel
.sizl
.cx
= 1;
385 pdc
->dclevel
.sizl
.cy
= 1;
389 /* Reference the new bitmap and check if it's valid */
390 psurfNew
= SURFACE_ShareLockSurface(hbmp
);
397 /* Check if the bitmap is compatile with the dc */
398 cBitsPixel
= gajBitsPerFormat
[psurfNew
->SurfObj
.iBitmapFormat
];
399 if ((cBitsPixel
!= 1) &&
400 (cBitsPixel
!= pdc
->ppdev
->gdiinfo
.cBitsPixel
) &&
401 (psurfNew
->hSecure
== NULL
))
403 /* Dereference the bitmap, unlock the DC and fail. */
404 SURFACE_ShareUnlockSurface(psurfNew
);
409 /* Set the bitmap's hdc and check if it was set before */
410 hdcOld
= InterlockedCompareExchangePointer((PVOID
*)&psurfNew
->hdc
, hdc
, 0);
413 /* The bitmap is already selected into a different DC */
414 ASSERT(hdcOld
!= hdc
);
416 /* Dereference the bitmap, unlock the DC and fail. */
417 SURFACE_ShareUnlockSurface(psurfNew
);
422 /* Copy the bitmap size */
423 pdc
->dclevel
.sizl
= psurfNew
->SurfObj
.sizlBitmap
;
425 /* Check if the bitmap is a dibsection */
426 if (psurfNew
->hSecure
)
428 /* Set DIBSECTION attribute */
429 pdc
->pdcattr
->ulDirty_
|= DC_DIBSECTION
;
433 /* Remove DIBSECTION attribute */
434 pdc
->pdcattr
->ulDirty_
&= ~DC_DIBSECTION
;
438 /* Select the new bitmap */
439 pdc
->dclevel
.pSurface
= psurfNew
;
441 /* Check if there was a bitmap selected before */
444 /* Reset hdc of the old bitmap, it isn't selected anymore */
445 psurfOld
->hdc
= NULL
;
447 /* Dereference the old bitmap */
448 SURFACE_ShareUnlockSurface(psurfOld
);
451 /* Mark the dc brushes invalid */
452 pdc
->pdcattr
->ulDirty_
|= DIRTY_FILL
| DIRTY_LINE
;
454 /* FIXME: Improve by using a region without a handle and selecting it */
455 VisRgn
= IntSysCreateRectpRgn( 0,
457 pdc
->dclevel
.sizl
.cx
,
458 pdc
->dclevel
.sizl
.cy
);
462 GdiSelectVisRgn(hdc
, VisRgn
);
463 REGION_Delete(VisRgn
);
469 /* Return the old bitmap handle */
482 BOOL success
= FALSE
;
486 pdc
= DC_LockDc(hDC
);
489 EngSetLastError(ERROR_INVALID_PARAMETER
);
492 pdcattr
= pdc
->pdcattr
;
494 pPath
= PATH_LockPath(pdc
->dclevel
.hPath
);
501 /* Check that path is closed */
502 if (pPath
->state
!= PATH_Closed
)
504 EngSetLastError(ERROR_CAN_NOT_COMPLETE
);
509 /* Construct a region from the path */
510 RgnPath
= IntSysCreateRectpRgn(0, 0, 0, 0);
513 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
518 if (!PATH_PathToRegion(pPath
, pdcattr
->jFillMode
, RgnPath
))
520 EngSetLastError(ERROR_CAN_NOT_COMPLETE
);
521 REGION_Delete(RgnPath
);
526 success
= IntGdiExtSelectClipRgn(pdc
, RgnPath
, Mode
) != ERROR
;
527 REGION_Delete(RgnPath
);
531 PATH_EmptyPath(pPath
);
533 /* FIXME: Should this function delete the path even if it failed? */
535 PATH_UnlockPath(pPath
);
550 // Legacy crap that will die with font engine rewrite
551 if (!NT_SUCCESS(TextIntRealizeFont(hlfntNew
, NULL
)))
556 /* Get the current selected font */
557 hlfntOld
= pdc
->dclevel
.plfnt
->BaseObject
.hHmgr
;
559 /* Check if a new font should be selected */
560 if (hlfntNew
!= hlfntOld
)
562 /* Lock the new font */
563 plfntNew
= LFONT_ShareLockFont(hlfntNew
);
566 /* Success, dereference the old font */
567 LFONT_ShareUnlockFont(pdc
->dclevel
.plfnt
);
569 /* Select the new font */
570 pdc
->dclevel
.plfnt
= plfntNew
;
571 pdc
->pdcattr
->hlfntNew
= hlfntNew
;
573 /* Update dirty flags */
574 pdc
->pdcattr
->ulDirty_
|= DIRTY_CHARSET
;
575 pdc
->pdcattr
->ulDirty_
&= ~SLOW_WIDTHS
;
579 /* Failed, restore old, return NULL */
580 pdc
->pdcattr
->hlfntNew
= hlfntOld
;
597 /* Check parameters */
598 if ((hdc
== NULL
) || (hfont
== NULL
))
604 pdc
= DC_LockDc(hdc
);
610 /* Call the internal function */
611 hfontOld
= DC_hSelectFont(pdc
, hfont
);
616 /* Return the previously selected font */
622 NtGdiGetDCObject(HDC hDC
, INT ObjectType
)
628 /* From Wine: GetCurrentObject does not SetLastError() on a null object */
629 if(!hDC
) return NULL
;
631 if(!(pdc
= DC_LockDc(hDC
)))
635 pdcattr
= pdc
->pdcattr
;
637 if (pdcattr
->ulDirty_
& (DIRTY_FILL
| DC_BRUSH_DIRTY
))
638 DC_vUpdateFillBrush(pdc
);
640 if (pdcattr
->ulDirty_
& (DIRTY_LINE
| DC_PEN_DIRTY
))
641 DC_vUpdateLineBrush(pdc
);
645 case GDI_OBJECT_TYPE_EXTPEN
:
646 case GDI_OBJECT_TYPE_PEN
:
647 SelObject
= pdcattr
->hpen
;
650 case GDI_OBJECT_TYPE_BRUSH
:
651 SelObject
= pdcattr
->hbrush
;
654 case GDI_OBJECT_TYPE_PALETTE
:
655 SelObject
= pdc
->dclevel
.hpal
;
658 case GDI_OBJECT_TYPE_FONT
:
659 SelObject
= pdcattr
->hlfntNew
;
662 case GDI_OBJECT_TYPE_BITMAP
:
664 SURFACE
*psurf
= pdc
->dclevel
.pSurface
;
665 SelObject
= psurf
? psurf
->BaseObject
.hHmgr
: StockObjects
[DEFAULT_BITMAP
];
669 case GDI_OBJECT_TYPE_COLORSPACE
:
670 DPRINT1("FIXME: NtGdiGetCurrentObject() ObjectType OBJ_COLORSPACE not supported yet!\n");
671 // SelObject = dc->dclevel.pColorSpace.BaseObject.hHmgr; ?
677 EngSetLastError(ERROR_INVALID_PARAMETER
);
685 /* See WINE, MSDN, OSR and Feng Yuan - Windows Graphics Programming Win32 GDI and DirectDraw
687 * 1st: http://www.codeproject.com/gdi/cliprgnguide.asp is wrong!
689 * The intersection of the clip with the meta region is not Rao it's API!
690 * Go back and read 7.2 Clipping pages 418-19:
692 * 1) The Rao region is the intersection of the API region and the system region,
693 * named after the Microsoft engineer who initially proposed it.
694 * 2) The Rao region can be calculated from the API region and the system region.
697 * API region is the intersection of the meta region and the clipping region,
698 * clearly named after the fact that it is controlled by GDI API calls.
709 PREGION prgnSrc
= NULL
;
711 pdc
= DC_LockDc(hdc
);
714 EngSetLastError(ERROR_INVALID_HANDLE
);
721 prgnSrc
= pdc
->dclevel
.prgnClip
;
725 prgnSrc
= pdc
->dclevel
.prgnMeta
;
729 if (pdc
->fs
& DC_FLAG_DIRTY_RAO
)
730 CLIPPING_UpdateGCRegion(pdc
);
733 prgnSrc
= pdc
->prgnAPI
;
735 else if (pdc
->dclevel
.prgnClip
)
737 prgnSrc
= pdc
->dclevel
.prgnClip
;
739 else if (pdc
->dclevel
.prgnMeta
)
741 prgnSrc
= pdc
->dclevel
.prgnMeta
;
746 prgnSrc
= pdc
->prgnVis
;
755 PREGION prgnDest
= REGION_LockRgn(hrgnDest
);
758 ret
= IntGdiCombineRgn(prgnDest
, prgnSrc
, 0, RGN_COPY
) == ERROR
? -1 : 1;
759 if ((ret
== 1) && (iCode
== SYSRGN
))
760 IntGdiOffsetRgn(prgnDest
, pdc
->ptlDCOrig
.x
, pdc
->ptlDCOrig
.y
);
761 REGION_UnlockRgn(prgnDest
);
778 OUT OPTIONAL PVOID pvBuf
)