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.
787 lines
19 KiB
787 lines
19 KiB
/**************************************************************************\
|
|
*
|
|
* Copyright (c) 1999 Microsoft Corporation
|
|
*
|
|
* Module Name:
|
|
*
|
|
* PathIterator.cpp
|
|
*
|
|
* Abstract:
|
|
*
|
|
* Implementation of the DpPathTypeIterator and DpPathIterator classes
|
|
*
|
|
* Revision History:
|
|
*
|
|
* 11/13/1999 ikkof
|
|
* Created it.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.hpp"
|
|
|
|
VOID
|
|
DpPathTypeIterator::SetTypes(const BYTE* types, INT count)
|
|
{
|
|
if(types && count > 0)
|
|
{
|
|
Types = types;
|
|
Count = count;
|
|
|
|
// Set Valid flag to TRUE so that CheckValid()
|
|
// can call NextSubpath() and NextPathType().
|
|
|
|
SetValid(TRUE);
|
|
SetValid(CheckValid());
|
|
}
|
|
else
|
|
Initialize();
|
|
}
|
|
|
|
// !!! bhouse CheckValid should not be required
|
|
//
|
|
// When we create an iterator, we should be able to provide
|
|
// data that is consistent and that does not need to be
|
|
// checked.
|
|
// Also, CheckValid actually has side effects like determining
|
|
// whether the path has beziers and calculating sub-path count.
|
|
// These should be provided at iterator creation time or taken
|
|
// out of the source path for which the iterator is created.
|
|
// The reasoning is that this data should persist beyond the
|
|
// lifespan of the iterator so that we do not have to keep
|
|
// re-calculating information that can be calculated once and
|
|
// stored with the path.
|
|
|
|
|
|
BOOL
|
|
DpPathTypeIterator::CheckValid()
|
|
{
|
|
if(Count < 0)
|
|
return FALSE;
|
|
else if(Count == 0) // Allow an empty path.
|
|
return TRUE;
|
|
else
|
|
{
|
|
// If Count > 0 and Types = NULL, the path is not valid.
|
|
|
|
if(Types == NULL)
|
|
return FALSE;
|
|
}
|
|
|
|
INT startIndex, endIndex;
|
|
BOOL isClosed;
|
|
BOOL isValid = TRUE;
|
|
|
|
Rewind();
|
|
|
|
INT subpathCount = 0;
|
|
|
|
HasBezier = FALSE;
|
|
ExtendedPath = FALSE;
|
|
|
|
while(
|
|
NextSubpath(&startIndex, &endIndex, &isClosed)
|
|
&& isValid
|
|
)
|
|
{
|
|
INT typeStartIndex, typeEndIndex;
|
|
BYTE pathType = PathPointTypeStart;
|
|
|
|
if(endIndex == startIndex && Count > 1)
|
|
{
|
|
// This is a case when the next subpath has only one point.
|
|
|
|
isValid = FALSE;
|
|
}
|
|
|
|
while(
|
|
NextPathType(&pathType, &typeStartIndex, &typeEndIndex)
|
|
&& isValid
|
|
)
|
|
{
|
|
INT count = typeEndIndex - typeStartIndex + 1;
|
|
INT order = (INT) pathType;
|
|
|
|
switch(pathType)
|
|
{
|
|
case PathPointTypeStart:
|
|
// This happens when there is only one point
|
|
// in a path.
|
|
|
|
if(count == 1)
|
|
isValid;
|
|
else
|
|
{
|
|
ASSERT(("Invalid path type."));
|
|
isValid = FALSE;
|
|
}
|
|
break;
|
|
|
|
// The number of the Bezier points must be in the form of
|
|
// n*order + 1.
|
|
|
|
case PathPointTypeBezier3:
|
|
if(count % order != 1)
|
|
isValid = FALSE;
|
|
if(!HasBezier)
|
|
HasBezier = TRUE;
|
|
if(order != 3 && !ExtendedPath)
|
|
ExtendedPath = TRUE;
|
|
break;
|
|
|
|
case PathPointTypeLine:
|
|
break;
|
|
|
|
default:
|
|
// Undefined path type.
|
|
|
|
WARNING(("Undefined path type."));
|
|
isValid = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
subpathCount++;
|
|
}
|
|
|
|
Rewind();
|
|
|
|
SubpathCount = subpathCount;
|
|
|
|
return isValid;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Returns the index range of the next subpah.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [OUT] startIndex - the starting index of the next subpath.
|
|
* [OUT] endIndex - the ending index of the next subpath.
|
|
* [OUT] isClosed - TRUE is the next subpath is closed.
|
|
*
|
|
* Return Value:
|
|
*
|
|
* Retuns the sumber of points in the next subpath.
|
|
* Returns 0 if there is no more subpath.
|
|
*
|
|
* History:
|
|
*
|
|
* 11/01/1999 ikkof
|
|
* Created it.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
INT
|
|
DpPathTypeIterator::NextSubpath(
|
|
INT* startIndex,
|
|
INT* endIndex,
|
|
BOOL *isClosed
|
|
)
|
|
{
|
|
if(!IsValid() || Count == 0)
|
|
return 0;
|
|
|
|
INT count = Count;
|
|
|
|
if(SubpathEndIndex >= count - 1)
|
|
return 0;
|
|
|
|
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;
|
|
|
|
const BYTE* types = Types + i;
|
|
|
|
while(i < count)
|
|
{
|
|
// Do the move segments.
|
|
|
|
segmentCount = 0;
|
|
while(i < count && (*types & PathPointTypePathTypeMask) == PathPointTypeStart)
|
|
{
|
|
segmentCount++;
|
|
if(hasData)
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// Skip the consequtive move segments in the beginning of a subpath.
|
|
|
|
SubpathStartIndex = i;
|
|
SubpathEndIndex = SubpathStartIndex;
|
|
i++;
|
|
types++;
|
|
}
|
|
}
|
|
if(segmentCount > 0 && hasData)
|
|
{
|
|
SubpathEndIndex = i - 1;
|
|
break;
|
|
}
|
|
|
|
// Do the non-move segments.
|
|
|
|
segmentCount = 0;
|
|
|
|
while(i < count && (*types & PathPointTypePathTypeMask) != PathPointTypeStart)
|
|
{
|
|
i++;
|
|
types++;
|
|
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)
|
|
{
|
|
// If there is the close flag this subpath is closed.
|
|
|
|
if((Types[SubpathEndIndex] & PathPointTypeCloseSubpath))
|
|
{
|
|
*isClosed = TRUE;
|
|
}
|
|
else
|
|
*isClosed = FALSE;
|
|
}
|
|
else
|
|
*isClosed = FALSE;
|
|
|
|
// 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 = SubpathStartIndex;
|
|
TypeEndIndex = -1; // Indicate that this is the first type
|
|
// in the current subpath.
|
|
|
|
// Set the current index to the start index of the subpath.
|
|
|
|
Index = SubpathStartIndex;
|
|
|
|
return segmentCount;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Returns the path type, and the index range of the next segment.
|
|
* This must be used after NextSubpath() is called. This returns only
|
|
* the next segment within the current subpath.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [OUT] pathType - the type of the next segment ignoring the closed
|
|
* and other flags.
|
|
* [OUT] startIndex - the starting index of the next subpath.
|
|
* [OUT] endIndex - the ending index of the next subpath.
|
|
*
|
|
* Return Value:
|
|
*
|
|
* Retuns the sumber of points in the next segment.
|
|
* Returns 0 if there is no more segment in the current subpath.
|
|
*
|
|
* History:
|
|
*
|
|
* 11/01/1999 ikkof
|
|
* Created it.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
INT
|
|
DpPathTypeIterator::NextPathType(
|
|
BYTE* pathType,
|
|
INT* startIndex,
|
|
INT* endIndex
|
|
)
|
|
{
|
|
if(!IsValid() || Count == 0)
|
|
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.
|
|
|
|
if(TypeEndIndex <= 0)
|
|
TypeEndIndex = SubpathStartIndex; // This is the first type.
|
|
|
|
TypeStartIndex = TypeEndIndex;
|
|
INT i = TypeStartIndex;
|
|
INT segmentCount = 0;
|
|
|
|
i++; // Go to the next point.
|
|
|
|
const BYTE* types = Types + i;
|
|
|
|
while(i < count)
|
|
{
|
|
// Do the move segments.
|
|
|
|
segmentCount = 0;
|
|
while(i < count && (*types & PathPointTypePathTypeMask) == PathPointTypeStart)
|
|
{
|
|
// Move the start and end index.
|
|
|
|
TypeStartIndex = i;
|
|
TypeEndIndex = TypeStartIndex;
|
|
i++;
|
|
types++;
|
|
segmentCount++;
|
|
}
|
|
|
|
// Do the non-move segments.
|
|
|
|
segmentCount = 0;
|
|
BYTE nextType = *types & PathPointTypePathTypeMask;
|
|
while(i < count && (*types & PathPointTypePathTypeMask) == nextType)
|
|
{
|
|
i++;
|
|
types++;
|
|
segmentCount++;
|
|
}
|
|
if(segmentCount > 0)
|
|
{
|
|
TypeEndIndex = TypeStartIndex + segmentCount;
|
|
*pathType = nextType;
|
|
break;
|
|
}
|
|
}
|
|
|
|
*startIndex = TypeStartIndex;
|
|
*endIndex = TypeEndIndex;
|
|
segmentCount = TypeEndIndex - TypeStartIndex + 1;
|
|
|
|
return segmentCount;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Returns the index range of the next subpah.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [OUT] startIndex - the starting index of the next subpath.
|
|
* [OUT] endIndex - the ending index of the next subpath.
|
|
* [OUT] isClosed - TRUE is the next subpath is closed.
|
|
*
|
|
* Return Value:
|
|
*
|
|
* Retuns the sumber of points in the next subpath.
|
|
* Returns 0 if there is no more subpath.
|
|
*
|
|
* History:
|
|
*
|
|
* 11/01/1999 ikkof
|
|
* Created it.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
INT
|
|
DpPathTypeIterator::NextMarker(
|
|
INT* startIndex,
|
|
INT* endIndex
|
|
)
|
|
{
|
|
if(!IsValid() || Count == 0)
|
|
return 0;
|
|
|
|
INT count = Count;
|
|
|
|
if(MarkerEndIndex >= count - 1)
|
|
return 0;
|
|
|
|
INT i;
|
|
|
|
// Set the starting index of the current subpath.
|
|
|
|
if(MarkerEndIndex <= 0)
|
|
{
|
|
MarkerStartIndex = 0;
|
|
i = 1;
|
|
}
|
|
else
|
|
{
|
|
MarkerStartIndex = MarkerEndIndex + 1;
|
|
MarkerEndIndex = MarkerStartIndex;
|
|
i = MarkerStartIndex + 1;
|
|
}
|
|
|
|
const BYTE* types = Types + i;
|
|
BOOL hasData = FALSE;
|
|
|
|
while(i < count && (*types & PathPointTypePathMarker) == 0)
|
|
{
|
|
i++;
|
|
types++;
|
|
}
|
|
|
|
if(i < count)
|
|
MarkerEndIndex = i;
|
|
else
|
|
MarkerEndIndex = count - 1;
|
|
|
|
*startIndex = MarkerStartIndex;
|
|
*endIndex = MarkerEndIndex;
|
|
INT segmentCount = MarkerEndIndex - MarkerStartIndex + 1;
|
|
|
|
// Set the start and end index of type to be the starting index of
|
|
// the current marker. NextSubpath() and NextPathType() will
|
|
// start from the beginning of the current current marked path.
|
|
|
|
SubpathStartIndex = SubpathEndIndex = MarkerStartIndex;
|
|
TypeStartIndex = TypeEndIndex = MarkerStartIndex;
|
|
|
|
// Set the current index to the start index of the subpath.
|
|
|
|
Index = MarkerStartIndex;
|
|
|
|
return segmentCount;
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Returns TRUE if the control type in the given index is in dash mode.
|
|
* Otherwise this returns FALSE. If the given index is outside of
|
|
* the range this returns FALSE. A user must know the range of the
|
|
* index beforehand to find the correct information.
|
|
*
|
|
\**************************************************************************/
|
|
BOOL DpPathTypeIterator::IsDashMode(INT index)
|
|
{
|
|
if(!IsValid() || Count == 0 || index < 0 || index >= Count)
|
|
return FALSE;
|
|
|
|
return (Types[index] & PathPointTypeDashMode);
|
|
}
|
|
|
|
DpPathIterator::DpPathIterator(
|
|
const DpPath* path
|
|
)
|
|
{
|
|
Initialize();
|
|
|
|
if(path)
|
|
{
|
|
const BYTE* types = path->GetPathTypes();
|
|
const GpPointF* points = path->GetPathPoints();
|
|
INT count = path->GetPointCount();
|
|
SetData(points, types, count);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
DpPathIterator::SetData(
|
|
const GpPointF* points,
|
|
const BYTE* types,
|
|
INT count
|
|
)
|
|
{
|
|
if(points && types && count > 0)
|
|
{
|
|
Points = points;
|
|
Types = types;
|
|
Count = count;
|
|
|
|
// Set Valid flag to TRUE so that CheckValid()
|
|
// can call NextSubpath() and NextPathType().
|
|
|
|
SetValid(TRUE);
|
|
SetValid(CheckValid());
|
|
}
|
|
else
|
|
Initialize();
|
|
}
|
|
|
|
VOID
|
|
DpPathIterator::SetData(
|
|
const DpPath* path
|
|
)
|
|
{
|
|
if(path)
|
|
{
|
|
const BYTE* types = path->GetPathTypes();
|
|
const GpPointF* points = path->GetPathPoints();
|
|
INT count = path->GetPointCount();
|
|
SetData(points, types, count);
|
|
}
|
|
else
|
|
Initialize();
|
|
}
|
|
|
|
INT
|
|
DpPathIterator::NextSubpath(
|
|
INT* startIndex,
|
|
INT* endIndex,
|
|
BOOL *isClosed
|
|
)
|
|
{
|
|
if(!IsValid() || Count == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
BOOL closed = TRUE;
|
|
INT start = 0, end = 0;
|
|
INT count = DpPathTypeIterator::NextSubpath(&start, &end, &closed);
|
|
|
|
*startIndex = start;
|
|
*endIndex = end;
|
|
*isClosed = closed;
|
|
|
|
return count;
|
|
}
|
|
|
|
INT
|
|
DpPathIterator::NextSubpath(
|
|
DpPath* path,
|
|
BOOL *isClosed
|
|
)
|
|
{
|
|
if(!IsValid() || Count == 0 || !path)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
BOOL closed = TRUE;
|
|
INT start = 0, end = 0;
|
|
INT count = DpPathTypeIterator::NextSubpath(&start, &end, &closed);
|
|
|
|
GpPathData pathData;
|
|
pathData.Count = count;
|
|
pathData.Points = (GpPointF*) &Points[start];
|
|
pathData.Types = (BYTE*) &Types[start];
|
|
|
|
path->SetPathData(&pathData);
|
|
|
|
*isClosed = closed;
|
|
|
|
return count;
|
|
}
|
|
|
|
INT
|
|
DpPathIterator::NextMarker(
|
|
INT* startIndex,
|
|
INT* endIndex
|
|
)
|
|
{
|
|
if(!IsValid() || Count == 0)
|
|
return 0;
|
|
|
|
INT count = DpPathTypeIterator::NextMarker(startIndex, endIndex);
|
|
|
|
return count;
|
|
}
|
|
|
|
INT
|
|
DpPathIterator::NextMarker(
|
|
DpPath* path
|
|
)
|
|
{
|
|
if(!IsValid() || Count == 0 || !path)
|
|
return 0;
|
|
|
|
BOOL closed;
|
|
INT start = 0, end = 0;
|
|
INT count = DpPathTypeIterator::NextMarker(&start, &end);
|
|
|
|
GpPathData pathData;
|
|
pathData.Count = count;
|
|
pathData.Points = (GpPointF*) &Points[start];
|
|
pathData.Types = (BYTE*) &Types[start];
|
|
|
|
path->SetPathData(&pathData);
|
|
|
|
return count;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* This retrieves the next points and types up to the number count.
|
|
* This does not copy the unnecessary (consequetive) move points.
|
|
* This fills up the data until the count number is reached. This fills
|
|
* data beyond the current subpath.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [OUT] points - point array to copy the retrieved point data.
|
|
* [OUT] types - type array to copy the retrieved type data.
|
|
* [IN] count - the number of points to be copied (request).
|
|
*
|
|
* Retrun Value:
|
|
* Returns the total number of the retrieved points.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
INT
|
|
DpPathIterator::Enumerate(
|
|
GpPointF* points,
|
|
BYTE* types,
|
|
INT count
|
|
)
|
|
{
|
|
if(!IsValid() || Count == 0)
|
|
return 0;
|
|
|
|
INT totalNumber = 0;
|
|
INT number = EnumerateWithinSubpath(points, types, count);
|
|
|
|
while(number > 0)
|
|
{
|
|
totalNumber += number;
|
|
count -= number;
|
|
|
|
if(count > 0)
|
|
{
|
|
points += number;
|
|
types += number;
|
|
number = EnumerateWithinSubpath(points, types, count);
|
|
}
|
|
else
|
|
number = 0;
|
|
}
|
|
|
|
return totalNumber;
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* This retrieves the next points and types up to the number count.
|
|
* This does not copy the unnecessary (consequetive) move points.
|
|
* This fills up the data until the count number is reached or the
|
|
* end of the current subopath is reached.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [OUT] points - point array to copy the retrieved point data.
|
|
* [OUT] types - type array to copy the retrieved type data.
|
|
* [IN] count - the number of points to be copied (request).
|
|
*
|
|
* Retrun Value:
|
|
* Returns the total number of the retrieved points.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
INT
|
|
DpPathIterator::EnumerateWithinSubpath(
|
|
GpPointF* points,
|
|
BYTE* types,
|
|
INT count
|
|
)
|
|
{
|
|
if(!IsValid() || Count == 0 || count <= 0 || !points || !types)
|
|
return 0;
|
|
|
|
INT startIndex, endIndex;
|
|
BOOL isClosed;
|
|
INT segmentCount;
|
|
|
|
if(Index == 0)
|
|
segmentCount = NextSubpath(&startIndex, &endIndex, &isClosed);
|
|
|
|
if(Index > SubpathEndIndex)
|
|
segmentCount = NextSubpath(&startIndex, &endIndex, &isClosed);
|
|
else
|
|
segmentCount = SubpathEndIndex - SubpathStartIndex + 1;
|
|
|
|
if(segmentCount == 0)
|
|
return 0; // No more segment.
|
|
|
|
count = min(count, SubpathEndIndex - Index + 1);
|
|
|
|
if(count > 0)
|
|
{
|
|
GpMemcpy(points, Points + Index, count*sizeof(GpPointF));
|
|
GpMemcpy(types, Types + Index, count);
|
|
Index += count;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* This copies the data stored in Points and Types arrays
|
|
* in the index range between startIndex and endIndex.
|
|
* This may copy unnecessary (consequetive) move points.
|
|
* startIndex and endIndex must be within the index range of
|
|
* the original data. Otherwise, this does not copy the data
|
|
* and returns 0.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [OUT] points - point array to copy the retrieved point data.
|
|
* [OUT] types - type array to copy the retrieved type data.
|
|
* [IN] startIndex - start index of the origianl data
|
|
* [IN] endIndex - end index of the origianl data.
|
|
*
|
|
* Retrun Value:
|
|
* Returns the total number of the copied points.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
INT
|
|
DpPathIterator::CopyData(
|
|
GpPointF* points,
|
|
BYTE* types,
|
|
INT startIndex,
|
|
INT endIndex
|
|
)
|
|
{
|
|
if(!IsValid() || Count == 0 || startIndex < 0 || endIndex >= Count
|
|
|| startIndex > endIndex || !points || !types)
|
|
return 0;
|
|
|
|
INT count = endIndex - startIndex + 1;
|
|
|
|
ASSERT(count > 0);
|
|
|
|
GpMemcpy(points, Points + startIndex, count*sizeof(GpPointF));
|
|
GpMemcpy(types, Types + startIndex, count);
|
|
Index += count;
|
|
|
|
return count;
|
|
}
|
|
|
|
|