Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenfillshap.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS win32 kernel mode subsystem 00003 * LICENSE: GPL - See COPYING in the top level directory 00004 * FILE: subsystems/win32/win32k/objects/fillshap.c 00005 * PURPOSE: fillshap 00006 * PROGRAMMER: 00007 */ 00008 00009 #include <win32k.h> 00010 00011 #define NDEBUG 00012 #include <debug.h> 00013 00014 #define Rsin(d) ((d) == 0.0 ? 0.0 : ((d) == 90.0 ? 1.0 : sin(d*M_PI/180.0))) 00015 #define Rcos(d) ((d) == 0.0 ? 1.0 : ((d) == 90.0 ? 0.0 : cos(d*M_PI/180.0))) 00016 00017 BOOL FASTCALL 00018 IntGdiPolygon(PDC dc, 00019 PPOINT Points, 00020 int Count) 00021 { 00022 SURFACE *psurf; 00023 PBRUSH pbrLine, pbrFill; 00024 BOOL ret = FALSE; // Default to failure 00025 RECTL DestRect; 00026 int CurrentPoint; 00027 PDC_ATTR pdcattr; 00028 POINTL BrushOrigin; 00029 // int Left; 00030 // int Top; 00031 00032 ASSERT(dc); // Caller's responsibility to pass a valid dc 00033 00034 if (!Points || Count < 2 ) 00035 { 00036 EngSetLastError(ERROR_INVALID_PARAMETER); 00037 return FALSE; 00038 } 00039 00040 /* 00041 // Find start x, y 00042 Left = Points[0].x; 00043 Top = Points[0].y; 00044 for (CurrentPoint = 1; CurrentPoint < Count; ++CurrentPoint) { 00045 Left = min(Left, Points[CurrentPoint].x); 00046 Top = min(Top, Points[CurrentPoint].y); 00047 } 00048 */ 00049 00050 pdcattr = dc->pdcattr; 00051 00052 /* Convert to screen coordinates */ 00053 IntLPtoDP(dc, Points, Count); 00054 for (CurrentPoint = 0; CurrentPoint < Count; CurrentPoint++) 00055 { 00056 Points[CurrentPoint].x += dc->ptlDCOrig.x; 00057 Points[CurrentPoint].y += dc->ptlDCOrig.y; 00058 } 00059 // No need to have path here. 00060 { 00061 DestRect.left = Points[0].x; 00062 DestRect.right = Points[0].x; 00063 DestRect.top = Points[0].y; 00064 DestRect.bottom = Points[0].y; 00065 00066 for (CurrentPoint = 1; CurrentPoint < Count; ++CurrentPoint) 00067 { 00068 DestRect.left = min(DestRect.left, Points[CurrentPoint].x); 00069 DestRect.right = max(DestRect.right, Points[CurrentPoint].x); 00070 DestRect.top = min(DestRect.top, Points[CurrentPoint].y); 00071 DestRect.bottom = max(DestRect.bottom, Points[CurrentPoint].y); 00072 } 00073 00074 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY)) 00075 DC_vUpdateFillBrush(dc); 00076 00077 if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY)) 00078 DC_vUpdateLineBrush(dc); 00079 00080 /* Special locking order to avoid lock-ups */ 00081 pbrFill = dc->dclevel.pbrFill; 00082 pbrLine = dc->dclevel.pbrLine; 00083 psurf = dc->dclevel.pSurface; 00084 /* FIXME: psurf can be NULL!!!! don't assert but handle this case gracefully! */ 00085 ASSERT(psurf); 00086 00087 /* Now fill the polygon with the current fill brush. */ 00088 if (!(pbrFill->flAttrs & BR_IS_NULL)) 00089 { 00090 BrushOrigin = *((PPOINTL)&pbrFill->ptOrigin); 00091 BrushOrigin.x += dc->ptlDCOrig.x; 00092 BrushOrigin.y += dc->ptlDCOrig.y; 00093 ret = IntFillPolygon (dc, 00094 psurf, 00095 &dc->eboFill.BrushObject, 00096 Points, 00097 Count, 00098 DestRect, 00099 &BrushOrigin); 00100 } 00101 00102 // Draw the Polygon Edges with the current pen ( if not a NULL pen ) 00103 if (!(pbrLine->flAttrs & BR_IS_NULL)) 00104 { 00105 int i; 00106 00107 for (i = 0; i < Count-1; i++) 00108 { 00109 00110 // DPRINT1("Polygon Making line from (%d,%d) to (%d,%d)\n", 00111 // Points[0].x, Points[0].y, 00112 // Points[1].x, Points[1].y ); 00113 00114 ret = IntEngLineTo(&psurf->SurfObj, 00115 dc->rosdc.CombinedClip, 00116 &dc->eboLine.BrushObject, 00117 Points[i].x, /* From */ 00118 Points[i].y, 00119 Points[i+1].x, /* To */ 00120 Points[i+1].y, 00121 &DestRect, 00122 ROP2_TO_MIX(pdcattr->jROP2)); /* MIX */ 00123 if (!ret) break; 00124 } 00125 /* Close the polygon */ 00126 if (ret) 00127 { 00128 ret = IntEngLineTo(&psurf->SurfObj, 00129 dc->rosdc.CombinedClip, 00130 &dc->eboLine.BrushObject, 00131 Points[Count-1].x, /* From */ 00132 Points[Count-1].y, 00133 Points[0].x, /* To */ 00134 Points[0].y, 00135 &DestRect, 00136 ROP2_TO_MIX(pdcattr->jROP2)); /* MIX */ 00137 } 00138 } 00139 } 00140 00141 return ret; 00142 } 00143 00144 BOOL FASTCALL 00145 IntGdiPolyPolygon(DC *dc, 00146 LPPOINT Points, 00147 PULONG PolyCounts, 00148 int Count) 00149 { 00150 if (PATH_IsPathOpen(dc->dclevel)) 00151 return PATH_PolyPolygon ( dc, Points, (PINT)PolyCounts, Count); 00152 00153 while (--Count >=0) 00154 { 00155 if (!IntGdiPolygon ( dc, Points, *PolyCounts )) 00156 return FALSE; 00157 Points+=*PolyCounts++; 00158 } 00159 return TRUE; 00160 } 00161 00162 00163 00164 /******************************************************************************/ 00165 00166 /* 00167 * NtGdiEllipse 00168 * 00169 * Author 00170 * Filip Navara 00171 * 00172 * Remarks 00173 * This function uses optimized Bresenham's ellipse algorithm. It draws 00174 * four lines of the ellipse in one pass. 00175 * 00176 */ 00177 00178 BOOL APIENTRY 00179 NtGdiEllipse( 00180 HDC hDC, 00181 int Left, 00182 int Top, 00183 int Right, 00184 int Bottom) 00185 { 00186 PDC dc; 00187 PDC_ATTR pdcattr; 00188 RECTL RectBounds; 00189 PBRUSH pbrush; 00190 BOOL ret = TRUE; 00191 LONG PenWidth, PenOrigWidth; 00192 LONG RadiusX, RadiusY, CenterX, CenterY; 00193 PBRUSH pFillBrushObj; 00194 BRUSH tmpFillBrushObj; 00195 00196 if ((Left == Right) || (Top == Bottom)) return TRUE; 00197 00198 dc = DC_LockDc(hDC); 00199 if (dc == NULL) 00200 { 00201 EngSetLastError(ERROR_INVALID_HANDLE); 00202 return FALSE; 00203 } 00204 if (dc->dctype == DC_TYPE_INFO) 00205 { 00206 DC_UnlockDc(dc); 00207 /* Yes, Windows really returns TRUE in this case */ 00208 return TRUE; 00209 } 00210 00211 if (PATH_IsPathOpen(dc->dclevel)) 00212 { 00213 ret = PATH_Ellipse(dc, Left, Top, Right, Bottom); 00214 DC_UnlockDc(dc); 00215 return ret; 00216 } 00217 00218 if (Right < Left) 00219 { 00220 INT tmp = Right; Right = Left; Left = tmp; 00221 } 00222 if (Bottom < Top) 00223 { 00224 INT tmp = Bottom; Bottom = Top; Top = tmp; 00225 } 00226 00227 pdcattr = dc->pdcattr; 00228 00229 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY)) 00230 DC_vUpdateFillBrush(dc); 00231 00232 if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY)) 00233 DC_vUpdateLineBrush(dc); 00234 00235 pbrush = PEN_ShareLockPen(pdcattr->hpen); 00236 if (!pbrush) 00237 { 00238 DPRINT1("Ellipse Fail 1\n"); 00239 DC_UnlockDc(dc); 00240 EngSetLastError(ERROR_INTERNAL_ERROR); 00241 return FALSE; 00242 } 00243 00244 PenOrigWidth = PenWidth = pbrush->ptPenWidth.x; 00245 if (pbrush->ulPenStyle == PS_NULL) PenWidth = 0; 00246 00247 if (pbrush->ulPenStyle == PS_INSIDEFRAME) 00248 { 00249 if (2*PenWidth > (Right - Left)) PenWidth = (Right -Left + 1)/2; 00250 if (2*PenWidth > (Bottom - Top)) PenWidth = (Bottom -Top + 1)/2; 00251 Left += PenWidth / 2; 00252 Right -= (PenWidth - 1) / 2; 00253 Top += PenWidth / 2; 00254 Bottom -= (PenWidth - 1) / 2; 00255 } 00256 00257 if (!PenWidth) PenWidth = 1; 00258 pbrush->ptPenWidth.x = PenWidth; 00259 00260 RectBounds.left = Left; 00261 RectBounds.right = Right; 00262 RectBounds.top = Top; 00263 RectBounds.bottom = Bottom; 00264 00265 IntLPtoDP(dc, (LPPOINT)&RectBounds, 2); 00266 00267 RectBounds.left += dc->ptlDCOrig.x; 00268 RectBounds.right += dc->ptlDCOrig.x; 00269 RectBounds.top += dc->ptlDCOrig.y; 00270 RectBounds.bottom += dc->ptlDCOrig.y; 00271 00272 // Setup for dynamic width and height. 00273 RadiusX = max((RectBounds.right - RectBounds.left) / 2, 2); // Needs room 00274 RadiusY = max((RectBounds.bottom - RectBounds.top) / 2, 2); 00275 CenterX = (RectBounds.right + RectBounds.left) / 2; 00276 CenterY = (RectBounds.bottom + RectBounds.top) / 2; 00277 00278 DPRINT("Ellipse 1: Left: %d, Top: %d, Right: %d, Bottom: %d\n", 00279 RectBounds.left,RectBounds.top,RectBounds.right,RectBounds.bottom); 00280 00281 DPRINT("Ellipse 2: XLeft: %d, YLeft: %d, Width: %d, Height: %d\n", 00282 CenterX - RadiusX, CenterY + RadiusY, RadiusX*2, RadiusY*2); 00283 00284 pFillBrushObj = BRUSH_ShareLockBrush(pdcattr->hbrush); 00285 if (NULL == pFillBrushObj) 00286 { 00287 DPRINT1("FillEllipse Fail\n"); 00288 EngSetLastError(ERROR_INTERNAL_ERROR); 00289 ret = FALSE; 00290 } 00291 else 00292 { 00293 RtlCopyMemory(&tmpFillBrushObj, pFillBrushObj, sizeof(tmpFillBrushObj)); 00294 //tmpFillBrushObj.ptOrigin.x += RectBounds.left - Left; 00295 //tmpFillBrushObj.ptOrigin.y += RectBounds.top - Top; 00296 tmpFillBrushObj.ptOrigin.x += dc->ptlDCOrig.x; 00297 tmpFillBrushObj.ptOrigin.y += dc->ptlDCOrig.y; 00298 ret = IntFillEllipse( dc, 00299 CenterX - RadiusX, 00300 CenterY - RadiusY, 00301 RadiusX*2, // Width 00302 RadiusY*2, // Height 00303 &tmpFillBrushObj); 00304 BRUSH_ShareUnlockBrush(pFillBrushObj); 00305 } 00306 00307 if (ret) 00308 ret = IntDrawEllipse( dc, 00309 CenterX - RadiusX, 00310 CenterY - RadiusY, 00311 RadiusX*2, // Width 00312 RadiusY*2, // Height 00313 pbrush); 00314 00315 pbrush->ptPenWidth.x = PenOrigWidth; 00316 PEN_ShareUnlockPen(pbrush); 00317 DC_UnlockDc(dc); 00318 DPRINT("Ellipse Exit.\n"); 00319 return ret; 00320 } 00321 00322 #if 0 00323 00324 // When the fill mode is ALTERNATE, GDI fills the area between odd-numbered and 00325 // even-numbered polygon sides on each scan line. That is, GDI fills the area between the 00326 // first and second side, between the third and fourth side, and so on. 00327 00328 // WINDING Selects winding mode (fills any region with a nonzero winding value). 00329 // When the fill mode is WINDING, GDI fills any region that has a nonzero winding value. 00330 // This value is defined as the number of times a pen used to draw the polygon would go around the region. 00331 // The direction of each edge of the polygon is important. 00332 00333 extern BOOL FillPolygon(PDC dc, 00334 SURFOBJ *SurfObj, 00335 PBRUSHOBJ BrushObj, 00336 MIX RopMode, 00337 CONST PPOINT Points, 00338 int Count, 00339 RECTL BoundRect); 00340 00341 #endif 00342 00343 00344 ULONG_PTR 00345 APIENTRY 00346 NtGdiPolyPolyDraw( IN HDC hDC, 00347 IN PPOINT UnsafePoints, 00348 IN PULONG UnsafeCounts, 00349 IN ULONG Count, 00350 IN INT iFunc ) 00351 { 00352 DC *dc; 00353 PVOID pTemp; 00354 LPPOINT SafePoints; 00355 PULONG SafeCounts; 00356 NTSTATUS Status = STATUS_SUCCESS; 00357 BOOL Ret = TRUE; 00358 ULONG nPoints = 0, nMaxPoints = 0, nInvalid = 0, i; 00359 00360 if (!UnsafePoints || !UnsafeCounts || 00361 Count == 0 || iFunc == 0 || iFunc > GdiPolyPolyRgn) 00362 { 00363 /* Windows doesn't set last error */ 00364 return FALSE; 00365 } 00366 00367 _SEH2_TRY 00368 { 00369 ProbeForRead(UnsafePoints, Count * sizeof(POINT), 1); 00370 ProbeForRead(UnsafeCounts, Count * sizeof(ULONG), 1); 00371 00372 /* Count points and validate poligons */ 00373 for (i = 0; i < Count; i++) 00374 { 00375 if (UnsafeCounts[i] < 2) 00376 { 00377 nInvalid++; 00378 } 00379 nPoints += UnsafeCounts[i]; 00380 nMaxPoints = max(nMaxPoints, UnsafeCounts[i]); 00381 } 00382 } 00383 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 00384 { 00385 Status = _SEH2_GetExceptionCode(); 00386 } 00387 _SEH2_END; 00388 00389 if (!NT_SUCCESS(Status)) 00390 { 00391 /* Windows doesn't set last error */ 00392 return FALSE; 00393 } 00394 00395 if (nPoints == 0 || nPoints < nMaxPoints) 00396 { 00397 /* If all polygon counts are zero, or we have overflow, 00398 return without setting a last error code. */ 00399 return FALSE; 00400 } 00401 00402 if (nInvalid != 0) 00403 { 00404 /* If at least one poly count is 0 or 1, fail */ 00405 EngSetLastError(ERROR_INVALID_PARAMETER); 00406 return FALSE; 00407 } 00408 00409 /* Allocate one buffer for both counts and points */ 00410 pTemp = ExAllocatePoolWithTag(PagedPool, 00411 Count * sizeof(ULONG) + nPoints * sizeof(POINT), 00412 TAG_SHAPE); 00413 if (!pTemp) 00414 { 00415 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 00416 return FALSE; 00417 } 00418 00419 SafeCounts = pTemp; 00420 SafePoints = (PVOID)(SafeCounts + Count); 00421 00422 _SEH2_TRY 00423 { 00424 /* Pointers already probed! */ 00425 RtlCopyMemory(SafeCounts, UnsafeCounts, Count * sizeof(ULONG)); 00426 RtlCopyMemory(SafePoints, UnsafePoints, nPoints * sizeof(POINT)); 00427 } 00428 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 00429 { 00430 Status = _SEH2_GetExceptionCode(); 00431 } 00432 _SEH2_END; 00433 00434 if (!NT_SUCCESS(Status)) 00435 { 00436 ExFreePoolWithTag(pTemp, TAG_SHAPE); 00437 return FALSE; 00438 } 00439 00440 /* Special handling for GdiPolyPolyRgn */ 00441 if (iFunc == GdiPolyPolyRgn) 00442 { 00443 HRGN hRgn; 00444 hRgn = IntCreatePolyPolygonRgn(SafePoints, SafeCounts, Count, (INT_PTR)hDC); 00445 ExFreePoolWithTag(pTemp, TAG_SHAPE); 00446 return (ULONG_PTR)hRgn; 00447 } 00448 00449 dc = DC_LockDc(hDC); 00450 if (!dc) 00451 { 00452 EngSetLastError(ERROR_INVALID_HANDLE); 00453 ExFreePool(pTemp); 00454 return FALSE; 00455 } 00456 00457 if (dc->dctype == DC_TYPE_INFO) 00458 { 00459 DC_UnlockDc(dc); 00460 ExFreePool(pTemp); 00461 /* Yes, Windows really returns TRUE in this case */ 00462 return TRUE; 00463 } 00464 00465 DC_vPrepareDCsForBlit(dc, dc->rosdc.CombinedClip->rclBounds, 00466 NULL, dc->rosdc.CombinedClip->rclBounds); 00467 00468 if (dc->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY)) 00469 DC_vUpdateFillBrush(dc); 00470 00471 if (dc->pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY)) 00472 DC_vUpdateLineBrush(dc); 00473 00474 /* Perform the actual work */ 00475 switch (iFunc) 00476 { 00477 case GdiPolyPolygon: 00478 Ret = IntGdiPolyPolygon(dc, SafePoints, SafeCounts, Count); 00479 break; 00480 case GdiPolyPolyLine: 00481 Ret = IntGdiPolyPolyline(dc, SafePoints, SafeCounts, Count); 00482 break; 00483 case GdiPolyBezier: 00484 Ret = IntGdiPolyBezier(dc, SafePoints, *SafeCounts); 00485 break; 00486 case GdiPolyLineTo: 00487 Ret = IntGdiPolylineTo(dc, SafePoints, *SafeCounts); 00488 break; 00489 case GdiPolyBezierTo: 00490 Ret = IntGdiPolyBezierTo(dc, SafePoints, *SafeCounts); 00491 break; 00492 default: 00493 EngSetLastError(ERROR_INVALID_PARAMETER); 00494 Ret = FALSE; 00495 } 00496 00497 /* Cleanup and return */ 00498 DC_vFinishBlit(dc, NULL); 00499 DC_UnlockDc(dc); 00500 ExFreePool(pTemp); 00501 00502 return (ULONG_PTR)Ret; 00503 } 00504 00505 00506 BOOL 00507 FASTCALL 00508 IntRectangle(PDC dc, 00509 int LeftRect, 00510 int TopRect, 00511 int RightRect, 00512 int BottomRect) 00513 { 00514 SURFACE *psurf = NULL; 00515 PBRUSH pbrLine, pbrFill; 00516 BOOL ret = FALSE; // Default to failure 00517 RECTL DestRect; 00518 MIX Mix; 00519 PDC_ATTR pdcattr; 00520 POINTL BrushOrigin; 00521 00522 ASSERT ( dc ); // Caller's responsibility to set this up 00523 00524 pdcattr = dc->pdcattr; 00525 00526 // Rectangle Path only. 00527 if ( PATH_IsPathOpen(dc->dclevel) ) 00528 { 00529 return PATH_Rectangle ( dc, LeftRect, TopRect, RightRect, BottomRect ); 00530 } 00531 00532 /* Make sure rectangle is not inverted */ 00533 DestRect.left = min(LeftRect, RightRect); 00534 DestRect.right = max(LeftRect, RightRect); 00535 DestRect.top = min(TopRect, BottomRect); 00536 DestRect.bottom = max(TopRect, BottomRect); 00537 00538 IntLPtoDP(dc, (LPPOINT)&DestRect, 2); 00539 00540 DestRect.left += dc->ptlDCOrig.x; 00541 DestRect.right += dc->ptlDCOrig.x; 00542 DestRect.top += dc->ptlDCOrig.y; 00543 DestRect.bottom += dc->ptlDCOrig.y; 00544 00545 /* In GM_COMPATIBLE, don't include bottom and right edges */ 00546 if (pdcattr->iGraphicsMode == GM_COMPATIBLE) 00547 { 00548 DestRect.right--; 00549 DestRect.bottom--; 00550 } 00551 00552 DC_vPrepareDCsForBlit(dc, DestRect, NULL, DestRect); 00553 00554 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY)) 00555 DC_vUpdateFillBrush(dc); 00556 00557 if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY)) 00558 DC_vUpdateLineBrush(dc); 00559 00560 pbrFill = dc->dclevel.pbrFill; 00561 pbrLine = dc->dclevel.pbrLine; 00562 if (!pbrLine) 00563 { 00564 ret = FALSE; 00565 goto cleanup; 00566 } 00567 00568 psurf = dc->dclevel.pSurface; 00569 if (!psurf) 00570 { 00571 ret = FALSE; 00572 goto cleanup; 00573 } 00574 00575 if (pbrFill) 00576 { 00577 if (!(pbrFill->flAttrs & BR_IS_NULL)) 00578 { 00579 BrushOrigin = *((PPOINTL)&pbrFill->ptOrigin); 00580 BrushOrigin.x += dc->ptlDCOrig.x; 00581 BrushOrigin.y += dc->ptlDCOrig.y; 00582 ret = IntEngBitBlt(&psurf->SurfObj, 00583 NULL, 00584 NULL, 00585 dc->rosdc.CombinedClip, 00586 NULL, 00587 &DestRect, 00588 NULL, 00589 NULL, 00590 &dc->eboFill.BrushObject, 00591 &BrushOrigin, 00592 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY)); 00593 } 00594 } 00595 00596 // Draw the rectangle with the current pen 00597 00598 ret = TRUE; // Change default to success 00599 00600 if (!(pbrLine->flAttrs & BR_IS_NULL)) 00601 { 00602 Mix = ROP2_TO_MIX(pdcattr->jROP2); 00603 ret = ret && IntEngLineTo(&psurf->SurfObj, 00604 dc->rosdc.CombinedClip, 00605 &dc->eboLine.BrushObject, 00606 DestRect.left, DestRect.top, DestRect.right, DestRect.top, 00607 &DestRect, // Bounding rectangle 00608 Mix); 00609 00610 ret = ret && IntEngLineTo(&psurf->SurfObj, 00611 dc->rosdc.CombinedClip, 00612 &dc->eboLine.BrushObject, 00613 DestRect.right, DestRect.top, DestRect.right, DestRect.bottom, 00614 &DestRect, // Bounding rectangle 00615 Mix); 00616 00617 ret = ret && IntEngLineTo(&psurf->SurfObj, 00618 dc->rosdc.CombinedClip, 00619 &dc->eboLine.BrushObject, 00620 DestRect.right, DestRect.bottom, DestRect.left, DestRect.bottom, 00621 &DestRect, // Bounding rectangle 00622 Mix); 00623 00624 ret = ret && IntEngLineTo(&psurf->SurfObj, 00625 dc->rosdc.CombinedClip, 00626 &dc->eboLine.BrushObject, 00627 DestRect.left, DestRect.bottom, DestRect.left, DestRect.top, 00628 &DestRect, // Bounding rectangle 00629 Mix); 00630 } 00631 00632 cleanup: 00633 DC_vFinishBlit(dc, NULL); 00634 00635 /* Move current position in DC? 00636 MSDN: The current position is neither used nor updated by Rectangle. */ 00637 00638 return ret; 00639 } 00640 00641 BOOL 00642 APIENTRY 00643 NtGdiRectangle(HDC hDC, 00644 int LeftRect, 00645 int TopRect, 00646 int RightRect, 00647 int BottomRect) 00648 { 00649 DC *dc; 00650 BOOL ret; // Default to failure 00651 00652 dc = DC_LockDc(hDC); 00653 if (!dc) 00654 { 00655 EngSetLastError(ERROR_INVALID_HANDLE); 00656 return FALSE; 00657 } 00658 if (dc->dctype == DC_TYPE_INFO) 00659 { 00660 DC_UnlockDc(dc); 00661 /* Yes, Windows really returns TRUE in this case */ 00662 return TRUE; 00663 } 00664 00665 /* Do we rotate or shear? */ 00666 if (!(dc->dclevel.mxWorldToDevice.flAccel & XFORM_SCALE)) 00667 { 00668 POINTL DestCoords[4]; 00669 ULONG PolyCounts = 4; 00670 00671 DestCoords[0].x = DestCoords[3].x = LeftRect; 00672 DestCoords[0].y = DestCoords[1].y = TopRect; 00673 DestCoords[1].x = DestCoords[2].x = RightRect; 00674 DestCoords[2].y = DestCoords[3].y = BottomRect; 00675 // Use IntGdiPolyPolygon so to support PATH. 00676 ret = IntGdiPolyPolygon(dc, DestCoords, &PolyCounts, 1); 00677 } 00678 else 00679 { 00680 ret = IntRectangle(dc, LeftRect, TopRect, RightRect, BottomRect ); 00681 } 00682 00683 DC_UnlockDc(dc); 00684 00685 return ret; 00686 } 00687 00688 00689 BOOL 00690 FASTCALL 00691 IntRoundRect( 00692 PDC dc, 00693 int Left, 00694 int Top, 00695 int Right, 00696 int Bottom, 00697 int xCurveDiameter, 00698 int yCurveDiameter) 00699 { 00700 PDC_ATTR pdcattr; 00701 PBRUSH pbrLine, pbrFill; 00702 RECTL RectBounds; 00703 LONG PenWidth, PenOrigWidth; 00704 BOOL ret = TRUE; // Default to success 00705 BRUSH brushTemp; 00706 00707 ASSERT ( dc ); // Caller's responsibility to set this up 00708 00709 if ( PATH_IsPathOpen(dc->dclevel) ) 00710 return PATH_RoundRect ( dc, Left, Top, Right, Bottom, 00711 xCurveDiameter, yCurveDiameter ); 00712 00713 if ((Left == Right) || (Top == Bottom)) return TRUE; 00714 00715 xCurveDiameter = max(abs( xCurveDiameter ), 1); 00716 yCurveDiameter = max(abs( yCurveDiameter ), 1); 00717 00718 if (Right < Left) 00719 { 00720 INT tmp = Right; Right = Left; Left = tmp; 00721 } 00722 if (Bottom < Top) 00723 { 00724 INT tmp = Bottom; Bottom = Top; Top = tmp; 00725 } 00726 00727 pdcattr = dc->pdcattr; 00728 00729 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY)) 00730 DC_vUpdateFillBrush(dc); 00731 00732 if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY)) 00733 DC_vUpdateLineBrush(dc); 00734 00735 pbrLine = PEN_ShareLockPen(pdcattr->hpen); 00736 if (!pbrLine) 00737 { 00738 /* Nothing to do, as we don't have a bitmap */ 00739 EngSetLastError(ERROR_INTERNAL_ERROR); 00740 return FALSE; 00741 } 00742 00743 PenOrigWidth = PenWidth = pbrLine->ptPenWidth.x; 00744 if (pbrLine->ulPenStyle == PS_NULL) PenWidth = 0; 00745 00746 if (pbrLine->ulPenStyle == PS_INSIDEFRAME) 00747 { 00748 if (2*PenWidth > (Right - Left)) PenWidth = (Right -Left + 1)/2; 00749 if (2*PenWidth > (Bottom - Top)) PenWidth = (Bottom -Top + 1)/2; 00750 Left += PenWidth / 2; 00751 Right -= (PenWidth - 1) / 2; 00752 Top += PenWidth / 2; 00753 Bottom -= (PenWidth - 1) / 2; 00754 } 00755 00756 if (!PenWidth) PenWidth = 1; 00757 pbrLine->ptPenWidth.x = PenWidth; 00758 00759 RectBounds.left = Left; 00760 RectBounds.top = Top; 00761 RectBounds.right = Right; 00762 RectBounds.bottom = Bottom; 00763 00764 IntLPtoDP(dc, (LPPOINT)&RectBounds, 2); 00765 00766 RectBounds.left += dc->ptlDCOrig.x; 00767 RectBounds.top += dc->ptlDCOrig.y; 00768 RectBounds.right += dc->ptlDCOrig.x; 00769 RectBounds.bottom += dc->ptlDCOrig.y; 00770 00771 pbrFill = BRUSH_ShareLockBrush(pdcattr->hbrush); 00772 if (!pbrFill) 00773 { 00774 DPRINT1("FillRound Fail\n"); 00775 EngSetLastError(ERROR_INTERNAL_ERROR); 00776 ret = FALSE; 00777 } 00778 else 00779 { 00780 RtlCopyMemory(&brushTemp, pbrFill, sizeof(brushTemp)); 00781 brushTemp.ptOrigin.x += RectBounds.left - Left; 00782 brushTemp.ptOrigin.y += RectBounds.top - Top; 00783 ret = IntFillRoundRect( dc, 00784 RectBounds.left, 00785 RectBounds.top, 00786 RectBounds.right, 00787 RectBounds.bottom, 00788 xCurveDiameter, 00789 yCurveDiameter, 00790 &brushTemp); 00791 BRUSH_ShareUnlockBrush(pbrFill); 00792 } 00793 00794 if (ret) 00795 ret = IntDrawRoundRect( dc, 00796 RectBounds.left, 00797 RectBounds.top, 00798 RectBounds.right, 00799 RectBounds.bottom, 00800 xCurveDiameter, 00801 yCurveDiameter, 00802 pbrLine); 00803 00804 pbrLine->ptPenWidth.x = PenOrigWidth; 00805 PEN_ShareUnlockPen(pbrLine); 00806 return ret; 00807 } 00808 00809 BOOL 00810 APIENTRY 00811 NtGdiRoundRect( 00812 HDC hDC, 00813 int LeftRect, 00814 int TopRect, 00815 int RightRect, 00816 int BottomRect, 00817 int Width, 00818 int Height) 00819 { 00820 DC *dc = DC_LockDc(hDC); 00821 BOOL ret = FALSE; /* Default to failure */ 00822 00823 DPRINT("NtGdiRoundRect(0x%x,%i,%i,%i,%i,%i,%i)\n",hDC,LeftRect,TopRect,RightRect,BottomRect,Width,Height); 00824 if ( !dc ) 00825 { 00826 DPRINT1("NtGdiRoundRect() - hDC is invalid\n"); 00827 EngSetLastError(ERROR_INVALID_HANDLE); 00828 } 00829 else if (dc->dctype == DC_TYPE_INFO) 00830 { 00831 DC_UnlockDc(dc); 00832 /* Yes, Windows really returns TRUE in this case */ 00833 ret = TRUE; 00834 } 00835 else 00836 { 00837 ret = IntRoundRect ( dc, LeftRect, TopRect, RightRect, BottomRect, Width, Height ); 00838 DC_UnlockDc ( dc ); 00839 } 00840 00841 return ret; 00842 } 00843 00844 BOOL 00845 NTAPI 00846 GreGradientFill( 00847 HDC hdc, 00848 PTRIVERTEX pVertex, 00849 ULONG nVertex, 00850 PVOID pMesh, 00851 ULONG nMesh, 00852 ULONG ulMode) 00853 { 00854 PDC pdc; 00855 SURFACE *psurf; 00856 EXLATEOBJ exlo; 00857 RECTL rclExtent; 00858 POINTL ptlDitherOrg; 00859 ULONG i; 00860 BOOL bRet; 00861 00862 /* Check parameters */ 00863 if (ulMode & GRADIENT_FILL_TRIANGLE) 00864 { 00865 PGRADIENT_TRIANGLE pTriangle = (PGRADIENT_TRIANGLE)pMesh; 00866 00867 for (i = 0; i < nMesh; i++, pTriangle++) 00868 { 00869 if (pTriangle->Vertex1 >= nVertex || 00870 pTriangle->Vertex2 >= nVertex || 00871 pTriangle->Vertex3 >= nVertex) 00872 { 00873 EngSetLastError(ERROR_INVALID_PARAMETER); 00874 return FALSE; 00875 } 00876 } 00877 } 00878 else 00879 { 00880 PGRADIENT_RECT pRect = (PGRADIENT_RECT)pMesh; 00881 for (i = 0; i < nMesh; i++, pRect++) 00882 { 00883 if (pRect->UpperLeft >= nVertex || pRect->LowerRight >= nVertex) 00884 { 00885 EngSetLastError(ERROR_INVALID_PARAMETER); 00886 return FALSE; 00887 } 00888 } 00889 } 00890 00891 /* Lock the output DC */ 00892 pdc = DC_LockDc(hdc); 00893 if(!pdc) 00894 { 00895 EngSetLastError(ERROR_INVALID_HANDLE); 00896 return FALSE; 00897 } 00898 00899 if(pdc->dctype == DC_TYPE_INFO) 00900 { 00901 DC_UnlockDc(pdc); 00902 /* Yes, Windows really returns TRUE in this case */ 00903 return TRUE; 00904 } 00905 00906 psurf = pdc->dclevel.pSurface; 00907 if(!psurf) 00908 { 00909 /* Memory DC with no surface selected */ 00910 DC_UnlockDc(pdc); 00911 return TRUE; // CHECKME 00912 } 00913 00914 /* Calculate extent */ 00915 rclExtent.left = rclExtent.right = pVertex->x; 00916 rclExtent.top = rclExtent.bottom = pVertex->y; 00917 for (i = 0; i < nVertex; i++) 00918 { 00919 rclExtent.left = min(rclExtent.left, (pVertex + i)->x); 00920 rclExtent.right = max(rclExtent.right, (pVertex + i)->x); 00921 rclExtent.top = min(rclExtent.top, (pVertex + i)->y); 00922 rclExtent.bottom = max(rclExtent.bottom, (pVertex + i)->y); 00923 } 00924 IntLPtoDP(pdc, (LPPOINT)&rclExtent, 2); 00925 00926 rclExtent.left += pdc->ptlDCOrig.x; 00927 rclExtent.right += pdc->ptlDCOrig.x; 00928 rclExtent.top += pdc->ptlDCOrig.y; 00929 rclExtent.bottom += pdc->ptlDCOrig.y; 00930 00931 ptlDitherOrg.x = ptlDitherOrg.y = 0; 00932 IntLPtoDP(pdc, (LPPOINT)&ptlDitherOrg, 1); 00933 00934 ptlDitherOrg.x += pdc->ptlDCOrig.x; 00935 ptlDitherOrg.y += pdc->ptlDCOrig.y; 00936 00937 EXLATEOBJ_vInitialize(&exlo, &gpalRGB, psurf->ppal, 0, 0, 0); 00938 00939 ASSERT(pdc->rosdc.CombinedClip); 00940 00941 DC_vPrepareDCsForBlit(pdc, rclExtent, NULL, rclExtent); 00942 00943 bRet = IntEngGradientFill(&psurf->SurfObj, 00944 pdc->rosdc.CombinedClip, 00945 &exlo.xlo, 00946 pVertex, 00947 nVertex, 00948 pMesh, 00949 nMesh, 00950 &rclExtent, 00951 &ptlDitherOrg, 00952 ulMode); 00953 00954 EXLATEOBJ_vCleanup(&exlo); 00955 DC_vFinishBlit(pdc, NULL); 00956 DC_UnlockDc(pdc); 00957 00958 return bRet; 00959 } 00960 00961 BOOL 00962 APIENTRY 00963 NtGdiGradientFill( 00964 HDC hdc, 00965 PTRIVERTEX pVertex, 00966 ULONG nVertex, 00967 PVOID pMesh, 00968 ULONG nMesh, 00969 ULONG ulMode) 00970 { 00971 BOOL bRet; 00972 PTRIVERTEX SafeVertex; 00973 PVOID SafeMesh; 00974 ULONG cbVertex, cbMesh; 00975 00976 /* Validate parameters */ 00977 if (!pVertex || !nVertex || !pMesh || !nMesh) 00978 { 00979 EngSetLastError(ERROR_INVALID_PARAMETER); 00980 return FALSE; 00981 } 00982 00983 switch (ulMode) 00984 { 00985 case GRADIENT_FILL_RECT_H: 00986 case GRADIENT_FILL_RECT_V: 00987 cbMesh = nMesh * sizeof(GRADIENT_RECT); 00988 break; 00989 case GRADIENT_FILL_TRIANGLE: 00990 cbMesh = nMesh * sizeof(GRADIENT_TRIANGLE); 00991 break; 00992 default: 00993 EngSetLastError(ERROR_INVALID_PARAMETER); 00994 return FALSE; 00995 } 00996 00997 cbVertex = nVertex * sizeof(TRIVERTEX) ; 00998 if(cbVertex + cbMesh <= cbVertex) 00999 { 01000 /* Overflow */ 01001 return FALSE ; 01002 } 01003 01004 /* Allocate a kernel mode buffer */ 01005 SafeVertex = ExAllocatePoolWithTag(PagedPool, cbVertex + cbMesh, TAG_SHAPE); 01006 if(!SafeVertex) 01007 { 01008 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 01009 return FALSE; 01010 } 01011 01012 SafeMesh = (PVOID)((ULONG_PTR)SafeVertex + cbVertex); 01013 01014 /* Copy the parameters to kernel mode */ 01015 _SEH2_TRY 01016 { 01017 ProbeForRead(pVertex, cbVertex, 1); 01018 ProbeForRead(pMesh, cbMesh, 1); 01019 RtlCopyMemory(SafeVertex, pVertex, cbVertex); 01020 RtlCopyMemory(SafeMesh, pMesh, cbMesh); 01021 } 01022 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 01023 { 01024 ExFreePoolWithTag(SafeVertex, TAG_SHAPE); 01025 SetLastNtError(_SEH2_GetExceptionCode()); 01026 _SEH2_YIELD(return FALSE;) 01027 } 01028 _SEH2_END; 01029 01030 /* Call the internal function */ 01031 bRet = GreGradientFill(hdc, SafeVertex, nVertex, SafeMesh, nMesh, ulMode); 01032 01033 /* Cleanup and return result */ 01034 ExFreePoolWithTag(SafeVertex, TAG_SHAPE); 01035 return bRet; 01036 } 01037 01038 BOOL APIENTRY 01039 NtGdiExtFloodFill( 01040 HDC hDC, 01041 INT XStart, 01042 INT YStart, 01043 COLORREF Color, 01044 UINT FillType) 01045 { 01046 PDC dc; 01047 PDC_ATTR pdcattr; 01048 SURFACE *psurf = NULL; 01049 EXLATEOBJ exlo; 01050 BOOL Ret = FALSE; 01051 RECTL DestRect; 01052 POINTL Pt; 01053 ULONG ConvColor; 01054 01055 dc = DC_LockDc(hDC); 01056 if (!dc) 01057 { 01058 EngSetLastError(ERROR_INVALID_HANDLE); 01059 return FALSE; 01060 } 01061 if (dc->dctype == DC_TYPE_INFO) 01062 { 01063 DC_UnlockDc(dc); 01064 /* Yes, Windows really returns TRUE in this case */ 01065 return TRUE; 01066 } 01067 01068 pdcattr = dc->pdcattr; 01069 01070 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY)) 01071 DC_vUpdateFillBrush(dc); 01072 01073 if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY)) 01074 DC_vUpdateLineBrush(dc); 01075 01076 Pt.x = XStart; 01077 Pt.y = YStart; 01078 IntLPtoDP(dc, (LPPOINT)&Pt, 1); 01079 01080 Ret = NtGdiPtInRegion(dc->rosdc.hGCClipRgn, Pt.x, Pt.y); 01081 if (Ret) 01082 IntGdiGetRgnBox(dc->rosdc.hGCClipRgn,(LPRECT)&DestRect); 01083 else 01084 goto cleanup; 01085 01086 psurf = dc->dclevel.pSurface; 01087 if (!psurf) 01088 { 01089 Ret = FALSE; 01090 goto cleanup; 01091 } 01092 01093 EXLATEOBJ_vInitialize(&exlo, &gpalRGB, psurf->ppal, 0, 0xffffff, 0); 01094 01095 /* Only solid fills supported for now 01096 * How to support pattern brushes and non standard surfaces (not offering dib functions): 01097 * Version a (most likely slow): call DrvPatBlt for every pixel 01098 * Version b: create a flood mask and let MaskBlt blit a masked brush */ 01099 ConvColor = XLATEOBJ_iXlate(&exlo.xlo, Color); 01100 Ret = DIB_XXBPP_FloodFillSolid(&psurf->SurfObj, &dc->eboFill.BrushObject, &DestRect, &Pt, ConvColor, FillType); 01101 01102 EXLATEOBJ_vCleanup(&exlo); 01103 01104 cleanup: 01105 DC_UnlockDc(dc); 01106 return Ret; 01107 } 01108 01109 /* EOF */ Generated on Sun May 27 2012 04:38:25 for ReactOS by
1.7.6.1
|