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.
858 lines
20 KiB
858 lines
20 KiB
/**************************************************************************\
|
|
*
|
|
* Copyright (c) 1999 Microsoft Corporation
|
|
*
|
|
* Abstract:
|
|
*
|
|
* Implementation of XBezier class and its DDA.
|
|
*
|
|
* History:
|
|
*
|
|
* 11/08/1999 ikkof
|
|
* Created it.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.hpp"
|
|
|
|
// Path types used for advanced path.
|
|
|
|
// !!! [asecchia]
|
|
// this is a very clumsy hack to enable the XPath stuff to work.
|
|
// we should have an internal set of enum values that are different
|
|
// from the external ones.
|
|
|
|
#define PathPointTypeBezier2 2 // quadratic Beizer
|
|
#define PathPointTypeBezier4 4 // quartic (4th order) Beizer
|
|
#define PathPointTypeBezier5 5 // quintic (5th order) Bezier
|
|
#define PathPointTypeBezier6 6 // hexaic (6th order) Bezier
|
|
|
|
|
|
|
|
GpXPath::GpXPath(const GpPath* path)
|
|
{
|
|
InitDefaultState();
|
|
|
|
if(!path || !path->IsValid())
|
|
return;
|
|
|
|
INT count = path->GetPointCount();
|
|
const GpPointF *pts = ((GpPath*) path)->GetPathPoints();
|
|
const BYTE *types = ((GpPath*) path)->GetPathTypes();
|
|
|
|
if(pts && types && count > 0)
|
|
{
|
|
Types = (BYTE*) GpMalloc(count);
|
|
XPoints.Count = count;
|
|
XPoints.Dimension = 2;
|
|
XPoints.Data = (REALD*) GpMalloc(2*count*sizeof(REALD));
|
|
XPoints.IsDataAllocated = TRUE;
|
|
|
|
if(Types && XPoints.Data)
|
|
{
|
|
GpMemcpy(Types, types, count);
|
|
REALD* data = XPoints.Data;
|
|
for(INT i = 0; i < count; i++)
|
|
{
|
|
*data++ = pts->X;
|
|
*data++ = pts->Y;
|
|
pts++;
|
|
}
|
|
SetValid(TRUE);
|
|
}
|
|
FillMode = ((GpPath*) path)->GetFillMode();
|
|
}
|
|
}
|
|
|
|
GpXPath::GpXPath(
|
|
const GpPath* path,
|
|
const GpRectF& rect,
|
|
const GpPointF* points,
|
|
INT count,
|
|
WarpMode warpMode
|
|
)
|
|
{
|
|
InitDefaultState();
|
|
|
|
if(warpMode == WarpModePerspective)
|
|
ConvertToPerspectivePath(path, rect, points, count);
|
|
else if(warpMode == WarpModeBilinear)
|
|
ConvertToBilinearPath(path, rect, points, count);
|
|
}
|
|
|
|
GpStatus
|
|
GpXPath::ConvertToPerspectivePath(
|
|
const GpPath* path,
|
|
const GpRectF& rect,
|
|
const GpPointF* points,
|
|
INT count
|
|
)
|
|
{
|
|
ASSERT(path && path->IsValid());
|
|
|
|
if(!path || !path->IsValid())
|
|
return InvalidParameter;
|
|
|
|
// Obtain the path points.
|
|
|
|
const GpPointF* pathPts = ((GpPath*) path)->GetPathPoints();
|
|
const BYTE* pathTypes = ((GpPath*) path)->GetPathTypes();
|
|
INT pathCount = path->GetPointCount();
|
|
|
|
BYTE* types = (BYTE*) GpMalloc(pathCount);
|
|
|
|
if(!types)
|
|
return OutOfMemory;
|
|
|
|
GpMemcpy(types, pathTypes, pathCount);
|
|
|
|
// Set the perspective transform.
|
|
|
|
GpPerspectiveTransform trans(rect, points, count);
|
|
|
|
// Convert the path points to 3D perspective points.
|
|
|
|
REALD* data = (REALD*) GpMalloc(3*pathCount*sizeof(REALD));
|
|
|
|
if(!data)
|
|
return OutOfMemory;
|
|
|
|
// Use this data for xpoints.
|
|
|
|
XPoints.Count = pathCount;
|
|
XPoints.Dimension = 3;
|
|
XPoints.Data = data;
|
|
XPoints.IsDataAllocated = TRUE;
|
|
|
|
Types = types;
|
|
GpStatus status = trans.ConvertPoints(pathPts, pathCount, &XPoints);
|
|
|
|
if(status == Ok)
|
|
SetValid(TRUE);
|
|
|
|
return status;
|
|
}
|
|
|
|
GpStatus
|
|
GpXPath::ConvertToBilinearPath(
|
|
const GpPath* path,
|
|
const GpRectF& rect,
|
|
const GpPointF* points,
|
|
INT count
|
|
)
|
|
{
|
|
ASSERT(path && path->IsValid());
|
|
|
|
if(!path || !path->IsValid())
|
|
return InvalidParameter;
|
|
|
|
// Obtain the path points.
|
|
|
|
const GpPointF* pathPts = ((GpPath*) path)->GetPathPoints();
|
|
const BYTE* pathTypes = ((GpPath*) path)->GetPathTypes();
|
|
INT pathCount = path->GetPointCount();
|
|
|
|
// The maximum data size of the bilinear transform is
|
|
// 2*pathCount - 1. Here set it as 2*pathCount.
|
|
|
|
INT dimension = 2;
|
|
INT maxCount = 2*pathCount;
|
|
REALD* data = (REALD*) GpMalloc(dimension*maxCount*sizeof(REALD));
|
|
BYTE* types = (BYTE*) GpMalloc(maxCount);
|
|
|
|
if(!data || !types)
|
|
{
|
|
GpFree(data);
|
|
GpFree(types);
|
|
|
|
return OutOfMemory;
|
|
}
|
|
|
|
GpMemset(types, 0, maxCount);
|
|
|
|
// Set the bilinear transform.
|
|
|
|
GpBilinearTransform trans(rect, points, count);
|
|
|
|
DpPathIterator iter(pathPts, pathTypes, pathCount);
|
|
|
|
INT startIndex, endIndex;
|
|
BOOL isClosed;
|
|
GpStatus status = Ok;
|
|
REALD* dataPtr = data;
|
|
|
|
INT totalCount = 0; // Number of control points.
|
|
|
|
while(
|
|
iter.NextSubpath(
|
|
&startIndex, &endIndex, &isClosed)
|
|
&& status == Ok
|
|
)
|
|
{
|
|
INT typeStartIndex, typeEndIndex;
|
|
BYTE pathType;
|
|
BOOL isFirstPoint = TRUE;
|
|
|
|
while(
|
|
iter.NextPathType(&pathType, &typeStartIndex, &typeEndIndex)
|
|
&& status == Ok
|
|
)
|
|
{
|
|
// Starting point of the current suptype
|
|
// and the number of points.
|
|
|
|
const GpPointF* pts = pathPts + typeStartIndex;
|
|
INT typeCount = typeEndIndex - typeStartIndex + 1;
|
|
|
|
switch(pathType)
|
|
{
|
|
case PathPointTypeBezier3:
|
|
trans.ConvertCubicBeziers(pts, typeCount, dataPtr);
|
|
pts += typeCount - 1;
|
|
dataPtr += dimension*2*(typeCount - 1);
|
|
|
|
if(isFirstPoint)
|
|
{
|
|
*(types + totalCount) = PathPointTypeStart;
|
|
totalCount++;
|
|
}
|
|
|
|
GpMemset(types + totalCount, PathPointTypeBezier6, 2*(typeCount - 1));
|
|
totalCount += 2*(typeCount - 1);
|
|
isFirstPoint = FALSE;
|
|
break;
|
|
|
|
case PathPointTypeLine:
|
|
trans.ConvertLines(pts, typeCount, dataPtr);
|
|
pts += typeCount - 1;
|
|
dataPtr += dimension*2*(typeCount - 1);
|
|
|
|
if(isFirstPoint)
|
|
{
|
|
*(types + totalCount) = PathPointTypeStart;
|
|
totalCount++;
|
|
}
|
|
|
|
GpMemset(types + totalCount, PathPointTypeBezier2, 2*(typeCount - 1));
|
|
totalCount += 2*(typeCount - 1);
|
|
isFirstPoint = FALSE;
|
|
break;
|
|
|
|
case PathPointTypeStart:
|
|
case PathPointTypeBezier2:
|
|
case PathPointTypeBezier4:
|
|
case PathPointTypeBezier5:
|
|
case PathPointTypeBezier6:
|
|
default:
|
|
// Should not have any of those types in GpPath.
|
|
|
|
ASSERT(0);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Types = types;
|
|
XPoints.Count = totalCount;
|
|
XPoints.Dimension = dimension;
|
|
XPoints.Data = data;
|
|
XPoints.IsDataAllocated = TRUE;
|
|
SetValid(TRUE);
|
|
|
|
return Ok;
|
|
}
|
|
|
|
GpStatus
|
|
GpXPath::Flatten(
|
|
DynByteArray* flattenTypes,
|
|
DynPointFArray* flattenPoints,
|
|
const GpMatrix *matrix
|
|
)
|
|
{
|
|
GpStatus status = Ok;
|
|
|
|
ASSERT(matrix);
|
|
|
|
FPUStateSaver fpuState; // Setup the FPU state.
|
|
|
|
flattenPoints->Reset(FALSE);
|
|
flattenTypes->Reset(FALSE);
|
|
|
|
INT dimension = XPoints.Dimension;
|
|
REALD* data = XPoints.Data;
|
|
|
|
GpXPathIterator iter(this);
|
|
|
|
INT startIndex, endIndex;
|
|
BOOL isClosed;
|
|
|
|
GpPointF* ptsBuffer = NULL;
|
|
|
|
while(
|
|
iter.NextSubpath(
|
|
&startIndex, &endIndex, &isClosed)
|
|
&& status == Ok
|
|
)
|
|
{
|
|
INT typeStartIndex, typeEndIndex;
|
|
BYTE pathType;
|
|
BOOL isFirstPoint = TRUE;
|
|
|
|
while(
|
|
iter.NextPathType(&pathType, &typeStartIndex, &typeEndIndex)
|
|
&& status == Ok
|
|
)
|
|
{
|
|
INT count, index;
|
|
BYTE* types;
|
|
GpPointF* pts;
|
|
|
|
switch(pathType)
|
|
{
|
|
case PathPointTypeStart:
|
|
break;
|
|
|
|
case PathPointTypeBezier2:
|
|
case PathPointTypeBezier3:
|
|
case PathPointTypeBezier4:
|
|
case PathPointTypeBezier5:
|
|
case PathPointTypeBezier6:
|
|
{
|
|
BOOL dontCopy = FALSE;
|
|
GpXBezier bezier;
|
|
GpXPoints xpoints;
|
|
INT order;
|
|
|
|
xpoints.SetData(
|
|
data + typeStartIndex*dimension,
|
|
dimension,
|
|
typeEndIndex - typeStartIndex + 1,
|
|
dontCopy // Don't copy the data.
|
|
);
|
|
order = (INT) pathType;
|
|
if(bezier.SetBeziers(order, xpoints) == Ok)
|
|
{
|
|
// Flatten() flattens Bezier.
|
|
// The flattened points are already transformed.
|
|
|
|
DynPointFArray bezierFlattenPts;
|
|
|
|
bezier.Flatten(&bezierFlattenPts, matrix);
|
|
// count = bezier.GetFlattenCount();
|
|
count = bezierFlattenPts.GetCount();
|
|
|
|
// Check if there is already the first point.
|
|
if(!isFirstPoint)
|
|
count--; // Don't add the first point.
|
|
|
|
if (count > 0)
|
|
{
|
|
|
|
if((types = flattenTypes->AddMultiple(count)) != NULL)
|
|
{
|
|
// pts = bezier.GetFlattenData();
|
|
pts = bezierFlattenPts.GetDataBuffer();
|
|
|
|
if(!isFirstPoint)
|
|
pts++; // Skip the first point.
|
|
|
|
flattenPoints->AddMultiple(pts, count);
|
|
GpMemset(types, PathPointTypeLine, count);
|
|
if(isFirstPoint)
|
|
types[0] = PathPointTypeStart;
|
|
|
|
isFirstPoint = FALSE;
|
|
}
|
|
else
|
|
status = OutOfMemory;
|
|
|
|
}
|
|
|
|
}
|
|
else
|
|
status =InvalidParameter;
|
|
}
|
|
|
|
break;
|
|
|
|
case PathPointTypeLine:
|
|
default:
|
|
count = typeEndIndex - typeStartIndex + 1;
|
|
|
|
if(!isFirstPoint)
|
|
count--;
|
|
|
|
if((types = flattenTypes->AddMultiple(count)) != NULL)
|
|
{
|
|
// Set the type.
|
|
|
|
GpMemset(types, PathPointTypeLine, count);
|
|
if(isFirstPoint)
|
|
types[0] = PathPointTypeStart;
|
|
|
|
// Get the first data.
|
|
|
|
REALD* dataPtr = data + typeStartIndex*dimension;
|
|
if(!isFirstPoint)
|
|
dataPtr += dimension; // Skip the first point.
|
|
|
|
// Allocate the point buffer to save
|
|
// for the flatten points.
|
|
|
|
pts = (GpPointF*) GpRealloc(ptsBuffer,
|
|
count*sizeof(GpPointF));
|
|
|
|
if(!pts)
|
|
{
|
|
status = OutOfMemory;
|
|
break;
|
|
}
|
|
else
|
|
ptsBuffer = pts;
|
|
|
|
// Copy the data
|
|
|
|
GpPointF* ptsPtr = pts;
|
|
|
|
for(INT k = 0; k < count; k++)
|
|
{
|
|
// Simply copy the first 2 elments
|
|
// of the data as the x and y component.
|
|
|
|
REALD x, y, w;
|
|
|
|
x = *dataPtr++;
|
|
y = *dataPtr++;
|
|
|
|
// Do the perspective projection if
|
|
// dimension is higher than 2.
|
|
|
|
if(dimension > 2)
|
|
{
|
|
w = *dataPtr;
|
|
x /= w;
|
|
y /= w;
|
|
}
|
|
|
|
ptsPtr->X = TOREAL(x);
|
|
ptsPtr->Y = TOREAL(y);
|
|
|
|
ptsPtr++;
|
|
|
|
// Skip the rest.
|
|
|
|
if(dimension > 2)
|
|
dataPtr += (dimension - 2);
|
|
}
|
|
|
|
// Add to the flatten points.
|
|
|
|
index = flattenPoints->GetCount();
|
|
flattenPoints->AddMultiple(pts, count);
|
|
|
|
// Get the data biffer of the flatten points.
|
|
|
|
pts = flattenPoints->GetDataBuffer();
|
|
|
|
// Transform the newly added points.
|
|
|
|
matrix->Transform(pts + index, count);
|
|
|
|
isFirstPoint = FALSE;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
// This is the end of the current subpath. Close subpath
|
|
// if necessary.
|
|
|
|
if(isClosed)
|
|
{
|
|
BYTE* typeBuffer = flattenTypes->GetDataBuffer();
|
|
INT lastCount = flattenTypes->GetCount();
|
|
typeBuffer[lastCount - 1] |= PathPointTypeCloseSubpath;
|
|
}
|
|
}
|
|
|
|
if(ptsBuffer)
|
|
GpFree(ptsBuffer);
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* GpXPathIterator class
|
|
*
|
|
* 11/08/1999 ikkof
|
|
* Created it.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
GpXPathIterator::GpXPathIterator(GpXPath* xpath)
|
|
{
|
|
Initialize();
|
|
|
|
if(xpath && xpath->IsValid())
|
|
{
|
|
TotalCount = xpath->GetPointCount();
|
|
XPoints.SetData(
|
|
xpath->GetPathPoints(),
|
|
xpath->GetPointDimension(),
|
|
TotalCount,
|
|
FALSE // Don't copy data.
|
|
);
|
|
Types = xpath->GetPathTypes();
|
|
}
|
|
|
|
// Check if this path is valid.
|
|
|
|
if(
|
|
XPoints.Data
|
|
&& XPoints.Dimension > 0
|
|
&& XPoints.Count > 0
|
|
&& Types
|
|
&& TotalCount > 0
|
|
)
|
|
{
|
|
SetValid(TRUE);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
GpXPathIterator::Initialize()
|
|
{
|
|
// XPath = NULL;
|
|
Types = NULL;
|
|
TotalCount = 0;
|
|
Index = 0;
|
|
SubpathStartIndex = 0;
|
|
SubpathEndIndex = 0;
|
|
TypeStartIndex = 0;
|
|
TypeEndIndex = 0;
|
|
SetValid(FALSE);
|
|
}
|
|
|
|
|
|
INT
|
|
GpXPathIterator::Enumerate(GpXPoints* xpoints, BYTE* types)
|
|
{
|
|
if(!IsValid())
|
|
return 0;
|
|
|
|
ASSERT(xpoints && types);
|
|
if(xpoints == NULL || types == NULL)
|
|
return 0;
|
|
|
|
INT inputSize = xpoints->Dimension*xpoints->Count;
|
|
|
|
ASSERT(xpoints->Data && inputSize > 0);
|
|
if(xpoints->Data == NULL || inputSize <= 0)
|
|
return 0;
|
|
|
|
if(Index >= TotalCount)
|
|
return 0;
|
|
|
|
// Make sure the resultant dimension is the same as
|
|
// the internal dimension.
|
|
|
|
INT dimension = XPoints.Dimension;
|
|
if(xpoints->Dimension != dimension)
|
|
{
|
|
xpoints->Dimension = dimension;
|
|
xpoints->Count = inputSize/dimension;
|
|
}
|
|
|
|
INT number = min(TotalCount - Index, xpoints->Count);
|
|
GpMemcpy(
|
|
xpoints->Data,
|
|
XPoints.Data + Index*dimension,
|
|
number*dimension*sizeof(REALD));
|
|
GpMemcpy(types, Types + Index, number*sizeof(BYTE));
|
|
|
|
Index += number;
|
|
|
|
return number;
|
|
}
|
|
|
|
INT
|
|
GpXPathIterator::NextSubpath(INT* startIndex, INT* endIndex, BOOL *isClosed)
|
|
{
|
|
if(!IsValid())
|
|
return 0;
|
|
|
|
INT count = TotalCount;
|
|
|
|
if(SubpathEndIndex >= count - 1)
|
|
return 0;
|
|
|
|
const BYTE* types = Types;
|
|
|
|
INT i;
|
|
|
|
// Set the starting index of the current subpath.
|
|
|
|
if(SubpathEndIndex == 0)
|
|
{
|
|
SubpathStartIndex = 0;
|
|
i = 1;
|
|
}
|
|
else
|
|
{
|
|
SubpathStartIndex = SubpathEndIndex + 1;
|
|
SubpathEndIndex = SubpathStartIndex;
|
|
i = SubpathStartIndex + 1;
|
|
}
|
|
|
|
BOOL hasData = FALSE;
|
|
INT segmentCount = 0;
|
|
|
|
while(i < count)
|
|
{
|
|
// Do the move segments.
|
|
|
|
segmentCount = 0;
|
|
while(i < count && (types[i] & PathPointTypePathTypeMask) == PathPointTypeStart)
|
|
{
|
|
segmentCount++;
|
|
if(hasData)
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
SubpathStartIndex = i;
|
|
SubpathEndIndex = SubpathStartIndex;
|
|
i++;
|
|
}
|
|
}
|
|
if(segmentCount > 0 && hasData)
|
|
{
|
|
SubpathEndIndex = i - 1;
|
|
break;
|
|
}
|
|
|
|
// Do the non-move segments.
|
|
|
|
segmentCount = 0;
|
|
BYTE nextType = types[i] & PathPointTypePathTypeMask;
|
|
while(i < count && (types[i] & PathPointTypePathTypeMask) == nextType)
|
|
{
|
|
i++;
|
|
segmentCount++;
|
|
}
|
|
if(segmentCount > 0)
|
|
{
|
|
hasData = TRUE;
|
|
}
|
|
}
|
|
|
|
*startIndex = SubpathStartIndex;
|
|
if(i >= count)
|
|
SubpathEndIndex = count - 1; // The last subpath.
|
|
*endIndex = SubpathEndIndex;
|
|
segmentCount = SubpathEndIndex - SubpathStartIndex + 1;
|
|
if(segmentCount <= 1) // Start and end point is the same.
|
|
segmentCount = 0;
|
|
|
|
if(segmentCount > 1)
|
|
{
|
|
// If there is the close flag or the start and end points match,
|
|
// this subpath is closed.
|
|
|
|
if(
|
|
(types[SubpathEndIndex] & PathPointTypeCloseSubpath)
|
|
|| XPoints.AreEqualPoints(SubpathStartIndex, SubpathEndIndex)
|
|
)
|
|
{
|
|
*isClosed = TRUE;
|
|
}
|
|
else
|
|
*isClosed = FALSE;
|
|
}
|
|
else
|
|
*isClosed = FALSE;
|
|
|
|
// Set the current index to the starting index of the current subpath.
|
|
|
|
Index = SubpathStartIndex;
|
|
|
|
// Set the start and end index of type to be the starting index of
|
|
// the current subpath. NextPathType() will start from the
|
|
// beginning of the current subpath.
|
|
|
|
TypeStartIndex = TypeEndIndex = SubpathStartIndex;
|
|
|
|
return segmentCount;
|
|
}
|
|
|
|
|
|
INT
|
|
GpXPathIterator::EnumerateSubpath(
|
|
GpXPoints* xpoints,
|
|
BYTE* types
|
|
)
|
|
{
|
|
if(!IsValid())
|
|
return 0;
|
|
|
|
ASSERT(xpoints && types);
|
|
if(xpoints == NULL || types == NULL)
|
|
return 0;
|
|
|
|
INT inputSize = xpoints->Dimension*xpoints->Count;
|
|
|
|
ASSERT(xpoints->Data && inputSize > 0);
|
|
if(xpoints->Data == NULL || inputSize <= 0)
|
|
return 0;
|
|
|
|
if(Index > SubpathEndIndex)
|
|
return 0;
|
|
|
|
// Make sure the resultant dimension is the same as
|
|
// the internal dimension.
|
|
|
|
INT dimension = XPoints.Dimension;
|
|
if(xpoints->Dimension != dimension)
|
|
{
|
|
xpoints->Dimension = dimension;
|
|
xpoints->Count = inputSize/dimension;
|
|
}
|
|
|
|
INT number = min(SubpathEndIndex - Index + 1, xpoints->Count);
|
|
|
|
GpMemcpy(
|
|
xpoints->Data,
|
|
XPoints.Data + Index*dimension,
|
|
number*dimension*sizeof(REALD));
|
|
GpMemcpy(types, Types + Index, number*sizeof(BYTE));
|
|
|
|
Index += number;
|
|
|
|
return number;
|
|
}
|
|
|
|
|
|
INT
|
|
GpXPathIterator::NextPathType(
|
|
BYTE* pathType,
|
|
INT* startIndex,
|
|
INT* endIndex
|
|
)
|
|
{
|
|
if(!IsValid())
|
|
return 0;
|
|
|
|
if(TypeEndIndex >= SubpathEndIndex)
|
|
return 0; // There is no more segment in the current subpath.
|
|
|
|
INT count = SubpathEndIndex + 1; // Limit for the ending index.
|
|
const BYTE* types = Types;
|
|
|
|
TypeStartIndex = TypeEndIndex;
|
|
INT i = TypeStartIndex;
|
|
INT segmentCount = 0;
|
|
|
|
i++; // Go to the next point.
|
|
|
|
while(i < count)
|
|
{
|
|
// Do the move segments.
|
|
|
|
segmentCount = 0;
|
|
while(i < count && (types[i] & PathPointTypePathTypeMask) == PathPointTypeStart)
|
|
{
|
|
// Move the start and end index.
|
|
|
|
TypeStartIndex = i;
|
|
TypeEndIndex = TypeStartIndex;
|
|
i++;
|
|
segmentCount++;
|
|
}
|
|
|
|
// Do the non-move segments.
|
|
|
|
segmentCount = 0;
|
|
BYTE nextType = types[i] & PathPointTypePathTypeMask;
|
|
while(i < count && (types[i] & PathPointTypePathTypeMask) == nextType)
|
|
{
|
|
i++;
|
|
segmentCount++;
|
|
}
|
|
if(segmentCount > 0)
|
|
{
|
|
TypeEndIndex = TypeStartIndex + segmentCount;
|
|
*pathType = nextType;
|
|
break;
|
|
}
|
|
}
|
|
|
|
*startIndex = TypeStartIndex;
|
|
*endIndex = TypeEndIndex;
|
|
segmentCount = TypeEndIndex - TypeStartIndex + 1;
|
|
if(segmentCount <= 1)
|
|
{
|
|
// Start and End type index is the same. This means there is
|
|
// no more segment left.
|
|
|
|
segmentCount = 0;
|
|
}
|
|
|
|
// Set the current index to the starting index of the current subpath.
|
|
|
|
Index = TypeStartIndex;
|
|
|
|
return segmentCount;
|
|
}
|
|
|
|
|
|
INT
|
|
GpXPathIterator::EnumeratePathType(
|
|
GpXPoints* xpoints,
|
|
BYTE* types
|
|
)
|
|
{
|
|
if(!IsValid())
|
|
return 0;
|
|
|
|
ASSERT(xpoints && types);
|
|
if(xpoints == NULL || types == NULL)
|
|
return 0;
|
|
|
|
INT inputSize = xpoints->Dimension*xpoints->Count;
|
|
|
|
ASSERT(xpoints->Data && inputSize > 0);
|
|
if(xpoints->Data == NULL || inputSize <= 0)
|
|
return 0;
|
|
|
|
if(Index > TypeEndIndex)
|
|
return 0;
|
|
|
|
// Make sure the resultant dimension is the same as
|
|
// the internal dimension.
|
|
|
|
INT dimension = XPoints.Dimension;
|
|
if(xpoints->Dimension != dimension)
|
|
{
|
|
xpoints->Dimension = dimension;
|
|
xpoints->Count = inputSize/dimension;
|
|
}
|
|
|
|
INT number = min(TypeEndIndex - Index + 1, xpoints->Count);
|
|
|
|
GpMemcpy(
|
|
xpoints->Data,
|
|
XPoints.Data + Index*dimension,
|
|
number*dimension*sizeof(REALD));
|
|
GpMemcpy(types, Types + Index, number*sizeof(BYTE));
|
|
|
|
Index += number;
|
|
|
|
return number;
|
|
}
|
|
|
|
|
|
|