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

1855 lines
48 KiB
C++

/**************************************************************************\
*
* Copyright (c) 1998-1999 Microsoft Corporation
*
* Module Name:
*
* Graphics.hpp
*
* Abstract:
*
* Declarations for Graphics class
*
* Revision History:
*
* 12/04/1998 davidx
* Created it.
*
\**************************************************************************/
#ifndef _GRAPHICS_HPP
#define _GRAPHICS_HPP
#include "printer.hpp"
#define GDIP_NOOP_ROP3 0x00AA0029 // do-nothing ROP
// definitions copied from winddi.h :
#ifndef _WINDDI_
DECLARE_HANDLE(HSURF);
DECLARE_HANDLE(DHSURF);
DECLARE_HANDLE(DHPDEV);
typedef struct _SURFOBJ
{
DHSURF dhsurf;
HSURF hsurf;
DHPDEV dhpdev;
HDEV hdev;
SIZEL sizlBitmap;
ULONG cjBits;
PVOID pvBits;
PVOID pvScan0;
LONG lDelta;
ULONG iUniq;
ULONG iBitmapFormat;
USHORT iType;
USHORT fjBitmap;
} SURFOBJ;
#endif
// Forward declaration of the GpCachedBitmap class.
class GpCachedBitmap;
class CopyOnWriteBitmap;
/**
* Represent a graphics context
*/
class GpGraphics
{
friend class GpBitmap;
friend class CopyOnWriteBitmap;
friend class GpMetafile;
friend class MetafilePlayer;
friend class HdcLock;
friend class DriverUni;
friend class MetafileRecorder;
friend class DriverStringImager;
friend class FullTextImager;
friend class FastTextImager;
friend class GpCachedBitmap;
private:
// We now use an ObjectTag to determine if the object is valid
// instead of using a BOOL. This is much more robust and helps
// with debugging. It also enables us to version our objects
// more easily with a version number in the ObjectTag.
ObjectTag Tag; // Keep this as the 1st value in the object!
protected:
VOID SetValid(BOOL valid)
{
Tag = valid ? ObjectTagGraphics : ObjectTagInvalid;
}
// This method is here so that we have a virtual function table so
// that we can add virtual methods in V2 without shifting the position
// of the Tag value within the data structure.
virtual VOID DontCallThis()
{
DontCallThis();
}
public:
LONG LockedByGetDC; // Used by GdipGetDC and GdipReleaseDC
protected:
static GpGraphics*
GetForMetafile(
IMetafileRecord * metafile,
EmfType type,
HDC hdc
);
// used by the MetafileRecorder in the EndRecording method
VOID NoOpPatBlt(
INT left,
INT top,
INT width,
INT height
)
{
// Get the devlock because the surface will be flushed when we get the
// HDC
Devlock devlock(Device);
// Get the HDC in the correct state
HDC hdc = Context->GetHdc(Surface);
if (hdc != NULL)
{
::PatBlt(hdc, left, top, width, height, GDIP_NOOP_ROP3);
Context->ReleaseHdc(hdc);
}
// Now Reset the HDC so that this happens before the
// EndOfFile record (which has to be the last record before the
// EMF's EOF record).
Context->ResetHdc();
}
// If we should send rects to the driver instead of a path
BOOL UseDriverRects() const
{
return (Context->WorldToDevice.IsTranslateScale() &&
((!Context->AntiAliasMode) || DownLevel));
}
public:
// Get a graphics context from an existing Win32 HDC or HWND
static GpGraphics* GetFromHdc(HDC hdc, HANDLE hDevice = NULL);
// Default behaviour is to ignore ICM mode.
static GpGraphics* GetFromHwnd(
HWND hwnd,
HdcIcmMode icmMode = IcmModeOff
);
~GpGraphics();
// Internal use only
static GpGraphics* GetFromHdcSurf(HDC hdc,
SURFOBJ* surfObj,
RECTL* bandClip);
static GpGraphics* GetFromGdiScreenDC(HDC hdc);
// Get the lock object
GpLockable *GetObjectLock() const
{
return &Lockable;
}
// Check to see if the object is valid
BOOL IsValid() const
{
#ifdef _X86_
// We have to guarantee that the Tag field doesn't move for
// versioning to work between releases of GDI+.
ASSERT(offsetof(GpGraphics, Tag) == 4);
#endif
ASSERT((Tag == ObjectTagGraphics) || (Tag == ObjectTagInvalid));
#if DBG
if (Tag == ObjectTagInvalid)
{
WARNING1("Invalid Graphics");
}
#endif
return (Tag == ObjectTagGraphics);
}
// Derive a win32 HDC from the graphics context
HDC GetHdc();
VOID ReleaseHdc(HDC hdc);
// Flush any pending rendering
VOID Flush(GpFlushIntention intention)
{
Devlock devlock(Device);
DrvFlush(intention);
}
//------------------------------------------------------------------------
// Manipulate the current world transform
//------------------------------------------------------------------------
GpStatus SetWorldTransform(const GpMatrix& matrix);
GpStatus ResetWorldTransform();
GpStatus MultiplyWorldTransform(const GpMatrix& matrix,
GpMatrixOrder order = MatrixOrderPrepend);
GpStatus TranslateWorldTransform(REAL dx, REAL dy,
GpMatrixOrder order = MatrixOrderPrepend);
GpStatus ScaleWorldTransform(REAL sx, REAL sy,
GpMatrixOrder order = MatrixOrderPrepend);
GpStatus RotateWorldTransform(REAL angle,
GpMatrixOrder order = MatrixOrderPrepend);
VOID GetWorldTransform(GpMatrix & matrix) const
{
matrix = Context->WorldToPage;
}
GpStatus GetDeviceToWorldTransform(GpMatrix * matrix) const;
VOID GetWorldToDeviceTransform(GpMatrix * matrix) const
{
*matrix = Context->WorldToDevice;
}
VOID GetWorldToDeviceTransform(REAL * m) const
{
Context->WorldToDevice.GetMatrix(m);
}
VOID GetWorldPixelSize(REAL & xSize, REAL & ySize);
// Manipulate the current page transform
// !! *PageTransform's to be phased out...
GpStatus SetPageTransform(GpPageUnit unit, REAL scale = 1);
GpStatus ResetPageTransform()
{
return SetPageTransform(UnitDisplay);
}
GpPageUnit GetPageUnit() const { return Context->PageUnit; }
REAL GetPageScale() const { return Context->PageScale; }
GpStatus SetPageUnit(GpPageUnit unit)
{
return SetPageTransform(unit, GetPageScale());
}
GpStatus SetPageScale(REAL scale)
{
return SetPageTransform(GetPageUnit(), scale);
}
GpStatus TransformPoints(
GpPointF * points,
INT count,
GpCoordinateSpace source = CoordinateSpaceWorld,
GpCoordinateSpace dest = CoordinateSpaceDevice
);
/// GetScaleForAlternatePageUnit
//
// Return world unit scale factor corresponding to the difference
// between the page units selected in the graphics and a unit specified
// to an API such as pen thickness or font height.
//
// The returned vector provides the amount by which to multiply world
// x and y coordinates so that they will behave according to the
// alternate unit when passed through Context.WorldToDevice.
REAL GetScaleForAlternatePageUnit(Unit unit) const
{
// pen width and font height must not use UnitDisplay because
// it is a device dependent unit.
ASSERT(unit != UnitDisplay);
// The x:Y aspect ratio of the device resolution doesn't matter here,
// we get exactly the same values whether we use DpiX/PageMultiplierX
// or DpiY/PageMiltiplierY.
switch (unit)
{
case UnitDocument:
return ((GetDpiX()/300.0f) / Context->PageMultiplierX);
case UnitPoint:
return ((GetDpiX()/72.0f) / Context->PageMultiplierX);
case UnitMillimeter:
return ((GetDpiX()/25.4f) / Context->PageMultiplierX);
case UnitInch:
return (GetDpiX() / Context->PageMultiplierX);
case UnitWorld:
case UnitPixel:
default:
return 1.0f;
}
}
// Clipping related methods
GpStatus SetClip(GpGraphics* g, CombineMode combineMode);
GpStatus SetClip(const GpRectF& rect, CombineMode combineMode);
GpStatus SetClip(GpPath* path, CombineMode combineMode,
BOOL isDevicePath = FALSE);
GpStatus SetClip(GpRegion* region, CombineMode combineMode);
GpStatus SetClip(HRGN hRgn, CombineMode combineMode);
GpStatus ResetClip();
GpStatus OffsetClip(REAL dx, REAL dy);
GpRegion* GetClip() const;
GpStatus GetClip(GpRegion* region) const;
// save and restore graphics state
INT Save();
VOID Restore(INT gstate);
// start and end container drawing
INT
BeginContainer(
const GpRectF & destRect,
const GpRectF & srcRect,
GpPageUnit srcUnit,
REAL srcDpiX = 0.0f, // for metafile playback only
REAL srcDpiY = 0.0f,
BOOL srcIsDisplay = TRUE // for metafile playback only
);
INT BeginContainer(
// all these params are only applicable for metafile playback
BOOL forceIdentityTransform = FALSE,
REAL srcDpiX = 0.0f,
REAL srcDpiY = 0.0f,
BOOL srcIsDisplay = TRUE
);
VOID EndContainer(INT containerState);
// Hit testing operations
VOID GetClipBounds(GpRectF& rect) const;
BOOL IsClipEmpty() const;
VOID GetVisibleClipBounds(GpRectF& rect) const;
BOOL IsVisibleClipEmpty() const;
GpRegion* GetVisibleClip() const;
HRGN GetVisibleClipHRgn() const
{
return Context->VisibleClip.GetHRgn();
}
BOOL IsVisible(const GpPointF& point) const;
BOOL IsVisible(const GpRectF& rect) const;
GpStatus GetPixelColor(REAL x, REAL y, ARGB* argb) const;
// Set antialiasing mode
VOID SetAntiAliasMode( BOOL newMode )
{
ASSERT(Context);
// for Printer DC never set AA
if (IsPrinter())
{
Context->AntiAliasMode = FALSE;
return;
}
if (IsRecording() && (newMode != Context->AntiAliasMode))
{
Metafile->RecordSetAntiAliasMode(newMode);
}
Context->AntiAliasMode = newMode;
}
BOOL GetAntiAliasMode() const
{
ASSERT(Context);
return(Context->AntiAliasMode);
}
// Set antialiasing text
VOID SetTextRenderingHint( TextRenderingHint newMode)
{
ASSERT(Context);
// for Printer DC never set AA or Clear Type text
if (IsPrinter())
{
Context->TextRenderHint = TextRenderingHintSingleBitPerPixelGridFit;
return;
}
if (IsRecording() && (newMode != Context->TextRenderHint))
{
Metafile->RecordSetTextRenderingHint(newMode);
}
Context->TextRenderHint = newMode;
}
TextRenderingHint GetTextRenderingHint() const
{
ASSERT(Context);
return(Context->TextRenderHint);
}
// this procedure is meant to be used by internal text routines
// and will return real text rendering hint (not TextRenderingHintSystemDefault)
// we should always call CalculateTextRenderingHintInternal() before
// calling GetTextRenderingHintInternal()
TextRenderingHint GetTextRenderingHintInternal() const
{
return TextRenderingHintInternal;
}
Status SetTextContrast(UINT contrast)
{
ASSERT(Context);
if (contrast > MAX_TEXT_CONTRAST_VALUE)
return InvalidParameter;
// for Printer DC never set AA or Clear Type text
if (IsPrinter())
{
Context->TextContrast = 0;
return Ok;
}
if (IsRecording() && (contrast != Context->TextContrast))
{
Metafile->RecordSetTextContrast(contrast);
}
Context->TextContrast = contrast;
return Ok;
}
UINT GetTextContrast() const
{
ASSERT(Context);
return Context->TextContrast;
}
// Rendering Origin
// This is the origin used for Dither and Halftone matrix origins
// and should be used for any raster operations that need an origin.
VOID SetRenderingOrigin(INT x, INT y)
{
ASSERT(Context);
if (IsRecording() &&
(x != Context->RenderingOriginX ||
y != Context->RenderingOriginY)
)
{
Metafile->RecordSetRenderingOrigin(x, y);
}
Context->RenderingOriginX = x;
Context->RenderingOriginY = y;
}
// Rendering Origin
// Returns the origin used for the Dither and Halftone matrix origin.
VOID GetRenderingOrigin(INT *x, INT *y) const
{
ASSERT(Context);
ASSERT(x);
ASSERT(y);
*x = Context->RenderingOriginX;
*y = Context->RenderingOriginY;
}
// Compositing mode
VOID SetCompositingMode( GpCompositingMode newMode )
{
ASSERT(Context);
if (IsRecording() && (newMode != Context->CompositingMode))
{
Metafile->RecordSetCompositingMode(newMode);
}
Context->CompositingMode = newMode;
}
GpCompositingMode GetCompositingMode() const
{
ASSERT(Context);
return(Context->CompositingMode);
}
// Compositing quality
VOID SetCompositingQuality( GpCompositingQuality newQuality )
{
ASSERT(Context);
if (IsRecording() && (newQuality != Context->CompositingQuality))
{
Metafile->RecordSetCompositingQuality(newQuality);
}
Context->CompositingQuality = newQuality;
}
GpCompositingQuality GetCompositingQuality() const
{
ASSERT(Context);
return(Context->CompositingQuality);
}
VOID SetInterpolationMode(InterpolationMode newMode)
{
ASSERT(Context);
if (IsRecording() && (newMode != Context->FilterType))
{
Metafile->RecordSetInterpolationMode(newMode);
}
Context->FilterType = newMode;
}
InterpolationMode GetInterpolationMode() const
{
ASSERT(Context);
return Context->FilterType;
}
VOID SetPixelOffsetMode(PixelOffsetMode newMode)
{
ASSERT(Context);
if (newMode != Context->PixelOffset)
{
if (IsRecording())
{
Metafile->RecordSetPixelOffsetMode(newMode);
}
Context->PixelOffset = newMode;
Context->InverseOk = FALSE;
Context->UpdateWorldToDeviceMatrix();
}
}
PixelOffsetMode GetPixelOffsetMode() const
{
ASSERT(Context);
return Context->PixelOffset;
}
//------------------------------------------------------------------------
// GetNearestColor (for <= 8bpp surfaces)
//------------------------------------------------------------------------
ARGB
GetNearestColor(
ARGB argb
);
//------------------------------------------------------------------------
// Stroke vector shapes
//------------------------------------------------------------------------
GpStatus
DrawLine(
GpPen* pen,
const GpPointF& pt1,
const GpPointF& pt2
)
{
GpPointF points[2];
points[0] = pt1;
points[1] = pt2;
return(DrawLines(pen, &points[0], 2));
}
GpStatus
DrawLine(
GpPen* pen,
REAL x1,
REAL y1,
REAL x2,
REAL y2
)
{
GpPointF points[2];
points[0].X = x1;
points[0].Y = y1;
points[1].X = x2;
points[1].Y = y2;
return(DrawLines(pen, &points[0], 2));
}
GpStatus
DrawLines(
GpPen* pen,
const GpPointF* points,
INT count,
BOOL closed = FALSE
);
GpStatus
DrawArc(
GpPen* pen,
const GpRectF& rect,
REAL startAngle,
REAL sweepAngle
);
GpStatus
DrawArc(
GpPen* pen,
REAL x,
REAL y,
REAL width,
REAL height,
REAL startAngle,
REAL sweepAngle
)
{
GpRectF rect(x, y, width, height);
return DrawArc(pen, rect, startAngle, sweepAngle);
}
GpStatus
DrawBezier(
GpPen* pen,
const GpPointF& pt1,
const GpPointF& pt2,
const GpPointF& pt3,
const GpPointF& pt4
)
{
GpPointF points[4];
points[0] = pt1;
points[1] = pt2;
points[2] = pt3;
points[3] = pt4;
return DrawBeziers(pen, points, 4);
}
GpStatus
DrawBezier(
GpPen* pen,
REAL x1, REAL y1,
REAL x2, REAL y2,
REAL x3, REAL y3,
REAL x4, REAL y4
)
{
GpPointF points[4];
points[0].X = x1;
points[0].Y = y1;
points[1].X = x2;
points[1].Y = y2;
points[2].X = x3;
points[2].Y = y3;
points[3].X = x4;
points[3].Y = y4;
return DrawBeziers(pen, points, 4);
}
GpStatus
DrawBeziers(
GpPen* pen,
const GpPointF* points,
INT count
);
GpStatus
DrawRect(
GpPen* pen,
const GpRectF& rect
)
{
return(DrawRects(pen, &rect, 1));
}
GpStatus
DrawRect(
GpPen* pen,
REAL x,
REAL y,
REAL width,
REAL height
)
{
GpRectF rect(x, y, width, height);
return(DrawRects(pen, &rect, 1));
}
GpStatus
DrawRects(
GpPen* pen,
const GpRectF* rects,
INT count
);
GpStatus
DrawEllipse(
GpPen* pen,
const GpRectF& rect
);
GpStatus
DrawEllipse(
GpPen* pen,
REAL x,
REAL y,
REAL width,
REAL height
)
{
GpRectF rect(x, y, width, height);
return DrawEllipse(pen, rect);
}
GpStatus
DrawPie(
GpPen* pen,
const GpRectF& rect,
REAL startAngle,
REAL sweepAngle
);
GpStatus
DrawPie(
GpPen* pen,
REAL x,
REAL y,
REAL width,
REAL height,
REAL startAngle,
REAL sweepAngle
)
{
GpRectF rect(x, y, width, height);
return DrawPie(pen, rect, startAngle, sweepAngle);
}
GpStatus
DrawPolygon(
GpPen* pen,
const GpPointF* points,
INT count
)
{
return(DrawLines(pen, points, count, TRUE));
}
GpStatus
DrawPath(
GpPen* pen,
GpPath* path
);
GpStatus
DrawPathData(
GpPen* pen,
const GpPointF* points,
const BYTE *types,
INT count,
GpFillMode fillMode
)
{
GpStatus status = GenericError;
GpPath path(points, types, count, fillMode);
if(path.IsValid())
status = DrawPath(pen, &path);
return status;
}
GpStatus
DrawCurve(
GpPen* pen,
const GpPointF* points,
INT count
);
GpStatus
DrawCurve(
GpPen* pen,
const GpPointF* points,
INT count,
REAL tension,
INT offset,
INT numberOfSegments
);
GpStatus
DrawClosedCurve(
GpPen* pen,
const GpPointF* points,
INT count
);
GpStatus
DrawClosedCurve(
GpPen* pen,
const GpPointF* points,
INT count,
REAL tension
);
//------------------------------------------------------------------------
// Fill shapes
//------------------------------------------------------------------------
GpStatus
Clear(
const GpColor &color
);
GpStatus
FillRect(
GpBrush* brush,
const GpRectF& rect
)
{
return(FillRects(brush, &rect, 1));
}
GpStatus
FillRect(
GpBrush* brush,
REAL x,
REAL y,
REAL width,
REAL height
)
{
GpRectF rect(x, y, width, height);
return(FillRects(brush, &rect, 1));
}
GpStatus
FillRects(
GpBrush* brush,
const GpRectF* rects,
INT count
);
GpStatus
FillPolygon(
GpBrush* brush,
const GpPointF* points,
INT count
)
{
return FillPolygon(brush, points, count, FillModeAlternate);
}
GpStatus
FillPolygon(
GpBrush* brush,
const GpPointF* points,
INT count,
GpFillMode fillMode
);
GpStatus
FillEllipse(
GpBrush* brush,
const GpRectF& rect
);
GpStatus
FillEllipse(
GpBrush* brush,
REAL x,
REAL y,
REAL width,
REAL height
)
{
GpRectF rect(x, y, width, height);
return FillEllipse(brush, rect);
}
GpStatus
FillPie(
GpBrush* brush,
const GpRectF& rect,
REAL startAngle,
REAL sweepAngle
);
GpStatus
FillPie(
GpBrush* brush,
REAL x,
REAL y,
REAL width,
REAL height,
REAL startAngle,
REAL sweepAngle
)
{
GpRectF rect(x, y, width, height);
return FillPie(brush, rect, startAngle, sweepAngle);
}
GpStatus
FillPath(
const GpBrush* brush,
GpPath* path
);
GpStatus
FillPathData(
GpBrush* brush,
const GpPointF* points,
const BYTE *types,
INT count,
GpFillMode fillMode
)
{
GpStatus status = GenericError;
GpPath path(points, types, count, fillMode);
if(path.IsValid())
status = FillPath(brush, &path);
return status;
}
GpStatus
FillClosedCurve(
GpBrush* brush,
const GpPointF* points,
INT count,
REAL tension = 0.5,
GpFillMode fillMode = FillModeAlternate
);
GpStatus
FillRegion(
GpBrush* brush,
GpRegion* region
);
//------------------------------------------------------------------------
// Draw text strings
//------------------------------------------------------------------------
#define DG_NOGDI 4 // Disable optimisation through GDI
#define DG_SIDEWAY 0x80000000 // flag used by the drivers (Meta Driver) for sideway runs.
// To be removed, replaced by DrawRealizedGlyphs and GdiDrawGlyphs
GpStatus
DrawGlyphs(
const UINT16 *glyphIndices,
INT count,
const GpFontFace *face,
INT style,
REAL emSize,
Unit unit,
const GpBrush *brush,
const UINT32 *px,
const UINT32 *py,
INT flags,
const GpMatrix *pmx = NULL
);
// Internal text drawing APIs
protected:
// should be called once per DrawString/DrawDriverString call
// checks for invalid text rendering hint combinations
GpStatus CheckTextMode();
// this method is meant to calculate TextRenderingHintInternal
// we call this method once and only once before using GetTextRenderingHintInternal()
void CalculateTextRenderingHintInternal();
public:
GpStatus DrawPlacedGlyphs(
const GpFaceRealization *faceRealization,
const GpBrush *brush,
INT flags,
const WCHAR *string,
UINT stringLength,
BOOL rightToLeft,
const UINT16 *glyphs,
const UINT16 *glyphMap,
const PointF *glyphOrigins,
INT glyphCount,
ItemScript Script,
BOOL sideways // e.g. FE characters in vertical text
);
GpStatus DrawDriverGlyphs(
const UINT16 *glyphs,
INT glyphCount,
const GpFont *font,
const GpFontFace *face,
const GpBrush *brush,
const WCHAR *string,
const PointF *positions,
INT flags,
const GpMatrix *matrix
);
// External text drawing APIs
GpStatus
DrawString(
const WCHAR *string,
INT length,
const GpFont *font,
const RectF *layoutRect,
const GpStringFormat *format,
const GpBrush *brush
);
GpStatus
MeasureString(
const WCHAR *string,
INT length,
const GpFont *font,
const RectF *layoutRect,
const GpStringFormat *format,
RectF *boundingBox,
INT *codepointsFitted,
INT *linesFilled
);
GpStatus
MeasureCharacterRanges(
const WCHAR *string,
INT length,
const GpFont *font,
const RectF &layoutRect,
const GpStringFormat *format,
INT regionCount,
GpRegion **regions
);
/// Start API for graphicstext.cpp
GpStatus
RecordEmfPlusDrawDriverString(
const UINT16 *text,
INT glyphCount,
const GpFont *font,
const GpFontFace *face,
const GpBrush *brush,
const PointF *positions,
INT flags,
const GpMatrix *matrix // optional
);
GpStatus
DrawDriverString(
const UINT16 *text,
INT length,
const GpFont *font,
const GpBrush *brush,
const PointF *positions,
INT flags,
const GpMatrix *matrix
);
GpStatus
MeasureDriverString(
const UINT16 *text,
INT glyphCount,
const GpFont *font,
const PointF *positions,
INT flags,
const GpMatrix *matrix, // In - Optional glyph transform
RectF *boundingBox // Out - Overall bounding box of cells
);
GpStatus
DrawFontStyleLine(
const PointF *baselineOrigin, // baseline origin
REAL baselineLength, // baseline length
const GpFontFace *face, // font face
const GpBrush *brush, // brush
BOOL vertical, // vertical text?
REAL emSize, // font EM size in world unit
INT style, // kind of lines to be drawn
const GpMatrix *matrix = NULL // additional transform
);
REAL GetDevicePenWidth(
REAL widthInWorldUnits,
const GpMatrix *matrix = NULL
);
/// End API for graphicstext.cpp
GpStatus
DrawCachedBitmap(
GpCachedBitmap *cb,
INT x,
INT y
)
{
return DrvDrawCachedBitmap(cb, x, y);
}
//------------------------------------------------------------------------
// Draw images (both bitmap and metafile)
//------------------------------------------------------------------------
GpStatus
DrawImage(
GpImage* image,
const GpPointF& point
);
GpStatus
DrawImage(
GpImage* image,
REAL x,
REAL y
)
{
GpPointF point(x, y);
return DrawImage(image, point);
}
GpStatus
DrawImage(
GpImage* image,
const GpRectF& destRect
);
GpStatus
DrawImage(
GpImage* image,
REAL x,
REAL y,
REAL width,
REAL height
)
{
GpRectF destRect(x, y, width, height);
return DrawImage(image, destRect);
}
GpStatus
DrawImage(
GpImage* image,
const GpPointF* destPoints,
INT count
);
GpStatus
DrawImage(
GpImage* image,
REAL x,
REAL y,
const GpRectF & srcRect,
GpPageUnit srcUnit
);
GpStatus
DrawImage(
GpImage* image,
const GpRectF& destRect,
const GpRectF& srcRect,
GpPageUnit srcUnit,
const GpImageAttributes* imageAttributes = NULL,
DrawImageAbort callback = NULL,
VOID* callbackData = NULL
);
GpStatus
DrawImage(
GpImage* image,
const GpPointF* destPoints,
INT count,
const GpRectF& srcRect,
GpPageUnit srcUnit,
const GpImageAttributes* imageAttributes = NULL,
DrawImageAbort callback = NULL,
VOID* callbackData = NULL
);
GpStatus
EnumerateMetafile(
const GpMetafile * metafile,
const PointF & destPoint,
EnumerateMetafileProc callback,
VOID * callbackData,
const GpImageAttributes * imageAttributes
);
GpStatus
EnumerateMetafile(
const GpMetafile * metafile,
const RectF & destRect,
EnumerateMetafileProc callback,
VOID * callbackData,
const GpImageAttributes * imageAttributes
);
GpStatus
EnumerateMetafile(
const GpMetafile * metafile,
const PointF * destPoints,
INT count,
EnumerateMetafileProc callback,
VOID * callbackData,
const GpImageAttributes * imageAttributes
);
GpStatus
EnumerateMetafile(
const GpMetafile * metafile,
const PointF & destPoint,
const RectF & srcRect,
Unit srcUnit,
EnumerateMetafileProc callback,
VOID * callbackData,
const GpImageAttributes * imageAttributes
);
GpStatus
EnumerateMetafile(
const GpMetafile * metafile,
const RectF & destRect,
const RectF & srcRect,
Unit srcUnit,
EnumerateMetafileProc callback,
VOID * callbackData,
const GpImageAttributes * imageAttributes
);
GpStatus
EnumerateMetafile(
const GpMetafile * metafile,
const PointF * destPoints,
INT count,
const RectF & srcRect,
Unit srcUnit,
EnumerateMetafileProc callback,
VOID * callbackData,
const GpImageAttributes * imageAttributes
);
GpStatus
Comment(
UINT sizeData,
const BYTE * data
)
{
GpStatus status = InvalidParameter;
if (IsRecording())
{
status = Metafile->RecordComment(sizeData, data);
if (status != Ok)
{
SetValid(FALSE); // Prevent any more recording
}
}
return status;
}
// Called only by metafile player
GpStatus
EnumEmf(
MetafilePlayer * player,
HENHMETAFILE hEmf,
const GpRectF & destRect,
const GpRectF & srcRect,
const GpRectF & deviceDestRect,
MetafileType type,
BOOL isTranslateScale,
BOOL renderToBitmap,
const GpMatrix & flipAndCropTransform
);
// Called only by metafile player
GpStatus
EnumEmfPlusDual(
MetafilePlayer * player,
HENHMETAFILE hEmf,
const GpRectF& destRect, // inclusive, exclusive
const GpRectF& deviceDestRect, // inclusive, exclusive
BOOL isTranslateScale,
BOOL renderToBitmap
);
protected:
// if an HWND is passed in, the default ICM mode is off.
// if an HDC is passed in, the icmMode flag is ignored.
GpGraphics(
HWND hwnd,
HDC hdc,
INT clientWidth,
INT clientHeight,
HdcIcmMode icmMode = IcmModeOff,
BOOL gdiLayered = FALSE
);
GpGraphics(DpBitmap * surface);
GpStatus GetDCDrawBounds(HDC hdc, RECT *rect);
public:
// The Context dpi and the Surface dpi are always the same,
// except possibly during metafile playback when the Context
// may be using the metafile dpi (which is what rendering
// should use).
REAL GetDpiX() const { return Context->GetDpiX(); }
REAL GetDpiY() const { return Context->GetDpiY(); }
BOOL IsPrinter() const { return Printer; }
protected:
enum HalftoneType
{
HalftoneTypeNone,
HalftoneType16Color,
HalftoneType216Color,
HalftoneType15Bpp,
HalftoneType16Bpp,
};
HalftoneType GetHalftoneType() const
{
EpPaletteMap* paletteMap = BottomContext.PaletteMap;
// !! TODO: Verify this works on when switching modes
if (paletteMap != NULL)
{
// we are doing 8bpp palette map
if (paletteMap->IsVGAOnly())
{
return HalftoneType16Color;
}
else
{
return HalftoneType216Color;
}
}
else if (Surface->PixelFormat == PixelFormat16bppRGB555)
{
return HalftoneType15Bpp;
}
else if (Surface->PixelFormat == PixelFormat16bppRGB565)
{
return HalftoneType16Bpp;
}
else
{
return HalftoneTypeNone;
}
}
//--------------------------------------------------------------
// Internal fill and draw routines that do not record
// path, rect, or region in a metafile.
//--------------------------------------------------------------
GpStatus
RenderFillRects(
GpRectF* bounds,
INT count,
const GpRectF* rects,
GpBrush* brush
)
{
GpRect deviceBounds;
GpStatus status = BoundsFToRect(bounds, &deviceBounds);
if (status == Ok && !IsTotallyClipped(&deviceBounds))
{
// Now that we've done a bunch of work in accumulating the bounds,
// acquire the device lock before calling the driver:
Devlock devlock(Device);
return DrvFillRects(&deviceBounds, count, rects, brush->GetDeviceBrush());
}
return status;
}
GpStatus
RenderFillRegion(
GpRectF* bounds,
GpRegion* region,
GpBrush* brush,
GpRect* metafileBounds
)
{
GpRect deviceBounds;
GpStatus status = BoundsFToRect(bounds, &deviceBounds);
BOOL isInfinite = FALSE;
GpMatrix identity;
if (status == Ok && !IsTotallyClipped(&deviceBounds))
{
// Now that we've done a bunch of work in accumulating the bounds,
// acquire the device lock before calling the driver:
status = region->UpdateDeviceRegion(&(Context->WorldToDevice));
if (status == Ok)
{
DpRegion * deviceRegion = &(region->DeviceRegion);
DpRegion metafileRegion;
if (metafileBounds != NULL)
{
metafileRegion.Set(metafileBounds);
metafileRegion.And(deviceRegion);
if (!metafileRegion.IsValid())
{
return GenericError;
}
deviceRegion = &metafileRegion;
}
// Get the actual bounds now to give to the driver
deviceRegion->GetBounds(&deviceBounds);
// Make sure there is still something to fill so we
// don't ASSERT later on.
if ((deviceBounds.Width > 0) && (deviceBounds.Height > 0))
{
Devlock devlock(Device);
return DrvFillRegion(&deviceBounds, deviceRegion, brush->GetDeviceBrush());
}
}
}
return status;
}
GpStatus RenderDrawPath(
GpRectF *bounds,
GpPath *path,
GpPen *pen
);
GpStatus RenderFillPath(
GpRectF *bounds,
GpPath *path,
const GpBrush *brush
);
VOID
GetImageDestPageSize(
const GpImage * image,
REAL srcWidth,
REAL srcHeight,
GpPageUnit srcUnit,
REAL & destWidth,
REAL & destHeight
);
VOID
DeviceToWorldTransformRect(
const GpRect & deviceRect,
GpRectF & rect
) const;
static GpGraphics *GetFromGdiBitmap(HDC hdc);
static GpGraphics *GetFromGdipBitmap(
GpBitmap* bitmap,
ImageInfo * imageInfo,
EpScanBitmap * scanBitmap,
BOOL isDisplay
);
static GpGraphics *GetFromGdiPrinterDC(HDC hdc);
static GpGraphics *GetFromGdiEmfDC(HDC hdc);
static GpGraphics *GetFromDirectDrawSurface(IDirectDrawSurface7 * surface);
static GpGraphics *GetFromGdiPrinterDC(HDC hdc, HANDLE hPrinter);
static INT GetPostscriptLevel(HDC hdc, HANDLE hPrinter);
GpStatus StartPrinterEMF();
GpStatus EndPrinterEMF();
BOOL IsTotallyClipped(GpRect *rect) const;
BOOL IsRecording() const { return Metafile != NULL; }
BOOL IsDisplay() const { return Context->IsDisplay; }
VOID DoResetClip()
{
Context->AppClip.SetInfinite();
// ContainerClip always contains the clipping for the container,
// intersected with the WindowClip.
Context->VisibleClip.Set(&(Context->ContainerClip));
}
// The AppClip has been set into VisibleClip; now intersect it with
// the container clip and the window clip.
GpStatus AndVisibleClip()
{
// ContainerClip always contains the clipping for the container,
// intersected with the WindowClip.
return Context->VisibleClip.And(&(Context->ContainerClip));
}
GpStatus
CombineClip(
const GpRectF & rect,
CombineMode combineMode
);
GpStatus
CombineClip(
const GpPath * path,
CombineMode combineMode,
BOOL isDevicePath = FALSE
);
GpStatus
CombineClip(
GpRegion * region,
CombineMode combineMode
);
GpStatus
InheritAppClippingAndTransform(
HDC hdc
);
VOID
ResetState(
INT x,
INT y,
INT width,
INT height
);
VOID
UpdateDrawBounds(
INT x,
INT y,
INT width,
INT height
);
//--------------------------------------------------------------------------
// Routines for calling the driver
//--------------------------------------------------------------------------
VOID
DrvFlush(
GpFlushIntention intention
)
{
ASSERTMSG(Device->DeviceLock.IsLockedByCurrentThread(),
("DeviceLock must be held by current thread"));
Driver->Flush(Device, Surface, intention);
}
GpStatus
DrvStrokePath(
const GpRect *drawBounds,
const DpPath *path,
const DpPen *pen
)
{
ASSERTMSG(GetObjectLock()->IsLocked(),
("Graphics object must be locked"));
ASSERTMSG(Device->DeviceLock.IsLockedByCurrentThread(),
("DeviceLock must be held by current thread"));
FPUStateSaver::AssertMode();
Surface->Uniqueness = (DWORD)GpObject::GenerateUniqueness();
return(Driver->StrokePath(Context, Surface, drawBounds, path, pen));
}
GpStatus
DrvFillRects(
const GpRect *drawBounds,
INT numRects,
const GpRectF *rects,
const DpBrush *brush
)
{
ASSERTMSG(GetObjectLock()->IsLocked(),
("Graphics object must be locked"));
ASSERTMSG(Device->DeviceLock.IsLockedByCurrentThread(),
("DeviceLock must be held by current thread"));
FPUStateSaver::AssertMode();
Surface->Uniqueness = (DWORD)GpObject::GenerateUniqueness();
return(Driver->FillRects(Context, Surface, drawBounds,
numRects, rects, brush));
}
GpStatus
DrvFillPath(
const GpRect *drawBounds,
const DpPath *path,
const DpBrush *brush
)
{
ASSERTMSG(GetObjectLock()->IsLocked(),
("Graphics object must be locked"));
ASSERTMSG(Device->DeviceLock.IsLockedByCurrentThread(),
("DeviceLock must be held by current thread"));
FPUStateSaver::AssertMode();
Surface->Uniqueness = (DWORD)GpObject::GenerateUniqueness();
return(Driver->FillPath(Context, Surface, drawBounds, path, brush));
}
GpStatus
DrvFillRegion(
const GpRect *drawBounds,
const DpRegion *region,
const DpBrush *brush
)
{
ASSERTMSG(GetObjectLock()->IsLocked(),
("Graphics object must be locked"));
ASSERTMSG(Device->DeviceLock.IsLockedByCurrentThread(),
("DeviceLock must be held by current thread"));
FPUStateSaver::AssertMode();
Surface->Uniqueness = (DWORD)GpObject::GenerateUniqueness();
return(Driver->FillRegion(Context, Surface, drawBounds, region, brush));
}
GpStatus
DrvDrawGlyphs(
const GpRect *drawBounds,
const GpGlyphPos *glyphPos,
const GpGlyphPos *glyphPathPos,
INT count,
const DpBrush *brush,
const GpFaceRealization *faceRealization,
const UINT16 *glyphs,
const UINT16 *glyphMap,
const PointF *glyphOrigins,
INT glyphCount,
const WCHAR *string,
UINT stringLength,
ItemScript script,
INT edgeGlyphAdvance,
BOOL rightToLeft,
INT flags
)
{
// check the input parameter!!
GpStatus status;
DrawGlyphData drawGlyphData;
drawGlyphData.context = Context;
drawGlyphData.surface = Surface;
drawGlyphData.drawBounds = drawBounds;
drawGlyphData.glyphPos = glyphPos;
drawGlyphData.glyphPathPos = glyphPathPos;
drawGlyphData.count = count;
drawGlyphData.brush = brush;
drawGlyphData.faceRealization = faceRealization;
drawGlyphData.glyphs = glyphs;
drawGlyphData.glyphMap = glyphMap;
drawGlyphData.glyphOrigins = glyphOrigins;
drawGlyphData.glyphCount = glyphCount;
drawGlyphData.string = string;
drawGlyphData.stringLength = stringLength;
drawGlyphData.script = script;
drawGlyphData.edgeGlyphAdvance = edgeGlyphAdvance;
drawGlyphData.rightToLeft = rightToLeft;
drawGlyphData.flags = flags;
status = Driver->DrawGlyphs(&drawGlyphData);
return status;
}
// Draw the CachedBitmap on this graphics.
// This routine sets up the rendering origin and the locks
// and calls the appropriate driver.
GpStatus
DrvDrawCachedBitmap(
GpCachedBitmap *inputCachedBitmap,
INT x,
INT y
);
GpStatus
DrvDrawImage(
const GpRect *drawBounds,
GpBitmap *intputBitmap,
INT numPoints,
const GpPointF *dstPoints,
const GpRectF *srcRect,
const GpImageAttributes *imageAttributes,
DrawImageAbort callback,
VOID *callbackData,
DriverDrawImageFlags flags
);
GpStatus
DrvMoveBits(
const GpRect *drawBounds,
const GpRect *dstRect,
const GpPoint *srcPoint
)
{
GpStatus status;
ASSERTMSG(GetObjectLock()->IsLocked(),
("Graphics object must be locked"));
ASSERTMSG(Device->DeviceLock.IsLockedByCurrentThread(),
("DeviceLock must be held by current thread"));
FPUStateSaver::AssertMode();
Surface->Uniqueness = (DWORD)GpObject::GenerateUniqueness();
status = Driver->MoveBits(Context, Surface, drawBounds, dstRect,
srcPoint);
return status;
}
public:
// Simple inline function to return the selected surface.
DpBitmap *GetSurface() {
return Surface;
}
// Simple inline function to return the driver.
DpDriver *GetDriver() {
return Driver;
}
protected:
enum GraphicsType
{
GraphicsBitmap = 1,
GraphicsScreen = 2,
GraphicsMetafile = 3,
};
mutable GpLockable Lockable;
GpRect SurfaceBounds; // Bounds of surface in device units.
DpBitmap *Surface; // Selected surface
GpBitmap *GdipBitmap; // point to GpBitmap if the graphics is created from one
IMetafileRecord * Metafile; // For recording metafiles
BOOL Printer; // Whether this object is a printer
PGDIPPRINTINIT PrintInit; // Initialization data for printer types
HGLOBAL PrinterEMF;
GpMetafile *PrinterMetafile;
GpGraphics *PrinterGraphics;
BOOL DownLevel; // Whether or not to do down-level metafile
GraphicsType Type; // Type of GpGraphics created
BOOL CreatedDevice; // Whether 'Device' was created at GpGraphics
// construction time, and so needs to be
// freed in the GpGraphics destructor
GpDevice *Device; // Associated device
DpDriver *Driver; // Associate driver interface
DpContext *Context; // Contains all the driver-viewable state:
// Transforms, clipping, alpha/antialias/etc.
// modes
DpContext BottomContext; // Always the bottom of the Context Stack
DpRegion WindowClip; // The clip region of the window
TextRenderingHint TextRenderingHintInternal; // cached internal value of TextRenderingHint
// valid during one call to Draw(Driver)String
};
#endif // !_GRAPHICS_HPP