/* ** This method fills the portion of the polygon that intersects with the scanline ** Scanline. */ static void POLYGONFILL_FillScanLineAlternate( PDC dc, int ScanLine, FILL_EDGE* ActiveHead, SURFOBJ *SurfObj, PBRUSHOBJ BrushObj, MIX RopMode ) { FILL_EDGE *pLeft, *pRight; if ( !ActiveHead ) return; pLeft = ActiveHead; pRight = pLeft->pNext; ASSERT(pRight); while ( NULL != pRight ) { int x1 = pLeft->XIntercept[0]; int x2 = pRight->XIntercept[1]; if ( x2 > x1 ) { RECTL BoundRect; BoundRect.top = ScanLine; BoundRect.bottom = ScanLine + 1; BoundRect.left = x1; BoundRect.right = x2; DPRINT("Fill Line (%d, %d) to (%d, %d)\n",x1, ScanLine, x2, ScanLine); IntEngLineTo( SurfObj, dc->CombinedClip, BrushObj, x1, ScanLine, x2, ScanLine, &BoundRect, // Bounding rectangle RopMode); // MIX } pLeft = pRight->pNext; pRight = pLeft ? pLeft->pNext : NULL; } }
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; }
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; }
// this is highly hacked from W32kPolygon... BOOL Polygon ( CONST PPOINT UnsafePoints, int Count, int polyFillMode ) { BOOL ret; RECTL DestRect; int CurrentPoint; PPOINT Points; SURFOBJ* SurfObj = 0; DC dc; PBRUSHOBJ OutBrushObj = 0; dc.CombinedClip = 0; dc.w.polyFillMode = polyFillMode; DPRINT1("In W32kPolygon()\n"); if ( NULL == UnsafePoints || Count < 2) { DPRINT1("ERROR_INVALID_PARAMETER\n"); return FALSE; } /* Copy points from userspace to kernelspace */ Points = (PPOINT)EngAllocMem(0, Count * sizeof(POINT)); if (NULL == Points) { DPRINT1("ERROR_NOT_ENOUGH_MEMORY\n"); return FALSE; } MmCopyFromCaller(Points, UnsafePoints, Count * sizeof(POINT)); if ( memcmp ( Points, UnsafePoints, Count * sizeof(POINT) ) ) { free(Points); return FALSE; } 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); } // Draw the Polygon Edges with the current pen for (CurrentPoint = 0; CurrentPoint < Count; ++CurrentPoint) { POINT To, From; //, Next; /* Let CurrentPoint be i * if i+1 > Count, Draw a line from Points[i] to Points[0] * Draw a line from Points[i] to Points[i+1] */ From = Points[CurrentPoint]; if ( CurrentPoint + 1 >= Count) { To = Points[0]; } else { To = Points[CurrentPoint + 1]; } DPRINT1("Polygon Making line from (%ld,%ld) to (%ld,%ld)\n", From.x, From.y, To.x, To.y ); IntEngLineTo(SurfObj, dc.CombinedClip, OutBrushObj, From.x, From.y, To.x, To.y, &DestRect, EDGE_CHAR); /* MIX */ } /* determine the fill mode to fill the polygon. */ ret = FillPolygon(&dc, SurfObj, OutBrushObj, FILL_CHAR, Points, Count, DestRect ); free(Points); return ret; }
static void POLYGONFILL_FillScanLineWinding( PDC dc, int ScanLine, FILL_EDGE* ActiveHead, SURFOBJ *SurfObj, PBRUSHOBJ BrushObj, MIX RopMode ) { FILL_EDGE *pLeft, *pRight; int x1, x2, winding = 0; RECTL BoundRect; if ( !ActiveHead ) return; BoundRect.top = ScanLine; BoundRect.bottom = ScanLine + 1; pLeft = ActiveHead; winding = pLeft->YDirection; pRight = pLeft->pNext; ASSERT(pRight); // setup first line... x1 = pLeft->XIntercept[0]; x2 = pRight->XIntercept[1]; pLeft = pRight; pRight = pLeft->pNext; winding += pLeft->YDirection; while ( NULL != pRight ) { int newx1 = pLeft->XIntercept[0]; int newx2 = pRight->XIntercept[1]; if ( winding ) { // check and see if this new line touches the previous... if ( (newx1 >= x1 && newx1 <= x2) || (newx2 >= x1 && newx2 <= x2) || (x1 >= newx1 && x1 <= newx2) || (x2 >= newx2 && x2 <= newx2) ) { // yup, just tack it on to our existing line x1 = MIN(x1,newx1); x2 = MAX(x2,newx2); } else { // nope - render the old line.. BoundRect.left = x1; BoundRect.right = x2; DPRINT("Fill Line (%d, %d) to (%d, %d)\n",x1, ScanLine, x2, ScanLine); IntEngLineTo( SurfObj, dc->CombinedClip, BrushObj, x1, ScanLine, x2, ScanLine, &BoundRect, // Bounding rectangle RopMode); // MIX x1 = newx1; x2 = newx2; } } pLeft = pRight; pRight = pLeft->pNext; winding += pLeft->YDirection; } // there will always be a line left-over, render it now... BoundRect.left = x1; BoundRect.right = x2; DPRINT("Fill Line (%d, %d) to (%d, %d)\n",x1, ScanLine, x2, ScanLine); IntEngLineTo( SurfObj, dc->CombinedClip, BrushObj, x1, ScanLine, x2, ScanLine, &BoundRect, // Bounding rectangle RopMode); // MIX }