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: win32ss/gdi/ntgdi/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 /* Update the eboFill's solid color */
53 EBRUSHOBJ_vSetSolidRGBColor(&pdc
->eboFill
, pdcattr
->crBrushClr
);
57 pdcattr
->ulDirty_
&= ~(DIRTY_FILL
| DC_BRUSH_DIRTY
);
62 DC_vUpdateLineBrush(PDC pdc
)
64 PDC_ATTR pdcattr
= pdc
->pdcattr
;
67 /* Check if the pen handle has changed */
68 if (pdcattr
->hpen
!= pdc
->dclevel
.pbrLine
->BaseObject
.hHmgr
)
70 /* Try to lock the new pen */
71 pbrLine
= PEN_ShareLockPen(pdcattr
->hpen
);
74 /* Unlock old brush, set new brush */
75 BRUSH_ShareUnlockBrush(pdc
->dclevel
.pbrLine
);
76 pdc
->dclevel
.pbrLine
= pbrLine
;
78 /* Mark eboLine as dirty */
79 pdcattr
->ulDirty_
|= DIRTY_LINE
;
83 /* Invalid pen handle, restore old one */
84 pdcattr
->hpen
= pdc
->dclevel
.pbrLine
->BaseObject
.hHmgr
;
88 /* Check if the EBRUSHOBJ needs update */
89 if (pdcattr
->ulDirty_
& DIRTY_LINE
)
92 EBRUSHOBJ_vUpdateFromDC(&pdc
->eboLine
, pdc
->dclevel
.pbrLine
, pdc
);
95 /* Check for DC pen */
96 if (pdcattr
->hpen
== StockObjects
[DC_PEN
])
98 /* Update the eboLine's solid color */
99 EBRUSHOBJ_vSetSolidRGBColor(&pdc
->eboLine
, pdcattr
->crPenClr
);
103 pdcattr
->ulDirty_
&= ~(DIRTY_LINE
| DC_PEN_DIRTY
);
108 DC_vUpdateTextBrush(PDC pdc
)
110 PDC_ATTR pdcattr
= pdc
->pdcattr
;
112 /* Timo : The text brush should never be changed.
113 * Jérôme : Yeah, but its palette must be updated anyway! */
114 if(pdcattr
->ulDirty_
& DIRTY_TEXT
)
115 EBRUSHOBJ_vUpdateFromDC(&pdc
->eboText
, pbrDefaultBrush
, pdc
);
117 /* Update the eboText's solid color */
118 EBRUSHOBJ_vSetSolidRGBColor(&pdc
->eboText
, pdcattr
->crForegroundClr
);
121 pdcattr
->ulDirty_
&= ~DIRTY_TEXT
;
126 DC_vUpdateBackgroundBrush(PDC pdc
)
128 PDC_ATTR pdcattr
= pdc
->pdcattr
;
130 if(pdcattr
->ulDirty_
& DIRTY_BACKGROUND
)
131 EBRUSHOBJ_vUpdateFromDC(&pdc
->eboBackground
, pbrDefaultBrush
, pdc
);
133 /* Update the eboBackground's solid color */
134 EBRUSHOBJ_vSetSolidRGBColor(&pdc
->eboBackground
, pdcattr
->crBackgroundClr
);
137 pdcattr
->ulDirty_
&= ~DIRTY_BACKGROUND
;
142 DC_vSetBrushOrigin(PDC pdc
, LONG x
, LONG y
)
144 /* Set the brush origin */
145 pdc
->dclevel
.ptlBrushOrigin
.x
= x
;
146 pdc
->dclevel
.ptlBrushOrigin
.y
= y
;
148 /* Set the fill origin */
149 pdc
->ptlFillOrigin
.x
= x
+ pdc
->ptlDCOrig
.x
;
150 pdc
->ptlFillOrigin
.y
= y
+ pdc
->ptlDCOrig
.y
;
154 * \name NtGdiSetBrushOrg
156 * \brief Sets the brush origin that GDI uses when drawing with pattern
157 * brushes. The brush origin is relative to the DC origin.
161 _Success_(return!=FALSE
)
169 _Out_opt_ LPPOINT pptOut
)
173 /* Call the internal function */
174 BOOL Ret
= GreSetBrushOrg( hdc
, x
, y
, &ptOut
);
177 /* Check if the old origin was requested */
180 /* Enter SEH for buffer transfer */
183 /* Probe and copy the old origin */
184 ProbeForWrite(pptOut
, sizeof(POINT
), 1);
187 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
189 _SEH2_YIELD(return FALSE
);
202 BOOL ForceBackground
)
205 HPALETTE oldPal
= NULL
;
208 // FIXME: Mark the palette as a [fore\back]ground pal
209 pdc
= DC_LockDc(hDC
);
215 /* Check if this is a valid palette handle */
216 ppal
= PALETTE_ShareLockPalette(hpal
);
223 /// FIXME: we shouldn't dereference pSurface when the PDEV is not locked
224 /* Is this a valid palette for this depth? */
225 if ((!pdc
->dclevel
.pSurface
) ||
226 (BitsPerFormat(pdc
->dclevel
.pSurface
->SurfObj
.iBitmapFormat
) <= 8
227 && (ppal
->flFlags
& PAL_INDEXED
)) ||
228 (BitsPerFormat(pdc
->dclevel
.pSurface
->SurfObj
.iBitmapFormat
) > 8))
230 /* Get old palette, set new one */
231 oldPal
= pdc
->dclevel
.hpal
;
232 pdc
->dclevel
.hpal
= hpal
;
233 DC_vSelectPalette(pdc
, ppal
);
235 /* Mark the brushes invalid */
236 pdc
->pdcattr
->ulDirty_
|= DIRTY_FILL
| DIRTY_LINE
|
237 DIRTY_BACKGROUND
| DIRTY_TEXT
;
240 if(pdc
->dctype
== DCTYPE_MEMORY
)
242 // This didn't work anyway
243 //IntGdiRealizePalette(hDC);
246 PALETTE_ShareUnlockPalette(ppal
);
264 if (hDC
== NULL
|| hBrush
== NULL
) return NULL
;
266 pDC
= DC_LockDc(hDC
);
272 /* Simply return the user mode value, without checking */
273 hOrgBrush
= pDC
->pdcattr
->hbrush
;
274 pDC
->pdcattr
->hbrush
= hBrush
;
275 DC_vUpdateFillBrush(pDC
);
294 if (hDC
== NULL
|| hPen
== NULL
) return NULL
;
296 pDC
= DC_LockDc(hDC
);
302 /* Simply return the user mode value, without checking */
303 hOrgPen
= pDC
->pdcattr
->hpen
;
304 pDC
->pdcattr
->hpen
= hPen
;
305 DC_vUpdateLineBrush(pDC
);
314 DC_bIsBitmapCompatible(PDC pdc
, PSURFACE psurf
)
318 /* Must be an API bitmap */
319 if (!(psurf
->flags
& API_BITMAP
)) return FALSE
;
321 /* DIB sections are always compatible */
322 if (psurf
->hSecure
!= NULL
) return TRUE
;
324 /* See if this is the same PDEV */
325 if (psurf
->SurfObj
.hdev
== (HDEV
)pdc
->ppdev
)
328 /* Get the bit depth of the bitmap */
329 cBitsPixel
= gajBitsPerFormat
[psurf
->SurfObj
.iBitmapFormat
];
331 /* 1 BPP is compatible */
332 if ((cBitsPixel
== 1) || (cBitsPixel
== pdc
->ppdev
->gdiinfo
.cBitsPixel
))
349 PSURFACE psurfNew
, psurfOld
;
353 /* Verify parameters */
354 if (hdc
== NULL
|| hbmp
== NULL
) return NULL
;
356 /* First lock the DC */
357 pdc
= DC_LockDc(hdc
);
363 /* Must be a memory dc to select a bitmap */
364 if (pdc
->dctype
!= DC_TYPE_MEMORY
)
370 /* Save the old bitmap */
371 psurfOld
= pdc
->dclevel
.pSurface
;
373 /* Check if there is a bitmap selected */
376 /* Get the old bitmap's handle */
377 hbmpOld
= psurfOld
->BaseObject
.hHmgr
;
381 /* Use the default bitmap */
382 hbmpOld
= StockObjects
[DEFAULT_BITMAP
];
385 /* Check if the new bitmap is already selected */
388 /* Unlock the DC and return the old bitmap */
393 /* Check if the default bitmap was passed */
394 if (hbmp
== StockObjects
[DEFAULT_BITMAP
])
398 /* Default bitmap is 1x1 pixel */
399 pdc
->dclevel
.sizl
.cx
= 1;
400 pdc
->dclevel
.sizl
.cy
= 1;
404 /* Reference the new bitmap and check if it's valid */
405 psurfNew
= SURFACE_ShareLockSurface(hbmp
);
412 /* Check if the bitmap is compatible with the dc */
413 if (!DC_bIsBitmapCompatible(pdc
, psurfNew
))
415 /* Dereference the bitmap, unlock the DC and fail. */
416 SURFACE_ShareUnlockSurface(psurfNew
);
421 /* Set the bitmap's hdc and check if it was set before */
422 hdcOld
= InterlockedCompareExchangePointer((PVOID
*)&psurfNew
->hdc
, hdc
, 0);
425 /* The bitmap is already selected into a different DC */
426 ASSERT(hdcOld
!= hdc
);
428 /* Dereference the bitmap, unlock the DC and fail. */
429 SURFACE_ShareUnlockSurface(psurfNew
);
434 /* Copy the bitmap size */
435 pdc
->dclevel
.sizl
= psurfNew
->SurfObj
.sizlBitmap
;
437 /* Check if the bitmap is a dibsection */
438 if (psurfNew
->hSecure
)
440 /* Set DIBSECTION attribute */
441 pdc
->pdcattr
->ulDirty_
|= DC_DIBSECTION
;
445 /* Remove DIBSECTION attribute */
446 pdc
->pdcattr
->ulDirty_
&= ~DC_DIBSECTION
;
450 /* Select the new bitmap */
451 pdc
->dclevel
.pSurface
= psurfNew
;
453 /* Check if there was a bitmap selected before */
456 /* Reset hdc of the old bitmap, it isn't selected anymore */
457 psurfOld
->hdc
= NULL
;
459 /* Dereference the old bitmap */
460 SURFACE_ShareUnlockSurface(psurfOld
);
463 /* Mark the DC brushes and the RAO region invalid */
464 pdc
->pdcattr
->ulDirty_
|= DIRTY_FILL
| DIRTY_LINE
;
465 pdc
->fs
|= DC_FLAG_DIRTY_RAO
;
467 /* Update the system region */
468 REGION_SetRectRgn(pdc
->prgnVis
,
471 pdc
->dclevel
.sizl
.cx
,
472 pdc
->dclevel
.sizl
.cy
);
477 /* Return the old bitmap handle */
489 PPATH pPath
, pNewPath
;
490 BOOL success
= FALSE
;
494 pdc
= DC_LockDc(hDC
);
497 EngSetLastError(ERROR_INVALID_PARAMETER
);
500 pdcattr
= pdc
->pdcattr
;
502 pPath
= PATH_LockPath(pdc
->dclevel
.hPath
);
509 /* Check that path is closed */
510 if (pPath
->state
!= PATH_Closed
)
512 EngSetLastError(ERROR_CAN_NOT_COMPLETE
);
517 /* Construct a region from the path */
518 RgnPath
= IntSysCreateRectpRgn(0, 0, 0, 0);
521 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
526 pNewPath
= PATH_FlattenPath(pPath
);
528 success
= PATH_PathToRegion(pNewPath
, pdcattr
->jFillMode
, RgnPath
);
530 PATH_UnlockPath(pNewPath
);
531 PATH_Delete(pNewPath
->BaseObject
.hHmgr
);
533 if (success
) success
= IntGdiExtSelectClipRgn(pdc
, RgnPath
, Mode
) != ERROR
;
535 REGION_Delete(RgnPath
);
538 PATH_UnlockPath(pPath
);
539 PATH_Delete(pdc
->dclevel
.hPath
);
540 pdc
->dclevel
.flPath
&= ~DCPATH_ACTIVE
;
541 pdc
->dclevel
.hPath
= NULL
;
557 // Legacy crap that will die with font engine rewrite
558 if (!NT_SUCCESS(TextIntRealizeFont(hlfntNew
, NULL
)))
563 /* Get the current selected font */
564 hlfntOld
= pdc
->dclevel
.plfnt
->BaseObject
.hHmgr
;
566 /* Check if a new font should be selected */
567 if (hlfntNew
!= hlfntOld
)
569 /* Lock the new font */
570 plfntNew
= LFONT_ShareLockFont(hlfntNew
);
573 /* Success, dereference the old font */
574 LFONT_ShareUnlockFont(pdc
->dclevel
.plfnt
);
576 /* Select the new font */
577 pdc
->dclevel
.plfnt
= plfntNew
;
578 pdc
->pdcattr
->hlfntNew
= hlfntNew
;
580 /* Update dirty flags */
581 pdc
->pdcattr
->ulDirty_
|= DIRTY_CHARSET
;
582 pdc
->pdcattr
->ulDirty_
&= ~SLOW_WIDTHS
;
586 /* Failed, restore old, return NULL */
587 pdc
->pdcattr
->hlfntNew
= hlfntOld
;
604 /* Check parameters */
605 if ((hdc
== NULL
) || (hfont
== NULL
))
611 pdc
= DC_LockDc(hdc
);
617 /* Call the internal function */
618 hfontOld
= DC_hSelectFont(pdc
, hfont
);
623 /* Return the previously selected font */
629 NtGdiGetDCObject(HDC hDC
, INT ObjectType
)
635 /* From Wine: GetCurrentObject does not SetLastError() on a null object */
636 if(!hDC
) return NULL
;
638 if(!(pdc
= DC_LockDc(hDC
)))
642 pdcattr
= pdc
->pdcattr
;
644 if (pdcattr
->ulDirty_
& (DIRTY_FILL
| DC_BRUSH_DIRTY
))
645 DC_vUpdateFillBrush(pdc
);
647 if (pdcattr
->ulDirty_
& (DIRTY_LINE
| DC_PEN_DIRTY
))
648 DC_vUpdateLineBrush(pdc
);
652 case GDI_OBJECT_TYPE_EXTPEN
:
653 case GDI_OBJECT_TYPE_PEN
:
654 SelObject
= pdcattr
->hpen
;
657 case GDI_OBJECT_TYPE_BRUSH
:
658 SelObject
= pdcattr
->hbrush
;
661 case GDI_OBJECT_TYPE_PALETTE
:
662 SelObject
= pdc
->dclevel
.hpal
;
665 case GDI_OBJECT_TYPE_FONT
:
666 SelObject
= pdcattr
->hlfntNew
;
669 case GDI_OBJECT_TYPE_BITMAP
:
671 SURFACE
*psurf
= pdc
->dclevel
.pSurface
;
672 SelObject
= psurf
? psurf
->BaseObject
.hHmgr
: StockObjects
[DEFAULT_BITMAP
];
676 case GDI_OBJECT_TYPE_COLORSPACE
:
677 DPRINT1("FIXME: NtGdiGetCurrentObject() ObjectType OBJ_COLORSPACE not supported yet!\n");
678 // SelObject = dc->dclevel.pColorSpace.BaseObject.hHmgr; ?
684 EngSetLastError(ERROR_INVALID_PARAMETER
);
692 /* See WINE, MSDN, OSR and Feng Yuan - Windows Graphics Programming Win32 GDI and DirectDraw
694 * 1st: http://www.codeproject.com/gdi/cliprgnguide.asp is wrong!
696 * The intersection of the clip with the meta region is not Rao it's API!
697 * Go back and read 7.2 Clipping pages 418-19:
699 * 1) The Rao region is the intersection of the API region and the system region,
700 * named after the Microsoft engineer who initially proposed it.
701 * 2) The Rao region can be calculated from the API region and the system region.
704 * API region is the intersection of the meta region and the clipping region,
705 * clearly named after the fact that it is controlled by GDI API calls.
716 PREGION prgnSrc
= NULL
;
718 pdc
= DC_LockDc(hdc
);
721 EngSetLastError(ERROR_INVALID_HANDLE
);
728 prgnSrc
= pdc
->dclevel
.prgnClip
;
732 prgnSrc
= pdc
->dclevel
.prgnMeta
;
736 if (pdc
->fs
& DC_FLAG_DIRTY_RAO
)
737 CLIPPING_UpdateGCRegion(pdc
);
740 prgnSrc
= pdc
->prgnAPI
;
742 else if (pdc
->dclevel
.prgnClip
)
744 prgnSrc
= pdc
->dclevel
.prgnClip
;
746 else if (pdc
->dclevel
.prgnMeta
)
748 prgnSrc
= pdc
->dclevel
.prgnMeta
;
753 prgnSrc
= pdc
->prgnVis
;
762 PREGION prgnDest
= REGION_LockRgn(hrgnDest
);
765 ret
= IntGdiCombineRgn(prgnDest
, prgnSrc
, 0, RGN_COPY
) == ERROR
? -1 : 1;
766 if ((ret
== 1) && (iCode
== SYSRGN
))
768 /// \todo FIXME This is not really correct, since we already modified the region
769 ret
= REGION_bOffsetRgn(prgnDest
, pdc
->ptlDCOrig
.x
, pdc
->ptlDCOrig
.y
);
771 REGION_UnlockRgn(prgnDest
);
788 OUT OPTIONAL PVOID pvBuf
)