Leaked source code of windows server 2003
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

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