WindowsXP-SP1/windows/advcore/gdiplus/engine/entry/brush.cpp
2020-09-30 16:53:49 +02:00

5850 lines
171 KiB
C++

/**************************************************************************\
*
* Copyright (c) 1998 Microsoft Corporation
*
* Abstract:
*
* Implementation of GpBrush class
*
* Revision History:
*
* 12/09/1998 davidx
* Flesh out brush interfaces.
*
* 12/08/1998 andrewgo
* Initial placeholders.
*
\**************************************************************************/
#include "precomp.hpp"
// For GetData and SetData methods
#define GDIP_BRUSHFLAGS_PATH 0x00000001
#define GDIP_BRUSHFLAGS_TRANSFORM 0x00000002
#define GDIP_BRUSHFLAGS_PRESETCOLORS 0x00000004
#define GDIP_BRUSHFLAGS_BLENDFACTORS 0x00000008
#define GDIP_BRUSHFLAGS_BLENDFACTORSH GDIP_BRUSHFLAGS_BLENDFACTORS
#define GDIP_BRUSHFLAGS_BLENDFACTORSV 0x00000010
#define GDIP_BRUSHFLAGS_BLENDFACTORS0 GDIP_BRUSHFLAGS_BLENDFACTORSH
#define GDIP_BRUSHFLAGS_BLENDFACTORS1 GDIP_BRUSHFLAGS_BLENDFACTORSV
#define GDIP_BRUSHFLAGS_BLENDFACTORS2 0x00000020
#define GDIP_BRUSHFLAGS_FOCUSSCALES 0x00000040
#define GDIP_BRUSHFLAGS_ISGAMMACORRECTED 0x00000080
// Defined in path.cpp
extern BOOL
IsRectanglePoints(
const GpPointF* points,
INT count,
const GpMatrix * matrix,
GpRectF * transformedBounds
);
GpStatus
GpElementaryBrush::MultiplyTransform(const GpMatrix& matrix,
GpMatrixOrder order)
{
GpStatus status = Ok;
if (matrix.IsInvertible())
{
if (order == MatrixOrderPrepend)
{
DeviceBrush.Xform.Prepend(matrix);
}
else
{
DeviceBrush.Xform.Append(matrix);
}
UpdateUid();
}
else
status = InvalidParameter;
return status;
}
/**************************************************************************\
*
* Function Description:
*
* Calculate the brush transform from a starting point and two directions.
*
* Arguments:
*
* [OUT] m - matrix coefficients
* [OUT] width - width (the length of dP1)
* [OUT] height - height (the length of dP2)
* [IN] p0 - the starting point of the brush.
* [IN] dP1 - the vector to represent the transformed x-direction.
* [IN] dP2 - the vector to represent the transformed y-direction.
*
* Return Vaule:
*
* TRUE if the transform matrix is non-degenerate.
* Otherwise returns FALSE.
*
* History:
*
* 06/03/1999 ikkof
* Created it.
*
\**************************************************************************/
BOOL getLineGradientTransform(
REAL* m,
REAL* width,
REAL* height,
const GpPointF& p0,
const GpPointF& dP1,
const GpPointF& dP2
)
{
// Make sure the flat API has correctly set the FPU.
FPUStateSaver::AssertMode();
REAL l1 = dP1.X*dP1.X + dP1.Y*dP1.Y;
REAL l2 = dP2.X*dP2.X + dP2.Y*dP2.Y;
REAL test = dP1.X*dP2.Y - dP1.Y*dP2.X;
if(l1 == 0 || l2 == 0 || test == 0)
return FALSE;
l1 = REALSQRT(l1);
l2 = REALSQRT(l2);
m[0] = TOREAL(dP1.X/l1); // M11
m[1] = TOREAL(dP1.Y/l1); // M12
m[2] = TOREAL(dP2.X/l2); // M21
m[3] = TOREAL(dP2.Y/l2); // M22
m[4] = TOREAL(p0.X - p0.X*m[0] - p0.Y*m[2]); // Dx
m[5] = TOREAL(p0.Y - p0.X*m[1] - p0.Y*m[3]); // Dy
*width = l1;
*height = l2;
return TRUE;
}
static GpStatus
LinearGradientRectFromPoints(
const GpPointF& point1,
const GpPointF& point2,
GpRectF & rect
)
{
// If the API specifies two coincident points, we
// can't get information for the gradient, so we
// fail the construction here.
if( IsClosePointF(point1, point2) )
{
return InvalidParameter;
}
// Compute the bounding rectangle of the two input points.
rect.X = min(point1.X, point2.X);
rect.Y = min(point1.Y, point2.Y);
rect.Width = REALABS(point1.X-point2.X);
rect.Height = REALABS(point1.Y-point2.Y);
// eliminate degenerate rectangles when the two
// input points form a horizontal or vertical line.
// This is a very odd way of coercing a 1d linear gradient
// into a rect gradient and avoiding later matrix computation error
// when we try get an affine warp between this rectangle and a
// reference rectangle.
if( IsCloseReal(point1.X, point2.X) )
{
rect.X -= rect.Height/2;
rect.Width = rect.Height;
}
if( IsCloseReal(point1.Y, point2.Y) )
{
rect.Y -= rect.Width/2;
rect.Height = rect.Width;
}
return Ok;
}
static GpStatus
CalcLinearGradientXform(
REAL angle,
BOOL isAngleScalable,
const GpRectF& rect,
GpMatrix& xform
)
{
GpPointF p0, dP1, dP2;
angle = GpModF(angle, 360);
INT zone;
REALD deltaTheta;
const REALD degreeToRadian = 3.1415926535897932/180;
if(angle < 90)
{
zone = 0;
deltaTheta = angle;
}
else if(angle < 180)
{
zone = 1;
deltaTheta = 180 - angle;
}
else if(angle < 270)
{
zone = 2;
deltaTheta = angle - 180;
}
else
{
zone = 3;
deltaTheta = 360 - angle;
}
REALD s, c;
deltaTheta *= degreeToRadian;
s = sin(deltaTheta);
c = cos(deltaTheta);
// d0 is the distance between p0 and the starting corner of the
// original rectangle.
// d1 and d2 is the length of dP1 and dP2, respectively.
REALD top, left, w, h, d0, d1, d2;
REALD x0, y0; // Starting corner of the original rectangle.
GpPointD norm; // Direction of dP1.
// Direction of dP2 = (-norm.Y, norm.X) which is 90 degree rotation
// of dP1.
if(!isAngleScalable)
{
left = rect.X;
top = rect.Y;
w = rect.Width;
h = rect.Height;
}
else
{
// Scale to (0, 0, 1, 1) rectangle.
top = 0.0;
left = 0.0;
w = 1.0;
h = 1.0;
}
switch(zone)
{
case 0:
d0 = w*s;
norm.X = c;
norm.Y = s;
x0 = left;
y0 = top;
break;
case 1:
d0 = h*c;
norm.X = - c;
norm.Y = s;
x0 = left + w;
y0 = top;
break;
case 2:
d0 = w*s;
norm.X = - c;
norm.Y = - s;
x0 = left + w;
y0 = top + h;
break;
case 3:
d0 = h*c;
norm.X = c;
norm.Y = - s;
x0 = left;
y0 = top + h;
break;
}
d2 = w*s + h*c;
d1 = w*c + h*s;
p0.X = TOREAL(x0 + d0*norm.Y);
p0.Y = TOREAL(y0 - d0*norm.X);
dP1.X = TOREAL(d1*norm.X);
dP1.Y = TOREAL(d1*norm.Y);
dP2.X = TOREAL(- d2*norm.Y);
dP2.Y = TOREAL(d2*norm.X);
if(isAngleScalable)
{
// Scale back.
p0.X = rect.Width*p0.X + rect.X;
p0.Y = rect.Height*p0.Y + rect.Y;
dP1.X *= rect.Width;
dP1.Y *= rect.Height;
dP2.X *= rect.Width;
dP2.Y *= rect.Height;
}
// Set up the transform.
GpPointF points[3];
points[0] = p0;
points[1].X = p0.X + dP1.X;
points[1].Y = p0.Y + dP1.Y;
points[2].X = p0.X + dP2.X;
points[2].Y = p0.Y + dP2.Y;
GpStatus status;
if(xform.InferAffineMatrix(&points[0], rect) == Ok)
{
return Ok;
}
return InvalidParameter;
}
GpStatus
GpLineGradient::ChangeLinePoints(
const GpPointF& point1,
const GpPointF& point2,
BOOL isAngleScalable
)
{
GpStatus status;
GpRectF rect;
if ((status = LinearGradientRectFromPoints(point1, point2, rect)) != Ok)
{
return status;
}
REAL angle = GetAngleFromPoints(point1, point2);
GpMatrix xform;
if ((status = CalcLinearGradientXform(angle, isAngleScalable, rect, xform)) == Ok)
{
DeviceBrush.Xform = xform;
DeviceBrush.Rect = rect;
DeviceBrush.IsAngleScalable = isAngleScalable;
DeviceBrush.Points[0] = point1;
DeviceBrush.Points[1] = point2;
return Ok;
}
return status;
}
GpLineGradient::GpLineGradient(
const GpPointF& point1,
const GpPointF& point2,
const GpColor& color1,
const GpColor& color2,
GpWrapMode wrapMode
)
{
// Make sure the flat API has correctly set the FPU.
FPUStateSaver::AssertMode();
REAL angle;
GpRectF rect;
if (LinearGradientRectFromPoints(point1, point2, rect) != Ok)
{
SetValid(FALSE);
return;
}
// Compute the angle of the line formed by point1 and point2.
// Note atan2 is only undefined if dP.Y == 0.0 and dP.X == 0.0
// and then it returns 0 radians. We take care of that case separately
// (above).
// Also, atan2 correctly computes the quadrant from the two input points.
GpPointF dP = point2 - point1;
double rad = atan2((double)(dP.Y), (double)(dP.X));
SetLineGradient(
point1,
point2,
rect,
color1,
color2,
// why aren't we working in radians???
(REAL)(rad*180.0/3.1415926535897932),
FALSE,
wrapMode
);
}
/**************************************************************************\
*
* Function Description:
*
* Creates a LineGradient which is defined by the rectangle.
*
* Arguments:
*
* [IN] rect - the rectangle to define this gradient.
* [IN] color1 - the color of the start point.
* [IN] color2 - the color of the end point.
* [IN] mode - the line gradient mode
* [IN] wrapMode - the wrap mode of this brush.
*
* The start and end points of this gradient is defined as follows
* according to the line gradient mode:
*
* mode start point end point
* -------------------------------------------------------------
* LineGradientHorizontal top-left top-right
* LineGradientVertical top-right bottom-right
* LineGradientForwardDiagonal top-left bottom-right
* LineGradientBackwardDiagonal bottom-left top-right
*
*
* History:
*
* 06/03/1999 ikkof
* Created it.
*
\**************************************************************************/
GpLineGradient::GpLineGradient(
const GpRectF& rect,
const GpColor& color1,
const GpColor& color2,
LinearGradientMode mode,
GpWrapMode wrapMode
)
{
// Make sure the flat API has correctly set the FPU.
FPUStateSaver::AssertMode();
BOOL isAngleScalable = TRUE;
REAL angle = 0;
GpPointF point1;
GpPointF point2;
switch(mode)
{
case LinearGradientModeHorizontal:
angle = 0;
point1.X = rect.X;
point1.Y = (rect.Y + rect.GetBottom()) / 2.0f;
point2.X = rect.GetRight();
point2.Y = point1.Y;
break;
case LinearGradientModeVertical:
angle = 90;
point1.X = (rect.X + rect.GetRight()) / 2.0f;
point1.Y = rect.Y;
point2.X = point1.X;
point2.Y = rect.GetBottom();
break;
case LinearGradientModeForwardDiagonal:
angle = 45;
point1.X = rect.X;
point1.Y = rect.Y;
point2.X = rect.GetRight();
point2.Y = rect.GetBottom();
break;
case LinearGradientModeBackwardDiagonal:
angle = 135;
point1.X = rect.GetRight();
point1.Y = rect.Y;
point2.X = rect.X;
point2.Y = rect.GetBottom();
break;
default:
// No such a case.
ASSERT(0);
SetValid(FALSE);
return;
}
SetLineGradient(
point1,
point2,
rect,
color1,
color2,
angle,
isAngleScalable,
wrapMode);
}
/**************************************************************************\
*
* Function Description:
*
* Creates a LineGradient which is defined by the rectangle.
*
* Arguments:
*
* [IN] rect - the rectangle to define this gradient.
* [IN] color1 - the color of the start point.
* [IN] color2 - the color of the end point.
* [IN] angle - the angle of the gradient
* [IN] isAngleScalable - TRUE if 45 degree is corner to corner.
* The default value is FALSE.
* [IN] wrapMode - the wrap mode of this brush.
*
*
*
* History:
*
* 10/06/1999 ikkof
* Created it.
*
\**************************************************************************/
GpLineGradient::GpLineGradient(
const GpRectF& rect,
const GpColor& color1,
const GpColor& color2,
REAL angle,
BOOL isAngleScalable,
GpWrapMode wrapMode
)
{
// Make sure the flat API has correctly set the FPU.
FPUStateSaver::AssertMode();
GpPointF point1;
GpPointF point2;
// Not an Office scenario, but need to fix at some point
// so we can print to PCL better.
point1.X = point1.Y = point2.X = point2.Y = 0;
SetLineGradient(
point1,
point2,
rect,
color1,
color2,
angle,
isAngleScalable,
wrapMode);
}
GpStatus
GpLineGradient::SetLineGradient(
const GpPointF& point1,
const GpPointF& point2,
const GpRectF& rect,
const GpColor& color1,
const GpColor& color2,
REAL angle,
BOOL isAngleScalable,
GpWrapMode wrapMode
)
{
// Make sure the flat API has correctly set the FPU.
FPUStateSaver::AssertMode();
DeviceBrush.Wrap = wrapMode;
DeviceBrush.Colors[0] = color1;
DeviceBrush.Colors[1] = color2;
DeviceBrush.Colors[2] = color1;
DeviceBrush.Colors[3] = color2;
DeviceBrush.BlendCounts[0] = DeviceBrush.BlendCounts[1] = 1;
DeviceBrush.BlendFactors[0] = DeviceBrush.BlendFactors[1] = NULL;
DeviceBrush.Falloffs[0] = DeviceBrush.Falloffs[1] = 1;
GpStatus status;
if (CalcLinearGradientXform(angle, isAngleScalable, rect, DeviceBrush.Xform) == Ok)
{
SetValid(TRUE);
DeviceBrush.Rect = rect;
DeviceBrush.IsAngleScalable = isAngleScalable;
DeviceBrush.Points[0] = point1;
DeviceBrush.Points[1] = point2;
status = Ok;
}
else
{
SetValid(FALSE);
GpMemset(&DeviceBrush.Rect, 0, sizeof(DeviceBrush.Rect));
GpMemset(DeviceBrush.Points, 0, sizeof(DeviceBrush.Points[0]) * 2);
DeviceBrush.IsAngleScalable = FALSE;
status = InvalidParameter;
}
return status;
}
GpStatus
GpLineGradient::SetLinePoints(
const GpPointF& point1,
const GpPointF& point2
)
{
// Make sure the flat API has correctly set the FPU.
FPUStateSaver::AssertMode();
GpPointF p0, dP1, dP2;
p0 = point1;
dP1.X = point2.X - point1.X;
dP1.Y = point2.Y - point1.Y;
dP2.X = - dP1.Y;
dP2.Y = dP1.X;
REAL m[6];
REAL width, height;
if(getLineGradientTransform(&m[0], &width, &height, p0, dP1, dP2))
{
SetValid(TRUE);
DeviceBrush.Rect.X = p0.X;
DeviceBrush.Rect.Y = p0.Y;
DeviceBrush.Rect.Width = width;
DeviceBrush.Rect.Height = height;
}
else
{
// Don't change the current state.
return GenericError;
}
DeviceBrush.Xform.SetMatrix(m);
UpdateUid();
return Ok;
}
GpStatus
GpLineGradient::GetLinePoints(GpPointF* points)
{
// Make sure the flat API has correctly set the FPU.
FPUStateSaver::AssertMode();
ASSERT(points);
points[0].X = DeviceBrush.Rect.X;
points[0].Y = DeviceBrush.Rect.Y;
points[1].X = DeviceBrush.Rect.X + DeviceBrush.Rect.Width;
points[1].Y = DeviceBrush.Rect.Y + DeviceBrush.Rect.Height;
DeviceBrush.Xform.Transform(points, 2);
return Ok;
}
INT
GpLineGradient::GetPresetBlendCount()
{
if(DeviceBrush.UsesPresetColors)
return DeviceBrush.BlendCounts[0];
else
return 0;
}
/*
** This returns the premultiplied colors
*/
GpStatus
GpLineGradient::GetPresetBlend(
GpColor* blendColors,
REAL* blendPositions,
INT count)
{
// Make sure the flat API has correctly set the FPU.
FPUStateSaver::AssertMode();
if(!blendColors || !blendPositions || count <= 1)
return InvalidParameter;
if(DeviceBrush.UsesPresetColors &&
DeviceBrush.PresetColors &&
DeviceBrush.BlendPositions[0])
{
for(INT i = 0; i < count; i++)
{
blendColors[i].SetColor(DeviceBrush.PresetColors[i]);
}
GpMemcpy(blendPositions,
DeviceBrush.BlendPositions[0],
count*sizeof(REAL));
return Ok;
}
else
return GenericError;
}
GpStatus
GpLineGradient::SetPresetBlend(
const GpColor* blendColors,
const REAL* blendPositions,
INT count)
{
// Make sure the flat API has correctly set the FPU.
FPUStateSaver::AssertMode();
if(!blendColors || !blendPositions || count <= 1)
return InvalidParameter;
ARGB* newColors = (ARGB*) GpRealloc(DeviceBrush.PresetColors,
count*sizeof(ARGB));
if (newColors != NULL)
{
DeviceBrush.PresetColors = newColors;
}
else
{
return OutOfMemory;
}
REAL* newPositions = (REAL*) GpRealloc(DeviceBrush.BlendPositions[0],
count*sizeof(REAL));
if (newPositions != NULL)
{
DeviceBrush.BlendPositions[0] = newPositions;
}
else
{
return OutOfMemory;
}
GpFree(DeviceBrush.BlendFactors[0]);
// DeviceBrush.BlendFactors[1] is always NULL for LineGradient.
DeviceBrush.BlendFactors[0] = NULL;
DeviceBrush.UsesPresetColors = TRUE;
for(INT i = 0; i < count; i++)
{
newColors[i] = blendColors[i].GetValue();
}
GpMemcpy(newPositions, blendPositions, count*sizeof(REAL));
DeviceBrush.BlendCounts[0] = count;
UpdateUid();
return Ok;
}
/**************************************************************************\
*
* Function Description:
*
* Blend any transparent colors in this brush with white. Note that
* colors are premultiplied, since they will become fully opaque.
*
* Arguments:
*
* Return Value:
*
* GpStatus - Ok or failure status
*
\**************************************************************************/
GpStatus GpLineGradient::BlendWithWhite()
{
if (DeviceBrush.UsesPresetColors)
{
GpColor color;
for (INT i=0; i<DeviceBrush.BlendCounts[0]; i++)
{
color.SetValue(GpColor::ConvertToPremultiplied(DeviceBrush.PresetColors[i]));
color.BlendOpaqueWithWhite();
DeviceBrush.PresetColors[i] = color.GetValue();
}
return Ok;
}
else
{
return GpRectGradient::BlendWithWhite();
}
}
BOOL
GpPathGradient::IsRectangle() const
{
BOOL result = FALSE;
if (DeviceBrush.PointsPtr != NULL)
result = IsRectanglePoints(DeviceBrush.PointsPtr, DeviceBrush.Count, NULL, NULL);
else
{
GpPath* path = static_cast<GpPath*> (DeviceBrush.Path);
if(path)
result = path->IsRectangle(NULL);
}
return result;
}
INT
GpPathGradient::GetPresetBlendCount() const
{
if(DeviceBrush.UsesPresetColors)
return DeviceBrush.BlendCounts[0];
else
return 0;
}
/*
** This returns the premultiplied colors
*/
GpStatus
GpPathGradient::GetPresetBlend(
GpColor* blendColors,
REAL* blendPositions,
INT count) const
{
if(!blendColors || !blendPositions || count <= 1)
return InvalidParameter;
if(DeviceBrush.UsesPresetColors && DeviceBrush.PresetColors && DeviceBrush.BlendPositions[0])
{
// Users will obtain the preset colors as radial blend colors.
// 0 position means the center location and 1 position means the
// the outer edge. In order to convert those colors and position arrays
// from the weight factor arrays in PathGradient,
// we must invert the order of the returned arrays.
for(INT i = 0; i < count; i++)
{
blendColors[count - 1 -i].SetColor(DeviceBrush.PresetColors[i]);
blendPositions[count - 1 -i] = TOREAL(1.0 - DeviceBrush.BlendPositions[0][i]);
}
return Ok;
}
else
return GenericError;
}
GpStatus
GpPathGradient::SetPresetBlend(
const GpColor* blendColors,
const REAL* blendPositions,
INT count)
{
if(!blendColors || !blendPositions || count <= 1)
return InvalidParameter;
ARGB* newColors = (ARGB*) GpRealloc(DeviceBrush.PresetColors, count*sizeof(ARGB));
if (newColors != NULL)
{
DeviceBrush.PresetColors = newColors;
}
else
{
return OutOfMemory;
}
REAL* newPositions = (REAL*) GpRealloc(DeviceBrush.BlendPositions[0], count*sizeof(REAL));
if (newPositions != NULL)
{
DeviceBrush.BlendPositions[0] = newPositions;
}
else
{
return OutOfMemory;
}
GpFree(DeviceBrush.BlendFactors[0]);
DeviceBrush.BlendFactors[0] = NULL;
DeviceBrush.UsesPresetColors = TRUE;
// Users will supply the preset colors as radial blend colors.
// 0 position means the center location and 1 position means the
// the outer edge. In order to convert those colors and position arrays
// to the weight factor arrays in PathGradient,
// we must invert the order of the given arrays.
for(INT i = 0; i < count; i++)
{
// PresetColors are stored non-premultiplied.
newColors[count - 1 - i] = blendColors[i].GetValue();
newPositions[count - 1 - i] = TOREAL(1.0 - blendPositions[i]);
}
DeviceBrush.BlendCounts[0] = count;
UpdateUid();
return Ok;
}
//==================================================================
// Copy constructors
//==================================================================
GpElementaryBrush::GpElementaryBrush(const GpElementaryBrush *brush)
{
if(brush && brush->IsValid())
{
// !!! [asecchia] we should really be asking the DeviceBrush to
// copy it's members instead of duplicating the code all over
// the place. Current code is error prone - each subclass is has to
// know all about how to copy and what has or hasn't been updated on
// the chain down to it's ancestor.
DeviceBrush.Xform = brush->DeviceBrush.Xform;
DeviceBrush.Wrap = brush->DeviceBrush.Wrap;
DeviceBrush.IsGammaCorrected = brush->DeviceBrush.IsGammaCorrected;
SetValid(brush->IsValid());
}
else
SetValid(FALSE);
}
GpTexture::GpTexture(
const GpTexture *brush
) : GpElementaryBrush(brush)
{
if(brush && brush->IsValid())
{
const DpBrush* devBrush = &(brush->DeviceBrush);
InitializeBrush(brush->Image, devBrush->Wrap, NULL);
SetTransform(devBrush->Xform);
}
else
SetValid(FALSE);
}
GpRectGradient::GpRectGradient(
const GpRectGradient *brush
) : GpGradientBrush(brush)
{
if(brush && brush->IsValid())
{
const DpBrush* devBrush = &(brush->DeviceBrush);
InitializeBrush(
devBrush->Rect,
&(devBrush->Colors[0]),
devBrush->Wrap
);
SetTransform(devBrush->Xform);
SetHorizontalBlend(
devBrush->BlendFactors[0],
devBrush->BlendPositions[0],
devBrush->BlendCounts[0]
);
SetVerticalBlend(
devBrush->BlendFactors[1],
devBrush->BlendPositions[1],
devBrush->BlendCounts[1]
);
}
else
SetValid(FALSE);
}
GpLineGradient::GpLineGradient(
const GpLineGradient *brush
) : GpRectGradient(brush)
{
if(brush && brush->IsValid())
{
// Copy the preset colors.
// !!! [asecchia] why isn't this handled in a uniform way?
const DpBrush* devBrush = &(brush->DeviceBrush);
DeviceBrush.Points[0] = devBrush->Points[0];
DeviceBrush.Points[1] = devBrush->Points[1];
DeviceBrush.IsAngleScalable = devBrush->IsAngleScalable;
if(devBrush->UsesPresetColors)
{
SetPresetBlend(
(GpColor*)(devBrush->PresetColors),
(REAL*)(devBrush->BlendPositions[0]),
devBrush->BlendCounts[0]
);
}
}
}
GpPathGradient::GpPathGradient(
const GpPathGradient *brush
) : GpGradientBrush(brush)
{
if(brush && brush->IsValid())
{
const DpBrush* devBrush = &(brush->DeviceBrush);
// If a path exists for the brush, use that for initialization.
// Otherwise, use the points collection.
if (devBrush->Path != NULL)
{
DefaultBrush();
DeviceBrush.Wrap = devBrush->Wrap;
DeviceBrush.Path = devBrush->Path->ClonePath();
PrepareBrush();
}
else
{
InitializeBrush(devBrush->PointsPtr,
devBrush->Count,
devBrush->Wrap);
}
if(IsValid())
{
SetTransform(devBrush->Xform);
SetCenterPoint(devBrush->Points[0]);
SetCenterColor(devBrush->Colors[0]);
SetSurroundColors(devBrush->ColorsPtr);
DeviceBrush.Falloffs[0] = devBrush->Falloffs[0];
DeviceBrush.FocusScaleX = devBrush->FocusScaleX;
DeviceBrush.FocusScaleY = devBrush->FocusScaleY;
DeviceBrush.UsesPresetColors = devBrush->UsesPresetColors;
INT blendCount = devBrush->BlendCounts[0];
DeviceBrush.BlendCounts[0] = blendCount;
// If we're cloning a brush with preset colors, copy preset colors
// and blend positions. Otherwise, copy the blend factors and
// blend positions.
if (devBrush->UsesPresetColors)
{
ARGB* newColors = (ARGB*) GpRealloc(DeviceBrush.PresetColors, blendCount*sizeof(ARGB));
if (newColors != NULL)
{
DeviceBrush.PresetColors = newColors;
REAL* newPositions = (REAL*) GpRealloc(DeviceBrush.BlendPositions[0], blendCount*sizeof(REAL));
if (newPositions != NULL)
{
DeviceBrush.BlendPositions[0] = newPositions;
GpFree(DeviceBrush.BlendFactors[0]);
DeviceBrush.BlendFactors[0] = NULL;
memcpy(DeviceBrush.PresetColors,
devBrush->PresetColors,
blendCount*sizeof(ARGB));
memcpy(DeviceBrush.BlendPositions[0],
devBrush->BlendPositions[0],
blendCount*sizeof(REAL));
}
else
{
SetValid(FALSE);
}
}
else
{
SetValid(FALSE);
}
}
else if (devBrush->BlendFactors[0] && devBrush->BlendPositions[0])
{
REAL* newFactors = (REAL*) GpRealloc(DeviceBrush.BlendFactors[0], blendCount*sizeof(REAL));
if (newFactors != NULL)
{
DeviceBrush.BlendFactors[0] = newFactors;
REAL* newPositions = (REAL*) GpRealloc(DeviceBrush.BlendPositions[0], blendCount*sizeof(REAL));
if (newPositions != NULL)
{
DeviceBrush.BlendPositions[0] = newPositions;
memcpy(DeviceBrush.BlendFactors[0],
devBrush->BlendFactors[0],
blendCount*sizeof(REAL));
memcpy(DeviceBrush.BlendPositions[0],
devBrush->BlendPositions[0],
blendCount*sizeof(REAL));
}
else
{
SetValid(FALSE);
}
}
else
{
SetValid(FALSE);
}
}
}
}
else
SetValid(FALSE);
}
GpHatch::GpHatch(const GpHatch* brush)
{
if(brush && brush->IsValid())
{
const DpBrush* devBrush = &(brush->DeviceBrush);
InitializeBrush(devBrush->Style,
devBrush->Colors[0],
devBrush->Colors[1]);
}
else
SetValid(FALSE);
}
/**************************************************************************\
*
* Function Description:
*
* Getting horizontal falloff / blend-factors for
* a rectangular gradient brush object
*
* Arguments:
*
* [OUT] blendFactors - Buffer for returning the horizontal
* falloff or blend-factors.
* count - Size of the buffer (in number of REAL elements)
*
* Return Value:
*
* Status code
*
\**************************************************************************/
GpStatus
GpRectGradient::GetHorizontalBlend(
REAL* blendFactors,
REAL* blendPositions,
INT count
)
{
if(!blendFactors || !blendPositions || count < 1)
return InvalidParameter;
// Check if the input buffer is big enough
if (count < DeviceBrush.BlendCounts[0])
return InsufficientBuffer;
if (DeviceBrush.BlendCounts[0] == 1)
{
// Return falloff parameter
blendFactors[0] = DeviceBrush.Falloffs[0];
}
else
{
// Return blend factors
GpMemcpy(
blendFactors,
DeviceBrush.BlendFactors[0],
DeviceBrush.BlendCounts[0]*sizeof(REAL)
);
GpMemcpy(
blendPositions,
DeviceBrush.BlendPositions[0],
DeviceBrush.BlendCounts[0]*sizeof(REAL)
);
}
return Ok;
}
/**************************************************************************\
*
* Function Description:
*
* Setting horizontal falloff / blend-factors for
* a rectangular gradient brush object
*
* Arguments:
*
* [IN] blendFactors - Specify the new blend factors
* count - Number of elements in the blend factor array
*
* Return Value:
*
* Status code
*
\**************************************************************************/
GpStatus
GpRectGradient::SetHorizontalBlend(
const REAL* blendFactors,
const REAL* blendPositions,
INT count
)
{
if(!blendFactors || !blendPositions || count < 1)
return InvalidParameter;
if (count == 1)
{
// Setting falloff parameter
GpFree(DeviceBrush.BlendFactors[0]);
DeviceBrush.BlendFactors[0] = NULL;
GpFree(DeviceBrush.BlendPositions[0]);
DeviceBrush.BlendPositions[0] = NULL;
if (blendFactors == NULL)
DeviceBrush.Falloffs[0] = 1;
else
DeviceBrush.Falloffs[0] = blendFactors[0];
DeviceBrush.BlendCounts[0] = 1;
}
else
{
ASSERT(blendFactors != NULL && blendPositions != NULL);
// blend positions must start at 0.0 and end at 1.0
if (REALABS(blendPositions[0]) > REAL_EPSILON ||
REALABS(1.0f - blendPositions[count-1]) > REAL_EPSILON)
{
return InvalidParameter;
}
// Setting blend factors
REAL* newFactors;
REAL* newPositions;
newFactors = (REAL*) GpRealloc(DeviceBrush.BlendFactors[0], count*sizeof(REAL));
if (newFactors != NULL)
{
DeviceBrush.BlendFactors[0] = newFactors;
}
else
{
return OutOfMemory;
}
newPositions = (REAL*) GpRealloc(DeviceBrush.BlendPositions[0], count*sizeof(REAL));
if (newPositions != NULL)
{
DeviceBrush.BlendPositions[0] = newPositions;
}
else
{
return OutOfMemory;
}
if (newFactors == NULL || newPositions == NULL)
return OutOfMemory;
GpMemcpy(newFactors, blendFactors, count*sizeof(REAL));
GpMemcpy(newPositions, blendPositions, count*sizeof(REAL));
DeviceBrush.BlendCounts[0] = count;
}
DeviceBrush.UsesPresetColors = FALSE;
GpFree(DeviceBrush.PresetColors);
DeviceBrush.PresetColors = NULL;
UpdateUid();
return Ok;
}
/**************************************************************************\
*
* Function Description:
*
* Getting vertical falloff / blend-factors for
* a rectangular gradient brush object
*
* Arguments:
*
* [OUT] blendFactors - Buffer for returning the vertical
* falloff or blend-factors.
* count - Size of the buffer (in number of REAL elements)
*
* Return Value:
*
* Status code
*
\**************************************************************************/
GpStatus
GpRectGradient::GetVerticalBlend(
REAL* blendFactors,
REAL* blendPositions,
INT count
)
{
if(!blendFactors || !blendPositions || count < 1)
return InvalidParameter;
// Check if the input buffer is big enough
if (count < DeviceBrush.BlendCounts[1])
return InsufficientBuffer;
if (DeviceBrush.BlendCounts[1] == 1)
{
// Return falloff parameter
blendFactors[0] = DeviceBrush.Falloffs[1];
}
else
{
// Return blend factors
GpMemcpy(
blendFactors,
DeviceBrush.BlendFactors[1],
DeviceBrush.BlendCounts[1]*sizeof(REAL));
GpMemcpy(
blendPositions,
DeviceBrush.BlendPositions[1],
DeviceBrush.BlendCounts[1]*sizeof(REAL));
}
return Ok;
}
/**************************************************************************\
*
* Function Description:
*
* Setting vertical falloff / blend-factors for
* a rectangular gradient brush object
*
* Arguments:
*
* [IN] blendFactors - Specify the new blend factors
* count - Number of elements in the blend factor array
*
* Return Value:
*
* Status code
*
\**************************************************************************/
GpStatus
GpRectGradient::SetVerticalBlend(
const REAL* blendFactors,
const REAL* blendPositions,
INT count
)
{
if(!blendFactors || !blendPositions || count < 1)
return InvalidParameter;
if (count == 1)
{
// Setting falloff parameter
GpFree(DeviceBrush.BlendFactors[1]);
DeviceBrush.BlendFactors[1] = NULL;
GpFree(DeviceBrush.BlendPositions[1]);
DeviceBrush.BlendPositions[1] = NULL;
if (blendFactors == NULL)
DeviceBrush.Falloffs[1] = 1;
else
DeviceBrush.Falloffs[1] = blendFactors[0];
DeviceBrush.BlendCounts[1] = 1;
}
else
{
ASSERT(blendFactors != NULL && blendPositions != NULL);
// Setting blend factors
REAL* newFactors;
REAL* newPositions;
newFactors = (REAL*) GpRealloc(DeviceBrush.BlendFactors[1], count*sizeof(REAL));
if (newFactors != NULL)
{
DeviceBrush.BlendFactors[1] = newFactors;
}
else
{
return OutOfMemory;
}
newPositions = (REAL*) GpRealloc(DeviceBrush.BlendPositions[1], count*sizeof(REAL));
if (newPositions != NULL)
{
DeviceBrush.BlendPositions[1] = newPositions;
}
else
{
return OutOfMemory;
}
GpMemcpy(newFactors, blendFactors, count*sizeof(REAL));
GpMemcpy(newPositions, blendPositions, count*sizeof(REAL));
DeviceBrush.BlendCounts[1] = count;
}
DeviceBrush.UsesPresetColors = FALSE;
GpFree(DeviceBrush.PresetColors);
DeviceBrush.PresetColors = NULL;
UpdateUid();
return Ok;
}
/**************************************************************************\
*
* Function Description:
*
* Blend any transparent colors in this brush with white. Note that colors
* are converted to premultiplied first, since they will become fully opaque.
*
* Arguments:
*
* Return Value:
*
* GpStatus - Ok or failure status
*
\**************************************************************************/
GpStatus GpRectGradient::BlendWithWhite()
{
GpColor color;
for (INT i=0; i<4; i++)
{
color.SetValue(DeviceBrush.Colors[i].GetPremultipliedValue());
color.BlendOpaqueWithWhite();
DeviceBrush.Colors[i] = color.GetValue();
}
return Ok;
}
//--------------------------------------------------------------------------
// Path Gradient
//--------------------------------------------------------------------------
VOID
GpPathGradient::PrepareBrush()
{
GpPath* path = static_cast<GpPath*> (DeviceBrush.Path);
if (path)
{
DeviceBrush.Count = path->Points.GetCount();
GpPointF* points = path->Points.GetDataBuffer();
if(!DeviceBrush.ColorsPtr)
{
DeviceBrush.ColorsPtr = (GpColor*)GpMalloc(DeviceBrush.Count*sizeof(GpColor));
if (DeviceBrush.ColorsPtr != NULL)
GpMemset(&DeviceBrush.ColorsPtr[0], 255, DeviceBrush.Count*sizeof(GpColor));
}
REAL xmin, xmax, ymin, ymax, x0, y0;
x0 = xmin = xmax = points[0].X;
y0 = ymin = ymax = points[0].Y;
for(INT i = 1; i < DeviceBrush.Count; i++)
{
x0 += points[i].X;
y0 += points[i].Y;
xmin = min(xmin, points[i].X);
xmax = max(xmax, points[i].X);
ymin = min(ymin, points[i].Y);
ymax = max(ymax, points[i].Y);
}
DeviceBrush.Rect.X = xmin;
DeviceBrush.Rect.Width = xmax - xmin;
DeviceBrush.Rect.Y = ymin;
DeviceBrush.Rect.Height = ymax - ymin;
if(!WrapModeIsValid(DeviceBrush.Wrap) || DeviceBrush.Rect.Width <= 0 || DeviceBrush.Rect.Height <= 0)
return;
DeviceBrush.Points[0].X = x0/DeviceBrush.Count;
DeviceBrush.Points[0].Y = y0/DeviceBrush.Count;
SetValid(TRUE);
}
}
GpStatus
GpPathGradient::Flatten(GpMatrix* matrix) const
{
GpPath* path = static_cast<GpPath*> (DeviceBrush.Path);
if(!path)
return Ok;
if(path->HasCurve())
{
INT origCount = DeviceBrush.Count;
GpStatus status = path->Flatten(
const_cast<DynByteArray*>(&FlattenTypes),
const_cast<DynPointFArray*> (&FlattenPoints),
matrix);
if(status == Ok)
{
DeviceBrush.Count = FlattenPoints.GetCount();
DeviceBrush.PointsPtr = FlattenPoints.GetDataBuffer();
if ((DeviceBrush.Count > origCount) &&
(DeviceBrush.ColorsPtr != NULL))
{
// The colors array is no longer the proper size. Adjust the
// size and copy up the last color. It is the apps responsibility
// to estimate and specify the correct number of flattened points.
const_cast<GpColor*>(DeviceBrush.ColorsPtr) = (GpColor*) GpRealloc((VOID*)DeviceBrush.ColorsPtr,
sizeof(GpColor)*DeviceBrush.Count);
if (DeviceBrush.ColorsPtr != NULL)
{
GpColor copyColor = (origCount > 1) ?
DeviceBrush.ColorsPtr[origCount-1] :
GpColor(0xFFFFFFFF);
for (INT i=origCount; i<DeviceBrush.Count; i++)
{
DeviceBrush.ColorsPtr[i] = copyColor;
}
}
else
{
return OutOfMemory;
}
}
}
}
else
{
DeviceBrush.Count = path->GetPointCount();
DeviceBrush.PointsPtr = const_cast<GpPointF*> (path->GetPathPoints());
}
return Ok;
}
GpStatus
GpPathGradient::GetBlend(
REAL* blendFactors,
REAL* blendPositions,
INT count
) const
{
if(!blendFactors || !blendPositions || count < 1)
return InvalidParameter;
// Check if the input buffer is big enough
if (count < DeviceBrush.BlendCounts[0])
return InsufficientBuffer;
if (DeviceBrush.BlendCounts[0] == 1)
{
// Return falloff parameter
blendFactors[0] = DeviceBrush.Falloffs[0];
}
else
{
// Return blend factors
// Users want to obtain the blend factor as radial blend factors.
// 0 blend factor means 100 % center color and 0 position means
// the center location. In order to return those factor and
// position arrays, we must invert the weight and position factor
// arrays stored in this PathGradient class.
for(INT i = 0; i < DeviceBrush.BlendCounts[0]; i++)
{
blendFactors[DeviceBrush.BlendCounts[0] - 1 - i] = TOREAL(1.0 - DeviceBrush.BlendFactors[0][i]);
blendPositions[DeviceBrush.BlendCounts[0] - 1 - i] = TOREAL(1.0 - DeviceBrush.BlendPositions[0][i]);
}
}
return Ok;
}
GpStatus
GpPathGradient::SetBlend(
const REAL* blendFactors,
const REAL* blendPositions,
INT count
)
{
if(!blendFactors || !blendPositions || count < 1)
return InvalidParameter;
if (count == 1)
{
// Setting falloff parameter
GpFree(DeviceBrush.BlendFactors[0]);
DeviceBrush.BlendFactors[0] = NULL;
GpFree(DeviceBrush.BlendPositions[0]);
DeviceBrush.BlendPositions[0] = NULL;
if (blendFactors == NULL)
DeviceBrush.Falloffs[0] = 1;
else
DeviceBrush.Falloffs[0] = blendFactors[0];
DeviceBrush.BlendCounts[0] = 1;
}
else
{
// blend positions must start at 0.0 and end at 1.0
if (REALABS(blendPositions[0]) > REAL_EPSILON ||
REALABS(1.0f - blendPositions[count-1]) > REAL_EPSILON)
{
return InvalidParameter;
}
// Setting blend factors
REAL* newFactors;
REAL* newPositions;
newFactors = (REAL*) GpRealloc(DeviceBrush.BlendFactors[0], count*sizeof(REAL));
if (newFactors != NULL)
{
DeviceBrush.BlendFactors[0] = newFactors;
}
else
{
return OutOfMemory;
}
newPositions = (REAL*) GpRealloc(DeviceBrush.BlendPositions[0], count*sizeof(REAL));
if (newPositions != NULL)
{
DeviceBrush.BlendPositions[0] = newPositions;
}
else
{
return OutOfMemory;
}
// Users will supply the blend factor as radial blend factors.
// 0 blend factor means 100 % center color and 0 position means
// the center location. In order to convert those factor and position arrays
// to the weight and position factor arrays in PathGradient,
// we must invert the given arrays.
for(INT i = 0; i < count; i++)
{
newFactors[count - 1 - i] = TOREAL(1.0 - blendFactors[i]);
newPositions[count - 1 - i] = TOREAL(1.0 - blendPositions[i]);
}
DeviceBrush.BlendCounts[0] = count;
}
DeviceBrush.UsesPresetColors = FALSE;
GpFree(DeviceBrush.PresetColors);
DeviceBrush.PresetColors = NULL;
UpdateUid();
return Ok;
}
GpStatus
GpGradientBrush::GetSigmaBlendArray(
REAL focus,
REAL scale,
INT* count,
REAL* blendFactors,
REAL* blendPositions)
{
// Make sure the FPU is set correctly.
FPUStateSaver::AssertMode();
if(!blendFactors || !blendPositions || !count)
return InvalidParameter;
// This gives 1/4 of the Sigma array.
static REAL factors[] =
{
0, 59, 120, 182, 247, 314, 383, 454,
527, 602, 680, 759, 841, 926, 1013, 1102,
1194, 1288, 1385, 1485, 1587, 1692, 1800, 1911,
2024, 2141, 2260, 2383, 2508, 2637, 2769, 2904,
3042, 3183, 3328, 3477, 3628, 3783, 3942, 4104,
4270, 4439, 4612, 4789, 4969, 5153, 5341, 5533,
5728, 5928, 6131, 6338, 6549, 6764, 6983, 7206,
7434, 7665, 7900, 8139, 8382, 8630, 8881, 9136,
9396, 9660, 9927, 10199, 10475, 10755, 11039, 11327,
11619, 11916, 12216, 12520, 12828, 13140, 13456, 13776,
14099, 14427, 14758, 15093, 15431, 15774, 16119, 16469,
16822, 17178, 17538, 17901, 18267, 18637, 19009, 19385,
19764, 20146, 20530, 20918, 21308, 21701, 22096, 22494,
22894, 23297, 23702, 24109, 24518, 24929, 25342, 25756,
26173, 26591, 27010, 27431, 27853, 28276, 28701, 29126,
29552, 29979, 30407, 30836, 31264, 31694, 32123, 32553
};
if(focus < 0 || focus > 1 || scale < 0 || scale > 1)
return InvalidParameter;
if(blendFactors && blendPositions)
{
INT i, n;
scale /= 65536;
REAL one = 65536;
if(focus > 0 && focus < 1)
{
for(i = 0; i < 128; i++)
{
blendFactors[i] = factors[i];
blendPositions[i] = focus*i/255;
}
for(i = 128; i < 256; i++)
{
blendFactors[i] = one - factors[255 - i];
blendPositions[i] = focus*i/255;
}
// skip i = 256 since this gives the same data.
for(i = 257; i < 384; i++)
{
blendFactors[i - 1] = one - factors[i - 256];
blendPositions[i - 1] = TOREAL(focus + (1.0 - focus)*(i - 256)/255);
}
for(i = 384; i < 512; i++)
{
blendFactors[i - 1] = factors[511 - i];
blendPositions[i - 1] = TOREAL(focus + (1.0 - focus)*(i - 256)/255);
}
// Set n to 511 because we skipped index 256 above to avoid
// the duplicate 1 entry in the ramp from 0 to 1 to 0.
n = 511;
}
else if(focus == 1)
{
for(i = 0; i < 128; i++)
{
blendFactors[i] = factors[i];
blendPositions[i] = TOREAL(i)/255;
}
for(i = 128; i < 256; i++)
{
blendFactors[i] = one - factors[255 - i];
blendPositions[i] = TOREAL(i)/255;
}
n = 256;
}
else // focus == 0
{
for(i = 256; i < 384; i++)
{
blendFactors[i - 256] = one - factors[i - 256];
blendPositions[i - 256] = TOREAL(i - 256)/255;
}
for(i = 384; i < 512; i++)
{
blendFactors[i - 256] = factors[511 - i];
blendPositions[i - 256] = TOREAL(i - 256)/255;
}
n = 256;
}
for(i = 0; i < n; i++)
blendFactors[i] *= scale;
*count = n;
return Ok;
}
else
return InvalidParameter;
}
GpStatus
GpGradientBrush::GetLinearBlendArray(
REAL focus,
REAL scale,
INT* count,
REAL* blendFactors,
REAL* blendPositions)
{
if(!blendFactors || !blendPositions || !count)
return InvalidParameter;
if(focus < 0 || focus > 1 || scale < 0 || scale > 1)
return InvalidParameter;
if(blendFactors && blendPositions)
{
if(focus > 0 && focus < 1)
{
blendFactors[0] = 0.0f;
blendFactors[1] = scale;
blendFactors[2] = 0.0f;
blendPositions[0] = 0.0f;
blendPositions[1] = focus;
blendPositions[2] = 1.0f;
*count = 3;
}
else if(focus == 1)
{
blendFactors[0] = 0.0f;
blendFactors[1] = scale;
blendPositions[0] = 0.0f;
blendPositions[1] = 1.0f;
*count = 2;
}
else // focus == 0
{
blendFactors[0] = scale;
blendFactors[1] = 0.0f;
blendPositions[0] = 0.0f;
blendPositions[1] = 1.0f;
*count = 2;
}
return Ok;
}
else
return InvalidParameter;
}
GpStatus
GpGradientBrush::SetSigmaBlend(
REAL focus,
REAL scale)
{
REAL* blendFactors = (REAL*) GpMalloc(512*sizeof(REAL));
REAL* blendPositions = (REAL*) GpMalloc(512*sizeof(REAL));
INT count;
GpStatus status;
if(blendFactors && blendPositions)
{
status = GetSigmaBlendArray(focus, scale,
&count, blendFactors, blendPositions);
if(status == Ok)
status = SetBlend(&blendFactors[0], &blendPositions[0], count);
}
else
status = OutOfMemory;
GpFree(blendFactors);
GpFree(blendPositions);
return status;
}
GpStatus
GpGradientBrush::SetLinearBlend(
REAL focus,
REAL scale)
{
REAL blendFactors[3];
REAL blendPositions[3];
INT count;
GpStatus status = GetLinearBlendArray(focus, scale,
&count, &blendFactors[0], &blendPositions[0]);
if(status != Ok)
return status;
return SetBlend(&blendFactors[0], &blendPositions[0], count);
}
//--------------------------------------------------------------------------
// Hatch Brush
//--------------------------------------------------------------------------
const BYTE GdipHatchPatterns8bpp[HatchStyleTotal][64] = {
{ // HatchStyleHorizontal, 0
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
},
{ // HatchStyleVertical, 1
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
},
{ // HatchStyleForwardDiagonal, 2
0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
0x80, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x80, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x80, 0xff, 0x80, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x80, 0xff, 0x80, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x80, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x80,
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff,
},
{ // HatchStyleBackwardDiagonal, 3
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x80,
0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x80, 0x00,
0x00, 0x00, 0x00, 0x80, 0xff, 0x80, 0x00, 0x00,
0x00, 0x00, 0x80, 0xff, 0x80, 0x00, 0x00, 0x00,
0x00, 0x80, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00,
0x80, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
},
{ // HatchStyleCross, 4
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
},
{ // HatchStyleDiagonalCross 5
0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff,
0x80, 0xff, 0x80, 0x00, 0x00, 0x80, 0xff, 0x80,
0x00, 0x80, 0xff, 0x80, 0x80, 0xff, 0x80, 0x00,
0x00, 0x00, 0x80, 0xff, 0xff, 0x80, 0x00, 0x00,
0x00, 0x00, 0x80, 0xff, 0xff, 0x80, 0x00, 0x00,
0x00, 0x80, 0xff, 0x80, 0x80, 0xff, 0x80, 0x00,
0x80, 0xff, 0x80, 0x00, 0x00, 0x80, 0xff, 0x80,
0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff,
},
{ // HatchStyle05Percent, 6
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
},
{ // HatchStyle10Percent, 7
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
},
{ // HatchStyle20Percent, 8
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
},
{ // HatchStyle25Percent, 9
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00,
},
{ // HatchStyle30Percent, 10
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
},
{ // HatchStyle40Percent, 11
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
},
{ // HatchStyle50Percent, 12
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
},
{ // HatchStyle60Percent, 13
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff,
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff,
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
},
{ // HatchStyle70Percent, 14
0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff,
0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff,
0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff,
0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff,
},
{ // HatchStyle75Percent, 15
0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
},
{ // HatchStyle80Percent, 16
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
},
{ // HatchStyle90Percent, 17
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
},
{ // HatchStyleLightDownwardDiagonal, 18
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
},
{ // HatchStyleLightUpwardDiagonal, 19
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00,
0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00,
0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
},
{ // HatchStyleDarkDownwardDiagonal, 20
0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00,
0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff,
0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00,
0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff,
},
{ // HatchStyleDarkUpwardDiagonal, 21
0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00,
0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff,
0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00,
0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff,
},
{ // HatchStyleWideDownwardDiagonal, 22
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
},
{ // HatchStyleWideUpwardDiagonal, 23
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,
0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
},
{ // HatchStyleLightVertical, 24
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
},
{ // HatchStyleLightHorizontal, 25
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
},
{ // HatchStyleNarrowVertical, 26
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
},
{ // HatchStyleNarrowHorizontal, 27
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
},
{ // HatchStyleDarkVertical, 28
0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
},
{ // HatchStyleDarkHorizontal, 29
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
},
{ // HatchStyleDashedDownwardDiagonal, 30
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
},
{ // HatchStyleDashedUpwardDiagonal, 31
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00,
0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
},
{ // HatchStyleDashedHorizontal, 32
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
},
{ // HatchStyleDashedVertical, 33
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
},
{ // HatchStyleSmallConfetti, 34
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
},
{ // HatchStyleLargeConfetti, 35
0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff,
0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff,
},
{ // HatchStyleZigZag, 36
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00,
},
{ // HatchStyleWave, 37
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0xff,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0xff,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
},
{ // HatchStyleDiagonalBrick, 38
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00,
0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
},
{ // HatchStyleHorizontalBrick, 39
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
},
{ // HatchStyleWeave, 40
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00,
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00,
0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00,
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00,
0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
},
{ // HatchStylePlaid, 41
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
},
{ // HatchStyleDivot, 42
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
},
{ // HatchStyleDottedGrid, 43
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
},
{ // HatchStyleDottedDiamond, 44
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
},
{ // HatchStyleShingle, 45
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
},
{ // HatchStyleTrellis, 46
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff,
},
{ // HatchStyleSphere, 47
0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff,
0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,
},
{ // HatchStyleSmallGrid, 48
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
},
{ // HatchStyleSmallCheckerBoard, 49
0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff,
0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00,
0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00,
0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff,
0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff,
0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00,
0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00,
0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff,
},
{ // HatchStyleLargeCheckerBoard, 50
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
},
{ // HatchStyleOutlinedDiamond, 51
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
},
{ // HatchStyleSolidDiamond, 52
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
},
};
VOID
GpHatch::InitializeData()
{
if ((DeviceBrush.Style >= HatchStyleMin) &&
(DeviceBrush.Style <= HatchStyleMax))
{
GpMemcpy(DeviceBrush.Data, GdipHatchPatterns8bpp[DeviceBrush.Style], 64);
}
else
{
WARNING1("Bad Hatch Style Value");
GpMemset(DeviceBrush.Data, 0x00, 64); // make it transparent
}
}
/***************************************************************************\
*
* Equivalence comparsion functions
*
\***************************************************************************/
/**************************************************************************\
*
* Function Description:
*
* Answer TRUE if brush and the receiver are equivalent (i.e. - they will
* render indentically)
*
* Arguments:
*
* [IN] brush - GpBrush, or subclass, to compare this against.
*
* Return Value:
*
* TRUE if equivalent
*
* Created - 5/28/99 peterost
*
\**************************************************************************/
BOOL
GpHatch::IsEqual(const GpBrush * brush) const
{
if(!brush)
return FALSE;
if (brush == this)
return TRUE;
if (GpBrush::IsEqual(brush))
{
const GpHatch * hbrush = static_cast<const GpHatch *>(brush);
return hbrush->DeviceBrush.Style == DeviceBrush.Style &&
hbrush->DeviceBrush.Colors[0].IsEqual(DeviceBrush.Colors[0]) &&
hbrush->DeviceBrush.Colors[1].IsEqual(DeviceBrush.Colors[1]);
}
else
{
return FALSE;
}
}
/**************************************************************************\
*
* Function Description:
*
* Answer TRUE if brush and the receiver are equivalent (i.e. - they will
* render indentically). RectGradient brushes require all four colors and
* blend factors to be equal.
*
* Arguments:
*
* [IN] brush - GpBrush, or subclass, to compare this against.
*
* Return Value:
*
* TRUE if equivalent
*
* Created - 5/28/99 peterost
*
\**************************************************************************/
BOOL
GpRectGradient::IsEqual(const GpBrush * brush) const
{
if(!brush)
return FALSE;
if (brush == this)
return TRUE;
if (GpGradientBrush::IsEqual(brush))
{
const GpRectGradient * rbrush = static_cast<const GpRectGradient *>(brush);
if (rbrush->DeviceBrush.UsesPresetColors == DeviceBrush.UsesPresetColors &&
rbrush->DeviceBrush.BlendCounts[0] == DeviceBrush.BlendCounts[0] &&
rbrush->DeviceBrush.BlendCounts[1] == DeviceBrush.BlendCounts[1])
{
INT i;
if (DeviceBrush.UsesPresetColors)
{
// For preset colors, only the horizontal blend variables are used.
for (INT i=0; i<DeviceBrush.BlendCounts[0]; i++)
{
if (rbrush->DeviceBrush.PresetColors[i] != DeviceBrush.PresetColors[i] ||
rbrush->DeviceBrush.BlendPositions[0][i] != DeviceBrush.BlendPositions[0][i])
return FALSE;
}
}
else
{
for (i=0; i<4; i++)
{
if (!rbrush->DeviceBrush.Colors[i].IsEqual(DeviceBrush.Colors[i]))
return FALSE;
}
if (DeviceBrush.BlendCounts[0] > 1)
{
for (i=0; i<DeviceBrush.BlendCounts[0]; i++)
{
if (rbrush->DeviceBrush.BlendFactors[0][i] != DeviceBrush.BlendFactors[0][i] ||
rbrush->DeviceBrush.BlendPositions[0][i] != DeviceBrush.BlendPositions[0][i])
return FALSE;
}
}
else if (rbrush->DeviceBrush.Falloffs[0] != DeviceBrush.Falloffs[0])
{
return FALSE;
}
if (DeviceBrush.BlendCounts[1] > 1)
{
for (i=0; i<DeviceBrush.BlendCounts[1]; i++)
{
if (rbrush->DeviceBrush.BlendFactors[1][i] != DeviceBrush.BlendFactors[1][i] ||
rbrush->DeviceBrush.BlendPositions[1][i] != DeviceBrush.BlendPositions[1][i])
return FALSE;
}
}
else if (rbrush->DeviceBrush.Falloffs[1] != DeviceBrush.Falloffs[1])
{
return FALSE;
}
}
return TRUE;
}
else
{
return FALSE;
}
}
else
{
return FALSE;
}
}
/**************************************************************************\
*
* Function Description:
*
* Answer TRUE if brush and the receiver are equivalent (i.e. - they will
* render indentically).
*
* Arguments:
*
* [IN] brush - GpBrush, or subclass, to compare this against.
*
* Return Value:
*
* TRUE if equivalent
*
* Created - 6/2/99 peterost
*
\**************************************************************************/
#if 0
BOOL
GpRadialGradient::IsEqual(const GpBrush * brush) const
{
if(!brush)
return FALSE;
if (brush == this)
return TRUE;
if (GpGradientBrush::IsEqual(brush))
{
const GpRadialGradient * rbrush = static_cast<const GpRadialGradient *>(brush);
if (rbrush->DeviceBrush.UsesPresetColors == DeviceBrush.UsesPresetColors &&
rbrush->DeviceBrush.BlendCounts[0] == DeviceBrush.BlendCounts[0])
{
if (DeviceBrush.UsesPresetColors)
{
for (INT i=0; i<DeviceBrush.BlendCounts[0]; i++)
{
if (rbrush->DeviceBrush.PresetColors[i] != DeviceBrush.PresetColors[i] ||
rbrush->DeviceBrush.BlendPositions[0][i] != DeviceBrush.BlendPositions[0][i])
return FALSE;
}
}
else
{
if (rbrush->DeviceBrush.Colors[0].IsEqual(DeviceBrush.Colors[0]) &&
rbrush->DeviceBrush.Colors[1].IsEqual(DeviceBrush.Colors[1]))
{
if (DeviceBrush.BlendCounts[0] > 1)
{
for (INT i=0; i<DeviceBrush.BlendCounts[0]; i++)
{
if (rbrush->DeviceBrush.BlendFactors[0][i] != DeviceBrush.BlendFactors[0][i] ||
rbrush->DeviceBrush.BlendPositions[0][i] != DeviceBrush.BlendPositions[0][i])
return FALSE;
}
}
else if (rbrush->DeviceBrush.Falloffs[0] != DeviceBrush.Falloffs[0])
{
return FALSE;
}
}
else
{
return FALSE;
}
}
return TRUE;
}
else
{
return FALSE;
}
}
else
{
return FALSE;
}
}
/**************************************************************************\
*
* Function Description:
*
* Answer TRUE if brush and the receiver are equivalent (i.e. - they will
* render indentically).
*
* Arguments:
*
* [IN] brush - GpBrush, or subclass, to compare this against.
*
* Return Value:
*
* TRUE if equivalent
*
* Created - 6/7/99 peterost
*
\**************************************************************************/
BOOL
GpTriangleGradient::IsEqual(const GpBrush * brush) const
{
if(!brush)
return FALSE;
if (brush == this)
return TRUE;
if (GpGradientBrush::IsEqual(brush))
{
const GpTriangleGradient * tbrush = static_cast<const GpTriangleGradient *>(brush);
if (tbrush->DeviceBrush.BlendCounts[0] == DeviceBrush.BlendCounts[0] &&
tbrush->DeviceBrush.BlendCounts[1] == DeviceBrush.BlendCounts[1] &&
tbrush->DeviceBrush.BlendCounts[2] == DeviceBrush.BlendCounts[2] &&
tbrush->DeviceBrush.Rect.Equals(DeviceBrush.Rect))
{
INT i;
for (i=0; i<3; i++)
{
if (tbrush->DeviceBrush.Points[i].X != DeviceBrush.Points[i].X ||
tbrush->DeviceBrush.Points[i].Y != DeviceBrush.Points[i].Y ||
!(tbrush->DeviceBrush.Colors[i].IsEqual(DeviceBrush.Colors[i])))
return FALSE;
}
if (DeviceBrush.BlendCounts[0] > 1)
{
for (i=0; i<DeviceBrush.BlendCounts[0]; i++)
{
if (tbrush->DeviceBrush.BlendFactors[0][i] != DeviceBrush.BlendFactors[0][i] ||
tbrush->DeviceBrush.BlendPositions[0][i] != DeviceBrush.BlendPositions[0][i])
return FALSE;
}
}
else if (tbrush->DeviceBrush.Falloffs[0] != DeviceBrush.Falloffs[0])
{
return FALSE;
}
if (DeviceBrush.BlendCounts[1] > 1)
{
for (i=0; i<DeviceBrush.BlendCounts[1]; i++)
{
if (tbrush->DeviceBrush.BlendFactors[1][i] != DeviceBrush.BlendFactors[1][i] ||
tbrush->DeviceBrush.BlendPositions[1][i] != DeviceBrush.BlendPositions[1][i])
return FALSE;
}
}
else if (tbrush->DeviceBrush.Falloffs[1] != DeviceBrush.Falloffs[1])
{
return FALSE;
}
if (DeviceBrush.BlendCounts[2] > 1)
{
for (i=0; i<DeviceBrush.BlendCounts[2]; i++)
{
if (tbrush->DeviceBrush.BlendFactors[2][i] != DeviceBrush.BlendFactors[2][i] ||
tbrush->DeviceBrush.BlendPositions[2][i] != DeviceBrush.BlendPositions[2][i])
return FALSE;
}
}
else if (tbrush->DeviceBrush.Falloffs[2] != DeviceBrush.Falloffs[2])
{
return FALSE;
}
return TRUE;
}
else
{
return FALSE;
}
}
else
{
return FALSE;
}
}
#endif
/**************************************************************************\
*
* Function Description:
*
* Answer TRUE if brush and the receiver are equivalent (i.e. - they will
* render indentically).
*
* Arguments:
*
* [IN] brush - GpBrush, or subclass, to compare this against.
*
* Return Value:
*
* TRUE if equivalent
*
* Created - 6/7/99 peterost
*
\**************************************************************************/
BOOL
GpPathGradient::IsEqual(const GpBrush * brush) const
{
if(!brush)
return FALSE;
if (brush == this)
return TRUE;
if (GpGradientBrush::IsEqual(brush))
{
const GpPathGradient * pbrush = static_cast<const GpPathGradient *>(brush);
if (pbrush->DeviceBrush.BlendCounts[0] == DeviceBrush.BlendCounts[0] &&
pbrush->DeviceBrush.Count == DeviceBrush.Count &&
pbrush->DeviceBrush.OneSurroundColor == DeviceBrush.OneSurroundColor &&
pbrush->DeviceBrush.UsesPresetColors == DeviceBrush.UsesPresetColors &&
pbrush->DeviceBrush.Points[0].X == DeviceBrush.Points[0].X &&
pbrush->DeviceBrush.Points[0].Y == DeviceBrush.Points[0].Y &&
pbrush->DeviceBrush.Rect.Equals(DeviceBrush.Rect) &&
pbrush->DeviceBrush.Colors[0].IsEqual(DeviceBrush.Colors[0])
)
{
INT i;
for (i=0; i<DeviceBrush.Count; i++)
{
if (pbrush->DeviceBrush.PointsPtr[i].X != DeviceBrush.PointsPtr[i].X ||
pbrush->DeviceBrush.PointsPtr[i].Y != DeviceBrush.PointsPtr[i].Y ||
!(pbrush->DeviceBrush.ColorsPtr[i].IsEqual(DeviceBrush.ColorsPtr[i])))
return FALSE;
}
if (DeviceBrush.UsesPresetColors)
{
for (i=0; i<DeviceBrush.BlendCounts[0]; i++)
{
if (pbrush->DeviceBrush.PresetColors[i] != DeviceBrush.PresetColors[i] ||
pbrush->DeviceBrush.BlendPositions[0][i] != DeviceBrush.BlendPositions[0][i])
return FALSE;
}
}
else
{
if (DeviceBrush.BlendCounts[0] > 1)
{
for (i=0; i<DeviceBrush.BlendCounts[0]; i++)
{
if (pbrush->DeviceBrush.BlendFactors[0][i] != DeviceBrush.BlendFactors[0][i] ||
pbrush->DeviceBrush.BlendPositions[0][i] != DeviceBrush.BlendPositions[0][i])
return FALSE;
}
}
else if (pbrush->DeviceBrush.Falloffs[0] != DeviceBrush.Falloffs[0])
{
return FALSE;
}
}
}
return TRUE;
}
else
{
return FALSE;
}
}
DpOutputSpan*
GpSolidFill::CreateOutputSpan(
DpScanBuffer * scan,
DpContext *context,
const GpRect *drawBounds)
{
return new DpOutputSolidColorSpan(
DeviceBrush.SolidColor.GetPremultipliedValue(),
scan
);
}
DpOutputSpan*
GpRectGradient::CreateOutputSpan(
DpScanBuffer * scan,
DpContext *context,
const GpRect *drawBounds)
{
DpOutputSpan* span = NULL;
ARGB argb[4];
for(INT i = 0; i < 4; i++)
{
argb[i] = DeviceBrush.Colors[i].GetValue();
}
BOOL isHorizontal = FALSE;
BOOL isVertical = FALSE;
if(HasPresetColors() && DeviceBrush.BlendCounts[0] > 1)
isHorizontal = TRUE;
if(!isHorizontal && argb[0] == argb[2] && argb[1] == argb[3])
isHorizontal = TRUE;
if(!isHorizontal && argb[0] == argb[1] && argb[2] == argb[3])
isVertical = TRUE;
if(!isHorizontal && !isVertical)
{
span = new DpOutputGradientSpan(this, scan, context);
}
else
{
// !!![andrewgo] Not sure why a LinearGradient is coming down to us
// as BrushRectGrad - if it comes down as a BrushTypeLinearGradient
// (as it should) then we don't have to do any of the
// above 'isHorizontal', 'isVertical' stuff
FPUStateSaver fpuState; // Set the rounding mode.
if ((GetBrushType() == BrushTypeLinearGradient) /*|| (GetBrushType() == BrushRectGrad)*/)
{
if (OSInfo::HasMMX)
{
span = new DpOutputLinearGradientSpan_MMX(this, scan, context);
}
else
{
span = new DpOutputLinearGradientSpan(this, scan, context);
}
}
else
{
span = new DpOutputOneDGradientSpan(this, scan, context,
isHorizontal, isVertical);
}
}
if (span && !span->IsValid())
{
delete span;
span = NULL;
}
return span;
}
#if 0
DpOutputSpan*
GpRadialGradient::CreateOutputSpan(
DpScanBuffer * scan,
DpContext *context,
const GpRect *drawBounds)
{
return new DpOutputOneDGradientSpan(
this,
scan,
context
);
}
DpOutputSpan*
GpTriangleGradient::CreateOutputSpan(
DpScanBuffer * scan,
DpContext *context,
const GpRect *drawBounds)
{
return new DpOutputTriangleGradientSpan(
this,
scan,
context
);
}
#endif
DpOutputSpan*
GpPathGradient::CreateOutputSpan(
DpScanBuffer * scan,
DpContext *context,
const GpRect *drawBounds)
{
FPUStateSaver::AssertMode();
DpOutputSpan* span = NULL;
WrapMode wrap = DeviceBrush.Wrap;
// Check to see if a tiled gradient is really needed. It
// is not necessary if the transformed drawbounds fit
// entirely within the bounds of the brush rectangle.
if (drawBounds && wrap != WrapModeClamp)
{
GpMatrix inverseXForm = context->WorldToDevice;
if (Ok == inverseXForm.Invert())
{
GpRectF brushRect = DeviceBrush.Rect;
GpRectF transformRect;
TransformBounds(
&inverseXForm,
(REAL)drawBounds->GetLeft(),
(REAL)drawBounds->GetTop(),
(REAL)drawBounds->GetRight(),
(REAL)drawBounds->GetBottom(),
&transformRect
);
if (brushRect.Contains(transformRect))
{
wrap = WrapModeClamp;
}
}
}
if(wrap == WrapModeClamp)
{
if(!DeviceBrush.OneSurroundColor)
{
span = new DpOutputPathGradientSpan(
this,
scan,
context
);
}
else
{
span = new DpOutputOneDPathGradientSpan(
this,
scan,
context
);
}
}
else
{
INT width, height, ix, iy;
GpRectF brushRect = DeviceBrush.Rect;
// Create a texture brush to represent this path gradient brush.
// We do this by creating a texture as close to device resolution
// as we can and computing the transform (brush to world) for the
// texture brush decomposed into two transforms that take the
// brush via device space. The texture brush transform
// usually works out to be the inverse of the world to device, so
// the final texture brush draws with a resultant identity transform
// regardless of the world to device matrix. (exception when there is
// a rotation in the w2d).
GpPointF worldDestPoints[3];
worldDestPoints[0].X = brushRect.X ;
worldDestPoints[0].Y = brushRect.Y;
worldDestPoints[1].X = worldDestPoints[0].X + brushRect.Width;
worldDestPoints[1].Y = worldDestPoints[0].Y;
worldDestPoints[2].X = worldDestPoints[0].X;
worldDestPoints[2].Y = worldDestPoints[0].Y + brushRect.Height;
// Take into account transformation by both the brush xform and
// the world to device. This will handle transforms such as
// UnitInch and w2d scales.
// First get the destination points in world space by applying the
// brush transform.
DeviceBrush.Xform.Transform(worldDestPoints, 3);
GpPointF deviceDestPoints[3];
GpMemcpy(deviceDestPoints, worldDestPoints, sizeof(worldDestPoints));
// Now get the device space destination points by applying the
// world to device transform.
context->WorldToDevice.Transform(deviceDestPoints, 3);
// Compute the bounds in device space.
REAL xmin, xmax, ymin, ymax, nextX, nextY;
xmin = xmax = deviceDestPoints[1].X +
deviceDestPoints[2].X - deviceDestPoints[0].X;
ymin = ymax = deviceDestPoints[1].Y +
deviceDestPoints[2].Y - deviceDestPoints[0].Y;
for(INT i = 0; i < 3; i++)
{
nextX = deviceDestPoints[i].X;
nextY = deviceDestPoints[i].Y;
if(nextX < xmin)
xmin = nextX;
else if(nextX > xmax)
xmax = nextX;
if(nextY < ymin)
ymin = nextY;
else if(nextY > ymax)
ymax = nextY;
}
// Set the optimal bitmap bounds.
ix = GpRound(xmin);
iy = GpRound(ymin);
width = GpRound(xmax) - ix;
height = GpRound(ymax) - iy;
GpRectF bitmapBounds(0, 0, TOREAL(width), TOREAL(height));
// Decompose brushRect --> worldDestPoints transform into two matrix.
// mat1: brushRect --> bitmapBounds (device space)
// mat2: bitmapBounds --> worldDestPoints
GpMatrix mat1, mat2;
mat1.InferAffineMatrix(bitmapBounds, brushRect);
mat2.InferAffineMatrix(worldDestPoints, bitmapBounds);
if(width <= 0 || height <= 0)
return NULL;
// Create a bitmap which the gradient will be drawn onto.
// Make it the full width and height of the gradient, even
// though only a small portion may be used to simplify
// handling by downstream functions.
GpBitmap* bitmap = new GpBitmap(width, height, PixelFormat32bppARGB);
if(bitmap)
{
GpGraphics* g = bitmap->GetGraphicsContext();
if(g)
{
GpLock lock(g->GetObjectLock());
// Set the transform to brushRect --> bitmapBounds.
g->MultiplyWorldTransform(mat1);
WrapMode savedWrapMode = DeviceBrush.Wrap;
DeviceBrush.Wrap = WrapModeClamp;
GpMatrix savedMat = DeviceBrush.Xform;
DeviceBrush.Xform.Reset();
g->FillRect(this, brushRect.X, brushRect.Y,
brushRect.Width, brushRect.Height);
DeviceBrush.Wrap = savedWrapMode;
DeviceBrush.Xform = savedMat;
if(MorphedBrush)
delete MorphedBrush;
// Create a texuture with a unit tile and set the
// brush transform to bitmapBounds --> worldDestPoints.
GpTexture* texture = new GpTexture(bitmap, savedWrapMode);
// span must be NULL at this point. If it's not, we're going
// to leak memory when we create it below, or in the case of
// an error out, we may end up with uninitialized memory
// being returned to the caller.
ASSERT(span == NULL);
if(texture)
{
texture->MultiplyTransform(mat2);
span = texture->CreateOutputSpan(scan, context, drawBounds);
}
// Even if we failed to create the texture, we still want to
// set a reasonable (NULL) value for MorphedBrush so that we
// don't have a dangling pointer.
MorphedBrush = texture;
}
// We're done with this graphics.
// NOTE: this is explicitly done outside of the scope of the
// GpLock object, so that the GpLock (which modifies the graphics
// in its destructor) doesn't touch freed memory.
delete g;
bitmap->Dispose();
}
}
return span;
}
DpOutputSpan*
GpTexture::CreateOutputSpan(
DpScanBuffer *scan,
DpContext *context,
const GpRect *drawBounds)
{
DpOutputBilinearSpan *textureSpan = NULL;
GpMatrix brushTransform;
GpMatrix worldToDevice;
// Figure out the world-to-device transform:
worldToDevice = context->WorldToDevice;
this->GetTransform(&brushTransform);
worldToDevice.Prepend(brushTransform);
// Go through our heirarchy of scan drawers:
if (worldToDevice.IsIntegerTranslate() &&
((this->GetWrapMode() == WrapModeTile) ||
(this->GetWrapMode() == WrapModeClamp)))
{
textureSpan = new DpOutputBilinearSpan_Identity(this,
scan,
&worldToDevice,
context);
}
else if (OSInfo::HasMMX &&
GpValidFixed16(DeviceBrush.Rect.Width) &&
GpValidFixed16(DeviceBrush.Rect.Height))
{
textureSpan = new DpOutputBilinearSpan_MMX(this,
scan,
&worldToDevice,
context);
}
// Scan drawer creation may fail, so clean up and try one last time
if ((textureSpan) && !textureSpan->IsValid())
{
delete textureSpan;
textureSpan = NULL;
}
if (!textureSpan)
{
textureSpan = new DpOutputBilinearSpan(this,
scan,
&worldToDevice,
context);
}
if ((textureSpan) && !textureSpan->IsValid())
{
delete textureSpan;
textureSpan = NULL;
}
return textureSpan;
}
DpOutputSpan*
GpHatch::CreateOutputSpan(
DpScanBuffer * scan,
DpContext *context,
const GpRect *drawBounds)
{
if (StretchFactor == 1)
{
return new DpOutputHatchSpan(
this,
scan,
context
);
}
else
{
return new DpOutputStretchedHatchSpan(
this,
scan,
context,
StretchFactor
);
}
}
class SolidBrushData : public ObjectTypeData
{
public:
ARGB SolidColor;
};
/**************************************************************************\
*
* Function Description:
*
* Get the brush data.
*
* Arguments:
*
* [IN] dataBuffer - fill this buffer with the data
* [IN/OUT] size - IN - size of buffer; OUT - number bytes written
*
* Return Value:
*
* GpStatus - Ok or error code
*
* Created:
*
* 9/13/1999 DCurtis
*
\**************************************************************************/
GpStatus
GpSolidFill::GetData(
IStream * stream
) const
{
ASSERT (stream != NULL);
SolidBrushData brushData;
brushData.Type = DeviceBrush.Type;
brushData.SolidColor = DeviceBrush.SolidColor.GetValue();
stream->Write(&brushData, sizeof(brushData), NULL);
return Ok;
}
UINT
GpSolidFill::GetDataSize() const
{
return sizeof(SolidBrushData);
}
/**************************************************************************\
*
* Function Description:
*
* Read the brush object from memory.
*
* Arguments:
*
* [IN] dataBuffer - the data that was read from the stream
* [IN] size - the size of the data
*
* Return Value:
*
* GpStatus - Ok or failure status
*
* Created:
*
* 4/26/1999 DCurtis
*
\**************************************************************************/
GpStatus
GpSolidFill::SetData(
const BYTE * dataBuffer,
UINT size
)
{
ASSERT ((GpBrushType)(((SolidBrushData *)dataBuffer)->Type) == BrushTypeSolidColor);
if (dataBuffer == NULL)
{
WARNING(("dataBuffer is NULL"));
return InvalidParameter;
}
if (size < sizeof(SolidBrushData))
{
WARNING(("size too small"));
return InvalidParameter;
}
if (!((SolidBrushData *)dataBuffer)->MajorVersionMatches())
{
WARNING(("Version number mismatch"));
return InvalidParameter;
}
SetColor(GpColor(((SolidBrushData *)dataBuffer)->SolidColor));
return Ok;
}
GpStatus
GpSolidFill::ColorAdjust(
GpRecolor * recolor,
ColorAdjustType type
)
{
if(!recolor)
return InvalidParameter;
if (type == ColorAdjustTypeDefault)
{
type = ColorAdjustTypeBrush;
}
ARGB solidColor32 = Color.GetValue();
recolor->ColorAdjust(&solidColor32, 1, type);
this->SetColor(GpColor(solidColor32));
return Ok;
}
class TextureBrushData : public ObjectTypeData
{
public:
INT32 Flags;
INT32 Wrap;
};
/**************************************************************************\
*
* Function Description:
*
* Get the brush data.
*
* Arguments:
*
* [IN] dataBuffer - fill this buffer with the data
* [IN/OUT] size - IN - size of buffer; OUT - number bytes written
*
* Return Value:
*
* GpStatus - Ok or error code
*
* Created:
*
* 9/13/1999 DCurtis
*
\**************************************************************************/
GpStatus
GpTexture::GetData(
IStream * stream
) const
{
ASSERT (stream != NULL);
if (Image == NULL)
{
WARNING(("Image is NULL"));
return Ok;
}
INT flags = 0;
if (DeviceBrush.IsGammaCorrected)
{
flags |= GDIP_BRUSHFLAGS_ISGAMMACORRECTED;
}
if (!DeviceBrush.Xform.IsIdentity())
{
flags |= GDIP_BRUSHFLAGS_TRANSFORM;
}
TextureBrushData brushData;
brushData.Type = DeviceBrush.Type;
brushData.Flags = flags;
brushData.Wrap = DeviceBrush.Wrap;
stream->Write(&brushData, sizeof(brushData), NULL);
if (flags & GDIP_BRUSHFLAGS_TRANSFORM)
{
DeviceBrush.Xform.WriteMatrix(stream);
}
return Image->GetData(stream);
}
UINT
GpTexture::GetDataSize() const
{
if (Image == NULL)
{
WARNING(("Image is NULL"));
return 0;
}
UINT size = sizeof(TextureBrushData);
if (!DeviceBrush.Xform.IsIdentity())
{
size += GDIP_MATRIX_SIZE;
}
size += Image->GetDataSize();
return size;
}
/**************************************************************************\
*
* Function Description:
*
* Read the brush object from memory.
*
* Arguments:
*
* [IN] dataBuffer - the data that was read from the stream
* [IN] size - the size of the data
*
* Return Value:
*
* GpStatus - Ok or failure status
*
* Created:
*
* 4/26/1999 DCurtis
*
\**************************************************************************/
GpStatus
GpTexture::SetData(
const BYTE * dataBuffer,
UINT size
)
{
ASSERT ((GpBrushType)(((TextureBrushData *)dataBuffer)->Type) == BrushTypeTextureFill);
if (dataBuffer == NULL)
{
WARNING(("dataBuffer is NULL"));
return InvalidParameter;
}
if (size < sizeof(TextureBrushData))
{
WARNING(("size too small"));
return InvalidParameter;
}
const TextureBrushData * brushData;
brushData = reinterpret_cast<const TextureBrushData *>(dataBuffer);
if (!brushData->MajorVersionMatches())
{
WARNING(("Version number mismatch"));
return InvalidParameter;
}
DeviceBrush.Type = BrushTypeTextureFill;
DeviceBrush.Wrap = (GpWrapMode) brushData->Wrap;
DeviceBrush.IsGammaCorrected = ((brushData->Flags & GDIP_BRUSHFLAGS_ISGAMMACORRECTED) != 0);
dataBuffer += sizeof(TextureBrushData);
size -= sizeof(TextureBrushData);
if (brushData->Flags & GDIP_BRUSHFLAGS_TRANSFORM)
{
if (size < GDIP_MATRIX_SIZE)
{
WARNING(("size too small"));
return InvalidParameter;
}
DeviceBrush.Xform.SetMatrix((REAL *)dataBuffer);
dataBuffer += GDIP_MATRIX_SIZE;
size -= GDIP_MATRIX_SIZE;
}
if (Image != NULL)
{
Image->Dispose();
Image = NULL;
}
if (size >= sizeof(ObjectTypeData))
{
Image = (GpImage *)GpObject::Factory(ObjectTypeImage, (const ObjectData *)dataBuffer, size);
if (Image != NULL)
{
if ((Image->SetData(dataBuffer, size) == Ok) && Image->IsValid() &&
((ImageType = Image->GetImageType()) == ImageTypeBitmap))
{
GpPageUnit unit;
Image->GetBounds(&DeviceBrush.Rect, &unit);
SetValid(TRUE);
UpdateUid();
return Ok;
}
Image->Dispose();
Image = NULL;
}
}
WARNING(("Failure getting image"));
GpMemset(&DeviceBrush.Rect, 0, sizeof(DeviceBrush.Rect));
SetValid(FALSE);
return GenericError;
}
GpStatus
GpTexture::ColorAdjust(
GpRecolor * recolor,
ColorAdjustType type
)
{
if (type == ColorAdjustTypeDefault)
{
type = ColorAdjustTypeBrush;
}
if (Image != NULL)
{
Image->ColorAdjust(recolor, type);
UpdateUid();
}
return Ok;
}
VOID GpTexture::InitializeBrush(
GpImage* image,
GpWrapMode wrapMode,
const GpRectF* rect,
const GpImageAttributes *imageAttributes)
{
ASSERT(image && image->IsValid());
if (!WrapModeIsValid(wrapMode))
{
WARNING(("bad wrap mode"));
goto Failure;
}
GpImageType imageType;
imageType = image->GetImageType();
if (imageType == ImageTypeBitmap)
{
InitializeBrushBitmap(
static_cast<GpBitmap*>(image),
wrapMode, rect, imageAttributes
);
}
else if (imageType == ImageTypeMetafile)
{
// For now, convert the metafile into a bitmap image and use that to
// create the brush.
GpBitmap * bitmapImage;
if (rect != NULL)
{
// !!! we don't handle this case yet
if ((rect->X != 0) || (rect->Y != 0))
{
WARNING(("No handling for non-zero start in metafiles"));
}
// Don't apply the imageAttributes now, because WMF/EMF rendering
// doesn't support alpha. So wait until it's been converted to
// a bitmap to apply the imageAttributes.
bitmapImage = ((GpMetafile *)image)->GetBitmap(
GpRound(rect->Width),
GpRound(rect->Height), NULL);
}
else
{
// Let the metafile decide how big the bitmap should be
// Don't apply the imageAttributes now, because WMF/EMF rendering
// doesn't support alpha. So wait until it's been converted to
// a bitmap to apply the imageAttributes.
bitmapImage = ((GpMetafile *)image)->GetBitmap(0, 0, NULL);
}
if (bitmapImage != NULL)
{
ASSERT (bitmapImage->IsValid());
InitializeBrushBitmap(bitmapImage, wrapMode, NULL, imageAttributes, TRUE);
return;
}
goto Failure;
}
else // unknown image type
{
WARNING(("unknown image type"));
Failure:
Image = NULL;
SetValid(FALSE);
}
}
VOID GpTexture::InitializeBrushBitmap(
GpBitmap* bitmap,
GpWrapMode wrapMode,
const GpRectF* rect,
const GpImageAttributes *imageAttributes,
BOOL useBitmap)
{
DeviceBrush.Type = BrushTypeTextureFill;
DeviceBrush.Wrap = wrapMode;
ImageType = ImageTypeBitmap;
Image = NULL;
FPUStateSaver fpState; // Setup the fpu state.
if (bitmap && bitmap->IsValid())
{
GpRect *pRectI = NULL;
GpRect recti;
if(rect)
{
recti.X = GpRound(rect->X);
recti.Y = GpRound(rect->Y);
recti.Width = GpRound(rect->Width);
recti.Height = GpRound(rect->Height);
pRectI = &recti;
}
if(imageAttributes)
{
GpBitmap *dst = NULL;
if (bitmap->Recolor(
imageAttributes->recolor, &dst,
NULL, NULL, pRectI
) == Ok)
{
Image = dst;
// If useBitmap is TRUE that means the caller has transferred
// ownership of bitmap to us. In this case, Recolor makes
// a clone of the bitmap that we're going to use, so we have
// to free the bitmap passed in and use the clone instead,
// otherwise we leak.
if(useBitmap)
{
bitmap->Dispose();
}
}
}
// !!! note that this should be non-premultiplied ARGB.
// we'll fix this when we drop premultiplied data [asecchia]
// also note that the output of RecolorImage is 32BPP_ARGB
// if it's not NULL it's because the RecolorImage code cloned it already
if (Image == NULL)
{
if (useBitmap)
{
// This is for the case where we constructed a bitmap
// from a metafile image.
Image = bitmap;
}
else
{
#ifdef NO_PREMULTIPLIED_ALPHA
Image = bitmap->Clone(pRectI, PIXFMT_32BPP_ARGB);
#else
Image = bitmap->Clone(pRectI, PIXFMT_32BPP_PARGB);
#endif
}
}
}
if (Image && Image->IsValid())
{
SetValid(TRUE);
// Rect is given as a pixel unit in bitmap.
GpPageUnit unit;
Image->GetBounds(&DeviceBrush.Rect, &unit);
}
else
{
SetValid(FALSE);
GpMemset(&DeviceBrush.Rect,
0,
sizeof(DeviceBrush.Rect));
}
}
// See if this texture fill is really a picture fill (with a bitmap,
// not a metafile).
BOOL
GpTexture::IsPictureFill(
const GpMatrix * worldToDevice,
const GpRect * drawBounds
) const
{
ASSERT ((drawBounds->Width > 0) && (drawBounds->Height > 0));
BOOL isPictureFill = FALSE;
GpMatrix newBrushMatrix;
this->GetTransform(&newBrushMatrix);
if (worldToDevice != NULL)
{
newBrushMatrix.Append(*worldToDevice);
}
newBrushMatrix.Translate(
(REAL)-(drawBounds->X),
(REAL)-(drawBounds->Y),
MatrixOrderAppend
);
// See if the texture is supposed to fill the drawBounds.
// If so, this is a picture fill.
if (newBrushMatrix.IsTranslateScale())
{
Size size;
// If the texture is not a bitmap, this returns InvalidParameter.
if (this->GetBitmapSize(&size) == Ok)
{
GpRectF transformedRect(0.0f, 0.0f, (REAL)size.Width, (REAL)size.Height);
newBrushMatrix.TransformRect(transformedRect);
// get the transformed width
INT deltaValue = abs(GpRound(transformedRect.Width) - drawBounds->Width);
// We might be off a little because of the pixel offset mode
// or a matrix that isn't quite right for whatever reason.
if (deltaValue <= 2)
{
// get the transformed height
deltaValue = abs(GpRound(transformedRect.Height) - drawBounds->Height);
if (deltaValue <= 2)
{
if ((abs(GpRound(transformedRect.X)) <= 2) &&
(abs(GpRound(transformedRect.Y)) <= 2))
{
isPictureFill = TRUE;
}
}
}
}
}
return isPictureFill;
}
class RectGradientBrushData : public ObjectTypeData
{
public:
INT32 Flags;
INT32 Wrap;
GpRectF Rect;
UINT32 Color0;
UINT32 Color1;
UINT32 Color2;
UINT32 Color3;
};
/**************************************************************************\
*
* Function Description:
*
* Get the brush data.
*
* Arguments:
*
* [IN] dataBuffer - fill this buffer with the data
* [IN/OUT] size - IN - size of buffer; OUT - number bytes written
*
* Return Value:
*
* GpStatus - Ok or error code
*
* Created:
*
* 9/13/1999 DCurtis
*
\**************************************************************************/
GpStatus
GpRectGradient::GetData(
IStream * stream
) const
{
ASSERT (stream != NULL);
INT flags = 0;
if (DeviceBrush.IsGammaCorrected)
{
flags |= GDIP_BRUSHFLAGS_ISGAMMACORRECTED;
}
if (!DeviceBrush.Xform.IsIdentity())
{
flags |= GDIP_BRUSHFLAGS_TRANSFORM;
}
// Note: can't have both blendFactors and presetColors at the same time
// PresetColors used for GpLineGradient, but not for GpRectGradient.
if (DeviceBrush.UsesPresetColors && (DeviceBrush.BlendCounts[0] > 1) && (DeviceBrush.PresetColors != NULL) &&
(DeviceBrush.BlendPositions[0] != NULL) && (DeviceBrush.BlendFactors[0] == NULL))
{
flags |= GDIP_BRUSHFLAGS_PRESETCOLORS;
}
if ((DeviceBrush.BlendCounts[0] > 1) && (DeviceBrush.BlendFactors[0] != NULL) && (DeviceBrush.BlendPositions[0] != NULL))
{
flags |= GDIP_BRUSHFLAGS_BLENDFACTORSH;
}
if ((DeviceBrush.BlendCounts[1] > 1) && (DeviceBrush.BlendFactors[1] != NULL) && (DeviceBrush.BlendPositions[1] != NULL))
{
flags |= GDIP_BRUSHFLAGS_BLENDFACTORSV;
}
RectGradientBrushData brushData;
brushData.Type = DeviceBrush.Type;
brushData.Flags = flags;
brushData.Wrap = DeviceBrush.Wrap;
brushData.Rect = DeviceBrush.Rect;
brushData.Color0 = DeviceBrush.Colors[0].GetValue();
brushData.Color1 = DeviceBrush.Colors[1].GetValue();
brushData.Color2 = DeviceBrush.Colors[2].GetValue();
brushData.Color3 = DeviceBrush.Colors[3].GetValue();
stream->Write(&brushData, sizeof(brushData), NULL);
if (flags & GDIP_BRUSHFLAGS_TRANSFORM)
{
DeviceBrush.Xform.WriteMatrix(stream);
}
if (flags & GDIP_BRUSHFLAGS_PRESETCOLORS)
{
INT realSize = DeviceBrush.BlendCounts[0] * sizeof(REAL);
INT argbSize = DeviceBrush.BlendCounts[0] * sizeof(ARGB);
stream->Write(&DeviceBrush.BlendCounts[0], sizeof(INT32), NULL);
stream->Write(DeviceBrush.BlendPositions[0], realSize, NULL);
stream->Write(DeviceBrush.PresetColors, argbSize, NULL);
}
if (flags & GDIP_BRUSHFLAGS_BLENDFACTORSH)
{
INT realSize = DeviceBrush.BlendCounts[0] * sizeof(REAL);
stream->Write(&DeviceBrush.BlendCounts[0], sizeof(INT32), NULL);
stream->Write(DeviceBrush.BlendPositions[0], realSize, NULL);
stream->Write(DeviceBrush.BlendFactors[0], realSize, NULL);
}
if (flags & GDIP_BRUSHFLAGS_BLENDFACTORSV)
{
INT realSize = DeviceBrush.BlendCounts[1] * sizeof(REAL);
stream->Write(&DeviceBrush.BlendCounts[1], sizeof(INT32), NULL);
stream->Write(DeviceBrush.BlendPositions[1], realSize, NULL);
stream->Write(DeviceBrush.BlendFactors[1], realSize, NULL);
}
return Ok;
}
UINT
GpRectGradient::GetDataSize() const
{
UINT size = sizeof(RectGradientBrushData);
if (!DeviceBrush.Xform.IsIdentity())
{
size += GDIP_MATRIX_SIZE;
}
// Note: can't have both blendFactors and presetColors at the same time
// PresetColors used for GpLineGradient, but not for GpRectGradient.
if (DeviceBrush.UsesPresetColors && (DeviceBrush.BlendCounts[0] > 1) && (DeviceBrush.PresetColors != NULL) &&
(DeviceBrush.BlendPositions[0] != NULL) && (DeviceBrush.BlendFactors[0] == NULL))
{
size += sizeof(INT32) + ((sizeof(ARGB) + sizeof(REAL)) * DeviceBrush.BlendCounts[0]);
}
if ((DeviceBrush.BlendCounts[0] > 1) && (DeviceBrush.BlendFactors[0] != NULL) && (DeviceBrush.BlendPositions[0] != NULL))
{
size += sizeof(INT32) + ((sizeof(REAL) + sizeof(REAL)) * DeviceBrush.BlendCounts[0]);
}
if ((DeviceBrush.BlendCounts[1] > 1) && (DeviceBrush.BlendFactors[1] != NULL) && (DeviceBrush.BlendPositions[1] != NULL))
{
size += sizeof(INT32) + ((sizeof(REAL) + sizeof(REAL)) * DeviceBrush.BlendCounts[1]);
}
return size;
}
/**************************************************************************\
*
* Function Description:
*
* Read the brush object from memory.
*
* Arguments:
*
* [IN] dataBuffer - the data that was read from the stream
* [IN] size - the size of the data
*
* Return Value:
*
* GpStatus - Ok or failure status
*
* Created:
*
* 4/26/1999 DCurtis
*
\**************************************************************************/
GpStatus
GpRectGradient::SetData(
const BYTE * dataBuffer,
UINT size
)
{
ASSERT ((GpBrushType)(((RectGradientBrushData *)dataBuffer)->Type) == BrushTypeLinearGradient);
if (dataBuffer == NULL)
{
WARNING(("dataBuffer is NULL"));
return InvalidParameter;
}
if (size < sizeof(RectGradientBrushData))
{
WARNING(("size too small"));
return InvalidParameter;
}
const RectGradientBrushData * brushData;
GpColor colors[4];
brushData = reinterpret_cast<const RectGradientBrushData *>(dataBuffer);
if (!brushData->MajorVersionMatches())
{
WARNING(("Version number mismatch"));
return InvalidParameter;
}
colors[0].SetValue(brushData->Color0);
colors[1].SetValue(brushData->Color1);
colors[2].SetValue(brushData->Color2);
colors[3].SetValue(brushData->Color3);
InitializeBrush(brushData->Rect, colors, (GpWrapMode) brushData->Wrap);
DeviceBrush.IsGammaCorrected = ((brushData->Flags & GDIP_BRUSHFLAGS_ISGAMMACORRECTED) != 0);
dataBuffer += sizeof(RectGradientBrushData);
size -= sizeof(RectGradientBrushData);
if (brushData->Flags & GDIP_BRUSHFLAGS_TRANSFORM)
{
if (size < GDIP_MATRIX_SIZE)
{
WARNING(("size too small"));
return InvalidParameter;
}
DeviceBrush.Xform.SetMatrix((REAL *)dataBuffer);
dataBuffer += GDIP_MATRIX_SIZE;
size -= GDIP_MATRIX_SIZE;
}
if (brushData->Flags & GDIP_BRUSHFLAGS_PRESETCOLORS)
{
if (size < sizeof(INT32))
{
WARNING(("size too small"));
return InvalidParameter;
}
UINT count = ((INT32 *)dataBuffer)[0];
dataBuffer += sizeof(INT32);
size -= sizeof(INT32);
UINT realSize = count * sizeof(REAL);
UINT argbSize = count * sizeof(ARGB);
if (size < (realSize + argbSize))
{
WARNING(("size too small"));
return InvalidParameter;
}
ARGB* newColors = (ARGB*) GpRealloc(DeviceBrush.PresetColors, argbSize);
if (newColors != NULL)
{
// We have to just copy in the ARGB values, because they've already
// been premultiplied.
// Actually PresetColors is NON-premultiplied, but this code should
// still be right because we write them out non-premultiplied too.
GpMemcpy(newColors, dataBuffer + realSize, argbSize);
DeviceBrush.PresetColors = newColors;
REAL* newPositions = (REAL*) GpRealloc(DeviceBrush.BlendPositions[0], realSize);
if (newPositions != NULL)
{
GpMemcpy(newPositions, dataBuffer, realSize);
DeviceBrush.BlendPositions[0] = newPositions;
GpFree(DeviceBrush.BlendFactors[0]);
DeviceBrush.BlendFactors[0] = NULL;
DeviceBrush.UsesPresetColors = TRUE;
DeviceBrush.BlendCounts[0] = count;
}
}
dataBuffer += (realSize + argbSize);
size -= (realSize + argbSize);
}
if (brushData->Flags & GDIP_BRUSHFLAGS_BLENDFACTORSH)
{
if (size < sizeof(INT32))
{
WARNING(("size too small"));
return InvalidParameter;
}
UINT count = ((INT32 *)dataBuffer)[0];
dataBuffer += sizeof(INT32);
size -= sizeof(INT32);
UINT realSize = count * sizeof(REAL);
if (size < (2 * realSize))
{
WARNING(("size too small"));
return InvalidParameter;
}
this->SetHorizontalBlend((REAL *)(dataBuffer + realSize),(REAL *)dataBuffer, count);
dataBuffer += (2 * realSize);
size -= (2 * realSize);
}
if (brushData->Flags & GDIP_BRUSHFLAGS_BLENDFACTORSV)
{
if (size < sizeof(INT32))
{
WARNING(("size too small"));
return InvalidParameter;
}
UINT count = ((INT32 *)dataBuffer)[0];
dataBuffer += sizeof(INT32);
size -= sizeof(INT32);
UINT realSize = count * sizeof(REAL);
if (size < (2 * realSize))
{
WARNING(("size too small"));
return InvalidParameter;
}
this->SetVerticalBlend((REAL *)(dataBuffer + realSize), (REAL *)dataBuffer, count);
dataBuffer += (2 * realSize);
size -= (2 * realSize);
}
UpdateUid();
return Ok;
}
GpStatus
GpRectGradient::ColorAdjust(
GpRecolor * recolor,
ColorAdjustType type
)
{
if(!recolor)
return InvalidParameter;
if (type == ColorAdjustTypeDefault)
{
type = ColorAdjustTypeBrush;
}
ARGB solidColor32[4];
solidColor32[0] = DeviceBrush.Colors[0].GetValue();
solidColor32[1] = DeviceBrush.Colors[1].GetValue();
solidColor32[2] = DeviceBrush.Colors[2].GetValue();
solidColor32[3] = DeviceBrush.Colors[3].GetValue();
recolor->ColorAdjust(solidColor32, 4, type);
DeviceBrush.Colors[0].SetValue(solidColor32[0]);
DeviceBrush.Colors[1].SetValue(solidColor32[1]);
DeviceBrush.Colors[2].SetValue(solidColor32[2]);
DeviceBrush.Colors[3].SetValue(solidColor32[3]);
if (DeviceBrush.UsesPresetColors && (DeviceBrush.BlendCounts[0] > 1) && (DeviceBrush.PresetColors != NULL))
{
recolor->ColorAdjust(DeviceBrush.PresetColors, DeviceBrush.BlendCounts[0], type);
}
UpdateUid();
return Ok;
}
#if 0
class RadialGradientBrushData : public ObjectTypeData
{
public:
INT32 Flags;
INT32 Wrap;
GpRectF Rect;
UINT32 CenterColor;
UINT32 BoundaryColor;
};
/**************************************************************************\
*
* Function Description:
*
* Get the brush data.
*
* Arguments:
*
* [IN] dataBuffer - fill this buffer with the data
* [IN/OUT] size - IN - size of buffer; OUT - number bytes written
*
* Return Value:
*
* GpStatus - Ok or error code
*
* Created:
*
* 9/13/1999 DCurtis
*
\**************************************************************************/
GpStatus
GpRadialGradient::GetData(
IStream * stream
) const
{
ASSERT (stream != NULL);
INT flags = 0;
if (DeviceBrush.IsGammaCorrected)
{
flags |= GDIP_BRUSHFLAGS_ISGAMMACORRECTED;
}
if (!DeviceBrush.Xform.IsIdentity())
{
flags |= GDIP_BRUSHFLAGS_TRANSFORM;
}
// Note: can't have both blendFactors and presetColors at the same time
if (DeviceBrush.UsesPresetColors && (DeviceBrush.BlendCounts[0] > 1) && (DeviceBrush.PresetColors != NULL) &&
(DeviceBrush.BlendPositions[0] != NULL) && (DeviceBrush.BlendFactors[0] == NULL))
{
flags |= GDIP_BRUSHFLAGS_PRESETCOLORS;
}
if ((DeviceBrush.BlendCounts[0] > 1) && (DeviceBrush.BlendFactors[0] != NULL) && (DeviceBrush.BlendPositions[0] != NULL))
{
flags |= GDIP_BRUSHFLAGS_BLENDFACTORS;
}
RadialGradientBrushData brushData;
brushData.Type = DeviceBrush.Type;
brushData.Flags = flags;
brushData.Wrap = DeviceBrush.Wrap;
brushData.Rect = DeviceBrush.Rect;
brushData.CenterColor = DeviceBrush.Colors[0].GetValue();
brushData.BoundaryColor = DeviceBrush.Colors[1].GetValue();
stream->Write(&brushData, sizeof(brushData), NULL);
if (flags & GDIP_BRUSHFLAGS_TRANSFORM)
{
DeviceBrush.Xform.WriteMatrix(stream);
}
if (flags & GDIP_BRUSHFLAGS_PRESETCOLORS)
{
INT realSize = DeviceBrush.BlendCounts[0] * sizeof(REAL);
INT argbSize = DeviceBrush.BlendCounts[0] * sizeof(ARGB);
stream->Write(&DeviceBrush.BlendCounts[0], sizeof(INT32), NULL);
stream->Write(DeviceBrush.BlendPositions[0], realSize, NULL);
stream->Write(DeviceBrush.PresetColors, argbSize, NULL);
}
if (flags & GDIP_BRUSHFLAGS_BLENDFACTORS)
{
INT realSize = DeviceBrush.BlendCounts[0] * sizeof(REAL);
stream->Write(&DeviceBrush.BlendCounts[0], sizeof(INT32), NULL);
stream->Write(DeviceBrush.BlendPositions[0], realSize, NULL);
stream->Write(DeviceBrush.BlendFactors[0], realSize, NULL);
}
return Ok;
}
UINT
GpRadialGradient::GetDataSize() const
{
UINT size = sizeof(RadialGradientBrushData);
if (!DeviceBrush.Xform.IsIdentity())
{
size += GDIP_MATRIX_SIZE;
}
// Note: can't have both blendFactors and presetColors at the same time
if (DeviceBrush.UsesPresetColors && (DeviceBrush.BlendCounts[0] > 1) && (DeviceBrush.PresetColors != NULL) &&
(DeviceBrush.BlendPositions[0] != NULL) && (DeviceBrush.BlendFactors[0] == NULL))
{
size += sizeof(INT32) + ((sizeof(ARGB) + sizeof(REAL)) * DeviceBrush.BlendCounts[0]);
}
if ((DeviceBrush.BlendCounts[0] > 1) && (DeviceBrush.BlendFactors[0] != NULL) && (DeviceBrush.BlendPositions[0] != NULL))
{
size += sizeof(INT32) + ((sizeof(REAL) + sizeof(REAL)) * DeviceBrush.BlendCounts[0]);
}
return size;
}
/**************************************************************************\
*
* Function Description:
*
* Read the brush object from memory.
*
* Arguments:
*
* [IN] dataBuffer - the data that was read from the stream
* [IN] size - the size of the data
*
* Return Value:
*
* GpStatus - Ok or failure status
*
* Created:
*
* 4/26/1999 DCurtis
*
\**************************************************************************/
GpStatus
GpRadialGradient::SetData(
const BYTE * dataBuffer,
UINT size
)
{
// ASSERT ((GpBrushType)(((RadialGradientBrushData *)dataBuffer)->Type) == BrushTypeRadialGradient);
if (dataBuffer == NULL)
{
WARNING(("dataBuffer is NULL"));
return InvalidParameter;
}
if (size < sizeof(RadialGradientBrushData))
{
WARNING(("size too small"));
return InvalidParameter;
}
const RadialGradientBrushData * brushData;
GpColor centerColor;
GpColor boundaryColor;
brushData = reinterpret_cast<const RadialGradientBrushData *>(dataBuffer);
if (!brushData->MajorVersionMatches())
{
WARNING(("Version number mismatch"));
return InvalidParameter;
}
centerColor.SetValue(brushData->CenterColor);
boundaryColor.SetValue(brushData->BoundaryColor);
InitializeBrush(
brushData->Rect,
centerColor,
boundaryColor,
(GpWrapMode) brushData->Wrap
);
DeviceBrush.IsGammaCorrected = ((brushData->Flags & GDIP_BRUSHFLAGS_ISGAMMACORRECTED) != 0);
dataBuffer += sizeof(RadialGradientBrushData);
size -= sizeof(RadialGradientBrushData);
if (brushData->Flags & GDIP_BRUSHFLAGS_TRANSFORM)
{
if (size < GDIP_MATRIX_SIZE)
{
WARNING(("size too small"));
return InvalidParameter;
}
DeviceBrush.Xform.SetMatrix((REAL *)dataBuffer);
dataBuffer += GDIP_MATRIX_SIZE;
size -= GDIP_MATRIX_SIZE;
}
if (brushData->Flags & GDIP_BRUSHFLAGS_PRESETCOLORS)
{
if (size < sizeof(INT32))
{
WARNING(("size too small"));
return InvalidParameter;
}
UINT count = ((INT32 *)dataBuffer)[0];
dataBuffer += sizeof(INT32);
size -= sizeof(INT32);
UINT realSize = count * sizeof(REAL);
UINT argbSize = count * sizeof(ARGB);
if (size < (realSize + argbSize))
{
WARNING(("size too small"));
return InvalidParameter;
}
ARGB* newColors = (ARGB*) GpRealloc(DeviceBrush.PresetColors, argbSize);
if (newColors != NULL)
{
// We have to just copy in the ARGB values, because they've already
// been premultiplied.
GpMemcpy(newColors, dataBuffer + realSize, argbSize);
DeviceBrush.PresetColors = newColors;
REAL* newPositions = (REAL*) GpRealloc(DeviceBrush.BlendPositions[0], realSize);
if (newPositions != NULL)
{
GpMemcpy(newPositions, dataBuffer, realSize);
DeviceBrush.BlendPositions[0] = newPositions;
GpFree(DeviceBrush.BlendFactors[0]);
DeviceBrush.BlendFactors[0] = NULL;
DeviceBrush.UsesPresetColors = TRUE;
DeviceBrush.BlendCounts[0] = count;
}
}
dataBuffer += (realSize + argbSize);
size -= (realSize + argbSize);
}
if (brushData->Flags & GDIP_BRUSHFLAGS_BLENDFACTORS)
{
if (size < sizeof(INT32))
{
WARNING(("size too small"));
return InvalidParameter;
}
UINT count = ((INT32 *)dataBuffer)[0];
dataBuffer += sizeof(INT32);
size -= sizeof(INT32);
UINT realSize = count * sizeof(REAL);
if (size < (2 * realSize))
{
WARNING(("size too small"));
return InvalidParameter;
}
this->SetBlend((REAL *)(dataBuffer + realSize), (REAL *)dataBuffer, count);
dataBuffer += (2 * realSize);
size -= (2 * realSize);
}
UpdateUid();
return Ok;
}
GpStatus
GpRadialGradient::ColorAdjust(
GpRecolor * recolor,
ColorAdjustType type
)
{
if(!recolor)
return InvalidParameter;
if (type == ColorAdjustTypeDefault)
{
type = ColorAdjustTypeBrush;
}
ARGB solidColor32[2];
solidColor32[0] = DeviceBrush.Colors[0].GetValue();
solidColor32[1] = DeviceBrush.Colors[1].GetValue();
recolor->ColorAdjust(solidColor32, 2, type);
DeviceBrush.Colors[0].SetValue(solidColor32[0]);
DeviceBrush.Colors[1].SetValue(solidColor32[1]);
if (DeviceBrush.UsesPresetColors && (DeviceBrush.BlendCounts[0] > 1) && (DeviceBrush.PresetColors != NULL))
{
recolor->ColorAdjust(DeviceBrush.PresetColors, DeviceBrush.BlendCounts[0], type);
}
UpdateUid();
return Ok;
}
class TriangleGradientBrushData : public ObjectTypeData
{
public:
INT32 Flags;
INT32 Wrap;
GpPointF Points[3];
UINT32 Color0;
UINT32 Color1;
UINT32 Color2;
};
/**************************************************************************\
*
* Function Description:
*
* Get the brush data.
*
* Arguments:
*
* [IN] dataBuffer - fill this buffer with the data
* [IN/OUT] size - IN - size of buffer; OUT - number bytes written
*
* Return Value:
*
* GpStatus - Ok or error code
*
* Created:
*
* 9/13/1999 DCurtis
*
\**************************************************************************/
GpStatus
GpTriangleGradient::GetData(
IStream * stream
) const
{
ASSERT (stream != NULL);
INT flags = 0;
if (DeviceBrush.IsGammaCorrected)
{
flags |= GDIP_BRUSHFLAGS_ISGAMMACORRECTED;
}
if (!DeviceBrush.Xform.IsIdentity())
{
flags |= GDIP_BRUSHFLAGS_TRANSFORM;
}
if ((DeviceBrush.BlendCounts[0] > 1) && (DeviceBrush.BlendFactors[0] != NULL) && (DeviceBrush.BlendPositions[0] != NULL))
{
flags |= GDIP_BRUSHFLAGS_BLENDFACTORS0;
}
if ((DeviceBrush.BlendCounts[1] > 1) && (DeviceBrush.BlendFactors[1] != NULL) && (DeviceBrush.BlendPositions[1] != NULL))
{
flags |= GDIP_BRUSHFLAGS_BLENDFACTORS1;
}
if ((DeviceBrush.BlendCounts[2] > 1) && (DeviceBrush.BlendFactors[2] != NULL) && (DeviceBrush.BlendPositions[2] != NULL))
{
flags |= GDIP_BRUSHFLAGS_BLENDFACTORS2;
}
TriangleGradientBrushData brushData;
brushData.Type = DeviceBrush.Type;
brushData.Flags = flags;
brushData.Wrap = DeviceBrush.Wrap;
brushData.Points[0] = DeviceBrush.Points[0];
brushData.Points[1] = DeviceBrush.Points[1];
brushData.Points[2] = DeviceBrush.Points[2];
brushData.Color0 = DeviceBrush.Colors[0].GetValue();
brushData.Color1 = DeviceBrush.Colors[1].GetValue();
brushData.Color2 = DeviceBrush.Colors[2].GetValue();
stream->Write(&brushData, sizeof(brushData), NULL);
if (flags & GDIP_BRUSHFLAGS_TRANSFORM)
{
DeviceBrush.Xform.WriteMatrix(stream);
}
if (flags & GDIP_BRUSHFLAGS_BLENDFACTORS0)
{
INT realSize = DeviceBrush.BlendCounts[0] * sizeof(REAL);
stream->Write(&DeviceBrush.BlendCounts[0], sizeof(INT32), NULL);
stream->Write(DeviceBrush.BlendPositions[0], realSize, NULL);
stream->Write(DeviceBrush.BlendFactors[0], realSize, NULL);
}
if (flags & GDIP_BRUSHFLAGS_BLENDFACTORS1)
{
INT realSize = DeviceBrush.BlendCounts[1] * sizeof(REAL);
stream->Write(&DeviceBrush.BlendCounts[1], sizeof(INT32), NULL);
stream->Write(DeviceBrush.BlendPositions[1], realSize, NULL);
stream->Write(DeviceBrush.BlendFactors[1], realSize, NULL);
}
if (flags & GDIP_BRUSHFLAGS_BLENDFACTORS2)
{
INT realSize = DeviceBrush.BlendCounts[2] * sizeof(REAL);
stream->Write(&DeviceBrush.BlendCounts[2], sizeof(INT32), NULL);
stream->Write(DeviceBrush.BlendPositions[2], realSize, NULL);
stream->Write(DeviceBrush.BlendFactors[2], realSize, NULL);
}
return Ok;
}
UINT
GpTriangleGradient::GetDataSize() const
{
UINT size = sizeof(RectGradientBrushData);
if (!DeviceBrush.Xform.IsIdentity())
{
size += GDIP_MATRIX_SIZE;
}
if ((DeviceBrush.BlendCounts[0] > 1) && (DeviceBrush.BlendFactors[0] != NULL) && (DeviceBrush.BlendPositions[0] != NULL))
{
size += sizeof(INT32) + ((sizeof(REAL) + sizeof(REAL)) * DeviceBrush.BlendCounts[0]);
}
if ((DeviceBrush.BlendCounts[1] > 1) && (DeviceBrush.BlendFactors[1] != NULL) && (DeviceBrush.BlendPositions[1] != NULL))
{
size += sizeof(INT32) + ((sizeof(REAL) + sizeof(REAL)) * DeviceBrush.BlendCounts[1]);
}
if ((DeviceBrush.BlendCounts[2] > 1) && (DeviceBrush.BlendFactors[2] != NULL) && (DeviceBrush.BlendPositions[2] != NULL))
{
size += sizeof(INT32) + ((sizeof(REAL) + sizeof(REAL)) * DeviceBrush.BlendCounts[2]);
}
return size;
}
/**************************************************************************\
*
* Function Description:
*
* Read the brush object from memory.
*
* Arguments:
*
* [IN] dataBuffer - the data that was read from the stream
* [IN] size - the size of the data
*
* Return Value:
*
* GpStatus - Ok or failure status
*
* Created:
*
* 4/26/1999 DCurtis
*
\**************************************************************************/
GpStatus
GpTriangleGradient::SetData(
const BYTE * dataBuffer,
UINT size
)
{
// ASSERT ((GpBrushType)(((TriangleGradientBrushData *)dataBuffer)->Type) == BrushTypeTriangleGradient);
if (dataBuffer == NULL)
{
WARNING(("dataBuffer is NULL"));
return InvalidParameter;
}
if (size < sizeof(TriangleGradientBrushData))
{
WARNING(("size too small"));
return InvalidParameter;
}
const TriangleGradientBrushData * brushData;
GpColor colors[3];
brushData = reinterpret_cast<const TriangleGradientBrushData *>(dataBuffer);
if (!brushData->MajorVersionMatches())
{
WARNING(("Version number mismatch"));
return InvalidParameter;
}
colors[0].SetValue(brushData->Color0);
colors[1].SetValue(brushData->Color1);
colors[2].SetValue(brushData->Color2);
InitializeBrush(brushData->Points, colors, (GpWrapMode) brushData->Wrap);
DeviceBrush.IsGammaCorrected = ((brushData->Flags & GDIP_BRUSHFLAGS_ISGAMMACORRECTED) != 0);
dataBuffer += sizeof(TriangleGradientBrushData);
size -= sizeof(TriangleGradientBrushData);
if (brushData->Flags & GDIP_BRUSHFLAGS_TRANSFORM)
{
if (size < GDIP_MATRIX_SIZE)
{
WARNING(("size too small"));
return InvalidParameter;
}
DeviceBrush.Xform.SetMatrix((REAL *)dataBuffer);
dataBuffer += GDIP_MATRIX_SIZE;
size -= GDIP_MATRIX_SIZE;
}
if (brushData->Flags & GDIP_BRUSHFLAGS_BLENDFACTORS0)
{
if (size < sizeof(INT32))
{
WARNING(("size too small"));
return InvalidParameter;
}
UINT count = ((INT32 *)dataBuffer)[0];
dataBuffer += sizeof(INT32);
size -= sizeof(INT32);
UINT realSize = count * sizeof(REAL);
if (size < (2 * realSize))
{
WARNING(("size too small"));
return InvalidParameter;
}
this->SetBlend0((REAL *)(dataBuffer + realSize), (REAL *)dataBuffer, count);
dataBuffer += (2 * realSize);
size -= (2 * realSize);
}
if (brushData->Flags & GDIP_BRUSHFLAGS_BLENDFACTORS1)
{
if (size < sizeof(INT32))
{
WARNING(("size too small"));
return InvalidParameter;
}
UINT count = ((INT32 *)dataBuffer)[0];
dataBuffer += sizeof(INT32);
size -= sizeof(INT32);
UINT realSize = count * sizeof(REAL);
if (size < (2 * realSize))
{
WARNING(("size too small"));
return InvalidParameter;
}
this->SetBlend1((REAL *)(dataBuffer + realSize), (REAL *)dataBuffer, count);
dataBuffer += (2 * realSize);
size -= (2 * realSize);
}
if (brushData->Flags & GDIP_BRUSHFLAGS_BLENDFACTORS2)
{
if (size < sizeof(INT32))
{
WARNING(("size too small"));
return InvalidParameter;
}
UINT count = ((INT32 *)dataBuffer)[0];
dataBuffer += sizeof(INT32);
size -= sizeof(INT32);
UINT realSize = count * sizeof(REAL);
if (size < (2 * realSize))
{
WARNING(("size too small"));
return InvalidParameter;
}
this->SetBlend2((REAL *)(dataBuffer + realSize), (REAL *)dataBuffer, count);
dataBuffer += (2 * realSize);
size -= (2 * realSize);
}
UpdateUid();
return Ok;
}
GpStatus
GpTriangleGradient::ColorAdjust(
GpRecolor * recolor,
ColorAdjustType type
)
{
if(!recolor)
return InvalidParameter;
if (type == ColorAdjustTypeDefault)
{
type = ColorAdjustTypeBrush;
}
ARGB solidColor32[3];
solidColor32[0] = DeviceBrush.Colors[0].GetValue();
solidColor32[1] = DeviceBrush.Colors[1].GetValue();
solidColor32[2] = DeviceBrush.Colors[2].GetValue();
recolor->ColorAdjust(solidColor32, 3, type);
DeviceBrush.Colors[0].SetValue(solidColor32[0]);
DeviceBrush.Colors[1].SetValue(solidColor32[1]);
DeviceBrush.Colors[2].SetValue(solidColor32[2]);
UpdateUid();
return Ok;
}
#endif
class PathGradientBrushData : public ObjectTypeData
{
public:
INT32 Flags;
INT32 Wrap;
UINT32 CenterColor;
GpPointF CenterPoint;
UINT32 SurroundingColorCount;
};
/**************************************************************************\
*
* Function Description:
*
* Get the brush data.
*
* Arguments:
*
* [IN] dataBuffer - fill this buffer with the data
* [IN/OUT] size - IN - size of buffer; OUT - number bytes written
*
* Return Value:
*
* GpStatus - Ok or error code
*
* Created:
*
* 9/13/1999 DCurtis
*
\**************************************************************************/
GpStatus
GpPathGradient::GetData(
IStream * stream
) const
{
ASSERT (stream != NULL);
UINT pathSize = 0;
UINT surroundingColorCount = DeviceBrush.OneSurroundColor ? 1 : DeviceBrush.Count;
INT flags = 0;
GpPath * path = GpPath::GetPath(DeviceBrush.Path);
if (DeviceBrush.IsGammaCorrected)
{
flags |= GDIP_BRUSHFLAGS_ISGAMMACORRECTED;
}
if ((DeviceBrush.PointsPtr == NULL) && (path != NULL))
{
flags |= GDIP_BRUSHFLAGS_PATH;
pathSize = path->GetDataSize();
ASSERT((pathSize & 0x03) == 0);
}
if (!DeviceBrush.Xform.IsIdentity())
{
flags |= GDIP_BRUSHFLAGS_TRANSFORM;
}
// Note: can't have both blendFactors and presetColors at the same time
if (DeviceBrush.UsesPresetColors && (DeviceBrush.BlendCounts[0] > 1) && (DeviceBrush.PresetColors != NULL) &&
(DeviceBrush.BlendPositions[0] != NULL) && (DeviceBrush.BlendFactors[0] == NULL))
{
flags |= GDIP_BRUSHFLAGS_PRESETCOLORS;
}
if ((DeviceBrush.BlendCounts[0] > 1) && (DeviceBrush.BlendFactors[0] != NULL) && (DeviceBrush.BlendPositions[0] != NULL))
{
flags |= GDIP_BRUSHFLAGS_BLENDFACTORS;
}
if((DeviceBrush.FocusScaleX != 0) || (DeviceBrush.FocusScaleY != 0))
{
flags |= GDIP_BRUSHFLAGS_FOCUSSCALES;
}
PathGradientBrushData brushData;
brushData.Type = DeviceBrush.Type;
brushData.Flags = flags;
brushData.Wrap = DeviceBrush.Wrap;
brushData.CenterColor = DeviceBrush.Colors[0].GetValue();
brushData.CenterPoint = DeviceBrush.Points[0];
brushData.SurroundingColorCount = surroundingColorCount;
stream->Write(&brushData, sizeof(brushData), NULL);
ARGB argb;
for (UINT i = 0; i < surroundingColorCount; i++)
{
argb = DeviceBrush.ColorsPtr[i].GetValue();
stream->Write(&argb, sizeof(argb), NULL);
}
if (flags & GDIP_BRUSHFLAGS_PATH)
{
stream->Write(&pathSize, sizeof(INT32), NULL);
path->GetData(stream);
}
else
{
INT count = DeviceBrush.Count;
if (DeviceBrush.PointsPtr == NULL)
{
count = 0;
}
stream->Write(&count, sizeof(INT32), NULL);
if (count > 0)
{
INT pointsSize = count * sizeof(DeviceBrush.PointsPtr[0]);
stream->Write(DeviceBrush.PointsPtr, pointsSize, NULL);
}
}
if (flags & GDIP_BRUSHFLAGS_TRANSFORM)
{
DeviceBrush.Xform.WriteMatrix(stream);
}
if (flags & GDIP_BRUSHFLAGS_PRESETCOLORS)
{
INT count = DeviceBrush.BlendCounts[0];
INT realSize = count * sizeof(REAL);
INT argbSize = count * sizeof(ARGB);
REAL *newPositions = (REAL*) GpMalloc(realSize);
if (newPositions == NULL )
{
return OutOfMemory;
}
ARGB *newARGB = (ARGB*) GpMalloc(argbSize);
if (newARGB == NULL )
{
GpFree(newPositions);
return OutOfMemory;
}
GpColor *newPresetColors = new GpColor[count];
if (newPresetColors == NULL)
{
GpFree(newPositions);
GpFree (newARGB);
return OutOfMemory;
}
// Users will supply the preset colors as radial blend colors.
// 0 position means the center location and 1 position means the
// the outer edge. These are stored inverted internally, so to get back
// to the original user values, invert again.
GetPresetBlend(newPresetColors, newPositions, count);
for (INT i = 0; i < count; i++)
{
newARGB[i] = newPresetColors[i].GetValue();
}
stream->Write(&count, sizeof(INT32), NULL);
stream->Write(newPositions, realSize, NULL);
stream->Write(newARGB, argbSize, NULL);
GpFree(newPositions);
GpFree(newARGB);
delete newPresetColors;
}
if (flags & GDIP_BRUSHFLAGS_BLENDFACTORS)
{
INT count = DeviceBrush.BlendCounts[0];
INT realSize = count * sizeof(REAL);
// Users will supply the blend factor as radial blend factors, and these are stored
// with inverted values. To get back the original user specified blend factors to
// store, they must be inverted again.
REAL *newFactors = (REAL*) GpMalloc(realSize);
if (newFactors == NULL )
{
return OutOfMemory;
}
REAL *newPositions = (REAL*) GpMalloc(realSize);
if (newPositions == NULL )
{
GpFree(newFactors);
return OutOfMemory;
}
GetBlend(newFactors, newPositions, count);
stream->Write(&count, sizeof(INT32), NULL);
stream->Write(newPositions, realSize, NULL);
stream->Write(newFactors, realSize, NULL);
GpFree(newPositions);
GpFree(newFactors);
}
if (flags & GDIP_BRUSHFLAGS_FOCUSSCALES)
{
INT count = 2;
REAL focusScale[2];
focusScale[0] = DeviceBrush.FocusScaleX;
focusScale[1] = DeviceBrush.FocusScaleY;
stream->Write(&count, sizeof(INT32), NULL);
stream->Write(focusScale, 2 * sizeof(REAL), NULL);
}
return Ok;
}
UINT
GpPathGradient::GetDataSize() const
{
UINT pathSize;
UINT surroundingColorCount = DeviceBrush.OneSurroundColor ? 1 : DeviceBrush.Count;
UINT size = sizeof(PathGradientBrushData) +
(surroundingColorCount * sizeof(ARGB));
GpPath* path = static_cast<GpPath*> (DeviceBrush.Path);
if (DeviceBrush.PointsPtr != NULL)
{
size += sizeof(INT32) + (DeviceBrush.Count * sizeof(DeviceBrush.PointsPtr[0]));
}
else if (path != NULL)
{
pathSize = path->GetDataSize();
ASSERT((pathSize & 0x03) == 0);
size += sizeof(INT32) + pathSize;
}
if (!DeviceBrush.Xform.IsIdentity())
{
size += GDIP_MATRIX_SIZE;
}
// Note: can't have both blendFactors and presetColors at the same time
if (DeviceBrush.UsesPresetColors && (DeviceBrush.BlendCounts[0] > 1) && (DeviceBrush.PresetColors != NULL) &&
(DeviceBrush.BlendPositions[0] != NULL) && (DeviceBrush.BlendFactors[0] == NULL))
{
size += sizeof(INT32) + ((sizeof(ARGB) + sizeof(REAL)) * DeviceBrush.BlendCounts[0]);
}
if ((DeviceBrush.BlendCounts[0] > 1) && (DeviceBrush.BlendFactors[0] != NULL) && (DeviceBrush.BlendPositions[0] != NULL))
{
size += sizeof(INT32) + ((sizeof(REAL) + sizeof(REAL)) * DeviceBrush.BlendCounts[0]);
}
if((DeviceBrush.FocusScaleX != 0) || (DeviceBrush.FocusScaleY != 0))
{
size += sizeof(INT32) + 2*sizeof(REAL);
}
return size;
}
/**************************************************************************\
*
* Function Description:
*
* Read the brush object from memory.
*
* Arguments:
*
* [IN] dataBuffer - the data that was read from the stream
* [IN] size - the size of the data
*
* Return Value:
*
* GpStatus - Ok or failure status
*
* Created:
*
* 4/26/1999 DCurtis
*
\**************************************************************************/
GpStatus
GpPathGradient::SetData(
const BYTE * dataBuffer,
UINT size
)
{
ASSERT ((GpBrushType)(((PathGradientBrushData *)dataBuffer)->Type) == BrushTypePathGradient);
if (dataBuffer == NULL)
{
WARNING(("dataBuffer is NULL"));
return InvalidParameter;
}
if (size < sizeof(PathGradientBrushData))
{
WARNING(("size too small"));
return InvalidParameter;
}
if (DeviceBrush.PointsPtr != NULL)
{
GpFree(DeviceBrush.PointsPtr);
DeviceBrush.PointsPtr = NULL;
}
GpPath* path = static_cast<GpPath*> (DeviceBrush.Path);
if (path != NULL)
{
delete path;
path = NULL;
}
const PathGradientBrushData * brushData;
ARGB * surroundingColors;
brushData = reinterpret_cast<const PathGradientBrushData *>(dataBuffer);
if (!brushData->MajorVersionMatches())
{
WARNING(("Version number mismatch"));
return InvalidParameter;
}
dataBuffer += sizeof(PathGradientBrushData);
size -= sizeof(PathGradientBrushData);
if (size < (brushData->SurroundingColorCount * sizeof(ARGB)))
{
WARNING(("size too small"));
return InvalidParameter;
}
surroundingColors = (ARGB *)dataBuffer;
dataBuffer += (brushData->SurroundingColorCount * sizeof(ARGB));
size -= (brushData->SurroundingColorCount * sizeof(ARGB));
if (brushData->Flags & GDIP_BRUSHFLAGS_PATH)
{
if (size < sizeof(INT32))
{
WARNING(("size too small"));
return InvalidParameter;
}
UINT pathSize = ((INT32 *)dataBuffer)[0];
dataBuffer += sizeof(INT32);
size -= sizeof(INT32);
DefaultBrush();
DeviceBrush.Wrap = (GpWrapMode) brushData->Wrap;
if (size < pathSize)
{
WARNING(("size too small"));
return InvalidParameter;
}
path = new GpPath();
if (path)
{
path->SetData(dataBuffer, pathSize);
}
DeviceBrush.Path = path;
PrepareBrush();
dataBuffer += pathSize;
size -= pathSize;
}
else
{
if (size < sizeof(INT32))
{
WARNING(("size too small"));
return InvalidParameter;
}
INT count = ((INT32 *)dataBuffer)[0];
dataBuffer += sizeof(INT32);
size -= sizeof(INT32);
if (size < (count * sizeof(GpPointF)))
{
WARNING(("size too small"));
return InvalidParameter;
}
InitializeBrush((GpPointF *)dataBuffer, count, (GpWrapMode) brushData->Wrap);
dataBuffer += (count * sizeof(GpPointF));
size -= (count * sizeof(GpPointF));
}
DeviceBrush.IsGammaCorrected = ((brushData->Flags & GDIP_BRUSHFLAGS_ISGAMMACORRECTED) != 0);
SetCenterPoint(brushData->CenterPoint);
SetCenterColor(GpColor(brushData->CenterColor));
DeviceBrush.OneSurroundColor = (brushData->SurroundingColorCount == 1);
if (DeviceBrush.ColorsPtr != NULL)
{
for (UINT32 i = 0; i < brushData->SurroundingColorCount; i++)
{
SetSurroundColor(GpColor(surroundingColors[i]), i);
}
// OneSurroundColor requires n colors and they are all set to the
// same value. This is a very weird requirement, but that's the way
// it was written. One color simply isn't enough.
if (i == 1)
{
for (i = 1; (INT)i < DeviceBrush.Count; i++)
{
DeviceBrush.ColorsPtr[i] = GpColor(surroundingColors[0]);
}
}
}
if (brushData->Flags & GDIP_BRUSHFLAGS_TRANSFORM)
{
if (size < GDIP_MATRIX_SIZE)
{
WARNING(("size too small"));
return InvalidParameter;
}
DeviceBrush.Xform.SetMatrix((REAL *)dataBuffer);
dataBuffer += GDIP_MATRIX_SIZE;
size -= GDIP_MATRIX_SIZE;
}
if (brushData->Flags & GDIP_BRUSHFLAGS_PRESETCOLORS)
{
if (size < sizeof(INT32))
{
WARNING(("size too small"));
return InvalidParameter;
}
UINT count = ((INT32 *)dataBuffer)[0];
dataBuffer += sizeof(INT32);
size -= sizeof(INT32);
UINT realSize = count * sizeof(REAL);
UINT argbSize = count * sizeof(ARGB);
if (size < (realSize + argbSize))
{
WARNING(("size too small"));
return InvalidParameter;
}
ARGB *argbBuffer = (ARGB*)(dataBuffer + realSize);
GpColor *colors = new GpColor[count];
if (colors == NULL)
{
return OutOfMemory;
}
for (UINT i = 0; i < count; i++)
{
colors[i].SetValue(argbBuffer[i]);
}
this->SetPresetBlend(colors, (REAL *)dataBuffer, count);
dataBuffer += (realSize + argbSize);
size -= (realSize + argbSize);
delete colors;
}
if (brushData->Flags & GDIP_BRUSHFLAGS_BLENDFACTORS)
{
if (size < sizeof(INT32))
{
WARNING(("size too small"));
return InvalidParameter;
}
UINT count = ((INT32 *)dataBuffer)[0];
dataBuffer += sizeof(INT32);
size -= sizeof(INT32);
UINT realSize = count * sizeof(REAL);
if (size < (2 * realSize))
{
WARNING(("size too small"));
return InvalidParameter;
}
this->SetBlend((REAL *)(dataBuffer + realSize), (REAL *)dataBuffer, count);
dataBuffer += (2 * realSize);
size -= (2 * realSize);
}
if (brushData->Flags & GDIP_BRUSHFLAGS_FOCUSSCALES)
{
if (size < sizeof(INT32))
{
WARNING(("size too small"));
return InvalidParameter;
}
INT count = ((INT32 *)dataBuffer)[0];
dataBuffer += sizeof(INT32);
size -= sizeof(INT32);
if (size < (2 * sizeof(REAL)))
{
WARNING(("size too small"));
return InvalidParameter;
}
DeviceBrush.FocusScaleX = ((REAL *) dataBuffer)[0];
DeviceBrush.FocusScaleY = ((REAL *) dataBuffer)[1];
dataBuffer += (2 * sizeof(REAL));
size -= (2 * sizeof(REAL));
}
UpdateUid();
return Ok;
}
/**************************************************************************\
*
* Function Description:
*
* Blend any transparent colors in this brush with white. Note that
* colors are premultiplied, since they will become fully opaque.
*
* Arguments:
*
* Return Value:
*
* GpStatus - Ok or failure status
*
\**************************************************************************/
GpStatus GpPathGradient::BlendWithWhite()
{
DeviceBrush.Colors[0].SetValue(
GpColor::ConvertToPremultiplied(DeviceBrush.Colors[0].GetValue()));
DeviceBrush.Colors[0].BlendOpaqueWithWhite();
if (DeviceBrush.UsesPresetColors)
{
GpColor color;
for (INT i=0; i<DeviceBrush.BlendCounts[0]; i++)
{
color.SetValue(GpColor::ConvertToPremultiplied(DeviceBrush.PresetColors[i]));
color.BlendOpaqueWithWhite();
DeviceBrush.PresetColors[i] = color.GetValue();
}
}
else
{
for (INT i=0; i<DeviceBrush.Count; i++)
{
DeviceBrush.ColorsPtr[i].SetValue(
GpColor::ConvertToPremultiplied(DeviceBrush.ColorsPtr[i].GetValue()));
DeviceBrush.ColorsPtr[i].BlendOpaqueWithWhite();
}
}
return Ok;
}
/**************************************************************************\
*
* Function Description:
*
* Set the surround color.
*
* Arguments:
*
* [IN] color - the color to set.
* [IN] index - which color to set.
*
* Return Value:
*
* GpStatus - Ok or failure status
*
\**************************************************************************/
GpStatus GpPathGradient::SetSurroundColor(GpColor& color, INT index)
{
if(index >= 0 && index < DeviceBrush.Count)
{
if(DeviceBrush.OneSurroundColor)
{
if(index == 0)
{
DeviceBrush.ColorsPtr[0] = color;
// OneSurroundColor requires n colors and they are all set to the
// same value. This is a very weird requirement, but that's the way
// it was written. One color simply isn't enough.
for (INT i = 1; i < DeviceBrush.Count; i++)
{
DeviceBrush.ColorsPtr[i] = GpColor(DeviceBrush.ColorsPtr[0]);
}
UpdateUid();
}
else
{
if(DeviceBrush.ColorsPtr[0].GetValue() !=
color.GetValue())
{
DeviceBrush.OneSurroundColor = FALSE;
DeviceBrush.ColorsPtr[index] = color;
UpdateUid();
}
}
}
else
{
DeviceBrush.ColorsPtr[index] = color;
UpdateUid();
}
return Ok;
}
else
return InvalidParameter;
}
/**************************************************************************\
*
* Function Description:
*
* Set the surround colors.
*
* Arguments:
*
* [IN] color - the color to set.
*
* Return Value:
*
* GpStatus - Ok or failure status
*
\**************************************************************************/
GpStatus GpPathGradient::SetSurroundColors(const GpColor* colors)
{
GpStatus status = InvalidParameter;
ASSERT(DeviceBrush.Count > 0);
if(IsValid() && colors && DeviceBrush.Count > 0)
{
GpMemcpy(
DeviceBrush.ColorsPtr,
colors,
DeviceBrush.Count*sizeof(GpColor)
);
DeviceBrush.OneSurroundColor = TRUE;
INT i = 1;
ARGB value = colors[0].GetValue();
while((i < DeviceBrush.Count) && (DeviceBrush.OneSurroundColor))
{
if(colors[i].GetValue() != value)
{
DeviceBrush.OneSurroundColor = FALSE;
}
i++;
}
UpdateUid();
status = Ok;
}
return status;
}
GpStatus
GpPathGradient::ColorAdjust(
GpRecolor * recolor,
ColorAdjustType type
)
{
if(!recolor)
return InvalidParameter;
if (type == ColorAdjustTypeDefault)
{
type = ColorAdjustTypeBrush;
}
INT surroundingColorCount = DeviceBrush.OneSurroundColor ? 1 : DeviceBrush.Count;
if ((surroundingColorCount > 0) && (DeviceBrush.ColorsPtr != NULL))
{
ARGB solidColor32[32];
ARGB * color32 = solidColor32;
if (surroundingColorCount > 32)
{
color32 = new ARGB[surroundingColorCount];
if (color32 == NULL)
{
return OutOfMemory;
}
}
INT i;
for (i = 0; i < surroundingColorCount; i++)
{
color32[i] = DeviceBrush.ColorsPtr[i].GetValue();
}
recolor->ColorAdjust(color32, surroundingColorCount, type);
for (i = 0; i < surroundingColorCount; i++)
{
DeviceBrush.ColorsPtr[i].SetValue(color32[i]);
}
if (color32 != solidColor32)
{
delete[] color32;
}
}
if (DeviceBrush.UsesPresetColors && (DeviceBrush.BlendCounts[0] > 1) && (DeviceBrush.PresetColors != NULL))
{
recolor->ColorAdjust(DeviceBrush.PresetColors, DeviceBrush.BlendCounts[0], type);
}
UpdateUid();
return Ok;
}
class HatchBrushData : public ObjectTypeData
{
public:
INT32 Style;
UINT32 ForeColor;
UINT32 BackColor;
};
/**************************************************************************\
*
* Function Description:
*
* Get the brush data.
*
* Arguments:
*
* [IN] dataBuffer - fill this buffer with the data
* [IN/OUT] size - IN - size of buffer; OUT - number bytes written
*
* Return Value:
*
* GpStatus - Ok or error code
*
* Created:
*
* 9/13/1999 DCurtis
*
\**************************************************************************/
GpStatus
GpHatch::GetData(
IStream * stream
) const
{
ASSERT (stream != NULL);
HatchBrushData brushData;
brushData.Type = DeviceBrush.Type;
brushData.Style = DeviceBrush.Style;
brushData.ForeColor = DeviceBrush.Colors[0].GetValue();
brushData.BackColor = DeviceBrush.Colors[1].GetValue();
stream->Write(&brushData, sizeof(brushData), NULL);
return Ok;
}
UINT
GpHatch::GetDataSize() const
{
return sizeof(HatchBrushData);
}
/**************************************************************************\
*
* Function Description:
*
* Read the brush object from memory.
*
* Arguments:
*
* [IN] dataBuffer - the data that was read from the stream
* [IN] size - the size of the data
*
* Return Value:
*
* GpStatus - Ok or failure status
*
* Created:
*
* 4/26/1999 DCurtis
*
\**************************************************************************/
GpStatus
GpHatch::SetData(
const BYTE * dataBuffer,
UINT size
)
{
ASSERT ((GpBrushType)(((HatchBrushData *)dataBuffer)->Type) == BrushTypeHatchFill);
if (dataBuffer == NULL)
{
WARNING(("dataBuffer is NULL"));
return InvalidParameter;
}
if (size < sizeof(HatchBrushData))
{
WARNING(("size too small"));
return InvalidParameter;
}
const HatchBrushData * brushData;
brushData = reinterpret_cast<const HatchBrushData *>(dataBuffer);
if (!brushData->MajorVersionMatches())
{
WARNING(("Version number mismatch"));
return InvalidParameter;
}
InitializeBrush(static_cast<GpHatchStyle>(brushData->Style),
GpColor(brushData->ForeColor),
GpColor(brushData->BackColor));
UpdateUid();
return Ok;
}
GpStatus
GpHatch::ColorAdjust(
GpRecolor * recolor,
ColorAdjustType type
)
{
ASSERT(recolor != NULL);
if (type == ColorAdjustTypeDefault)
{
type = ColorAdjustTypeBrush;
}
ARGB solidColor32[2];
solidColor32[0] = DeviceBrush.Colors[0].GetValue();
//!!! bhouse: bug?
// seems that this should be BackColor ... I'm making the
// change!
// solidColor32[1] = ForeColor.GetValue();
solidColor32[1] = DeviceBrush.Colors[1].GetValue();
recolor->ColorAdjust(solidColor32, 2, type);
DeviceBrush.Colors[0].SetValue(solidColor32[0]);
DeviceBrush.Colors[1].SetValue(solidColor32[1]);
UpdateUid();
return Ok;
}
static COLORREF
AverageColors(
const GpColor * colors,
INT count
)
{
REAL r = 0;
REAL g = 0;
REAL b = 0;
if (count > 0)
{
for (INT i = 0; i < count; i++)
{
r += colors->GetRed();
g += colors->GetGreen();
b += colors->GetBlue();
}
r /= count;
g /= count;
b /= count;
}
INT red = GpRound(r);
INT green = GpRound(g);
INT blue = GpRound(b);
return RGB(red, green, blue);
}
static COLORREF
AverageColors(
const GpColor & color1,
const GpColor & color2
)
{
REAL r = ((REAL)((INT)color1.GetRed() + (INT)color2.GetRed())) / 2.0f;
REAL g = ((REAL)((INT)color1.GetGreen()+ (INT)color2.GetGreen())) / 2.0f;
REAL b = ((REAL)((INT)color1.GetBlue() + (INT)color2.GetBlue())) / 2.0f;
INT red = GpRound(r);
INT green = GpRound(g);
INT blue = GpRound(b);
return RGB(red, green, blue);
}
COLORREF
ToCOLORREF(
const DpBrush * deviceBrush
)
{
switch (deviceBrush->Type)
{
default:
ASSERT(0);
// FALLTHRU
case BrushTypeSolidColor:
return deviceBrush->SolidColor.ToCOLORREF();
case BrushTypeHatchFill:
return AverageColors(deviceBrush->Colors[0],
deviceBrush->Colors[1]);
case BrushTypeTextureFill:
return RGB(0x80, 0x80, 0x80);
// case BrushRectGrad:
case BrushTypeLinearGradient:
return AverageColors(deviceBrush->Colors, 4);
#if 0
case BrushRadialGrad:
return AverageColors(deviceBrush->Colors[0],
deviceBrush->Colors[1]);
case BrushTriangleGrad:
return AverageColors(deviceBrush->Colors, 3);
#endif
case BrushTypePathGradient:
return AverageColors(deviceBrush->Colors[0],
deviceBrush->ColorsPtr[0]);
}
}