You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
616 lines
18 KiB
616 lines
18 KiB
/*****************************************************************************
|
|
*
|
|
* conics - Entry points for Win32 to Win 16 converter
|
|
*
|
|
* Date: 7/1/91
|
|
* Author: Jeffrey Newman (c-jeffn)
|
|
*
|
|
* Copyright 1991 Microsoft Corp
|
|
*****************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
|
|
FLOAT eRadsPerDegree = (FLOAT) (ePI / (FLOAT) 180.0) ;
|
|
|
|
BOOL bFindRadialEllipseIntersection(PLOCALDC pLocalDC,
|
|
INT x1, INT y1, INT x2, INT y2,
|
|
INT x3, INT y3, INT x4, INT y4,
|
|
PPOINT pptStart, PPOINT pptEnd) ;
|
|
|
|
BOOL bIncIncToIncExcXform (PLOCALDC pLocalDC, PRECTL prcl) ;
|
|
|
|
VOID vDoArcReflection(PLOCALDC pLocalDC, PPOINTL pptl) ;
|
|
|
|
|
|
/***************************************************************************
|
|
* DoSetArcDirection - Win32 to Win16 Metafile Converter Entry Point
|
|
**************************************************************************/
|
|
BOOL WINAPI DoSetArcDirection(PLOCALDC pLocalDC, INT iArcDirection)
|
|
{
|
|
pLocalDC->iArcDirection = iArcDirection ;
|
|
|
|
return(SetArcDirection(pLocalDC->hdcHelper, iArcDirection) != 0);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
* AngleArc - Win32 to Win16 Metafile Converter Entry Point
|
|
**************************************************************************/
|
|
BOOL WINAPI DoAngleArc
|
|
(
|
|
PLOCALDC pLocalDC,
|
|
int x,
|
|
int y,
|
|
DWORD ulRadius,
|
|
FLOAT eStartAngle,
|
|
FLOAT eSweepAngle
|
|
)
|
|
{
|
|
BOOL b ;
|
|
POINTL aptl[4] ;
|
|
FLOAT eEndAngle;
|
|
INT iArcDirection;
|
|
|
|
// If we're recording the drawing orders for a path
|
|
// then just pass the drawing order to the helper DC.
|
|
// Do not emit any Win16 drawing orders.
|
|
|
|
if (pLocalDC->flags & RECORDING_PATH)
|
|
{
|
|
b = AngleArc(pLocalDC->hdcHelper, x, y, ulRadius, eStartAngle, eSweepAngle) ;
|
|
ASSERTGDI(b, "MF3216: DoAngleArc, in path render failed\n") ;
|
|
return(b) ;
|
|
}
|
|
|
|
// Do the transformations.
|
|
// And emit the Win16 drawing orders.
|
|
|
|
if (pLocalDC->flags & STRANGE_XFORM
|
|
|| eSweepAngle > 360.0f // more than one revolution
|
|
|| eSweepAngle < -360.0f
|
|
)
|
|
{
|
|
b = bRenderCurveWithPath(pLocalDC, (LPPOINT) NULL, (PBYTE) NULL, 0,
|
|
x, y, 0, 0, 0, 0, 0, 0,
|
|
ulRadius, eStartAngle, eSweepAngle, EMR_ANGLEARC);
|
|
|
|
return(b);
|
|
}
|
|
|
|
// Calculate the ARC bounding box.
|
|
|
|
aptl[0].x = x - ulRadius ;
|
|
aptl[0].y = y - ulRadius ;
|
|
aptl[1].x = x + ulRadius ;
|
|
aptl[1].y = y + ulRadius ;
|
|
|
|
// Calculate the begin and end points for ARC from the
|
|
// eStartAngle and eSweepAngle.
|
|
|
|
aptl[2].x = x + (LONG) ((double) (ulRadius) * cos(eStartAngle * eRadsPerDegree) + 0.5f) ;
|
|
aptl[2].y = y - (LONG) ((double) (ulRadius) * sin(eStartAngle * eRadsPerDegree) + 0.5f) ;
|
|
|
|
eEndAngle = eStartAngle + eSweepAngle ;
|
|
|
|
aptl[3].x = x + (LONG) ((double) (ulRadius) * cos(eEndAngle * eRadsPerDegree) + 0.5f) ;
|
|
aptl[3].y = y - (LONG) ((double) (ulRadius) * sin(eEndAngle * eRadsPerDegree) + 0.5f) ;
|
|
|
|
// If the endpoints are identical, we cannot represent the AngleArc as
|
|
// an ArcTo. Use path to render it instead.
|
|
|
|
if (aptl[2].x == aptl[3].x && aptl[2].y == aptl[3].y)
|
|
{
|
|
b = bRenderCurveWithPath(pLocalDC, (LPPOINT) NULL, (PBYTE) NULL, 0,
|
|
x, y, 0, 0, 0, 0, 0, 0,
|
|
ulRadius, eStartAngle, eSweepAngle, EMR_ANGLEARC);
|
|
|
|
return(b);
|
|
}
|
|
|
|
// At this point we have the same parameters that would apply to
|
|
// a standard ArcTo. However, we still need to determine the arc
|
|
// direction to apply. If the sweep angle is positive, it is counter-
|
|
// clockwise. If the sweep angle is negative, it is clockwise.
|
|
|
|
// Save the current arc direction.
|
|
|
|
iArcDirection = pLocalDC->iArcDirection;
|
|
|
|
// Prepare the arc direction for the ArcTo.
|
|
|
|
(void) DoSetArcDirection
|
|
(pLocalDC, eSweepAngle < 0.0f ? AD_CLOCKWISE : AD_COUNTERCLOCKWISE);
|
|
|
|
// Do the ArcTo.
|
|
|
|
b = DoArcTo(pLocalDC, aptl[0].x, aptl[0].y, aptl[1].x, aptl[1].y,
|
|
aptl[2].x, aptl[2].y, aptl[3].x, aptl[3].y) ;
|
|
|
|
// Restore the current arc direction.
|
|
|
|
(void) DoSetArcDirection(pLocalDC, iArcDirection);
|
|
|
|
return (b) ;
|
|
}
|
|
|
|
/***************************************************************************
|
|
* Arc - Win32 to Win16 Metafile Converter Entry Point
|
|
**************************************************************************/
|
|
BOOL WINAPI DoArc
|
|
(
|
|
PLOCALDC pLocalDC,
|
|
int x1,
|
|
int y1,
|
|
int x2,
|
|
int y2,
|
|
int x3,
|
|
int y3,
|
|
int x4,
|
|
int y4
|
|
)
|
|
{
|
|
BOOL b ;
|
|
|
|
b = bConicCommon (pLocalDC, x1, y1, x2, y2, x3, y3, x4, y4, EMR_ARC) ;
|
|
|
|
return(b) ;
|
|
}
|
|
|
|
/***************************************************************************
|
|
* ArcTo - Win32 to Win16 Metafile Converter Entry Point
|
|
**************************************************************************/
|
|
BOOL WINAPI DoArcTo
|
|
(
|
|
PLOCALDC pLocalDC,
|
|
int x1,
|
|
int y1,
|
|
int x2,
|
|
int y2,
|
|
int x3,
|
|
int y3,
|
|
int x4,
|
|
int y4
|
|
)
|
|
{
|
|
BOOL b ;
|
|
POINT ptStart,
|
|
ptEnd ;
|
|
|
|
// If we're recording the drawing orders for a path
|
|
// then just pass the drawing order to the helper DC.
|
|
// Do not emit any Win16 drawing orders.
|
|
|
|
if (pLocalDC->flags & RECORDING_PATH)
|
|
{
|
|
b = ArcTo(pLocalDC->hdcHelper, x1, y1, x2, y2, x3, y3, x4, y4) ;
|
|
return(b) ;
|
|
}
|
|
|
|
|
|
b = bFindRadialEllipseIntersection(pLocalDC,
|
|
x1, y1, x2, y2,
|
|
x3, y3, x4, y4,
|
|
&ptStart, &ptEnd) ;
|
|
if (b == FALSE)
|
|
return(b) ;
|
|
|
|
b = DoLineTo(pLocalDC, ptStart.x, ptStart.y) ;
|
|
if (b == FALSE)
|
|
return(b) ;
|
|
|
|
b = DoArc(pLocalDC, x1, y1, x2, y2, x3, y3, x4, y4) ;
|
|
if (b == FALSE)
|
|
return(b) ;
|
|
|
|
b = DoMoveTo(pLocalDC, ptEnd.x, ptEnd.y) ;
|
|
|
|
return(b) ;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
* Chord - Win32 to Win16 Metafile Converter Entry Point
|
|
**************************************************************************/
|
|
BOOL WINAPI DoChord
|
|
(
|
|
PLOCALDC pLocalDC,
|
|
int x1,
|
|
int y1,
|
|
int x2,
|
|
int y2,
|
|
int x3,
|
|
int y3,
|
|
int x4,
|
|
int y4
|
|
)
|
|
{
|
|
BOOL b ;
|
|
|
|
b = bConicCommon (pLocalDC, x1, y1, x2, y2, x3, y3, x4, y4, EMR_CHORD) ;
|
|
|
|
return(b) ;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
* Ellipse - Win32 to Win16 Metafile Converter Entry Point
|
|
**************************************************************************/
|
|
BOOL WINAPI DoEllipse
|
|
(
|
|
PLOCALDC pLocalDC,
|
|
int x1,
|
|
int y1,
|
|
int x2,
|
|
int y2
|
|
)
|
|
{
|
|
BOOL b ;
|
|
|
|
b = bConicCommon (pLocalDC, x1, y1, x2, y2, 0, 0, 0, 0, EMR_ELLIPSE) ;
|
|
|
|
return(b) ;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
* Pie - Win32 to Win16 Metafile Converter Entry Point
|
|
**************************************************************************/
|
|
BOOL WINAPI DoPie
|
|
(
|
|
PLOCALDC pLocalDC,
|
|
int x1,
|
|
int y1,
|
|
int x2,
|
|
int y2,
|
|
int x3,
|
|
int y3,
|
|
int x4,
|
|
int y4
|
|
)
|
|
{
|
|
BOOL b ;
|
|
|
|
b = bConicCommon (pLocalDC, x1, y1, x2, y2, x3, y3, x4, y4, EMR_PIE) ;
|
|
|
|
return(b) ;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
* bConicCommon - The mother of all conic translations.
|
|
* They are Arc, Chord, Pie, Ellipse, Rectangle and RoundRect.
|
|
**************************************************************************/
|
|
BOOL bConicCommon (PLOCALDC pLocalDC, INT x1, INT y1, INT x2, INT y2,
|
|
INT x3, INT y3, INT x4, INT y4,
|
|
DWORD mrType)
|
|
{
|
|
SHORT sx1, sx2, sx3, sx4,
|
|
sy1, sy2, sy3, sy4 ;
|
|
LONG nPointls ;
|
|
POINTL aptl[4] ;
|
|
BOOL b ;
|
|
|
|
// If we're recording the drawing orders for a path
|
|
// then just pass the drawing order to the helper DC.
|
|
// Do not emit any Win16 drawing orders.
|
|
|
|
if (pLocalDC->flags & RECORDING_PATH)
|
|
{
|
|
switch(mrType)
|
|
{
|
|
case EMR_ARC:
|
|
b = Arc(pLocalDC->hdcHelper, x1, y1, x2, y2,
|
|
x3, y3, x4, y4) ;
|
|
break ;
|
|
|
|
case EMR_CHORD:
|
|
b = Chord(pLocalDC->hdcHelper, x1, y1, x2, y2,
|
|
x3, y3, x4, y4) ;
|
|
break ;
|
|
|
|
case EMR_ELLIPSE:
|
|
b = Ellipse(pLocalDC->hdcHelper, x1, y1, x2, y2) ;
|
|
break ;
|
|
|
|
case EMR_PIE:
|
|
b = Pie(pLocalDC->hdcHelper, x1, y1, x2, y2,
|
|
x3, y3, x4, y4) ;
|
|
break ;
|
|
|
|
case EMR_RECTANGLE:
|
|
b = Rectangle(pLocalDC->hdcHelper, x1, y1, x2, y2) ;
|
|
break ;
|
|
|
|
case EMR_ROUNDRECT:
|
|
b = RoundRect(pLocalDC->hdcHelper, x1, y1, x2, y2, x3, y3) ;
|
|
break ;
|
|
|
|
default:
|
|
b = FALSE;
|
|
RIP("MF3216: bConicCommon, bad mrType");
|
|
break ;
|
|
}
|
|
|
|
ASSERTGDI(b, "MF3216: bConicCommon, in path render failed\n") ;
|
|
return(b) ;
|
|
}
|
|
|
|
// Do the transformations.
|
|
// And emit the Win16 drawing orders.
|
|
|
|
if (pLocalDC->flags & STRANGE_XFORM)
|
|
{
|
|
b = bRenderCurveWithPath(pLocalDC, (LPPOINT) NULL, (PBYTE) NULL, 0,
|
|
x1, y1, x2, y2, x3, y3, x4, y4, 0, 0.0f, 0.0f, mrType);
|
|
|
|
return(b);
|
|
}
|
|
|
|
// Do the simple transform case.
|
|
|
|
// Compute the number of points
|
|
|
|
nPointls = (LONG) (sizeof(aptl) / sizeof(POINTL)) ;
|
|
|
|
// Assign all the coordinates into an array for conversion.
|
|
|
|
aptl[0].x = x1 ;
|
|
aptl[0].y = y1 ;
|
|
aptl[1].x = x2 ;
|
|
aptl[1].y = y2 ;
|
|
aptl[2].x = x3 ;
|
|
aptl[2].y = y3 ;
|
|
aptl[3].x = x4 ;
|
|
aptl[3].y = y4 ;
|
|
|
|
// Take care of the arc direction.
|
|
|
|
switch (mrType)
|
|
{
|
|
case EMR_ARC:
|
|
case EMR_CHORD:
|
|
case EMR_PIE:
|
|
vDoArcReflection(pLocalDC, &aptl[2]) ;
|
|
break ;
|
|
|
|
default:
|
|
break ;
|
|
}
|
|
|
|
// Do the Record-time World to Play-time Page transformations.
|
|
// The radial definitions need only a world to page xform,
|
|
// and the ellipse definitions for roundrects only require
|
|
// a magnitude transformation.
|
|
|
|
if (mrType != EMR_ROUNDRECT)
|
|
{
|
|
b = bXformRWorldToPPage(pLocalDC, (PPOINTL) aptl, nPointls) ;
|
|
if (!b)
|
|
goto exit1 ;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
For roundrects do a Record-time-World to Play-time-Page
|
|
transform of the bounding box only. Then a magnatude only
|
|
transform of the corner ellipse definitions.
|
|
*/
|
|
|
|
b = bXformRWorldToPPage(pLocalDC, (PPOINTL) aptl, 2) ;
|
|
if (!b)
|
|
goto exit1 ;
|
|
|
|
aptl[2].x = iMagnitudeXform(pLocalDC, aptl[2].x, CX_MAG) ;
|
|
aptl[2].y = iMagnitudeXform(pLocalDC, aptl[2].y, CY_MAG) ;
|
|
aptl[3].x = iMagnitudeXform(pLocalDC, aptl[3].x, CX_MAG) ;
|
|
aptl[3].y = iMagnitudeXform(pLocalDC, aptl[3].y, CY_MAG) ;
|
|
}
|
|
|
|
// The bounding boxes for
|
|
// all the conics and rectangles that are handled by this
|
|
// common routine are inclusive-inclusive, and they must
|
|
// be transformed to the inclusive-exclusive Win16 form.
|
|
|
|
b = bIncIncToIncExcXform(pLocalDC, (PRECTL) &aptl[0]) ;
|
|
if (!b)
|
|
goto exit1 ;
|
|
|
|
// Assign the converted coordinates variables suited to
|
|
// the Win16 metafile.
|
|
|
|
sx1 = LOWORD(aptl[0].x) ;
|
|
sy1 = LOWORD(aptl[0].y) ;
|
|
sx2 = LOWORD(aptl[1].x) ;
|
|
sy2 = LOWORD(aptl[1].y) ;
|
|
sx3 = LOWORD(aptl[2].x) ;
|
|
sy3 = LOWORD(aptl[2].y) ;
|
|
sx4 = LOWORD(aptl[3].x) ;
|
|
sy4 = LOWORD(aptl[3].y) ;
|
|
|
|
// Emit the Win16 drawing orders to the Win16 metafile.
|
|
|
|
switch(mrType)
|
|
{
|
|
case EMR_ARC:
|
|
b = bEmitWin16Arc(pLocalDC, sx1, sy1, sx2, sy2,
|
|
sx3, sy3, sx4, sy4) ;
|
|
break ;
|
|
|
|
case EMR_CHORD:
|
|
b = bEmitWin16Chord(pLocalDC, sx1, sy1, sx2, sy2,
|
|
sx3, sy3, sx4, sy4) ;
|
|
break ;
|
|
|
|
case EMR_ELLIPSE:
|
|
b = bEmitWin16Ellipse(pLocalDC, sx1, sy1, sx2, sy2) ;
|
|
break ;
|
|
|
|
case EMR_PIE:
|
|
b = bEmitWin16Pie(pLocalDC, sx1, sy1, sx2, sy2,
|
|
sx3, sy3, sx4, sy4) ;
|
|
break ;
|
|
|
|
case EMR_RECTANGLE:
|
|
b = bEmitWin16Rectangle(pLocalDC, sx1, sy1, sx2, sy2) ;
|
|
break ;
|
|
|
|
case EMR_ROUNDRECT:
|
|
b = bEmitWin16RoundRect(pLocalDC, sx1, sy1, sx2, sy2, sx3, sy3) ;
|
|
break ;
|
|
|
|
default:
|
|
RIP("MF3216: bConicCommon, bad mrType");
|
|
break ;
|
|
}
|
|
|
|
exit1:
|
|
return (b) ;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
* vDoArcReflection - Test for an inversion in the RWorld to PPage matrix.
|
|
* If one and only one is found then swap the start
|
|
* and end position for the conics.
|
|
*****************************************************************************/
|
|
VOID vDoArcReflection(PLOCALDC pLocalDC, PPOINTL pptl)
|
|
{
|
|
FLOAT eM11,
|
|
eM22 ;
|
|
POINTL ptl ;
|
|
BOOL bFlip ;
|
|
|
|
// Win16 assumes the counter-clockwise arc direction in the
|
|
// device coordinates. Win32 defines the arc direction in the
|
|
// world coordinates.
|
|
|
|
// Assume no flipping of start and end points.
|
|
|
|
bFlip = FALSE ;
|
|
|
|
// Account for current arc direction.
|
|
|
|
if (pLocalDC->iArcDirection == AD_CLOCKWISE)
|
|
bFlip = !bFlip;
|
|
|
|
// If there is an inversion in the xform matrix then invert
|
|
// the arc direction.
|
|
|
|
eM11 = pLocalDC->xformRWorldToPPage.eM11 ;
|
|
eM22 = pLocalDC->xformRWorldToPPage.eM22 ;
|
|
|
|
if ( (eM11 < 0.0f && eM22 > 0.0f)
|
|
||(eM11 > 0.0f && eM22 < 0.0f)
|
|
)
|
|
bFlip = !bFlip;
|
|
|
|
// If the REQUESTED Win16 mapmode is fixed, then invert the
|
|
// arc direction.
|
|
|
|
switch(pLocalDC->iMapMode)
|
|
{
|
|
case MM_LOMETRIC:
|
|
case MM_HIMETRIC:
|
|
case MM_LOENGLISH:
|
|
case MM_HIENGLISH:
|
|
case MM_TWIPS:
|
|
bFlip = !bFlip;
|
|
break ;
|
|
}
|
|
|
|
if (bFlip)
|
|
SWAP(pptl[0], pptl[1], ptl);
|
|
|
|
return ;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
* bIncIncToIncExcXform - Inclusize Inclusive To Inclusive Exclusize
|
|
* transform in play time coordinate space.
|
|
*****************************************************************************/
|
|
BOOL bIncIncToIncExcXform (PLOCALDC pLocalDC, PRECTL prcl)
|
|
{
|
|
LONG l;
|
|
|
|
// Convert the points from Playtime Page to Playtime Device space.
|
|
|
|
if (!bXformPPageToPDev(pLocalDC, (PPOINTL) prcl, 2))
|
|
return(FALSE);
|
|
|
|
// Reorder the rectangle
|
|
|
|
if (prcl->left > prcl->right)
|
|
SWAP(prcl->left, prcl->right, l);
|
|
|
|
if (prcl->top > prcl->bottom)
|
|
SWAP(prcl->top, prcl->bottom, l);
|
|
|
|
// Expand the right and bottom by one pixel.
|
|
|
|
prcl->right++ ;
|
|
prcl->bottom++ ;
|
|
|
|
// Convert the points back to Playtime Page space
|
|
|
|
return(bXformPDevToPPage(pLocalDC, (PPOINTL) prcl, 2));
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
* bFindRadialEllipseIntersection - Calculate the intersection of a radial
|
|
* and an Ellipse.
|
|
*
|
|
* Play the ArcTo into a path then query the path for the first and
|
|
* last points on the Arc.
|
|
*****************************************************************************/
|
|
BOOL bFindRadialEllipseIntersection(PLOCALDC pLocalDC,
|
|
INT x1, INT y1, INT x2, INT y2,
|
|
INT x3, INT y3, INT x4, INT y4,
|
|
LPPOINT pptStart, LPPOINT pptEnd)
|
|
{
|
|
BOOL b;
|
|
POINT ptCP;
|
|
|
|
b = FALSE; // assume failure
|
|
|
|
// Save the current position in the helper DC.
|
|
|
|
if (!GetCurrentPositionEx(pLocalDC->hdcHelper, &ptCP))
|
|
return(FALSE);
|
|
|
|
// Do an ArcTo with the same start radial line.
|
|
|
|
if (!ArcTo(pLocalDC->hdcHelper, x1, y1, x2, y2, x3, y3, x3, y3))
|
|
goto exit_bFindRadialEllipseIntersection;
|
|
|
|
// Get the start point of the arc. It is the current position.
|
|
|
|
if (!GetCurrentPositionEx(pLocalDC->hdcHelper, pptStart))
|
|
goto exit_bFindRadialEllipseIntersection;
|
|
|
|
// Continue with the ArcTo with the same end radial line this time.
|
|
|
|
if (!ArcTo(pLocalDC->hdcHelper, x1, y1, x2, y2, x4, y4, x4, y4))
|
|
goto exit_bFindRadialEllipseIntersection;
|
|
|
|
// Get the end point of the arc. It is the current position.
|
|
|
|
if (!GetCurrentPositionEx(pLocalDC->hdcHelper, pptEnd))
|
|
goto exit_bFindRadialEllipseIntersection;
|
|
|
|
// Everything is golden.
|
|
|
|
b = TRUE;
|
|
|
|
exit_bFindRadialEllipseIntersection:
|
|
|
|
// Restore the current position in the helper DC.
|
|
|
|
if (!MoveToEx(pLocalDC->hdcHelper, ptCP.x, ptCP.y, (LPPOINT) NULL))
|
|
RIP("MF3216: bFindRadialEllipseIntersection, MoveToEx failed");
|
|
|
|
return(b);
|
|
}
|