COLORREF FASTCALL IntGdiSetTextColor(HDC hDC, COLORREF color) { COLORREF crOldColor; PDC pdc; PDC_ATTR pdcattr; pdc = DC_LockDc(hDC); if (!pdc) { EngSetLastError(ERROR_INVALID_HANDLE); return CLR_INVALID; } pdcattr = pdc->pdcattr; crOldColor = (COLORREF) pdcattr->ulForegroundClr; pdcattr->ulForegroundClr = (ULONG)color; if (pdcattr->crForegroundClr != color) { pdcattr->ulDirty_ |= (DIRTY_TEXT|DIRTY_LINE|DIRTY_FILL); pdcattr->crForegroundClr = color; } DC_vUpdateTextBrush(pdc); DC_vUpdateLineBrush(pdc); DC_vUpdateFillBrush(pdc); DC_UnlockDc(pdc); return crOldColor; }
/* * @implemented */ HPEN APIENTRY NtGdiSelectPen( IN HDC hDC, IN HPEN hPen) { PDC pDC; HPEN hOrgPen; if (hDC == NULL || hPen == NULL) return NULL; pDC = DC_LockDc(hDC); if (!pDC) { return NULL; } /* Simply return the user mode value, without checking */ hOrgPen = pDC->pdcattr->hpen; pDC->pdcattr->hpen = hPen; DC_vUpdateLineBrush(pDC); DC_UnlockDc(pDC); return hOrgPen; }
BOOL APIENTRY NtGdiArcInternal( ARCTYPE arctype, HDC hDC, int LeftRect, int TopRect, int RightRect, int BottomRect, int XStartArc, int YStartArc, int XEndArc, int YEndArc) { DC *dc; BOOL Ret; KFLOATING_SAVE FloatSave; dc = DC_LockDc (hDC); if(!dc) { EngSetLastError(ERROR_INVALID_HANDLE); return FALSE; } if (dc->dctype == DC_TYPE_INFO) { DC_UnlockDc(dc); /* Yes, Windows really returns TRUE in this case */ return TRUE; } DC_vPrepareDCsForBlit(dc, dc->rosdc.CombinedClip->rclBounds, NULL, dc->rosdc.CombinedClip->rclBounds); if (dc->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY)) DC_vUpdateFillBrush(dc); if (dc->pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY)) DC_vUpdateLineBrush(dc); KeSaveFloatingPointState(&FloatSave); Ret = IntGdiArcInternal( arctype, dc, LeftRect, TopRect, RightRect, BottomRect, XStartArc, YStartArc, XEndArc, YEndArc); KeRestoreFloatingPointState(&FloatSave); DC_vFinishBlit(dc, NULL); DC_UnlockDc( dc ); return Ret; }
BOOL FASTCALL IntGdiCleanDC(HDC hDC) { PDC dc; if (!hDC) return FALSE; dc = DC_LockDc(hDC); if (!dc) return FALSE; // Clean the DC if (defaultDCstate) { DC_vCopyState(defaultDCstate, dc, FALSE); /* Update the brushes now, because they reference some objects (the DC palette) * Which belong to the current process, and this DC might be used for another process * after being cleaned up (for GetDC(0) for instance) */ DC_vUpdateFillBrush(dc); DC_vUpdateBackgroundBrush(dc); DC_vUpdateLineBrush(dc); DC_vUpdateTextBrush(dc); } // Remove Path and reset flags. if (dc->dclevel.hPath) { DPRINT("Clean DC Remove Path\n"); if (!PATH_Delete(dc->dclevel.hPath)) { DPRINT1("Failed to remove Path\n"); } dc->dclevel.hPath = 0; dc->dclevel.flPath = 0; } /* DC_vCopyState frees the Clip rgn and the Meta rgn. Take care of the other ones * There is no need to clear prgnVis, as UserGetDC updates it immediately. */ if (dc->prgnRao) REGION_Delete(dc->prgnRao); if (dc->prgnAPI) REGION_Delete(dc->prgnAPI); dc->prgnRao = dc->prgnAPI = NULL; dc->fs |= DC_FLAG_DIRTY_RAO; DC_UnlockDc(dc); return TRUE; }
BOOL APIENTRY NtGdiAngleArc( IN HDC hDC, IN INT x, IN INT y, IN DWORD dwRadius, IN DWORD dwStartAngle, IN DWORD dwSweepAngle) { DC *pDC; BOOL Ret = FALSE; gxf_long worker, worker1; KFLOATING_SAVE FloatSave; pDC = DC_LockDc (hDC); if(!pDC) { EngSetLastError(ERROR_INVALID_HANDLE); return FALSE; } if (pDC->dctype == DC_TYPE_INFO) { DC_UnlockDc(pDC); /* Yes, Windows really returns TRUE in this case */ return TRUE; } KeSaveFloatingPointState(&FloatSave); worker.l = dwStartAngle; worker1.l = dwSweepAngle; DC_vPrepareDCsForBlit(pDC, pDC->rosdc.CombinedClip->rclBounds, NULL, pDC->rosdc.CombinedClip->rclBounds); if (pDC->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY)) DC_vUpdateFillBrush(pDC); if (pDC->pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY)) DC_vUpdateLineBrush(pDC); Ret = IntGdiAngleArc( pDC, x, y, dwRadius, worker.f, worker1.f); DC_vFinishBlit(pDC, NULL); DC_UnlockDc( pDC ); KeRestoreFloatingPointState(&FloatSave); return Ret; }
BOOL FASTCALL IntRoundRect( PDC dc, int Left, int Top, int Right, int Bottom, int xCurveDiameter, int yCurveDiameter) { PDC_ATTR pdcattr; PBRUSH pbrLine, pbrFill; RECTL RectBounds; LONG PenWidth, PenOrigWidth; BOOL ret = TRUE; // Default to success BRUSH brushTemp; ASSERT ( dc ); // Caller's responsibility to set this up if ( PATH_IsPathOpen(dc->dclevel) ) return PATH_RoundRect ( dc, Left, Top, Right, Bottom, xCurveDiameter, yCurveDiameter ); if ((Left == Right) || (Top == Bottom)) return TRUE; xCurveDiameter = max(abs( xCurveDiameter ), 1); yCurveDiameter = max(abs( yCurveDiameter ), 1); if (Right < Left) { INT tmp = Right; Right = Left; Left = tmp; } if (Bottom < Top) { INT tmp = Bottom; Bottom = Top; Top = tmp; } pdcattr = dc->pdcattr; if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY)) DC_vUpdateFillBrush(dc); if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY)) DC_vUpdateLineBrush(dc); pbrLine = PEN_ShareLockPen(pdcattr->hpen); if (!pbrLine) { /* Nothing to do, as we don't have a bitmap */ EngSetLastError(ERROR_INTERNAL_ERROR); return FALSE; } PenOrigWidth = PenWidth = pbrLine->ptPenWidth.x; if (pbrLine->ulPenStyle == PS_NULL) PenWidth = 0; if (pbrLine->ulPenStyle == PS_INSIDEFRAME) { if (2*PenWidth > (Right - Left)) PenWidth = (Right -Left + 1)/2; if (2*PenWidth > (Bottom - Top)) PenWidth = (Bottom -Top + 1)/2; Left += PenWidth / 2; Right -= (PenWidth - 1) / 2; Top += PenWidth / 2; Bottom -= (PenWidth - 1) / 2; } if (!PenWidth) PenWidth = 1; pbrLine->ptPenWidth.x = PenWidth; RectBounds.left = Left; RectBounds.top = Top; RectBounds.right = Right; RectBounds.bottom = Bottom; IntLPtoDP(dc, (LPPOINT)&RectBounds, 2); RectBounds.left += dc->ptlDCOrig.x; RectBounds.top += dc->ptlDCOrig.y; RectBounds.right += dc->ptlDCOrig.x; RectBounds.bottom += dc->ptlDCOrig.y; pbrFill = BRUSH_ShareLockBrush(pdcattr->hbrush); if (!pbrFill) { DPRINT1("FillRound Fail\n"); EngSetLastError(ERROR_INTERNAL_ERROR); ret = FALSE; } else { DC_vPrepareDCsForBlit(dc, RectBounds, NULL, RectBounds); RtlCopyMemory(&brushTemp, pbrFill, sizeof(brushTemp)); brushTemp.ptOrigin.x += RectBounds.left - Left; brushTemp.ptOrigin.y += RectBounds.top - Top; ret = IntFillRoundRect( dc, RectBounds.left, RectBounds.top, RectBounds.right, RectBounds.bottom, xCurveDiameter, yCurveDiameter, &brushTemp); BRUSH_ShareUnlockBrush(pbrFill); if (ret) { ret = IntDrawRoundRect( dc, RectBounds.left, RectBounds.top, RectBounds.right, RectBounds.bottom, xCurveDiameter, yCurveDiameter, pbrLine); } DC_vFinishBlit(dc, NULL); } pbrLine->ptPenWidth.x = PenOrigWidth; PEN_ShareUnlockPen(pbrLine); return ret; }
BOOL FASTCALL IntRectangle(PDC dc, int LeftRect, int TopRect, int RightRect, int BottomRect) { SURFACE *psurf = NULL; PBRUSH pbrLine, pbrFill; BOOL ret = FALSE; // Default to failure RECTL DestRect; MIX Mix; PDC_ATTR pdcattr; POINTL BrushOrigin; ASSERT ( dc ); // Caller's responsibility to set this up pdcattr = dc->pdcattr; // Rectangle Path only. if ( PATH_IsPathOpen(dc->dclevel) ) { return PATH_Rectangle ( dc, LeftRect, TopRect, RightRect, BottomRect ); } /* Make sure rectangle is not inverted */ DestRect.left = min(LeftRect, RightRect); DestRect.right = max(LeftRect, RightRect); DestRect.top = min(TopRect, BottomRect); DestRect.bottom = max(TopRect, BottomRect); IntLPtoDP(dc, (LPPOINT)&DestRect, 2); DestRect.left += dc->ptlDCOrig.x; DestRect.right += dc->ptlDCOrig.x; DestRect.top += dc->ptlDCOrig.y; DestRect.bottom += dc->ptlDCOrig.y; /* In GM_COMPATIBLE, don't include bottom and right edges */ if (pdcattr->iGraphicsMode == GM_COMPATIBLE) { DestRect.right--; DestRect.bottom--; } DC_vPrepareDCsForBlit(dc, DestRect, NULL, DestRect); if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY)) DC_vUpdateFillBrush(dc); if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY)) DC_vUpdateLineBrush(dc); pbrFill = dc->dclevel.pbrFill; pbrLine = dc->dclevel.pbrLine; if (!pbrLine) { ret = FALSE; goto cleanup; } psurf = dc->dclevel.pSurface; if (!psurf) { ret = FALSE; goto cleanup; } if (pbrFill) { if (!(pbrFill->flAttrs & BR_IS_NULL)) { BrushOrigin = *((PPOINTL)&pbrFill->ptOrigin); BrushOrigin.x += dc->ptlDCOrig.x; BrushOrigin.y += dc->ptlDCOrig.y; ret = IntEngBitBlt(&psurf->SurfObj, NULL, NULL, dc->rosdc.CombinedClip, NULL, &DestRect, NULL, NULL, &dc->eboFill.BrushObject, &BrushOrigin, ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY)); } } // Draw the rectangle with the current pen ret = TRUE; // Change default to success if (!(pbrLine->flAttrs & BR_IS_NULL)) { Mix = ROP2_TO_MIX(pdcattr->jROP2); ret = ret && IntEngLineTo(&psurf->SurfObj, dc->rosdc.CombinedClip, &dc->eboLine.BrushObject, DestRect.left, DestRect.top, DestRect.right, DestRect.top, &DestRect, // Bounding rectangle Mix); ret = ret && IntEngLineTo(&psurf->SurfObj, dc->rosdc.CombinedClip, &dc->eboLine.BrushObject, DestRect.right, DestRect.top, DestRect.right, DestRect.bottom, &DestRect, // Bounding rectangle Mix); ret = ret && IntEngLineTo(&psurf->SurfObj, dc->rosdc.CombinedClip, &dc->eboLine.BrushObject, DestRect.right, DestRect.bottom, DestRect.left, DestRect.bottom, &DestRect, // Bounding rectangle Mix); ret = ret && IntEngLineTo(&psurf->SurfObj, dc->rosdc.CombinedClip, &dc->eboLine.BrushObject, DestRect.left, DestRect.bottom, DestRect.left, DestRect.top, &DestRect, // Bounding rectangle Mix); } cleanup: DC_vFinishBlit(dc, NULL); /* Move current position in DC? MSDN: The current position is neither used nor updated by Rectangle. */ return ret; }
ULONG_PTR APIENTRY NtGdiPolyPolyDraw( IN HDC hDC, IN PPOINT UnsafePoints, IN PULONG UnsafeCounts, IN ULONG Count, IN INT iFunc ) { DC *dc; PVOID pTemp; LPPOINT SafePoints; PULONG SafeCounts; NTSTATUS Status = STATUS_SUCCESS; BOOL Ret = TRUE; ULONG nPoints = 0, nMaxPoints = 0, nInvalid = 0, i; if (!UnsafePoints || !UnsafeCounts || Count == 0 || iFunc == 0 || iFunc > GdiPolyPolyRgn) { /* Windows doesn't set last error */ return FALSE; } _SEH2_TRY { ProbeForRead(UnsafePoints, Count * sizeof(POINT), 1); ProbeForRead(UnsafeCounts, Count * sizeof(ULONG), 1); /* Count points and validate poligons */ for (i = 0; i < Count; i++) { if (UnsafeCounts[i] < 2) { nInvalid++; } nPoints += UnsafeCounts[i]; nMaxPoints = max(nMaxPoints, UnsafeCounts[i]); } } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Status = _SEH2_GetExceptionCode(); } _SEH2_END; if (!NT_SUCCESS(Status)) { /* Windows doesn't set last error */ return FALSE; } if (nPoints == 0 || nPoints < nMaxPoints) { /* If all polygon counts are zero, or we have overflow, return without setting a last error code. */ return FALSE; } if (nInvalid != 0) { /* If at least one poly count is 0 or 1, fail */ EngSetLastError(ERROR_INVALID_PARAMETER); return FALSE; } /* Allocate one buffer for both counts and points */ pTemp = ExAllocatePoolWithTag(PagedPool, Count * sizeof(ULONG) + nPoints * sizeof(POINT), TAG_SHAPE); if (!pTemp) { EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); return FALSE; } SafeCounts = pTemp; SafePoints = (PVOID)(SafeCounts + Count); _SEH2_TRY { /* Pointers already probed! */ RtlCopyMemory(SafeCounts, UnsafeCounts, Count * sizeof(ULONG)); RtlCopyMemory(SafePoints, UnsafePoints, nPoints * sizeof(POINT)); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Status = _SEH2_GetExceptionCode(); } _SEH2_END; if (!NT_SUCCESS(Status)) { ExFreePoolWithTag(pTemp, TAG_SHAPE); return FALSE; } /* Special handling for GdiPolyPolyRgn */ if (iFunc == GdiPolyPolyRgn) { HRGN hRgn; hRgn = IntCreatePolyPolygonRgn(SafePoints, SafeCounts, Count, (INT_PTR)hDC); ExFreePoolWithTag(pTemp, TAG_SHAPE); return (ULONG_PTR)hRgn; } dc = DC_LockDc(hDC); if (!dc) { EngSetLastError(ERROR_INVALID_HANDLE); ExFreePoolWithTag(pTemp, TAG_SHAPE); return FALSE; } if (dc->dctype == DC_TYPE_INFO) { DC_UnlockDc(dc); ExFreePoolWithTag(pTemp, TAG_SHAPE); /* Yes, Windows really returns TRUE in this case */ return TRUE; } DC_vPrepareDCsForBlit(dc, dc->rosdc.CombinedClip->rclBounds, NULL, dc->rosdc.CombinedClip->rclBounds); if (dc->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY)) DC_vUpdateFillBrush(dc); if (dc->pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY)) DC_vUpdateLineBrush(dc); /* Perform the actual work */ switch (iFunc) { case GdiPolyPolygon: Ret = IntGdiPolyPolygon(dc, SafePoints, SafeCounts, Count); break; case GdiPolyPolyLine: Ret = IntGdiPolyPolyline(dc, SafePoints, SafeCounts, Count); break; case GdiPolyBezier: Ret = IntGdiPolyBezier(dc, SafePoints, *SafeCounts); break; case GdiPolyLineTo: Ret = IntGdiPolylineTo(dc, SafePoints, *SafeCounts); break; case GdiPolyBezierTo: Ret = IntGdiPolyBezierTo(dc, SafePoints, *SafeCounts); break; default: EngSetLastError(ERROR_INVALID_PARAMETER); Ret = FALSE; } /* Cleanup and return */ DC_vFinishBlit(dc, NULL); DC_UnlockDc(dc); ExFreePoolWithTag(pTemp, TAG_SHAPE); return (ULONG_PTR)Ret; }
BOOL APIENTRY NtGdiEllipse( HDC hDC, int Left, int Top, int Right, int Bottom) { PDC dc; PDC_ATTR pdcattr; RECTL RectBounds; PBRUSH pbrush; BOOL ret = TRUE; LONG PenWidth, PenOrigWidth; LONG RadiusX, RadiusY, CenterX, CenterY; PBRUSH pFillBrushObj; BRUSH tmpFillBrushObj; if ((Left == Right) || (Top == Bottom)) return TRUE; dc = DC_LockDc(hDC); if (dc == NULL) { EngSetLastError(ERROR_INVALID_HANDLE); return FALSE; } if (dc->dctype == DC_TYPE_INFO) { DC_UnlockDc(dc); /* Yes, Windows really returns TRUE in this case */ return TRUE; } if (PATH_IsPathOpen(dc->dclevel)) { ret = PATH_Ellipse(dc, Left, Top, Right, Bottom); DC_UnlockDc(dc); return ret; } if (Right < Left) { INT tmp = Right; Right = Left; Left = tmp; } if (Bottom < Top) { INT tmp = Bottom; Bottom = Top; Top = tmp; } pdcattr = dc->pdcattr; if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY)) DC_vUpdateFillBrush(dc); if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY)) DC_vUpdateLineBrush(dc); pbrush = PEN_ShareLockPen(pdcattr->hpen); if (!pbrush) { DPRINT1("Ellipse Fail 1\n"); DC_UnlockDc(dc); EngSetLastError(ERROR_INTERNAL_ERROR); return FALSE; } PenOrigWidth = PenWidth = pbrush->ptPenWidth.x; if (pbrush->ulPenStyle == PS_NULL) PenWidth = 0; if (pbrush->ulPenStyle == PS_INSIDEFRAME) { if (2*PenWidth > (Right - Left)) PenWidth = (Right -Left + 1)/2; if (2*PenWidth > (Bottom - Top)) PenWidth = (Bottom -Top + 1)/2; Left += PenWidth / 2; Right -= (PenWidth - 1) / 2; Top += PenWidth / 2; Bottom -= (PenWidth - 1) / 2; } if (!PenWidth) PenWidth = 1; pbrush->ptPenWidth.x = PenWidth; RectBounds.left = Left; RectBounds.right = Right; RectBounds.top = Top; RectBounds.bottom = Bottom; IntLPtoDP(dc, (LPPOINT)&RectBounds, 2); RectBounds.left += dc->ptlDCOrig.x; RectBounds.right += dc->ptlDCOrig.x; RectBounds.top += dc->ptlDCOrig.y; RectBounds.bottom += dc->ptlDCOrig.y; // Setup for dynamic width and height. RadiusX = max((RectBounds.right - RectBounds.left) / 2, 2); // Needs room RadiusY = max((RectBounds.bottom - RectBounds.top) / 2, 2); CenterX = (RectBounds.right + RectBounds.left) / 2; CenterY = (RectBounds.bottom + RectBounds.top) / 2; DPRINT("Ellipse 1: Left: %d, Top: %d, Right: %d, Bottom: %d\n", RectBounds.left,RectBounds.top,RectBounds.right,RectBounds.bottom); DPRINT("Ellipse 2: XLeft: %d, YLeft: %d, Width: %d, Height: %d\n", CenterX - RadiusX, CenterY + RadiusY, RadiusX*2, RadiusY*2); pFillBrushObj = BRUSH_ShareLockBrush(pdcattr->hbrush); if (NULL == pFillBrushObj) { DPRINT1("FillEllipse Fail\n"); EngSetLastError(ERROR_INTERNAL_ERROR); ret = FALSE; } else { RtlCopyMemory(&tmpFillBrushObj, pFillBrushObj, sizeof(tmpFillBrushObj)); //tmpFillBrushObj.ptOrigin.x += RectBounds.left - Left; //tmpFillBrushObj.ptOrigin.y += RectBounds.top - Top; tmpFillBrushObj.ptOrigin.x += dc->ptlDCOrig.x; tmpFillBrushObj.ptOrigin.y += dc->ptlDCOrig.y; DC_vPrepareDCsForBlit(dc, RectBounds, NULL, RectBounds); ret = IntFillEllipse( dc, CenterX - RadiusX, CenterY - RadiusY, RadiusX*2, // Width RadiusY*2, // Height &tmpFillBrushObj); BRUSH_ShareUnlockBrush(pFillBrushObj); if (ret) { ret = IntDrawEllipse( dc, CenterX - RadiusX, CenterY - RadiusY, RadiusX*2, // Width RadiusY*2, // Height pbrush); } DC_vFinishBlit(dc, NULL); } pbrush->ptPenWidth.x = PenOrigWidth; PEN_ShareUnlockPen(pbrush); DC_UnlockDc(dc); DPRINT("Ellipse Exit.\n"); return ret; }
BOOL FASTCALL IntGdiPolygon(PDC dc, PPOINT Points, int Count) { SURFACE *psurf; PBRUSH pbrLine, pbrFill; BOOL ret = FALSE; // Default to failure RECTL DestRect; int CurrentPoint; PDC_ATTR pdcattr; POINTL BrushOrigin; // int Left; // int Top; ASSERT(dc); // Caller's responsibility to pass a valid dc if (!Points || Count < 2 ) { EngSetLastError(ERROR_INVALID_PARAMETER); return FALSE; } /* // Find start x, y Left = Points[0].x; Top = Points[0].y; for (CurrentPoint = 1; CurrentPoint < Count; ++CurrentPoint) { Left = min(Left, Points[CurrentPoint].x); Top = min(Top, Points[CurrentPoint].y); } */ pdcattr = dc->pdcattr; /* Convert to screen coordinates */ IntLPtoDP(dc, Points, Count); for (CurrentPoint = 0; CurrentPoint < Count; CurrentPoint++) { Points[CurrentPoint].x += dc->ptlDCOrig.x; Points[CurrentPoint].y += dc->ptlDCOrig.y; } // No need to have path here. { DestRect.left = Points[0].x; DestRect.right = Points[0].x; DestRect.top = Points[0].y; DestRect.bottom = Points[0].y; for (CurrentPoint = 1; CurrentPoint < Count; ++CurrentPoint) { DestRect.left = min(DestRect.left, Points[CurrentPoint].x); DestRect.right = max(DestRect.right, Points[CurrentPoint].x); DestRect.top = min(DestRect.top, Points[CurrentPoint].y); DestRect.bottom = max(DestRect.bottom, Points[CurrentPoint].y); } if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY)) DC_vUpdateFillBrush(dc); if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY)) DC_vUpdateLineBrush(dc); /* Special locking order to avoid lock-ups */ pbrFill = dc->dclevel.pbrFill; pbrLine = dc->dclevel.pbrLine; psurf = dc->dclevel.pSurface; /* FIXME: psurf can be NULL!!!! don't assert but handle this case gracefully! */ ASSERT(psurf); /* Now fill the polygon with the current fill brush. */ if (!(pbrFill->flAttrs & BR_IS_NULL)) { BrushOrigin = *((PPOINTL)&pbrFill->ptOrigin); BrushOrigin.x += dc->ptlDCOrig.x; BrushOrigin.y += dc->ptlDCOrig.y; ret = IntFillPolygon (dc, psurf, &dc->eboFill.BrushObject, Points, Count, DestRect, &BrushOrigin); } // Draw the Polygon Edges with the current pen ( if not a NULL pen ) if (!(pbrLine->flAttrs & BR_IS_NULL)) { int i; for (i = 0; i < Count-1; i++) { // DPRINT1("Polygon Making line from (%d,%d) to (%d,%d)\n", // Points[0].x, Points[0].y, // Points[1].x, Points[1].y ); ret = IntEngLineTo(&psurf->SurfObj, dc->rosdc.CombinedClip, &dc->eboLine.BrushObject, Points[i].x, /* From */ Points[i].y, Points[i+1].x, /* To */ Points[i+1].y, &DestRect, ROP2_TO_MIX(pdcattr->jROP2)); /* MIX */ if (!ret) break; } /* Close the polygon */ if (ret) { ret = IntEngLineTo(&psurf->SurfObj, dc->rosdc.CombinedClip, &dc->eboLine.BrushObject, Points[Count-1].x, /* From */ Points[Count-1].y, Points[0].x, /* To */ Points[0].y, &DestRect, ROP2_TO_MIX(pdcattr->jROP2)); /* MIX */ } } } return ret; }
BOOL APIENTRY NtGdiExtFloodFill( HDC hDC, INT XStart, INT YStart, COLORREF Color, UINT FillType) { PDC dc; PDC_ATTR pdcattr; SURFACE *psurf = NULL; EXLATEOBJ exlo; BOOL Ret = FALSE; RECTL DestRect; POINTL Pt; ULONG ConvColor; dc = DC_LockDc(hDC); if (!dc) { EngSetLastError(ERROR_INVALID_HANDLE); return FALSE; } if (dc->dctype == DC_TYPE_INFO) { DC_UnlockDc(dc); /* Yes, Windows really returns TRUE in this case */ return TRUE; } pdcattr = dc->pdcattr; if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY)) DC_vUpdateFillBrush(dc); if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY)) DC_vUpdateLineBrush(dc); Pt.x = XStart; Pt.y = YStart; IntLPtoDP(dc, (LPPOINT)&Pt, 1); Ret = NtGdiPtInRegion(dc->rosdc.hGCClipRgn, Pt.x, Pt.y); if (Ret) IntGdiGetRgnBox(dc->rosdc.hGCClipRgn,(LPRECT)&DestRect); else goto cleanup; DC_vPrepareDCsForBlit(dc, DestRect, NULL, DestRect); psurf = dc->dclevel.pSurface; if (!psurf) { Ret = FALSE; goto cleanup; } EXLATEOBJ_vInitialize(&exlo, &gpalRGB, psurf->ppal, 0, 0xffffff, 0); /* Only solid fills supported for now * How to support pattern brushes and non standard surfaces (not offering dib functions): * Version a (most likely slow): call DrvPatBlt for every pixel * Version b: create a flood mask and let MaskBlt blit a masked brush */ ConvColor = XLATEOBJ_iXlate(&exlo.xlo, Color); Ret = DIB_XXBPP_FloodFillSolid(&psurf->SurfObj, &dc->eboFill.BrushObject, &DestRect, &Pt, ConvColor, FillType); EXLATEOBJ_vCleanup(&exlo); cleanup: DC_vFinishBlit(dc, NULL); DC_UnlockDc(dc); return Ret; }
HANDLE APIENTRY NtGdiGetDCObject(HDC hDC, INT ObjectType) { HGDIOBJ SelObject; DC *pdc; PDC_ATTR pdcattr; /* From Wine: GetCurrentObject does not SetLastError() on a null object */ if(!hDC) return NULL; if(!(pdc = DC_LockDc(hDC))) { EngSetLastError(ERROR_INVALID_HANDLE); return NULL; } pdcattr = pdc->pdcattr; if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY)) DC_vUpdateFillBrush(pdc); if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY)) DC_vUpdateLineBrush(pdc); switch(ObjectType) { case GDI_OBJECT_TYPE_EXTPEN: case GDI_OBJECT_TYPE_PEN: SelObject = pdcattr->hpen; break; case GDI_OBJECT_TYPE_BRUSH: SelObject = pdcattr->hbrush; break; case GDI_OBJECT_TYPE_PALETTE: SelObject = pdc->dclevel.hpal; break; case GDI_OBJECT_TYPE_FONT: SelObject = pdcattr->hlfntNew; break; case GDI_OBJECT_TYPE_BITMAP: { SURFACE *psurf = pdc->dclevel.pSurface; SelObject = psurf ? psurf->BaseObject.hHmgr : NULL; break; } case GDI_OBJECT_TYPE_COLORSPACE: DPRINT1("FIXME: NtGdiGetCurrentObject() ObjectType OBJ_COLORSPACE not supported yet!\n"); // SelObject = dc->dclevel.pColorSpace.BaseObject.hHmgr; ? SelObject = NULL; break; default: SelObject = NULL; EngSetLastError(ERROR_INVALID_PARAMETER); break; } DC_UnlockDc(pdc); return SelObject; }
/* rc1 and rc2 are the rectangles where we want to draw or * from where we take pixels. */ VOID FASTCALL DC_vPrepareDCsForBlit( PDC pdcDest, const RECT* rcDest, PDC pdcSrc, const RECT* rcSrc) { PDC pdcFirst, pdcSecond; const RECT *prcFirst, *prcSecond; /* Update brushes */ if (pdcDest->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY)) DC_vUpdateFillBrush(pdcDest); if (pdcDest->pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY)) DC_vUpdateLineBrush(pdcDest); if(pdcDest->pdcattr->ulDirty_ & DIRTY_TEXT) DC_vUpdateTextBrush(pdcDest); /* Lock them in good order */ if(pdcSrc) { if((ULONG_PTR)pdcDest->ppdev->hsemDevLock >= (ULONG_PTR)pdcSrc->ppdev->hsemDevLock) { pdcFirst = pdcDest; prcFirst = rcDest; pdcSecond = pdcSrc; prcSecond = rcSrc; } else { pdcFirst = pdcSrc; prcFirst = rcSrc; pdcSecond = pdcDest; prcSecond = rcDest; } } else { pdcFirst = pdcDest ; prcFirst = rcDest; pdcSecond = NULL; prcSecond = NULL; } /* Update clipping of dest DC if needed */ if (pdcDest->dctype == DCTYPE_DIRECT) { DCE* dce = DceGetDceFromDC(pdcDest->BaseObject.hHmgr); if (dce) DceUpdateVisRgn(dce, dce->pwndOrg, dce->DCXFlags); } if (pdcDest->fs & DC_FLAG_DIRTY_RAO) CLIPPING_UpdateGCRegion(pdcDest); /* Lock and update first DC */ if(pdcFirst->dctype == DCTYPE_DIRECT) { EngAcquireSemaphore(pdcFirst->ppdev->hsemDevLock); /* Update surface if needed */ if(pdcFirst->ppdev->pSurface != pdcFirst->dclevel.pSurface) { DC_vUpdateDC(pdcFirst); } } if(pdcFirst->dctype == DCTYPE_DIRECT) { if (!prcFirst) prcFirst = &pdcFirst->erclClip; MouseSafetyOnDrawStart(pdcFirst->ppdev, prcFirst->left, prcFirst->top, prcFirst->right, prcFirst->bottom) ; } if (!pdcSecond) return; /* Lock and update second DC */ if(pdcSecond->dctype == DCTYPE_DIRECT) { EngAcquireSemaphore(pdcSecond->ppdev->hsemDevLock); /* Update surface if needed */ if(pdcSecond->ppdev->pSurface != pdcSecond->dclevel.pSurface) { DC_vUpdateDC(pdcSecond); } } if(pdcSecond->dctype == DCTYPE_DIRECT) { if (!prcSecond) prcSecond = &pdcSecond->erclClip; MouseSafetyOnDrawStart(pdcSecond->ppdev, prcSecond->left, prcSecond->top, prcSecond->right, prcSecond->bottom) ; } }
/* rc1 and rc2 are the rectangles where we want to draw or * from where we take pixels. */ VOID FASTCALL DC_vPrepareDCsForBlit(PDC pdc1, RECT rc1, PDC pdc2, RECT rc2) { PDC pdcFirst, pdcSecond; PRECT prcFirst, prcSecond; /* Update brushes */ if (pdc1->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY)) DC_vUpdateFillBrush(pdc1); if (pdc1->pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY)) DC_vUpdateLineBrush(pdc1); if(pdc1->pdcattr->ulDirty_ & DIRTY_TEXT) DC_vUpdateTextBrush(pdc1); /* Lock them in good order */ if(pdc2) { if((ULONG_PTR)pdc1->ppdev->hsemDevLock >= (ULONG_PTR)pdc2->ppdev->hsemDevLock) { pdcFirst = pdc1; prcFirst = &rc1; pdcSecond = pdc2; prcSecond = &rc2; } else { pdcFirst = pdc2; prcFirst = &rc2; pdcSecond = pdc1; prcSecond = &rc1; } } else { pdcFirst = pdc1 ; prcFirst = &rc1; pdcSecond = NULL; prcSecond = NULL; } if(pdcFirst && pdcFirst->dctype == DCTYPE_DIRECT) { EngAcquireSemaphore(pdcFirst->ppdev->hsemDevLock); MouseSafetyOnDrawStart(pdcFirst->ppdev, prcFirst->left, prcFirst->top, prcFirst->right, prcFirst->bottom) ; /* Update surface if needed */ if(pdcFirst->ppdev->pSurface != pdcFirst->dclevel.pSurface) { DC_vUpdateDC(pdcFirst); } } if(pdcSecond && pdcSecond->dctype == DCTYPE_DIRECT) { EngAcquireSemaphore(pdcSecond->ppdev->hsemDevLock); MouseSafetyOnDrawStart(pdcSecond->ppdev, prcSecond->left, prcSecond->top, prcSecond->right, prcSecond->bottom) ; /* Update surface if needed */ if(pdcSecond->ppdev->pSurface != pdcSecond->dclevel.pSurface) { DC_vUpdateDC(pdcSecond); } } }