⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 path.c

📁 这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统
💻 C
📖 第 1 页 / 共 3 页
字号:
 *
 * 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 )
{
  POINT point, pointCurPos;

  /* Check that path is open */
  if ( dc->w.path.state != PATH_Open )
    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 )
  {
    dc->w.path.newStroke = FALSE;
    IntGetCurrentPositionEx ( dc, &pointCurPos );
    CoordLPtoDP ( dc, &pointCurPos );
    if ( !PATH_AddEntry(&dc->w.path, &pointCurPos, PT_MOVETO) )
      return FALSE;
  }

  /* Add a PT_LINETO entry */
  return PATH_AddEntry(&dc->w.path, &point, PT_LINETO);
}

/* 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 )
{
  POINT corners[2], pointTemp;
  INT   temp;

  /* Check that path is open */
  if ( dc->w.path.state != PATH_Open )
    return FALSE;

  /* 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 );

  /* 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 ( IntGetGraphicsMode(dc) == GM_COMPATIBLE )
  {
    corners[1].x--;
    corners[1].y--;
  }

  /* Close any previous figure */
  IntGdiCloseFigure(dc);

  /* 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;

  /* Close the rectangle figure */
  IntGdiCloseFigure(dc) ;
  
  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()
 */
FASTCALL BOOL PATH_RoundRect(DC *dc, INT x1, INT y1, INT x2, INT y2, INT ell_width, INT ell_height)
{
   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;

   if(!PATH_CheckCorners(dc,corners,x1,y1,x2,y2))
      return FALSE;

   /* 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;

   IntGdiCloseFigure(dc);

   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
FASTCALL
PATH_Ellipse ( PDC dc, 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;
}

/* 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,
 * 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)
{
  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;

  /* FIXME: This function should check for all possible error returns */
  /* FIXME: Do we have to respect newStroke? */

  ASSERT ( dc );

  clockwise = ( dc->w.ArcDirection == AD_CLOCKWISE );

  /* Check that path is open */
  if ( dc->w.path.state != PATH_Open )
    return FALSE;

  /* FIXME: Do we have to close the current figure? */

  /* 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);

  /* 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;
  }

  /* 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 )
  {
    if ( angleEnd <= angleStart )
    {
      angleEnd+=2*M_PI;
      ASSERT(angleEnd>=angleStart);
    }
  }
  else
  {
    if(angleEnd>=angleStart)
    {
      angleEnd-=2*M_PI;
      ASSERT(angleEnd<=angleStart);
    }
  }

  /* In GM_COMPATIBLE, don't include bottom and right edges */
  if ( IntGetGraphicsMode(dc) == GM_COMPATIBLE )
  {
    corners[1].x--;
    corners[1].y--;
  }

  /* 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;
    }

    /* 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;
    }

    /* Add the Bezier spline to the path */
    PATH_DoArcPart ( &dc->w.path, corners, angleStartQuadrant, angleEndQuadrant, start );
    start = FALSE;
  } while(!end);

  /* 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, &centre, PT_LINETO | PT_CLOSEFIGURE))
         return FALSE;
   }

  return TRUE;
}

BOOL
FASTCALL
PATH_PolyBezierTo ( PDC dc, const POINT *pts, DWORD cbPoints )
{
  POINT pt;
  ULONG i;

  ASSERT ( dc );
  ASSERT ( pts );
  ASSERT ( cbPoints );

  /* 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;
}

BOOL
FASTCALL
PATH_PolyBezier ( PDC dc, const POINT *pts, DWORD cbPoints )
{
  POINT   pt;
  ULONG   i;

  ASSERT ( dc );
  ASSERT ( pts );
  ASSERT ( cbPoints );

   /* Check that path is open */
  if ( dc->w.path.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;
}

BOOL
FASTCALL
PATH_Polyline ( PDC dc, const POINT *pts, DWORD cbPoints )
{
  POINT   pt;
  ULONG   i;

  ASSERT ( dc );
  ASSERT ( pts );
  ASSERT ( cbPoints );

  /* Check that path is open */
  if ( dc->w.path.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_LINETO);
  }
  return TRUE;
}

BOOL
FASTCALL
PATH_PolylineTo ( PDC dc, const POINT *pts, DWORD cbPoints )
{
  POINT   pt;
  ULONG   i;

  ASSERT ( dc );
  ASSERT ( pts );
  ASSERT ( cbPoints );

  /* 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_LINETO);
  }

  return TRUE;
}


BOOL
FASTCALL
PATH_Polygon ( PDC dc, const POINT *pts, DWORD cbPoints )
{
  POINT   pt;
  ULONG   i;

  ASSERT ( dc );
  ASSERT ( pts );

  /* Check that path is open */
  if ( dc->w.path.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 :
      ((i == cbPoints-1) ? PT_LINETO | PT_CLOSEFIGURE :
      PT_LINETO));
  }
  return TRUE;
}

BOOL
FASTCALL
PATH_PolyPolygon ( PDC dc, const POINT* pts, const INT* counts, UINT polygons )
{
  POINT   pt, startpt;
  ULONG   poly, point, i;

  ASSERT ( dc );
  ASSERT ( pts );
  ASSERT ( counts );
  ASSERT ( polygons );

  /* Check that path is open */
  if ( dc->w.path.state != PATH_Open );
    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(&dc->w.path, &pt, (point == 0) ? PT_MOVETO : PT_LINETO);
    }
    /* 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;

  for(i = 0, poly = 0; poly < polylines; poly++)
  {
    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);
    }
  }
  return TRUE;
}

/***********************************************************************
 * Internal functions
 */

/* PATH_CheckCorners
 *
 * Helper function for PATH_RoundRect() and PATH_Rectangle()
 */
BOOL PATH_CheckCorners(DC *dc, POINT corners[], INT x1, INT y1, INT x2, INT y2)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -