/**************************************************************************\ * * 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 #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(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(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= 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 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; iIsEqual(*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