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