/**************************************************************************\ * * Copyright (c) 1998-2000 Microsoft Corporation * * Abstract: * * Internal "scan class" prototypes. These classes represent a set of * "primitive" operations, which are characterized by being quick to render, * and fairly simple to represent. * * [agodfrey] At time of writing, they are all scan-line operations, so the * name "scan class" kinda fits; however, we may need to add ones which * aren't scan-line oriented - e.g. one for aliased single-pixel-wide * opaque solid-filled lines. * * Revision History: * * 12/01/1998 andrewgo * Created it. * 02/22/2000 agodfrey * For ClearType, but also useful for other future improvements: * Expanded it to allow different types of record. * Cleared up some of the CachedBitmap confusion, * and removed the confusion between "opaque" and "SourceCopy". * \**************************************************************************/ #ifndef _SCAN_HPP #define _SCAN_HPP #include #include "alphablender.hpp" struct EpScanRecord; // This color is used as a default to detect bugs. const ARGB HorridInfraPurpleColor = 0x80ff80ff; // blenderNum: // Used when an operation mixes different scan types. // We don't use an enum because the meaning of each blender depends // on the situation. // // At the time of writing, only CachedBitmap uses this - to select // between the regular and opaque scan types. // BlenderMax: The number of different scan types allowed in one // Start() ... End() sequence. e.g. if this is 2, blenderNum can be 0 or 1. typedef VOID *(EpScan::* NEXTBUFFERFUNCTION)( INT x, INT y, INT newWidth, INT updateWidth, INT blenderNum ); const INT BlenderMax = 2; //-------------------------------------------------------------------------- // Scan iterator class // // [agodfrey]: The naming is confusing. Suggestions: // Rename "EpScan*" to "EpScanIterator". // Rename "NEXTBUFFERFUNCTION" // to something about "next scan", not "next buffer". // Make a stronger name distinction between EpScanIterator* and // EpScanBufferNative. // // NOTE: These classes are not reentrant, and therefore cannot be used // by more than one thread at a time. In actual use, this means // that their use must be synchronized under the device lock. //-------------------------------------------------------------------------- class EpScan { public: // Some scan types have settings which are constant for an entire // Start() ... End() operation. Right now, there are only a few such // settings. So, we just pass them as parameters with defaults. // // But if this grows, we might need to put them in a structure, // or pass them in a separate call. // // pixFmtGeneral - the input pixel format for the color data, // in the "Blend" and "CT" scan types. // pixFmtOpaque - the input pixel format for the color data, // in the "Opaque" scan type. // solidColor - the solid fill color for "*SolidFill" scan types. // The default is chosen to detect bugs. virtual BOOL Start( DpDriver *driver, DpContext *context, DpBitmap *surface, NEXTBUFFERFUNCTION *getBuffer, EpScanType scanType, PixelFormatID pixFmtGeneral = PixelFormat32bppPARGB, PixelFormatID pixFmtOpaque = PixelFormat32bppPARGB, ARGB solidColor = HorridInfraPurpleColor ) { // Common initialization stuff. BlenderConfig[0].ScanType = scanType; BlenderConfig[0].SourcePixelFormat = pixFmtGeneral; // For now, blender 1 is only used for CachedBitmap rendering; // it's the blender for the opaque, "native format" data. BlenderConfig[1].ScanType = EpScanTypeOpaque; BlenderConfig[1].SourcePixelFormat = pixFmtOpaque; CurrentX = 0; CurrentY = 0; DitherOriginX = context->RenderingOriginX; DitherOriginY = context->RenderingOriginY; return TRUE; } virtual VOID End(INT currentWidth) = 0; virtual VOID *GetCurrentBuffer() = 0; virtual BYTE *GetCurrentCTBuffer() = 0; virtual VOID Flush() = 0; // This function processes an entire batch of scans - // it handles multiple pixel formats and combinations // of Blend and Opaque // If a scan class doesn't support it, it returns FALSE. virtual BOOL ProcessBatch( EpScanRecord *batchStart, EpScanRecord *batchEnd, INT minX, INT minY, INT maxX, INT maxY ) { return FALSE; } // The x and y coordinates for the current scanline (blending scanline). // not the current requested next buffer. INT CurrentX; INT CurrentY; // The origin for the dither pattern. INT DitherOriginX; INT DitherOriginY; // "Blender configuration" // // For one Start() ... End() sequence, at most two different scan types are // used, and often there's just one. // So, we allocate two EpAlphaBlender objects, and set them up // appropriately during Start(). // // Right now, the second one is only used for CachedBitmap. But in the // future, it might be used e.g. to mix "solidfill" scans with // "blend" scans for antialiased solid fills. In that case, Start() will // need more parameters to tell it how to set up the blender objects. // // Note: // // In V2, we may want to avoid reinitializing the AlphaBlenders // for every primitive. But that'll take some work - there are many reasons // we might need to reinitialize. It wouldn't be enough to have // an EpAlphaBlender for each scan type (and I wouldn't recommend it // anyway.) // !!! [agodfrey] "EpBlenderConfig" and "BlenderConfig" could do with // better names. But I can't think of any. struct EpBlenderConfig { EpAlphaBlender AlphaBlender; PixelFormatID SourcePixelFormat; EpScanType ScanType; VOID Initialize( PixelFormatID dstFormat, const DpContext *context, const ColorPalette *dstpal, VOID **tempBuffers, BOOL dither16bpp, BOOL useRMW, ARGB solidColor) { AlphaBlender.Initialize( ScanType, dstFormat, SourcePixelFormat, context, dstpal, tempBuffers, dither16bpp, useRMW, solidColor); } }; EpBlenderConfig BlenderConfig[BlenderMax]; // LastBlenderNum: // Used by the flush mechanism in the NextBuffer functions // to figure out which AlphaBlender to use to flush the buffer. INT LastBlenderNum; }; //-------------------------------------------------------------------------- // Scan buffer class // // This class is intended to be used be any drawing code wishing to output // to a scan buffer; callers should not use the EpScan class directly. //-------------------------------------------------------------------------- template class EpScanBufferNative { 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! VOID SetValid(BOOL valid) { Tag = valid ? ObjectTagScanBufferNative : ObjectTagInvalid; } private: DpBitmap *Surface; EpScan *Scan; NEXTBUFFERFUNCTION NextBufferFunction; INT CurrentWidth; public: // noTransparentPixels - TRUE if there will be no transparent pixels. // If you're not sure, set it to FALSE. // // If it's set to TRUE, we'll substitute "Opaque" scan types for "Blend" // scan types - if the pixels are all opaque, they're equivalent, // and "Opaque" is faster. // solidColor - The solid color for *SolidFill scan types. // The default is chosen to detect bugs. EpScanBufferNative( EpScan *scan, DpDriver *driver, DpContext *context, DpBitmap *surface, BOOL noTransparentPixels = FALSE, EpScanType scanType = EpScanTypeBlend, PixelFormatID pixFmtGeneral = PixelFormat32bppPARGB, PixelFormatID pixFmtOpaque = PixelFormat32bppPARGB, ARGB solidColor = HorridInfraPurpleColor ) { if ( noTransparentPixels && (scanType == EpScanTypeBlend)) { scanType = EpScanTypeOpaque; } CurrentWidth = 0; Surface = surface; Scan = scan; SetValid(Scan->Start( driver, context, surface, &NextBufferFunction, scanType, pixFmtGeneral, pixFmtOpaque, solidColor )); } ~EpScanBufferNative() { if (IsValid()) { Scan->End(CurrentWidth); } SetValid(FALSE); // so we don't use a deleted object } // This function processes an entire batch of scans - // it handles multiple pixel formats and combinations // of SourceOver and SourceCopy. // If it's unsupported, it returns FALSE. BOOL ProcessBatch( EpScanRecord *batchStart, EpScanRecord *batchEnd, INT minX, INT minY, INT maxX, INT maxY ) { return Scan->ProcessBatch(batchStart, batchEnd, minX, minY, maxX, maxY); } BOOL IsValid() const { ASSERT((Tag == ObjectTagScanBufferNative) || (Tag == ObjectTagInvalid)); #if DBG if (Tag == ObjectTagInvalid) { WARNING1("Invalid ScanBufferNative"); } #endif return (Tag == ObjectTagScanBufferNative); } // NextBuffer() flushes the previous scan (if there was one) and // returns a pointer to the new buffer. Note that NextBuffer() // will never fail (but the constructor to EpScanBufferNative might // have!). // // blenderNum: // Used when an operation mixes different scan types. // We don't use an enum because the meaning of each blender depends // on the situation. // // At the time of writing, only CachedBitmap uses this - to select // between the regular and opaque scan types. // // Note: The contents of the buffer are not zeroed by NextBuffer(). // Use NextBufferClear() if you want the contents zeroed if // you're doing an accumulation type of operation. // // Note: NextBuffer() may or may not return the same pointer as the // previous NextBuffer() call. T *NextBuffer( INT x, INT y, INT nextWidth, INT blenderNum = 0 ) { ASSERT(IsValid()); T *buffer = (T *)((Scan->*NextBufferFunction)( x, y, nextWidth, CurrentWidth, blenderNum )); CurrentWidth = nextWidth; return buffer; } T *NextBufferClear( INT x, INT y, INT width, INT blenderNum = 0 ) { T *buffer = NextBuffer(x, y, width, blenderNum); GpMemset(buffer, 0, width * sizeof(T)); return buffer; } // !!! [agodfrey]: It would be better to remove the CurrentWidth member, // and have UpdateWidth call a member in the Scan object. // // It would also make this class' NextBuffer implementation less // confusing - it wouldn't mix parameters describing the next scan // with parameters describing the current one. VOID UpdateWidth(INT width) { // The width can only be shrunk: ASSERT(width <= CurrentWidth); CurrentWidth = width; } DpBitmap *GetSurface() { return Surface; } T *GetCurrentBuffer() { return (T *)(Scan->GetCurrentBuffer()); } BYTE *GetCurrentCTBuffer() { return Scan->GetCurrentCTBuffer(); } }; class EpPaletteMap; //-------------------------------------------------------------------------- // Direct access to the bits //-------------------------------------------------------------------------- // [agodfrey] EpScanEngine and EpScanBitmap have some common code. Consider // merging that code into a single class, derived from EpScan, and then // deriving EpScanEngine and EpScanBitmap from it. class EpScanEngine : public EpScan { private: BYTE *Dst; BYTE *Bits; INT Stride; INT PixelSize; // Presumably the pixel size of the destination. DpBitmap * Surface; VOID *Buffers[5]; private: VOID *NextBuffer( INT x, INT y, INT newWidth, INT updateWidth, INT blenderNum ); public: EpScanEngine() {} ~EpScanEngine() {} virtual BOOL Start( DpDriver *driver, DpContext *context, DpBitmap *surface, NEXTBUFFERFUNCTION *getBuffer, EpScanType scanType, PixelFormatID pixFmtGeneral, PixelFormatID pixFmtOpaque , ARGB solidColor ); virtual VOID End(INT updateWidth); virtual VOID* GetCurrentBuffer() { return static_cast(Buffers[3]); } virtual BYTE* GetCurrentCTBuffer() { ASSERT( (BlenderConfig[0].ScanType == EpScanTypeCT) || (BlenderConfig[0].ScanType == EpScanTypeCTSolidFill)); return static_cast(Buffers[4]); } virtual VOID Flush() {} }; //-------------------------------------------------------------------------- // Access to the GpBitmap bits // // This scan interface is used for scan drawing to a GpBitmap object. // The GpBitmap object is the internal representation of a GDI+ bitmap. //-------------------------------------------------------------------------- class EpScanBitmap; typedef VOID (EpScanBitmap::*SCANENDFUNCTION)(INT updateWidth); class EpScanBitmap : public EpScan { private: DpBitmap* Surface; GpBitmap* Bitmap; INT Width; INT Height; BOOL BitmapLocked; BitmapData LockedBitmapData; UINT BitmapLockFlags; VOID* CurrentScan; // only used by NextBufferNative INT PixelSize; // only used by NextBufferNative VOID *Buffers[5]; SCANENDFUNCTION EndFunc; private: VOID *NextBuffer32ARGB( INT x, INT y, INT newWidth, INT updateWidth, INT blenderNum ); VOID *NextBufferNative( INT x, INT y, INT newWidth, INT updateWidth, INT blenderNum ); VOID End32ARGB(INT updateWidth); VOID EndNative(INT updateWidth); public: EpScanBitmap() { Buffers[0] = NULL; BitmapLocked = FALSE; Bitmap = NULL; } ~EpScanBitmap() { FreeData(); } VOID SetBitmap(GpBitmap* bitmap) { Bitmap = bitmap; } VOID FreeData() { if (Buffers[0]) GpFree(Buffers[0]); Buffers[0] = NULL; } virtual BOOL Start( DpDriver *driver, DpContext *context, DpBitmap *surface, NEXTBUFFERFUNCTION *getBuffer, EpScanType scanType, PixelFormatID pixFmtGeneral, PixelFormatID pixFmtOpaque, ARGB solidColor ); virtual VOID End(INT updateWidth); virtual VOID *GetCurrentBuffer() { return static_cast(Buffers[3]); } virtual BYTE* GetCurrentCTBuffer() { ASSERT( (BlenderConfig[0].ScanType == EpScanTypeCT) || (BlenderConfig[0].ScanType == EpScanTypeCTSolidFill)); return static_cast(Buffers[4]); } virtual VOID Flush(); GpBitmap *GetBitmap() { return Bitmap; } }; //-------------------------------------------------------------------------- // Use either GDI or DCI for all scan drawing //-------------------------------------------------------------------------- // MAKE_*WORD_ALIGNED: // Increments the pointer, if necessary, to the next aligned address. // // WARNING: If you use this, you need to remember the original pointer, // so that you can free the memory later. // // "p = MAKE_QWORD_ALIGNED(blah, p)" is a bug. #define MAKE_QWORD_ALIGNED(type, p) (\ reinterpret_cast((reinterpret_cast(p) + 7) & ~7)) #define MAKE_DWORD_ALIGNED(type, p) (\ reinterpret_cast((reinterpret_cast(p) + 3) & ~3)) // Adds the given number of bytes to a pointer #define ADD_POINTER(type, p, increment) (\ reinterpret_cast(reinterpret_cast(p) + (increment))) #define ASSERT_DWORD_ALIGNED(p) ASSERTMSG(!(reinterpret_cast(p) & 3), ("'" #p "' not DWORD aligned")) #define ASSERT_QWORD_ALIGNED(p) ASSERTMSG(!(reinterpret_cast(p) & 7), ("'" #p "' not QWORD aligned")) // The variable-format structure for all batch record types. // Must be stored at a QWORD-aligned location struct EpScanRecord { UINT16 BlenderNum; // Identifies the AlphaBlender to be used to render // the scan. (0 through BlenderMax-1). UINT16 ScanType; // EpScanType explicitly coerced into 2 bytes. INT X; INT Y; INT Width; // Number of pixels to output INT OrgWidth; // The original width when the record was allocated. // (The width may change later, and we need the original // width in order to calculate the positions of // the variable-length records.) // Different scan types have different fields after the header: // 1) EpScanTypeOpaque, EpScanTypeBlend: // A color buffer, of "Width" pixels, in some pixel format. 8-byte aligned. // 2) EpScanTypeCT: // A color buffer, of "Width" pixels, in some pixel format. 8-byte aligned. // A CT coverage buffer, of "Width" bytes. 4-byte aligned. // 3) EpScanTypeCTSolidFill: // A CT coverage buffer, of "Width" bytes. 4-byte aligned. // Return the color buffer, of "Width" pixels. Valid for // EpScanTypeOpaque, EpScanTypeBlend and EpScanTypeCT. VOID *GetColorBuffer() { if (GetScanType() == EpScanTypeCTSolidFill) return NULL; return CalculateColorBufferPosition( this, GetScanType() ); } EpScanType GetScanType() { return static_cast(ScanType); } VOID SetScanType(EpScanType type) { ASSERT(type < (1<(type); } // A safe way to set blenderNum - the cast is protected by an assertion. VOID SetBlenderNum(INT blenderNum) { ASSERT( (blenderNum >= 0) && (blenderNum < BlenderMax)); BlenderNum = static_cast(blenderNum); } // Return the CT buffer, of "Width" pixels. // Valid for EpScanTypeCT and EpScanTypeCTSolidFill only. // // colorFormatSize - the size of a "color buffer" pixel, in bytes. BYTE *GetCTBuffer( INT colorFormatSize ) { EpScanType type = GetScanType(); ASSERT( (type == EpScanTypeCT) || (type == EpScanTypeCTSolidFill)); if (type == EpScanTypeCT) { return CalculateCTBufferPosition( this, type, OrgWidth, colorFormatSize); } else { return CalculateCTBufferPositionCTSolidFill(this); } } // Calculates the position of the next scan record, given enough data // about the current one. // // This is like NextScanRecord, but it doesn't require the "currentRecord" // pointer to point to valid memory. Instead, the necessary data is // passed in parameters. // // Callers can use this to decide whether the record will fit into // available memory. // // currentRecord - points to the "current" record. This doesn't need // to be a valid record, and the memory it points to // doesn't need to be big enough to hold the current // record. Must be QWORD-aligned. // type - the type of record // width - the actual number of pixels // colorFormatSize - the size of a "color buffer" pixel, in bytes. static EpScanRecord *CalculateNextScanRecord( EpScanRecord *currentRecord, EpScanType type, INT width, INT colorFormatSize ) { return InternalCalculateNextScanRecord( currentRecord, type, width, width, colorFormatSize); } // Returns a pointer to the next scan record, based on the current, // valid scan record. // // colorFormatSize - the size of a "color buffer" pixel, in bytes. EpScanRecord *NextScanRecord( INT colorFormatSize ) { return InternalCalculateNextScanRecord( this, GetScanType(), Width, OrgWidth, colorFormatSize); } private: // These functions are 'static' to emphasize that they're usable on // EpScanRecord pointers which don't point to valid memory. // Calculates the position of the next scan record, given enough data // about the current one. // // currentRecord - points to the "current" record. This doesn't need // to be a valid record, and the memory it points to // doesn't need to be big enough to hold the current // record. Must be QWORD-aligned. // type - the type of record // width - the actual number of pixels // orgWidth - the "original" width - the width at the time the // scan was first allocated. Can't be smaller than // 'width'. // colorFormatSize - the size of a "color buffer" pixel, in bytes. static EpScanRecord *InternalCalculateNextScanRecord( EpScanRecord *currentRecord, EpScanType type, INT width, INT orgWidth, INT colorFormatSize ) { ASSERT_QWORD_ALIGNED(currentRecord); EpScanRecord *p; // If width < orgWidth, we can reclaim some of the space at the end. // However, the record positions are based on orgWidth, so // only the final record can be shrunk. // // So, the pattern for the below is: // 1) Get the pointer to the last field, using "orgWidth". // 2) Add the field size, using "width" (not "orgWidth"). // 3) QWORD-align it. switch (type) { case EpScanTypeBlend: case EpScanTypeOpaque: p = ADD_POINTER( EpScanRecord *, CalculateColorBufferPosition(currentRecord, type), width * colorFormatSize); break; case EpScanTypeCT: p = ADD_POINTER( EpScanRecord *, CalculateCTBufferPosition( currentRecord, type, orgWidth, colorFormatSize), width); break; case EpScanTypeCTSolidFill: p = ADD_POINTER( EpScanRecord *, CalculateCTBufferPositionCTSolidFill( currentRecord), width); break; } return MAKE_QWORD_ALIGNED(EpScanRecord *, p); } // Return a pointer to the color buffer. Valid for // EpScanTypeOpaque, EpScanTypeBlend and EpScanTypeCT. // // currentRecord - the "current" record, QWORD-aligned. // type - the type of record static VOID *CalculateColorBufferPosition( EpScanRecord *currentRecord, EpScanType type ) { ASSERT_QWORD_ALIGNED(currentRecord); ASSERT( (type == EpScanTypeOpaque) || (type == EpScanTypeBlend) || (type == EpScanTypeCT)); // Since the pointer is QWORD-aligned, we can do this by adding // the 'QWORD-aligned size' of this structure. // // The "regular" way would be to add the size and then // QWORD-align the pointer. But this is more efficient, because // qwordAlignedSize is a compile-time constant. const INT qwordAlignedSize = (sizeof(EpScanRecord) + 7) & ~7; return ADD_POINTER(VOID *, currentRecord, qwordAlignedSize); } // Return a pointer to the CT buffer. // Valid for EpScanTypeCT only. // // currentRecord - the "current" record, QWORD-aligned. // type - the type of record // width - the number of pixels // colorFormatSize - the size of a "color buffer" pixel, in bytes. static BYTE *CalculateCTBufferPosition( EpScanRecord *currentRecord, EpScanType type, INT width, INT colorFormatSize ) { ASSERT_QWORD_ALIGNED(currentRecord); ASSERT(type == EpScanTypeCT); BYTE *p = ADD_POINTER( BYTE *, CalculateColorBufferPosition(currentRecord, type), colorFormatSize * width); return MAKE_DWORD_ALIGNED(BYTE *, p); } // Return a pointer to the CT buffer, of "Width" pixels. // Valid for EpScanTypeCTSolidFill only. // // currentRecord - the "current" record, QWORD-aligned. // type - the type of record // width - the number of pixels // colorFormatSize - the size of a "color buffer" pixel, in bytes. static BYTE *CalculateCTBufferPositionCTSolidFill( EpScanRecord *currentRecord ) { ASSERT_QWORD_ALIGNED(currentRecord); BYTE *p = reinterpret_cast(currentRecord+1); ASSERT_DWORD_ALIGNED(p); return p; } }; // Queue data structures: enum GdiDciStatus { GdiDciStatus_TryDci, // We're to try using DCI, but it hasn't been // initialized yet (which if it fails will // cause us to fall back to GDI) GdiDciStatus_UseDci, // We successfully initialized DCI, so use it // for all drawing GdiDciStatus_UseGdi, // Use only GDI for all drawing }; // Minimum buffer size for the DCI drawing queue: #define SCAN_BUFFER_SIZE 64*1024 class EpScanGdiDci : public EpScan { private: // Persistent state: GdiDciStatus Status; // Class status GpDevice* Device; // Associate device; must exist for // the lifetime of this object DpContext* Context; // Points to the context object related // to any records sitting in the batch. // May be invalid if the batch is // empty. DpBitmap* Surface; // Similarly points to the surface // related to any records sitting in // the batch. BOOL IsPrinter; // Is the destination a printer? DCISURFACEINFO *DciSurface; // DCI surface state, allocated by // DCI INT PixelSize; // Pixel size, in bytes for the current // batch record VOID *Buffers[5]; // Temporary scan buffers // Cache objects: HRGN CacheRegionHandle; // Region we hang on to so that we // don't have to re-create on every // query RGNDATA *CacheRegionData; // Clipping data allocation (may be // NULL) INT CacheDataSize; RECT *EnumerateRect; INT EnumerateCount; // Bounds accumulation: INT MinX; INT MaxX; INT MinY; INT MaxY; // Note that YMax is 'inclusive' // Global offset for the batch processing. INT BatchOffsetX; INT BatchOffsetY; // For *SolidFill scan types, we need to record the solid color passed // to Start(). We use it when we call EpAlphaBlender::Initialize() ARGB SolidColor; // Enumeration information: VOID *BufferMemory; // Points to start of buffer memory // block EpScanRecord *BufferStart; // Points to queue buffer start. // QWORD-aligned. EpScanRecord *BufferEnd; // Points to end of queue buffer EpScanRecord *BufferCurrent; // Points to current queue position INT BufferSize; // Size of queue buffer in bytes private: VOID *NextBuffer( INT x, INT y, INT newWidth, INT updateWidth, INT blenderNum ); VOID LazyInitialize(); VOID EmptyBatch(); VOID DownloadClipping_Dci(HDC hdc, POINT *clientOffset); VOID ProcessBatch_Dci(HDC hdc, EpScanRecord* bufferStart, EpScanRecord* bufferEnd); BOOL Reinitialize_Dci(); VOID LazyInitialize_Dci(); EpScanRecord* FASTCALL DrawScanRecords_Dci( BYTE* bits, INT stride, EpScanRecord* record, EpScanRecord* endRecord, INT xOffset, INT yOffset, INT xClipLeft, INT yClipTop, INT xClipRight, INT yClipBottom ); VOID ProcessBatch_Gdi( HDC hdc, EpScanRecord* bufferStart, EpScanRecord* bufferEnd ); // Perform SrcOver blend using GDI for 32bpp (P)ARGB source pixels only. VOID SrcOver_Gdi_ARGB( HDC destinationHdc, HDC dibSectionHdc, VOID *dibSection, EpScanRecord *scanRecord ); public: // Pass TRUE for 'tryDci' if it's okay to try using DCI for our rendering; // otherwise only use GDI: EpScanGdiDci(GpDevice *device, BOOL tryDci = FALSE); ~EpScanGdiDci(); virtual BOOL Start( DpDriver *driver, DpContext *context, DpBitmap *surface, NEXTBUFFERFUNCTION *getBuffer, EpScanType scanType, PixelFormatID pixFmtGeneral, PixelFormatID pixFmtOpaque, ARGB solidColor ); virtual VOID End(INT updateWidth); virtual VOID* GetCurrentBuffer() { return BufferCurrent->GetColorBuffer(); } virtual BYTE* GetCurrentCTBuffer() { // We assume that in ClearType cases, // there is only one scan type for the Start()...End() sequence ASSERT(BufferCurrent->BlenderNum == 0); // This should only be called for ClearType scan types ASSERT( (BlenderConfig[0].ScanType == EpScanTypeCT) || (BlenderConfig[0].ScanType == EpScanTypeCTSolidFill)); ASSERT(BlenderConfig[0].ScanType == BufferCurrent->GetScanType()); return BufferCurrent->GetCTBuffer( GetPixelFormatSize(BlenderConfig[0].SourcePixelFormat) >> 3 ); } virtual VOID Flush(); // This function processes an entire batch of scans - // it handles multiple pixel formats and combinations // of SourceOver and SourceCopy. virtual BOOL ProcessBatch( EpScanRecord *batchStart, EpScanRecord *batchEnd, INT minX, INT minY, INT maxX, INT maxY ); }; #endif // !_SCAN_HPP