/**************************************************************************\ * * Copyright (c) 1998-1999 Microsoft Corporation * * Module Name: * * path.hpp * * Abstract: * * Path related declarations * * Revision History: * * 12/06/1998 davidx * Created it. * * 06/16/1999 t-wehunt * Added RemoveSelfIntersections(). * \**************************************************************************/ #ifndef _PATH_HPP #define _PATH_HPP // This is used by the widener as an internal flag and as a deletion mask for // the endcap placement code. These two usages do not overlap. const INT PathPointTypeInternalUse = 0x40; /* // PathPointType is defined in GdiplusEnums.h. // Internally, we can use 0x40 for the internal use. //-------------------------------------------------------------------------- // Path point types (only the lowest 8 bits are used.) // The lowest 3 bits are interpreted as point type // The higher 5 bits are reserved for flags. //-------------------------------------------------------------------------- enum PathPointType { PathPointTypeStart = 0, // move PathPointTypeLine = 1, // line PathPointTypeBezier = 3, // default Beizer (= cubic Bezier) PathPointTypePathTypeMask = 0x07, // type mask (lowest 3 bits). PathPointTypeDashMode = 0x10, // currently in dash mode. PathPointTypePathMarker = 0x20, // a marker for the path. PathPointTypeCloseSubpath = 0x80, // closed flag // Path types used for advanced path. PathPointTypeBezier2 = 2, // quadratic Beizer PathPointTypeBezier3 = 3, // cubic Bezier PathPointTypeBezier4 = 4, // quartic (4th order) Beizer PathPointTypeBezier5 = 5, // quintic (5th order) Bezier PathPointTypeBezier6 = 6 // hexaic (6th order) Bezier }; */ class GpGlyphPath; inline BOOL IsStartType(BYTE type) { return ((type & PathPointTypePathTypeMask) == PathPointTypeStart); } inline BOOL IsClosedType(BYTE type) { return ((type & PathPointTypeCloseSubpath) == PathPointTypeCloseSubpath); } inline BOOL IsDashType(BYTE type) { return ((type & PathPointTypeDashMode) == PathPointTypeDashMode); } class GpPath : public DpPath { friend class GpGraphics; friend class GpPathGradient; public: // Path constructors GpPath(GpFillMode fillMode = FillModeAlternate) { InitDefaultState(fillMode); SetValid(TRUE); } GpPath(const GpPointF* points, const BYTE* types, INT count, GpFillMode fillMode = FillModeAlternate); GpPath( const GpPointF *points, INT count, GpPointF *stackPoints, BYTE *stackTypes, INT stackCount, GpFillMode fillMode = FillModeAlternate, DpPathFlags flags = PossiblyNonConvex ); GpPath(HRGN hRgn); // create a path from a GDI region handle GpPath(const DpRegion* region); // create a path from a GDI+ region // Get the lock object GpLockable *GetObjectLock() { return &Lockable; } GpPath* Clone() const { ASSERT(IsValid()) GpPath* path = new GpPath(this); CheckValid(path); return path; } GpStatus Reset(GpFillMode fillMode = FillModeAlternate) { // !!! bhouse We should allow reseting invalid paths ASSERT(IsValid()); InitDefaultState(fillMode); return Ok; } virtual GpStatus GetBounds( GpRect *bounds, const GpMatrix *matrix = NULL, const DpPen* pen = NULL, REAL dpiX = 0, REAL dpiY = 0 ) const; virtual GpStatus GetBounds( GpRectF *bounds, const GpMatrix *matrix = NULL, const DpPen* pen = NULL, REAL dpiX = 0, REAL dpiY = 0 ) const; REAL GetSharpestAngle() const { if(!(CacheFlags & kSharpestAngleValid)) CalcSharpestAngle(); return SharpestAngle; } // Set a marker at the current location. GpStatus SetMarker(); // Clear all markers. GpStatus ClearMarkers(); // Add lines to the path object GpStatus AddLine(const GpPointF& pt1, const GpPointF& pt2) { GpPointF points[2]; points[0] = pt1; points[1] = pt2; return AddLines(points, 2); } GpStatus AddLine(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 AddLines(points, 2); } GpStatus AddLines(const GpPointF* points, INT count); // Add an arc to the path object GpStatus AddArc(const GpRectF& rect, REAL startAngle, REAL sweepAngle); GpStatus AddArc(REAL x, REAL y, REAL width, REAL height, REAL startAngle, REAL sweepAngle) { GpRectF rect(x, y, width, height); return AddArc(rect, startAngle, sweepAngle); } // Add Bezier curves to the path object GpStatus AddBezier(const GpPointF& pt1, const GpPointF& pt2, const GpPointF& pt3, const GpPointF& pt4); GpStatus AddBezier(REAL x1, REAL y1, REAL x2, REAL y2, REAL x3, REAL y3, REAL x4, REAL y4); GpStatus AddBeziers(const GpPointF* points, INT count); // Add cardinal splines to the path object GpStatus AddCurve(const GpPointF* points, INT count); GpStatus AddCurve(const GpPointF* points, INT count, REAL tension, INT offset, INT numberOfSegments); GpStatus AddClosedCurve(const GpPointF* points, INT count); GpStatus AddClosedCurve(const GpPointF* points, INT count, REAL tension); // Add closed shapes to the path object GpStatus AddRects(const GpRectF* rects, INT count); GpStatus AddRects(const RECT* rects, INT count); GpStatus AddPolygon(const GpPointF* points, INT count); GpStatus AddEllipse(const GpRectF& rect); GpStatus AddPie(const GpRectF& rect, REAL startAngle, REAL sweepAngle); GpStatus AddRect(const GpRectF& rect) { return AddRects(&rect, 1); } GpStatus AddEllipse(REAL x, REAL y, REAL width, REAL height) { GpRectF rect(x, y, width, height); return AddEllipse(rect); } GpStatus AddPie(REAL x, REAL y, REAL width, REAL height, REAL startAngle, REAL sweepAngle) { GpRectF rect(x, y, width, height); return AddPie(rect, startAngle, sweepAngle); } // Add a path to the path object GpStatus AddPath(const GpPointF* points, const BYTE* types, INT count, BOOL connect); GpStatus AddPath(const GpPath* path, BOOL connect); // Reverse the direction of a path. GpStatus Reverse(); GpStatus GetLastPoint(GpPointF* point); // used by font GpStatus MoveTo(const GpPointF point); GpStatus AddPoints(const GpPointF* points, ULONG count, PathPointType type); GpStatus AddGlyphPath(GpGlyphPath *glyphPath, REAL x, REAL y, const GpMatrix * matrix = 0); GpStatus AddString( const WCHAR *string, INT length, const GpFontFamily *family, INT style, REAL emSize, const RectF *layoutRect, const GpStringFormat *format ); // Get the flatten data. virtual GpStatus Flatten( DynByteArray *flattenTypes, DynPointFArray *flattenPoints, const GpMatrix *matrix = NULL, const REAL flatness = FlatnessDefault ) const; // Flatten this path. GpStatus Flatten( const GpMatrix *matrix = NULL, const REAL flatness = FlatnessDefault ); // Get the morph and flatten data. GpStatus WarpAndFlatten( DynByteArray* flattenTypes, DynPointFArray* flattenPoints, const GpMatrix* matrix, const GpPointF* destPoint, INT count, const GpRectF& srcRect, WarpMode warpMode = WarpModePerspective ); // Morph and flatten itself. GpStatus WarpAndFlattenSelf( GpMatrix* matrix, const GpPointF* destPoint, INT count, const GpRectF& srcRect, WarpMode warpMode = WarpModePerspective ); // Morph to the flatten points. // Widen the path object GpPath* GetWidenedPath( const GpPen* pen, const GpMatrix* matrix = NULL, REAL flatness = FlatnessDefault ) const; GpStatus Widen( GpPen* pen, GpMatrix* matrix = NULL, REAL flatness = FlatnessDefault ); // Get the flattened path. virtual const DpPath * GetFlattenedPath( const GpMatrix* matrix, DpEnumerationType type, const DpPen* pen = NULL ) const; // Dreate a dashed path. (override) GpPath* CreateDashedPath( const GpPen* pen, const GpMatrix* matrix, REAL dpiX, REAL dpiY, REAL dashScale = 1.0f, BOOL needDashCaps = TRUE ) const; GpPath* CreateDashedPath( const DpPen* pen, const GpMatrix* matrix, REAL dpiX, REAL dpiY, REAL dashScale = 1.0f, BOOL needDashCaps = TRUE ) const; // Get the open and closed portion of the current path. GpPath* GetOpenPath(); GpPath* GetClosedPath(); // Determine if the path is empty, i.e. with no points BOOL IsEmpty() const { return GetPointCount() == 0; } BOOL IsRectangle( const GpMatrix * matrix, GpRectF * transformedBounds = NULL ) const; // Determine if path consists of a single polygon/polyline. BOOL IsPolygon() const { return (SubpathCount == 1) && !HasBezier; } // Return true if the two objects represent identical paths BOOL IsEqual(const GpPath* path) const; // Transform the path by the specified matrix VOID Transform(const GpMatrix * matrix); VOID SetHasBezier(BOOL _hasBezier) { HasBezier = _hasBezier; } // Hit testing GpStatus IsVisible( GpPointF* point, BOOL* isVisible, GpMatrix* matrix = NULL); GpStatus IsOutlineVisible(GpPointF* point, BOOL* isVisible, GpPen* pen, GpMatrix* matrix = NULL, REAL dpiX = 0, REAL dpiY = 0); // DDI entry point handlers for DpPath static GpPath* GetPath(const DpPath* path) { return (GpPath*)(path); } static DpPath* DriverCreateWidenedPath( const DpPath* path, const DpPen* pen, DpContext* context, BOOL outline ); static VOID DriverDeletePath(DpPath* path); static DpPath* DriverClonePath(DpPath* path); static VOID DriverTransformPath(DpPath* path, GpMatrix* matrix); // Compute the winding mode outline. GpStatus ComputeWindingModeOutline( const GpMatrix *matrix, REAL flatness, BOOL *wereIntersectsRemoved = NULL ); // Used for a mark-sweep point deletion algorithm in the path. VOID EraseMarkedSegments(); virtual DynArray *GetSubpathInformation() const; protected: VOID ComputeSubpathInformationCache() const; GpPath(const GpPath* path); GpPath *GetWidenedPathInternal( const DpPen *pen, const GpMatrix *matrix, REAL flatness = FlatnessDefault, BOOL insetPen = FALSE ) const; protected: BYTE* AddPointHelper( const GpPointF* points, INT count, BOOL addClosedFigure ); GpPath* GetOpenOrClosedPath(BOOL openPath); static GpPointF* ConvertSplineToBezierPoints( const GpPointF* points, INT count, INT offset, INT numberOfSegments, REAL tension, INT* bezierCount ); static INT GetArcPoints( GpPointF* points, const GpRectF& rect, REAL startAngle, REAL sweepAngle ); VOID InitDefaultState(GpFillMode fillMode); VOID ResetCacheBounds() const { CacheFlags = (kCacheBoundsValid | kSharpestAngleValid); SharpestAngle = 2; CacheBounds.X = 0; CacheBounds.Y = 0; CacheBounds.Width = 0; CacheBounds.Height = 0; } VOID InvalidateCache() const { CacheFlags = 0; } VOID UpdateCacheBounds() const { if(!(CacheFlags & kCacheBoundsValid)) CalcCacheBounds(); } VOID CalcCacheBounds() const; VOID CalcSharpestAngle() const; // Data Members: protected: GpLockable Lockable; // object lock enum { kCacheBoundsValid = 1, kSharpestAngleValid = 2, kSubpathInfoValid = 4 }; mutable ULONG CacheFlags; mutable GpRectF CacheBounds; mutable REAL SharpestAngle; // Some small number of subpaths for our initial allocation should suffice // for most usage scenarios. mutable DynArrayIA SubpathInfoCache; }; class GpPathIterator : public DpPathIterator { public: GpPathIterator(GpPath* path) : DpPathIterator(path) { } virtual INT GetCount() { if(IsValid()) return Count; else return 0; } virtual INT GetSubpathCount() { if(IsValid()) return SubpathCount; else return 0; } // This iterator is not used for the extended path. virtual BOOL IsValid() {return (DpPathIterator::IsValid() && !ExtendedPath);} // Get the lock object GpLockable *GetObjectLock() { return &Lockable; } protected: GpLockable Lockable; }; #endif // !_PATH_HPP