-\r
-#include <w32k.h>\r
-\r
-#define NDEBUG\r
-#include <debug.h>\r
-\r
-typedef struct tagSHAPEPOINT
-{
- int X;
- int Y;
- int Type;
-} SHAPEPOINT, *PSHAPEPOINT;
-
-#define SHAPEPOINT_TYPE_CIRCLE 'C'
-#define SHAPEPOINT_TYPE_LINE_RIGHT 'R' /* Fill at right side of line */
-#define SHAPEPOINT_TYPE_LINE_LEFT 'L' /* Fill at left side of line */
-
-#define SETPOINT(x, y, type) \
- ShapePoints[*PointCount].X = (x); \
- ShapePoints[*PointCount].Y = (y); \
- ShapePoints[*PointCount].Type = (type); \
- (*PointCount)++
-
-#define SETCIRCLEPOINT(x, y) \
- SETPOINT(x, y, SHAPEPOINT_TYPE_CIRCLE)
-\r
-#ifdef TODO
-STATIC VOID
-FASTCALL
-CirclePoints(UINT *PointCount, PSHAPEPOINT ShapePoints, int Left, int Top,
- int Right, int Bottom)
-{
- int X, X18, X27, X36, X45;
- int Y, Y14, Y23, Y58, Y67;
- int d, Radius;
- BOOL Even;
-
- Even = (0 == (Right - Left) % 2);
- Right--;
- Bottom--;
- Radius = (Right - Left) >> 1;
-
- if (Even)
- {
- X = 0;
- Y = Radius;
- d = 2 - Radius;
- X18 = Right;
- X27 = ((Left + Right) >> 1) + 1;
- X36 = (Left + Right) >> 1;
- X45 = Left;
- Y14 = Top + Radius;
- Y23 = Top;
- Y58 = Top + Radius + 1;
- Y67 = Top + (Right - Left);
- ShapePoints[*PointCount].X = X27;
- SETCIRCLEPOINT(X27, Y23);
- SETCIRCLEPOINT(X36, Y23);
- SETCIRCLEPOINT(X18, Y14);
- SETCIRCLEPOINT(X45, Y14);
- SETCIRCLEPOINT(X18, Y58);
- SETCIRCLEPOINT(X45, Y58);
- SETCIRCLEPOINT(X27, Y67);
- SETCIRCLEPOINT(X36, Y67);
- }
- else
- {
- X = 0;
- Y = Radius;
- d = 1 - Radius;
- X18 = Right;
- X27 = (Left + Right) >> 1;
- X36 = (Left + Right) >> 1;
- X45 = Left;
- Y14 = Top + Radius;
- Y23 = Top;
- Y58 = Top + Radius;
- Y67 = Top + (Right - Left);
- SETCIRCLEPOINT(X27, Y23);
- SETCIRCLEPOINT(X45, Y14);
- SETCIRCLEPOINT(X18, Y58);
- SETCIRCLEPOINT(X27, Y67);
- }
-
- while (X < Y)
- {
- if (d < 0)
- {
- d += (X << 1) + (Even ? 4 : 3);
-
- X27++;
- X36--;
- Y14--;
- Y58++;
- }
- else
- {
- d += ((X - Y) << 1) + 5;
- Y--;
-
- Y23++;
- Y67--;
- X18--;
- X45++;
- X27++;
- X36--;
- Y14--;
- Y58++;
- }
- X++;
-
- SETCIRCLEPOINT(X27, Y23);
- SETCIRCLEPOINT(X36, Y23);
- SETCIRCLEPOINT(X18, Y14);
- SETCIRCLEPOINT(X45, Y14);
- SETCIRCLEPOINT(X18, Y58);
- SETCIRCLEPOINT(X45, Y58);
- SETCIRCLEPOINT(X27, Y67);
- SETCIRCLEPOINT(X36, Y67);
- }
-}
-
-STATIC VOID
-LinePoints(UINT *PointCount, PSHAPEPOINT ShapePoints, int Left, int Top,
- int Right, int Bottom, int XTo, int YTo, BOOL Start)
-{
- LONG x, y, deltax, deltay, i, xchange, ychange, error;
- int Type;
-
- x = (Right + Left) >> 1;
- y = (Bottom + Top) >> 1;
- deltax = XTo - x;
- deltay = YTo - y;
-
- if (deltax < 0)
- {
- xchange = -1;
- deltax = - deltax;
- x--;
- }
- else
- {
- xchange = 1;
- }
-
- if (deltay < 0)
- {
- ychange = -1;
- deltay = - deltay;
- y--;
- Type = (Start ? SHAPEPOINT_TYPE_LINE_LEFT : SHAPEPOINT_TYPE_LINE_RIGHT);
- }
- else
- {
- ychange = 1;
- Type = (Start ? SHAPEPOINT_TYPE_LINE_RIGHT : SHAPEPOINT_TYPE_LINE_LEFT);
- }
- if (y == YTo)
- {
- for (i = x; i <= XTo; i++)
- {
- SETPOINT(i, y, Type);
- }
- }
- else if (x == XTo)
- {
- for (i = y; i <= YTo; i++)
- {
- SETPOINT(x, i, Type);
- }
- }
- else
- {
- error = 0;
-
- if (deltax < deltay)
- {
- for (i = 0; i < deltay; i++)
- {
- SETPOINT(x, y, Type);
- y = y + ychange;
- error = error + deltax;
-
- if (deltay <= error)
- {
- x = x + xchange;
- error = error - deltay;
- }
- }
- }
- else
- {
- for (i = 0; i < deltax; i++)
- {
- SETPOINT(x, y, Type);
- x = x + xchange;
- error = error + deltay;
- if (deltax <= error)
- {
- y = y + ychange;
- error = error - deltax;
- }
- }
- }
- }
-}
-
-STATIC int
-CDECL
-CompareShapePoints(const void *pv1, const void *pv2)
-{
- if (((const PSHAPEPOINT) pv1)->Y < ((const PSHAPEPOINT) pv2)->Y)
- {
- return -1;
- }
- else if (((const PSHAPEPOINT) pv2)->Y < ((const PSHAPEPOINT) pv1)->Y)
- {
- return +1;
- }
- else if (((const PSHAPEPOINT) pv1)->X < ((const PSHAPEPOINT) pv2)->X)
- {
- return -1;
- }
- else if (((const PSHAPEPOINT) pv2)->X < ((const PSHAPEPOINT) pv1)->X)
- {
- return +1;
- }
- else
- {
- return 0;
- }
-}
-#endif
-
-\r
+#include <w32k.h>
+
+#define NDEBUG
+#include <debug.h>
+
+/*
+ * a couple macros to fill a single pixel or a line
+ */
+#define PUTPIXEL(x,y,BrushInst) \
+ ret = ret && IntEngLineTo(&BitmapObj->SurfObj, \
+ dc->CombinedClip, \
+ &BrushInst.BrushObject, \
+ x, y, (x)+1, y, \
+ &RectBounds, \
+ ROP2_TO_MIX(Dc_Attr->jROP2));
+
+#define PUTLINE(x1,y1,x2,y2,BrushInst) \
+ ret = ret && IntEngLineTo(&BitmapObj->SurfObj, \
+ dc->CombinedClip, \
+ &BrushInst.BrushObject, \
+ x1, y1, x2, y2, \
+ &RectBounds, \
+ ROP2_TO_MIX(Dc_Attr->jROP2));
+
+#define Rsin(d) ((d) == 0.0 ? 0.0 : ((d) == 90.0 ? 1.0 : sin(d*M_PI/180.0)))
+#define Rcos(d) ((d) == 0.0 ? 1.0 : ((d) == 90.0 ? 0.0 : cos(d*M_PI/180.0)))
+
+static
BOOL
-STDCALL
-NtGdiPie(HDC hDC,
- int Left,
- int Top,
- int Right,
- int Bottom,
- int XRadialStart,
- int YRadialStart,
- int XRadialEnd,
- int YRadialEnd)
+FASTCALL
+IntArc( DC *dc,
+ int Left,
+ int Top,
+ int Right,
+ int Bottom,
+ int XRadialStart,
+ int YRadialStart,
+ int XRadialEnd,
+ int YRadialEnd,
+ ARCTYPE arctype)
{
-#ifdef TODO
- PDC dc;
- PDC_ATTR;
+ PDC_ATTR Dc_Attr;
RECTL RectBounds;
- SURFOBJ *SurfObj;
- BRUSHOBJ PenBrushObj;
- PBRUSHOBJ FillBrushObj;
- PSHAPEPOINT ShapePoints;
- UINT Point, PointCount;
+ PGDIBRUSHOBJ PenBrushObj, FillBrushObj;
+ GDIBRUSHINST FillBrushInst, PenBrushInst;
+ BITMAPOBJ *BitmapObj;
BOOL ret = TRUE;
- int Y, CircleStart, CircleEnd, LineStart, LineEnd;
- BOOL FullFill;
-
- if (Right <= Left || Bottom <= Top)
+ double AngleStart, AngleEnd;
+ LONG RadiusX, RadiusY, CenterX, CenterY;
+ LONG SfCx, SfCy, EfCx, EfCy;
+
+/* top
+ ___________________
+ +| |
+ | |
+ | |
+ left | | right
+ | |
+ | |
+ 0|___________________|
+ 0 bottom +
+ */
+ if (Right <= Left || Top <= Bottom)
{
+ DPRINT1("Arc Fail 1\n");
SetLastWin32Error(ERROR_INVALID_PARAMETER);
return FALSE;
}
-
+/*
if (Right - Left != Bottom - Top)
{
UNIMPLEMENTED;
}
+*/
+ Dc_Attr = dc->pDc_Attr;
+ if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
- dc = DC_LockDc ( hDC );
- if (NULL == dc)
+ FillBrushObj = BRUSHOBJ_LockBrush(Dc_Attr->hbrush);
+ if (NULL == FillBrushObj)
{
- SetLastWin32Error(ERROR_INVALID_HANDLE);
+ DPRINT1("Arc Fail 2\n");
+ SetLastWin32Error(ERROR_INTERNAL_ERROR);
return FALSE;
}
- if (dc->DC_Type == DC_TYPE_INFO)
+
+ PenBrushObj = PENOBJ_LockPen(Dc_Attr->hpen);
+ if (NULL == PenBrushObj)
{
- DC_UnlockDc(dc);
- /* Yes, Windows really returns TRUE in this case */
- return TRUE;
+ DPRINT1("Arc Fail 3\n");
+ BRUSHOBJ_UnlockBrush(FillBrushObj);
+ SetLastWin32Error(ERROR_INTERNAL_ERROR);
+ return FALSE;
}
- Dc_Attr = dc->pDc_Attr;
- if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
-
- FillBrushObj = BRUSHOBJ_LockBrush(Dc_Attr->hbrush);
- if (NULL == FillBrushObj)
+ BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
+ if (NULL == BitmapObj)
{
- DC_UnlockDc(dc);
+ DPRINT1("Arc Fail 4\n");
+ BRUSHOBJ_UnlockBrush(FillBrushObj);
+ PENOBJ_UnlockPen(PenBrushObj);
SetLastWin32Error(ERROR_INTERNAL_ERROR);
return FALSE;
}
- Left += dc->ptlDCOrig.x;
- Right += dc->ptlDCOrig.x;
- Top += dc->ptlDCOrig.y;
+ IntGdiInitBrushInstance(&FillBrushInst, FillBrushObj, dc->XlateBrush);
+ IntGdiInitBrushInstance(&PenBrushInst, PenBrushObj, dc->XlatePen);
+
+ Left += dc->ptlDCOrig.x;
+ Right += dc->ptlDCOrig.x;
+ Top += dc->ptlDCOrig.y;
Bottom += dc->ptlDCOrig.y;
+
XRadialStart += dc->ptlDCOrig.x;
YRadialStart += dc->ptlDCOrig.y;
- XRadialEnd += dc->ptlDCOrig.x;
- YRadialEnd += dc->ptlDCOrig.y;
+ XRadialEnd += dc->ptlDCOrig.x;
+ YRadialEnd += dc->ptlDCOrig.y;
- RectBounds.left = Left;
- RectBounds.right = Right;
- RectBounds.top = Top;
- RectBounds.bottom = Bottom;
+ DPRINT1("1: StartX: %d, StartY: %d, EndX: %d, EndY: %d\n",
+ XRadialStart,YRadialStart,XRadialEnd,YRadialEnd);
- SurfObj = (SURFOBJ*) AccessUserObject((ULONG)dc->Surface);
- HPenToBrushObj(&PenBrushObj, Dc_Attr->hpen);
-
- /* Number of points for the circle is 4 * sqrt(2) * Radius, start
- and end line have at most Radius points, so allocate at least
- that much */
- ShapePoints = ExAllocatePoolWithTag(PagedPool, 8 * (Right - Left + 1) / 2 * sizeof(SHAPEPOINT), TAG_SHAPE);
- if (NULL == ShapePoints)
- {
- BRUSHOBJ_UnlockBrush(FillBrushObj);
- DC_UnlockDc(dc);
-
- SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
- return FALSE;
- }
+ RectBounds.left = Left;
+ RectBounds.right = Right;
+ RectBounds.top = Top;
+ RectBounds.bottom = Bottom;
+ DPRINT1("1: Left: %d, Top: %d, Right: %d, Bottom: %d\n",
+ RectBounds.left,RectBounds.top,RectBounds.right,RectBounds.bottom);
if (Left == Right)
{
- PUTPIXEL(Left, Top, &PenBrushObj);
+ DPRINT1("Arc Good Exit\n");
+ PUTPIXEL(Left, Top, PenBrushInst);
+ BITMAPOBJ_UnlockBitmap(BitmapObj);
BRUSHOBJ_UnlockBrush(FillBrushObj);
- DC_UnlockDc(dc);
-
+ PENOBJ_UnlockPen(PenBrushObj);
return ret;
}
+ RadiusX = (RectBounds.right - RectBounds.left)/2;
+ RadiusY = (RectBounds.bottom - RectBounds.top)/2;
+ CenterX = RectBounds.left + RadiusX;
+ CenterY = RectBounds.top + RadiusY;
+
+ AngleEnd = atan2(-(YRadialEnd - CenterY), XRadialEnd - CenterX)* (180.0 / M_PI);
+ AngleStart = atan2(-(YRadialStart - CenterY), XRadialStart - CenterX)* (180.0 / M_PI);
- PointCount = 0;
- CirclePoints(&PointCount, ShapePoints, Left, Top, Right, Bottom);
- LinePoints(&PointCount, ShapePoints, Left, Top, Right, Bottom,
- XRadialStart, YRadialStart, TRUE);
- LinePoints(&PointCount, ShapePoints, Left, Top, Right, Bottom,
- XRadialEnd, YRadialEnd, FALSE);
- ASSERT(PointCount <= 8 * (Right - Left + 1) / 2);
- EngSort((PBYTE) ShapePoints, sizeof(SHAPEPOINT), PointCount, CompareShapePoints);
-
- FullFill = TRUE;
- Point = 0;
- while (Point < PointCount)
+ SfCx = (Rcos(AngleStart) * RadiusX);
+ SfCy = (Rsin(AngleStart) * RadiusY);
+
+ EfCx = (Rcos(AngleEnd) * RadiusX);
+ EfCy = (Rsin(AngleEnd) * RadiusY);
{
- Y = ShapePoints[Point].Y;
-
- /* Skip any line pixels before circle */
- while (Point < PointCount && ShapePoints[Point].Y == Y
- && SHAPEPOINT_TYPE_CIRCLE != ShapePoints[Point].Type)
- {
- Point++;
- }
-
- /* Handle left side of circle */
- if (Point < PointCount && ShapePoints[Point].Y == Y)
- {
- CircleStart = ShapePoints[Point].X;
- Point++;
- while (Point < PointCount && ShapePoints[Point].Y == Y
- && ShapePoints[Point].X == ShapePoints[Point - 1].X + 1
- && SHAPEPOINT_TYPE_CIRCLE == ShapePoints[Point].Type)
- {
- Point++;
- }
- CircleEnd = ShapePoints[Point - 1].X;
-
- PUTLINE(CircleStart, Y, CircleEnd + 1, Y, &PenBrushObj);
- }
-
- /* Handle line(s) (max 2) inside the circle */
- while (Point < PointCount && ShapePoints[Point].Y == Y
- && SHAPEPOINT_TYPE_CIRCLE != ShapePoints[Point].Type)
- {
- LineStart = ShapePoints[Point].X;
- Point++;
- while (Point < PointCount && ShapePoints[Point].Y == Y
- && ShapePoints[Point].X == ShapePoints[Point - 1].X + 1
- && ShapePoints[Point].Type == ShapePoints[Point - 1].Type)
- {
- Point++;
- }
- LineEnd = ShapePoints[Point - 1].X;
-
- PUTLINE(LineStart, Y, LineEnd + 1, Y, &PenBrushObj);
- }
-
- /* Handle right side of circle */
- while (Point < PointCount && ShapePoints[Point].Y == Y
- && SHAPEPOINT_TYPE_CIRCLE == ShapePoints[Point].Type)
- {
- CircleStart = ShapePoints[Point].X;
- Point++;
- while (Point < PointCount && ShapePoints[Point].Y == Y
- && ShapePoints[Point].X == ShapePoints[Point - 1].X + 1
- && SHAPEPOINT_TYPE_CIRCLE == ShapePoints[Point].Type)
- {
- Point++;
- }
- CircleEnd = ShapePoints[Point - 1].X;
-
- PUTLINE(CircleStart, Y, CircleEnd + 1, Y, &PenBrushObj);
- }
-
- /* Skip any line pixels after circle */
- while (Point < PointCount && ShapePoints[Point].Y == Y)
- {
- Point++;
- }
- }
+ FLOAT AngS = AngleStart, Factor = 1;
+ int x,y, ox = 0, oy = 0;
+
+ if (arctype == GdiTypePie)
+ {
+ PUTLINE(SfCx + CenterX, SfCy + CenterY, CenterX, CenterY, PenBrushInst);
+ }
+
+ for(; AngS < AngleEnd; AngS += Factor)
+ {
+ x = (Rcos(AngS) * RadiusX);
+ y = (Rsin(AngS) * RadiusY);
+
+ if (arctype == GdiTypePie)
+ PUTLINE((x + CenterX) - 1, (y + CenterY) - 1, CenterX, CenterY, FillBrushInst);
+
+ PUTPIXEL (x + CenterX, y + CenterY, PenBrushInst);
+ ox = x;
+ oy = y;
+ }
+
+ if (arctype == GdiTypePie)
+ PUTLINE(EfCx + CenterX, EfCy + CenterY, CenterX, CenterY, PenBrushInst);
- ExFreePool(ShapePoints);
+ }
+ BITMAPOBJ_UnlockBitmap(BitmapObj);
BRUSHOBJ_UnlockBrush(FillBrushObj);
- DC_UnlockDc(dc);
-
+ PENOBJ_UnlockPen(PenBrushObj);
+ DPRINT1("IntArc Exit.\n");
return ret;
-#else
- return TRUE;
-#endif
}
-\r
-\r
-static BOOL FASTCALL\r
-IntArc( DC *dc, int LeftRect, int TopRect, int RightRect, int BottomRect,\r
- int XStartArc, int YStartArc, int XEndArc, int YEndArc, ARCTYPE arctype)\r
-{\r
- return TRUE;\r
-}\r
-\r
-BOOL FASTCALL\r
-IntGdiArcInternal(\r
- ARCTYPE arctype,\r
- DC *dc,\r
- int LeftRect,\r
- int TopRect,\r
- int RightRect,\r
- int BottomRect,\r
- int XStartArc,\r
- int YStartArc,\r
- int XEndArc,\r
- int YEndArc)\r
-{\r
- INT rx, ry;\r
- RECT rc, rc1;\r
-\r
- if(PATH_IsPathOpen(dc->w.path))\r
- {\r
- INT type = arctype;\r
- if (arctype == GdiTypeArcTo) type = GdiTypeArc;\r
- return PATH_Arc(dc, LeftRect, TopRect, RightRect, BottomRect,\r
- XStartArc, YStartArc, XEndArc, YEndArc, type);\r
- }\r
-\r
- IntGdiSetRect(&rc, LeftRect, TopRect, RightRect, BottomRect);\r
- IntGdiSetRect(&rc1, XStartArc, YStartArc, XEndArc, YEndArc);\r
-\r
- rx = (rc.right - rc.left)/2 - 1;\r
- ry = (rc.bottom - rc.top)/2 -1;\r
- rc.left += rx;\r
- rc.top += ry;\r
-\r
- return IntArc( dc, rc.left, rc.top, rx, ry,\r
- rc1.left, rc1.top, rc1.right, rc1.bottom, arctype);\r
-}\r
-\r
+
+
+BOOL FASTCALL
+IntGdiArcInternal(
+ ARCTYPE arctype,
+ DC *dc,
+ int LeftRect,
+ int TopRect,
+ int RightRect,
+ int BottomRect,
+ int XStartArc,
+ int YStartArc,
+ int XEndArc,
+ int YEndArc)
+{
+ BOOL Ret;
+ RECT rc, rc1;
+ double AngleStart, AngleEnd;
+ LONG RadiusX, RadiusY, CenterX, CenterY, Width, Height;
+ LONG SfCx, SfCy, EfCx = 0, EfCy = 0;
+
+ DPRINT1("StartX: %d, StartY: %d, EndX: %d, EndY: %d\n",
+ XStartArc,YStartArc,XEndArc,YEndArc);
+ DPRINT1("Left: %d, Top: %d, Right: %d, Bottom: %d\n",
+ LeftRect,TopRect,RightRect,BottomRect);
+
+ if (PATH_IsPathOpen(dc->DcLevel))
+ {
+ return PATH_Arc( dc,
+ LeftRect,
+ TopRect,
+ RightRect,
+ BottomRect,
+ XStartArc,
+ YStartArc,
+ XEndArc,
+ YEndArc,
+ arctype);
+ }
+
+ if (arctype == GdiTypeArcTo)
+ {
+ Width = fabs(RightRect - LeftRect);
+ Height = fabs(BottomRect - TopRect);
+ RadiusX = Width/2;
+ RadiusY = Height/2;
+ CenterX = RightRect > LeftRect ? LeftRect + RadiusX : RightRect + RadiusX;
+ CenterY = BottomRect > TopRect ? TopRect + RadiusY : BottomRect + RadiusY;
+
+ AngleStart = atan2((YStartArc - CenterY)/Height, (XStartArc - CenterX)/Width);
+ AngleEnd = atan2((YEndArc - CenterY)/Height, (XEndArc - CenterX)/Width);
+
+ EfCx = GDI_ROUND(CenterX+cos(AngleEnd) * RadiusX);
+ EfCy = GDI_ROUND(CenterY+sin(AngleEnd) * RadiusY);
+ SfCx = GDI_ROUND(CenterX+cos(AngleStart) * RadiusX);
+ SfCy = GDI_ROUND(CenterY+sin(AngleStart) * RadiusY);
+
+ IntGdiLineTo(dc, SfCx, SfCy);
+ }
+
+ IntGdiSetRect(&rc, LeftRect, TopRect, RightRect, BottomRect);
+ IntGdiSetRect(&rc1, XStartArc, YStartArc, XEndArc, YEndArc);
+
+// IntLPtoDP(dc, (LPPOINT)&rc, 2);
+// IntLPtoDP(dc, (LPPOINT)&rc1, 2);
+
+ Ret = IntArc( dc,
+ rc.left,
+ rc.top,
+ rc.right,
+ rc.bottom,
+ rc1.left,
+ rc1.top,
+ rc1.right,
+ rc1.bottom,
+ arctype);
+
+ if (arctype == GdiTypeArcTo)
+ {
+ dc->ptlDCOrig.x = EfCx;
+ dc->ptlDCOrig.y = EfCy;
+ }
+
+ return Ret;
+}
+
+BOOL
+FASTCALL
+IntGdiAngleArc( PDC pDC,
+ INT x,
+ INT y,
+ DWORD dwRadius,
+ FLOAT eStartAngle,
+ FLOAT eSweepAngle)
+{
+ INT x1, y1, x2, y2, arcdir;
+ BOOL result;
+
+ /* Calculate the end point */
+ x2 = x + (INT)(cos(((eStartAngle+eSweepAngle)/360)*(M_PI*2)) * dwRadius);
+ y2 = y - (INT)(sin(((eStartAngle+eSweepAngle)/360)*(M_PI*2)) * dwRadius);
+
+ x1 = x + (INT)(cos((eStartAngle/360)*(M_PI*2)) * dwRadius);
+ y1 = y - (INT)(sin((eStartAngle/360)*(M_PI*2)) * dwRadius);
+
+ arcdir = pDC->DcLevel.flPath & DCPATH_CLOCKWISE;
+ if (eSweepAngle >= 0)
+ pDC->DcLevel.flPath &= ~DCPATH_CLOCKWISE;
+ else
+ pDC->DcLevel.flPath |= DCPATH_CLOCKWISE;
+
+ result = IntGdiArcInternal( GdiTypeArcTo,
+ pDC,
+ x-dwRadius,
+ y+dwRadius,
+ x+dwRadius,
+ y-dwRadius,
+ x1,
+ y1,
+ x2,
+ y2 );
+
+ pDC->DcLevel.flPath |= (arcdir & DCPATH_CLOCKWISE);
+
+ if (result)
+ {
+ POINT point;
+ point.x=x2;
+ point.y=y2;
+// CoordLPtoDP ( pDC, &point );
+ pDC->ptlDCOrig.x = point.x;
+ pDC->ptlDCOrig.y = point.y;
+ }
+ return result;
+}
+
+/* FUNCTIONS *****************************************************************/
+
BOOL
APIENTRY
NtGdiAngleArc(
IN DWORD dwStartAngle,
IN DWORD dwSweepAngle)
{
- DC *dc;\r
- BOOL Ret = FALSE;\r
- gxf_long worker, worker1;\r
-\r
- dc = DC_LockDc (hDC);\r
- if(!dc)\r
- {\r
- SetLastWin32Error(ERROR_INVALID_HANDLE);\r
- return FALSE;\r
- }\r
- if (dc->DC_Type == DC_TYPE_INFO)\r
- {\r
- DC_UnlockDc(dc);\r
- /* Yes, Windows really returns TRUE in this case */\r
- return TRUE;\r
- }\r
- worker.l = dwStartAngle;\r
- worker1.l = dwSweepAngle;\r
-\r
- DC_UnlockDc( dc );\r
- return Ret;\r
+ DC *pDC;
+ BOOL Ret = FALSE;
+ gxf_long worker, worker1;
+
+ pDC = DC_LockDc (hDC);
+ if(!pDC)
+ {
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+ if (pDC->DC_Type == DC_TYPE_INFO)
+ {
+ DC_UnlockDc(pDC);
+ /* Yes, Windows really returns TRUE in this case */
+ return TRUE;
+ }
+ worker.l = dwStartAngle;
+ worker1.l = dwSweepAngle;
+ Ret = IntGdiAngleArc( pDC, x, y, dwRadius, worker.f, worker1.f);
+ DC_UnlockDc( pDC );
+ return Ret;
}
-\r
-BOOL\r
-STDCALL\r
-NtGdiArcInternal(\r
- ARCTYPE arctype,\r
- HDC hDC,\r
- int LeftRect,\r
- int TopRect,\r
- int RightRect,\r
- int BottomRect,\r
- int XStartArc,\r
- int YStartArc,\r
- int XEndArc,\r
- int YEndArc)\r
-{\r
- DC *dc;\r
- BOOL Ret;\r
-\r
- dc = DC_LockDc (hDC);\r
- if(!dc)\r
- {\r
- SetLastWin32Error(ERROR_INVALID_HANDLE);\r
- return FALSE;\r
- }\r
- if (dc->DC_Type == DC_TYPE_INFO)\r
- {\r
- DC_UnlockDc(dc);\r
- /* Yes, Windows really returns TRUE in this case */\r
- return TRUE;\r
- }\r
-\r
- if (arctype == GdiTypeArcTo)\r
- {\r
- // Line from current position to starting point of arc\r
- if ( !IntGdiLineTo(dc, XStartArc, YStartArc) )\r
- {\r
- DC_UnlockDc(dc);\r
- return FALSE;\r
- }\r
- }\r
-\r
- Ret = IntGdiArcInternal(\r
- arctype,\r
- dc,\r
- LeftRect,\r
- TopRect,\r
- RightRect,\r
- BottomRect,\r
- XStartArc,\r
- YStartArc,\r
- XEndArc,\r
- YEndArc);\r
-\r
- if (arctype == GdiTypeArcTo)\r
- {\r
- // If no error occured, the current position is moved to the ending point of the arc.\r
- if(Ret)\r
- IntGdiMoveToEx(dc, XEndArc, YEndArc, NULL);\r
- }\r
-\r
- DC_UnlockDc( dc );\r
- return Ret;\r
-}\r
-\r
+
+BOOL
+STDCALL
+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;
+
+ dc = DC_LockDc (hDC);
+ if(!dc)
+ {
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+ if (dc->DC_Type == DC_TYPE_INFO)
+ {
+ DC_UnlockDc(dc);
+ /* Yes, Windows really returns TRUE in this case */
+ return TRUE;
+ }
+
+ Ret = IntGdiArcInternal(
+ arctype,
+ dc,
+ LeftRect,
+ TopRect,
+ RightRect,
+ BottomRect,
+ XStartArc,
+ YStartArc,
+ XEndArc,
+ YEndArc);
+
+ DC_UnlockDc( dc );
+ return Ret;
+}
+
-/*\r
- * ReactOS W32 Subsystem\r
- * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team\r
- *\r
- * This program is free software; you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation; either version 2 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program; if not, write to the Free Software\r
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
- */\r
-/* $Id: bitmaps.c 28300 2007-08-12 15:20:09Z tkreuzer $ */\r
-\r
-#include <w32k.h>\r
-\r
-#define NDEBUG\r
-#include <debug.h>\r
-\r
-\r
-\r
-BOOL STDCALL\r
-NtGdiAlphaBlend(\r
- HDC hDCDest,\r
- LONG XOriginDest,\r
- LONG YOriginDest,\r
- LONG WidthDest,\r
- LONG HeightDest,\r
- HDC hDCSrc,\r
- LONG XOriginSrc,\r
- LONG YOriginSrc,\r
- LONG WidthSrc,\r
- LONG HeightSrc,\r
- BLENDFUNCTION BlendFunc,\r
- HANDLE hcmXform)\r
-{\r
- PDC DCDest = NULL;\r
- PDC DCSrc = NULL;\r
- BITMAPOBJ *BitmapDest, *BitmapSrc;\r
- RECTL DestRect, SourceRect;\r
- BOOL Status;\r
- XLATEOBJ *XlateObj;\r
- BLENDOBJ BlendObj;\r
- BlendObj.BlendFunction = BlendFunc;\r
-\r
- DCDest = DC_LockDc(hDCDest);\r
- if (NULL == DCDest)\r
- {\r
- DPRINT1("Invalid destination dc handle (0x%08x) passed to NtGdiAlphaBlend\n", hDCDest);\r
- SetLastWin32Error(ERROR_INVALID_HANDLE);\r
- return FALSE;\r
- }\r
- if (DCDest->DC_Type == DC_TYPE_INFO)\r
- {\r
- DC_UnlockDc(DCDest);\r
- /* Yes, Windows really returns TRUE in this case */\r
- return TRUE;\r
- }\r
-\r
- if (hDCSrc != hDCDest)\r
- {\r
- DCSrc = DC_LockDc(hDCSrc);\r
- if (NULL == DCSrc)\r
- {\r
- DC_UnlockDc(DCDest);\r
- DPRINT1("Invalid source dc handle (0x%08x) passed to NtGdiAlphaBlend\n", hDCSrc);\r
- SetLastWin32Error(ERROR_INVALID_HANDLE);\r
- return FALSE;\r
- }\r
- if (DCSrc->DC_Type == DC_TYPE_INFO)\r
- {\r
- DC_UnlockDc(DCSrc);\r
- DC_UnlockDc(DCDest);\r
- /* Yes, Windows really returns TRUE in this case */\r
- return TRUE;\r
- }\r
- }\r
- else\r
- {\r
- DCSrc = DCDest;\r
- }\r
-\r
- /* Offset the destination and source by the origin of their DCs. */\r
- XOriginDest += DCDest->ptlDCOrig.x;\r
- YOriginDest += DCDest->ptlDCOrig.y;\r
- XOriginSrc += DCSrc->ptlDCOrig.x;\r
- YOriginSrc += DCSrc->ptlDCOrig.y;\r
-\r
- DestRect.left = XOriginDest;\r
- DestRect.top = YOriginDest;\r
- DestRect.right = XOriginDest + WidthDest;\r
- DestRect.bottom = YOriginDest + HeightDest;\r
-\r
- SourceRect.left = XOriginSrc;\r
- SourceRect.top = YOriginSrc;\r
- SourceRect.right = XOriginSrc + WidthSrc;\r
- SourceRect.bottom = YOriginSrc + HeightSrc;\r
-\r
- /* Determine surfaces to be used in the bitblt */\r
- BitmapDest = BITMAPOBJ_LockBitmap(DCDest->w.hBitmap);\r
- if (!BitmapDest)\r
- {\r
- DC_UnlockDc(DCSrc);\r
- DC_UnlockDc(DCDest);\r
- return FALSE;\r
- }\r
- if (DCSrc->w.hBitmap == DCDest->w.hBitmap)\r
- BitmapSrc = BitmapDest;\r
- else\r
- {\r
- BitmapSrc = BITMAPOBJ_LockBitmap(DCSrc->w.hBitmap);\r
- if (!BitmapDest)\r
- {\r
- BITMAPOBJ_UnlockBitmap(BitmapDest);\r
- DC_UnlockDc(DCSrc);\r
- DC_UnlockDc(DCDest);\r
- return FALSE;\r
- }\r
- }\r
-\r
- /* Create the XLATEOBJ. */\r
- XlateObj = IntCreateXlateForBlt(DCDest, DCSrc, BitmapDest, BitmapSrc);\r
-\r
- if (XlateObj == (XLATEOBJ*)-1)\r
- {\r
- DPRINT1("error!!!\n");\r
- SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);\r
- XlateObj = NULL;\r
- Status = FALSE;\r
- }\r
- else\r
- {\r
- /* Perform the alpha blend operation */\r
- Status = IntEngAlphaBlend(&BitmapDest->SurfObj, &BitmapSrc->SurfObj,\r
- DCDest->CombinedClip, XlateObj,\r
- &DestRect, &SourceRect, &BlendObj);\r
- }\r
-\r
- if (XlateObj != NULL)\r
- EngDeleteXlate(XlateObj);\r
-\r
- BITMAPOBJ_UnlockBitmap(BitmapDest);\r
- if (BitmapSrc != BitmapDest)\r
- BITMAPOBJ_UnlockBitmap(BitmapSrc);\r
- DC_UnlockDc(DCDest);\r
- if (hDCSrc != hDCDest)\r
- DC_UnlockDc(DCSrc);\r
-\r
- return Status;\r
-}\r
-\r
-BOOL STDCALL\r
-NtGdiBitBlt(\r
- HDC hDCDest,\r
- INT XDest,\r
- INT YDest,\r
- INT Width,\r
- INT Height,\r
- HDC hDCSrc,\r
- INT XSrc,\r
- INT YSrc,\r
- DWORD ROP,\r
- IN DWORD crBackColor,\r
- IN FLONG fl)\r
-{\r
- PDC DCDest = NULL;\r
- PDC DCSrc = NULL;\r
- PDC_ATTR Dc_Attr = NULL;\r
- BITMAPOBJ *BitmapDest, *BitmapSrc = NULL;\r
- RECTL DestRect;\r
- POINTL SourcePoint, BrushOrigin;\r
- BOOL Status = FALSE;\r
- XLATEOBJ *XlateObj = NULL;\r
- PGDIBRUSHOBJ BrushObj = NULL;\r
- GDIBRUSHINST BrushInst;\r
- BOOL UsesSource = ROP3_USES_SOURCE(ROP);\r
- BOOL UsesPattern = ROP3_USES_PATTERN(ROP);\r
-\r
- DCDest = DC_LockDc(hDCDest);\r
- if (NULL == DCDest)\r
- {\r
- DPRINT("Invalid destination dc handle (0x%08x) passed to NtGdiBitBlt\n", hDCDest);\r
- return FALSE;\r
- }\r
- if (DCDest->DC_Type == DC_TYPE_INFO)\r
- {\r
- DC_UnlockDc(DCDest);\r
- /* Yes, Windows really returns TRUE in this case */\r
- return TRUE;\r
- }\r
-\r
- if (UsesSource)\r
- {\r
- if (hDCSrc != hDCDest)\r
- {\r
- DCSrc = DC_LockDc(hDCSrc);\r
- if (NULL == DCSrc)\r
- {\r
- DC_UnlockDc(DCDest);\r
- DPRINT("Invalid source dc handle (0x%08x) passed to NtGdiBitBlt\n", hDCSrc);\r
- return FALSE;\r
- }\r
- if (DCSrc->DC_Type == DC_TYPE_INFO)\r
- {\r
- DC_UnlockDc(DCSrc);\r
- DC_UnlockDc(DCDest);\r
- /* Yes, Windows really returns TRUE in this case */\r
- return TRUE;\r
- }\r
- }\r
- else\r
- {\r
- DCSrc = DCDest;\r
- }\r
- }\r
- else\r
- {\r
- DCSrc = NULL;\r
- }\r
-\r
- Dc_Attr = DCDest->pDc_Attr;\r
- if (!Dc_Attr) Dc_Attr = &DCDest->Dc_Attr;\r
-\r
- /* Offset the destination and source by the origin of their DCs. */\r
- XDest += DCDest->ptlDCOrig.x;\r
- YDest += DCDest->ptlDCOrig.y;\r
- if (UsesSource)\r
- {\r
- XSrc += DCSrc->ptlDCOrig.x;\r
- YSrc += DCSrc->ptlDCOrig.y;\r
- }\r
-\r
- DestRect.left = XDest;\r
- DestRect.top = YDest;\r
- DestRect.right = XDest+Width;\r
- DestRect.bottom = YDest+Height;\r
-\r
- IntLPtoDP(DCDest, (LPPOINT)&DestRect, 2);\r
-\r
- SourcePoint.x = XSrc;\r
- SourcePoint.y = YSrc;\r
-\r
- BrushOrigin.x = 0;\r
- BrushOrigin.y = 0;\r
-\r
- /* Determine surfaces to be used in the bitblt */\r
- BitmapDest = BITMAPOBJ_LockBitmap(DCDest->w.hBitmap);\r
- if (!BitmapDest)\r
- goto cleanup;\r
-\r
- if (UsesSource)\r
- {\r
- if (DCSrc->w.hBitmap == DCDest->w.hBitmap)\r
- BitmapSrc = BitmapDest;\r
- else\r
- {\r
- BitmapSrc = BITMAPOBJ_LockBitmap(DCSrc->w.hBitmap);\r
- if (!BitmapSrc)\r
- goto cleanup;\r
- }\r
- }\r
- else\r
- {\r
- BitmapSrc = NULL;\r
- }\r
-\r
- if (UsesPattern)\r
- {\r
- BrushObj = BRUSHOBJ_LockBrush(Dc_Attr->hbrush);\r
- if (NULL == BrushObj)\r
- {\r
- SetLastWin32Error(ERROR_INVALID_HANDLE);\r
- goto cleanup;\r
- }\r
- BrushOrigin = *((PPOINTL)&BrushObj->ptOrigin);\r
- IntGdiInitBrushInstance(&BrushInst, BrushObj, DCDest->XlateBrush);\r
- }\r
- else\r
- {\r
- BrushObj = NULL;\r
- }\r
-\r
- /* Create the XLATEOBJ. */\r
- if (UsesSource)\r
- {\r
- XlateObj = IntCreateXlateForBlt(DCDest, DCSrc, BitmapDest, BitmapSrc);\r
-\r
- if (XlateObj == (XLATEOBJ*)-1)\r
- {\r
- DPRINT1("error!\n");\r
- SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);\r
- XlateObj = NULL;\r
- goto cleanup;\r
- }\r
- }\r
-\r
- /* Perform the bitblt operation */\r
- Status = IntEngBitBlt( BitmapDest ? &BitmapDest->SurfObj : NULL, BitmapSrc ? &BitmapSrc->SurfObj : NULL, NULL,\r
- DCDest->CombinedClip, XlateObj, &DestRect,\r
- &SourcePoint, NULL,\r
- BrushObj ? &BrushInst.BrushObject : NULL,\r
- &BrushOrigin, ROP3_TO_ROP4(ROP));\r
-\r
-cleanup:\r
- if (UsesSource && XlateObj != NULL)\r
- EngDeleteXlate(XlateObj);\r
-\r
- if(BitmapDest != NULL)\r
- {\r
- BITMAPOBJ_UnlockBitmap(BitmapDest);\r
- }\r
- if (UsesSource && BitmapSrc != BitmapDest)\r
- {\r
- BITMAPOBJ_UnlockBitmap(BitmapSrc);\r
- }\r
- if (BrushObj != NULL)\r
- {\r
- BRUSHOBJ_UnlockBrush(BrushObj);\r
- }\r
- if (UsesSource && hDCSrc != hDCDest)\r
- {\r
- DC_UnlockDc(DCSrc);\r
- }\r
- DC_UnlockDc(DCDest);\r
-\r
- return Status;\r
-}\r
-\r
-BOOL STDCALL\r
-NtGdiTransparentBlt(\r
- HDC hdcDst,\r
- INT xDst,\r
- INT yDst,\r
- INT cxDst,\r
- INT cyDst,\r
- HDC hdcSrc,\r
- INT xSrc,\r
- INT ySrc,\r
- INT cxSrc,\r
- INT cySrc,\r
- COLORREF TransColor)\r
-{\r
- PDC DCDest, DCSrc;\r
- RECTL rcDest, rcSrc;\r
- BITMAPOBJ *BitmapDest, *BitmapSrc = NULL;\r
- XLATEOBJ *XlateObj = NULL;\r
- HPALETTE SourcePalette = 0, DestPalette = 0;\r
- PPALGDI PalDestGDI, PalSourceGDI;\r
- USHORT PalDestMode, PalSrcMode;\r
- ULONG TransparentColor = 0;\r
- BOOL Ret = FALSE;\r
-\r
- if(!(DCDest = DC_LockDc(hdcDst)))\r
- {\r
- DPRINT1("Invalid destination dc handle (0x%08x) passed to NtGdiTransparentBlt\n", hdcDst);\r
- SetLastWin32Error(ERROR_INVALID_HANDLE);\r
- return FALSE;\r
- }\r
- if (DCDest->DC_Type == DC_TYPE_INFO)\r
- {\r
- DC_UnlockDc(DCDest);\r
- /* Yes, Windows really returns TRUE in this case */\r
- return TRUE;\r
- }\r
-\r
- if((hdcDst != hdcSrc) && !(DCSrc = DC_LockDc(hdcSrc)))\r
- {\r
- DC_UnlockDc(DCDest);\r
- DPRINT1("Invalid source dc handle (0x%08x) passed to NtGdiTransparentBlt\n", hdcSrc);\r
- SetLastWin32Error(ERROR_INVALID_HANDLE);\r
- return FALSE;\r
- }\r
- if(hdcDst == hdcSrc)\r
- {\r
- DCSrc = DCDest;\r
- }\r
- if (DCSrc->DC_Type == DC_TYPE_INFO)\r
- {\r
- DC_UnlockDc(DCSrc);\r
- if(hdcDst != hdcSrc)\r
- {\r
- DC_UnlockDc(DCDest);\r
- }\r
- /* Yes, Windows really returns TRUE in this case */\r
- return TRUE;\r
- }\r
-\r
- /* Offset positions */\r
- xDst += DCDest->ptlDCOrig.x;\r
- yDst += DCDest->ptlDCOrig.y;\r
- xSrc += DCSrc->ptlDCOrig.x;\r
- ySrc += DCSrc->ptlDCOrig.y;\r
-\r
- BitmapDest = BITMAPOBJ_LockBitmap(DCDest->w.hBitmap);\r
- if (!BitmapDest)\r
- {\r
- goto done;\r
- }\r
-\r
- BitmapSrc = BITMAPOBJ_LockBitmap(DCSrc->w.hBitmap);\r
- if (!BitmapSrc)\r
- {\r
- goto done;\r
- }\r
-\r
- DestPalette = BitmapDest->hDIBPalette;\r
- if (!DestPalette) DestPalette = pPrimarySurface->DevInfo.hpalDefault;\r
-\r
- SourcePalette = BitmapSrc->hDIBPalette;\r
- if (!SourcePalette) SourcePalette = pPrimarySurface->DevInfo.hpalDefault;\r
-\r
- if(!(PalSourceGDI = PALETTE_LockPalette(SourcePalette)))\r
- {\r
- SetLastWin32Error(ERROR_INVALID_HANDLE);\r
- goto done;\r
- }\r
- PalSrcMode = PalSourceGDI->Mode;\r
- PALETTE_UnlockPalette(PalSourceGDI);\r
-\r
- if(DestPalette != SourcePalette)\r
- {\r
- if (!(PalDestGDI = PALETTE_LockPalette(DestPalette)))\r
- {\r
- SetLastWin32Error(ERROR_INVALID_HANDLE);\r
- goto done;\r
- }\r
- PalDestMode = PalDestGDI->Mode;\r
- PALETTE_UnlockPalette(PalDestGDI);\r
- }\r
- else\r
- {\r
- PalDestMode = PalSrcMode;\r
- }\r
-\r
- /* Translate Transparent (RGB) Color to the source palette */\r
- if((XlateObj = (XLATEOBJ*)IntEngCreateXlate(PalSrcMode, PAL_RGB, SourcePalette, NULL)))\r
- {\r
- TransparentColor = XLATEOBJ_iXlate(XlateObj, (ULONG)TransColor);\r
- EngDeleteXlate(XlateObj);\r
- }\r
-\r
- /* Create the XLATE object to convert colors between source and destination */\r
- XlateObj = (XLATEOBJ*)IntEngCreateXlate(PalDestMode, PalSrcMode, DestPalette, SourcePalette);\r
-\r
- rcDest.left = xDst;\r
- rcDest.top = yDst;\r
- rcDest.right = rcDest.left + cxDst;\r
- rcDest.bottom = rcDest.top + cyDst;\r
- rcSrc.left = xSrc;\r
- rcSrc.top = ySrc;\r
- rcSrc.right = rcSrc.left + cxSrc;\r
- rcSrc.bottom = rcSrc.top + cySrc;\r
-\r
- if((cxDst != cxSrc) || (cyDst != cySrc))\r
- {\r
- DPRINT1("TransparentBlt() does not support stretching at the moment!\n");\r
- goto done;\r
- }\r
-\r
- Ret = IntEngTransparentBlt(&BitmapDest->SurfObj, &BitmapSrc->SurfObj,\r
- DCDest->CombinedClip, XlateObj, &rcDest, &rcSrc,\r
- TransparentColor, 0);\r
-\r
-done:\r
- DC_UnlockDc(DCSrc);\r
- if (BitmapDest)\r
- {\r
- BITMAPOBJ_UnlockBitmap(BitmapDest);\r
- }\r
- if (BitmapSrc)\r
- {\r
- BITMAPOBJ_UnlockBitmap(BitmapSrc);\r
- }\r
- if(hdcDst != hdcSrc)\r
- {\r
- DC_UnlockDc(DCDest);\r
- }\r
- if(XlateObj)\r
- {\r
- EngDeleteXlate(XlateObj);\r
- }\r
- return Ret;\r
-}\r
-\r
-/***********************************************************************\r
- * MaskBlt\r
- * Ported from WINE by sedwards 11-4-03\r
- *\r
- * Someone thought it would be faster to do it here and then switch back\r
- * to GDI32. I dunno. Write a test and let me know.\r
- */\r
-\r
-static __inline BYTE\r
-SwapROP3_SrcDst(BYTE bRop3)\r
-{\r
- return (bRop3 & 0x99) | ((bRop3 & 0x22) << 1) | ((bRop3 & 0x44) >> 1);\r
-}\r
-\r
-#define FRGND_ROP3(ROP4) ((ROP4) & 0x00FFFFFF)\r
-#define BKGND_ROP3(ROP4) (ROP3Table[(SwapROP3_SrcDst((ROP4)>>24)) & 0xFF])\r
-#define DSTCOPY 0x00AA0029\r
-#define DSTERASE 0x00220326 /* dest = dest & (~src) : DSna */\r
-\r
-BOOL STDCALL\r
-NtGdiMaskBlt (\r
- HDC hdcDest, INT nXDest, INT nYDest,\r
- INT nWidth, INT nHeight, HDC hdcSrc,\r
- INT nXSrc, INT nYSrc, HBITMAP hbmMask,\r
- INT xMask, INT yMask, DWORD dwRop,\r
- IN DWORD crBackColor)\r
-{\r
- HBITMAP hOldMaskBitmap, hBitmap2, hOldBitmap2, hBitmap3, hOldBitmap3;\r
- HDC hDCMask, hDC1, hDC2;\r
- static const DWORD ROP3Table[256] =\r
- {\r
- 0x00000042, 0x00010289,\r
- 0x00020C89, 0x000300AA,\r
- 0x00040C88, 0x000500A9,\r
- 0x00060865, 0x000702C5,\r
- 0x00080F08, 0x00090245,\r
- 0x000A0329, 0x000B0B2A,\r
- 0x000C0324, 0x000D0B25,\r
- 0x000E08A5, 0x000F0001,\r
- 0x00100C85, 0x001100A6,\r
- 0x00120868, 0x001302C8,\r
- 0x00140869, 0x001502C9,\r
- 0x00165CCA, 0x00171D54,\r
- 0x00180D59, 0x00191CC8,\r
- 0x001A06C5, 0x001B0768,\r
- 0x001C06CA, 0x001D0766,\r
- 0x001E01A5, 0x001F0385,\r
- 0x00200F09, 0x00210248,\r
- 0x00220326, 0x00230B24,\r
- 0x00240D55, 0x00251CC5,\r
- 0x002606C8, 0x00271868,\r
- 0x00280369, 0x002916CA,\r
- 0x002A0CC9, 0x002B1D58,\r
- 0x002C0784, 0x002D060A,\r
- 0x002E064A, 0x002F0E2A,\r
- 0x0030032A, 0x00310B28,\r
- 0x00320688, 0x00330008,\r
- 0x003406C4, 0x00351864,\r
- 0x003601A8, 0x00370388,\r
- 0x0038078A, 0x00390604,\r
- 0x003A0644, 0x003B0E24,\r
- 0x003C004A, 0x003D18A4,\r
- 0x003E1B24, 0x003F00EA,\r
- 0x00400F0A, 0x00410249,\r
- 0x00420D5D, 0x00431CC4,\r
- 0x00440328, 0x00450B29,\r
- 0x004606C6, 0x0047076A,\r
- 0x00480368, 0x004916C5,\r
- 0x004A0789, 0x004B0605,\r
- 0x004C0CC8, 0x004D1954,\r
- 0x004E0645, 0x004F0E25,\r
- 0x00500325, 0x00510B26,\r
- 0x005206C9, 0x00530764,\r
- 0x005408A9, 0x00550009,\r
- 0x005601A9, 0x00570389,\r
- 0x00580785, 0x00590609,\r
- 0x005A0049, 0x005B18A9,\r
- 0x005C0649, 0x005D0E29,\r
- 0x005E1B29, 0x005F00E9,\r
- 0x00600365, 0x006116C6,\r
- 0x00620786, 0x00630608,\r
- 0x00640788, 0x00650606,\r
- 0x00660046, 0x006718A8,\r
- 0x006858A6, 0x00690145,\r
- 0x006A01E9, 0x006B178A,\r
- 0x006C01E8, 0x006D1785,\r
- 0x006E1E28, 0x006F0C65,\r
- 0x00700CC5, 0x00711D5C,\r
- 0x00720648, 0x00730E28,\r
- 0x00740646, 0x00750E26,\r
- 0x00761B28, 0x007700E6,\r
- 0x007801E5, 0x00791786,\r
- 0x007A1E29, 0x007B0C68,\r
- 0x007C1E24, 0x007D0C69,\r
- 0x007E0955, 0x007F03C9,\r
- 0x008003E9, 0x00810975,\r
- 0x00820C49, 0x00831E04,\r
- 0x00840C48, 0x00851E05,\r
- 0x008617A6, 0x008701C5,\r
- 0x008800C6, 0x00891B08,\r
- 0x008A0E06, 0x008B0666,\r
- 0x008C0E08, 0x008D0668,\r
- 0x008E1D7C, 0x008F0CE5,\r
- 0x00900C45, 0x00911E08,\r
- 0x009217A9, 0x009301C4,\r
- 0x009417AA, 0x009501C9,\r
- 0x00960169, 0x0097588A,\r
- 0x00981888, 0x00990066,\r
- 0x009A0709, 0x009B07A8,\r
- 0x009C0704, 0x009D07A6,\r
- 0x009E16E6, 0x009F0345,\r
- 0x00A000C9, 0x00A11B05,\r
- 0x00A20E09, 0x00A30669,\r
- 0x00A41885, 0x00A50065,\r
- 0x00A60706, 0x00A707A5,\r
- 0x00A803A9, 0x00A90189,\r
- 0x00AA0029, 0x00AB0889,\r
- 0x00AC0744, 0x00AD06E9,\r
- 0x00AE0B06, 0x00AF0229,\r
- 0x00B00E05, 0x00B10665,\r
- 0x00B21974, 0x00B30CE8,\r
- 0x00B4070A, 0x00B507A9,\r
- 0x00B616E9, 0x00B70348,\r
- 0x00B8074A, 0x00B906E6,\r
- 0x00BA0B09, 0x00BB0226,\r
- 0x00BC1CE4, 0x00BD0D7D,\r
- 0x00BE0269, 0x00BF08C9,\r
- 0x00C000CA, 0x00C11B04,\r
- 0x00C21884, 0x00C3006A,\r
- 0x00C40E04, 0x00C50664,\r
- 0x00C60708, 0x00C707AA,\r
- 0x00C803A8, 0x00C90184,\r
- 0x00CA0749, 0x00CB06E4,\r
- 0x00CC0020, 0x00CD0888,\r
- 0x00CE0B08, 0x00CF0224,\r
- 0x00D00E0A, 0x00D1066A,\r
- 0x00D20705, 0x00D307A4,\r
- 0x00D41D78, 0x00D50CE9,\r
- 0x00D616EA, 0x00D70349,\r
- 0x00D80745, 0x00D906E8,\r
- 0x00DA1CE9, 0x00DB0D75,\r
- 0x00DC0B04, 0x00DD0228,\r
- 0x00DE0268, 0x00DF08C8,\r
- 0x00E003A5, 0x00E10185,\r
- 0x00E20746, 0x00E306EA,\r
- 0x00E40748, 0x00E506E5,\r
- 0x00E61CE8, 0x00E70D79,\r
- 0x00E81D74, 0x00E95CE6,\r
- 0x00EA02E9, 0x00EB0849,\r
- 0x00EC02E8, 0x00ED0848,\r
- 0x00EE0086, 0x00EF0A08,\r
- 0x00F00021, 0x00F10885,\r
- 0x00F20B05, 0x00F3022A,\r
- 0x00F40B0A, 0x00F50225,\r
- 0x00F60265, 0x00F708C5,\r
- 0x00F802E5, 0x00F90845,\r
- 0x00FA0089, 0x00FB0A09,\r
- 0x00FC008A, 0x00FD0A0A,\r
- 0x00FE02A9, 0x00FF0062,\r
- };\r
-\r
- if (!hbmMask)\r
- return NtGdiBitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop), 0, 0);\r
-\r
- /* 1. make mask bitmap's dc */\r
- hDCMask = NtGdiCreateCompatibleDC(hdcDest);\r
- hOldMaskBitmap = (HBITMAP)NtGdiSelectBitmap(hDCMask, hbmMask);\r
-\r
- /* 2. make masked Background bitmap */\r
-\r
- /* 2.1 make bitmap */\r
- hDC1 = NtGdiCreateCompatibleDC(hdcDest);\r
- hBitmap2 = NtGdiCreateCompatibleBitmap(hdcDest, nWidth, nHeight);\r
- hOldBitmap2 = (HBITMAP)NtGdiSelectBitmap(hDC1, hBitmap2);\r
-\r
- /* 2.2 draw dest bitmap and mask */\r
- NtGdiBitBlt(hDC1, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, SRCCOPY, 0, 0);\r
- NtGdiBitBlt(hDC1, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, BKGND_ROP3(dwRop), 0, 0);\r
- NtGdiBitBlt(hDC1, 0, 0, nWidth, nHeight, hDCMask, xMask, yMask, DSTERASE, 0, 0);\r
-\r
- /* 3. make masked Foreground bitmap */\r
-\r
- /* 3.1 make bitmap */\r
- hDC2 = NtGdiCreateCompatibleDC(hdcDest);\r
- hBitmap3 = NtGdiCreateCompatibleBitmap(hdcDest, nWidth, nHeight);\r
- hOldBitmap3 = (HBITMAP)NtGdiSelectBitmap(hDC2, hBitmap3);\r
-\r
- /* 3.2 draw src bitmap and mask */\r
- NtGdiBitBlt(hDC2, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY, 0, 0);\r
- NtGdiBitBlt(hDC2, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop), 0,0);\r
- NtGdiBitBlt(hDC2, 0, 0, nWidth, nHeight, hDCMask, xMask, yMask, SRCAND, 0, 0);\r
-\r
- /* 4. combine two bitmap and copy it to hdcDest */\r
- NtGdiBitBlt(hDC1, 0, 0, nWidth, nHeight, hDC2, 0, 0, SRCPAINT, 0, 0);\r
- NtGdiBitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hDC1, 0, 0, SRCCOPY, 0, 0);\r
-\r
- /* 5. restore all object */\r
- NtGdiSelectBitmap(hDCMask, hOldMaskBitmap);\r
- NtGdiSelectBitmap(hDC1, hOldBitmap2);\r
- NtGdiSelectBitmap(hDC2, hOldBitmap3);\r
-\r
- /* 6. delete all temp object */\r
- NtGdiDeleteObject(hBitmap2);\r
- NtGdiDeleteObject(hBitmap3);\r
-\r
- NtGdiDeleteObjectApp(hDC1);\r
- NtGdiDeleteObjectApp(hDC2);\r
- NtGdiDeleteObjectApp(hDCMask);\r
-\r
- return TRUE;\r
-}\r
-\r
-BOOL\r
-APIENTRY\r
-NtGdiPlgBlt(\r
- IN HDC hdcTrg,\r
- IN LPPOINT pptlTrg,\r
- IN HDC hdcSrc,\r
- IN INT xSrc,\r
- IN INT ySrc,\r
- IN INT cxSrc,\r
- IN INT cySrc,\r
- IN HBITMAP hbmMask,\r
- IN INT xMask,\r
- IN INT yMask,\r
- IN DWORD crBackColor)\r
-{\r
- UNIMPLEMENTED;\r
- return FALSE;\r
-}\r
-\r
-BOOL STDCALL\r
-NtGdiStretchBlt(\r
- HDC hDCDest,\r
- INT XOriginDest,\r
- INT YOriginDest,\r
- INT WidthDest,\r
- INT HeightDest,\r
- HDC hDCSrc,\r
- INT XOriginSrc,\r
- INT YOriginSrc,\r
- INT WidthSrc,\r
- INT HeightSrc,\r
- DWORD ROP,\r
- IN DWORD dwBackColor)\r
-{\r
- PDC DCDest = NULL;\r
- PDC DCSrc = NULL;\r
- PDC_ATTR Dc_Attr;\r
- BITMAPOBJ *BitmapDest, *BitmapSrc;\r
- RECTL DestRect;\r
- RECTL SourceRect;\r
- BOOL Status;\r
- XLATEOBJ *XlateObj = NULL;\r
- PGDIBRUSHOBJ BrushObj = NULL;\r
- BOOL UsesSource = ((ROP & 0xCC0000) >> 2) != (ROP & 0x330000);\r
- BOOL UsesPattern = ((ROP & 0xF00000) >> 4) != (ROP & 0x0F0000);\r
-\r
- if (0 == WidthDest || 0 == HeightDest || 0 == WidthSrc || 0 == HeightSrc)\r
- {\r
- SetLastWin32Error(ERROR_INVALID_PARAMETER);\r
- return FALSE;\r
- }\r
- DCDest = DC_LockDc(hDCDest);\r
- if (NULL == DCDest)\r
- {\r
- DPRINT1("Invalid destination dc handle (0x%08x) passed to NtGdiStretchBlt\n", hDCDest);\r
- SetLastWin32Error(ERROR_INVALID_HANDLE);\r
- return FALSE;\r
- }\r
- if (DCDest->DC_Type == DC_TYPE_INFO)\r
- {\r
- DC_UnlockDc(DCDest);\r
- /* Yes, Windows really returns TRUE in this case */\r
- return TRUE;\r
- }\r
-\r
- if (UsesSource)\r
- {\r
- if (hDCSrc != hDCDest)\r
- {\r
- DCSrc = DC_LockDc(hDCSrc);\r
- if (NULL == DCSrc)\r
- {\r
- DC_UnlockDc(DCDest);\r
- DPRINT1("Invalid source dc handle (0x%08x) passed to NtGdiStretchBlt\n", hDCSrc);\r
- SetLastWin32Error(ERROR_INVALID_HANDLE);\r
- return FALSE;\r
- }\r
- if (DCSrc->DC_Type == DC_TYPE_INFO)\r
- {\r
- DC_UnlockDc(DCSrc);\r
- DC_UnlockDc(DCDest);\r
- /* Yes, Windows really returns TRUE in this case */\r
- return TRUE;\r
- }\r
- }\r
- else\r
- {\r
- DCSrc = DCDest;\r
- }\r
- }\r
- else\r
- {\r
- DCSrc = NULL;\r
- }\r
-\r
- /* Offset the destination and source by the origin of their DCs. */\r
- // FIXME: ptlDCOrig is in device coordinates!\r
- XOriginDest += DCDest->ptlDCOrig.x;\r
- YOriginDest += DCDest->ptlDCOrig.y;\r
- if (UsesSource)\r
- {\r
- XOriginSrc += DCSrc->ptlDCOrig.x;\r
- YOriginSrc += DCSrc->ptlDCOrig.y;\r
- }\r
-\r
- DestRect.left = XOriginDest;\r
- DestRect.top = YOriginDest;\r
- DestRect.right = XOriginDest+WidthDest;\r
- DestRect.bottom = YOriginDest+HeightDest;\r
-\r
- SourceRect.left = XOriginSrc;\r
- SourceRect.top = YOriginSrc;\r
- SourceRect.right = XOriginSrc+WidthSrc;\r
- SourceRect.bottom = YOriginSrc+HeightSrc;\r
-\r
- /* Determine surfaces to be used in the bitblt */\r
- BitmapDest = BITMAPOBJ_LockBitmap(DCDest->w.hBitmap);\r
- if (UsesSource)\r
- {\r
- if (DCSrc->w.hBitmap == DCDest->w.hBitmap)\r
- BitmapSrc = BitmapDest;\r
- else\r
- BitmapSrc = BITMAPOBJ_LockBitmap(DCSrc->w.hBitmap);\r
-\r
- int sw = BitmapSrc->SurfObj.sizlBitmap.cx;\r
- int sh = BitmapSrc->SurfObj.sizlBitmap.cy;\r
- if ( SourceRect.left < 0 )\r
- {\r
- DestRect.left = DestRect.right - (DestRect.right-DestRect.left) * (SourceRect.right)/abs(SourceRect.right-SourceRect.left);\r
- SourceRect.left = 0;\r
- }\r
- if ( SourceRect.top < 0 )\r
- {\r
- DestRect.top = DestRect.bottom - (DestRect.bottom-DestRect.top) * (SourceRect.bottom)/abs(SourceRect.bottom-SourceRect.top);\r
- SourceRect.top = 0;\r
- }\r
- if ( SourceRect.right < -1 )\r
- {\r
- DestRect.right = DestRect.left + (DestRect.right-DestRect.left) * (-1-SourceRect.left)/abs(SourceRect.right-SourceRect.left);\r
- SourceRect.right = -1;\r
- }\r
- if ( SourceRect.bottom < -1 )\r
- {\r
- DestRect.bottom = DestRect.top + (DestRect.bottom-DestRect.top) * (-1-SourceRect.top)/abs(SourceRect.bottom-SourceRect.top);\r
- SourceRect.bottom = -1;\r
- }\r
- if ( SourceRect.right > sw )\r
- {\r
- DestRect.right = DestRect.left + (DestRect.right-DestRect.left) * abs(sw-SourceRect.left) / abs(SourceRect.right-SourceRect.left);\r
- SourceRect.right = sw;\r
- }\r
- if ( SourceRect.bottom > sh )\r
- {\r
- DestRect.bottom = DestRect.top + (DestRect.bottom-DestRect.top) * abs(sh-SourceRect.top) / abs(SourceRect.bottom-SourceRect.top);\r
- SourceRect.bottom = sh;\r
- }\r
- sw--;\r
- sh--;\r
- if ( SourceRect.left > sw )\r
- {\r
- DestRect.left = DestRect.right - (DestRect.right-DestRect.left) * (SourceRect.right-sw) / abs(SourceRect.right-SourceRect.left);\r
- SourceRect.left = 0;\r
- }\r
- if ( SourceRect.top > sh )\r
- {\r
- DestRect.top = DestRect.bottom - (DestRect.bottom-DestRect.top) * (SourceRect.bottom-sh) / abs(SourceRect.bottom-SourceRect.top);\r
- SourceRect.top = 0;\r
- }\r
- if (0 == (DestRect.right-DestRect.left) || 0 == (DestRect.bottom-DestRect.top) || 0 == (SourceRect.right-SourceRect.left) || 0 == (SourceRect.bottom-SourceRect.top))\r
- {\r
- SetLastWin32Error(ERROR_INVALID_PARAMETER);\r
- Status = FALSE;\r
- goto failed;\r
- }\r
-\r
- /* Create the XLATEOBJ. */\r
- XlateObj = IntCreateXlateForBlt(DCDest, DCSrc, BitmapDest, BitmapSrc);\r
- if (XlateObj == (XLATEOBJ*)-1)\r
- {\r
- SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);\r
- Status = FALSE;\r
- goto failed;\r
- }\r
- }\r
- else\r
- {\r
- BitmapSrc = NULL;\r
- }\r
-\r
- if (UsesPattern)\r
- {\r
- Dc_Attr = DCDest->pDc_Attr;\r
- if (!Dc_Attr) Dc_Attr = &DCDest->Dc_Attr;\r
- BrushObj = BRUSHOBJ_LockBrush(Dc_Attr->hbrush);\r
- if (NULL == BrushObj)\r
- {\r
- SetLastWin32Error(ERROR_INVALID_HANDLE);\r
- Status = FALSE;\r
- goto failed;\r
- }\r
- }\r
- else\r
- {\r
- BrushObj = NULL;\r
- }\r
-\r
- /* Perform the bitblt operation */\r
- Status = IntEngStretchBlt(&BitmapDest->SurfObj, &BitmapSrc->SurfObj,\r
- NULL, DCDest->CombinedClip, XlateObj,\r
- &DestRect, &SourceRect, NULL, NULL, NULL,\r
- COLORONCOLOR);\r
-\r
-failed:\r
- if (XlateObj)\r
- {\r
- EngDeleteXlate(XlateObj);\r
- }\r
- if (BrushObj)\r
- {\r
- BRUSHOBJ_UnlockBrush(BrushObj);\r
- }\r
- if (UsesSource && DCSrc->w.hBitmap != DCDest->w.hBitmap)\r
- {\r
- BITMAPOBJ_UnlockBitmap(BitmapSrc);\r
- }\r
- BITMAPOBJ_UnlockBitmap(BitmapDest);\r
- if (UsesSource && hDCSrc != hDCDest)\r
- {\r
- DC_UnlockDc(DCSrc);\r
- }\r
- DC_UnlockDc(DCDest);\r
-\r
- return Status;\r
-}\r
-\r
-BOOL FASTCALL\r
-IntPatBlt(\r
- PDC dc,\r
- INT XLeft,\r
- INT YLeft,\r
- INT Width,\r
- INT Height,\r
- DWORD ROP,\r
- PGDIBRUSHOBJ BrushObj)\r
-{\r
- RECTL DestRect;\r
- BITMAPOBJ *BitmapObj;\r
- GDIBRUSHINST BrushInst;\r
- POINTL BrushOrigin;\r
- BOOL ret = TRUE;\r
-\r
- ASSERT(BrushObj);\r
-\r
- BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);\r
- if (BitmapObj == NULL)\r
- {\r
- SetLastWin32Error(ERROR_INVALID_HANDLE);\r
- return FALSE;\r
- }\r
-\r
- if (!(BrushObj->flAttrs & GDIBRUSH_IS_NULL))\r
- {\r
- if (Width > 0)\r
- {\r
- DestRect.left = XLeft + dc->ptlDCOrig.x;\r
- DestRect.right = XLeft + Width + dc->ptlDCOrig.x;\r
- }\r
- else\r
- {\r
- DestRect.left = XLeft + Width + 1 + dc->ptlDCOrig.x;\r
- DestRect.right = XLeft + dc->ptlDCOrig.x + 1;\r
- }\r
-\r
- if (Height > 0)\r
- {\r
- DestRect.top = YLeft + dc->ptlDCOrig.y;\r
- DestRect.bottom = YLeft + Height + dc->ptlDCOrig.y;\r
- }\r
- else\r
- {\r
- DestRect.top = YLeft + Height + dc->ptlDCOrig.y + 1;\r
- DestRect.bottom = YLeft + dc->ptlDCOrig.y + 1;\r
- }\r
-\r
- IntLPtoDP(dc, (LPPOINT)&DestRect, 2);\r
-\r
- BrushOrigin.x = BrushObj->ptOrigin.x + dc->ptlDCOrig.x;\r
- BrushOrigin.y = BrushObj->ptOrigin.y + dc->ptlDCOrig.y;\r
-\r
- IntGdiInitBrushInstance(&BrushInst, BrushObj, dc->XlateBrush);\r
-\r
- ret = IntEngBitBlt(\r
- &BitmapObj->SurfObj,\r
- NULL,\r
- NULL,\r
- dc->CombinedClip,\r
- NULL,\r
- &DestRect,\r
- NULL,\r
- NULL,\r
- &BrushInst.BrushObject, // use pDC->eboFill\r
- &BrushOrigin,\r
- ROP3_TO_ROP4(ROP));\r
- }\r
-\r
- BITMAPOBJ_UnlockBitmap(BitmapObj);\r
-\r
- return ret;\r
-}\r
-\r
-BOOL FASTCALL\r
-IntGdiPolyPatBlt(\r
- HDC hDC,\r
- DWORD dwRop,\r
- PPATRECT pRects,\r
- int cRects,\r
- ULONG Reserved)\r
-{\r
- int i;\r
- PPATRECT r;\r
- PGDIBRUSHOBJ BrushObj;\r
- DC *dc;\r
-\r
- dc = DC_LockDc(hDC);\r
- if (dc == NULL)\r
- {\r
- SetLastWin32Error(ERROR_INVALID_HANDLE);\r
- return FALSE;\r
- }\r
- if (dc->DC_Type == DC_TYPE_INFO)\r
- {\r
- DC_UnlockDc(dc);\r
- /* Yes, Windows really returns TRUE in this case */\r
- return TRUE;\r
- }\r
-\r
- for (r = pRects, i = 0; i < cRects; i++)\r
- {\r
- BrushObj = BRUSHOBJ_LockBrush(r->hBrush);\r
- if(BrushObj != NULL)\r
- {\r
- IntPatBlt(\r
- dc,\r
- r->r.left,\r
- r->r.top,\r
- r->r.right,\r
- r->r.bottom,\r
- dwRop,\r
- BrushObj);\r
- BRUSHOBJ_UnlockBrush(BrushObj);\r
- }\r
- r++;\r
- }\r
-\r
- DC_UnlockDc(dc);\r
-\r
- return TRUE;\r
-}\r
-\r
-\r
-BOOL STDCALL\r
-NtGdiPatBlt(\r
- HDC hDC,\r
- INT XLeft,\r
- INT YLeft,\r
- INT Width,\r
- INT Height,\r
- DWORD ROP)\r
-{\r
- PGDIBRUSHOBJ BrushObj;\r
- DC *dc;\r
- PDC_ATTR Dc_Attr;\r
- BOOL ret;\r
-\r
- BOOL UsesSource = ROP3_USES_SOURCE(ROP);\r
- if (UsesSource)\r
- {\r
- /* in this case we call on GdiMaskBlt */\r
- return NtGdiMaskBlt(hDC, XLeft, YLeft, Width, Height, 0,0,0,0,0,0,ROP,0);\r
- }\r
-\r
- dc = DC_LockDc(hDC);\r
- if (dc == NULL)\r
- {\r
- SetLastWin32Error(ERROR_INVALID_HANDLE);\r
- return FALSE;\r
- }\r
- Dc_Attr = dc->pDc_Attr;\r
- if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;\r
- if (dc->DC_Type == DC_TYPE_INFO)\r
- {\r
- DC_UnlockDc(dc);\r
- /* Yes, Windows really returns TRUE in this case */\r
- return TRUE;\r
- }\r
-\r
- BrushObj = BRUSHOBJ_LockBrush(Dc_Attr->hbrush);\r
- if (BrushObj == NULL)\r
- {\r
- SetLastWin32Error(ERROR_INVALID_HANDLE);\r
- DC_UnlockDc(dc);\r
- return FALSE;\r
- }\r
-\r
- ret = IntPatBlt(\r
- dc,\r
- XLeft,\r
- YLeft,\r
- Width,\r
- Height,\r
- ROP,\r
- BrushObj);\r
-\r
- BRUSHOBJ_UnlockBrush(BrushObj);\r
- DC_UnlockDc(dc);\r
-\r
- return ret;\r
-}\r
-\r
-BOOL STDCALL\r
-NtGdiPolyPatBlt(\r
- HDC hDC,\r
- DWORD dwRop,\r
- IN PPOLYPATBLT pRects,\r
- IN DWORD cRects,\r
- IN DWORD Mode)\r
-{\r
- PPATRECT rb = NULL;\r
- NTSTATUS Status = STATUS_SUCCESS;\r
- BOOL Ret;\r
-\r
- if (cRects > 0)\r
- {\r
- rb = ExAllocatePoolWithTag(PagedPool, sizeof(PATRECT) * cRects, TAG_PATBLT);\r
- if (!rb)\r
- {\r
- SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);\r
- return FALSE;\r
- }\r
- _SEH_TRY\r
- {\r
- ProbeForRead(pRects,\r
- cRects * sizeof(PATRECT),\r
- 1);\r
- RtlCopyMemory(rb,\r
- pRects,\r
- cRects * sizeof(PATRECT));\r
- }\r
- _SEH_HANDLE\r
- {\r
- Status = _SEH_GetExceptionCode();\r
- }\r
- _SEH_END;\r
-\r
- if (!NT_SUCCESS(Status))\r
- {\r
- ExFreePool(rb);\r
- SetLastNtError(Status);\r
- return FALSE;\r
- }\r
- }\r
-\r
- Ret = IntGdiPolyPatBlt(hDC, dwRop, (PPATRECT)pRects, cRects, Mode);\r
-\r
- if (cRects > 0)\r
- ExFreePool(rb);\r
-\r
- return Ret;\r
-}\r
+/*
+ * ReactOS W32 Subsystem
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/* $Id: bitmaps.c 28300 2007-08-12 15:20:09Z tkreuzer $ */
+
+#include <w32k.h>
+
+#define NDEBUG
+#include <debug.h>
+
+
+
+BOOL STDCALL
+NtGdiAlphaBlend(
+ HDC hDCDest,
+ LONG XOriginDest,
+ LONG YOriginDest,
+ LONG WidthDest,
+ LONG HeightDest,
+ HDC hDCSrc,
+ LONG XOriginSrc,
+ LONG YOriginSrc,
+ LONG WidthSrc,
+ LONG HeightSrc,
+ BLENDFUNCTION BlendFunc,
+ HANDLE hcmXform)
+{
+ PDC DCDest = NULL;
+ PDC DCSrc = NULL;
+ BITMAPOBJ *BitmapDest, *BitmapSrc;
+ RECTL DestRect, SourceRect;
+ BOOL Status;
+ XLATEOBJ *XlateObj;
+ BLENDOBJ BlendObj;
+ BlendObj.BlendFunction = BlendFunc;
+
+ DCDest = DC_LockDc(hDCDest);
+ if (NULL == DCDest)
+ {
+ DPRINT1("Invalid destination dc handle (0x%08x) passed to NtGdiAlphaBlend\n", hDCDest);
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+ if (DCDest->DC_Type == DC_TYPE_INFO)
+ {
+ DC_UnlockDc(DCDest);
+ /* Yes, Windows really returns TRUE in this case */
+ return TRUE;
+ }
+
+ if (hDCSrc != hDCDest)
+ {
+ DCSrc = DC_LockDc(hDCSrc);
+ if (NULL == DCSrc)
+ {
+ DC_UnlockDc(DCDest);
+ DPRINT1("Invalid source dc handle (0x%08x) passed to NtGdiAlphaBlend\n", hDCSrc);
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+ if (DCSrc->DC_Type == DC_TYPE_INFO)
+ {
+ DC_UnlockDc(DCSrc);
+ DC_UnlockDc(DCDest);
+ /* Yes, Windows really returns TRUE in this case */
+ return TRUE;
+ }
+ }
+ else
+ {
+ DCSrc = DCDest;
+ }
+
+ /* Offset the destination and source by the origin of their DCs. */
+ XOriginDest += DCDest->ptlDCOrig.x;
+ YOriginDest += DCDest->ptlDCOrig.y;
+ XOriginSrc += DCSrc->ptlDCOrig.x;
+ YOriginSrc += DCSrc->ptlDCOrig.y;
+
+ DestRect.left = XOriginDest;
+ DestRect.top = YOriginDest;
+ DestRect.right = XOriginDest + WidthDest;
+ DestRect.bottom = YOriginDest + HeightDest;
+
+ SourceRect.left = XOriginSrc;
+ SourceRect.top = YOriginSrc;
+ SourceRect.right = XOriginSrc + WidthSrc;
+ SourceRect.bottom = YOriginSrc + HeightSrc;
+
+ /* Determine surfaces to be used in the bitblt */
+ BitmapDest = BITMAPOBJ_LockBitmap(DCDest->w.hBitmap);
+ if (!BitmapDest)
+ {
+ DC_UnlockDc(DCSrc);
+ DC_UnlockDc(DCDest);
+ return FALSE;
+ }
+ if (DCSrc->w.hBitmap == DCDest->w.hBitmap)
+ BitmapSrc = BitmapDest;
+ else
+ {
+ BitmapSrc = BITMAPOBJ_LockBitmap(DCSrc->w.hBitmap);
+ if (!BitmapDest)
+ {
+ BITMAPOBJ_UnlockBitmap(BitmapDest);
+ DC_UnlockDc(DCSrc);
+ DC_UnlockDc(DCDest);
+ return FALSE;
+ }
+ }
+
+ /* Create the XLATEOBJ. */
+ XlateObj = IntCreateXlateForBlt(DCDest, DCSrc, BitmapDest, BitmapSrc);
+
+ if (XlateObj == (XLATEOBJ*)-1)
+ {
+ DPRINT1("error!!!\n");
+ SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
+ XlateObj = NULL;
+ Status = FALSE;
+ }
+ else
+ {
+ /* Perform the alpha blend operation */
+ Status = IntEngAlphaBlend(&BitmapDest->SurfObj, &BitmapSrc->SurfObj,
+ DCDest->CombinedClip, XlateObj,
+ &DestRect, &SourceRect, &BlendObj);
+ }
+
+ if (XlateObj != NULL)
+ EngDeleteXlate(XlateObj);
+
+ BITMAPOBJ_UnlockBitmap(BitmapDest);
+ if (BitmapSrc != BitmapDest)
+ BITMAPOBJ_UnlockBitmap(BitmapSrc);
+ DC_UnlockDc(DCDest);
+ if (hDCSrc != hDCDest)
+ DC_UnlockDc(DCSrc);
+
+ return Status;
+}
+
+BOOL STDCALL
+NtGdiBitBlt(
+ HDC hDCDest,
+ INT XDest,
+ INT YDest,
+ INT Width,
+ INT Height,
+ HDC hDCSrc,
+ INT XSrc,
+ INT YSrc,
+ DWORD ROP,
+ IN DWORD crBackColor,
+ IN FLONG fl)
+{
+ PDC DCDest = NULL;
+ PDC DCSrc = NULL;
+ PDC_ATTR Dc_Attr = NULL;
+ BITMAPOBJ *BitmapDest, *BitmapSrc = NULL;
+ RECTL DestRect;
+ POINTL SourcePoint, BrushOrigin;
+ BOOL Status = FALSE;
+ XLATEOBJ *XlateObj = NULL;
+ PGDIBRUSHOBJ BrushObj = NULL;
+ GDIBRUSHINST BrushInst;
+ BOOL UsesSource = ROP3_USES_SOURCE(ROP);
+ BOOL UsesPattern = ROP3_USES_PATTERN(ROP);
+
+ DCDest = DC_LockDc(hDCDest);
+ if (NULL == DCDest)
+ {
+ DPRINT("Invalid destination dc handle (0x%08x) passed to NtGdiBitBlt\n", hDCDest);
+ return FALSE;
+ }
+ if (DCDest->DC_Type == DC_TYPE_INFO)
+ {
+ DC_UnlockDc(DCDest);
+ /* Yes, Windows really returns TRUE in this case */
+ return TRUE;
+ }
+
+ if (UsesSource)
+ {
+ if (hDCSrc != hDCDest)
+ {
+ DCSrc = DC_LockDc(hDCSrc);
+ if (NULL == DCSrc)
+ {
+ DC_UnlockDc(DCDest);
+ DPRINT("Invalid source dc handle (0x%08x) passed to NtGdiBitBlt\n", hDCSrc);
+ return FALSE;
+ }
+ if (DCSrc->DC_Type == DC_TYPE_INFO)
+ {
+ DC_UnlockDc(DCSrc);
+ DC_UnlockDc(DCDest);
+ /* Yes, Windows really returns TRUE in this case */
+ return TRUE;
+ }
+ }
+ else
+ {
+ DCSrc = DCDest;
+ }
+ }
+ else
+ {
+ DCSrc = NULL;
+ }
+
+ Dc_Attr = DCDest->pDc_Attr;
+ if (!Dc_Attr) Dc_Attr = &DCDest->Dc_Attr;
+
+ /* Offset the destination and source by the origin of their DCs. */
+ XDest += DCDest->ptlDCOrig.x;
+ YDest += DCDest->ptlDCOrig.y;
+ if (UsesSource)
+ {
+ XSrc += DCSrc->ptlDCOrig.x;
+ YSrc += DCSrc->ptlDCOrig.y;
+ }
+
+ DestRect.left = XDest;
+ DestRect.top = YDest;
+ DestRect.right = XDest+Width;
+ DestRect.bottom = YDest+Height;
+
+ IntLPtoDP(DCDest, (LPPOINT)&DestRect, 2);
+
+ SourcePoint.x = XSrc;
+ SourcePoint.y = YSrc;
+
+ BrushOrigin.x = 0;
+ BrushOrigin.y = 0;
+
+ /* Determine surfaces to be used in the bitblt */
+ BitmapDest = BITMAPOBJ_LockBitmap(DCDest->w.hBitmap);
+ if (!BitmapDest)
+ goto cleanup;
+
+ if (UsesSource)
+ {
+ if (DCSrc->w.hBitmap == DCDest->w.hBitmap)
+ BitmapSrc = BitmapDest;
+ else
+ {
+ BitmapSrc = BITMAPOBJ_LockBitmap(DCSrc->w.hBitmap);
+ if (!BitmapSrc)
+ goto cleanup;
+ }
+ }
+ else
+ {
+ BitmapSrc = NULL;
+ }
+
+ if (UsesPattern)
+ {
+ BrushObj = BRUSHOBJ_LockBrush(Dc_Attr->hbrush);
+ if (NULL == BrushObj)
+ {
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ goto cleanup;
+ }
+ BrushOrigin = *((PPOINTL)&BrushObj->ptOrigin);
+ IntGdiInitBrushInstance(&BrushInst, BrushObj, DCDest->XlateBrush);
+ }
+ else
+ {
+ BrushObj = NULL;
+ }
+
+ /* Create the XLATEOBJ. */
+ if (UsesSource)
+ {
+ XlateObj = IntCreateXlateForBlt(DCDest, DCSrc, BitmapDest, BitmapSrc);
+
+ if (XlateObj == (XLATEOBJ*)-1)
+ {
+ DPRINT1("error!\n");
+ SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
+ XlateObj = NULL;
+ goto cleanup;
+ }
+ }
+
+ /* Perform the bitblt operation */
+ Status = IntEngBitBlt( BitmapDest ? &BitmapDest->SurfObj : NULL, BitmapSrc ? &BitmapSrc->SurfObj : NULL, NULL,
+ DCDest->CombinedClip, XlateObj, &DestRect,
+ &SourcePoint, NULL,
+ BrushObj ? &BrushInst.BrushObject : NULL,
+ &BrushOrigin, ROP3_TO_ROP4(ROP));
+
+cleanup:
+ if (UsesSource && XlateObj != NULL)
+ EngDeleteXlate(XlateObj);
+
+ if(BitmapDest != NULL)
+ {
+ BITMAPOBJ_UnlockBitmap(BitmapDest);
+ }
+ if (UsesSource && BitmapSrc != BitmapDest)
+ {
+ BITMAPOBJ_UnlockBitmap(BitmapSrc);
+ }
+ if (BrushObj != NULL)
+ {
+ BRUSHOBJ_UnlockBrush(BrushObj);
+ }
+ if (UsesSource && hDCSrc != hDCDest)
+ {
+ DC_UnlockDc(DCSrc);
+ }
+ DC_UnlockDc(DCDest);
+
+ return Status;
+}
+
+BOOL STDCALL
+NtGdiTransparentBlt(
+ HDC hdcDst,
+ INT xDst,
+ INT yDst,
+ INT cxDst,
+ INT cyDst,
+ HDC hdcSrc,
+ INT xSrc,
+ INT ySrc,
+ INT cxSrc,
+ INT cySrc,
+ COLORREF TransColor)
+{
+ PDC DCDest, DCSrc;
+ RECTL rcDest, rcSrc;
+ BITMAPOBJ *BitmapDest, *BitmapSrc = NULL;
+ XLATEOBJ *XlateObj = NULL;
+ HPALETTE SourcePalette = 0, DestPalette = 0;
+ PPALGDI PalDestGDI, PalSourceGDI;
+ USHORT PalDestMode, PalSrcMode;
+ ULONG TransparentColor = 0;
+ BOOL Ret = FALSE;
+
+ if(!(DCDest = DC_LockDc(hdcDst)))
+ {
+ DPRINT1("Invalid destination dc handle (0x%08x) passed to NtGdiTransparentBlt\n", hdcDst);
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+ if (DCDest->DC_Type == DC_TYPE_INFO)
+ {
+ DC_UnlockDc(DCDest);
+ /* Yes, Windows really returns TRUE in this case */
+ return TRUE;
+ }
+
+ if((hdcDst != hdcSrc) && !(DCSrc = DC_LockDc(hdcSrc)))
+ {
+ DC_UnlockDc(DCDest);
+ DPRINT1("Invalid source dc handle (0x%08x) passed to NtGdiTransparentBlt\n", hdcSrc);
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+ if(hdcDst == hdcSrc)
+ {
+ DCSrc = DCDest;
+ }
+ if (DCSrc->DC_Type == DC_TYPE_INFO)
+ {
+ DC_UnlockDc(DCSrc);
+ if(hdcDst != hdcSrc)
+ {
+ DC_UnlockDc(DCDest);
+ }
+ /* Yes, Windows really returns TRUE in this case */
+ return TRUE;
+ }
+
+ /* Offset positions */
+ xDst += DCDest->ptlDCOrig.x;
+ yDst += DCDest->ptlDCOrig.y;
+ xSrc += DCSrc->ptlDCOrig.x;
+ ySrc += DCSrc->ptlDCOrig.y;
+
+ BitmapDest = BITMAPOBJ_LockBitmap(DCDest->w.hBitmap);
+ if (!BitmapDest)
+ {
+ goto done;
+ }
+
+ BitmapSrc = BITMAPOBJ_LockBitmap(DCSrc->w.hBitmap);
+ if (!BitmapSrc)
+ {
+ goto done;
+ }
+
+ DestPalette = BitmapDest->hDIBPalette;
+ if (!DestPalette) DestPalette = pPrimarySurface->DevInfo.hpalDefault;
+
+ SourcePalette = BitmapSrc->hDIBPalette;
+ if (!SourcePalette) SourcePalette = pPrimarySurface->DevInfo.hpalDefault;
+
+ if(!(PalSourceGDI = PALETTE_LockPalette(SourcePalette)))
+ {
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ goto done;
+ }
+ PalSrcMode = PalSourceGDI->Mode;
+ PALETTE_UnlockPalette(PalSourceGDI);
+
+ if(DestPalette != SourcePalette)
+ {
+ if (!(PalDestGDI = PALETTE_LockPalette(DestPalette)))
+ {
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ goto done;
+ }
+ PalDestMode = PalDestGDI->Mode;
+ PALETTE_UnlockPalette(PalDestGDI);
+ }
+ else
+ {
+ PalDestMode = PalSrcMode;
+ }
+
+ /* Translate Transparent (RGB) Color to the source palette */
+ if((XlateObj = (XLATEOBJ*)IntEngCreateXlate(PalSrcMode, PAL_RGB, SourcePalette, NULL)))
+ {
+ TransparentColor = XLATEOBJ_iXlate(XlateObj, (ULONG)TransColor);
+ EngDeleteXlate(XlateObj);
+ }
+
+ /* Create the XLATE object to convert colors between source and destination */
+ XlateObj = (XLATEOBJ*)IntEngCreateXlate(PalDestMode, PalSrcMode, DestPalette, SourcePalette);
+
+ rcDest.left = xDst;
+ rcDest.top = yDst;
+ rcDest.right = rcDest.left + cxDst;
+ rcDest.bottom = rcDest.top + cyDst;
+ rcSrc.left = xSrc;
+ rcSrc.top = ySrc;
+ rcSrc.right = rcSrc.left + cxSrc;
+ rcSrc.bottom = rcSrc.top + cySrc;
+
+ if((cxDst != cxSrc) || (cyDst != cySrc))
+ {
+ DPRINT1("TransparentBlt() does not support stretching at the moment!\n");
+ goto done;
+ }
+
+ Ret = IntEngTransparentBlt(&BitmapDest->SurfObj, &BitmapSrc->SurfObj,
+ DCDest->CombinedClip, XlateObj, &rcDest, &rcSrc,
+ TransparentColor, 0);
+
+done:
+ DC_UnlockDc(DCSrc);
+ if (BitmapDest)
+ {
+ BITMAPOBJ_UnlockBitmap(BitmapDest);
+ }
+ if (BitmapSrc)
+ {
+ BITMAPOBJ_UnlockBitmap(BitmapSrc);
+ }
+ if(hdcDst != hdcSrc)
+ {
+ DC_UnlockDc(DCDest);
+ }
+ if(XlateObj)
+ {
+ EngDeleteXlate(XlateObj);
+ }
+ return Ret;
+}
+
+/***********************************************************************
+ * MaskBlt
+ * Ported from WINE by sedwards 11-4-03
+ *
+ * Someone thought it would be faster to do it here and then switch back
+ * to GDI32. I dunno. Write a test and let me know.
+ */
+
+static __inline BYTE
+SwapROP3_SrcDst(BYTE bRop3)
+{
+ return (bRop3 & 0x99) | ((bRop3 & 0x22) << 1) | ((bRop3 & 0x44) >> 1);
+}
+
+#define FRGND_ROP3(ROP4) ((ROP4) & 0x00FFFFFF)
+#define BKGND_ROP3(ROP4) (ROP3Table[(SwapROP3_SrcDst((ROP4)>>24)) & 0xFF])
+#define DSTCOPY 0x00AA0029
+#define DSTERASE 0x00220326 /* dest = dest & (~src) : DSna */
+
+BOOL STDCALL
+NtGdiMaskBlt (
+ HDC hdcDest, INT nXDest, INT nYDest,
+ INT nWidth, INT nHeight, HDC hdcSrc,
+ INT nXSrc, INT nYSrc, HBITMAP hbmMask,
+ INT xMask, INT yMask, DWORD dwRop,
+ IN DWORD crBackColor)
+{
+ HBITMAP hOldMaskBitmap, hBitmap2, hOldBitmap2, hBitmap3, hOldBitmap3;
+ HDC hDCMask, hDC1, hDC2;
+ static const DWORD ROP3Table[256] =
+ {
+ 0x00000042, 0x00010289,
+ 0x00020C89, 0x000300AA,
+ 0x00040C88, 0x000500A9,
+ 0x00060865, 0x000702C5,
+ 0x00080F08, 0x00090245,
+ 0x000A0329, 0x000B0B2A,
+ 0x000C0324, 0x000D0B25,
+ 0x000E08A5, 0x000F0001,
+ 0x00100C85, 0x001100A6,
+ 0x00120868, 0x001302C8,
+ 0x00140869, 0x001502C9,
+ 0x00165CCA, 0x00171D54,
+ 0x00180D59, 0x00191CC8,
+ 0x001A06C5, 0x001B0768,
+ 0x001C06CA, 0x001D0766,
+ 0x001E01A5, 0x001F0385,
+ 0x00200F09, 0x00210248,
+ 0x00220326, 0x00230B24,
+ 0x00240D55, 0x00251CC5,
+ 0x002606C8, 0x00271868,
+ 0x00280369, 0x002916CA,
+ 0x002A0CC9, 0x002B1D58,
+ 0x002C0784, 0x002D060A,
+ 0x002E064A, 0x002F0E2A,
+ 0x0030032A, 0x00310B28,
+ 0x00320688, 0x00330008,
+ 0x003406C4, 0x00351864,
+ 0x003601A8, 0x00370388,
+ 0x0038078A, 0x00390604,
+ 0x003A0644, 0x003B0E24,
+ 0x003C004A, 0x003D18A4,
+ 0x003E1B24, 0x003F00EA,
+ 0x00400F0A, 0x00410249,
+ 0x00420D5D, 0x00431CC4,
+ 0x00440328, 0x00450B29,
+ 0x004606C6, 0x0047076A,
+ 0x00480368, 0x004916C5,
+ 0x004A0789, 0x004B0605,
+ 0x004C0CC8, 0x004D1954,
+ 0x004E0645, 0x004F0E25,
+ 0x00500325, 0x00510B26,
+ 0x005206C9, 0x00530764,
+ 0x005408A9, 0x00550009,
+ 0x005601A9, 0x00570389,
+ 0x00580785, 0x00590609,
+ 0x005A0049, 0x005B18A9,
+ 0x005C0649, 0x005D0E29,
+ 0x005E1B29, 0x005F00E9,
+ 0x00600365, 0x006116C6,
+ 0x00620786, 0x00630608,
+ 0x00640788, 0x00650606,
+ 0x00660046, 0x006718A8,
+ 0x006858A6, 0x00690145,
+ 0x006A01E9, 0x006B178A,
+ 0x006C01E8, 0x006D1785,
+ 0x006E1E28, 0x006F0C65,
+ 0x00700CC5, 0x00711D5C,
+ 0x00720648, 0x00730E28,
+ 0x00740646, 0x00750E26,
+ 0x00761B28, 0x007700E6,
+ 0x007801E5, 0x00791786,
+ 0x007A1E29, 0x007B0C68,
+ 0x007C1E24, 0x007D0C69,
+ 0x007E0955, 0x007F03C9,
+ 0x008003E9, 0x00810975,
+ 0x00820C49, 0x00831E04,
+ 0x00840C48, 0x00851E05,
+ 0x008617A6, 0x008701C5,
+ 0x008800C6, 0x00891B08,
+ 0x008A0E06, 0x008B0666,
+ 0x008C0E08, 0x008D0668,
+ 0x008E1D7C, 0x008F0CE5,
+ 0x00900C45, 0x00911E08,
+ 0x009217A9, 0x009301C4,
+ 0x009417AA, 0x009501C9,
+ 0x00960169, 0x0097588A,
+ 0x00981888, 0x00990066,
+ 0x009A0709, 0x009B07A8,
+ 0x009C0704, 0x009D07A6,
+ 0x009E16E6, 0x009F0345,
+ 0x00A000C9, 0x00A11B05,
+ 0x00A20E09, 0x00A30669,
+ 0x00A41885, 0x00A50065,
+ 0x00A60706, 0x00A707A5,
+ 0x00A803A9, 0x00A90189,
+ 0x00AA0029, 0x00AB0889,
+ 0x00AC0744, 0x00AD06E9,
+ 0x00AE0B06, 0x00AF0229,
+ 0x00B00E05, 0x00B10665,
+ 0x00B21974, 0x00B30CE8,
+ 0x00B4070A, 0x00B507A9,
+ 0x00B616E9, 0x00B70348,
+ 0x00B8074A, 0x00B906E6,
+ 0x00BA0B09, 0x00BB0226,
+ 0x00BC1CE4, 0x00BD0D7D,
+ 0x00BE0269, 0x00BF08C9,
+ 0x00C000CA, 0x00C11B04,
+ 0x00C21884, 0x00C3006A,
+ 0x00C40E04, 0x00C50664,
+ 0x00C60708, 0x00C707AA,
+ 0x00C803A8, 0x00C90184,
+ 0x00CA0749, 0x00CB06E4,
+ 0x00CC0020, 0x00CD0888,
+ 0x00CE0B08, 0x00CF0224,
+ 0x00D00E0A, 0x00D1066A,
+ 0x00D20705, 0x00D307A4,
+ 0x00D41D78, 0x00D50CE9,
+ 0x00D616EA, 0x00D70349,
+ 0x00D80745, 0x00D906E8,
+ 0x00DA1CE9, 0x00DB0D75,
+ 0x00DC0B04, 0x00DD0228,
+ 0x00DE0268, 0x00DF08C8,
+ 0x00E003A5, 0x00E10185,
+ 0x00E20746, 0x00E306EA,
+ 0x00E40748, 0x00E506E5,
+ 0x00E61CE8, 0x00E70D79,
+ 0x00E81D74, 0x00E95CE6,
+ 0x00EA02E9, 0x00EB0849,
+ 0x00EC02E8, 0x00ED0848,
+ 0x00EE0086, 0x00EF0A08,
+ 0x00F00021, 0x00F10885,
+ 0x00F20B05, 0x00F3022A,
+ 0x00F40B0A, 0x00F50225,
+ 0x00F60265, 0x00F708C5,
+ 0x00F802E5, 0x00F90845,
+ 0x00FA0089, 0x00FB0A09,
+ 0x00FC008A, 0x00FD0A0A,
+ 0x00FE02A9, 0x00FF0062,
+ };
+
+ if (!hbmMask)
+ return NtGdiBitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop), 0, 0);
+
+ /* 1. make mask bitmap's dc */
+ hDCMask = NtGdiCreateCompatibleDC(hdcDest);
+ hOldMaskBitmap = (HBITMAP)NtGdiSelectBitmap(hDCMask, hbmMask);
+
+ /* 2. make masked Background bitmap */
+
+ /* 2.1 make bitmap */
+ hDC1 = NtGdiCreateCompatibleDC(hdcDest);
+ hBitmap2 = NtGdiCreateCompatibleBitmap(hdcDest, nWidth, nHeight);
+ hOldBitmap2 = (HBITMAP)NtGdiSelectBitmap(hDC1, hBitmap2);
+
+ /* 2.2 draw dest bitmap and mask */
+ NtGdiBitBlt(hDC1, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, SRCCOPY, 0, 0);
+ NtGdiBitBlt(hDC1, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, BKGND_ROP3(dwRop), 0, 0);
+ NtGdiBitBlt(hDC1, 0, 0, nWidth, nHeight, hDCMask, xMask, yMask, DSTERASE, 0, 0);
+
+ /* 3. make masked Foreground bitmap */
+
+ /* 3.1 make bitmap */
+ hDC2 = NtGdiCreateCompatibleDC(hdcDest);
+ hBitmap3 = NtGdiCreateCompatibleBitmap(hdcDest, nWidth, nHeight);
+ hOldBitmap3 = (HBITMAP)NtGdiSelectBitmap(hDC2, hBitmap3);
+
+ /* 3.2 draw src bitmap and mask */
+ NtGdiBitBlt(hDC2, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY, 0, 0);
+ NtGdiBitBlt(hDC2, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop), 0,0);
+ NtGdiBitBlt(hDC2, 0, 0, nWidth, nHeight, hDCMask, xMask, yMask, SRCAND, 0, 0);
+
+ /* 4. combine two bitmap and copy it to hdcDest */
+ NtGdiBitBlt(hDC1, 0, 0, nWidth, nHeight, hDC2, 0, 0, SRCPAINT, 0, 0);
+ NtGdiBitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hDC1, 0, 0, SRCCOPY, 0, 0);
+
+ /* 5. restore all object */
+ NtGdiSelectBitmap(hDCMask, hOldMaskBitmap);
+ NtGdiSelectBitmap(hDC1, hOldBitmap2);
+ NtGdiSelectBitmap(hDC2, hOldBitmap3);
+
+ /* 6. delete all temp object */
+ NtGdiDeleteObject(hBitmap2);
+ NtGdiDeleteObject(hBitmap3);
+
+ NtGdiDeleteObjectApp(hDC1);
+ NtGdiDeleteObjectApp(hDC2);
+ NtGdiDeleteObjectApp(hDCMask);
+
+ return TRUE;
+}
+
+BOOL
+APIENTRY
+NtGdiPlgBlt(
+ IN HDC hdcTrg,
+ IN LPPOINT pptlTrg,
+ IN HDC hdcSrc,
+ IN INT xSrc,
+ IN INT ySrc,
+ IN INT cxSrc,
+ IN INT cySrc,
+ IN HBITMAP hbmMask,
+ IN INT xMask,
+ IN INT yMask,
+ IN DWORD crBackColor)
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
+
+BOOL STDCALL
+NtGdiStretchBlt(
+ HDC hDCDest,
+ INT XOriginDest,
+ INT YOriginDest,
+ INT WidthDest,
+ INT HeightDest,
+ HDC hDCSrc,
+ INT XOriginSrc,
+ INT YOriginSrc,
+ INT WidthSrc,
+ INT HeightSrc,
+ DWORD ROP,
+ IN DWORD dwBackColor)
+{
+ PDC DCDest = NULL;
+ PDC DCSrc = NULL;
+ PDC_ATTR Dc_Attr;
+ BITMAPOBJ *BitmapDest, *BitmapSrc;
+ RECTL DestRect;
+ RECTL SourceRect;
+ BOOL Status;
+ XLATEOBJ *XlateObj = NULL;
+ PGDIBRUSHOBJ BrushObj = NULL;
+ BOOL UsesSource = ((ROP & 0xCC0000) >> 2) != (ROP & 0x330000);
+ BOOL UsesPattern = ((ROP & 0xF00000) >> 4) != (ROP & 0x0F0000);
+
+ if (0 == WidthDest || 0 == HeightDest || 0 == WidthSrc || 0 == HeightSrc)
+ {
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+ DCDest = DC_LockDc(hDCDest);
+ if (NULL == DCDest)
+ {
+ DPRINT1("Invalid destination dc handle (0x%08x) passed to NtGdiStretchBlt\n", hDCDest);
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+ if (DCDest->DC_Type == DC_TYPE_INFO)
+ {
+ DC_UnlockDc(DCDest);
+ /* Yes, Windows really returns TRUE in this case */
+ return TRUE;
+ }
+
+ if (UsesSource)
+ {
+ if (hDCSrc != hDCDest)
+ {
+ DCSrc = DC_LockDc(hDCSrc);
+ if (NULL == DCSrc)
+ {
+ DC_UnlockDc(DCDest);
+ DPRINT1("Invalid source dc handle (0x%08x) passed to NtGdiStretchBlt\n", hDCSrc);
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+ if (DCSrc->DC_Type == DC_TYPE_INFO)
+ {
+ DC_UnlockDc(DCSrc);
+ DC_UnlockDc(DCDest);
+ /* Yes, Windows really returns TRUE in this case */
+ return TRUE;
+ }
+ }
+ else
+ {
+ DCSrc = DCDest;
+ }
+ }
+ else
+ {
+ DCSrc = NULL;
+ }
+
+ /* Offset the destination and source by the origin of their DCs. */
+ // FIXME: ptlDCOrig is in device coordinates!
+ XOriginDest += DCDest->ptlDCOrig.x;
+ YOriginDest += DCDest->ptlDCOrig.y;
+ if (UsesSource)
+ {
+ XOriginSrc += DCSrc->ptlDCOrig.x;
+ YOriginSrc += DCSrc->ptlDCOrig.y;
+ }
+
+ DestRect.left = XOriginDest;
+ DestRect.top = YOriginDest;
+ DestRect.right = XOriginDest+WidthDest;
+ DestRect.bottom = YOriginDest+HeightDest;
+
+ SourceRect.left = XOriginSrc;
+ SourceRect.top = YOriginSrc;
+ SourceRect.right = XOriginSrc+WidthSrc;
+ SourceRect.bottom = YOriginSrc+HeightSrc;
+
+ /* Determine surfaces to be used in the bitblt */
+ BitmapDest = BITMAPOBJ_LockBitmap(DCDest->w.hBitmap);
+ if (UsesSource)
+ {
+ if (DCSrc->w.hBitmap == DCDest->w.hBitmap)
+ BitmapSrc = BitmapDest;
+ else
+ BitmapSrc = BITMAPOBJ_LockBitmap(DCSrc->w.hBitmap);
+
+ int sw = BitmapSrc->SurfObj.sizlBitmap.cx;
+ int sh = BitmapSrc->SurfObj.sizlBitmap.cy;
+ if ( SourceRect.left < 0 )
+ {
+ DestRect.left = DestRect.right - (DestRect.right-DestRect.left) * (SourceRect.right)/abs(SourceRect.right-SourceRect.left);
+ SourceRect.left = 0;
+ }
+ if ( SourceRect.top < 0 )
+ {
+ DestRect.top = DestRect.bottom - (DestRect.bottom-DestRect.top) * (SourceRect.bottom)/abs(SourceRect.bottom-SourceRect.top);
+ SourceRect.top = 0;
+ }
+ if ( SourceRect.right < -1 )
+ {
+ DestRect.right = DestRect.left + (DestRect.right-DestRect.left) * (-1-SourceRect.left)/abs(SourceRect.right-SourceRect.left);
+ SourceRect.right = -1;
+ }
+ if ( SourceRect.bottom < -1 )
+ {
+ DestRect.bottom = DestRect.top + (DestRect.bottom-DestRect.top) * (-1-SourceRect.top)/abs(SourceRect.bottom-SourceRect.top);
+ SourceRect.bottom = -1;
+ }
+ if ( SourceRect.right > sw )
+ {
+ DestRect.right = DestRect.left + (DestRect.right-DestRect.left) * abs(sw-SourceRect.left) / abs(SourceRect.right-SourceRect.left);
+ SourceRect.right = sw;
+ }
+ if ( SourceRect.bottom > sh )
+ {
+ DestRect.bottom = DestRect.top + (DestRect.bottom-DestRect.top) * abs(sh-SourceRect.top) / abs(SourceRect.bottom-SourceRect.top);
+ SourceRect.bottom = sh;
+ }
+ sw--;
+ sh--;
+ if ( SourceRect.left > sw )
+ {
+ DestRect.left = DestRect.right - (DestRect.right-DestRect.left) * (SourceRect.right-sw) / abs(SourceRect.right-SourceRect.left);
+ SourceRect.left = 0;
+ }
+ if ( SourceRect.top > sh )
+ {
+ DestRect.top = DestRect.bottom - (DestRect.bottom-DestRect.top) * (SourceRect.bottom-sh) / abs(SourceRect.bottom-SourceRect.top);
+ SourceRect.top = 0;
+ }
+ if (0 == (DestRect.right-DestRect.left) || 0 == (DestRect.bottom-DestRect.top) || 0 == (SourceRect.right-SourceRect.left) || 0 == (SourceRect.bottom-SourceRect.top))
+ {
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ Status = FALSE;
+ goto failed;
+ }
+
+ /* Create the XLATEOBJ. */
+ XlateObj = IntCreateXlateForBlt(DCDest, DCSrc, BitmapDest, BitmapSrc);
+ if (XlateObj == (XLATEOBJ*)-1)
+ {
+ SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
+ Status = FALSE;
+ goto failed;
+ }
+ }
+ else
+ {
+ BitmapSrc = NULL;
+ }
+
+ if (UsesPattern)
+ {
+ Dc_Attr = DCDest->pDc_Attr;
+ if (!Dc_Attr) Dc_Attr = &DCDest->Dc_Attr;
+ BrushObj = BRUSHOBJ_LockBrush(Dc_Attr->hbrush);
+ if (NULL == BrushObj)
+ {
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ Status = FALSE;
+ goto failed;
+ }
+ }
+ else
+ {
+ BrushObj = NULL;
+ }
+
+ /* Perform the bitblt operation */
+ Status = IntEngStretchBlt(&BitmapDest->SurfObj, &BitmapSrc->SurfObj,
+ NULL, DCDest->CombinedClip, XlateObj,
+ &DestRect, &SourceRect, NULL, NULL, NULL,
+ COLORONCOLOR);
+
+failed:
+ if (XlateObj)
+ {
+ EngDeleteXlate(XlateObj);
+ }
+ if (BrushObj)
+ {
+ BRUSHOBJ_UnlockBrush(BrushObj);
+ }
+ if (UsesSource && DCSrc->w.hBitmap != DCDest->w.hBitmap)
+ {
+ BITMAPOBJ_UnlockBitmap(BitmapSrc);
+ }
+ BITMAPOBJ_UnlockBitmap(BitmapDest);
+ if (UsesSource && hDCSrc != hDCDest)
+ {
+ DC_UnlockDc(DCSrc);
+ }
+ DC_UnlockDc(DCDest);
+
+ return Status;
+}
+
+BOOL FASTCALL
+IntPatBlt(
+ PDC dc,
+ INT XLeft,
+ INT YLeft,
+ INT Width,
+ INT Height,
+ DWORD ROP,
+ PGDIBRUSHOBJ BrushObj)
+{
+ RECTL DestRect;
+ BITMAPOBJ *BitmapObj;
+ GDIBRUSHINST BrushInst;
+ POINTL BrushOrigin;
+ BOOL ret = TRUE;
+
+ ASSERT(BrushObj);
+
+ BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
+ if (BitmapObj == NULL)
+ {
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+
+ if (!(BrushObj->flAttrs & GDIBRUSH_IS_NULL))
+ {
+ if (Width > 0)
+ {
+ DestRect.left = XLeft + dc->ptlDCOrig.x;
+ DestRect.right = XLeft + Width + dc->ptlDCOrig.x;
+ }
+ else
+ {
+ DestRect.left = XLeft + Width + 1 + dc->ptlDCOrig.x;
+ DestRect.right = XLeft + dc->ptlDCOrig.x + 1;
+ }
+
+ if (Height > 0)
+ {
+ DestRect.top = YLeft + dc->ptlDCOrig.y;
+ DestRect.bottom = YLeft + Height + dc->ptlDCOrig.y;
+ }
+ else
+ {
+ DestRect.top = YLeft + Height + dc->ptlDCOrig.y + 1;
+ DestRect.bottom = YLeft + dc->ptlDCOrig.y + 1;
+ }
+
+ IntLPtoDP(dc, (LPPOINT)&DestRect, 2);
+
+ BrushOrigin.x = BrushObj->ptOrigin.x + dc->ptlDCOrig.x;
+ BrushOrigin.y = BrushObj->ptOrigin.y + dc->ptlDCOrig.y;
+
+ IntGdiInitBrushInstance(&BrushInst, BrushObj, dc->XlateBrush);
+
+ ret = IntEngBitBlt(
+ &BitmapObj->SurfObj,
+ NULL,
+ NULL,
+ dc->CombinedClip,
+ NULL,
+ &DestRect,
+ NULL,
+ NULL,
+ &BrushInst.BrushObject, // use pDC->eboFill
+ &BrushOrigin,
+ ROP3_TO_ROP4(ROP));
+ }
+
+ BITMAPOBJ_UnlockBitmap(BitmapObj);
+
+ return ret;
+}
+
+BOOL FASTCALL
+IntGdiPolyPatBlt(
+ HDC hDC,
+ DWORD dwRop,
+ PPATRECT pRects,
+ int cRects,
+ ULONG Reserved)
+{
+ int i;
+ PPATRECT r;
+ PGDIBRUSHOBJ BrushObj;
+ DC *dc;
+
+ dc = DC_LockDc(hDC);
+ if (dc == NULL)
+ {
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+ if (dc->DC_Type == DC_TYPE_INFO)
+ {
+ DC_UnlockDc(dc);
+ /* Yes, Windows really returns TRUE in this case */
+ return TRUE;
+ }
+
+ for (r = pRects, i = 0; i < cRects; i++)
+ {
+ BrushObj = BRUSHOBJ_LockBrush(r->hBrush);
+ if(BrushObj != NULL)
+ {
+ IntPatBlt(
+ dc,
+ r->r.left,
+ r->r.top,
+ r->r.right,
+ r->r.bottom,
+ dwRop,
+ BrushObj);
+ BRUSHOBJ_UnlockBrush(BrushObj);
+ }
+ r++;
+ }
+
+ DC_UnlockDc(dc);
+
+ return TRUE;
+}
+
+
+BOOL STDCALL
+NtGdiPatBlt(
+ HDC hDC,
+ INT XLeft,
+ INT YLeft,
+ INT Width,
+ INT Height,
+ DWORD ROP)
+{
+ PGDIBRUSHOBJ BrushObj;
+ DC *dc;
+ PDC_ATTR Dc_Attr;
+ BOOL ret;
+
+ BOOL UsesSource = ROP3_USES_SOURCE(ROP);
+ if (UsesSource)
+ {
+ /* in this case we call on GdiMaskBlt */
+ return NtGdiMaskBlt(hDC, XLeft, YLeft, Width, Height, 0,0,0,0,0,0,ROP,0);
+ }
+
+ dc = DC_LockDc(hDC);
+ if (dc == NULL)
+ {
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+ Dc_Attr = dc->pDc_Attr;
+ if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
+ if (dc->DC_Type == DC_TYPE_INFO)
+ {
+ DC_UnlockDc(dc);
+ /* Yes, Windows really returns TRUE in this case */
+ return TRUE;
+ }
+
+ BrushObj = BRUSHOBJ_LockBrush(Dc_Attr->hbrush);
+ if (BrushObj == NULL)
+ {
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ DC_UnlockDc(dc);
+ return FALSE;
+ }
+
+ ret = IntPatBlt(
+ dc,
+ XLeft,
+ YLeft,
+ Width,
+ Height,
+ ROP,
+ BrushObj);
+
+ BRUSHOBJ_UnlockBrush(BrushObj);
+ DC_UnlockDc(dc);
+
+ return ret;
+}
+
+BOOL STDCALL
+NtGdiPolyPatBlt(
+ HDC hDC,
+ DWORD dwRop,
+ IN PPOLYPATBLT pRects,
+ IN DWORD cRects,
+ IN DWORD Mode)
+{
+ PPATRECT rb = NULL;
+ NTSTATUS Status = STATUS_SUCCESS;
+ BOOL Ret;
+
+ if (cRects > 0)
+ {
+ rb = ExAllocatePoolWithTag(PagedPool, sizeof(PATRECT) * cRects, TAG_PATBLT);
+ if (!rb)
+ {
+ SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+ return FALSE;
+ }
+ _SEH_TRY
+ {
+ ProbeForRead(pRects,
+ cRects * sizeof(PATRECT),
+ 1);
+ RtlCopyMemory(rb,
+ pRects,
+ cRects * sizeof(PATRECT));
+ }
+ _SEH_HANDLE
+ {
+ Status = _SEH_GetExceptionCode();
+ }
+ _SEH_END;
+
+ if (!NT_SUCCESS(Status))
+ {
+ ExFreePool(rb);
+ SetLastNtError(Status);
+ return FALSE;
+ }
+ }
+
+ Ret = IntGdiPolyPatBlt(hDC, dwRop, (PPATRECT)pRects, cRects, Mode);
+
+ if (cRects > 0)
+ ExFreePool(rb);
+
+ return Ret;
+}
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-/* $Id$ */
#include <w32k.h>
#include "math.h"
#define GROW_FACTOR_NUMER 2 /* Numerator of grow factor for the array */
#define GROW_FACTOR_DENOM 1 /* Denominator of grow factor */
-BOOL FASTCALL PATH_AddEntry (GdiPath *pPath, const POINT *pPoint, BYTE flags);
-BOOL FASTCALL PATH_AddFlatBezier (GdiPath *pPath, POINT *pt, BOOL closed);
-BOOL FASTCALL PATH_DoArcPart (GdiPath *pPath, FLOAT_POINT corners[], double angleStart, double angleEnd, BOOL addMoveTo);
-BOOL FASTCALL PATH_FillPath( PDC dc, GdiPath *pPath );
-BOOL FASTCALL PATH_FlattenPath (GdiPath *pPath);
+BOOL FASTCALL PATH_AddEntry (PPATH pPath, const POINT *pPoint, BYTE flags);
+BOOL FASTCALL PATH_AddFlatBezier (PPATH pPath, POINT *pt, BOOL closed);
+BOOL FASTCALL PATH_DoArcPart (PPATH pPath, FLOAT_POINT corners[], double angleStart, double angleEnd, BYTE startEntryType);
+BOOL FASTCALL PATH_FillPath( PDC dc, PPATH pPath );
+BOOL FASTCALL PATH_FlattenPath (PPATH pPath);
VOID FASTCALL PATH_NormalizePoint (FLOAT_POINT corners[], const FLOAT_POINT *pPoint, double *pX, double *pY);
-BOOL FASTCALL PATH_PathToRegion (GdiPath *pPath, INT nPolyFillMode, HRGN *pHrgn);
-BOOL FASTCALL PATH_ReserveEntries (GdiPath *pPath, INT numEntries);
+
+BOOL FASTCALL PATH_ReserveEntries (PPATH pPath, INT numEntries);
VOID FASTCALL PATH_ScaleNormalizedPoint (FLOAT_POINT corners[], double x, double y, POINT *pPoint);
-BOOL FASTCALL PATH_StrokePath(DC *dc, GdiPath *pPath);
+BOOL FASTCALL PATH_StrokePath(DC *dc, PPATH pPath);
BOOL PATH_CheckCorners(DC *dc, POINT corners[], INT x1, INT y1, INT x2, INT y2);
-VOID FASTCALL
-IntGetCurrentPositionEx(PDC dc, LPPOINT pt);
+VOID FASTCALL IntGetCurrentPositionEx(PDC dc, LPPOINT pt);
+/***********************************************************************
+ * Internal functions
+ */
BOOL
-STDCALL
-NtGdiAbortPath(HDC hDC)
+FASTCALL
+PATH_Delete(HPATH hPath)
{
- BOOL ret = TRUE;
- PDC dc = DC_LockDc ( hDC );
-
- if( !dc ) return FALSE;
-
- PATH_EmptyPath(&dc->w.path);
-
- DC_UnlockDc ( dc );
- return ret;
+ if (!hPath) return FALSE;
+ PPATH pPath = PATH_LockPath( hPath );
+ if (!pPath) return FALSE;
+ PATH_DestroyGdiPath( pPath );
+ PATH_UnlockPath( pPath );
+ PATH_FreeExtPathByHandle(hPath);
+ return TRUE;
}
-BOOL
-STDCALL
-NtGdiBeginPath( HDC hDC )
-{
- BOOL ret = TRUE;
- PDC dc = DC_LockDc ( hDC );
-
- if( !dc ) return FALSE;
-
- /* If path is already open, do nothing */
- if ( dc->w.path.state != PATH_Open )
- {
- /* Make sure that path is empty */
- PATH_EmptyPath( &dc->w.path );
-
- /* Initialize variables for new path */
- dc->w.path.newStroke = TRUE;
- dc->w.path.state = PATH_Open;
- }
-
- DC_UnlockDc ( dc );
- return ret;
-}
VOID
FASTCALL
-IntGdiCloseFigure(PDC pDc)
+IntGdiCloseFigure(PPATH pPath)
{
- ASSERT(pDc);
- ASSERT(pDc->w.path.state == PATH_Open);
+ ASSERT(pPath->state == PATH_Open);
// FIXME: Shouldn't we draw a line to the beginning of the figure?
// Set PT_CLOSEFIGURE on the last entry and start a new stroke
- if(pDc->w.path.numEntriesUsed)
+ if(pPath->numEntriesUsed)
{
- pDc->w.path.pFlags[pDc->w.path.numEntriesUsed-1]|=PT_CLOSEFIGURE;
- pDc->w.path.newStroke=TRUE;
+ pPath->pFlags[pPath->numEntriesUsed-1]|=PT_CLOSEFIGURE;
+ pPath->newStroke=TRUE;
}
}
+/* PATH_FillPath
+ *
+ *
+ */
BOOL
-STDCALL
-NtGdiCloseFigure(HDC hDC)
+FASTCALL
+PATH_FillPath( PDC dc, PPATH pPath )
{
- BOOL Ret = FALSE; // default to failure
- PDC pDc;
+ INT mapMode, graphicsMode;
+ SIZE ptViewportExt, ptWindowExt;
+ POINTL ptViewportOrg, ptWindowOrg;
+ XFORM xform;
+ HRGN hrgn;
+ PDC_ATTR Dc_Attr = dc->pDc_Attr;
- DPRINT("Enter %s\n", __FUNCTION__);
+ if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
- pDc = DC_LockDc(hDC);
- if(!pDc) return FALSE;
+ if( pPath->state != PATH_Closed )
+ {
+ SetLastWin32Error(ERROR_CAN_NOT_COMPLETE);
+ return FALSE;
+ }
- if(pDc->w.path.state==PATH_Open)
- {
- IntGdiCloseFigure(pDc);
- Ret = TRUE;
- }
- else
- {
- // FIXME: check if lasterror is set correctly
- SetLastWin32Error(ERROR_CAN_NOT_COMPLETE);
- }
+ if( PATH_PathToRegion( pPath, Dc_Attr->jFillMode, &hrgn ))
+ {
+ /* Since PaintRgn interprets the region as being in logical coordinates
+ * but the points we store for the path are already in device
+ * coordinates, we have to set the mapping mode to MM_TEXT temporarily.
+ * Using SaveDC to save information about the mapping mode / world
+ * transform would be easier but would require more overhead, especially
+ * now that SaveDC saves the current path.
+ */
- DC_UnlockDc(pDc);
+ /* Save the information about the old mapping mode */
+ mapMode = Dc_Attr->iMapMode;
+ ptViewportExt = Dc_Attr->szlViewportExt;
+ ptViewportOrg = Dc_Attr->ptlViewportOrg;
+ ptWindowExt = Dc_Attr->szlWindowExt;
+ ptWindowOrg = Dc_Attr->ptlWindowOrg;
- return Ret;
-}
+ /* Save world transform
+ * NB: The Windows documentation on world transforms would lead one to
+ * believe that this has to be done only in GM_ADVANCED; however, my
+ * tests show that resetting the graphics mode to GM_COMPATIBLE does
+ * not reset the world transform.
+ */
+ xform = dc->DcLevel.xformWorld2Wnd;
-BOOL
-STDCALL
-NtGdiEndPath(HDC hDC)
-{
- BOOL ret = TRUE;
- PDC dc = DC_LockDc ( hDC );
+ /* Set MM_TEXT */
+ IntGdiSetMapMode( dc, MM_TEXT );
+ Dc_Attr->ptlViewportOrg.x = 0;
+ Dc_Attr->ptlViewportOrg.y = 0;
+ Dc_Attr->ptlWindowOrg.x = 0;
+ Dc_Attr->ptlWindowOrg.y = 0;
+
+ graphicsMode = Dc_Attr->iGraphicsMode;
+ Dc_Attr->iGraphicsMode = GM_ADVANCED;
+ IntGdiModifyWorldTransform( dc, &xform, MWT_IDENTITY );
+ Dc_Attr->iGraphicsMode = graphicsMode;
- if ( !dc ) return FALSE;
+ /* Paint the region */
+ IntGdiPaintRgn( dc, hrgn );
+ NtGdiDeleteObject( hrgn );
+ /* Restore the old mapping mode */
+ IntGdiSetMapMode( dc, mapMode );
+ Dc_Attr->szlViewportExt = ptViewportExt;
+ Dc_Attr->ptlViewportOrg = ptViewportOrg;
+ Dc_Attr->szlWindowExt = ptWindowExt;
+ Dc_Attr->ptlWindowOrg = ptWindowOrg;
- /* Check that path is currently being constructed */
- if( dc->w.path.state != PATH_Open )
- {
- ret = FALSE;
+ /* Go to GM_ADVANCED temporarily to restore the world transform */
+ graphicsMode = Dc_Attr->iGraphicsMode;
+ Dc_Attr->iGraphicsMode = GM_ADVANCED;
+ IntGdiModifyWorldTransform( dc, &xform, MWT_MAX+1 );
+ Dc_Attr->iGraphicsMode = graphicsMode;
+ return TRUE;
}
- /* Set flag to indicate that path is finished */
- else dc->w.path.state = PATH_Closed;
-
- DC_UnlockDc ( dc );
- return ret;
+ return FALSE;
}
-BOOL
-STDCALL
-NtGdiFillPath(HDC hDC)
+/* PATH_InitGdiPath
+ *
+ * Initializes the GdiPath structure.
+ */
+VOID
+FASTCALL
+PATH_InitGdiPath ( PPATH pPath )
{
- BOOL ret = TRUE;
- PDC dc = DC_LockDc ( hDC );
+ ASSERT(pPath!=NULL);
- if ( !dc ) return FALSE;
+ pPath->state=PATH_Null;
+ pPath->pPoints=NULL;
+ pPath->pFlags=NULL;
+ pPath->numEntriesUsed=0;
+ pPath->numEntriesAllocated=0;
+}
- ret = PATH_FillPath( dc, &dc->w.path );
- if( ret )
- {
- /* FIXME: Should the path be emptied even if conversion
- failed? */
- PATH_EmptyPath( &dc->w.path );
- }
+/* PATH_DestroyGdiPath
+ *
+ * Destroys a GdiPath structure (frees the memory in the arrays).
+ */
+VOID
+FASTCALL
+PATH_DestroyGdiPath ( PPATH pPath )
+{
+ ASSERT(pPath!=NULL);
- DC_UnlockDc ( dc );
- return ret;
+ if (pPath->pPoints) ExFreePool(pPath->pPoints);
+ if (pPath->pFlags) ExFreePool(pPath->pFlags);
}
+/* PATH_AssignGdiPath
+ *
+ * Copies the GdiPath structure "pPathSrc" to "pPathDest". A deep copy is
+ * performed, i.e. the contents of the pPoints and pFlags arrays are copied,
+ * not just the pointers. Since this means that the arrays in pPathDest may
+ * need to be resized, pPathDest should have been initialized using
+ * PATH_InitGdiPath (in C++, this function would be an assignment operator,
+ * not a copy constructor).
+ * Returns TRUE if successful, else FALSE.
+ */
BOOL
-STDCALL
-NtGdiFlattenPath(HDC hDC)
+FASTCALL
+PATH_AssignGdiPath ( PPATH pPathDest, const PPATH pPathSrc )
{
- BOOL Ret = FALSE;
- DC *pDc;
-
- DPRINT("Enter %s\n", __FUNCTION__);
+ ASSERT(pPathDest!=NULL && pPathSrc!=NULL);
- pDc = DC_LockDc(hDC);
- if(!pDc) return FALSE;
+ /* Make sure destination arrays are big enough */
+ if ( !PATH_ReserveEntries(pPathDest, pPathSrc->numEntriesUsed) )
+ return FALSE;
- if(pDc->w.path.state == PATH_Open)
- Ret = PATH_FlattenPath(&pDc->w.path);
+ /* Perform the copy operation */
+ memcpy(pPathDest->pPoints, pPathSrc->pPoints,
+ sizeof(POINT)*pPathSrc->numEntriesUsed);
+ memcpy(pPathDest->pFlags, pPathSrc->pFlags,
+ sizeof(BYTE)*pPathSrc->numEntriesUsed);
- DC_UnlockDc(pDc);
- return Ret;
+ pPathDest->state=pPathSrc->state;
+ pPathDest->numEntriesUsed=pPathSrc->numEntriesUsed;
+ pPathDest->newStroke=pPathSrc->newStroke;
+ return TRUE;
}
-
+/* PATH_MoveTo
+ *
+ * Should be called when a MoveTo is performed on a DC that has an
+ * open path. This starts a new stroke. Returns TRUE if successful, else
+ * FALSE.
+ */
BOOL
-APIENTRY
-NtGdiGetMiterLimit(
- IN HDC hdc,
- OUT PDWORD pdwOut)
+FASTCALL
+PATH_MoveTo ( PDC dc )
{
- DC *pDc;
- gxf_long worker;
- NTSTATUS Status = STATUS_SUCCESS;
-
- if(!(pDc = DC_LockDc(hdc))) return FALSE;
-
- worker.f = pDc->DcLevel.laPath.eMiterLimit;
+ PPATH pPath = PATH_LockPath( dc->DcLevel.hPath );
+ if (!pPath) return FALSE;
- if (pdwOut)
+ /* Check that path is open */
+ if ( pPath->state != PATH_Open )
{
- _SEH_TRY
- {
- ProbeForWrite(pdwOut,
- sizeof(DWORD),
- 1);
- *pdwOut = worker.l;
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
- if (!NT_SUCCESS(Status))
- {
- SetLastNtError(Status);
- DC_UnlockDc(pDc);
- return FALSE;
- }
+ PATH_UnlockPath( pPath );
+ /* FIXME: Do we have to call SetLastError? */
+ return FALSE;
}
-
- DC_UnlockDc(pDc);
+ /* Start a new stroke */
+ pPath->newStroke = TRUE;
+ PATH_UnlockPath( pPath );
return TRUE;
-
}
-INT
-STDCALL
-NtGdiGetPath(
- HDC hDC,
- LPPOINT Points,
- LPBYTE Types,
- INT nSize)
+/* PATH_LineTo
+ *
+ * Should be called when a LineTo is performed on a DC that has an
+ * open path. This adds a PT_LINETO entry to the path (and possibly
+ * a PT_MOVETO entry, if this is the first LineTo in a stroke).
+ * Returns TRUE if successful, else FALSE.
+ */
+BOOL
+FASTCALL
+PATH_LineTo ( PDC dc, INT x, INT y )
{
- INT ret = -1;
- GdiPath *pPath;
-
- DC *dc = DC_LockDc(hDC);
- if(!dc)
- {
- DPRINT1("Can't lock dc!\n");
- return -1;
- }
+ BOOL Ret;
+ PPATH pPath;
+ POINT point, pointCurPos;
- pPath = &dc->w.path;
+ pPath = PATH_LockPath( dc->DcLevel.hPath );
+ if (!pPath) return FALSE;
- if(pPath->state != PATH_Closed)
- {
- SetLastWin32Error(ERROR_CAN_NOT_COMPLETE);
- goto done;
- }
+ /* Check that path is open */
+ if ( pPath->state != PATH_Open )
+ {
+ PATH_UnlockPath( pPath );
+ return FALSE;
+ }
- if(nSize==0)
- {
- ret = pPath->numEntriesUsed;
- }
- else if(nSize<pPath->numEntriesUsed)
- {
- SetLastWin32Error(ERROR_INVALID_PARAMETER);
- goto done;
- }
- else
- {
- _SEH_TRY
- {
- memcpy(Points, pPath->pPoints, sizeof(POINT)*pPath->numEntriesUsed);
- memcpy(Types, pPath->pFlags, sizeof(BYTE)*pPath->numEntriesUsed);
-
- /* Convert the points to logical coordinates */
- IntDPtoLP(dc, Points, pPath->numEntriesUsed);
+ /* Convert point to device coordinates */
+ point.x=x;
+ point.y=y;
+ CoordLPtoDP ( dc, &point );
- ret = pPath->numEntriesUsed;
- }
- _SEH_HANDLE
- {
- SetLastNtError(_SEH_GetExceptionCode());
- }
- _SEH_END
- }
+ /* Add a PT_MOVETO if necessary */
+ if ( pPath->newStroke )
+ {
+ pPath->newStroke = FALSE;
+ IntGetCurrentPositionEx ( dc, &pointCurPos );
+ CoordLPtoDP ( dc, &pointCurPos );
+ if ( !PATH_AddEntry(pPath, &pointCurPos, PT_MOVETO) )
+ {
+ PATH_UnlockPath( pPath );
+ return FALSE;
+ }
+ }
-done:
- DC_UnlockDc(dc);
- return ret;
+ /* Add a PT_LINETO entry */
+ Ret = PATH_AddEntry(pPath, &point, PT_LINETO);
+ PATH_UnlockPath( pPath );
+ return Ret;
}
-HRGN
-STDCALL
-NtGdiPathToRegion(HDC hDC)
+/* PATH_Rectangle
+ *
+ * Should be called when a call to Rectangle is performed on a DC that has
+ * an open path. Returns TRUE if successful, else FALSE.
+ */
+BOOL
+FASTCALL
+PATH_Rectangle ( PDC dc, INT x1, INT y1, INT x2, INT y2 )
{
- GdiPath *pPath;
- HRGN hrgnRval = 0;
- DC *pDc;
- PDC_ATTR Dc_Attr;
-
- DPRINT("Enter %s\n", __FUNCTION__);
+ PPATH pPath;
+ POINT corners[2], pointTemp;
+ INT temp;
- pDc = DC_LockDc(hDC);
- if(!pDc) return NULL;
- Dc_Attr = pDc->pDc_Attr;
- if(!Dc_Attr) Dc_Attr = &pDc->Dc_Attr;
- pPath = &pDc->w.path;
+ pPath = PATH_LockPath( dc->DcLevel.hPath );
+ if (!pPath) return FALSE;
- if(pPath->state!=PATH_Closed)
- {
- //FIXME: check that setlasterror is being called correctly
- SetLastWin32Error(ERROR_CAN_NOT_COMPLETE);
- }
- else
- {
- /* FIXME: Should we empty the path even if conversion failed? */
- if(PATH_PathToRegion(pPath, Dc_Attr->jFillMode, &hrgnRval))
- PATH_EmptyPath(pPath);
- }
+ /* Check that path is open */
+ if ( pPath->state != PATH_Open )
+ {
+ PATH_UnlockPath( pPath );
+ return FALSE;
+ }
- DC_UnlockDc(pDc);
- return hrgnRval;
-}
+ /* Convert points to device coordinates */
+ corners[0].x=x1;
+ corners[0].y=y1;
+ corners[1].x=x2;
+ corners[1].y=y2;
+ IntLPtoDP ( dc, corners, 2 );
-BOOL
-APIENTRY
-NtGdiSetMiterLimit(
- IN HDC hdc,
- IN DWORD dwNew,
- IN OUT OPTIONAL PDWORD pdwOut)
-{
- DC *pDc;
- gxf_long worker, worker1;
- NTSTATUS Status = STATUS_SUCCESS;
+ /* Make sure first corner is top left and second corner is bottom right */
+ if ( corners[0].x > corners[1].x )
+ {
+ temp=corners[0].x;
+ corners[0].x=corners[1].x;
+ corners[1].x=temp;
+ }
+ if ( corners[0].y > corners[1].y )
+ {
+ temp=corners[0].y;
+ corners[0].y=corners[1].y;
+ corners[1].y=temp;
+ }
- if(!(pDc = DC_LockDc(hdc))) return FALSE;
+ /* In GM_COMPATIBLE, don't include bottom and right edges */
+ if ( IntGetGraphicsMode(dc) == GM_COMPATIBLE )
+ {
+ corners[1].x--;
+ corners[1].y--;
+ }
- worker.l = dwNew;
- worker1.f = pDc->DcLevel.laPath.eMiterLimit;
- pDc->DcLevel.laPath.eMiterLimit = worker.f;
+ /* Close any previous figure */
+ IntGdiCloseFigure(pPath);
- if (pdwOut)
+ /* Add four points to the path */
+ pointTemp.x=corners[1].x;
+ pointTemp.y=corners[0].y;
+ if ( !PATH_AddEntry(pPath, &pointTemp, PT_MOVETO) )
{
- _SEH_TRY
- {
- ProbeForWrite(pdwOut,
- sizeof(DWORD),
- 1);
- *pdwOut = worker1.l;
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
- if (!NT_SUCCESS(Status))
- {
- SetLastNtError(Status);
- DC_UnlockDc(pDc);
- return FALSE;
- }
+ PATH_UnlockPath( pPath );
+ return FALSE;
+ }
+ if ( !PATH_AddEntry(pPath, corners, PT_LINETO) )
+ {
+ PATH_UnlockPath( pPath );
+ return FALSE;
+ }
+ pointTemp.x=corners[0].x;
+ pointTemp.y=corners[1].y;
+ if ( !PATH_AddEntry(pPath, &pointTemp, PT_LINETO) )
+ {
+ PATH_UnlockPath( pPath );
+ return FALSE;
+ }
+ if ( !PATH_AddEntry(pPath, corners+1, PT_LINETO) )
+ {
+ PATH_UnlockPath( pPath );
+ return FALSE;
}
- DC_UnlockDc(pDc);
+ /* Close the rectangle figure */
+ IntGdiCloseFigure(pPath) ;
+ PATH_UnlockPath( pPath );
return TRUE;
}
-BOOL
-STDCALL
-NtGdiStrokeAndFillPath(HDC hDC)
+/* PATH_RoundRect
+ *
+ * Should be called when a call to RoundRect is performed on a DC that has
+ * an open path. Returns TRUE if successful, else FALSE.
+ *
+ * FIXME: it adds the same entries to the path as windows does, but there
+ * is an error in the bezier drawing code so that there are small pixel-size
+ * gaps when the resulting path is drawn by StrokePath()
+ */
+BOOL FASTCALL PATH_RoundRect(DC *dc, INT x1, INT y1, INT x2, INT y2, INT ell_width, INT ell_height)
{
- DC *pDc;
- BOOL bRet = FALSE;
+ PPATH pPath;
+ POINT corners[2], pointTemp;
+ FLOAT_POINT ellCorners[2];
- DPRINT("Enter %s\n", __FUNCTION__);
+ pPath = PATH_LockPath( dc->DcLevel.hPath );
+ if (!pPath) return FALSE;
- if(!(pDc = DC_LockDc(hDC))) return FALSE;
+ /* Check that path is open */
+ if(pPath->state!=PATH_Open)
+ {
+ PATH_UnlockPath( pPath );
+ return FALSE;
+ }
- bRet = PATH_FillPath(pDc, &pDc->w.path);
- if(bRet) bRet = PATH_StrokePath(pDc, &pDc->w.path);
- if(bRet) PATH_EmptyPath(&pDc->w.path);
+ if(!PATH_CheckCorners(dc,corners,x1,y1,x2,y2))
+ {
+ PATH_UnlockPath( pPath );
+ return FALSE;
+ }
- DC_UnlockDc(pDc);
- return bRet;
+ /* Add points to the roundrect path */
+ ellCorners[0].x = corners[1].x-ell_width;
+ ellCorners[0].y = corners[0].y;
+ ellCorners[1].x = corners[1].x;
+ ellCorners[1].y = corners[0].y+ell_height;
+ if(!PATH_DoArcPart(pPath, ellCorners, 0, -M_PI_2, PT_MOVETO))
+ {
+ PATH_UnlockPath( pPath );
+ return FALSE;
+ }
+ pointTemp.x = corners[0].x+ell_width/2;
+ pointTemp.y = corners[0].y;
+ if(!PATH_AddEntry(pPath, &pointTemp, PT_LINETO))
+ {
+ PATH_UnlockPath( pPath );
+ return FALSE;
+ }
+ ellCorners[0].x = corners[0].x;
+ ellCorners[1].x = corners[0].x+ell_width;
+ if(!PATH_DoArcPart(pPath, ellCorners, -M_PI_2, -M_PI, FALSE))
+ {
+ PATH_UnlockPath( pPath );
+ return FALSE;
+ }
+ pointTemp.x = corners[0].x;
+ pointTemp.y = corners[1].y-ell_height/2;
+ if(!PATH_AddEntry(pPath, &pointTemp, PT_LINETO))
+ {
+ PATH_UnlockPath( pPath );
+ return FALSE;
+ }
+ ellCorners[0].y = corners[1].y-ell_height;
+ ellCorners[1].y = corners[1].y;
+ if(!PATH_DoArcPart(pPath, ellCorners, M_PI, M_PI_2, FALSE))
+ {
+ PATH_UnlockPath( pPath );
+ return FALSE;
+ }
+ pointTemp.x = corners[1].x-ell_width/2;
+ pointTemp.y = corners[1].y;
+ if(!PATH_AddEntry(pPath, &pointTemp, PT_LINETO))
+ {
+ PATH_UnlockPath( pPath );
+ return FALSE;
+ }
+ ellCorners[0].x = corners[1].x-ell_width;
+ ellCorners[1].x = corners[1].x;
+ if(!PATH_DoArcPart(pPath, ellCorners, M_PI_2, 0, FALSE))
+ {
+ PATH_UnlockPath( pPath );
+ return FALSE;
+ }
+
+ IntGdiCloseFigure(pPath);
+ PATH_UnlockPath( pPath );
+ return TRUE;
}
+/* PATH_Ellipse
+ *
+ * Should be called when a call to Ellipse is performed on a DC that has
+ * an open path. This adds four Bezier splines representing the ellipse
+ * to the path. Returns TRUE if successful, else FALSE.
+ */
BOOL
-STDCALL
-NtGdiStrokePath(HDC hDC)
+FASTCALL
+PATH_Ellipse ( PDC dc, INT x1, INT y1, INT x2, INT y2 )
{
- DC *pDc;
- BOOL bRet = FALSE;
-
- DPRINT("Enter %s\n", __FUNCTION__);
-
- if(!(pDc = DC_LockDc(hDC))) return FALSE;
-
- bRet = PATH_StrokePath(pDc, &pDc->w.path);
- PATH_EmptyPath(&pDc->w.path);
-
- DC_UnlockDc(pDc);
- return bRet;
+ PPATH pPath;
+ /* TODO: This should probably be revised to call PATH_AngleArc */
+ /* (once it exists) */
+ BOOL Ret = PATH_Arc ( dc, x1, y1, x2, y2, x1, (y1+y2)/2, x1, (y1+y2)/2, GdiTypeArc );
+ if (Ret)
+ {
+ pPath = PATH_LockPath( dc->DcLevel.hPath );
+ if (!pPath) return FALSE;
+ IntGdiCloseFigure(pPath);
+ PATH_UnlockPath( pPath );
+ }
+ return Ret;
}
+/* PATH_Arc
+ *
+ * Should be called when a call to Arc is performed on a DC that has
+ * an open path. This adds up to five Bezier splines representing the arc
+ * to the path. When 'lines' is 1, we add 1 extra line to get a chord,
+ * when 'lines' is 2, we add 2 extra lines to get a pie, and when 'lines' is
+ * -1 we add 1 extra line from the current DC position to the starting position
+ * of the arc before drawing the arc itself (arcto). Returns TRUE if successful,
+ * else FALSE.
+ */
BOOL
-STDCALL
-NtGdiWidenPath(HDC hDC)
+FASTCALL
+PATH_Arc ( PDC dc, INT x1, INT y1, INT x2, INT y2,
+ INT xStart, INT yStart, INT xEnd, INT yEnd, INT lines)
{
- UNIMPLEMENTED;
- return FALSE;
-}
+ double angleStart, angleEnd, angleStartQuadrant, angleEndQuadrant=0.0;
+ /* Initialize angleEndQuadrant to silence gcc's warning */
+ double x, y;
+ FLOAT_POINT corners[2], pointStart, pointEnd;
+ POINT centre, pointCurPos;
+ BOOL start, end, Ret = TRUE;
+ INT temp;
+ BOOL clockwise;
+ PPATH pPath;
-BOOL STDCALL NtGdiSelectClipPath(HDC hDC,
- int Mode)
-{
- HRGN hrgnPath;
- BOOL success = FALSE;
- PDC dc = DC_LockDc ( hDC );
- PDC_ATTR Dc_Attr;
-
- if( !dc ) return FALSE;
- Dc_Attr = dc->pDc_Attr;
- if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
- /* Check that path is closed */
- if( dc->w.path.state != PATH_Closed )
- {
- SetLastWin32Error(ERROR_CAN_NOT_COMPLETE);
- return FALSE;
- }
- /* Construct a region from the path */
- else if( PATH_PathToRegion( &dc->w.path, Dc_Attr->jFillMode, &hrgnPath ) )
- {
- success = GdiExtSelectClipRgn( dc, hrgnPath, Mode ) != ERROR;
- NtGdiDeleteObject( hrgnPath );
-
- /* Empty the path */
- if( success )
- PATH_EmptyPath( &dc->w.path);
- /* FIXME: Should this function delete the path even if it failed? */
- }
+ /* FIXME: This function should check for all possible error returns */
+ /* FIXME: Do we have to respect newStroke? */
- DC_UnlockDc ( dc );
- return success;
-}
+ ASSERT ( dc );
-/***********************************************************************
- * Exported functions
- */
+ pPath = PATH_LockPath( dc->DcLevel.hPath );
+ if (!pPath) return FALSE;
+ clockwise = ((dc->DcLevel.flPath & DCPATH_CLOCKWISE) != 0);
-/* PATH_FillPath
- *
- *
- */
-BOOL
-FASTCALL
-PATH_FillPath( PDC dc, GdiPath *pPath )
-{
- INT mapMode, graphicsMode;
- SIZE ptViewportExt, ptWindowExt;
- POINTL ptViewportOrg, ptWindowOrg;
- XFORM xform;
- HRGN hrgn;
- PDC_ATTR Dc_Attr = dc->pDc_Attr;
+ /* Check that path is open */
+ if ( pPath->state != PATH_Open )
+ {
+ Ret = FALSE;
+ goto ArcExit;
+ }
- if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
+ /* Check for zero height / width */
+ /* FIXME: Only in GM_COMPATIBLE? */
+ if ( x1==x2 || y1==y2 )
+ {
+ Ret = TRUE;
+ goto ArcExit;
+ }
+ /* Convert points to device coordinates */
+ corners[0].x=(FLOAT)x1;
+ corners[0].y=(FLOAT)y1;
+ corners[1].x=(FLOAT)x2;
+ corners[1].y=(FLOAT)y2;
+ pointStart.x=(FLOAT)xStart;
+ pointStart.y=(FLOAT)yStart;
+ pointEnd.x=(FLOAT)xEnd;
+ pointEnd.y=(FLOAT)yEnd;
+ INTERNAL_LPTODP_FLOAT(dc, corners);
+ INTERNAL_LPTODP_FLOAT(dc, corners+1);
+ INTERNAL_LPTODP_FLOAT(dc, &pointStart);
+ INTERNAL_LPTODP_FLOAT(dc, &pointEnd);
- if( pPath->state != PATH_Closed )
+ /* Make sure first corner is top left and second corner is bottom right */
+ if ( corners[0].x > corners[1].x )
{
- SetLastWin32Error(ERROR_CAN_NOT_COMPLETE);
- return FALSE;
+ temp=corners[0].x;
+ corners[0].x=corners[1].x;
+ corners[1].x=temp;
+ }
+ if ( corners[0].y > corners[1].y )
+ {
+ temp=corners[0].y;
+ corners[0].y=corners[1].y;
+ corners[1].y=temp;
}
- if( PATH_PathToRegion( pPath, Dc_Attr->jFillMode, &hrgn ))
+ /* Compute start and end angle */
+ PATH_NormalizePoint(corners, &pointStart, &x, &y);
+ angleStart=atan2(y, x);
+ PATH_NormalizePoint(corners, &pointEnd, &x, &y);
+ angleEnd=atan2(y, x);
+
+ /* Make sure the end angle is "on the right side" of the start angle */
+ if ( clockwise )
{
- /* Since PaintRgn interprets the region as being in logical coordinates
- * but the points we store for the path are already in device
- * coordinates, we have to set the mapping mode to MM_TEXT temporarily.
- * Using SaveDC to save information about the mapping mode / world
- * transform would be easier but would require more overhead, especially
- * now that SaveDC saves the current path.
- */
+ if ( angleEnd <= angleStart )
+ {
+ angleEnd+=2*M_PI;
+ ASSERT(angleEnd>=angleStart);
+ }
+ }
+ else
+ {
+ if(angleEnd>=angleStart)
+ {
+ angleEnd-=2*M_PI;
+ ASSERT(angleEnd<=angleStart);
+ }
+ }
- /* Save the information about the old mapping mode */
- mapMode = Dc_Attr->iMapMode;
- ptViewportExt = Dc_Attr->szlViewportExt;
- ptViewportOrg = Dc_Attr->ptlViewportOrg;
- ptWindowExt = Dc_Attr->szlWindowExt;
- ptWindowOrg = Dc_Attr->ptlWindowOrg;
+ /* In GM_COMPATIBLE, don't include bottom and right edges */
+ if ( IntGetGraphicsMode(dc) == GM_COMPATIBLE )
+ {
+ corners[1].x--;
+ corners[1].y--;
+ }
- /* Save world transform
- * NB: The Windows documentation on world transforms would lead one to
- * believe that this has to be done only in GM_ADVANCED; however, my
- * tests show that resetting the graphics mode to GM_COMPATIBLE does
- * not reset the world transform.
- */
- xform = dc->DcLevel.xformWorld2Wnd;
+ /* arcto: Add a PT_MOVETO only if this is the first entry in a stroke */
+ if(lines==GdiTypeArcTo && pPath->newStroke) // -1
+ {
+ pPath->newStroke=FALSE;
+ IntGetCurrentPositionEx ( dc, &pointCurPos );
+ CoordLPtoDP(dc, &pointCurPos);
+ if(!PATH_AddEntry(pPath, &pointCurPos, PT_MOVETO))
+ {
+ Ret = FALSE;
+ goto ArcExit;
+ }
+ }
- /* Set MM_TEXT */
- IntGdiSetMapMode( dc, MM_TEXT );
- Dc_Attr->ptlViewportOrg.x = 0;
- Dc_Attr->ptlViewportOrg.y = 0;
- Dc_Attr->ptlWindowOrg.x = 0;
- Dc_Attr->ptlWindowOrg.y = 0;
+ /* Add the arc to the path with one Bezier spline per quadrant that the
+ * arc spans */
+ start=TRUE;
+ end=FALSE;
+ do
+ {
+ /* Determine the start and end angles for this quadrant */
+ if(start)
+ {
+ angleStartQuadrant=angleStart;
+ if ( clockwise )
+ angleEndQuadrant=(floor(angleStart/M_PI_2)+1.0)*M_PI_2;
+ else
+ angleEndQuadrant=(ceil(angleStart/M_PI_2)-1.0)*M_PI_2;
+ }
+ else
+ {
+ angleStartQuadrant=angleEndQuadrant;
+ if ( clockwise )
+ angleEndQuadrant+=M_PI_2;
+ else
+ angleEndQuadrant-=M_PI_2;
+ }
- graphicsMode = Dc_Attr->iGraphicsMode;
- Dc_Attr->iGraphicsMode = GM_ADVANCED;
- IntGdiModifyWorldTransform( dc, &xform, MWT_IDENTITY );
- Dc_Attr->iGraphicsMode = graphicsMode;
+ /* Have we reached the last part of the arc? */
+ if ( (clockwise && angleEnd<angleEndQuadrant)
+ || (!clockwise && angleEnd>angleEndQuadrant)
+ )
+ {
+ /* Adjust the end angle for this quadrant */
+ angleEndQuadrant = angleEnd;
+ end = TRUE;
+ }
- /* Paint the region */
- IntGdiPaintRgn( dc, hrgn );
- NtGdiDeleteObject( hrgn );
- /* Restore the old mapping mode */
- IntGdiSetMapMode( dc, mapMode );
- Dc_Attr->szlViewportExt = ptViewportExt;
- Dc_Attr->ptlViewportOrg = ptViewportOrg;
- Dc_Attr->szlWindowExt = ptWindowExt;
- Dc_Attr->ptlWindowOrg = ptWindowOrg;
+ /* Add the Bezier spline to the path */
+ PATH_DoArcPart ( pPath, corners, angleStartQuadrant, angleEndQuadrant,
+ start ? (lines==GdiTypeArcTo ? PT_LINETO : PT_MOVETO) : FALSE ); // -1
+ start = FALSE;
+ } while(!end);
- /* Go to GM_ADVANCED temporarily to restore the world transform */
- graphicsMode = Dc_Attr->iGraphicsMode;
- Dc_Attr->iGraphicsMode = GM_ADVANCED;
- IntGdiModifyWorldTransform( dc, &xform, MWT_MAX+1 );
- Dc_Attr->iGraphicsMode = graphicsMode;
- return TRUE;
+ /* chord: close figure. pie: add line and close figure */
+ if (lines==GdiTypeChord) // 1
+ {
+ IntGdiCloseFigure(pPath);
}
- return FALSE;
+ else if (lines==GdiTypePie) // 2
+ {
+ centre.x = (corners[0].x+corners[1].x)/2;
+ centre.y = (corners[0].y+corners[1].y)/2;
+ if(!PATH_AddEntry(pPath, ¢re, PT_LINETO | PT_CLOSEFIGURE))
+ Ret = FALSE;
+ }
+ArcExit:
+ PATH_UnlockPath( pPath );
+ return Ret;
}
-/* PATH_InitGdiPath
- *
- * Initializes the GdiPath structure.
- */
-VOID
+BOOL
FASTCALL
-PATH_InitGdiPath ( GdiPath *pPath )
+PATH_PolyBezierTo ( PDC dc, const POINT *pts, DWORD cbPoints )
{
- ASSERT(pPath!=NULL);
+ POINT pt;
+ ULONG i;
+ PPATH pPath;
- pPath->state=PATH_Null;
- pPath->pPoints=NULL;
- pPath->pFlags=NULL;
- pPath->numEntriesUsed=0;
- pPath->numEntriesAllocated=0;
-}
+ ASSERT ( dc );
+ ASSERT ( pts );
+ ASSERT ( cbPoints );
-/* PATH_DestroyGdiPath
- *
- * Destroys a GdiPath structure (frees the memory in the arrays).
- */
-VOID
-FASTCALL
-PATH_DestroyGdiPath ( GdiPath *pPath )
-{
- ASSERT(pPath!=NULL);
+ pPath = PATH_LockPath( dc->DcLevel.hPath );
+ if (!pPath) return FALSE;
+
+ /* Check that path is open */
+ if ( pPath->state != PATH_Open )
+ {
+ PATH_UnlockPath( pPath );
+ return FALSE;
+ }
- if (pPath->pPoints) ExFreePool(pPath->pPoints);
- if (pPath->pFlags) ExFreePool(pPath->pFlags);
+ /* Add a PT_MOVETO if necessary */
+ if ( pPath->newStroke )
+ {
+ pPath->newStroke=FALSE;
+ IntGetCurrentPositionEx ( dc, &pt );
+ CoordLPtoDP ( dc, &pt );
+ if ( !PATH_AddEntry(pPath, &pt, PT_MOVETO) )
+ {
+ PATH_UnlockPath( pPath );
+ return FALSE;
+ }
+ }
+
+ for(i = 0; i < cbPoints; i++)
+ {
+ pt = pts[i];
+ CoordLPtoDP ( dc, &pt );
+ PATH_AddEntry(pPath, &pt, PT_BEZIERTO);
+ }
+ PATH_UnlockPath( pPath );
+ return TRUE;
}
-/* PATH_AssignGdiPath
- *
- * Copies the GdiPath structure "pPathSrc" to "pPathDest". A deep copy is
- * performed, i.e. the contents of the pPoints and pFlags arrays are copied,
- * not just the pointers. Since this means that the arrays in pPathDest may
- * need to be resized, pPathDest should have been initialized using
- * PATH_InitGdiPath (in C++, this function would be an assignment operator,
- * not a copy constructor).
- * Returns TRUE if successful, else FALSE.
- */
BOOL
FASTCALL
-PATH_AssignGdiPath ( GdiPath *pPathDest, const GdiPath *pPathSrc )
+PATH_PolyBezier ( PDC dc, const POINT *pts, DWORD cbPoints )
{
- ASSERT(pPathDest!=NULL && pPathSrc!=NULL);
+ POINT pt;
+ ULONG i;
+ PPATH pPath;
- /* Make sure destination arrays are big enough */
- if ( !PATH_ReserveEntries(pPathDest, pPathSrc->numEntriesUsed) )
- return FALSE;
+ ASSERT ( dc );
+ ASSERT ( pts );
+ ASSERT ( cbPoints );
- /* Perform the copy operation */
- memcpy(pPathDest->pPoints, pPathSrc->pPoints,
- sizeof(POINT)*pPathSrc->numEntriesUsed);
- memcpy(pPathDest->pFlags, pPathSrc->pFlags,
- sizeof(BYTE)*pPathSrc->numEntriesUsed);
+ pPath = PATH_LockPath( dc->DcLevel.hPath );
+ if (!pPath) return FALSE;
- pPathDest->state=pPathSrc->state;
- pPathDest->numEntriesUsed=pPathSrc->numEntriesUsed;
- pPathDest->newStroke=pPathSrc->newStroke;
+ /* Check that path is open */
+ if ( pPath->state != PATH_Open )
+ {
+ PATH_UnlockPath( pPath );
+ return FALSE;
+ }
+ for ( i = 0; i < cbPoints; i++ )
+ {
+ pt = pts[i];
+ CoordLPtoDP ( dc, &pt );
+ PATH_AddEntry ( pPath, &pt, (i == 0) ? PT_MOVETO : PT_BEZIERTO );
+ }
+ PATH_UnlockPath( pPath );
return TRUE;
}
-/* PATH_MoveTo
- *
- * Should be called when a MoveTo is performed on a DC that has an
- * open path. This starts a new stroke. Returns TRUE if successful, else
- * FALSE.
- */
BOOL
FASTCALL
-PATH_MoveTo ( PDC dc )
+PATH_Polyline ( PDC dc, const POINT *pts, DWORD cbPoints )
{
+ POINT pt;
+ ULONG i;
+ PPATH pPath;
- /* Check that path is open */
- if ( dc->w.path.state != PATH_Open )
- /* FIXME: Do we have to call SetLastError? */
- return FALSE;
+ ASSERT ( dc );
+ ASSERT ( pts );
+ ASSERT ( cbPoints );
- /* Start a new stroke */
- dc->w.path.newStroke = TRUE;
+ pPath = PATH_LockPath( dc->DcLevel.hPath );
+ if (!pPath) return FALSE;
+ /* Check that path is open */
+ if ( pPath->state != PATH_Open )
+ {
+ PATH_UnlockPath( pPath );
+ return FALSE;
+ }
+ for ( i = 0; i < cbPoints; i++ )
+ {
+ pt = pts[i];
+ CoordLPtoDP ( dc, &pt );
+ PATH_AddEntry(pPath, &pt, (i == 0) ? PT_MOVETO : PT_LINETO);
+ }
+ PATH_UnlockPath( pPath );
return TRUE;
}
-/* PATH_LineTo
- *
- * Should be called when a LineTo is performed on a DC that has an
- * open path. This adds a PT_LINETO entry to the path (and possibly
- * a PT_MOVETO entry, if this is the first LineTo in a stroke).
- * Returns TRUE if successful, else FALSE.
- */
BOOL
FASTCALL
-PATH_LineTo ( PDC dc, INT x, INT y )
+PATH_PolylineTo ( PDC dc, const POINT *pts, DWORD cbPoints )
{
- POINT point, pointCurPos;
+ POINT pt;
+ ULONG i;
+ PPATH pPath;
+
+ ASSERT ( dc );
+ ASSERT ( pts );
+ ASSERT ( cbPoints );
+ pPath = PATH_LockPath( dc->DcLevel.hPath );
+ if (!pPath) return FALSE;
+
/* Check that path is open */
- if ( dc->w.path.state != PATH_Open )
+ if ( pPath->state != PATH_Open )
+ {
+ PATH_UnlockPath( pPath );
return FALSE;
-
- /* Convert point to device coordinates */
- point.x=x;
- point.y=y;
- CoordLPtoDP ( dc, &point );
+ }
/* Add a PT_MOVETO if necessary */
- if ( dc->w.path.newStroke )
+ if ( pPath->newStroke )
{
- dc->w.path.newStroke = FALSE;
- IntGetCurrentPositionEx ( dc, &pointCurPos );
- CoordLPtoDP ( dc, &pointCurPos );
- if ( !PATH_AddEntry(&dc->w.path, &pointCurPos, PT_MOVETO) )
+ pPath->newStroke = FALSE;
+ IntGetCurrentPositionEx ( dc, &pt );
+ CoordLPtoDP ( dc, &pt );
+ if ( !PATH_AddEntry(pPath, &pt, PT_MOVETO) )
+ {
+ PATH_UnlockPath( pPath );
return FALSE;
+ }
}
- /* Add a PT_LINETO entry */
- return PATH_AddEntry(&dc->w.path, &point, PT_LINETO);
+ for(i = 0; i < cbPoints; i++)
+ {
+ pt = pts[i];
+ CoordLPtoDP ( dc, &pt );
+ PATH_AddEntry(pPath, &pt, PT_LINETO);
+ }
+ PATH_UnlockPath( pPath );
+ return TRUE;
}
-/* PATH_Rectangle
- *
- * Should be called when a call to Rectangle is performed on a DC that has
- * an open path. Returns TRUE if successful, else FALSE.
- */
+
BOOL
FASTCALL
-PATH_Rectangle ( PDC dc, INT x1, INT y1, INT x2, INT y2 )
+PATH_Polygon ( PDC dc, const POINT *pts, DWORD cbPoints )
{
- POINT corners[2], pointTemp;
- INT temp;
+ POINT pt;
+ ULONG i;
+ PPATH pPath;
- /* Check that path is open */
- if ( dc->w.path.state != PATH_Open )
- return FALSE;
+ ASSERT ( dc );
+ ASSERT ( pts );
- /* Convert points to device coordinates */
- corners[0].x=x1;
- corners[0].y=y1;
- corners[1].x=x2;
- corners[1].y=y2;
- IntLPtoDP ( dc, corners, 2 );
+ pPath = PATH_LockPath( dc->DcLevel.hPath );
+ if (!pPath) return FALSE;
- /* Make sure first corner is top left and second corner is bottom right */
- if ( corners[0].x > corners[1].x )
- {
- temp=corners[0].x;
- corners[0].x=corners[1].x;
- corners[1].x=temp;
- }
- if ( corners[0].y > corners[1].y )
+ /* Check that path is open */
+ if ( pPath->state != PATH_Open )
{
- temp=corners[0].y;
- corners[0].y=corners[1].y;
- corners[1].y=temp;
+ PATH_UnlockPath( pPath );
+ return FALSE;
}
- /* In GM_COMPATIBLE, don't include bottom and right edges */
- if ( IntGetGraphicsMode(dc) == GM_COMPATIBLE )
+ for(i = 0; i < cbPoints; i++)
{
- corners[1].x--;
- corners[1].y--;
+ pt = pts[i];
+ CoordLPtoDP ( dc, &pt );
+ PATH_AddEntry(pPath, &pt, (i == 0) ? PT_MOVETO :
+ ((i == cbPoints-1) ? PT_LINETO | PT_CLOSEFIGURE :
+ PT_LINETO));
}
+ PATH_UnlockPath( pPath );
+ return TRUE;
+}
- /* Close any previous figure */
- IntGdiCloseFigure(dc);
+BOOL
+FASTCALL
+PATH_PolyPolygon ( PDC dc, const POINT* pts, const INT* counts, UINT polygons )
+{
+ POINT pt, startpt;
+ ULONG poly, point, i;
+ PPATH pPath;
- /* Add four points to the path */
- pointTemp.x=corners[1].x;
- pointTemp.y=corners[0].y;
- if ( !PATH_AddEntry(&dc->w.path, &pointTemp, PT_MOVETO) )
- return FALSE;
- if ( !PATH_AddEntry(&dc->w.path, corners, PT_LINETO) )
- return FALSE;
- pointTemp.x=corners[0].x;
- pointTemp.y=corners[1].y;
- if ( !PATH_AddEntry(&dc->w.path, &pointTemp, PT_LINETO) )
- return FALSE;
- if ( !PATH_AddEntry(&dc->w.path, corners+1, PT_LINETO) )
- return FALSE;
+ ASSERT ( dc );
+ ASSERT ( pts );
+ ASSERT ( counts );
+ ASSERT ( polygons );
- /* Close the rectangle figure */
- IntGdiCloseFigure(dc) ;
+ pPath = PATH_LockPath( dc->DcLevel.hPath );
+ if (!pPath) return FALSE;
+
+ /* Check that path is open */
+ if ( pPath->state != PATH_Open )
+ {
+ PATH_UnlockPath( pPath );
+ return FALSE;
+ }
+ for(i = 0, poly = 0; poly < polygons; poly++)
+ {
+ for(point = 0; point < (ULONG) counts[poly]; point++, i++)
+ {
+ pt = pts[i];
+ CoordLPtoDP ( dc, &pt );
+ if(point == 0) startpt = pt;
+ PATH_AddEntry(pPath, &pt, (point == 0) ? PT_MOVETO : PT_LINETO);
+ }
+ /* win98 adds an extra line to close the figure for some reason */
+ PATH_AddEntry(pPath, &startpt, PT_LINETO | PT_CLOSEFIGURE);
+ }
+ PATH_UnlockPath( pPath );
return TRUE;
}
-/* PATH_RoundRect
- *
- * Should be called when a call to RoundRect is performed on a DC that has
- * an open path. Returns TRUE if successful, else FALSE.
- *
- * FIXME: it adds the same entries to the path as windows does, but there
- * is an error in the bezier drawing code so that there are small pixel-size
- * gaps when the resulting path is drawn by StrokePath()
- */
-BOOL FASTCALL PATH_RoundRect(DC *dc, INT x1, INT y1, INT x2, INT y2, INT ell_width, INT ell_height)
+BOOL
+FASTCALL
+PATH_PolyPolyline ( PDC dc, const POINT* pts, const DWORD* counts, DWORD polylines )
{
- GdiPath *pPath = &dc->w.path;
- POINT corners[2], pointTemp;
- FLOAT_POINT ellCorners[2];
-
- /* Check that path is open */
- if(pPath->state!=PATH_Open)
- return FALSE;
+ POINT pt;
+ ULONG poly, point, i;
+ PPATH pPath;
- if(!PATH_CheckCorners(dc,corners,x1,y1,x2,y2))
- return FALSE;
+ ASSERT ( dc );
+ ASSERT ( pts );
+ ASSERT ( counts );
+ ASSERT ( polylines );
- /* Add points to the roundrect path */
- ellCorners[0].x = corners[1].x-ell_width;
- ellCorners[0].y = corners[0].y;
- ellCorners[1].x = corners[1].x;
- ellCorners[1].y = corners[0].y+ell_height;
- if(!PATH_DoArcPart(pPath, ellCorners, 0, -M_PI_2, TRUE))
- return FALSE;
- pointTemp.x = corners[0].x+ell_width/2;
- pointTemp.y = corners[0].y;
- if(!PATH_AddEntry(pPath, &pointTemp, PT_LINETO))
- return FALSE;
- ellCorners[0].x = corners[0].x;
- ellCorners[1].x = corners[0].x+ell_width;
- if(!PATH_DoArcPart(pPath, ellCorners, -M_PI_2, -M_PI, FALSE))
- return FALSE;
- pointTemp.x = corners[0].x;
- pointTemp.y = corners[1].y-ell_height/2;
- if(!PATH_AddEntry(pPath, &pointTemp, PT_LINETO))
- return FALSE;
- ellCorners[0].y = corners[1].y-ell_height;
- ellCorners[1].y = corners[1].y;
- if(!PATH_DoArcPart(pPath, ellCorners, M_PI, M_PI_2, FALSE))
- return FALSE;
- pointTemp.x = corners[1].x-ell_width/2;
- pointTemp.y = corners[1].y;
- if(!PATH_AddEntry(pPath, &pointTemp, PT_LINETO))
- return FALSE;
- ellCorners[0].x = corners[1].x-ell_width;
- ellCorners[1].x = corners[1].x;
- if(!PATH_DoArcPart(pPath, ellCorners, M_PI_2, 0, FALSE))
- return FALSE;
+ pPath = PATH_LockPath( dc->DcLevel.hPath );
+ if (!pPath) return FALSE;
- IntGdiCloseFigure(dc);
+ /* Check that path is open */
+ if ( pPath->state != PATH_Open )
+ {
+ PATH_UnlockPath( pPath );
+ return FALSE;
+ }
- return TRUE;
+ for(i = 0, poly = 0; poly < polylines; poly++)
+ {
+ for(point = 0; point < counts[poly]; point++, i++)
+ {
+ pt = pts[i];
+ CoordLPtoDP ( dc, &pt );
+ PATH_AddEntry(pPath, &pt, (point == 0) ? PT_MOVETO : PT_LINETO);
+ }
+ }
+ PATH_UnlockPath( pPath );
+ return TRUE;
}
-/* PATH_Ellipse
+
+/* PATH_CheckCorners
*
- * Should be called when a call to Ellipse is performed on a DC that has
- * an open path. This adds four Bezier splines representing the ellipse
- * to the path. Returns TRUE if successful, else FALSE.
+ * Helper function for PATH_RoundRect() and PATH_Rectangle()
*/
-BOOL
-FASTCALL
-PATH_Ellipse ( PDC dc, INT x1, INT y1, INT x2, INT y2 )
+BOOL PATH_CheckCorners(DC *dc, POINT corners[], INT x1, INT y1, INT x2, INT y2)
{
- /* TODO: This should probably be revised to call PATH_AngleArc */
- /* (once it exists) */
- BOOL Ret = PATH_Arc ( dc, x1, y1, x2, y2, x1, (y1+y2)/2, x1, (y1+y2)/2, GdiTypeArc );
- if (Ret) IntGdiCloseFigure(dc);
- return Ret;
+ INT temp;
+ PDC_ATTR Dc_Attr = dc->pDc_Attr;
+ if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
+
+ /* Convert points to device coordinates */
+ corners[0].x=x1;
+ corners[0].y=y1;
+ corners[1].x=x2;
+ corners[1].y=y2;
+ CoordLPtoDP(dc, &corners[0]);
+ CoordLPtoDP(dc, &corners[1]);
+
+ /* Make sure first corner is top left and second corner is bottom right */
+ if(corners[0].x>corners[1].x)
+ {
+ temp=corners[0].x;
+ corners[0].x=corners[1].x;
+ corners[1].x=temp;
+ }
+ if(corners[0].y>corners[1].y)
+ {
+ temp=corners[0].y;
+ corners[0].y=corners[1].y;
+ corners[1].y=temp;
+ }
+
+ /* In GM_COMPATIBLE, don't include bottom and right edges */
+ if(Dc_Attr->iGraphicsMode==GM_COMPATIBLE)
+ {
+ corners[1].x--;
+ corners[1].y--;
+ }
+
+ return TRUE;
}
-/* PATH_Arc
+
+/* PATH_AddFlatBezier
*
- * Should be called when a call to Arc is performed on a DC that has
- * an open path. This adds up to five Bezier splines representing the arc
- * to the path. When 'lines' is 1, we add 1 extra line to get a chord,
- * and when 'lines' is 2, we add 2 extra lines to get a pie.
- * Returns TRUE if successful, else FALSE.
*/
BOOL
FASTCALL
-PATH_Arc ( PDC dc, INT x1, INT y1, INT x2, INT y2,
- INT xStart, INT yStart, INT xEnd, INT yEnd, INT lines)
+PATH_AddFlatBezier ( PPATH pPath, POINT *pt, BOOL closed )
{
- double angleStart, angleEnd, angleStartQuadrant, angleEndQuadrant=0.0;
- /* Initialize angleEndQuadrant to silence gcc's warning */
- double x, y;
- FLOAT_POINT corners[2], pointStart, pointEnd;
- POINT centre;
- BOOL start, end;
- INT temp;
- BOOL clockwise;
+ POINT *pts;
+ INT no, i;
- /* FIXME: This function should check for all possible error returns */
- /* FIXME: Do we have to respect newStroke? */
+ pts = GDI_Bezier( pt, 4, &no );
+ if ( !pts ) return FALSE;
- ASSERT ( dc );
+ for(i = 1; i < no; i++)
+ PATH_AddEntry(pPath, &pts[i], (i == no-1 && closed) ? PT_LINETO | PT_CLOSEFIGURE : PT_LINETO);
- clockwise = ((dc->DcLevel.flPath & DCPATH_CLOCKWISE) != 0);
+ ExFreePool(pts);
+ return TRUE;
+}
- /* Check that path is open */
- if ( dc->w.path.state != PATH_Open )
- return FALSE;
+/* PATH_FlattenPath
+ *
+ * Replaces Beziers with line segments
+ *
+ */
+BOOL
+FASTCALL
+PATH_FlattenPath(PPATH pPath)
+{
+ PATH newPath;
+ INT srcpt;
- /* FIXME: Do we have to close the current figure? */
+ RtlZeroMemory(&newPath, sizeof(newPath));
+ newPath.state = PATH_Open;
+ for(srcpt = 0; srcpt < pPath->numEntriesUsed; srcpt++) {
+ switch(pPath->pFlags[srcpt] & ~PT_CLOSEFIGURE) {
+ case PT_MOVETO:
+ case PT_LINETO:
+ PATH_AddEntry(&newPath, &pPath->pPoints[srcpt], pPath->pFlags[srcpt]);
+ break;
+ case PT_BEZIERTO:
+ PATH_AddFlatBezier(&newPath, &pPath->pPoints[srcpt-1], pPath->pFlags[srcpt+2] & PT_CLOSEFIGURE);
+ srcpt += 2;
+ break;
+ }
+ }
+ newPath.state = PATH_Closed;
+ PATH_AssignGdiPath(pPath, &newPath);
+ PATH_EmptyPath(&newPath);
+ return TRUE;
+}
- /* Check for zero height / width */
- /* FIXME: Only in GM_COMPATIBLE? */
- if ( x1==x2 || y1==y2 )
- return TRUE;
- /* Convert points to device coordinates */
- corners[0].x=(FLOAT)x1;
- corners[0].y=(FLOAT)y1;
- corners[1].x=(FLOAT)x2;
- corners[1].y=(FLOAT)y2;
- pointStart.x=(FLOAT)xStart;
- pointStart.y=(FLOAT)yStart;
- pointEnd.x=(FLOAT)xEnd;
- pointEnd.y=(FLOAT)yEnd;
- INTERNAL_LPTODP_FLOAT(dc, corners);
- INTERNAL_LPTODP_FLOAT(dc, corners+1);
- INTERNAL_LPTODP_FLOAT(dc, &pointStart);
- INTERNAL_LPTODP_FLOAT(dc, &pointEnd);
+HRGN FASTCALL IntCreatePolyPolygonRgn(POINT *Pts, INT *Count, INT nbpolygons,INT mode);
+/* PATH_PathToRegion
+ *
+ * Creates a region from the specified path using the specified polygon
+ * filling mode. The path is left unchanged. A handle to the region that
+ * was created is stored in *pHrgn. If successful, TRUE is returned; if an
+ * error occurs, SetLastError is called with the appropriate value and
+ * FALSE is returned.
+ */
+BOOL
+FASTCALL
+PATH_PathToRegion ( PPATH pPath, INT nPolyFillMode, HRGN *pHrgn )
+{
+ int numStrokes, iStroke, i;
+ INT *pNumPointsInStroke;
+ HRGN hrgn = 0;
- /* Make sure first corner is top left and second corner is bottom right */
- if ( corners[0].x > corners[1].x )
- {
- temp=corners[0].x;
- corners[0].x=corners[1].x;
- corners[1].x=temp;
- }
- if ( corners[0].y > corners[1].y )
- {
- temp=corners[0].y;
- corners[0].y=corners[1].y;
- corners[1].y=temp;
- }
+ ASSERT(pPath!=NULL);
+ ASSERT(pHrgn!=NULL);
- /* Compute start and end angle */
- PATH_NormalizePoint(corners, &pointStart, &x, &y);
- angleStart=atan2(y, x);
- PATH_NormalizePoint(corners, &pointEnd, &x, &y);
- angleEnd=atan2(y, x);
+ PATH_FlattenPath ( pPath );
- /* Make sure the end angle is "on the right side" of the start angle */
- if ( clockwise )
- {
- if ( angleEnd <= angleStart )
- {
- angleEnd+=2*M_PI;
- ASSERT(angleEnd>=angleStart);
- }
- }
- else
- {
- if(angleEnd>=angleStart)
- {
- angleEnd-=2*M_PI;
- ASSERT(angleEnd<=angleStart);
- }
- }
+ /* FIXME: What happens when number of points is zero? */
- /* In GM_COMPATIBLE, don't include bottom and right edges */
- if ( IntGetGraphicsMode(dc) == GM_COMPATIBLE )
+ /* First pass: Find out how many strokes there are in the path */
+ /* FIXME: We could eliminate this with some bookkeeping in GdiPath */
+ numStrokes=0;
+ for(i=0; i<pPath->numEntriesUsed; i++)
+ if((pPath->pFlags[i] & ~PT_CLOSEFIGURE) == PT_MOVETO)
+ numStrokes++;
+
+ /* Allocate memory for number-of-points-in-stroke array */
+ pNumPointsInStroke=(int *)ExAllocatePoolWithTag(PagedPool, sizeof(int) * numStrokes, TAG_PATH);
+ if(!pNumPointsInStroke)
{
- corners[1].x--;
- corners[1].y--;
+ SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+ return FALSE;
}
- /* Add the arc to the path with one Bezier spline per quadrant that the
- * arc spans */
- start=TRUE;
- end=FALSE;
- do
+ /* Second pass: remember number of points in each polygon */
+ iStroke=-1; /* Will get incremented to 0 at beginning of first stroke */
+ for(i=0; i<pPath->numEntriesUsed; i++)
{
- /* Determine the start and end angles for this quadrant */
- if(start)
- {
- angleStartQuadrant=angleStart;
- if ( clockwise )
- angleEndQuadrant=(floor(angleStart/M_PI_2)+1.0)*M_PI_2;
- else
- angleEndQuadrant=(ceil(angleStart/M_PI_2)-1.0)*M_PI_2;
- }
- else
+ /* Is this the beginning of a new stroke? */
+ if((pPath->pFlags[i] & ~PT_CLOSEFIGURE) == PT_MOVETO)
{
- angleStartQuadrant=angleEndQuadrant;
- if ( clockwise )
- angleEndQuadrant+=M_PI_2;
- else
- angleEndQuadrant-=M_PI_2;
+ iStroke++;
+ pNumPointsInStroke[iStroke]=0;
}
- /* Have we reached the last part of the arc? */
- if ( (clockwise && angleEnd<angleEndQuadrant)
- || (!clockwise && angleEnd>angleEndQuadrant)
- )
- {
- /* Adjust the end angle for this quadrant */
- angleEndQuadrant = angleEnd;
- end = TRUE;
- }
+ pNumPointsInStroke[iStroke]++;
+ }
- /* Add the Bezier spline to the path */
- PATH_DoArcPart ( &dc->w.path, corners, angleStartQuadrant, angleEndQuadrant, start );
- start = FALSE;
- } while(!end);
+ /* Create a region from the strokes */
+ hrgn = IntCreatePolyPolygonRgn( pPath->pPoints,
+ pNumPointsInStroke,
+ numStrokes,
+ nPolyFillMode);
+ if(hrgn==(HRGN)0)
+ {
+ SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+ return FALSE;
+ }
- /* chord: close figure. pie: add line and close figure */
- if(lines==GdiTypeChord) // 1
- {
- IntGdiCloseFigure(dc);
- }
- else if(lines==GdiTypePie) // 2
- {
- centre.x = (corners[0].x+corners[1].x)/2;
- centre.y = (corners[0].y+corners[1].y)/2;
- if(!PATH_AddEntry(&dc->w.path, ¢re, PT_LINETO | PT_CLOSEFIGURE))
- return FALSE;
- }
+ /* Free memory for number-of-points-in-stroke array */
+ ExFreePool(pNumPointsInStroke);
+ /* Success! */
+ *pHrgn=hrgn;
return TRUE;
}
-BOOL
+/* PATH_EmptyPath
+ *
+ * Removes all entries from the path and sets the path state to PATH_Null.
+ */
+VOID
FASTCALL
-PATH_PolyBezierTo ( PDC dc, const POINT *pts, DWORD cbPoints )
+PATH_EmptyPath ( PPATH pPath )
{
- POINT pt;
- ULONG i;
-
- ASSERT ( dc );
- ASSERT ( pts );
- ASSERT ( cbPoints );
+ ASSERT(pPath!=NULL);
- /* Check that path is open */
- if ( dc->w.path.state != PATH_Open )
- return FALSE;
-
- /* Add a PT_MOVETO if necessary */
- if ( dc->w.path.newStroke )
- {
- dc->w.path.newStroke=FALSE;
- IntGetCurrentPositionEx ( dc, &pt );
- CoordLPtoDP ( dc, &pt );
- if ( !PATH_AddEntry(&dc->w.path, &pt, PT_MOVETO) )
- return FALSE;
- }
-
- for(i = 0; i < cbPoints; i++)
- {
- pt = pts[i];
- CoordLPtoDP ( dc, &pt );
- PATH_AddEntry(&dc->w.path, &pt, PT_BEZIERTO);
- }
- return TRUE;
+ pPath->state=PATH_Null;
+ pPath->numEntriesUsed=0;
}
+/* PATH_AddEntry
+ *
+ * Adds an entry to the path. For "flags", pass either PT_MOVETO, PT_LINETO
+ * or PT_BEZIERTO, optionally ORed with PT_CLOSEFIGURE. Returns TRUE if
+ * successful, FALSE otherwise (e.g. if not enough memory was available).
+ */
BOOL
FASTCALL
-PATH_PolyBezier ( PDC dc, const POINT *pts, DWORD cbPoints )
+PATH_AddEntry ( PPATH pPath, const POINT *pPoint, BYTE flags )
{
- POINT pt;
- ULONG i;
+ ASSERT(pPath!=NULL);
- ASSERT ( dc );
- ASSERT ( pts );
- ASSERT ( cbPoints );
+ /* FIXME: If newStroke is true, perhaps we want to check that we're
+ * getting a PT_MOVETO
+ */
- /* Check that path is open */
- if ( dc->w.path.state != PATH_Open )
+ /* Check that path is open */
+ if ( pPath->state != PATH_Open )
return FALSE;
- for ( i = 0; i < cbPoints; i++ )
- {
- pt = pts[i];
- CoordLPtoDP ( dc, &pt );
- PATH_AddEntry ( &dc->w.path, &pt, (i == 0) ? PT_MOVETO : PT_BEZIERTO );
- }
-
- return TRUE;
-}
+ /* Reserve enough memory for an extra path entry */
+ if ( !PATH_ReserveEntries(pPath, pPath->numEntriesUsed+1) )
+ return FALSE;
-BOOL
-FASTCALL
-PATH_Polyline ( PDC dc, const POINT *pts, DWORD cbPoints )
-{
- POINT pt;
- ULONG i;
+ /* Store information in path entry */
+ pPath->pPoints[pPath->numEntriesUsed]=*pPoint;
+ pPath->pFlags[pPath->numEntriesUsed]=flags;
- ASSERT ( dc );
- ASSERT ( pts );
- ASSERT ( cbPoints );
+ /* If this is PT_CLOSEFIGURE, we have to start a new stroke next time */
+ if((flags & PT_CLOSEFIGURE) == PT_CLOSEFIGURE)
+ pPath->newStroke=TRUE;
- /* Check that path is open */
- if ( dc->w.path.state != PATH_Open )
- return FALSE;
+ /* Increment entry count */
+ pPath->numEntriesUsed++;
- for ( i = 0; i < cbPoints; i++ )
- {
- pt = pts[i];
- CoordLPtoDP ( dc, &pt );
- PATH_AddEntry(&dc->w.path, &pt, (i == 0) ? PT_MOVETO : PT_LINETO);
- }
return TRUE;
}
+/* PATH_ReserveEntries
+ *
+ * Ensures that at least "numEntries" entries (for points and flags) have
+ * been allocated; allocates larger arrays and copies the existing entries
+ * to those arrays, if necessary. Returns TRUE if successful, else FALSE.
+ */
BOOL
FASTCALL
-PATH_PolylineTo ( PDC dc, const POINT *pts, DWORD cbPoints )
+PATH_ReserveEntries ( PPATH pPath, INT numEntries )
{
- POINT pt;
- ULONG i;
-
- ASSERT ( dc );
- ASSERT ( pts );
- ASSERT ( cbPoints );
-
- /* Check that path is open */
- if ( dc->w.path.state != PATH_Open )
- return FALSE;
+ INT numEntriesToAllocate;
+ POINT *pPointsNew;
+ BYTE *pFlagsNew;
- /* Add a PT_MOVETO if necessary */
- if ( dc->w.path.newStroke )
- {
- dc->w.path.newStroke = FALSE;
- IntGetCurrentPositionEx ( dc, &pt );
- CoordLPtoDP ( dc, &pt );
- if ( !PATH_AddEntry(&dc->w.path, &pt, PT_MOVETO) )
- return FALSE;
- }
+ ASSERT(pPath!=NULL);
+ ASSERT(numEntries>=0);
- for(i = 0; i < cbPoints; i++)
+ /* Do we have to allocate more memory? */
+ if(numEntries > pPath->numEntriesAllocated)
{
- pt = pts[i];
- CoordLPtoDP ( dc, &pt );
- PATH_AddEntry(&dc->w.path, &pt, PT_LINETO);
- }
-
- return TRUE;
-}
-
+ /* Find number of entries to allocate. We let the size of the array
+ * grow exponentially, since that will guarantee linear time
+ * complexity. */
+ if(pPath->numEntriesAllocated)
+ {
+ numEntriesToAllocate=pPath->numEntriesAllocated;
+ while(numEntriesToAllocate<numEntries)
+ numEntriesToAllocate=numEntriesToAllocate*GROW_FACTOR_NUMER/GROW_FACTOR_DENOM;
+ } else
+ numEntriesToAllocate=numEntries;
-BOOL
-FASTCALL
-PATH_Polygon ( PDC dc, const POINT *pts, DWORD cbPoints )
-{
- POINT pt;
- ULONG i;
+ /* Allocate new arrays */
+ pPointsNew=(POINT *)ExAllocatePoolWithTag(PagedPool, numEntriesToAllocate * sizeof(POINT), TAG_PATH);
+ if(!pPointsNew)
+ return FALSE;
+ pFlagsNew=(BYTE *)ExAllocatePoolWithTag(PagedPool, numEntriesToAllocate * sizeof(BYTE), TAG_PATH);
+ if(!pFlagsNew)
+ {
+ ExFreePool(pPointsNew);
+ return FALSE;
+ }
- ASSERT ( dc );
- ASSERT ( pts );
+ /* Copy old arrays to new arrays and discard old arrays */
+ if(pPath->pPoints)
+ {
+ ASSERT(pPath->pFlags);
- /* Check that path is open */
- if ( dc->w.path.state != PATH_Open )
- return FALSE;
+ memcpy(pPointsNew, pPath->pPoints, sizeof(POINT)*pPath->numEntriesUsed);
+ memcpy(pFlagsNew, pPath->pFlags, sizeof(BYTE)*pPath->numEntriesUsed);
- for(i = 0; i < cbPoints; i++)
- {
- pt = pts[i];
- CoordLPtoDP ( dc, &pt );
- PATH_AddEntry(&dc->w.path, &pt, (i == 0) ? PT_MOVETO :
- ((i == cbPoints-1) ? PT_LINETO | PT_CLOSEFIGURE :
- PT_LINETO));
+ ExFreePool(pPath->pPoints);
+ ExFreePool(pPath->pFlags);
+ }
+ pPath->pPoints=pPointsNew;
+ pPath->pFlags=pFlagsNew;
+ pPath->numEntriesAllocated=numEntriesToAllocate;
}
+
return TRUE;
}
+/* PATH_DoArcPart
+ *
+ * Creates a Bezier spline that corresponds to part of an arc and appends the
+ * corresponding points to the path. The start and end angles are passed in
+ * "angleStart" and "angleEnd"; these angles should span a quarter circle
+ * at most. If "startEntryType" is non-zero, an entry of that type for the first
+ * control point is added to the path; otherwise, it is assumed that the current
+ * position is equal to the first control point.
+ */
BOOL
FASTCALL
-PATH_PolyPolygon ( PDC dc, const POINT* pts, const INT* counts, UINT polygons )
+PATH_DoArcPart ( PPATH pPath, FLOAT_POINT corners[],
+ double angleStart, double angleEnd, BYTE startEntryType )
{
- POINT pt, startpt;
- ULONG poly, point, i;
+ double halfAngle, a;
+ double xNorm[4], yNorm[4];
+ POINT point;
+ int i;
- ASSERT ( dc );
- ASSERT ( pts );
- ASSERT ( counts );
- ASSERT ( polygons );
+ ASSERT(fabs(angleEnd-angleStart)<=M_PI_2);
- /* Check that path is open */
- if ( dc->w.path.state != PATH_Open );
- return FALSE;
+ /* FIXME: Is there an easier way of computing this? */
- for(i = 0, poly = 0; poly < polygons; poly++)
+ /* Compute control points */
+ halfAngle=(angleEnd-angleStart)/2.0;
+ if(fabs(halfAngle)>1e-8)
{
- for(point = 0; point < (ULONG) counts[poly]; point++, i++)
+ a=4.0/3.0*(1-cos(halfAngle))/sin(halfAngle);
+ xNorm[0]=cos(angleStart);
+ yNorm[0]=sin(angleStart);
+ xNorm[1]=xNorm[0] - a*yNorm[0];
+ yNorm[1]=yNorm[0] + a*xNorm[0];
+ xNorm[3]=cos(angleEnd);
+ yNorm[3]=sin(angleEnd);
+ xNorm[2]=xNorm[3] + a*yNorm[3];
+ yNorm[2]=yNorm[3] - a*xNorm[3];
+ } else
+ for(i=0; i<4; i++)
{
- pt = pts[i];
- CoordLPtoDP ( dc, &pt );
- if(point == 0) startpt = pt;
- PATH_AddEntry(&dc->w.path, &pt, (point == 0) ? PT_MOVETO : PT_LINETO);
+ xNorm[i]=cos(angleStart);
+ yNorm[i]=sin(angleStart);
}
- /* win98 adds an extra line to close the figure for some reason */
- PATH_AddEntry(&dc->w.path, &startpt, PT_LINETO | PT_CLOSEFIGURE);
- }
- return TRUE;
-}
-
-BOOL
-FASTCALL
-PATH_PolyPolyline ( PDC dc, const POINT* pts, const DWORD* counts, DWORD polylines )
-{
- POINT pt;
- ULONG poly, point, i;
-
- ASSERT ( dc );
- ASSERT ( pts );
- ASSERT ( counts );
- ASSERT ( polylines );
- /* Check that path is open */
- if ( dc->w.path.state != PATH_Open )
- return FALSE;
+ /* Add starting point to path if desired */
+ if(startEntryType)
+ {
+ PATH_ScaleNormalizedPoint(corners, xNorm[0], yNorm[0], &point);
+ if(!PATH_AddEntry(pPath, &point, startEntryType))
+ return FALSE;
+ }
- for(i = 0, poly = 0; poly < polylines; poly++)
+ /* Add remaining control points */
+ for(i=1; i<4; i++)
{
- for(point = 0; point < counts[poly]; point++, i++)
- {
- pt = pts[i];
- CoordLPtoDP ( dc, &pt );
- PATH_AddEntry(&dc->w.path, &pt, (point == 0) ? PT_MOVETO : PT_LINETO);
- }
+ PATH_ScaleNormalizedPoint(corners, xNorm[i], yNorm[i], &point);
+ if(!PATH_AddEntry(pPath, &point, PT_BEZIERTO))
+ return FALSE;
}
+
return TRUE;
}
-/***********************************************************************
- * Internal functions
- */
-
-/* PATH_CheckCorners
+/* PATH_ScaleNormalizedPoint
*
- * Helper function for PATH_RoundRect() and PATH_Rectangle()
+ * Scales a normalized point (x, y) with respect to the box whose corners are
+ * passed in "corners". The point is stored in "*pPoint". The normalized
+ * coordinates (-1.0, -1.0) correspond to corners[0], the coordinates
+ * (1.0, 1.0) correspond to corners[1].
*/
-BOOL PATH_CheckCorners(DC *dc, POINT corners[], INT x1, INT y1, INT x2, INT y2)
+VOID
+FASTCALL
+PATH_ScaleNormalizedPoint ( FLOAT_POINT corners[], double x,
+ double y, POINT *pPoint )
{
- INT temp;
- PDC_ATTR Dc_Attr = dc->pDc_Attr;
- if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
-
- /* Convert points to device coordinates */
- corners[0].x=x1;
- corners[0].y=y1;
- corners[1].x=x2;
- corners[1].y=y2;
- CoordLPtoDP(dc, &corners[0]);
- CoordLPtoDP(dc, &corners[1]);
-
- /* Make sure first corner is top left and second corner is bottom right */
- if(corners[0].x>corners[1].x)
- {
- temp=corners[0].x;
- corners[0].x=corners[1].x;
- corners[1].x=temp;
- }
- if(corners[0].y>corners[1].y)
- {
- temp=corners[0].y;
- corners[0].y=corners[1].y;
- corners[1].y=temp;
- }
-
- /* In GM_COMPATIBLE, don't include bottom and right edges */
- if(Dc_Attr->iGraphicsMode==GM_COMPATIBLE)
- {
- corners[1].x--;
- corners[1].y--;
- }
-
- return TRUE;
+ ASSERT ( corners );
+ ASSERT ( pPoint );
+ pPoint->x=GDI_ROUND( (double)corners[0].x + (double)(corners[1].x-corners[0].x)*0.5*(x+1.0) );
+ pPoint->y=GDI_ROUND( (double)corners[0].y + (double)(corners[1].y-corners[0].y)*0.5*(y+1.0) );
}
-
-/* PATH_AddFlatBezier
+/* PATH_NormalizePoint
*
+ * Normalizes a point with respect to the box whose corners are passed in
+ * corners. The normalized coordinates are stored in *pX and *pY.
*/
-BOOL
+VOID
FASTCALL
-PATH_AddFlatBezier ( GdiPath *pPath, POINT *pt, BOOL closed )
+PATH_NormalizePoint ( FLOAT_POINT corners[],
+ const FLOAT_POINT *pPoint,
+ double *pX, double *pY)
{
- POINT *pts;
- INT no, i;
+ ASSERT ( corners );
+ ASSERT ( pPoint );
+ ASSERT ( pX );
+ ASSERT ( pY );
+ *pX=(double)(pPoint->x-corners[0].x)/(double)(corners[1].x-corners[0].x) * 2.0 - 1.0;
+ *pY=(double)(pPoint->y-corners[0].y)/(double)(corners[1].y-corners[0].y) * 2.0 - 1.0;
+}
- pts = GDI_Bezier( pt, 4, &no );
- if ( !pts ) return FALSE;
- for(i = 1; i < no; i++)
- PATH_AddEntry(pPath, &pts[i], (i == no-1 && closed) ? PT_LINETO | PT_CLOSEFIGURE : PT_LINETO);
+BOOL FASTCALL PATH_StrokePath(DC *dc, PPATH pPath)
+{
+ BOOL ret = FALSE;
+ INT i=0;
+ INT nLinePts, nAlloc;
+ POINT *pLinePts = NULL;
+ POINT ptViewportOrg, ptWindowOrg;
+ SIZE szViewportExt, szWindowExt;
+ DWORD mapMode, graphicsMode;
+ XFORM xform;
+ PDC_ATTR Dc_Attr = dc->pDc_Attr;
- ExFreePool(pts);
- return TRUE;
-}
+ DPRINT("Enter %s\n", __FUNCTION__);
-/* PATH_FlattenPath
- *
- * Replaces Beziers with line segments
- *
- */
-BOOL
-FASTCALL
-PATH_FlattenPath(GdiPath *pPath)
-{
- GdiPath newPath;
- INT srcpt;
+ if (pPath->state != PATH_Closed)
+ return FALSE;
- RtlZeroMemory(&newPath, sizeof(newPath));
- newPath.state = PATH_Open;
- for(srcpt = 0; srcpt < pPath->numEntriesUsed; srcpt++) {
- switch(pPath->pFlags[srcpt] & ~PT_CLOSEFIGURE) {
- case PT_MOVETO:
- case PT_LINETO:
- PATH_AddEntry(&newPath, &pPath->pPoints[srcpt], pPath->pFlags[srcpt]);
- break;
- case PT_BEZIERTO:
- PATH_AddFlatBezier(&newPath, &pPath->pPoints[srcpt-1], pPath->pFlags[srcpt+2] & PT_CLOSEFIGURE);
- srcpt += 2;
- break;
- }
- }
- newPath.state = PATH_Closed;
- PATH_AssignGdiPath(pPath, &newPath);
- PATH_EmptyPath(&newPath);
- return TRUE;
-}
+ if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
+ /* Save the mapping mode info */
+ mapMode = Dc_Attr->iMapMode;
+ IntGetViewportExtEx(dc, &szViewportExt);
+ IntGetViewportOrgEx(dc, &ptViewportOrg);
+ IntGetWindowExtEx(dc, &szWindowExt);
+ IntGetWindowOrgEx(dc, &ptWindowOrg);
+ xform = dc->DcLevel.xformWorld2Wnd;
-/* PATH_PathToRegion
- *
- * Creates a region from the specified path using the specified polygon
- * filling mode. The path is left unchanged. A handle to the region that
- * was created is stored in *pHrgn. If successful, TRUE is returned; if an
- * error occurs, SetLastError is called with the appropriate value and
- * FALSE is returned.
- */
+ /* Set MM_TEXT */
+ Dc_Attr->iMapMode = MM_TEXT;
+ Dc_Attr->ptlViewportOrg.x = 0;
+ Dc_Attr->ptlViewportOrg.y = 0;
+ Dc_Attr->ptlWindowOrg.x = 0;
+ Dc_Attr->ptlWindowOrg.y = 0;
+ graphicsMode = Dc_Attr->iGraphicsMode;
+ Dc_Attr->iGraphicsMode = GM_ADVANCED;
+ IntGdiModifyWorldTransform(dc, &xform, MWT_IDENTITY);
+ Dc_Attr->iGraphicsMode = graphicsMode;
+ /* Allocate enough memory for the worst case without beziers (one PT_MOVETO
+ * and the rest PT_LINETO with PT_CLOSEFIGURE at the end) plus some buffer
+ * space in case we get one to keep the number of reallocations small. */
+ nAlloc = pPath->numEntriesUsed + 1 + 300;
+ pLinePts = ExAllocatePoolWithTag(PagedPool, nAlloc * sizeof(POINT), TAG_PATH);
+ if(!pLinePts)
+ {
+ DPRINT1("Can't allocate pool!\n");
+ SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+ goto end;
+ }
+ nLinePts = 0;
-BOOL
-FASTCALL
-PATH_PathToRegion ( GdiPath *pPath, INT nPolyFillMode, HRGN *pHrgn )
-{
- int numStrokes, iStroke, i;
- INT *pNumPointsInStroke;
- HRGN hrgn = 0;
+ for(i = 0; i < pPath->numEntriesUsed; i++)
+ {
+ if((i == 0 || (pPath->pFlags[i-1] & PT_CLOSEFIGURE))
+ && (pPath->pFlags[i] != PT_MOVETO))
+ {
+ DPRINT1("Expected PT_MOVETO %s, got path flag %d\n",
+ i == 0 ? "as first point" : "after PT_CLOSEFIGURE",
+ (INT)pPath->pFlags[i]);
+ goto end;
+ }
- ASSERT(pPath!=NULL);
- ASSERT(pHrgn!=NULL);
+ switch(pPath->pFlags[i])
+ {
+ case PT_MOVETO:
+ DPRINT("Got PT_MOVETO (%ld, %ld)\n",
+ pPath->pPoints[i].x, pPath->pPoints[i].y);
+ if(nLinePts >= 2) IntGdiPolyline(dc, pLinePts, nLinePts);
+ nLinePts = 0;
+ pLinePts[nLinePts++] = pPath->pPoints[i];
+ break;
+ case PT_LINETO:
+ case (PT_LINETO | PT_CLOSEFIGURE):
+ DPRINT("Got PT_LINETO (%ld, %ld)\n",
+ pPath->pPoints[i].x, pPath->pPoints[i].y);
+ pLinePts[nLinePts++] = pPath->pPoints[i];
+ break;
+ case PT_BEZIERTO:
+ DPRINT("Got PT_BEZIERTO\n");
+ if(pPath->pFlags[i+1] != PT_BEZIERTO ||
+ (pPath->pFlags[i+2] & ~PT_CLOSEFIGURE) != PT_BEZIERTO)
+ {
+ DPRINT1("Path didn't contain 3 successive PT_BEZIERTOs\n");
+ ret = FALSE;
+ goto end;
+ }
+ else
+ {
+ INT nBzrPts, nMinAlloc;
+ POINT *pBzrPts = GDI_Bezier(&pPath->pPoints[i-1], 4, &nBzrPts);
+ /* Make sure we have allocated enough memory for the lines of
+ * this bezier and the rest of the path, assuming we won't get
+ * another one (since we won't reallocate again then). */
+ nMinAlloc = nLinePts + (pPath->numEntriesUsed - i) + nBzrPts;
+ if(nAlloc < nMinAlloc)
+ {
+ // Reallocate memory
- PATH_FlattenPath ( pPath );
+ POINT *Realloc = NULL;
+ nAlloc = nMinAlloc * 2;
- /* FIXME: What happens when number of points is zero? */
+ Realloc = ExAllocatePoolWithTag(PagedPool,
+ nAlloc * sizeof(POINT),
+ TAG_PATH);
- /* First pass: Find out how many strokes there are in the path */
- /* FIXME: We could eliminate this with some bookkeeping in GdiPath */
- numStrokes=0;
- for(i=0; i<pPath->numEntriesUsed; i++)
- if((pPath->pFlags[i] & ~PT_CLOSEFIGURE) == PT_MOVETO)
- numStrokes++;
+ if(!Realloc)
+ {
+ DPRINT1("Can't allocate pool!\n");
+ goto end;
+ }
- /* Allocate memory for number-of-points-in-stroke array */
- pNumPointsInStroke=(int *)ExAllocatePoolWithTag(PagedPool, sizeof(int) * numStrokes, TAG_PATH);
- if(!pNumPointsInStroke)
- {
-// SetLastError(ERROR_NOT_ENOUGH_MEMORY);
- return FALSE;
- }
+ memcpy(Realloc, pLinePts, nLinePts*sizeof(POINT));
+ ExFreePool(pLinePts);
+ pLinePts = Realloc;
+ }
+ memcpy(&pLinePts[nLinePts], &pBzrPts[1], (nBzrPts - 1) * sizeof(POINT));
+ nLinePts += nBzrPts - 1;
+ ExFreePool(pBzrPts);
+ i += 2;
+ }
+ break;
+ default:
+ DPRINT1("Got path flag %d (not supported)\n", (INT)pPath->pFlags[i]);
+ goto end;
+ }
- /* Second pass: remember number of points in each polygon */
- iStroke=-1; /* Will get incremented to 0 at beginning of first stroke */
- for(i=0; i<pPath->numEntriesUsed; i++)
- {
- /* Is this the beginning of a new stroke? */
- if((pPath->pFlags[i] & ~PT_CLOSEFIGURE) == PT_MOVETO)
- {
- iStroke++;
- pNumPointsInStroke[iStroke]=0;
+ if(pPath->pFlags[i] & PT_CLOSEFIGURE)
+ {
+ pLinePts[nLinePts++] = pLinePts[0];
+ }
}
+ if(nLinePts >= 2)
+ IntGdiPolyline(dc, pLinePts, nLinePts);
- pNumPointsInStroke[iStroke]++;
- }
-
- /* Create a region from the strokes */
-/* hrgn=CreatePolyPolygonRgn(pPath->pPoints, pNumPointsInStroke,
- numStrokes, nPolyFillMode); FIXME: reinclude when region code implemented */
- if(hrgn==(HRGN)0)
- {
-// SetLastError(ERROR_NOT_ENOUGH_MEMORY);
- return FALSE;
- }
+ ret = TRUE;
- /* Free memory for number-of-points-in-stroke array */
- ExFreePool(pNumPointsInStroke);
+end:
+ if(pLinePts)ExFreePool(pLinePts);
- /* Success! */
- *pHrgn=hrgn;
- return TRUE;
-}
+ /* Restore the old mapping mode */
+ Dc_Attr->iMapMode = mapMode;
+ Dc_Attr->szlWindowExt.cx = szWindowExt.cx;
+ Dc_Attr->szlWindowExt.cy = szWindowExt.cy;
+ Dc_Attr->ptlWindowOrg.x = ptWindowOrg.x;
+ Dc_Attr->ptlWindowOrg.y = ptWindowOrg.y;
-/* PATH_EmptyPath
- *
- * Removes all entries from the path and sets the path state to PATH_Null.
- */
-VOID
-FASTCALL
-PATH_EmptyPath ( GdiPath *pPath )
-{
- ASSERT(pPath!=NULL);
+ Dc_Attr->szlViewportExt.cx = szViewportExt.cx;
+ Dc_Attr->szlViewportExt.cy = szViewportExt.cy;
+ Dc_Attr->ptlViewportOrg.x = ptViewportOrg.x;
+ Dc_Attr->ptlViewportOrg.y = ptViewportOrg.y;
- pPath->state=PATH_Null;
- pPath->numEntriesUsed=0;
+ /* Restore the world transform */
+ dc->DcLevel.xformWorld2Wnd = xform;
+
+ /* If we've moved the current point then get its new position
+ which will be in device (MM_TEXT) co-ords, convert it to
+ logical co-ords and re-set it. This basically updates
+ dc->CurPosX|Y so that their values are in the correct mapping
+ mode.
+ */
+ if(i > 0)
+ {
+ POINT pt;
+ IntGetCurrentPositionEx(dc, &pt);
+ IntDPtoLP(dc, &pt, 1);
+ IntGdiMoveToEx(dc, pt.x, pt.y, NULL);
+ }
+ DPRINT("Leave %s, ret=%d\n", __FUNCTION__, ret);
+ return ret;
}
-/* PATH_AddEntry
- *
- * Adds an entry to the path. For "flags", pass either PT_MOVETO, PT_LINETO
- * or PT_BEZIERTO, optionally ORed with PT_CLOSEFIGURE. Returns TRUE if
- * successful, FALSE otherwise (e.g. if not enough memory was available).
- */
+#define round(x) ((int)((x)>0?(x)+0.5:(x)-0.5))
+
+static
BOOL
FASTCALL
-PATH_AddEntry ( GdiPath *pPath, const POINT *pPoint, BYTE flags )
+PATH_WidenPath(DC *dc)
{
- ASSERT(pPath!=NULL);
+ INT i, j, numStrokes, penWidth, penWidthIn, penWidthOut, size, penStyle;
+ BOOL ret = FALSE;
+ PPATH pPath, pNewPath, *pStrokes, pUpPath, pDownPath;
+ EXTLOGPEN *elp;
+ DWORD obj_type, joint, endcap, penType;
+ PDC_ATTR Dc_Attr = dc->pDc_Attr;
- /* FIXME: If newStroke is true, perhaps we want to check that we're
- * getting a PT_MOVETO
- */
+ pPath = PATH_LockPath( dc->DcLevel.hPath );
+ if (!pPath) return FALSE;
- /* Check that path is open */
- if ( pPath->state != PATH_Open )
- return FALSE;
+ if(pPath->state == PATH_Open)
+ {
+ PATH_UnlockPath( pPath );
+ SetLastWin32Error(ERROR_CAN_NOT_COMPLETE);
+ return FALSE;
+ }
- /* Reserve enough memory for an extra path entry */
- if ( !PATH_ReserveEntries(pPath, pPath->numEntriesUsed+1) )
- return FALSE;
+ if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
- /* Store information in path entry */
- pPath->pPoints[pPath->numEntriesUsed]=*pPoint;
- pPath->pFlags[pPath->numEntriesUsed]=flags;
+ PATH_FlattenPath(pPath);
- /* If this is PT_CLOSEFIGURE, we have to start a new stroke next time */
- if((flags & PT_CLOSEFIGURE) == PT_CLOSEFIGURE)
- pPath->newStroke=TRUE;
+ size = IntGdiGetObject( Dc_Attr->hpen, 0, NULL);
+ if (!size)
+ {
+ PATH_UnlockPath( pPath );
+ SetLastWin32Error(ERROR_CAN_NOT_COMPLETE);
+ return FALSE;
+ }
- /* Increment entry count */
- pPath->numEntriesUsed++;
+ elp = ExAllocatePoolWithTag(PagedPool, size, TAG_PATH);
+ (VOID) IntGdiGetObject( Dc_Attr->hpen, size, elp);
- return TRUE;
-}
+ obj_type = GDIOBJ_GetObjectType(Dc_Attr->hpen);
+ if(obj_type == GDI_OBJECT_TYPE_PEN)
+ {
+ penStyle = ((LOGPEN*)elp)->lopnStyle;
+ }
+ else if(obj_type == GDI_OBJECT_TYPE_EXTPEN)
+ {
+ penStyle = elp->elpPenStyle;
+ }
+ else
+ {
+ SetLastWin32Error(ERROR_CAN_NOT_COMPLETE);
+ ExFreePool(elp);
+ PATH_UnlockPath( pPath );
+ return FALSE;
+ }
-/* PATH_ReserveEntries
- *
- * Ensures that at least "numEntries" entries (for points and flags) have
- * been allocated; allocates larger arrays and copies the existing entries
- * to those arrays, if necessary. Returns TRUE if successful, else FALSE.
- */
-BOOL
-FASTCALL
-PATH_ReserveEntries ( GdiPath *pPath, INT numEntries )
-{
- INT numEntriesToAllocate;
- POINT *pPointsNew;
- BYTE *pFlagsNew;
+ penWidth = elp->elpWidth;
+ ExFreePool(elp);
- ASSERT(pPath!=NULL);
- ASSERT(numEntries>=0);
+ endcap = (PS_ENDCAP_MASK & penStyle);
+ joint = (PS_JOIN_MASK & penStyle);
+ penType = (PS_TYPE_MASK & penStyle);
- /* Do we have to allocate more memory? */
- if(numEntries > pPath->numEntriesAllocated)
- {
- /* Find number of entries to allocate. We let the size of the array
- * grow exponentially, since that will guarantee linear time
- * complexity. */
- if(pPath->numEntriesAllocated)
+ /* The function cannot apply to cosmetic pens */
+ if(obj_type == GDI_OBJECT_TYPE_EXTPEN && penType == PS_COSMETIC)
{
- numEntriesToAllocate=pPath->numEntriesAllocated;
- while(numEntriesToAllocate<numEntries)
- numEntriesToAllocate=numEntriesToAllocate*GROW_FACTOR_NUMER/GROW_FACTOR_DENOM;
- } else
- numEntriesToAllocate=numEntries;
+ PATH_UnlockPath( pPath );
+ SetLastWin32Error(ERROR_CAN_NOT_COMPLETE);
+ return FALSE;
+ }
- /* Allocate new arrays */
- pPointsNew=(POINT *)ExAllocatePoolWithTag(PagedPool, numEntriesToAllocate * sizeof(POINT), TAG_PATH);
- if(!pPointsNew)
- return FALSE;
- pFlagsNew=(BYTE *)ExAllocatePoolWithTag(PagedPool, numEntriesToAllocate * sizeof(BYTE), TAG_PATH);
- if(!pFlagsNew)
+ penWidthIn = penWidth / 2;
+ penWidthOut = penWidth / 2;
+ if(penWidthIn + penWidthOut < penWidth)
+ penWidthOut++;
+
+ numStrokes = 0;
+
+ pStrokes = ExAllocatePoolWithTag(PagedPool, sizeof(PPATH), TAG_PATH);
+ pStrokes[0] = ExAllocatePoolWithTag(PagedPool, sizeof(PATH), TAG_PATH);
+ PATH_InitGdiPath(pStrokes[0]);
+ pStrokes[0]->pFlags = ExAllocatePoolWithTag(PagedPool, pPath->numEntriesUsed * sizeof(INT), TAG_PATH);
+ pStrokes[0]->pPoints = ExAllocatePoolWithTag(PagedPool, pPath->numEntriesUsed * sizeof(POINT), TAG_PATH);
+ pStrokes[0]->numEntriesUsed = 0;
+
+ for(i = 0, j = 0; i < pPath->numEntriesUsed; i++, j++)
{
- ExFreePool(pPointsNew);
- return FALSE;
+ POINT point;
+ if((i == 0 || (pPath->pFlags[i-1] & PT_CLOSEFIGURE)) &&
+ (pPath->pFlags[i] != PT_MOVETO))
+ {
+ DPRINT1("Expected PT_MOVETO %s, got path flag %c\n",
+ i == 0 ? "as first point" : "after PT_CLOSEFIGURE",
+ pPath->pFlags[i]);
+ return FALSE;
+ }
+ switch(pPath->pFlags[i])
+ {
+ case PT_MOVETO:
+ if(numStrokes > 0)
+ {
+ pStrokes[numStrokes - 1]->state = PATH_Closed;
+ }
+ numStrokes++;
+ j = 0;
+ ExFreePool(pStrokes);
+ pStrokes = ExAllocatePoolWithTag(PagedPool, numStrokes * sizeof(PPATH), TAG_PATH);
+ pStrokes[numStrokes - 1] = ExAllocatePoolWithTag(PagedPool, sizeof(PATH), TAG_PATH);
+
+ PATH_InitGdiPath(pStrokes[numStrokes - 1]);
+ pStrokes[numStrokes - 1]->state = PATH_Open;
+ case PT_LINETO:
+ case (PT_LINETO | PT_CLOSEFIGURE):
+ point.x = pPath->pPoints[i].x;
+ point.y = pPath->pPoints[i].y;
+ PATH_AddEntry(pStrokes[numStrokes - 1], &point, pPath->pFlags[i]);
+ break;
+ case PT_BEZIERTO:
+ /* should never happen because of the FlattenPath call */
+ DPRINT1("Should never happen\n");
+ break;
+ default:
+ DPRINT1("Got path flag %c\n", pPath->pFlags[i]);
+ return FALSE;
+ }
}
- /* Copy old arrays to new arrays and discard old arrays */
- if(pPath->pPoints)
- {
- ASSERT(pPath->pFlags);
+ pNewPath = ExAllocatePoolWithTag(PagedPool, sizeof(PATH), TAG_PATH);
+ PATH_InitGdiPath(pNewPath);
+ pNewPath->state = PATH_Open;
- memcpy(pPointsNew, pPath->pPoints, sizeof(POINT)*pPath->numEntriesUsed);
- memcpy(pFlagsNew, pPath->pFlags, sizeof(BYTE)*pPath->numEntriesUsed);
+ for(i = 0; i < numStrokes; i++)
+ {
+ pUpPath = ExAllocatePoolWithTag(PagedPool, sizeof(PATH), TAG_PATH);
+ PATH_InitGdiPath(pUpPath);
+ pUpPath->state = PATH_Open;
+ pDownPath = ExAllocatePoolWithTag(PagedPool, sizeof(PATH), TAG_PATH);
+ PATH_InitGdiPath(pDownPath);
+ pDownPath->state = PATH_Open;
+
+ for(j = 0; j < pStrokes[i]->numEntriesUsed; j++)
+ {
+ /* Beginning or end of the path if not closed */
+ if((!(pStrokes[i]->pFlags[pStrokes[i]->numEntriesUsed - 1] & PT_CLOSEFIGURE)) && (j == 0 || j == pStrokes[i]->numEntriesUsed - 1) )
+ {
+ /* Compute segment angle */
+ double xo, yo, xa, ya, theta;
+ POINT pt;
+ FLOAT_POINT corners[2];
+ if(j == 0)
+ {
+ xo = pStrokes[i]->pPoints[j].x;
+ yo = pStrokes[i]->pPoints[j].y;
+ xa = pStrokes[i]->pPoints[1].x;
+ ya = pStrokes[i]->pPoints[1].y;
+ }
+ else
+ {
+ xa = pStrokes[i]->pPoints[j - 1].x;
+ ya = pStrokes[i]->pPoints[j - 1].y;
+ xo = pStrokes[i]->pPoints[j].x;
+ yo = pStrokes[i]->pPoints[j].y;
+ }
+ theta = atan2( ya - yo, xa - xo );
+ switch(endcap)
+ {
+ case PS_ENDCAP_SQUARE :
+ pt.x = xo + round(sqrt(2) * penWidthOut * cos(M_PI_4 + theta));
+ pt.y = yo + round(sqrt(2) * penWidthOut * sin(M_PI_4 + theta));
+ PATH_AddEntry(pUpPath, &pt, (j == 0 ? PT_MOVETO : PT_LINETO) );
+ pt.x = xo + round(sqrt(2) * penWidthIn * cos(- M_PI_4 + theta));
+ pt.y = yo + round(sqrt(2) * penWidthIn * sin(- M_PI_4 + theta));
+ PATH_AddEntry(pUpPath, &pt, PT_LINETO);
+ break;
+ case PS_ENDCAP_FLAT :
+ pt.x = xo + round( penWidthOut * cos(theta + M_PI_2) );
+ pt.y = yo + round( penWidthOut * sin(theta + M_PI_2) );
+ PATH_AddEntry(pUpPath, &pt, (j == 0 ? PT_MOVETO : PT_LINETO));
+ pt.x = xo - round( penWidthIn * cos(theta + M_PI_2) );
+ pt.y = yo - round( penWidthIn * sin(theta + M_PI_2) );
+ PATH_AddEntry(pUpPath, &pt, PT_LINETO);
+ break;
+ case PS_ENDCAP_ROUND :
+ default :
+ corners[0].x = xo - penWidthIn;
+ corners[0].y = yo - penWidthIn;
+ corners[1].x = xo + penWidthOut;
+ corners[1].y = yo + penWidthOut;
+ PATH_DoArcPart(pUpPath ,corners, theta + M_PI_2 , theta + 3 * M_PI_4, (j == 0 ? PT_MOVETO : FALSE));
+ PATH_DoArcPart(pUpPath ,corners, theta + 3 * M_PI_4 , theta + M_PI, FALSE);
+ PATH_DoArcPart(pUpPath ,corners, theta + M_PI, theta + 5 * M_PI_4, FALSE);
+ PATH_DoArcPart(pUpPath ,corners, theta + 5 * M_PI_4 , theta + 3 * M_PI_2, FALSE);
+ break;
+ }
+ }
+ /* Corpse of the path */
+ else
+ {
+ /* Compute angle */
+ INT previous, next;
+ double xa, ya, xb, yb, xo, yo;
+ double alpha, theta, miterWidth;
+ DWORD _joint = joint;
+ POINT pt;
+ PPATH pInsidePath, pOutsidePath;
+ if(j > 0 && j < pStrokes[i]->numEntriesUsed - 1)
+ {
+ previous = j - 1;
+ next = j + 1;
+ }
+ else if (j == 0)
+ {
+ previous = pStrokes[i]->numEntriesUsed - 1;
+ next = j + 1;
+ }
+ else
+ {
+ previous = j - 1;
+ next = 0;
+ }
+ xo = pStrokes[i]->pPoints[j].x;
+ yo = pStrokes[i]->pPoints[j].y;
+ xa = pStrokes[i]->pPoints[previous].x;
+ ya = pStrokes[i]->pPoints[previous].y;
+ xb = pStrokes[i]->pPoints[next].x;
+ yb = pStrokes[i]->pPoints[next].y;
+ theta = atan2( yo - ya, xo - xa );
+ alpha = atan2( yb - yo, xb - xo ) - theta;
+ if (alpha > 0) alpha -= M_PI;
+ else alpha += M_PI;
+ if(_joint == PS_JOIN_MITER && dc->DcLevel.laPath.eMiterLimit < fabs(1 / sin(alpha/2)))
+ {
+ _joint = PS_JOIN_BEVEL;
+ }
+ if(alpha > 0)
+ {
+ pInsidePath = pUpPath;
+ pOutsidePath = pDownPath;
+ }
+ else if(alpha < 0)
+ {
+ pInsidePath = pDownPath;
+ pOutsidePath = pUpPath;
+ }
+ else
+ {
+ continue;
+ }
+ /* Inside angle points */
+ if(alpha > 0)
+ {
+ pt.x = xo - round( penWidthIn * cos(theta + M_PI_2) );
+ pt.y = yo - round( penWidthIn * sin(theta + M_PI_2) );
+ }
+ else
+ {
+ pt.x = xo + round( penWidthIn * cos(theta + M_PI_2) );
+ pt.y = yo + round( penWidthIn * sin(theta + M_PI_2) );
+ }
+ PATH_AddEntry(pInsidePath, &pt, PT_LINETO);
+ if(alpha > 0)
+ {
+ pt.x = xo + round( penWidthIn * cos(M_PI_2 + alpha + theta) );
+ pt.y = yo + round( penWidthIn * sin(M_PI_2 + alpha + theta) );
+ }
+ else
+ {
+ pt.x = xo - round( penWidthIn * cos(M_PI_2 + alpha + theta) );
+ pt.y = yo - round( penWidthIn * sin(M_PI_2 + alpha + theta) );
+ }
+ PATH_AddEntry(pInsidePath, &pt, PT_LINETO);
+ /* Outside angle point */
+ switch(_joint)
+ {
+ case PS_JOIN_MITER :
+ miterWidth = fabs(penWidthOut / cos(M_PI_2 - fabs(alpha) / 2));
+ pt.x = xo + round( miterWidth * cos(theta + alpha / 2) );
+ pt.y = yo + round( miterWidth * sin(theta + alpha / 2) );
+ PATH_AddEntry(pOutsidePath, &pt, PT_LINETO);
+ break;
+ case PS_JOIN_BEVEL :
+ if(alpha > 0)
+ {
+ pt.x = xo + round( penWidthOut * cos(theta + M_PI_2) );
+ pt.y = yo + round( penWidthOut * sin(theta + M_PI_2) );
+ }
+ else
+ {
+ pt.x = xo - round( penWidthOut * cos(theta + M_PI_2) );
+ pt.y = yo - round( penWidthOut * sin(theta + M_PI_2) );
+ }
+ PATH_AddEntry(pOutsidePath, &pt, PT_LINETO);
+ if(alpha > 0)
+ {
+ pt.x = xo - round( penWidthOut * cos(M_PI_2 + alpha + theta) );
+ pt.y = yo - round( penWidthOut * sin(M_PI_2 + alpha + theta) );
+ }
+ else
+ {
+ pt.x = xo + round( penWidthOut * cos(M_PI_2 + alpha + theta) );
+ pt.y = yo + round( penWidthOut * sin(M_PI_2 + alpha + theta) );
+ }
+ PATH_AddEntry(pOutsidePath, &pt, PT_LINETO);
+ break;
+ case PS_JOIN_ROUND :
+ default :
+ if(alpha > 0)
+ {
+ pt.x = xo + round( penWidthOut * cos(theta + M_PI_2) );
+ pt.y = yo + round( penWidthOut * sin(theta + M_PI_2) );
+ }
+ else
+ {
+ pt.x = xo - round( penWidthOut * cos(theta + M_PI_2) );
+ pt.y = yo - round( penWidthOut * sin(theta + M_PI_2) );
+ }
+ PATH_AddEntry(pOutsidePath, &pt, PT_BEZIERTO);
+ pt.x = xo + round( penWidthOut * cos(theta + alpha / 2) );
+ pt.y = yo + round( penWidthOut * sin(theta + alpha / 2) );
+ PATH_AddEntry(pOutsidePath, &pt, PT_BEZIERTO);
+ if(alpha > 0)
+ {
+ pt.x = xo - round( penWidthOut * cos(M_PI_2 + alpha + theta) );
+ pt.y = yo - round( penWidthOut * sin(M_PI_2 + alpha + theta) );
+ }
+ else
+ {
+ pt.x = xo + round( penWidthOut * cos(M_PI_2 + alpha + theta) );
+ pt.y = yo + round( penWidthOut * sin(M_PI_2 + alpha + theta) );
+ }
+ PATH_AddEntry(pOutsidePath, &pt, PT_BEZIERTO);
+ break;
+ }
+ }
+ }
+ for(j = 0; j < pUpPath->numEntriesUsed; j++)
+ {
+ POINT pt;
+ pt.x = pUpPath->pPoints[j].x;
+ pt.y = pUpPath->pPoints[j].y;
+ PATH_AddEntry(pNewPath, &pt, (j == 0 ? PT_MOVETO : PT_LINETO));
+ }
+ for(j = 0; j < pDownPath->numEntriesUsed; j++)
+ {
+ POINT pt;
+ pt.x = pDownPath->pPoints[pDownPath->numEntriesUsed - j - 1].x;
+ pt.y = pDownPath->pPoints[pDownPath->numEntriesUsed - j - 1].y;
+ PATH_AddEntry(pNewPath, &pt, ( (j == 0 && (pStrokes[i]->pFlags[pStrokes[i]->numEntriesUsed - 1] & PT_CLOSEFIGURE)) ? PT_MOVETO : PT_LINETO));
+ }
- ExFreePool(pPath->pPoints);
- ExFreePool(pPath->pFlags);
+ PATH_DestroyGdiPath(pStrokes[i]);
+ ExFreePool(pStrokes[i]);
+ PATH_DestroyGdiPath(pUpPath);
+ ExFreePool(pUpPath);
+ PATH_DestroyGdiPath(pDownPath);
+ ExFreePool(pDownPath);
}
- pPath->pPoints=pPointsNew;
- pPath->pFlags=pFlagsNew;
- pPath->numEntriesAllocated=numEntriesToAllocate;
- }
+ ExFreePool(pStrokes);
- return TRUE;
+ pNewPath->state = PATH_Closed;
+ if (!(ret = PATH_AssignGdiPath(pPath, pNewPath)))
+ DPRINT1("Assign path failed\n");
+ PATH_DestroyGdiPath(pNewPath);
+ ExFreePool(pNewPath);
+ return ret;
}
-/* PATH_DoArcPart
- *
- * Creates a Bezier spline that corresponds to part of an arc and appends the
- * corresponding points to the path. The start and end angles are passed in
- * "angleStart" and "angleEnd"; these angles should span a quarter circle
- * at most. If "addMoveTo" is true, a PT_MOVETO entry for the first control
- * point is added to the path; otherwise, it is assumed that the current
- * position is equal to the first control point.
+
+
+/***********************************************************************
+ * Exported functions
*/
+
BOOL
-FASTCALL
-PATH_DoArcPart ( GdiPath *pPath, FLOAT_POINT corners[],
- double angleStart, double angleEnd, BOOL addMoveTo )
+STDCALL
+NtGdiAbortPath(HDC hDC)
{
- double halfAngle, a;
- double xNorm[4], yNorm[4];
- POINT point;
- int i;
+ PPATH pPath;
+ PDC dc = DC_LockDc ( hDC );
+ if ( !dc )
+ {
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
- ASSERT(fabs(angleEnd-angleStart)<=M_PI_2);
+ pPath = PATH_LockPath(dc->DcLevel.hPath);
+ {
+ DC_UnlockDc(dc);
+ return FALSE;
+ }
- /* FIXME: Is there an easier way of computing this? */
+ PATH_EmptyPath(pPath);
- /* Compute control points */
- halfAngle=(angleEnd-angleStart)/2.0;
- if(fabs(halfAngle)>1e-8)
+ PATH_UnlockPath(pPath);
+ DC_UnlockDc ( dc );
+ return TRUE;
+}
+
+BOOL
+STDCALL
+NtGdiBeginPath( HDC hDC )
+{
+ PPATH pPath;
+ PDC dc;
+
+ dc = DC_LockDc ( hDC );
+ if ( !dc )
{
- a=4.0/3.0*(1-cos(halfAngle))/sin(halfAngle);
- xNorm[0]=cos(angleStart);
- yNorm[0]=sin(angleStart);
- xNorm[1]=xNorm[0] - a*yNorm[0];
- yNorm[1]=yNorm[0] + a*xNorm[0];
- xNorm[3]=cos(angleEnd);
- yNorm[3]=sin(angleEnd);
- xNorm[2]=xNorm[3] + a*yNorm[3];
- yNorm[2]=yNorm[3] - a*xNorm[3];
- } else
- for(i=0; i<4; i++)
- {
- xNorm[i]=cos(angleStart);
- yNorm[i]=sin(angleStart);
- }
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
- /* Add starting point to path if desired */
- if(addMoveTo)
+ /* If path is already open, do nothing. Check if not Save DC state */
+ if ((dc->DcLevel.flPath & DCPATH_ACTIVE) && !(dc->DcLevel.flPath & DCPATH_SAVE))
{
- PATH_ScaleNormalizedPoint(corners, xNorm[0], yNorm[0], &point);
- if(!PATH_AddEntry(pPath, &point, PT_MOVETO))
- return FALSE;
+ DC_UnlockDc ( dc );
+ return TRUE;
}
- /* Add remaining control points */
- for(i=1; i<4; i++)
+ if ( dc->DcLevel.hPath )
{
- PATH_ScaleNormalizedPoint(corners, xNorm[i], yNorm[i], &point);
- if(!PATH_AddEntry(pPath, &point, PT_BEZIERTO))
- return FALSE;
+ DPRINT1("BeginPath 1 0x%x\n", dc->DcLevel.hPath);
+ if ( !(dc->DcLevel.flPath & DCPATH_SAVE) )
+ { // Remove previous handle.
+ if (!PATH_Delete(dc->DcLevel.hPath))
+ {
+ DC_UnlockDc ( dc );
+ return FALSE;
+ }
+ }
+ else
+ { // Clear flags and Handle.
+ dc->DcLevel.flPath &= ~(DCPATH_SAVE|DCPATH_ACTIVE);
+ dc->DcLevel.hPath = NULL;
+ }
}
+ pPath = PATH_AllocPathWithHandle();
+ if (!pPath)
+ {
+ SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+ return FALSE;
+ }
+ dc->DcLevel.flPath |= DCPATH_ACTIVE; // Set active ASAP!
- return TRUE;
-}
+ dc->DcLevel.hPath = pPath->BaseObject.hHmgr;
-/* PATH_ScaleNormalizedPoint
- *
- * Scales a normalized point (x, y) with respect to the box whose corners are
- * passed in "corners". The point is stored in "*pPoint". The normalized
- * coordinates (-1.0, -1.0) correspond to corners[0], the coordinates
- * (1.0, 1.0) correspond to corners[1].
- */
-VOID
-FASTCALL
-PATH_ScaleNormalizedPoint ( FLOAT_POINT corners[], double x,
- double y, POINT *pPoint )
+ DPRINT1("BeginPath 2 h 0x%x p 0x%x\n", dc->DcLevel.hPath, pPath);
+ // Path handles are shared. Also due to recursion with in the same thread.
+ GDIOBJ_UnlockObjByPtr((POBJ)pPath); // Unlock
+ pPath = PATH_LockPath(dc->DcLevel.hPath); // Share Lock.
+
+ /* Make sure that path is empty */
+ PATH_EmptyPath( pPath );
+
+ /* Initialize variables for new path */
+ pPath->newStroke = TRUE;
+ pPath->state = PATH_Open;
+
+ PATH_UnlockPath(pPath);
+ DC_UnlockDc ( dc );
+ return TRUE;
+}
+
+BOOL
+STDCALL
+NtGdiCloseFigure(HDC hDC)
{
- ASSERT ( corners );
- ASSERT ( pPoint );
- pPoint->x=GDI_ROUND( (double)corners[0].x + (double)(corners[1].x-corners[0].x)*0.5*(x+1.0) );
- pPoint->y=GDI_ROUND( (double)corners[0].y + (double)(corners[1].y-corners[0].y)*0.5*(y+1.0) );
+ BOOL Ret = FALSE; // default to failure
+ PDC pDc;
+ PPATH pPath;
+
+ DPRINT("Enter %s\n", __FUNCTION__);
+
+ pDc = DC_LockDc(hDC);
+ if (!pDc)
+ {
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+ pPath = PATH_LockPath( pDc->DcLevel.hPath );
+ if (!pPath)
+ {
+ DC_UnlockDc(pDc);
+ return FALSE;
+ }
+
+ if (pPath->state==PATH_Open)
+ {
+ IntGdiCloseFigure(pPath);
+ Ret = TRUE;
+ }
+ else
+ {
+ // FIXME: check if lasterror is set correctly
+ SetLastWin32Error(ERROR_CAN_NOT_COMPLETE);
+ }
+
+ PATH_UnlockPath( pPath );
+ DC_UnlockDc(pDc);
+ return Ret;
}
-/* PATH_NormalizePoint
- *
- * Normalizes a point with respect to the box whose corners are passed in
- * corners. The normalized coordinates are stored in *pX and *pY.
- */
-VOID
-FASTCALL
-PATH_NormalizePoint ( FLOAT_POINT corners[],
- const FLOAT_POINT *pPoint,
- double *pX, double *pY)
+BOOL
+STDCALL
+NtGdiEndPath(HDC hDC)
{
- ASSERT ( corners );
- ASSERT ( pPoint );
- ASSERT ( pX );
- ASSERT ( pY );
- *pX=(double)(pPoint->x-corners[0].x)/(double)(corners[1].x-corners[0].x) * 2.0 - 1.0;
- *pY=(double)(pPoint->y-corners[0].y)/(double)(corners[1].y-corners[0].y) * 2.0 - 1.0;
+ BOOL ret = TRUE;
+ PPATH pPath;
+ PDC dc = DC_LockDc ( hDC );
+
+ if ( !dc )
+ {
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+
+ pPath = PATH_LockPath( dc->DcLevel.hPath );
+ if (!pPath)
+ {
+ DC_UnlockDc ( dc );
+ return FALSE;
+ }
+ /* Check that path is currently being constructed */
+ if ( (pPath->state != PATH_Open) || !(dc->DcLevel.flPath & DCPATH_ACTIVE) )
+ {
+ DPRINT1("EndPath ERROR! 0x%x\n", dc->DcLevel.hPath);
+ SetLastWin32Error(ERROR_CAN_NOT_COMPLETE);
+ ret = FALSE;
+ }
+ /* Set flag to indicate that path is finished */
+ else
+ {
+ DPRINT1("EndPath 0x%x\n", dc->DcLevel.hPath);
+ pPath->state = PATH_Closed;
+ dc->DcLevel.flPath &= ~DCPATH_ACTIVE;
+ }
+ PATH_UnlockPath( pPath );
+ DC_UnlockDc ( dc );
+ return ret;
}
+BOOL
+STDCALL
+NtGdiFillPath(HDC hDC)
+{
+ BOOL ret = TRUE;
+ PPATH pPath;
+ PDC dc = DC_LockDc ( hDC );
+
+ if ( !dc )
+ {
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+ pPath = PATH_LockPath( dc->DcLevel.hPath );
+ if (!pPath)
+ {
+ DC_UnlockDc ( dc );
+ return FALSE;
+ }
-BOOL FASTCALL PATH_StrokePath(DC *dc, GdiPath *pPath)
+ ret = PATH_FillPath( dc, pPath );
+ if ( ret )
+ {
+ /* FIXME: Should the path be emptied even if conversion
+ failed? */
+ PATH_EmptyPath( pPath );
+ }
+
+ PATH_UnlockPath( pPath );
+ DC_UnlockDc ( dc );
+ return ret;
+}
+
+BOOL
+STDCALL
+NtGdiFlattenPath(HDC hDC)
{
- BOOL ret = FALSE;
- INT i=0;
- INT nLinePts, nAlloc;
- POINT *pLinePts = NULL;
- POINT ptViewportOrg, ptWindowOrg;
- SIZE szViewportExt, szWindowExt;
- DWORD mapMode, graphicsMode;
- XFORM xform;
- PDC_ATTR Dc_Attr = dc->pDc_Attr;
+ BOOL Ret = FALSE;
+ DC *pDc;
+ PPATH pPath;
- DPRINT("Enter %s\n", __FUNCTION__);
+ DPRINT("Enter %s\n", __FUNCTION__);
- if(pPath->state != PATH_Closed)
- return FALSE;
- if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
- /* Save the mapping mode info */
- mapMode = Dc_Attr->iMapMode;
- IntGetViewportExtEx(dc, &szViewportExt);
- IntGetViewportOrgEx(dc, &ptViewportOrg);
- IntGetWindowExtEx(dc, &szWindowExt);
- IntGetWindowOrgEx(dc, &ptWindowOrg);
- xform = dc->DcLevel.xformWorld2Wnd;
+ pDc = DC_LockDc(hDC);
+ if (!pDc)
+ {
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
- /* Set MM_TEXT */
- Dc_Attr->iMapMode = MM_TEXT;
- Dc_Attr->ptlViewportOrg.x = 0;
- Dc_Attr->ptlViewportOrg.y = 0;
- Dc_Attr->ptlWindowOrg.x = 0;
- Dc_Attr->ptlWindowOrg.y = 0;
- graphicsMode = Dc_Attr->iGraphicsMode;
- Dc_Attr->iGraphicsMode = GM_ADVANCED;
- IntGdiModifyWorldTransform(dc, &xform, MWT_IDENTITY);
- Dc_Attr->iGraphicsMode = graphicsMode;
+ pPath = PATH_LockPath( pDc->DcLevel.hPath );
+ if (!pPath)
+ {
+ DC_UnlockDc ( pDc );
+ return FALSE;
+ }
+ if (pPath->state == PATH_Open)
+ Ret = PATH_FlattenPath(pPath);
- /* Allocate enough memory for the worst case without beziers (one PT_MOVETO
- * and the rest PT_LINETO with PT_CLOSEFIGURE at the end) plus some buffer
- * space in case we get one to keep the number of reallocations small. */
- nAlloc = pPath->numEntriesUsed + 1 + 300;
- pLinePts = ExAllocatePoolWithTag(PagedPool, nAlloc * sizeof(POINT), TAG_PATH);
- if(!pLinePts)
- {
- DPRINT1("Can't allocate pool!\n");
- SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
- goto end;
- }
- nLinePts = 0;
+ PATH_UnlockPath( pPath );
+ DC_UnlockDc(pDc);
+ return Ret;
+}
- for(i = 0; i < pPath->numEntriesUsed; i++)
- {
- if((i == 0 || (pPath->pFlags[i-1] & PT_CLOSEFIGURE))
- && (pPath->pFlags[i] != PT_MOVETO))
- {
- DPRINT1("Expected PT_MOVETO %s, got path flag %d\n",
- i == 0 ? "as first point" : "after PT_CLOSEFIGURE",
- (INT)pPath->pFlags[i]);
- goto end;
- }
- switch(pPath->pFlags[i])
- {
- case PT_MOVETO:
- DPRINT("Got PT_MOVETO (%ld, %ld)\n",
- pPath->pPoints[i].x, pPath->pPoints[i].y);
- if(nLinePts >= 2) IntGdiPolyline(dc, pLinePts, nLinePts);
- nLinePts = 0;
- pLinePts[nLinePts++] = pPath->pPoints[i];
- break;
- case PT_LINETO:
- case (PT_LINETO | PT_CLOSEFIGURE):
- DPRINT("Got PT_LINETO (%ld, %ld)\n",
- pPath->pPoints[i].x, pPath->pPoints[i].y);
- pLinePts[nLinePts++] = pPath->pPoints[i];
- break;
- case PT_BEZIERTO:
- DPRINT("Got PT_BEZIERTO\n");
- if(pPath->pFlags[i+1] != PT_BEZIERTO ||
- (pPath->pFlags[i+2] & ~PT_CLOSEFIGURE) != PT_BEZIERTO)
- {
- DPRINT1("Path didn't contain 3 successive PT_BEZIERTOs\n");
- ret = FALSE;
- goto end;
- }
- else
- {
- INT nBzrPts, nMinAlloc;
- POINT *pBzrPts = GDI_Bezier(&pPath->pPoints[i-1], 4, &nBzrPts);
- /* Make sure we have allocated enough memory for the lines of
- * this bezier and the rest of the path, assuming we won't get
- * another one (since we won't reallocate again then). */
- nMinAlloc = nLinePts + (pPath->numEntriesUsed - i) + nBzrPts;
- if(nAlloc < nMinAlloc)
- {
- // Reallocate memory
+BOOL
+APIENTRY
+NtGdiGetMiterLimit(
+ IN HDC hdc,
+ OUT PDWORD pdwOut)
+{
+ DC *pDc;
+ gxf_long worker;
+ NTSTATUS Status = STATUS_SUCCESS;
- POINT *Realloc = NULL;
- nAlloc = nMinAlloc * 2;
+ if (!(pDc = DC_LockDc(hdc)))
+ {
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
- Realloc = ExAllocatePoolWithTag(PagedPool,
- nAlloc * sizeof(POINT),
- TAG_PATH);
+ worker.f = pDc->DcLevel.laPath.eMiterLimit;
- if(!Realloc)
- {
- DPRINT1("Can't allocate pool!\n");
- goto end;
- }
+ if (pdwOut)
+ {
+ _SEH_TRY
+ {
+ ProbeForWrite(pdwOut,
+ sizeof(DWORD),
+ 1);
+ *pdwOut = worker.l;
+ }
+ _SEH_HANDLE
+ {
+ Status = _SEH_GetExceptionCode();
+ }
+ _SEH_END;
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ DC_UnlockDc(pDc);
+ return FALSE;
+ }
+ }
- memcpy(Realloc, pLinePts, nLinePts*sizeof(POINT));
- ExFreePool(pLinePts);
- pLinePts = Realloc;
- }
- memcpy(&pLinePts[nLinePts], &pBzrPts[1], (nBzrPts - 1) * sizeof(POINT));
- nLinePts += nBzrPts - 1;
- ExFreePool(pBzrPts);
- i += 2;
- }
- break;
- default:
- DPRINT1("Got path flag %d (not supported)\n", (INT)pPath->pFlags[i]);
- goto end;
- }
+ DC_UnlockDc(pDc);
+ return TRUE;
- if(pPath->pFlags[i] & PT_CLOSEFIGURE)
- {
- pLinePts[nLinePts++] = pLinePts[0];
- }
- }//for
+}
- if(nLinePts >= 2)
- IntGdiPolyline(dc, pLinePts, nLinePts);
+INT
+STDCALL
+NtGdiGetPath(
+ HDC hDC,
+ LPPOINT Points,
+ LPBYTE Types,
+ INT nSize)
+{
+ INT ret = -1;
+ PPATH pPath;
- ret = TRUE;
+ DC *dc = DC_LockDc(hDC);
+ if (!dc)
+ {
+ DPRINT1("Can't lock dc!\n");
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ return -1;
+ }
-end:
- if(pLinePts)ExFreePool(pLinePts);
+ pPath = PATH_LockPath( dc->DcLevel.hPath );
+ if (!pPath)
+ {
+ DC_UnlockDc ( dc );
+ return -1;
+ }
- /* Restore the old mapping mode */
- Dc_Attr->iMapMode = mapMode;
- Dc_Attr->szlWindowExt.cx = szWindowExt.cx;
- Dc_Attr->szlWindowExt.cy = szWindowExt.cy;
- Dc_Attr->ptlWindowOrg.x = ptWindowOrg.x;
- Dc_Attr->ptlWindowOrg.y = ptWindowOrg.y;
+ if (pPath->state != PATH_Closed)
+ {
+ SetLastWin32Error(ERROR_CAN_NOT_COMPLETE);
+ goto done;
+ }
- Dc_Attr->szlViewportExt.cx = szViewportExt.cx;
- Dc_Attr->szlViewportExt.cy = szViewportExt.cy;
- Dc_Attr->ptlViewportOrg.x = ptViewportOrg.x;
- Dc_Attr->ptlViewportOrg.y = ptViewportOrg.y;
+ if (nSize==0)
+ {
+ ret = pPath->numEntriesUsed;
+ }
+ else if(nSize<pPath->numEntriesUsed)
+ {
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ goto done;
+ }
+ else
+ {
+ _SEH_TRY
+ {
+ memcpy(Points, pPath->pPoints, sizeof(POINT)*pPath->numEntriesUsed);
+ memcpy(Types, pPath->pFlags, sizeof(BYTE)*pPath->numEntriesUsed);
- /* Restore the world transform */
- dc->DcLevel.xformWorld2Wnd = xform;
+ /* Convert the points to logical coordinates */
+ IntDPtoLP(dc, Points, pPath->numEntriesUsed);
- /* If we've moved the current point then get its new position
- which will be in device (MM_TEXT) co-ords, convert it to
- logical co-ords and re-set it. This basically updates
- dc->CurPosX|Y so that their values are in the correct mapping
- mode.
- */
- if(i > 0)
- {
- POINT pt;
- IntGetCurrentPositionEx(dc, &pt);
- IntDPtoLP(dc, &pt, 1);
- IntGdiMoveToEx(dc, pt.x, pt.y, NULL);
- }
- DPRINT("Leave %s, ret=%d\n", __FUNCTION__, ret);
- return ret;
+ ret = pPath->numEntriesUsed;
+ }
+ _SEH_HANDLE
+ {
+ SetLastNtError(_SEH_GetExceptionCode());
+ }
+ _SEH_END
+ }
+
+done:
+ PATH_UnlockPath( pPath );
+ DC_UnlockDc(dc);
+ return ret;
+}
+
+HRGN
+STDCALL
+NtGdiPathToRegion(HDC hDC)
+{
+ PPATH pPath;
+ HRGN hrgnRval = 0;
+ DC *pDc;
+ PDC_ATTR Dc_Attr;
+
+ DPRINT("Enter %s\n", __FUNCTION__);
+
+ pDc = DC_LockDc(hDC);
+ if (!pDc)
+ {
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ return NULL;
+ }
+
+ Dc_Attr = pDc->pDc_Attr;
+ if(!Dc_Attr) Dc_Attr = &pDc->Dc_Attr;
+
+ pPath = PATH_LockPath( pDc->DcLevel.hPath );
+ if (!pPath)
+ {
+ DC_UnlockDc ( pDc );
+ return NULL;
+ }
+
+ if (pPath->state!=PATH_Closed)
+ {
+ //FIXME: check that setlasterror is being called correctly
+ SetLastWin32Error(ERROR_CAN_NOT_COMPLETE);
+ }
+ else
+ {
+ /* FIXME: Should we empty the path even if conversion failed? */
+ if(PATH_PathToRegion(pPath, Dc_Attr->jFillMode, &hrgnRval))
+ PATH_EmptyPath(pPath);
+ }
+
+ PATH_UnlockPath( pPath );
+ DC_UnlockDc(pDc);
+ return hrgnRval;
+}
+
+BOOL
+APIENTRY
+NtGdiSetMiterLimit(
+ IN HDC hdc,
+ IN DWORD dwNew,
+ IN OUT OPTIONAL PDWORD pdwOut)
+{
+ DC *pDc;
+ gxf_long worker, worker1;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ if (!(pDc = DC_LockDc(hdc)))
+ {
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ worker.l = dwNew;
+ worker1.f = pDc->DcLevel.laPath.eMiterLimit;
+ pDc->DcLevel.laPath.eMiterLimit = worker.f;
+
+ if (pdwOut)
+ {
+ _SEH_TRY
+ {
+ ProbeForWrite(pdwOut,
+ sizeof(DWORD),
+ 1);
+ *pdwOut = worker1.l;
+ }
+ _SEH_HANDLE
+ {
+ Status = _SEH_GetExceptionCode();
+ }
+ _SEH_END;
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ DC_UnlockDc(pDc);
+ return FALSE;
+ }
+ }
+
+ DC_UnlockDc(pDc);
+ return TRUE;
+}
+
+BOOL
+STDCALL
+NtGdiStrokeAndFillPath(HDC hDC)
+{
+ DC *pDc;
+ PPATH pPath;
+ BOOL bRet = FALSE;
+
+ DPRINT1("Enter %s\n", __FUNCTION__);
+
+ if (!(pDc = DC_LockDc(hDC)))
+ {
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+ pPath = PATH_LockPath( pDc->DcLevel.hPath );
+ if (!pPath)
+ {
+ DC_UnlockDc ( pDc );
+ return FALSE;
+ }
+ bRet = PATH_FillPath(pDc, pPath);
+ if (bRet) bRet = PATH_StrokePath(pDc, pPath);
+ if (bRet) PATH_EmptyPath(pPath);
+
+ PATH_UnlockPath( pPath );
+ DC_UnlockDc(pDc);
+ return bRet;
+}
+
+BOOL
+STDCALL
+NtGdiStrokePath(HDC hDC)
+{
+ DC *pDc;
+ PPATH pPath;
+ BOOL bRet = FALSE;
+
+ DPRINT("Enter %s\n", __FUNCTION__);
+
+ if (!(pDc = DC_LockDc(hDC)))
+ {
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+ pPath = PATH_LockPath( pDc->DcLevel.hPath );
+ if (!pPath)
+ {
+ DC_UnlockDc ( pDc );
+ return FALSE;
+ }
+
+ bRet = PATH_StrokePath(pDc, pPath);
+ PATH_EmptyPath(pPath);
+
+ PATH_UnlockPath( pPath );
+ DC_UnlockDc(pDc);
+ return bRet;
+}
+
+BOOL
+STDCALL
+NtGdiWidenPath(HDC hDC)
+{
+ BOOL Ret;
+ PDC pdc = DC_LockDc ( hDC );
+ if ( !pdc )
+ {
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+ Ret = PATH_WidenPath(pdc);
+ DC_UnlockDc ( pdc );
+ return Ret;
+}
+
+BOOL
+STDCALL
+NtGdiSelectClipPath(HDC hDC,
+ int Mode)
+{
+ HRGN hrgnPath;
+ PPATH pPath;
+ BOOL success = FALSE;
+ PDC_ATTR Dc_Attr;
+ PDC dc = DC_LockDc ( hDC );
+
+ if ( !dc )
+ {
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ Dc_Attr = dc->pDc_Attr;
+ if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
+
+ pPath = PATH_LockPath( dc->DcLevel.hPath );
+ if (!pPath)
+ {
+ DC_UnlockDc ( dc );
+ return FALSE;
+ }
+ /* Check that path is closed */
+ if( pPath->state != PATH_Closed )
+ {
+ SetLastWin32Error(ERROR_CAN_NOT_COMPLETE);
+ return FALSE;
+ }
+ /* Construct a region from the path */
+ else if( PATH_PathToRegion( pPath, Dc_Attr->jFillMode, &hrgnPath ) )
+ {
+ success = GdiExtSelectClipRgn( dc, hrgnPath, Mode ) != ERROR;
+ NtGdiDeleteObject( hrgnPath );
+
+ /* Empty the path */
+ if( success )
+ PATH_EmptyPath( pPath);
+ /* FIXME: Should this function delete the path even if it failed? */
+ }
+ PATH_UnlockPath( pPath );
+ DC_UnlockDc ( dc );
+ return success;
}
/* EOF */