|
|
/**************************************************************************\
* * 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
|