You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2447 lines
64 KiB
2447 lines
64 KiB
/**************************************************************************\
|
|
*
|
|
* 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
|