- Rewrite NtGdiFillRgn and IntGdiPaintRgn
We now properly support painting regions on DCs with arbitrary world transforms, with pattern brushes and we respect the foreground ROP and mode of the DC. And we don't run into deadlocks due to having an exclusive region lock while trying to lock a DC. LOCKING MUST BE DONE IN PROPER ORDER!

svn path=/trunk/; revision=65730
This commit is contained in:
Timo Kreuzer 2014-12-18 08:12:23 +00:00
parent c3d2353ed6
commit c6f684e727

View file

@ -1021,103 +1021,146 @@ REGION_LPTODP(
if (IntGdiCombineRgn(prgnDest, prgnSrc, NULL, RGN_COPY) == ERROR) if (IntGdiCombineRgn(prgnDest, prgnSrc, NULL, RGN_COPY) == ERROR)
return FALSE; return FALSE;
return REGION_bXformRgn(prgnDest, &pdc->dclevel.mxWorldToDevice); return REGION_bXformRgn(prgnDest, DC_pmxWorldToDevice(pdc));
} }
BOOL BOOL
FASTCALL IntGdiFillRgn(
IntGdiPaintRgn( _In_ PDC pdc,
PDC dc, _In_ PREGION prgn,
PREGION Rgn) _In_ BRUSHOBJ *pbo)
{ {
PREGION VisRgn; PREGION prgnClip;
XCLIPOBJ ClipRegion; XCLIPOBJ xcoClip;
BOOL bRet = FALSE; BOOL bRet;
POINTL BrushOrigin; PSURFACE psurf;
SURFACE *psurf; DWORD rop2Fg;
PDC_ATTR pdcattr; MIX mix;
if ((dc == NULL) || (Rgn == NULL)) NT_ASSERT((pdc != NULL) && (prgn != NULL));
return FALSE;
pdcattr = dc->pdcattr; psurf = pdc->dclevel.pSurface;
if (psurf == NULL)
{
return TRUE;
}
ASSERT(!(pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))); prgnClip = IntSysCreateRectpRgn(0, 0, 0, 0);
if (prgnClip == NULL)
VisRgn = IntSysCreateRectpRgn(0, 0, 0, 0);
if (VisRgn == NULL)
{ {
return FALSE; return FALSE;
} }
// Transform region into device co-ords /* Transform region into device coordinates */
if (!REGION_LPTODP(dc, VisRgn, Rgn) || if (!REGION_LPTODP(pdc, prgnClip, prgn) ||
IntGdiOffsetRgn(VisRgn, dc->ptlDCOrig.x, dc->ptlDCOrig.y) == ERROR) IntGdiOffsetRgn(prgnClip, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y) == ERROR)
{ {
REGION_Delete(VisRgn); REGION_Delete(prgnClip);
return FALSE; return FALSE;
} }
if (dc->prgnRao) /* Intersect with the system or RAO region */
IntGdiCombineRgn(VisRgn, VisRgn, dc->prgnRao, RGN_AND); if (pdc->prgnRao)
IntGdiCombineRgn(prgnClip, prgnClip, pdc->prgnRao, RGN_AND);
else
IntGdiCombineRgn(prgnClip, prgnClip, pdc->prgnVis, RGN_AND);
IntEngInitClipObj(&ClipRegion); IntEngInitClipObj(&xcoClip);
IntEngUpdateClipRegion(&ClipRegion, IntEngUpdateClipRegion(&xcoClip,
VisRgn->rdh.nCount, prgnClip->rdh.nCount,
VisRgn->Buffer, prgnClip->Buffer,
&VisRgn->rdh.rcBound ); &prgnClip->rdh.rcBound );
BrushOrigin.x = pdcattr->ptlBrushOrigin.x; /* Get the FG rop and create a MIX based on the BK mode */
BrushOrigin.y = pdcattr->ptlBrushOrigin.y; rop2Fg = pdc->pdcattr->jROP2;
psurf = dc->dclevel.pSurface; mix = rop2Fg | (pdc->pdcattr->jBkMode == OPAQUE ? rop2Fg : R2_NOP) << 8;
/* FIXME: Handle psurf == NULL !!!! */
/* Call the internal function */
bRet = IntEngPaint(&psurf->SurfObj, bRet = IntEngPaint(&psurf->SurfObj,
&ClipRegion.ClipObj, &xcoClip.ClipObj,
&dc->eboFill.BrushObject, pbo,
&BrushOrigin, &pdc->pdcattr->ptlBrushOrigin,
0xFFFF); // FIXME: Don't know what to put here mix);
REGION_Delete(VisRgn); REGION_Delete(prgnClip);
IntEngFreeClipResources(&ClipRegion); IntEngFreeClipResources(&xcoClip);
// Fill the region // Fill the region
return bRet; return bRet;
} }
BOOL
FASTCALL
IntGdiPaintRgn(
_In_ PDC pdc,
_In_ PREGION prgn)
{
if (pdc->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
DC_vUpdateFillBrush(pdc);
return IntGdiFillRgn(pdc, prgn, &pdc->eboFill.BrushObject);
}
BOOL BOOL
APIENTRY APIENTRY
NtGdiFillRgn( NtGdiFillRgn(
HDC hDC, _In_ HDC hdc,
HRGN hRgn, _In_ HRGN hrgn,
HBRUSH hBrush) _In_ HBRUSH hbrush)
{ {
HBRUSH oldhBrush; PDC pdc;
PREGION rgn; PREGION prgn;
PRECTL r; PBRUSH pbrFill;
EBRUSHOBJ eboFill;
BOOL bResult;
rgn = RGNOBJAPI_Lock(hRgn, NULL); /* Lock the DC */
if (rgn == NULL) pdc = DC_LockDc(hdc);
if (pdc == NULL)
{ {
ERR("Failed to lock hdc %p\n", hdc);
return FALSE; return FALSE;
} }
oldhBrush = NtGdiSelectBrush(hDC, hBrush); /* Check if the DC has no surface (empty mem or info DC) */
if (oldhBrush == NULL) if (pdc->dclevel.pSurface == NULL)
{ {
RGNOBJAPI_Unlock(rgn); DC_UnlockDc(pdc);
return TRUE;
}
/* Lock the region */
prgn = RGNOBJAPI_Lock(hrgn, NULL);
if (prgn == NULL)
{
ERR("Failed to lock hrgn %p\n", hrgn);
DC_UnlockDc(pdc);
return FALSE; return FALSE;
} }
for (r = rgn->Buffer; r < rgn->Buffer + rgn->rdh.nCount; r++) /* Lock the brush */
pbrFill = BRUSH_ShareLockBrush(hbrush);
if (pbrFill == NULL)
{ {
NtGdiPatBlt(hDC, r->left, r->top, r->right - r->left, r->bottom - r->top, PATCOPY); ERR("Failed to lock hbrush %p\n", hbrush);
RGNOBJAPI_Unlock(prgn);
DC_UnlockDc(pdc);
return FALSE;
} }
RGNOBJAPI_Unlock(rgn); /* Initialize the brush object */
NtGdiSelectBrush(hDC, oldhBrush); /// \todo Check parameters
EBRUSHOBJ_vInit(&eboFill, pbrFill, pdc->dclevel.pSurface, 0x00FFFFFF, 0, NULL);
return TRUE; /* Call the internal function */
bResult = IntGdiFillRgn(pdc, prgn, &eboFill.BrushObject);
/* Cleanup locks */
BRUSH_ShareUnlockBrush(pbrFill);
RGNOBJAPI_Unlock(prgn);
DC_UnlockDc(pdc);
return bResult;
} }
BOOL BOOL