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.
653 lines
14 KiB
653 lines
14 KiB
/**************************************************************************\
|
|
*
|
|
* Copyright (c) 1998 Microsoft Corporation
|
|
*
|
|
* Module Name:
|
|
*
|
|
* BaseTypes.hpp
|
|
*
|
|
* Abstract:
|
|
*
|
|
* Basic types used by GDI+ implementation
|
|
*
|
|
* Revision History:
|
|
*
|
|
* 12/01/1998 davidx
|
|
* Created it.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
#ifndef _BASETYPES_HPP
|
|
#define _BASETYPES_HPP
|
|
|
|
#ifdef _X86_
|
|
#define FASTCALL _fastcall
|
|
#else
|
|
#define FASTCALL
|
|
#endif
|
|
|
|
//
|
|
// TODO: Remove the 'Gp' prefix from all these classes
|
|
// TODO: What is a GlyphPos? Why is it a base type?
|
|
//
|
|
|
|
namespace GpRuntime
|
|
{
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Forward declarations of various internal classes
|
|
//--------------------------------------------------------------------------
|
|
|
|
typedef double REALD;
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Represents a dimension in a 2D coordinate system
|
|
// (integer coordinates)
|
|
//--------------------------------------------------------------------------
|
|
|
|
class GpSize
|
|
{
|
|
public:
|
|
|
|
// Default constructor
|
|
|
|
GpSize()
|
|
{
|
|
// NOTE: Size is uninitialized by default.
|
|
// Specicifically, it's not initialized to 0,0.
|
|
}
|
|
|
|
// Construct a Size object using the specified
|
|
// x- and y- dimensions.
|
|
|
|
GpSize(INT width, INT height)
|
|
{
|
|
Width = width;
|
|
Height = height;
|
|
}
|
|
|
|
public:
|
|
|
|
// The fields are public here.
|
|
|
|
INT Width;
|
|
INT Height;
|
|
};
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Represents a location in a 2D coordinate system
|
|
// (integer coordinates)
|
|
//--------------------------------------------------------------------------
|
|
|
|
class GpPoint
|
|
{
|
|
public:
|
|
|
|
// Default constructor
|
|
|
|
GpPoint()
|
|
{
|
|
}
|
|
|
|
// Construct a Point object using the specified
|
|
// x- and y- coordinates.
|
|
|
|
GpPoint(INT x, INT y)
|
|
{
|
|
X = x;
|
|
Y = y;
|
|
}
|
|
|
|
public:
|
|
|
|
INT X;
|
|
INT Y;
|
|
};
|
|
|
|
class GpPointD
|
|
{
|
|
public:
|
|
|
|
// Default constructor
|
|
|
|
GpPointD()
|
|
{
|
|
}
|
|
|
|
// Construct a Point object using the specified
|
|
// x- and y- coordinates.
|
|
|
|
GpPointD(REALD x, REALD y)
|
|
{
|
|
X = x;
|
|
Y = y;
|
|
}
|
|
|
|
public:
|
|
|
|
REALD X;
|
|
REALD Y;
|
|
};
|
|
|
|
class GpPoint3F
|
|
{
|
|
public:
|
|
|
|
// Default constructor
|
|
|
|
GpPoint3F()
|
|
{
|
|
}
|
|
|
|
// Construct a Point object using the specified
|
|
// x- and y- coordinates.
|
|
|
|
GpPoint3F(REAL x, REAL y, REAL z)
|
|
{
|
|
X = x;
|
|
Y = y;
|
|
Z = z;
|
|
}
|
|
|
|
public:
|
|
|
|
REAL X;
|
|
REAL Y;
|
|
REAL Z;
|
|
};
|
|
|
|
class GpPoint3D
|
|
{
|
|
public:
|
|
|
|
// Default constructor
|
|
|
|
GpPoint3D()
|
|
{
|
|
}
|
|
|
|
// Construct a Point object using the specified
|
|
// x- and y- coordinates.
|
|
|
|
GpPoint3D(REALD x, REALD y, REALD z)
|
|
{
|
|
X = x;
|
|
Y = y;
|
|
Z = z;
|
|
}
|
|
|
|
public:
|
|
|
|
REALD X;
|
|
REALD Y;
|
|
REALD Z;
|
|
};
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Represents a rectangle in a 2D coordinate system
|
|
// (integer coordinates)
|
|
//--------------------------------------------------------------------------
|
|
|
|
class GpRect
|
|
{
|
|
public:
|
|
|
|
// Default constructor
|
|
|
|
GpRect()
|
|
{
|
|
}
|
|
|
|
// Construct a Rect object using the specified
|
|
// location and size.
|
|
|
|
GpRect(INT x, INT y, INT width, INT height)
|
|
{
|
|
X = x;
|
|
Y = y;
|
|
Width = width;
|
|
Height = height;
|
|
}
|
|
|
|
GpRect(const GpPoint& location, const GpSize& size)
|
|
{
|
|
X = location.X;
|
|
Y = location.Y;
|
|
Width = size.Width;
|
|
Height = size.Height;
|
|
}
|
|
|
|
// Determine if the rectangle is empty
|
|
|
|
BOOL IsEmpty() const
|
|
{
|
|
return (Width <= 0) || (Height <= 0);
|
|
}
|
|
|
|
// Return the left, top, right, and bottom
|
|
// coordinates of the rectangle
|
|
|
|
INT GetLeft() const
|
|
{
|
|
return X;
|
|
}
|
|
|
|
INT GetTop() const
|
|
{
|
|
return Y;
|
|
}
|
|
|
|
INT GetRight() const
|
|
{
|
|
return X+Width;
|
|
}
|
|
|
|
INT GetBottom() const
|
|
{
|
|
return Y+Height;
|
|
}
|
|
|
|
// Determine if the specified rect intersects with the
|
|
// current rect object.
|
|
|
|
BOOL IntersectsWith(const GpRect& rect)
|
|
{
|
|
return (GetLeft() < rect.GetRight() &&
|
|
GetTop() < rect.GetBottom() &&
|
|
GetRight() > rect.GetLeft() &&
|
|
GetBottom() > rect.GetTop());
|
|
}
|
|
|
|
// Intersect the current rect with the specified object
|
|
|
|
BOOL Intersect(const GpRect& rect)
|
|
{
|
|
return IntersectRect(*this, *this, rect);
|
|
}
|
|
|
|
// Intersect rect a and b and save the result into c
|
|
// Notice that c may be the same object as a or b.
|
|
// !!! Consider moving out-of-line
|
|
|
|
static BOOL IntersectRect(GpRect& c, const GpRect& a, const GpRect& b)
|
|
{
|
|
INT right = min(a.GetRight(), b.GetRight());
|
|
INT bottom = min(a.GetBottom(), b.GetBottom());
|
|
INT left = max(a.GetLeft(), b.GetLeft());
|
|
INT top = max(a.GetTop(), b.GetTop());
|
|
|
|
c.X = left;
|
|
c.Y = top;
|
|
c.Width = right - left;
|
|
c.Height = bottom - top;
|
|
return !c.IsEmpty();
|
|
}
|
|
|
|
public:
|
|
|
|
INT X;
|
|
INT Y;
|
|
INT Width;
|
|
INT Height;
|
|
};
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Represents a 32-bit ARGB color in AARRGGBB format
|
|
//--------------------------------------------------------------------------
|
|
|
|
class GpColor
|
|
{
|
|
public:
|
|
|
|
GpColor()
|
|
{
|
|
Argb = Color::Black;
|
|
}
|
|
|
|
GpColor(BYTE r, BYTE g, BYTE b)
|
|
{
|
|
Argb = MakeARGB(255, r, g, b);
|
|
}
|
|
|
|
GpColor(BYTE a, BYTE r, BYTE g, BYTE b)
|
|
{
|
|
Argb = MakeARGB(a, r, g, b);
|
|
}
|
|
|
|
GpColor(ARGB argb)
|
|
{
|
|
Argb = argb;
|
|
}
|
|
|
|
// Retrieve ARGB values
|
|
|
|
ARGB GetValue() const
|
|
{
|
|
return Argb;
|
|
}
|
|
|
|
VOID SetValue(IN ARGB argb)
|
|
{
|
|
Argb = argb;
|
|
}
|
|
|
|
// Extract A, R, G, B components
|
|
|
|
BYTE GetAlpha() const
|
|
{
|
|
return (BYTE) (Argb >> AlphaShift);
|
|
}
|
|
|
|
BYTE GetRed() const
|
|
{
|
|
return (BYTE) (Argb >> RedShift);
|
|
}
|
|
|
|
BYTE GetGreen() const
|
|
{
|
|
return (BYTE) (Argb >> GreenShift);
|
|
}
|
|
|
|
BYTE GetBlue() const
|
|
{
|
|
return (BYTE) (Argb >> BlueShift);
|
|
}
|
|
|
|
// Return premultiplied ARGB values
|
|
|
|
ARGB GetPremultipliedValue() const
|
|
{
|
|
return ConvertToPremultiplied(Argb);
|
|
}
|
|
|
|
// Determine if the color is completely opaque
|
|
|
|
BOOL IsOpaque() const
|
|
{
|
|
return (Argb & AlphaMask) == AlphaMask;
|
|
}
|
|
|
|
// Determine if the two colors are the same
|
|
|
|
BOOL IsEqual(const GpColor & color) const
|
|
{
|
|
return (Argb == color.Argb);
|
|
}
|
|
|
|
|
|
VOID SetColor(ARGB argb)
|
|
{
|
|
this->Argb = argb;
|
|
}
|
|
|
|
COLORREF ToCOLORREF() const
|
|
{
|
|
return RGB(GetRed(), GetGreen(), GetBlue());
|
|
}
|
|
|
|
VOID BlendOpaqueWithWhite()
|
|
{
|
|
UINT32 alpha = this->GetAlpha();
|
|
if (alpha == 0)
|
|
{
|
|
this->Argb = 0xFFFFFFFF;
|
|
}
|
|
else if (alpha != 255)
|
|
{
|
|
UINT32 multA = 255 - alpha;
|
|
|
|
UINT32 D1_000000FF = 0xFF;
|
|
UINT32 D2_0000FFFF = D1_000000FF * multA + 0x00000080;
|
|
UINT32 D3_000000FF = (D2_0000FFFF & 0x0000FF00) >> 8;
|
|
UINT32 D4_0000FF00 = (D2_0000FFFF + D3_000000FF) & 0x0000FF00;
|
|
|
|
UINT32 alphaContrib = D4_0000FF00 >> 8 |
|
|
D4_0000FF00 << 8 |
|
|
D4_0000FF00;
|
|
|
|
this->Argb = 0xFF000000 | (this->Argb + alphaContrib);
|
|
}
|
|
}
|
|
|
|
// Shift count and bit mask for A, R, G, B components
|
|
enum
|
|
{
|
|
AlphaShift = 24,
|
|
RedShift = 16,
|
|
GreenShift = 8,
|
|
BlueShift = 0
|
|
};
|
|
|
|
enum
|
|
{
|
|
AlphaMask = 0xff000000,
|
|
RedMask = 0x00ff0000,
|
|
GreenMask = 0x0000ff00,
|
|
BlueMask = 0x000000ff
|
|
};
|
|
|
|
// Assemble A, R, G, B values into a 32-bit integer
|
|
static ARGB MakeARGB(IN BYTE a,
|
|
IN BYTE r,
|
|
IN BYTE g,
|
|
IN BYTE b)
|
|
{
|
|
return (((ARGB) (b) << BlueShift) |
|
|
((ARGB) (g) << GreenShift) |
|
|
((ARGB) (r) << RedShift) |
|
|
((ARGB) (a) << AlphaShift));
|
|
}
|
|
|
|
// Convert an ARGB value to premultiplied form
|
|
|
|
static ARGB ConvertToPremultiplied(ARGB argb)
|
|
{
|
|
UINT alpha = (argb & AlphaMask) >> AlphaShift;
|
|
|
|
if (alpha == 0xff)
|
|
{
|
|
// fully opaque - don't need to do anything
|
|
}
|
|
else if (alpha == 0)
|
|
{
|
|
// fully transparent
|
|
|
|
argb = 0;
|
|
}
|
|
else
|
|
{
|
|
// translucent
|
|
// Approximate 1/255 by 257/65536:
|
|
|
|
UINT red = ((argb & RedMask) >> RedShift) * alpha + 0x80;
|
|
UINT green = ((argb & GreenMask) >> GreenShift) * alpha + 0x80;
|
|
UINT blue = ((argb & BlueMask) >> BlueShift) * alpha + 0x80;
|
|
|
|
argb = MakeARGB((BYTE) alpha,
|
|
(BYTE) ((red + (red >> 8)) >> 8),
|
|
(BYTE) ((green + (green >> 8)) >> 8),
|
|
(BYTE) ((blue + (blue >> 8)) >> 8));
|
|
}
|
|
|
|
return(argb);
|
|
}
|
|
|
|
// This is a variation of the above which is useful for
|
|
// antialiasing. It takes the argb value plus an additional
|
|
// alpha value (0-255) which is to multiply the alpha in the
|
|
// color before converting to premultiplied. In the antialiasing
|
|
// case, this extra alpha value is the coverage.
|
|
|
|
static ARGB PremultiplyWithCoverage(ARGB argb, BYTE coverage)
|
|
{
|
|
UINT alpha = (argb & AlphaMask) >> AlphaShift;
|
|
|
|
alpha = alpha*coverage + 0x80;
|
|
alpha = ((alpha + (alpha >> 8)) >> 8);
|
|
|
|
// translucent
|
|
// Approximate 1/255 by 257/65536:
|
|
|
|
UINT red = ((argb & RedMask) >> RedShift) * alpha + 0x80;
|
|
UINT green = ((argb & GreenMask) >> GreenShift) * alpha + 0x80;
|
|
UINT blue = ((argb & BlueMask) >> BlueShift) * alpha + 0x80;
|
|
|
|
argb = MakeARGB((BYTE) alpha,
|
|
(BYTE) ((red + (red >> 8)) >> 8),
|
|
(BYTE) ((green + (green >> 8)) >> 8),
|
|
(BYTE) ((blue + (blue >> 8)) >> 8));
|
|
|
|
return(argb);
|
|
}
|
|
|
|
static ARGB MultiplyCoverage(ARGB argb, BYTE coverage)
|
|
{
|
|
UINT alpha = (argb & AlphaMask) >> AlphaShift;
|
|
|
|
alpha = alpha*coverage + 0x80;
|
|
alpha = ((alpha + (alpha >> 8)) >> 8);
|
|
|
|
// translucent
|
|
// Approximate 1/255 by 257/65536:
|
|
|
|
UINT red = ((argb & RedMask) >> RedShift) * coverage + 0x80;
|
|
UINT green = ((argb & GreenMask) >> GreenShift) * coverage + 0x80;
|
|
UINT blue = ((argb & BlueMask) >> BlueShift) * coverage + 0x80;
|
|
|
|
argb = MakeARGB((BYTE) alpha,
|
|
(BYTE) ((red + (red >> 8)) >> 8),
|
|
(BYTE) ((green + (green >> 8)) >> 8),
|
|
(BYTE) ((blue + (blue >> 8)) >> 8));
|
|
|
|
return(argb);
|
|
}
|
|
|
|
static INT GetAlphaARGB(ARGB argb)
|
|
{
|
|
return ((argb & AlphaMask) >> AlphaShift);
|
|
}
|
|
|
|
static INT GetRedARGB(ARGB argb)
|
|
{
|
|
return ((argb & RedMask) >> RedShift);
|
|
}
|
|
|
|
static INT GetGreenARGB(ARGB argb)
|
|
{
|
|
return ((argb & GreenMask) >> GreenShift);
|
|
}
|
|
|
|
static INT GetBlueARGB(ARGB argb)
|
|
{
|
|
return ((argb & BlueMask) >> BlueShift);
|
|
}
|
|
|
|
private:
|
|
|
|
ARGB Argb;
|
|
|
|
};
|
|
|
|
// Union for converting between ARGB and 4 separate BYTE channel values.
|
|
|
|
union GpColorConverter
|
|
{
|
|
ARGB argb;
|
|
struct {
|
|
BYTE b;
|
|
BYTE g;
|
|
BYTE r;
|
|
BYTE a;
|
|
} Channel;
|
|
};
|
|
|
|
// 32 bits per channel floating point color value.
|
|
|
|
class GpFColor128
|
|
{
|
|
public:
|
|
|
|
REAL b;
|
|
REAL g;
|
|
REAL r;
|
|
REAL a;
|
|
};
|
|
|
|
|
|
class GpGlyphPos
|
|
{
|
|
public:
|
|
GpGlyphPos(int x0=0, int y0=0, int cx=0, int cy=0, BYTE* bts=NULL)
|
|
: Left(x0), Top(y0), Width(cx), Height(cy), BitsOrPath((PVOID) bts), bTempBits(FALSE), bIsBits(TRUE)
|
|
{}
|
|
|
|
inline INT GetLeft(void) const { return Left; }
|
|
inline INT GetTop(void) const { return Top; }
|
|
inline INT GetWidth(void) const { return Width; }
|
|
inline INT GetHeight(void) const { return Height; }
|
|
|
|
|
|
void SetLeft(INT l) { Left = l; }
|
|
void SetTop(INT t) { Top = t; }
|
|
void SetWidth(INT w) { Width = w; }
|
|
void SetHeight(INT h) { Height = h; }
|
|
|
|
BYTE * GetBits(void) const
|
|
{
|
|
if (bIsBits)
|
|
return (BYTE *) BitsOrPath;
|
|
|
|
return (BYTE *) NULL;
|
|
}
|
|
|
|
PVOID GetPath(void) const
|
|
{
|
|
if (!bIsBits)
|
|
return BitsOrPath;
|
|
else
|
|
return (PVOID) NULL;
|
|
}
|
|
|
|
void SetPath(PVOID path=NULL)
|
|
{
|
|
BitsOrPath = path;
|
|
bIsBits = FALSE;
|
|
}
|
|
|
|
void SetBits(BYTE* bts=NULL)
|
|
{
|
|
BitsOrPath = (PVOID) bts;
|
|
bIsBits = TRUE;
|
|
}
|
|
|
|
void SetTempBits(BYTE* bts=NULL)
|
|
{
|
|
BitsOrPath = (PVOID) bts;
|
|
|
|
if (bts)
|
|
{
|
|
bTempBits = TRUE;
|
|
}
|
|
}
|
|
|
|
BYTE * GetTempBits()
|
|
{
|
|
if (bTempBits)
|
|
return (BYTE *) BitsOrPath;
|
|
return NULL;
|
|
}
|
|
|
|
private:
|
|
INT Left;
|
|
INT Top;
|
|
INT Width;
|
|
INT Height;
|
|
BOOL bTempBits;
|
|
BOOL bIsBits;
|
|
PVOID BitsOrPath;
|
|
};
|
|
|
|
}
|
|
|
|
#endif // !_BASETYPES_HPP
|
|
|