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

2448 lines
64 KiB
C++

/**************************************************************************\
*
* Copyright (c) 1998 Microsoft Corporation
*
* Abstract:
*
* Brush API related declarations
*
* Revision History:
*
* 12/09/1998 davidx
* Flesh out Brush interfaces.
*
* 12/08/1998 andrewgo
* Created it.
*
\**************************************************************************/
#ifndef _BRUSH_HPP
#define _BRUSH_HPP
#define HatchBrush HatchFillBrush
#include "path.hpp" // GpPathGradient needs GpPath.
#include <stddef.h>
#include "..\..\sdkinc\GdiplusColor.h" // IsOpaque needs AlphaMask.
COLORREF
ToCOLORREF(
const DpBrush * deviceBrush
);
enum GpSpecialGradientType
{
GradientTypeNotSpecial,
GradientTypeHorizontal,
GradientTypeVertical,
GradientTypeDiagonal,
GradientTypePathTwoStep,
GradientTypePathComplex
};
//--------------------------------------------------------------------------
// Abstract base class for various brush types
//--------------------------------------------------------------------------
class GpBrush : public GpObject
{
protected:
VOID SetValid(BOOL valid)
{
GpObject::SetValid(valid ? ObjectTagBrush : ObjectTagInvalid);
}
public:
// Make a copy of the Brush object
virtual GpBrush* Clone() const = 0;
// Virtual destructor
virtual ~GpBrush() {}
// Determine if brushes are equivalent
virtual BOOL IsEqual(const GpBrush * brush) const
{
return DeviceBrush.Type == brush->DeviceBrush.Type;
}
// Get the lock object
GpLockable *GetObjectLock() const
{
return &Lockable;
}
GpBrushType GetBrushType() const
{
return DeviceBrush.Type;
}
const DpBrush * GetDeviceBrush() const
{
return & DeviceBrush;
}
virtual BOOL IsValid() const
{
return GpObject::IsValid(ObjectTagBrush);
}
virtual const DpPath * GetOutlinePath() const
{
return NULL;
}
virtual BOOL IsOpaque(BOOL ColorsOnly = FALSE) const = 0;
//IsSolid currently means that the entire fill has the same ARGB color.
//v2: Think about changing this to mean same RGB color instead.
virtual BOOL IsSolid() const = 0;
virtual BOOL IsNearConstant(BYTE *MinAlpha, BYTE* MaxAlpha) const = 0;
// return Horizontal, Vertical, or (in future path)
virtual GpSpecialGradientType
GetSpecialGradientType(const GpMatrix* matrix) const = 0;
virtual ObjectType GetObjectType() const { return ObjectTypeBrush; }
static GpBrush * GetBrush(const DpBrush * brush)
{
return (GpBrush *) ((BYTE *) brush - offsetof(GpBrush, DeviceBrush));
}
COLORREF ToCOLORREF() const
{
return ::ToCOLORREF(&DeviceBrush);
}
virtual DpOutputSpan* CreateOutputSpan(
DpScanBuffer * scan,
DpContext *context,
const GpRect *drawBounds = NULL) = 0;
void SetGammaCorrection(BOOL useGamma)
{
DeviceBrush.IsGammaCorrected = useGamma;
}
BOOL GetGammaCorrection() const
{
return DeviceBrush.IsGammaCorrected;
}
protected: // GDI+ Internal
DpBrush DeviceBrush;
mutable GpLockable Lockable;
};
//--------------------------------------------------------------------------
// Represent solid fill brush object
//--------------------------------------------------------------------------
class GpSolidFill : public GpBrush
{
public:
GpSolidFill(VOID)
{
DefaultBrush();
}
GpSolidFill(const GpColor& color)
: Color(color)
{
DeviceBrush.Type = BrushTypeSolidColor;
DeviceBrush.SolidColor.SetColor(color.GetValue());
SetValid(TRUE);
}
~GpSolidFill() {}
virtual UINT GetDataSize() const;
virtual GpStatus GetData(IStream * stream) const;
virtual GpStatus SetData(const BYTE * dataBuffer, UINT size);
virtual GpStatus ColorAdjust(
GpRecolor * recolor,
ColorAdjustType type
);
GpColor GetColor() const
{
return Color;
}
VOID SetColor(const GpColor& color)
{
Color = color;
DeviceBrush.SolidColor.SetColor(color.GetValue());
}
GpBrush* Clone() const
{
return new GpSolidFill(Color);
}
virtual BOOL IsEqual(const GpSolidFill * brush) const
{
return Color.IsEqual(brush->Color);
}
virtual BOOL IsOpaque(BOOL ColorsOnly = FALSE) const
{
return DeviceBrush.SolidColor.IsOpaque();
}
virtual BOOL IsSolid() const
{
//This may have to change if we change the defination of IsSolid.
//See comment at GpBrush::IsSolid() for more info.
return TRUE;
}
virtual BOOL IsNearConstant(BYTE *MinAlpha, BYTE* MaxAlpha) const
{
*MinAlpha = Color.GetAlpha();
*MaxAlpha = *MinAlpha;
return TRUE;
}
virtual GpSpecialGradientType
GetSpecialGradientType(const GpMatrix* matrix) const
{
return GradientTypeNotSpecial;
}
virtual DpOutputSpan* CreateOutputSpan(
DpScanBuffer * scan,
DpContext *context,
const GpRect *drawBounds=NULL);
private:
//bhouse: why do we have store a GpColor here?
GpColor Color;
VOID DefaultBrush()
{
Color.SetValue(Color::Black);
DeviceBrush.Type = BrushTypeSolidColor;
DeviceBrush.SolidColor.SetColor(Color.GetValue());
SetValid(TRUE);
}
};
//--------------------------------------------------------------------------
// Abstract brush which is made of an elementary object.
//--------------------------------------------------------------------------
class GpElementaryBrush : public GpBrush
{
public:
virtual BOOL IsOpaque(BOOL ColorsOnly = FALSE) const = 0;
// Set/get brush transform
GpStatus SetTransform(const GpMatrix& matrix)
{
GpStatus status = Ok;
// Keep the transform invertible
if (matrix.IsInvertible())
{
DeviceBrush.Xform = matrix;
UpdateUid();
}
else
status = InvalidParameter;
return status;
}
GpStatus GetTransform(GpMatrix* matrix) const
{
*matrix = DeviceBrush.Xform;
return Ok;
}
GpStatus ResetTransform()
{
DeviceBrush.Xform.Reset();
UpdateUid();
return Ok;
}
GpStatus MultiplyTransform(const GpMatrix& matrix,
GpMatrixOrder order = MatrixOrderPrepend);
GpStatus TranslateTransform(REAL dx, REAL dy,
GpMatrixOrder order = MatrixOrderPrepend)
{
DeviceBrush.Xform.Translate(dx, dy, order);
UpdateUid();
return Ok;
}
GpStatus ScaleTransform(REAL sx, REAL sy,
GpMatrixOrder order = MatrixOrderPrepend)
{
DeviceBrush.Xform.Scale(sx, sy, order);
UpdateUid();
return Ok;
}
GpStatus ScalePath(REAL sx, REAL sy)
{
DeviceBrush.Rect.X *= sx;
DeviceBrush.Rect.Y *= sy;
DeviceBrush.Rect.Height *= sy;
DeviceBrush.Rect.Width *= sx;
DeviceBrush.Points[0].X = DeviceBrush.Points[0].X * sx;
DeviceBrush.Points[0].Y = DeviceBrush.Points[0].Y * sy;
if (DeviceBrush.Path != NULL)
{
GpMatrix matrix(sx, 0.0f, 0.0f, sy, 0.0f, 0.0f);
DeviceBrush.Path->Transform(&matrix);
}
else if (DeviceBrush.PointsPtr && DeviceBrush.Count > 0)
{
for (INT i = 0; i < DeviceBrush.Count; i++)
{
DeviceBrush.PointsPtr[i].X *= sx;
DeviceBrush.PointsPtr[i].Y *= sy;
}
}
UpdateUid();
return Ok;
}
GpStatus RotateTransform(REAL angle,
GpMatrixOrder order = MatrixOrderPrepend)
{
DeviceBrush.Xform.Rotate(angle, order);
UpdateUid();
return Ok;
}
// Set/get brush wrapping mode
VOID SetWrapMode(GpWrapMode wrapMode)
{
if (!WrapModeIsValid(wrapMode))
return;
DeviceBrush.Wrap = wrapMode;
UpdateUid();
}
GpWrapMode GetWrapMode() const
{
return DeviceBrush.Wrap;
}
// Get source rectangle
VOID GetRect(GpRectF& rect) const
{
rect = DeviceBrush.Rect;
}
// Determine if the brushes are equivalent. Only compare for equivalence
// if both brushes are valid.
virtual BOOL isEqual(const GpBrush * brush) const
{
if (GpBrush::IsEqual(brush))
{
const GpElementaryBrush * ebrush;
ebrush = static_cast<const GpElementaryBrush *>(brush);
return IsValid() &&
ebrush->IsValid() &&
ebrush->DeviceBrush.Wrap == DeviceBrush.Wrap &&
ebrush->DeviceBrush.Xform.IsEqual(&DeviceBrush.Xform);
}
else
{
return FALSE;
}
}
virtual GpSpecialGradientType
GetSpecialGradientType(const GpMatrix* matrix) const
{
return GradientTypeNotSpecial;
}
protected: // GDI+ Internal
GpElementaryBrush()
{
SetValid(FALSE);
DeviceBrush.Wrap = WrapModeTile;
DeviceBrush.IsGammaCorrected = FALSE;
}
GpElementaryBrush(const GpElementaryBrush* brush);
};
//--------------------------------------------------------------------------
// Represent texture brush object
//
// A rectangel returned by GetRect() is given by the pixel unit in case of
// GpBitmap and by the inch unit in case of GpMetafile.
//--------------------------------------------------------------------------
class GpTexture : public GpElementaryBrush
{
public:
// Constructors
GpTexture() {
DefaultBrush();
}
GpTexture(GpImage* image, GpWrapMode wrapMode = WrapModeTile)
{
InitializeBrush(image, wrapMode, NULL);
}
GpTexture(GpImage* image, GpWrapMode wrapMode, const GpRectF& rect)
{
InitializeBrush(image, wrapMode, &rect);
}
GpTexture(GpImage *image, const GpRectF& rect, const GpImageAttributes *imageAttributes)
{
GpWrapMode wrapMode = WrapModeTile;
if (imageAttributes)
{
wrapMode = imageAttributes->DeviceImageAttributes.wrapMode;
if (!imageAttributes->HasRecoloring())
{
imageAttributes = NULL;
}
}
InitializeBrush(image, wrapMode, &rect, imageAttributes);
}
GpBrush* Clone() const
{
return new GpTexture(this);
}
~GpTexture() {
if(Image)
Image->Dispose();
}
virtual UINT GetDataSize() const;
virtual GpStatus GetData(IStream * stream) const;
virtual GpStatus SetData(const BYTE * dataBuffer, UINT size);
virtual GpStatus ColorAdjust(
GpRecolor * recolor,
ColorAdjustType type
);
// Get texture brush attributes
GpImage* GetImage()
{
// !!!
// Notice that we're returning a pointer
// to our internal bitmap object here.
return Image;
}
GpImageType GetImageType() const
{
return ImageType;
}
GpBitmap* GetBitmap() const
{
// !!!
// Notice that we're returning a pointer
// to our internal bitmap object here.
if(ImageType == ImageTypeBitmap)
return static_cast<GpBitmap*>(Image);
else
return NULL;
}
GpStatus GetBitmapSize(Size * size) const
{
GpBitmap * brushBitmap = this->GetBitmap();
if (brushBitmap != NULL)
{
brushBitmap->GetSize(size);
return Ok;
}
size->Width = size->Height = 0;
return InvalidParameter;
}
// Check the opacity of bitmap.
BOOL IsOpaque(BOOL ColorsOnly = FALSE) const
{
DpTransparency transparency;
GpBitmap *bitmap = GetBitmap();
if (bitmap == NULL)
{
return FALSE;
}
ASSERT(bitmap->IsValid());
if (ColorsOnly) // get real transparency, not cached
{
if (bitmap->GetTransparencyFlags(&transparency,
PixelFormat32bppPARGB) != Ok)
{
transparency = TransparencyUnknown;
}
}
else
{
if (bitmap->GetTransparencyHint(&transparency) != Ok)
{
transparency = TransparencyUnknown;
}
}
switch (transparency)
{
case TransparencyUnknown:
case TransparencySimple:
case TransparencyComplex:
case TransparencyNearConstant:
return FALSE;
case TransparencyOpaque:
case TransparencyNoAlpha:
return TRUE;
}
ASSERT(FALSE);
return FALSE;
}
BOOL Is01Bitmap() const
{
DpTransparency transparency;
GpBitmap *bitmap = GetBitmap();
if (bitmap == NULL)
{
return FALSE;
}
ASSERT(bitmap->IsValid());
if (bitmap->GetTransparencyHint(&transparency) != Ok)
return FALSE;
switch (transparency)
{
case TransparencyUnknown:
case TransparencyOpaque:
case TransparencyNoAlpha:
case TransparencyComplex:
case TransparencyNearConstant:
return FALSE;
case TransparencySimple:
return TRUE;
}
ASSERT(FALSE);
return FALSE;
}
virtual BOOL IsSolid() const
{
//This may have to change if we change the defination of IsSolid.
//See comment at GpBrush::IsSolid() for more info.
return FALSE;
}
virtual BOOL IsNearConstant(BYTE *MinAlpha, BYTE* MaxAlpha) const
{
DpTransparency transparency;
GpBitmap *bitmap = GetBitmap();
if (bitmap == NULL)
{
return FALSE;
}
ASSERT(bitmap->IsValid());
return (bitmap->GetTransparencyFlags(&transparency,
PixelFormat32bppPARGB,
MinAlpha,
MaxAlpha) == Ok) &&
transparency == TransparencyNearConstant;
}
// See if this texture fill is really a picture fill
BOOL IsPictureFill(
const GpMatrix * worldToDevice,
const GpRect * drawBounds
) const;
// Determine if the brushes are equivalent
virtual BOOL isEqual(const GpBrush * brush) const
{
// HACKHACK - To avoid a potentially large bitmap comparison,
// treat all texture brushes as different...
return FALSE;
}
virtual DpOutputSpan* CreateOutputSpan(
DpScanBuffer * scan,
DpContext *context,
const GpRect *drawBounds=NULL);
private:
GpTexture(const GpTexture *brush);
VOID InitializeBrush(
GpImage* image,
GpWrapMode wrapMode,
const GpRectF* rect,
const GpImageAttributes *imageAttributes=NULL);
VOID InitializeBrushBitmap(
GpBitmap* bitmap,
GpWrapMode wrapMode,
const GpRectF* rect,
const GpImageAttributes *imageAttributes,
BOOL useBitmap = FALSE // use the bitmap instead of cloning it?
);
VOID DefaultBrush()
{
InitializeBrushBitmap(NULL, WrapModeTile, NULL, NULL);
}
private:
GpImageType ImageType;
GpImage * Image; // brush image
};
class GpGradientBrush : public GpElementaryBrush
{
public:
virtual VOID GetColors(GpColor* colors) const = 0;
virtual INT GetNumberOfColors() const = 0;
virtual BOOL UsesDefaultColorArray() const = 0;
virtual BOOL IsOpaque(BOOL ColorsOnly = FALSE) const = 0;
virtual GpStatus SetBlend(
const REAL* blendFactors,
const REAL* blendPositions,
INT count)
{
return NotImplemented;
}
// Determine if the brushes are equivalent
virtual BOOL isEqual(const GpBrush * brush) const
{
if (GpElementaryBrush::IsEqual(brush))
{
const DpBrush * deviceBrush = brush->GetDeviceBrush();
return deviceBrush->Rect.Equals(DeviceBrush.Rect);
}
else
{
return FALSE;
}
}
virtual GpStatus BlendWithWhite()
{
return NotImplemented;
}
GpStatus SetSigmaBlend(REAL focus, REAL scale = 1.0f);
GpStatus SetLinearBlend(REAL focus, REAL scale = 1.0f);
protected:
GpGradientBrush()
{
GpMemset(&DeviceBrush.Rect, 0, sizeof(DeviceBrush.Rect));
}
GpGradientBrush(
const GpGradientBrush* brush
) : GpElementaryBrush(brush)
{
GpMemset(&DeviceBrush.Rect, 0, sizeof(DeviceBrush.Rect));
}
GpStatus GetSigmaBlendArray(
REAL focus,
REAL scale,
INT* count,
REAL* blendFactors,
REAL* blendPositions);
GpStatus GetLinearBlendArray(
REAL focus,
REAL scale,
INT* count,
REAL* blendFactors,
REAL* blendPositions);
};
//--------------------------------------------------------------------------
// Represent rectangular gradient brush object
//--------------------------------------------------------------------------
class GpRectGradient : public GpGradientBrush
{
friend class DpOutputGradientSpan;
friend class DpOutputOneDGradientSpan;
friend class DpOutputLinearGradientSpan;
public:
// Constructors
GpRectGradient(VOID)
{
DefaultBrush();
}
GpRectGradient(
const GpRectF& rect,
const GpColor* colors,
GpWrapMode wrapMode = WrapModeTile)
{
InitializeBrush(rect, colors, wrapMode);
}
virtual GpBrush* Clone() const
{
return new GpRectGradient(this);
}
~GpRectGradient()
{
GpFree(DeviceBrush.BlendFactors[0]);
GpFree(DeviceBrush.BlendFactors[1]);
GpFree(DeviceBrush.BlendPositions[0]);
GpFree(DeviceBrush.BlendPositions[1]);
GpFree(DeviceBrush.PresetColors);
}
virtual UINT GetDataSize() const;
virtual GpStatus GetData(IStream * stream) const;
virtual GpStatus SetData(const BYTE * dataBuffer, UINT size);
virtual GpStatus ColorAdjust(
GpRecolor * recolor,
ColorAdjustType type
);
virtual GpStatus BlendWithWhite();
// Get/set colors
VOID GetColors(GpColor* colors) const
{
ASSERT(colors);
colors[0] = DeviceBrush.Colors[0];
colors[1] = DeviceBrush.Colors[1];
colors[2] = DeviceBrush.Colors[2];
colors[3] = DeviceBrush.Colors[3];
}
VOID SetColors(const GpColor* colors)
{
ASSERT(colors);
DeviceBrush.Colors[0] = colors[0];
DeviceBrush.Colors[1] = colors[1];
DeviceBrush.Colors[2] = colors[2];
DeviceBrush.Colors[3] = colors[3];
UpdateUid();
}
INT GetNumberOfColors() const {return 4;}
BOOL UsesDefaultColorArray() const {return TRUE;}
// Get/set blend factors
//
// If the blendFactors.length = 1, then it's treated
// as the falloff parameter. Otherwise, it's the array
// of blend factors.
INT GetHorizontalBlendCount()
{
return DeviceBrush.BlendCounts[0];
}
GpStatus GetHorizontalBlend(
REAL* blendFactors,
REAL* blendPositions,
INT count
);
GpStatus SetHorizontalBlend(
const REAL* blendFactors,
const REAL* blendPositions,
INT count
);
INT GetVerticalBlendCount()
{
return DeviceBrush.BlendCounts[1];
}
GpStatus GetVerticalBlend(
REAL* blendFactors,
REAL* blendPositions,
INT count
);
virtual GpStatus SetVerticalBlend(
const REAL* blendFactors,
const REAL* blendPositions,
INT count
);
BOOL HasPresetColors() const
{
return DeviceBrush.UsesPresetColors;
}
// Check the opacity of this brush element. It is opaque only if
// ALL of the colors are opaque.
BOOL IsOpaque(BOOL ColorsOnly = FALSE) const
{
BOOL opaque = ColorsOnly || DeviceBrush.Wrap != WrapModeClamp;
if (HasPresetColors())
{
INT i=0;
while (opaque && (i < DeviceBrush.BlendCounts[0]))
{
opaque = opaque && GpColor(DeviceBrush.PresetColors[i]).IsOpaque();
i++;
}
}
else
{
opaque = opaque &&
DeviceBrush.Colors[0].IsOpaque() &&
DeviceBrush.Colors[1].IsOpaque() &&
DeviceBrush.Colors[2].IsOpaque() &&
DeviceBrush.Colors[3].IsOpaque();
}
return opaque;
}
virtual BOOL IsSolid() const
{
//This may have to change if we change the defination of IsSolid.
//See comment at GpBrush::IsSolid() for more info.
return FALSE;
}
virtual BOOL IsNearConstant(BYTE* MinAlpha, BYTE* MaxAlpha) const
{
if (HasPresetColors())
{
*MaxAlpha = GpColor(DeviceBrush.PresetColors[0]).GetAlpha();
*MinAlpha = *MaxAlpha;
for (INT i=1; i<DeviceBrush.BlendCounts[0]; i++)
{
*MaxAlpha = max(*MaxAlpha, GpColor(DeviceBrush.PresetColors[i]).GetAlpha());
*MinAlpha = min(*MinAlpha, GpColor(DeviceBrush.PresetColors[i]).GetAlpha());
}
}
else
{
*MinAlpha = min(min(DeviceBrush.Colors[0].GetAlpha(),
DeviceBrush.Colors[1].GetAlpha()),
min(DeviceBrush.Colors[2].GetAlpha(),
DeviceBrush.Colors[3].GetAlpha()));
*MaxAlpha = max(max(DeviceBrush.Colors[0].GetAlpha(),
DeviceBrush.Colors[1].GetAlpha()),
max(DeviceBrush.Colors[2].GetAlpha(),
DeviceBrush.Colors[3].GetAlpha()));
}
return (*MaxAlpha - *MinAlpha < NEARCONSTANTALPHA);
}
virtual BOOL IsEqual(const GpBrush * brush) const;
virtual DpOutputSpan* CreateOutputSpan(
DpScanBuffer * scan,
DpContext *context,
const GpRect *drawBounds=NULL);
protected:
GpRectGradient(const GpRectGradient* brush);
VOID InitializeBrush(
const GpRectF& rect,
const GpColor* colors,
GpWrapMode wrapMode
)
{
DeviceBrush.Type = (BrushType) BrushTypeLinearGradient; // BrushRectGrad;
DeviceBrush.Wrap = wrapMode;
DeviceBrush.Rect = rect;
DeviceBrush.UsesPresetColors = FALSE;
DeviceBrush.BlendCounts[0] = 1;
DeviceBrush.BlendCounts[1] = 1;
DeviceBrush.BlendFactors[0] = NULL;
DeviceBrush.BlendFactors[1] = NULL;
DeviceBrush.BlendPositions[0] = NULL;
DeviceBrush.BlendPositions[1] = NULL;
DeviceBrush.Falloffs[0] = 1;
DeviceBrush.Falloffs[1] = 1;
DeviceBrush.PresetColors = NULL;
if(!WrapModeIsValid(wrapMode) || rect.Width <= 0 || rect.Height <= 0)
{
SetValid(FALSE);
return;
}
SetValid(TRUE);
SetColors(colors);
}
VOID DefaultBrush(VOID)
{
DeviceBrush.Type = (BrushType) BrushTypeLinearGradient; //BrushRectGrad;
DeviceBrush.Wrap = WrapModeTile;
DeviceBrush.UsesPresetColors = FALSE;
GpMemset(&DeviceBrush.Rect, 0, sizeof(Rect));
GpColor color; // NULL brush
DeviceBrush.Colors[0] = color;
DeviceBrush.Colors[1] = color;
DeviceBrush.Colors[2] = color;
DeviceBrush.Colors[3] = color;
DeviceBrush.BlendCounts[0] = 1;
DeviceBrush.BlendCounts[1] = 1;
DeviceBrush.BlendFactors[0] = NULL;
DeviceBrush.BlendFactors[1] = NULL;
DeviceBrush.BlendPositions[0] = NULL;
DeviceBrush.BlendPositions[1] = NULL;
DeviceBrush.Falloffs[0] = 1;
DeviceBrush.Falloffs[1] = 1;
DeviceBrush.PresetColors = NULL;
// Defaults used for GpLineGradient
DeviceBrush.IsAngleScalable = FALSE;
DeviceBrush.Points[0].X = DeviceBrush.Points[0].Y = 0;
DeviceBrush.Points[1].X = DeviceBrush.Points[1].Y = 0;
SetValid(FALSE);
}
protected:
};
class GpLineGradient : public GpRectGradient
{
friend class DpOutputGradientSpan;
friend class DpOutputOneDGradientSpan;
public:
// Constructors
GpLineGradient(VOID)
{
DefaultBrush();
}
GpLineGradient(
const GpPointF& point1,
const GpPointF& point2,
const GpColor& color1,
const GpColor& color2,
GpWrapMode wrapMode = WrapModeTile
);
GpLineGradient(
const GpRectF& rect,
const GpColor& color1,
const GpColor& color2,
LinearGradientMode mode,
GpWrapMode wrapMode = WrapModeTile
);
GpLineGradient(
const GpRectF& rect,
const GpColor& color1,
const GpColor& color2,
REAL angle,
BOOL isAngleScalable = FALSE,
GpWrapMode wrapMode = WrapModeTile
);
GpLineGradient(
const GpRectF& rect,
const GpColor* colors,
GpWrapMode wrapMode = WrapModeTile)
:GpRectGradient(rect, colors, wrapMode)
{
}
GpBrush* Clone() const
{
return new GpLineGradient(this);
}
virtual GpStatus BlendWithWhite();
// Note: ChangeLinePoints works dramatically differently than SetLinePoints.
// ChangeLinePoints is more like the constructor that takes points.
GpStatus
GpLineGradient::ChangeLinePoints(
const GpPointF& point1,
const GpPointF& point2,
BOOL isAngleScalable
);
GpStatus SetLinePoints(const GpPointF& point1, const GpPointF& point2);
GpStatus GetLinePoints(GpPointF* points);
VOID SetLineColors(const GpColor& color1, const GpColor& color2)
{
DeviceBrush.Colors[0] = color1;
DeviceBrush.Colors[1] = color2;
DeviceBrush.Colors[2] = color1;
DeviceBrush.Colors[3] = color2;
UpdateUid();
}
VOID GetLineColors(GpColor* colors)
{
colors[0] = DeviceBrush.Colors[0];
colors[1] = DeviceBrush.Colors[1];
}
// Get/set blend factors
//
// If the blendFactors.length = 1, then it's treated
// as the falloff parameter. Otherwise, it's the array
// of blend factors.
INT GetBlendCount()
{
return GetHorizontalBlendCount();
}
GpStatus GetBlend(REAL* blendFactors, REAL* blendPositions, INT count)
{
return GetHorizontalBlend(blendFactors, blendPositions, count);
}
GpStatus SetBlend(
const REAL* blendFactors,
const REAL* blendPositions,
INT count
)
{
return SetHorizontalBlend(blendFactors, blendPositions, count);
}
// Setting Vertical Blend factor is not allowed.
GpStatus SetVerticalBlend(
const REAL* blendFactors,
const REAL* blendPositions,
INT count
)
{
ASSERT(0);
return GenericError;
}
// Get/set preset blend-factors
INT GetPresetBlendCount();
GpStatus GetPresetBlend(
GpColor* blendColors,
REAL* blendPositions,
INT count);
GpStatus SetPresetBlend(
const GpColor* blendColors,
const REAL* blendPositions,
INT count);
virtual GpSpecialGradientType
GetSpecialGradientType(const GpMatrix* matrix) const
{
GpMatrix m;
GpMatrix::MultiplyMatrix(m, DeviceBrush.Xform, *matrix);
if (m.IsTranslateScale())
{
return GradientTypeVertical;
}
else if (REALABS(m.GetM11()) < CPLX_EPSILON &&
REALABS(m.GetM12()) >= CPLX_EPSILON &&
REALABS(m.GetM21()) >= CPLX_EPSILON &&
REALABS(m.GetM22()) < CPLX_EPSILON)
{
return GradientTypeHorizontal;
}
else
{
return GradientTypeDiagonal;
}
}
protected:
GpLineGradient(const GpLineGradient* brush);
GpStatus SetLineGradient(
const GpPointF& point1,
const GpPointF& point2,
const GpRectF& rect,
const GpColor& color1,
const GpColor& color2,
REAL angle,
BOOL isAngleScalable = FALSE,
GpWrapMode wrapMode = WrapModeTile
);
};
//--------------------------------------------------------------------------
// Represent radial gradient brush object
//--------------------------------------------------------------------------
#if 0
class GpRadialGradient : public GpGradientBrush
{
friend class DpOutputGradientSpan;
friend class DpOutputOneDGradientSpan;
public:
// Constructors
GpRadialGradient(VOID)
{
DefaultBrush();
}
GpRadialGradient(
const GpRectF& rect,
const GpColor& centerColor,
const GpColor& boundaryColor,
GpWrapMode wrapMode = WrapModeClamp
)
{
InitializeBrush(rect, centerColor, boundaryColor, wrapMode);
}
GpBrush* Clone() const
{
return new GpRadialGradient(this);
}
~GpRadialGradient()
{
GpFree(DeviceBrush.BlendFactors[0]);
GpFree(DeviceBrush.BlendPositions[0]);
GpFree(DeviceBrush.PresetColors);
}
virtual UINT GetDataSize() const;
virtual GpStatus GetData(IStream * stream) const;
virtual GpStatus SetData(const BYTE * dataBuffer, UINT size);
virtual GpStatus ColorAdjust(
GpRecolor * recolor,
ColorAdjustType type
);
// Get/set color attributes
VOID SetCenterColor(const GpColor& color)
{
DeviceBrush.Colors[0] = color;
UpdateUid();
}
VOID SetBoundaryColor(const GpColor& color)
{
DeviceBrush.Colors[1] = color;
UpdateUid();
}
GpColor GetCenterColor() const
{
return DeviceBrush.Colors[0];
}
GpColor GetBoundaryColor() const
{
return DeviceBrush.Colors[1];
}
VOID GetColors(GpColor* colors) const
{
colors[0] = DeviceBrush.Colors[0];
colors[1] = DeviceBrush.Colors[1];
}
INT GetNumberOfColors() const {return 2;}
BOOL UsesDefaultColorArray() const {return TRUE;}
// Get/set falloff / blend-factors
INT GetBlendCount()
{
return DeviceBrush.BlendCounts[0];
}
GpStatus GetBlend(
REAL* blendFactors,
REAL* blendPositions,
INT count) const;
GpStatus SetBlend(
const REAL* blendFactors,
const REAL* blendPosition,
INT count
);
// Get/set preset blend-factors
BOOL HasPresetColors() const
{
return DeviceBrush.UsesPresetColors;
}
INT GetPresetBlendCount() const;
GpStatus GetPresetBlend(
GpColor* blendColors,
REAL* blendPositions,
INT count) const;
GpStatus SetPresetBlend(
const GpColor* blendColors,
const REAL* blendPositions,
INT count);
// Check the opacity of this brush element.
virtual BOOL IsOpaque(BOOL ColorsOnly = FALSE) const
{
// This gradient brush is opaque only if
// all the colors are opaque and wrap mode is not WrapModeClamp.
// In case of WrapModeClamp mode, we need alpha channel to do
// clipping outside of the oval.
return (DeviceBrush.Colors[0].IsOpaque() &&
DeviceBrush.Colors[1].IsOpaque() &&
(ColorsOnly || DeviceBrush.Wrap != WrapModeClamp));
}
virtual BOOL IsSolid() const
{
//This may have to change if we change the defination of IsSolid.
//See comment at GpBrush::IsSolid() for more info.
return FALSE;
}
virtual BOOL IsNearConstant(BYTE* MinAlpha, BYTE* MaxAlpha) const
{
*MinAlpha = min(DeviceBrush.Colors[0].GetAlpha(),
DeviceBrush.Colors[1].GetAlpha());
*MaxAlpha = max(DeviceBrush.Colors[0].GetAlpha(),
DeviceBrush.Colors[1].GetAlpha());
return (*MaxAlpha - *MinAlpha < NEARCONSTANTALPHA);
}
virtual BOOL IsEqual(const GpBrush * brush) const;
virtual DpOutputSpan* CreateOutputSpan(
DpScanBuffer * scan,
DpContext *context,
const GpRect *drawBounds=NULL);
private:
GpRadialGradient(const GpRadialGradient *brush);
VOID
InitializeBrush(
const GpRectF& rect,
const GpColor& centerColor,
const GpColor& boundaryColor,
GpWrapMode wrapMode
)
{
DeviceBrush.Type = (BrushType)-1; //BrushRadialGrad;
DeviceBrush.Wrap = wrapMode;
DeviceBrush.Rect = rect;
DeviceBrush.UsesPresetColors = FALSE;
DeviceBrush.Colors[0] = centerColor;
DeviceBrush.Colors[1] = boundaryColor;
DeviceBrush.BlendFactors[0] = NULL;
DeviceBrush.BlendPositions[0] = NULL;
DeviceBrush.BlendCounts[0] = 1;
DeviceBrush.Falloffs[0] = 1;
DeviceBrush.PresetColors = NULL;
SetValid(WrapModeIsValid(wrapMode) && rect.Width > 0 && rect.Height > 0);
}
VOID DefaultBrush(VOID)
{
DeviceBrush.Type = (BrushType)-1; //BrushRadialGrad;
GpMemset(&DeviceBrush.Rect, 0, sizeof(DeviceBrush.Rect));
DeviceBrush.Wrap = WrapModeTile;
DeviceBrush.UsesPresetColors = FALSE;
GpColor color(255, 255, 255); // Opaque white
DeviceBrush.Colors[0] = color;
DeviceBrush.Colors[1] = color;
DeviceBrush.BlendFactors[0] = NULL;
DeviceBrush.BlendPositions[0] = NULL;
DeviceBrush.BlendCounts[0] = 1;
DeviceBrush.Falloffs[0] = 1;
DeviceBrush.PresetColors = NULL;
SetValid(FALSE);
}
};
#endif
//--------------------------------------------------------------------------
// Represent triangle gradient brush object
//--------------------------------------------------------------------------
#if 0
class GpTriangleGradient : public GpGradientBrush
{
friend class DpOutputTriangleGradientSpan;
public:
// Constructors
GpTriangleGradient(VOID)
{
DefaultBrush();
}
GpTriangleGradient(
const GpPointF* points,
const GpColor* colors,
GpWrapMode wrapMode = WrapModeClamp
)
{
InitializeBrush(
points,
colors,
wrapMode);
}
GpBrush* Clone() const
{
return new GpTriangleGradient(this);
}
~GpTriangleGradient()
{
GpFree(DeviceBrush.BlendFactors[0]);
GpFree(DeviceBrush.BlendFactors[1]);
GpFree(DeviceBrush.BlendFactors[2]);
GpFree(DeviceBrush.BlendPositions[0]);
GpFree(DeviceBrush.BlendPositions[1]);
GpFree(DeviceBrush.BlendPositions[2]);
}
virtual UINT GetDataSize() const;
virtual GpStatus GetData(IStream * stream) const;
virtual GpStatus SetData(const BYTE * dataBuffer, UINT size);
virtual GpStatus ColorAdjust(
GpRecolor * recolor,
ColorAdjustType type
);
// Get/set colors
VOID GetColors(GpColor* colors) const
{
colors[0] = DeviceBrush.Colors[0];
colors[1] = DeviceBrush.Colors[1];
colors[2] = DeviceBrush.Colors[2];
}
VOID SetColors(const GpColor* colors)
{
DeviceBrush.Colors[0] = colors[0];
DeviceBrush.Colors[1] = colors[1];
DeviceBrush.Colors[2] = colors[2];
UpdateUid();
}
// Get/set triangle
VOID GetTriangle(GpPointF* points) const
{
points[0] = DeviceBrush.Points[0];
points[1] = DeviceBrush.Points[1];
points[2] = DeviceBrush.Points[2];
}
VOID SetTriangle(const GpPointF* points)
{
DeviceBrush.Points[0] = points[0];
DeviceBrush.Points[1] = points[1];
DeviceBrush.Points[2] = points[2];
UpdateUid();
}
INT GetNumberOfColors() const {return 3;}
BOOL UsesDefaultColorArray() const {return TRUE;}
// Get/set falloff / blend-factors
INT GetBlendCount0() const
{
return DeviceBrush.BlendCounts[0];
}
INT GetBlendCount1() const
{
return DeviceBrush.BlendCounts[1];
}
INT GetBlendCount2() const
{
return DeviceBrush.BlendCounts[2];
}
//!!! bhouse We really don't need all of these GetBlendX methods. We
// should just implement a single GetBlend() which takes an index.
// With the change to the data layout, the argument for this method
// is stronger. This should remove a bunch of redundant code.
GpStatus GetBlend0(
REAL* blendFactors,
REAL* blendPositions,
INT count) const;
GpStatus SetBlend0(
const REAL* blendFactors,
const REAL* blendPositions,
INT count);
GpStatus GetBlend1(
REAL* blendFactors,
REAL* blendPositions,
INT count) const;
GpStatus SetBlend1(
const REAL* blendFactors,
const REAL* blendPositions,
INT count);
GpStatus GetBlend2(
REAL* blendFactors,
REAL* blendPositions,
INT count) const;
GpStatus SetBlend2(
const REAL* blendFactors,
const REAL* blendPositions,
INT count);
// Check the opacity of this brush element.
virtual BOOL IsOpaque(BOOL ColorsOnly = FALSE) const
{
// This gradient brush is opaque only if
// all the colors are opaque.
// In case of WrapModeClamp mode, we need alpha channel to do
// clipping outside of the triangle.
return (DeviceBrush.Colors[0].IsOpaque() &&
DeviceBrush.Colors[1].IsOpaque() &&
DeviceBrush.Colors[2].IsOpaque() &&
(ColorsOnly || DeviceBrush.Wrap != WrapModeClamp));
}
virtual BOOL IsSolid() const
{
//This may have to change if we change the defination of IsSolid.
//See comment at GpBrush::IsSolid() for more info.
return FALSE;
}
virtual BOOL IsNearConstant(BYTE* MinAlpha, BYTE* MaxAlpha) const
{
*MinAlpha = min(DeviceBrush.Colors[0].GetAlpha(),
DeviceBrush.Colors[1].GetAlpha());
*MinAlpha = min(*MinAlpha,
DeviceBrush.Colors[2].GetAlpha());
*MaxAlpha = max(DeviceBrush.Colors[0].GetAlpha(),
DeviceBrush.Colors[1].GetAlpha());
*MaxAlpha = min(*MaxAlpha,
DeviceBrush.Colors[2].GetAlpha());
return (*MaxAlpha - *MinAlpha < NEARCONSTANTALPHA);
}
virtual BOOL IsEqual(const GpBrush * brush) const;
virtual DpOutputSpan* CreateOutputSpan(
DpScanBuffer * scan,
DpContext *context,
const pRect *drawBounds=NULL);
protected: // GDI+ Internal
GpTriangleGradient(const GpTriangleGradient* brush);
VOID
InitializeBrush(
const GpPointF* points,
const GpColor* colors,
GpWrapMode wrapMode
)
{
DeviceBrush.Type = (BrushType)-1; //BrushTriangleGrad;
DeviceBrush.Wrap = wrapMode;
// Set the blending and fall off factors.
DeviceBrush.Falloffs[0] = 1;
DeviceBrush.Falloffs[1] = 1;
DeviceBrush.Falloffs[2] = 1;
DeviceBrush.BlendCounts[0] = 1;
DeviceBrush.BlendCounts[1] = 1;
DeviceBrush.BlendCounts[2] = 1;
DeviceBrush.BlendFactors[0] = NULL;
DeviceBrush.BlendFactors[1] = NULL;
DeviceBrush.BlendFactors[2] = NULL;
DeviceBrush.BlendPositions[0] = NULL;
DeviceBrush.BlendPositions[1] = NULL;
DeviceBrush.BlendPositions[2] = NULL;
GpMemcpy(&DeviceBrush.Points[0],
points,
3*sizeof(GpPointF));
GpMemcpy(&DeviceBrush.Colors[0],
colors,
3*sizeof(GpColor));
// Get the boundary rectangle.
REAL xmin, xmax, ymin, ymax;
xmin = min(DeviceBrush.Points[0].X,
DeviceBrush.Points[1].X);
xmax = max(DeviceBrush.Points[0].X,
DeviceBrush.Points[1].X);
ymin = min(DeviceBrush.Points[0].Y,
DeviceBrush.Points[1].Y);
ymax = max(DeviceBrush.Points[0].Y,
DeviceBrush.Points[1].Y);
xmin = min(xmin, DeviceBrush.Points[2].X);
xmax = max(xmax, DeviceBrush.Points[2].X);
ymin = min(ymin, DeviceBrush.Points[2].Y);
ymax = max(ymax, DeviceBrush.Points[2].Y);
DeviceBrush.Rect.X = xmin;
DeviceBrush.Rect.Width = xmax - xmin;
DeviceBrush.Rect.Y = ymin;
DeviceBrush.Rect.Height = ymax - ymin;
if(!WrapModeIsValid(wrapMode) ||
DeviceBrush.Rect.Width <= 0 ||
DeviceBrush.Rect.Height <= 0)
{
SetValid(FALSE);
return;
}
SetValid(TRUE);
}
VOID DefaultBrush()
{
DeviceBrush.Type = (BrushType)-1; //BrushTriangleGrad;
GpMemset(&DeviceBrush.Points, 0, 3*sizeof(GpPointF));
DeviceBrush.Wrap = WrapModeClamp;
GpColor color(255, 255, 255); // Opaque white
DeviceBrush.Colors[0] = color;
DeviceBrush.Colors[1] = color;
DeviceBrush.Colors[2] = color;
GpMemset(&DeviceBrush.Rect, 0, sizeof(DeviceBrush.Rect));
DeviceBrush.Falloffs[0] = 1;
DeviceBrush.Falloffs[1] = 1;
DeviceBrush.Falloffs[2] = 1;
DeviceBrush.BlendCounts[0] = 1;
DeviceBrush.BlendCounts[1] = 1;
DeviceBrush.BlendCounts[2] = 1;
DeviceBrush.BlendFactors[0] = NULL;
DeviceBrush.BlendFactors[1] = NULL;
DeviceBrush.BlendFactors[2] = NULL;
DeviceBrush.BlendPositions[0] = NULL;
DeviceBrush.BlendPositions[1] = NULL;
DeviceBrush.BlendPositions[2] = NULL;
SetValid(FALSE);
}
};
#endif
//--------------------------------------------------------------------------
// Represent polygon gradient brush object
//--------------------------------------------------------------------------
class GpPathGradient : public GpGradientBrush
{
friend class DpOutputPathGradientSpan;
friend class DpOutputOneDPathGradientSpan;
public:
// Constructors
GpPathGradient()
{
DefaultBrush();
}
GpPathGradient(
const GpPointF* points,
INT count,
GpWrapMode wrapMode = WrapModeClamp
)
{
InitializeBrush(
points,
count,
wrapMode);
}
GpPathGradient(
const GpPath* path,
GpWrapMode wrapMode = WrapModeClamp
)
{
DefaultBrush();
DeviceBrush.Wrap = wrapMode;
if(path)
{
DeviceBrush.Path = new GpPath((GpPath*) path);
PrepareBrush();
}
else
DeviceBrush.Path = NULL;
}
BOOL IsRectangle() const;
GpBrush* Clone() const
{
return new GpPathGradient(this);
}
~GpPathGradient()
{
if(DeviceBrush.Path)
delete DeviceBrush.Path;
else
GpFree(DeviceBrush.PointsPtr);
GpFree(DeviceBrush.ColorsPtr);
GpFree(DeviceBrush.BlendFactors[0]);
GpFree(DeviceBrush.BlendPositions[0]);
GpFree(DeviceBrush.PresetColors);
if(MorphedBrush)
delete MorphedBrush;
}
virtual UINT GetDataSize() const;
virtual GpStatus GetData(IStream * stream) const;
virtual GpStatus SetData(const BYTE * dataBuffer, UINT size);
virtual GpStatus ColorAdjust(
GpRecolor * recolor,
ColorAdjustType type
);
virtual GpStatus BlendWithWhite();
// Get/set colors
VOID GetCenterColor(GpColor* color) const
{
if(color)
*color = DeviceBrush.Colors[0];
}
VOID SetCenterColor(const GpColor& color)
{
DeviceBrush.Colors[0] = color;
UpdateUid();
}
GpStatus GetSurroundColor(GpColor* color, INT index) const
{
if(color && index >= 0 && index < DeviceBrush.Count)
{
if(DeviceBrush.OneSurroundColor)
*color = DeviceBrush.ColorsPtr[0];
else
*color = DeviceBrush.ColorsPtr[index];
return Ok;
}
else
return InvalidParameter;
}
GpStatus SetSurroundColor(GpColor& color, INT index);
GpStatus SetSurroundColors(const GpColor* colors);
GpStatus GetSurroundColors(GpColor* colors) const
{
GpStatus status = InvalidParameter;
if(IsValid() && colors) {
GpMemcpy(colors,
DeviceBrush.ColorsPtr,
DeviceBrush.Count*sizeof(GpColor));
status = Ok;
}
return status;
}
// Get/set polygon
GpStatus GetPolygon(GpPointF* points)
{
GpStatus status = InvalidParameter;
ASSERT(DeviceBrush.Count > 0);
if(IsValid() && points && DeviceBrush.Count > 0)
{
GpMemcpy(points,
DeviceBrush.PointsPtr,
DeviceBrush.Count*sizeof(GpPointF));
status = Ok;
}
return status;
}
GpStatus SetPolygon(const GpPointF* points)
{
GpStatus status = InvalidParameter;
ASSERT(DeviceBrush.Count > 0);
if(IsValid() && points && DeviceBrush.Count > 0)
{
GpMemcpy(DeviceBrush.PointsPtr,
points,
DeviceBrush.Count*sizeof(GpPointF));
UpdateUid();
status = Ok;
}
return status;
}
GpStatus GetPoint(GpPointF* point, INT index) const
{
if(point && index >= 0 && index < DeviceBrush.Count)
{
*point = DeviceBrush.PointsPtr[index];
return Ok;
}
else
return GenericError;
}
GpStatus SetPoint(GpPointF& point, INT index)
{
if(index >= 0 && index < DeviceBrush.Count)
{
DeviceBrush.PointsPtr[index] = point;
UpdateUid();
return Ok;
}
else
return InvalidParameter;
}
GpStatus GetCenterPoint(GpPointF* point) const
{
if(point)
{
*point = DeviceBrush.Points[0];
return Ok;
}
else
return InvalidParameter;
}
GpStatus SetCenterPoint(const GpPointF& point)
{
DeviceBrush.Points[0] = point;
UpdateUid();
return Ok;
}
GpStatus GetInflationFactor(REAL* inflation) const
{
if (inflation)
{
*inflation = InflationFactor;
return Ok;
}
else
{
return InvalidParameter;
}
}
GpStatus SetInflationFactor(REAL inflation)
{
InflationFactor = inflation;
UpdateUid();
return Ok;
}
GpStatus GetFocusScales(REAL* xScale, REAL* yScale)
{
if(xScale && yScale)
{
*xScale = DeviceBrush.FocusScaleX;
*yScale = DeviceBrush.FocusScaleY;
return Ok;
}
else
return InvalidParameter;
}
GpStatus SetFocusScales(REAL xScale, REAL yScale)
{
DeviceBrush.FocusScaleX = xScale;
DeviceBrush.FocusScaleY = yScale;
UpdateUid();
return Ok;
}
// Number of Surround Points and Colors.
INT GetNumberOfPoints() const {return DeviceBrush.Count;}
INT GetNumberOfColors() const {return DeviceBrush.Count;}
BOOL UsesDefaultColorArray() const {return FALSE;} // Don't use
// the default array.
VOID GetColors(GpColor* colors) const // Implement a vurtual function.
{
GetSurroundColors(colors);
}
// Get/set falloff / blend-factors
BOOL HasPresetColors() const
{
return DeviceBrush.UsesPresetColors;
}
INT GetBlendCount() const
{
return DeviceBrush.BlendCounts[0];
}
GpStatus GetBlend(REAL* blendFactors, REAL* blendPositions, INT count) const;
GpStatus SetBlend(const REAL* blendFactors,
const REAL* blendPositions, INT count);
// Get/set preset blend-factors
INT GetPresetBlendCount() const;
GpStatus GetPresetBlend(
GpColor* blendColors,
REAL* blendPositions,
INT count) const;
GpStatus SetPresetBlend(
const GpColor* blendColors,
const REAL* blendPositions,
INT count);
// Check if the Path Gradient is rectangular.
BOOL IsRectangular() const
{
const GpPointF *points;
INT count;
if (DeviceBrush.Path != NULL)
{
return DeviceBrush.Path->IsRectangular();
}
else
{
count = DeviceBrush.Count;
points = DeviceBrush.PointsPtr;
}
if (count > 0 && points != NULL)
{
for (INT i=0; i<count; i++)
{
INT j = (i+1) % count;
if (REALABS(points[i].X-points[j].X) > REAL_EPSILON &&
REALABS(points[i].Y-points[j].Y) > REAL_EPSILON)
{
// Points are not at 90 degree angles, not rectangular.
return FALSE;
}
}
return TRUE;
}
return FALSE;
}
// Check the opacity of this brush element.
virtual BOOL IsOpaque(BOOL ColorsOnly = FALSE) const
{
// This gradient brush is opaque only if
// all the colors are opaque (including the center color
// which is DeviceBrush.Colors[0]).
// In case of WrapModeClamp mode, we need alpha channel to do
// clipping outside of the polygon.
BOOL test;
if(ColorsOnly || DeviceBrush.Wrap != WrapModeClamp)
{
test = (ColorsOnly || IsRectangle()) &&
DeviceBrush.Colors[0].IsOpaque();
INT i = 0;
INT count = DeviceBrush.UsesPresetColors ? DeviceBrush.BlendCounts[0] : DeviceBrush.Count;
while(i < count && test)
{
if (DeviceBrush.UsesPresetColors)
{
test = (DeviceBrush.PresetColors[i] & Color::AlphaMask) ==
Color::AlphaMask;
}
else
{
test = DeviceBrush.ColorsPtr[i].IsOpaque();
}
i++;
}
}
else
test = FALSE;
return test;
}
virtual GpSpecialGradientType
GetSpecialGradientType(const GpMatrix* matrix) const
{
if (DeviceBrush.UsesPresetColors)
{
ARGB color1 = DeviceBrush.Colors[0].GetValue(); // Center color
ARGB color2 = DeviceBrush.PresetColors[0]; // 1st Preset Color
for (INT i=1; i<DeviceBrush.BlendCounts[0]; i++)
{
ARGB color = DeviceBrush.PresetColors[i];
if ((color1 != color) && (color2 != color))
{
if (color1 == color2)
{
color2 = color;
}
else
{
return GradientTypePathComplex;
}
}
}
}
else
{
if (DeviceBrush.OneSurroundColor || DeviceBrush.Count <= 2)
{
return GradientTypePathTwoStep;
}
GpColor *color1 = &(DeviceBrush.ColorsPtr[0]);
GpColor *color2 = &(DeviceBrush.ColorsPtr[1]);
for (INT i=2; i<DeviceBrush.Count; i++)
{
GpColor *color = &(DeviceBrush.ColorsPtr[i]);
if (!color1->IsEqual(*color) && !color2->IsEqual(*color))
{
if (color1->IsEqual(*color2))
{
color2 = color;
}
else
{
return GradientTypePathComplex;
}
}
}
}
return GradientTypePathTwoStep;
}
virtual BOOL IsSolid() const
{
//This is not optimal but is such a rare case that it probably
//shouldn't be fixed as long as we keep the defination of IsSolid
//that we are currently using. See comment at GpBrush::IsSolid for
//definition.
return FALSE;
}
virtual BOOL IsNearConstant(BYTE* MinAlpha, BYTE* MaxAlpha) const
{
if (HasPresetColors())
{
*MaxAlpha = DeviceBrush.Colors[0].GetAlpha();
*MinAlpha = *MaxAlpha;
for (INT i=0; i<DeviceBrush.BlendCounts[0]; i++)
{
*MaxAlpha = max(*MaxAlpha, GpColor(DeviceBrush.PresetColors[i]).GetAlpha());
*MinAlpha = min(*MinAlpha, GpColor(DeviceBrush.PresetColors[i]).GetAlpha());
}
}
else
{
if (DeviceBrush.OneSurroundColor)
{
*MaxAlpha = max((DeviceBrush.ColorsPtr[0]).GetAlpha(), // surround
(DeviceBrush.Colors[0]).GetAlpha()); // center
*MinAlpha = min((DeviceBrush.ColorsPtr[0]).GetAlpha(), // surround
(DeviceBrush.Colors[0]).GetAlpha()); // center }
}
else
{
*MaxAlpha = DeviceBrush.Colors[0].GetAlpha();
*MinAlpha = *MaxAlpha;
for (INT i=0; i<DeviceBrush.Count; i++)
{
*MaxAlpha = max(*MaxAlpha, DeviceBrush.ColorsPtr[i].GetAlpha());
*MinAlpha = min(*MinAlpha, DeviceBrush.ColorsPtr[i].GetAlpha());
}
}
}
return (*MaxAlpha - *MinAlpha < NEARCONSTANTALPHA);
}
virtual BOOL IsEqual(const GpBrush * brush) const;
virtual DpOutputSpan* CreateOutputSpan(
DpScanBuffer * scan,
DpContext *context,
const GpRect *drawBounds=NULL);
protected: // GDI+ Internal
GpPathGradient(const GpPathGradient* brush);
VOID
PrepareBrush();
VOID
InitializeBrush(
const GpPointF* points,
INT count,
GpWrapMode wrapMode = WrapModeClamp
)
{
DeviceBrush.Type = BrushTypePathGradient;
DeviceBrush.Wrap = wrapMode;
SetValid(FALSE);
DeviceBrush.OneSurroundColor = TRUE;
DeviceBrush.UsesPresetColors = FALSE;
MorphedBrush = NULL;
DeviceBrush.Path = NULL;
DeviceBrush.PointsPtr = NULL;
DeviceBrush.ColorsPtr = NULL;
// Set the blending and fall off factors.
DeviceBrush.Falloffs[0] = 1;
DeviceBrush.BlendCounts[0] = 1;
DeviceBrush.BlendFactors[0] = NULL;
DeviceBrush.BlendPositions[0] = NULL;
DeviceBrush.PresetColors = NULL;
if(!WrapModeIsValid(wrapMode) || count <= 0 || points == NULL)
{
DeviceBrush.Count = 0;
return;
}
DeviceBrush.Count = count;
// Get the boundary rectangle.
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(DeviceBrush.Rect.Width <= 0 ||
DeviceBrush.Rect.Height <= 0)
return;
// The default center point is the center of gravity.
DeviceBrush.Points[0].X = x0 / DeviceBrush.Count;
DeviceBrush.Points[0].Y = y0 / DeviceBrush.Count;
DeviceBrush.PointsPtr =
(GpPointF*) GpMalloc(DeviceBrush.Count *
sizeof(GpPointF));
if(!DeviceBrush.PointsPtr)
{
DeviceBrush.Count = 0;
return;
}
DeviceBrush.ColorsPtr =
(GpColor*) GpMalloc(DeviceBrush.Count *
sizeof(GpColor));
if(!DeviceBrush.ColorsPtr)
{
GpFree(DeviceBrush.PointsPtr);
DeviceBrush.PointsPtr = NULL;
DeviceBrush.Count = 0;
return;
}
// If this comes so far, both Points and Colors are valid.
GpMemcpy(&DeviceBrush.PointsPtr[0],
points,
DeviceBrush.Count*sizeof(GpPointF));
GpMemset(&DeviceBrush.ColorsPtr[0],
255,
DeviceBrush.Count*sizeof(GpColor));
DeviceBrush.FocusScaleX = 0;
DeviceBrush.FocusScaleY = 0;
InflationFactor = 0.0f;
SetValid(TRUE);
}
VOID DefaultBrush(VOID)
{
DeviceBrush.Type = BrushTypePathGradient;
SetValid(FALSE);
DeviceBrush.OneSurroundColor = TRUE;
DeviceBrush.Wrap = WrapModeClamp;
DeviceBrush.UsesPresetColors = FALSE;
DeviceBrush.Path = NULL;
DeviceBrush.PointsPtr = NULL;
DeviceBrush.ColorsPtr = 0;
DeviceBrush.Count = 0;
// The default center point is the center of gravity.
GpMemset(&DeviceBrush.Rect, 0, sizeof(GpRectF));
GpMemset(&DeviceBrush.Points, 0, sizeof(GpPointF));
GpMemset(&DeviceBrush.Colors, 255, sizeof(GpColor));
DeviceBrush.FocusScaleX = 0;
DeviceBrush.FocusScaleY = 0;
// Set the blending and fall off factors.
DeviceBrush.Falloffs[0] = 1;
DeviceBrush.BlendCounts[0] = 1;
DeviceBrush.BlendFactors[0] = NULL;
DeviceBrush.BlendPositions[0] = NULL;
DeviceBrush.PresetColors = NULL;
MorphedBrush = NULL;
InflationFactor = 0.0f;
}
// This does not update the Uid of the object because it's defined as const
// But the object doesn't really change anyway
GpStatus Flatten(GpMatrix* matrix) const;
virtual
const DpPath *
GetOutlinePath(
VOID
) const
{
return DeviceBrush.Path;
}
protected:
GpBrush* MorphedBrush;
DynByteArray FlattenTypes;
DynPointFArray FlattenPoints;
REAL InflationFactor;
};
//--------------------------------------------------------------------------
// Represent hatch brush object
//--------------------------------------------------------------------------
class GpHatch : public GpBrush
{
friend class DpOutputHatchSpan;
public:
// Constructors
GpHatch(VOID)
{
DefaultBrush();
}
GpHatch(GpHatchStyle hatchStyle, const GpColor& foreColor)
{
InitializeBrush(hatchStyle, foreColor, 0);
}
GpHatch(
GpHatchStyle hatchStyle,
const GpColor& foreColor,
const GpColor& backColor)
{
InitializeBrush(hatchStyle, foreColor, backColor);
}
GpBrush* Clone() const
{
return new GpHatch(this);
}
~GpHatch() {}
virtual UINT GetDataSize() const;
virtual GpStatus GetData(IStream * stream) const;
virtual GpStatus SetData(const BYTE * dataBuffer, UINT size);
virtual GpStatus ColorAdjust(
GpRecolor * recolor,
ColorAdjustType type
);
virtual BOOL IsOpaque(BOOL ColorsOnly = FALSE) const
{
// This brush is opaque only if
// all the colors are opaque.
return (DeviceBrush.Colors[0].IsOpaque() &&
DeviceBrush.Colors[1].IsOpaque());
}
virtual BOOL IsSolid() const
{
//This may have to change if we change the defination of IsSolid.
//See comment at GpBrush::IsSolid() for more info.
return FALSE;
}
virtual BOOL IsNearConstant(BYTE* MinAlpha, BYTE* MaxAlpha) const
{
*MinAlpha = min(DeviceBrush.Colors[0].GetAlpha(),
DeviceBrush.Colors[1].GetAlpha());
*MaxAlpha = max(DeviceBrush.Colors[0].GetAlpha(),
DeviceBrush.Colors[1].GetAlpha());
return (*MaxAlpha - *MinAlpha < NEARCONSTANTALPHA);
}
virtual BOOL IsEqual(const GpBrush * brush) const;
virtual DpOutputSpan* CreateOutputSpan(
DpScanBuffer * scan,
DpContext *context,
const GpRect *drawBounds=NULL);
virtual GpSpecialGradientType
GetSpecialGradientType(const GpMatrix* matrix) const
{
return GradientTypeNotSpecial;
}
GpHatchStyle GetHatchStyle()
{
return DeviceBrush.Style;
}
GpStatus GetForegroundColor(GpColor* color)
{
ASSERT(color != NULL);
*color = DeviceBrush.Colors[0];
return Ok;
}
GpStatus GetBackgroundColor(GpColor* color)
{
ASSERT(color != NULL);
*color = DeviceBrush.Colors[1];
return Ok;
}
VOID SetStretchFactor(INT stretch)
{
StretchFactor = stretch;
}
private:
GpHatch(const GpHatch* brush);
VOID
InitializeBrush(
GpHatchStyle hatchStyle,
const GpColor& foreColor,
const GpColor& backColor
)
{
DeviceBrush.Type = BrushTypeHatchFill;
DeviceBrush.Style = hatchStyle;
DeviceBrush.Colors[0] = foreColor;
DeviceBrush.Colors[1] = backColor;
StretchFactor = 1;
InitializeData();
SetValid(TRUE);
}
VOID DefaultBrush()
{
InitializeBrush(HatchStyle50Percent,
GpColor(Color::Black),
GpColor(Color::White));
}
VOID
InitializeData();
INT StretchFactor;
};
#endif _BRUSH_HPP