Sample Code
Windows Driver Samples/ MSPLOT Plotter Driver Sample/ C++/ plotter/ output.c/
/*++ Copyright (c) 1990-2003 Microsoft Corporation Module Name: output.c Abstract: This module contains common plotter output functions to the spooler and printer. Author: 15-Nov-1993 Mon 19:36:04 updatee clean up / update / re-write / debugging information 30-Nov-1993 Tue 19:47:16 updated update coordinate system during send_page 21-Dec-1993 Tue 15:49:10 updated organizied, and restructre pen cache, remove SendDefaultPalette() [Environment:] GDI Device Driver - Plotter. [Notes:] Revision History: --*/ #include "precomp.h" #pragma hdrstop #define DBG_PLOTFILENAME DbgOutput #define DBG_SENDTRAILER 0x00000001 #define DBG_FLUSHBUF 0x00000002 #define DBG_FINDCACHEDPEN 0x00000004 #define DBG_CREATEPAL 0x00000008 #define DBG_FILLTYPE 0x00000010 #define DBG_PENUM 0x00000020 #define DBG_GETFINALCOLOR 0x00000040 #define DBG_SETCLIPWINDOW 0x00000080 #define DBG_OUTPUTXYPARMS 0x00000100 #define DBG_PAGE_HEADER 0x00000200 #define DBG_BESTPEN 0x00000400 #define DBG_BESTPEN_ALL 0x00000800 DEFINE_DBGVAR(0); #define MIN_POSTER_SIZE (1024L * 1024L * 12L) #if DBG static LPSTR pHSFillTypeName[] = { "HS_HORIZONTAL", "HS_VERTICAL", "HS_FDIAGONAL", "HS_BDIAGONAL", "HS_CROSS", "HS_DIAGCROSS", "HS_SOLIDCLR", "HS_FT_USER_DEFINED" }; #endif // // Local #defines and data structures only used in this file // // Define, GDI fill types and the HPGL2 code used to simulate them // static const LPSTR pHSFillType[] = { "3,#d,0", // HS_HORIZONTAL 0 /* ----- */ "3,#d,90", // HS_VERTICAL 1 /* ||||| */ "3,#d,135", // HS_FDIAGONAL 2 /* \\\\\ */ "3,#d,45", // HS_BDIAGONAL 3 /* ///// */ "4,#d,0", // HS_CROSS 4 /* +++++ */ "4,#d,45", // HS_DIAGCROSS 5 /* xxxxx */ "" , // HS_SOLIDCLR 6 "11,#d", // HS_FT_USER_DEFINED 7 }; // // HTPal tells the engine what formats we support for halftoning // // ulHTOutputFormat = HT_FORMAT_4BPP // ulPrimaryOrder = PRIMARY_ORDER_CBA // flHTFlags &= ~HT_FLAG_OUTPUT_CMY // PALENTRY HTPal[] = { // // B G R F //----------------------------- { 0x00, 0x00, 0x00, 0x00 }, // 0:K { 0x00, 0x00, 0xFF, 0x00 }, // 1:R { 0x00, 0xFF, 0x00, 0x00 }, // 2:G { 0x00, 0xFF, 0xFF, 0x00 }, // 3:Y { 0xFF, 0x00, 0x00, 0x00 }, // 4:B { 0xFF, 0x00, 0xFF, 0x00 }, // 5:M { 0xFF, 0xFF, 0x00, 0x00 }, // 6:C { 0xFF, 0xFF, 0xFF, 0x00 } // 7:W }; // // Define the RGB colors for the pen indices. see inc\plotgpc.h for color // assignment for the each PC_IDX_XXXX // PALENTRY PlotPenPal[PC_IDX_TOTAL] = { // // B G R F //------------------------------------------ { 255,255,255, 0 }, // PC_IDX_WHITE { 0, 0, 0, 0 }, // PC_IDX_BLACK { 0, 0,255, 0 }, // PC_IDX_RED { 0,255, 0, 0 }, // PC_IDX_GREEN { 0,255,255, 0 }, // PC_IDX_YELLOW { 255, 0, 0, 0 }, // PC_IDX_BLUE { 255, 0,255, 0 }, // PC_IDX_MAGENTA { 255,255, 0, 0 }, // PC_IDX_CYAN { 0,128,255, 0 }, // PC_IDX_ORANGE { 0,192,255, 0 }, // PC_IDX_BROWN { 255, 0,128, 0 } // PC_IDX_VIOLET }; #define PE_BASE_BITS 6 #define PE_BASE_NUM (DWORD)(1 << PE_BASE_BITS) #define PE_TERM_ADDER ((PE_BASE_NUM * 3) - 1) #define DEF_FORMATSTR_CHAR '#' #define TOTAL_LOCKED_PENS COUNT_ARRAY(HTPal) #define PEF_CACHE_LOCKED 0x01 typedef struct _PENENTRY { WORD Next; WORD PenNumber; PALENTRY PalEntry; } PENENTRY, FAR *PPENENTRY; #define PCF_HAS_LOCKED_PENS 0x01 typedef struct _PENCACHE { WORD Head; BYTE Flags; BYTE peFlags; WORD CurCount; WORD MaxCount; PENENTRY PenEntries[1]; } PENCACHE, FAR *PPENCACHE; #define INTENSITY(r,g,b) (BYTE)(((WORD)((r) * 30) + \ (WORD)((g) * 59) + \ (WORD)((b) * 11)) / 100) #define SAME_PPALENTRY(p1,p2) (((p1)->R == (p2)->R) && \ ((p1)->G == (p2)->G) && \ ((p1)->B == (p2)->B)) BYTE HPRGBGamma2p0[] = { 0, // 0 16, // 1 23, // 2 28, // 3 32, // 4 36, // 5 39, // 6 42, // 7 45, // 8 48, // 9 50, // 10 53, // 11 55, // 12 58, // 13 60, // 14 62, // 15 64, // 16 66, // 17 68, // 18 70, // 19 71, // 20 73, // 21 75, // 22 77, // 23 78, // 24 80, // 25 81, // 26 83, // 27 84, // 28 86, // 29 87, // 30 89, // 31 90, // 32 92, // 33 93, // 34 94, // 35 96, // 36 97, // 37 98, // 38 100, // 39 101, // 40 102, // 41 103, // 42 105, // 43 106, // 44 107, // 45 108, // 46 109, // 47 111, // 48 112, // 49 113, // 50 114, // 51 115, // 52 116, // 53 117, // 54 118, // 55 119, // 56 121, // 57 122, // 58 123, // 59 124, // 60 125, // 61 126, // 62 127, // 63 128, // 64 129, // 65 130, // 66 131, // 67 132, // 68 133, // 69 134, // 70 135, // 71 135, // 72 136, // 73 137, // 74 138, // 75 139, // 76 140, // 77 141, // 78 142, // 79 143, // 80 144, // 81 145, // 82 145, // 83 146, // 84 147, // 85 148, // 86 149, // 87 150, // 88 151, // 89 151, // 90 152, // 91 153, // 92 154, // 93 155, // 94 156, // 95 156, // 96 157, // 97 158, // 98 159, // 99 160, // 100 160, // 101 161, // 102 162, // 103 163, // 104 164, // 105 164, // 106 165, // 107 166, // 108 167, // 109 167, // 110 168, // 111 169, // 112 170, // 113 170, // 114 171, // 115 172, // 116 173, // 117 173, // 118 174, // 119 175, // 120 176, // 121 176, // 122 177, // 123 178, // 124 179, // 125 179, // 126 180, // 127 181, // 128 181, // 129 182, // 130 183, // 131 183, // 132 184, // 133 185, // 134 186, // 135 186, // 136 187, // 137 188, // 138 188, // 139 189, // 140 190, // 141 190, // 142 191, // 143 192, // 144 192, // 145 193, // 146 194, // 147 194, // 148 195, // 149 196, // 150 196, // 151 197, // 152 198, // 153 198, // 154 199, // 155 199, // 156 200, // 157 201, // 158 201, // 159 202, // 160 203, // 161 203, // 162 204, // 163 204, // 164 205, // 165 206, // 166 206, // 167 207, // 168 208, // 169 208, // 170 209, // 171 209, // 172 210, // 173 211, // 174 211, // 175 212, // 176 212, // 177 213, // 178 214, // 179 214, // 180 215, // 181 215, // 182 216, // 183 217, // 184 217, // 185 218, // 186 218, // 187 219, // 188 220, // 189 220, // 190 221, // 191 221, // 192 222, // 193 222, // 194 223, // 195 224, // 196 224, // 197 225, // 198 225, // 199 226, // 200 226, // 201 227, // 202 228, // 203 228, // 204 229, // 205 229, // 206 230, // 207 230, // 208 231, // 209 231, // 210 232, // 211 233, // 212 233, // 213 234, // 214 234, // 215 235, // 216 235, // 217 236, // 218 236, // 219 237, // 220 237, // 221 238, // 222 238, // 223 239, // 224 240, // 225 240, // 226 241, // 227 241, // 228 242, // 229 242, // 230 243, // 231 243, // 232 244, // 233 244, // 234 245, // 235 245, // 236 246, // 237 246, // 238 247, // 239 247, // 240 248, // 241 248, // 242 249, // 243 249, // 244 250, // 245 250, // 246 251, // 247 251, // 248 252, // 249 252, // 250 253, // 251 253, // 252 254, // 253 254, // 254 255 // 255 }; LONG BestMatchNonWhitePen( PPDEV pPDev, LONG R, LONG G, LONG B ) /*++ Routine Description: This functions locates the best match of a current pen given an RGB color. Arguments: pPDev - Pointer to our PDEV R - Red color G - Green color B - Blue color Return Value: LONG - Pen Index, this function assumes 0 is always white and 1 up to the max are the rest of the pens. Author: 08-Feb-1994 Tue 00:23:36 created 23-Jun-1994 Thu 14:00:00 updated Updated for non-white pen match Revision History: --*/ { PPENDATA pPenData; PALENTRY PenPalEntry; LONG LeastDiff; WORD ColorIdx; UINT Count; UINT RetIdx; UINT i; PLOTDBGBLK(PALENTRY RetPal) if (IS_RASTER(pPDev)) { PLOTASSERT(0, "BestMatchNonWhitePen: This is not PEN plotter", !IS_RASTER(pPDev), 0); return(0); } if (!(pPenData = (PPENDATA)pPDev->pPlotGPC->Pens.pData)) { PLOTWARN(("BestMatchNonWhitePen: pPlotGPC->Pens.pData=NULL")); return(0); } if (!(Count = (UINT)pPDev->pPlotGPC->Pens.Count)) { PLOTWARN(("BestMatchNonWhitePen: pPlotGPC->Pens.Count=0")); return(0); } PLOTDBGBLK(RetPal.R = 255) PLOTDBGBLK(RetPal.G = 255) PLOTDBGBLK(RetPal.B = 255) RetIdx = 0; LeastDiff = (3 * (256 * 256)); for (i = 1; i < Count; i++, pPenData++) { if (((ColorIdx = pPenData->ColorIdx) < PC_IDX_TOTAL) && (ColorIdx != PC_IDX_WHITE)) { LONG Temp; LONG Diff; PenPalEntry = PlotPenPal[ColorIdx]; Temp = R - (LONG)((DWORD)PenPalEntry.R); Diff = Temp * Temp; Temp = G - (LONG)((DWORD)PenPalEntry.G); Diff += Temp * Temp; Temp = B - (LONG)((DWORD)PenPalEntry.B); Diff += Temp * Temp; PLOTDBG(DBG_BESTPEN_ALL, ("BestMatchNonWhitePen: %2ld: (%03ld:%03ld:%03ld) DIF=%ld", i, (DWORD)PenPalEntry.R, (DWORD)PenPalEntry.G, (DWORD)PenPalEntry.B, Diff)); if (Diff < LeastDiff) { RetIdx = i; PLOTDBGBLK(RetPal = PenPalEntry) if (!(LeastDiff = Diff)) { // // We have exact match // break; } } } } if (!RetIdx) { PLOTWARN(("BestMatchNonWhitePen: Cannot find one make it WHITE")); } PLOTDBG(DBG_BESTPEN, ("BestMatchNonWhitePen: RGB=%02lx:%02lx:%02lx [%ld/%ld]=%02lx:%02lx:%02lx", R, G, B, (LONG)RetIdx, (LONG)pPDev->pPlotGPC->Pens.Count, (LONG)RetPal.R, (LONG)RetPal.G, (LONG)RetPal.B)); return((LONG)RetIdx); } VOID GetFinalColor( PPDEV pPDev, _Inout_ PPALENTRY pPalEntry ) /*++ Routine Description: This function modifies the input RGB color based on Grayscale and GAMMA Arguments: pPDev - Our PDEV pPalEntry - Pointer to the PALENTRY of interest Return Value: VOID but pPalEntry will be modified Author: 12-Apr-1994 Tue 14:03:37 created Revision History: --*/ { PALENTRY PalEntry = *pPalEntry; // // Do Gamma correction first // PalEntry.R = HPRGBGamma2p0[PalEntry.R]; PalEntry.G = HPRGBGamma2p0[PalEntry.G]; PalEntry.B = HPRGBGamma2p0[PalEntry.B]; // // If were in GRAYSCALE mode we need to convert the color to grayscale // if (pPDev->PlotDM.dm.dmColor != DMCOLOR_COLOR) { PalEntry.R = PalEntry.G = PalEntry.B = (BYTE)INTENSITY(PalEntry.R, PalEntry.G, PalEntry.B); } PLOTDBG(DBG_GETFINALCOLOR, ("GetFinalColor: %hs RGB=%03ld:%03ld:%03ld -> Gamma=%03ld:%03ld:%03ld", (pPDev->PlotDM.dm.dmColor != DMCOLOR_COLOR) ? "MONO" : "COLOR", (DWORD)pPalEntry->R, (DWORD)pPalEntry->G, (DWORD)pPalEntry->B, (DWORD)PalEntry.R, (DWORD)PalEntry.G, (DWORD)PalEntry.B)); // // Save it back and return // *pPalEntry = PalEntry; } LONG FindCachedPen( PPDEV pPDev, _Inout_ PPALENTRY pPalEntry ) /*++ Routine Description: This function searhes the PenCache and returns the pen number if it is found. If it is not found, it will add the new pen to the cache and delete one if needed. Finally it returns the pen back to the caller. Arguments: pPDev - Pointer to the device PDEV pPalEntry - Pointer to the PALENTRY for the specified RGB to locate. Return Value: DWORD - a Pen number, if an error occurred 0 is returned Author: 21-Dec-1993 Tue 12:42:31 updated re-write to make it as one pass search and adding. and commented 30-Nov-1993 Tue 23:19:04 created Revision History: --*/ { PPENCACHE pPenCache; PPENENTRY pPenStart; PPENENTRY pCurPen; PPENENTRY pPrevPen; PPENENTRY pPrevDelPen; PALENTRY PalEntry; LONG Count; PLOTASSERT(1, "FindCahcedPen: The pPalEntry = NULL", pPalEntry, 0); if (!IS_RASTER(pPDev)) { // // Since this is the index type of palette, the PalEntry should be // also passed as index in the BGR's B component // Count = (LONG)RGB(pPalEntry->B, pPalEntry->G, pPalEntry->R); PLOTDBG(DBG_FINDCACHEDPEN, ("FindCachedPen: PEN PLOTTER=%ld", Count)); if (Count > (LONG)((DWORD)pPDev->pPlotGPC->Pens.Count)) { PLOTERR(("FindCachedPen: INVALID Pen Color Index = %ld, Set to 1", Count)); Count = 1; } return(Count); } // // If we dont have a pen cache, nothing we can do but return an error. // if (!(pPenCache = (PPENCACHE)pPDev->pPenCache)) { PLOTERR(("FindCahcedPen: The pPenCache=NULL?")); return(0); } // // Make sure we set the flag correctly, the current PENENTRY flag is // located in peFlags field // PalEntry = *pPalEntry; PalEntry.Flags = pPenCache->peFlags; // // Convert to final color through gamma/gray scale // GetFinalColor(pPDev, &PalEntry); pPenStart = &(pPenCache->PenEntries[0]); pCurPen = pPenStart + pPenCache->Head; pPrevPen = pPrevDelPen = NULL; Count = (LONG)pPenCache->CurCount; while (Count--) { if (SAME_PPALENTRY(&(pCurPen->PalEntry), &PalEntry)) { PLOTDBG(DBG_FINDCACHEDPEN, ("FindCachedPen: Found Pen #%ld=%02lx:%02lx:%02lx, Linkes=%ld", (DWORD)pCurPen->PenNumber, (DWORD)PalEntry.R, (DWORD)PalEntry.G, (DWORD)PalEntry.B, (DWORD)(pPenCache->CurCount - Count))); // // Found the color for that pen, exit this loop since we are done. // break; } // // Keep track of a pen that makes sense to delete in case we need // to delete an entry in order to add the new one that is not found. // If the entry was used for something longer term, it would be locked // and thus would not be a candidate for removal. // if (!(pCurPen->PalEntry.Flags & PEF_CACHE_LOCKED)) { // // If this pen is not locked then it must ok to delete if we need to // pPrevDelPen = pPrevPen; } pPrevPen = pCurPen; pCurPen = pPenStart + pCurPen->Next; } // // If Count != -1 then we must have found a match, so we are done. // if (Count == -1) { // // We did not find the pen, so add it to the cache, remember if the // cache is full we must delete the last UNLOCKED entry // if (pPenCache->CurCount >= pPenCache->MaxCount) { // // Now delete the last un-locked entry, and add the new item to // that deleted entry // if (!(pPrevPen = pPrevDelPen)) { // // This is very strange, the last unlocked is the head?, this // is only possible if we have MaxCount = TOTAL_LOCKED_PENS + 1 // PLOTDBG(DBG_FINDCACHEDPEN, ("FindCachedPen: ??? Last unlocked pen is Linked List Head")); pCurPen = pPenStart + pPenCache->Head; } else { pCurPen = pPenStart + pPrevPen->Next; } PLOTASSERT(1, "Pen #%ld is a LOCKED pen", !(pCurPen->PalEntry.Flags & PEF_CACHE_LOCKED), (DWORD)pCurPen->PenNumber); PLOTDBG(DBG_FINDCACHEDPEN, ("FindCachedPen: REPLACE Pen #%ld=%02lx:%02lx:%02lx -> %02lx:%02lx:%02lx [%ld]", (DWORD)pCurPen->PenNumber, (DWORD)pCurPen->PalEntry.R, (DWORD)pCurPen->PalEntry.G, (DWORD)pCurPen->PalEntry.B, (DWORD)PalEntry.R, (DWORD)PalEntry.G, (DWORD)PalEntry.B, (DWORD)(pCurPen - pPenStart))); } else { // // Increment the cached pen count // ++(pPenCache->CurCount); PLOTDBG(DBG_FINDCACHEDPEN, ("FindCachedPen: ADD New Pen #%ld=%02lx:%02lx:%02lx [%ld/%ld]", (DWORD)pCurPen->PenNumber, (DWORD)PalEntry.R, (DWORD)PalEntry.G, (DWORD)PalEntry.B, pPenCache->CurCount, pPenCache->MaxCount)); } // // set the pen color in the cache and output the commands to the // plotter to add or change the current pen color setting // pCurPen->PalEntry = PalEntry; OutputFormatStr(pPDev, "PC#d,#d,#d,#d;", (LONG)pCurPen->PenNumber, (LONG)PalEntry.R, (LONG)PalEntry.G, (LONG)PalEntry.B); } // // Now move the pCurPen to the head of the linked list // if (pPrevPen) { // // Only move the current pen to the link list head if not already so // PLOTDBG(DBG_FINDCACHEDPEN, ("FindCachedPen: MOVE Pen #%ld to Linked List Head [%ld --> %ld]", (DWORD)pCurPen->PenNumber, (DWORD)pPenCache->Head, (DWORD)(pCurPen - pPenStart))); pPrevPen->Next = pCurPen->Next; pCurPen->Next = pPenCache->Head; pPenCache->Head = (WORD)(pCurPen - pPenStart); } return(pCurPen->PenNumber); } BOOL PlotCreatePalette( PPDEV pPDev ) /*++ Routine Description: This function creates a pen cache. It initializes the cache accordingly Arguments: pPDev - Pointer to the PDEV Return Value: BOOL to indicate operation Author: 30-Nov-1993 Tue 23:23:17 created 21-Dec-1993 Tue 12:40:30 updated Simplify version re-write 23-Dec-1993 Thu 20:16:52 updated Add NP number of pens command back to be able to use HPGL/2 palette Revision History: --*/ { if (!pPDev->pPlotGPC->MaxPens) { PLOTWARN(("PlotCreatePalette: Device MaxPens = 0")); } else if (IS_RASTER(pPDev)) { PPENCACHE pPenCache; PPENENTRY pPenEntry; DWORD dw; UINT Index; // // If this is the first time around then go ahead and alloc the memory // for our pen pallete cache. If the memory is already allocated then // we don't need to worry about it. // PLOTASSERT(1, "PlotCreatePalette: device has too few pens [%ld] available", pPDev->pPlotGPC->MaxPens > TOTAL_LOCKED_PENS, (DWORD)pPDev->pPlotGPC->MaxPens); dw = (DWORD)(sizeof(PENCACHE) + sizeof(PENENTRY) * (pPDev->pPlotGPC->MaxPens - 1)); if (pPDev->pPenCache == NULL) { PLOTDBG(DBG_CREATEPAL, ("PlotCreatePalette: Create NEW Palette")); pPDev->pPenCache = (LPVOID)LocalAlloc(LPTR, dw); } else { PLOTDBG(DBG_CREATEPAL, ("PlotCreatePalette: Re-Initialized Palette")); } if (pPenCache = (PPENCACHE)pPDev->pPenCache) { // // 1. Clear everything to zero // 2. Set MaxCount to the amount specified in the GPC // 3. Initialize the whole linked list as a linear list with // the pen number set // 4. Make last index link to 0xffff to prevent us from using it // ZeroMemory(pPenCache, dw); pPenCache->MaxCount = (WORD)pPDev->pPlotGPC->MaxPens; for (Index = 0, pPenEntry = &(pPenCache->PenEntries[0]); Index < (UINT)pPenCache->MaxCount; Index++, pPenEntry++) { pPenEntry->Next = (WORD)(Index + 1); pPenEntry->PenNumber = (WORD)Index; } pPenCache->PenEntries[pPenCache->MaxCount-1].Next = (WORD)0xffff; // // Before we add any pen palette we will establish the size of the // HPGL/2 Pen palette, and reset every pen back to our // standard which is used by gdi and the halftone Eng. (= 0.26mm wide) // OutputFormatStr(pPDev, "NP#d", (LONG)pPenCache->MaxCount); // // Now, add the entries we know we must keep around and make sure // they get locked. // PLOTDBG(DBG_CREATEPAL, ("PlotCreatePalette: add all %ld standard locked pens", TOTAL_LOCKED_PENS)); pPenCache->peFlags = PEF_CACHE_LOCKED; for (Index = 0; Index < (LONG)TOTAL_LOCKED_PENS; Index++) { FindCachedPen(pPDev, (PPALENTRY)&HTPal[Index]); } // // Now set the flag telling us the cache contains locked pens, and // unlock the cache. // pPenCache->Flags |= PCF_HAS_LOCKED_PENS; pPenCache->peFlags = 0; } else { PLOTERR(("PlotCreatePalette: LocalAlloc(PENCACHE=%ld) failed", dw)); return(FALSE); } } else { pPDev->BrightestPen = BestMatchNonWhitePen(pPDev, 255, 255, 255); PLOTDBG(DBG_CREATEPAL, ("PlotCreatePalette: Pen Plotter's Closest NON-WHITE PEN Index=ld", pPDev->BrightestPen)); } return(TRUE); } UINT AllocOutBuffer( PPDEV pPDev ) /*++ Routine Description: This function allocates a buffer to be used for caching output data specific to this job. This keeps us from making calls to EngWritePrinter with very small amounts of data. Arguments: pPDev - Pointer to our pdev Return Value: UINT count of how many bytes were allocated. If the buffer was already allocated, return the size. If an error occured (allocating memory) return 0. Author: 16-Nov-1993 Tue 07:39:46 created Revision History: --*/ { if ((!(pPDev->pOutBuffer)) && (!(pPDev->pOutBuffer = (LPBYTE)LocalAlloc(LPTR, OUTPUT_BUFFER_SIZE + 16)))) { PLOTERR(("CreateOutputBuffer: LocalAlloc(OutBuffer=%ld) failed", OUTPUT_BUFFER_SIZE)); return(0); } pPDev->cbBufferBytes = 0; return(OUTPUT_BUFFER_SIZE); } VOID FreeOutBuffer( PPDEV pPDev ) /*++ Routine Description: This function frees the allocated output buffer Arguments: pPDev - pointer to the PDEV Return Value: VOID Author: 16-Nov-1993 Tue 07:46:16 created Revision History: --*/ { if (pPDev->pOutBuffer) { LocalFree((HLOCAL)pPDev->pOutBuffer); pPDev->pOutBuffer = NULL; } pPDev->cbBufferBytes = 0; } BOOL FlushOutBuffer( PPDEV pPDev ) /*++ Routine Description: This function flushes the current contents of the output buffer by writing the contents to the target device via EngWritePrinter. Arguments: pPDev - Pointer to the PDEV Return Value: BOOL to indicate the result (TRUE == success) Author: 16-Nov-1993 Tue 09:56:27 created Revision History: 14-Sep-1999 Tue 17:36:08 updated Remove Checking for EngAbort(), this check in user mode will somehow return true at end of job and cause all output got cut off. --*/ { if (PLOT_CANCEL_JOB(pPDev)) { return(FALSE); } if (pPDev->cbBufferBytes) { DWORD cbWritten; if (pPDev->cbBufferBytes > OUTPUT_BUFFER_SIZE) { PLOTASSERT(1, "OutputBytes: pPDev->cbBufferBytes (%ld) OVERRUN", pPDev->cbBufferBytes <= OUTPUT_BUFFER_SIZE, pPDev->cbBufferBytes); pPDev->cbBufferBytes = OUTPUT_BUFFER_SIZE; pPDev->Flags |= PDEVF_CANCEL_JOB; return(FALSE); } // // We need to be concerned with the job getting cancelled from // either the app or the spooler. // If the job is cancelled from the client app and we were printing // direct then EngCheckAbort() should return true. // If the job was cancelled from the spooler (ie printman) then // the write printer will fail. // Anywhere we do prolonged processing we need to look and verify // we break out of any loop if the job is cancelled. Currently // we do this in OutputBitmapSection, DoPolygon, DoRectFill, and // DrvTextOut when we are enuming our STROBJ glyphs // if ((!WritePrinter(pPDev->hPrinter, pPDev->pOutBuffer, pPDev->cbBufferBytes, &cbWritten)) || (cbWritten != pPDev->cbBufferBytes)) { // // Set the cancel flag in our pdev; // PLOTDBG(DBG_FLUSHBUF, ("FlushOutBuffer: WritePrinter() failure")); pPDev->Flags |= PDEVF_CANCEL_JOB; return(FALSE); } #if 0 if (EngCheckAbort(pPDev->pso)) { PLOTDBG(DBG_FLUSHBUF, ("FlushOutBuffer: EngCheckAbort return TRUE")); pPDev->Flags |= PDEVF_CANCEL_JOB; return(FALSE); } #endif // // Reset to zero for clearing the buffer // pPDev->cbBufferBytes = 0; } return(TRUE); } LONG OutputBytes( PPDEV pPDev, _In_reads_bytes_(cBuf) LPBYTE pBuf, LONG cBuf ) /*++ Routine Description: This function output cBuf bytes from pBuf, by copying them into the output buffer (and flushing if required). Arguments: pPDev - Pointer to the PDEV pBuf - Pointer to the buffer location cBuf - Size of the buffer in bytes Return Value: LONG size of the buffer output, if < 0 then error occurred Author: 16-Nov-1993 Tue 08:18:41 created 07-Dec-1993 Tue 17:21:53 updated re-write, so it do bulk copy rather than byte by byte Revision History: --*/ { LPBYTE pOrgBuf = pBuf; LONG cSize; while (cBuf > 0) { if (PLOT_CANCEL_JOB(pPDev)) { return(-1); } if (pPDev->cbBufferBytes >= OUTPUT_BUFFER_SIZE) { if (!FlushOutBuffer(pPDev)) { return(-1); } } if ((cSize = OUTPUT_BUFFER_SIZE - pPDev->cbBufferBytes) > cBuf) { cSize = cBuf; } CopyMemory(pPDev->pOutBuffer + pPDev->cbBufferBytes, pBuf, cSize); pPDev->cbBufferBytes += cSize; pBuf += cSize; cBuf -= cSize; } return((LONG)(pBuf - pOrgBuf)); } LONG OutputString( PPDEV pPDev, LPCSTR pszStr ) /*++ Routine Description: This function outputs a null terminated string to the destination buffer Arguments: pPDev - Pointer to the PDEV pszStr - Pointer to the NULL terminated string Return Value: LONG size of the string output, if < 0 then error occurred Author: 16-Nov-1993 Tue 08:20:55 created 07-Dec-1993 Tue 17:21:37 updated re-write to call OutputBytes() Revision History: --*/ { return(OutputBytes(pPDev, (LPBYTE)pszStr, (LONG)strlen(pszStr))); } _Ret_range_(0, cchStr16 - 1) _Success_(return != 0) LONG LONGToASCII( LONG Number, _Out_writes_bytes_to_(cchStr16, return+1) LPSTR pStr16, size_t cchStr16, BYTE NumType ) /*++ Routine Description: This function convert a LONG number to ANSI ASCII Arguments: Number - 32-bit LONG number pStr16 - minimum 2 bytes to store the converted result Return Value: LONG - size of number string returned. This is one less than the number of bytes written to the output buffer. (last \0 not included). 0 - If the buffer is less than 2 bytes. If the buffer is not big enough to hold the ASCII text and the \0. For example, if converting 12345, buffer should be at least 6 bytes. If buffer is not big enough, we may partially fill it and still return 0. In such a case, buffer may not be null terminated. Author: 16-Nov-1993 Tue 08:24:07 created 16-Feb-1994 Wed 10:50:55 updated Updated so upper case character treated as polyline encoded mode Revision History: --*/ { LPSTR pOrgStr = pStr16; LPSTR pNumStr; BYTE NumStr[16]; // maximum for LONG are 1 sign + 10 digits // The incoming buffer needs to be at least 2 bytes long. if ( cchStr16 < 2 ) { return 0; } if ((NumType >= 'A') && (NumType <= 'Z')) { // // Polyline encoded number // PLOTDBG(DBG_PENUM, ("LONGToASCII: Convert PE Number %ld, Base=%ld", Number, PE_BASE_NUM)); if (Number < 0) { Number = 1 - Number - Number; } else { Number += Number; } while (Number >= PE_BASE_NUM) { if (cchStr16 > 1) { *pStr16++ = (BYTE)(63 + (Number & (PE_BASE_NUM - 1))); cchStr16--; } else { return 0; } Number >>= PE_BASE_BITS; } if (cchStr16 > 1) { *pStr16++ = (BYTE)(PE_TERM_ADDER + Number); cchStr16--; } else { return 0; } PLOTDBG(DBG_PENUM, ("LONGToASCII: LAST DIGIT: Number=%ld, [%02lx]", Number, Number + PE_TERM_ADDER)); } else { if (Number < 0) { Number = -Number; if (cchStr16 > 1) { *pStr16++ = '-'; cchStr16--; } else { return 0; } } pNumStr = NumStr; do { _Analysis_assume_(pNumStr < NumStr + 16); *pNumStr++ = (CHAR)((Number % 10) + '0'); } while (Number /= 10); // // Now reverse the digits // while (pNumStr > NumStr ) { if (cchStr16 > 1) { *pStr16++ = *(--pNumStr); cchStr16--; } else { return 0; } } } *pStr16 = '\0'; // null terminated return((UINT)(pStr16 - pOrgStr)); } LONG OutputXYParams( PPDEV pPDev, _In_reads_(cPoints) PPOINTL pPtXY, _In_opt_ PPOINTL pPtOffset, _In_opt_ PPOINTL pPtCurPos, UINT cPoints, UINT MaxCurPosSkips, BYTE NumType ) /*++ Routine Description: This function outputs long numbers, and inserts a ',' between numbers (other than the last number) Arguments: pPDev - Pointer to the PDEV pPtXY - Pointer to the array of POINTL data structure for the XY pair pPtOffset - Points to the POINTL Offset to be add to the pPtXY, NULL if no offset need to be added pPtCurPos - Points to the POINTL Current position in <<DEVICE>> coordinates to be substracted, this is used to output XY pair as relative model, if the pointer is NULL then absolute model is used, if the pointer is passed and return sucessful then the final XY position is written back to this POINTL cPoints - count of total pPtXY pairs need to be output MaxCurPosSkips - How many points before the current position will be updated NumType - one of 'l', 'L', 'F', 'f', 'p', 'P', 'D', 'd' Return Value: if sucessful it return the total number of bytes sent to the destination, if negative an error occurred Author: 17-Feb-1994 Thu 10:13:09 created Revision History: --*/ { LONG Size = 0; POINTL ptNow; POINTL ptTmp; POINTL ptOffset; POINTL ptCurPos = {0}; UINT XCount; UINT YCount; UINT XIdxStart; UINT CurPosSkips; BOOL NeedComma; BYTE XBuf[16]; BYTE YBuf[16]; NeedComma = (BOOL)((NumType >= 'a') && (NumType <= 'z')); if (pPtOffset) { ptOffset = *pPtOffset; } else { ptOffset.x = ptOffset.y = 0; } XIdxStart = 0; if (pPtCurPos) { ptCurPos = *pPtCurPos; } else if (!NeedComma) { XBuf[0] = '='; XIdxStart = 1; } CurPosSkips = MaxCurPosSkips; while (cPoints--) { ptNow.x = pPtXY->x + ptOffset.x; ptNow.y = pPtXY->y + ptOffset.y; ++pPtXY; XCount = XIdxStart; YCount = 0; switch (NumType) { case 'L': case 'l': ptNow.x = LTODEVL(pPDev, ptNow.x); ptNow.y = LTODEVL(pPDev, ptNow.y); break; case 'F': case 'f': ptNow.x = FXTODEVL(pPDev, ptNow.x); ptNow.y = FXTODEVL(pPDev, ptNow.y); break; case 'D': case 'd': break; case 'P': case 'p': if (ptNow.x >= 0) { XBuf[XCount++] = '+'; } if (ptNow.y >= 0) { YBuf[YCount++] = '+'; } break; default: PLOTASSERT(1,"OutputXYParams: Invalid Format type '%c'",0,NumType); return(-2); } if (pPtCurPos) { ptTmp = ptNow; ptNow.x -= ptCurPos.x; ptNow.y -= ptCurPos.y; if (!(--CurPosSkips)) { ptCurPos = ptTmp; CurPosSkips = MaxCurPosSkips; } if ((ptNow.x == 0) && (ptNow.y == 0) && (MaxCurPosSkips == 1)) { // // We do not need to move to the same position here // PLOTDBG(DBG_OUTPUTXYPARMS, ("OutputXYParms: ABS=(%ld, %ld), REL=(%ld, %ld) --- SKIP", ptTmp.x, ptTmp.y, ptNow.x, ptNow.y)); continue; } else { PLOTDBG(DBG_OUTPUTXYPARMS, ("OutputXYParms: ABS=(%ld, %ld), REL=(%ld, %ld)", ptTmp.x, ptTmp.y, ptNow.x, ptNow.y)); } } else { PLOTDBG(DBG_OUTPUTXYPARMS, ("OutputXYParms: ABS=(%ld, %ld)", ptNow.x, ptNow.y)); } XCount += LONGToASCII(ptNow.x, &XBuf[XCount], CCHOF(XBuf) - XCount, NumType); YCount += LONGToASCII(ptNow.y, &YBuf[YCount], CCHOF(YBuf) - YCount, NumType); if (NeedComma) { XBuf[XCount++] = ','; if (cPoints) { YBuf[YCount++] = ','; } } if ((OutputBytes(pPDev, XBuf, XCount) < 0) || (OutputBytes(pPDev, YBuf, YCount) < 0)) { return(-1); } Size += (XCount + YCount); } // // return back the new current position. // if (pPtCurPos) { *pPtCurPos = ptCurPos; } return(Size); } LONG OutputLONGParams( PPDEV pPDev, PLONG pNumbers, UINT cNumber, BYTE NumType ) /*++ Routine Description: This functions outputs LONG numbers and inserts a ',' between all but the last numbers. Arguments: pPDev - Pointer to the PDEV pNumbers - Point to the LONG arrary of numbers cNumber - Total number to be output NumType - one of 'l', 'L', 'F', 'f', 'p', 'P', 'D', 'd' Return Value: The return value is the total number of bytes sent to the destination. If negative an error occurred. Author: 16-Nov-1993 Tue 09:37:32 created 16-Feb-1994 Wed 10:49:16 updated Updated to add upper case of format char as in polyline encoded mode Revision History: --*/ { LONG Size = 0; LONG Count; LONG Num; BOOL NeedComma; BYTE NumBuf[16]; NeedComma = (BOOL)((NumType >= 'a') && (NumType <= 'z')); while (cNumber--) { Num = *pNumbers++; Count = 0; switch (NumType) { case 'L': case 'l': Num = LTODEVL(pPDev, Num); break; case 'F': case 'f': Num = FXTODEVL(pPDev, Num); break; case 'D': case 'd': break; case 'P': case 'p': if (Num >= 0) { NumBuf[Count++] = '+'; } break; default: PLOTASSERT(1,"OutputLONGParams: Invalid Format type '%c'",0,NumType); return(-2); } Count += LONGToASCII(Num, &NumBuf[Count], CCHOF(NumBuf) - Count, NumType); if ((NeedComma) && (cNumber)) { NumBuf[Count++] = ','; } if (OutputBytes(pPDev, NumBuf, Count) < 0) { return(-1); } Size += Count; } return(Size); } // // The following #define code is used by the OutputFormatStrDELI() and // OutputFormatStr() functions, it was easier to maintain this way // // 16-Feb-1994 Wed 10:50:24 updated // Updated to add upper case of format char as in polyline encoded mode // #define DO_FORMATSTR(pPDev, NumFormatChar, pszFormat) \ { \ LPSTR pLast; \ va_list vaList; \ LONG Num; \ LONG Size; \ LONG Count; \ BYTE bCur; \ BYTE NumBuf[16]; \ \ va_start(vaList, pszFormat); \ \ Size = 0; \ pLast = (LPSTR)pszFormat; \ \ while (bCur = *pszFormat++) { \ \ if (bCur == NumFormatChar) { \ \ if (Count = (LONG)(pszFormat - pLast - 1)) { \ \ Size += Count; \ \ if (OutputBytes(pPDev, pLast, Count) < 0) { \ \ return(-1); \ } \ } \ \ Num = va_arg(vaList, LONG); \ Count = 0; \ \ switch (bCur = *pszFormat++) { \ \ case 'L': \ case 'l': \ \ Num = LTODEVL(pPDev, Num); \ break; \ \ case 'F': \ case 'f': \ \ Num = FXTODEVL(pPDev, Num); \ break; \ \ case 'D': \ case 'd': \ \ break; \ \ case 'P': \ case 'p': \ \ if (Num >= 0) { \ \ NumBuf[Count++] = '+'; \ } \ \ break; \ \ default: \ \ PLOTASSERT(1,"Invalid Format type '%c'",0,*(pszFormat-1)); \ return(-2); \ } \ \ Count += LONGToASCII(Num, &NumBuf[Count], sizeof(NumBuf) - Count, bCur); \ Size += Count; \ pLast = (LPSTR)pszFormat; \ \ if (OutputBytes(pPDev, NumBuf, Count) < 0) { \ \ return(-1); \ } \ } \ } \ \ if (Count = (LONG)(pszFormat - pLast - 1)) { \ \ Size += Count; \ \ if (OutputBytes(pPDev, pLast, Count) < 0) { \ \ return(-1); \ } \ } \ \ va_end(vaList); \ \ return(Size); \ } LONG cdecl OutputFormatStrDELI( PPDEV pPDev, CHAR NumFormatChar, LPCSTR pszFormat, ... ) /*++ Routine Description: This function outputs a string and optionally replaces '#' with LONG numbers passed on the stack Arguments: pPDev - Pointer to the PDEV NumFormatChar - the character in the pszFormat string will be replaced by LONG numbers on the stack pszFormat - a ASCII string, only 'NumFormatChar' will be replaced with a 32-bit LONG number on the stack Return Value: LONG size of the string write to the output buffer, a negative number indicates an error Author: 16-Nov-1993 Tue 07:56:18 created Revision History: --*/ { DO_FORMATSTR(pPDev, NumFormatChar, pszFormat); } LONG cdecl OutputFormatStr( PPDEV pPDev, LPCSTR pszFormat, ... ) /*++ Routine Description: This function outputs the passed stack variables with the default format. Arguments: pPDev - Pointer to the PDEV pszFormat - a ASCII string, only '#' will be replaced with a 32-bit LONG number on the stack Return Value: LONG size of the string written to the output buffer, a negative number siginals an error Author: 16-Nov-1993 Tue 07:56:18 created Revision History: --*/ { DO_FORMATSTR(pPDev, DEF_FORMATSTR_CHAR, pszFormat); } BOOL OutputCommaSep( PPDEV pPDev ) /*++ Routine Description: This funtion outputs a ',' (comma ) to the destination Arguments: pPDev - Pointer to the PDEV Return Value: BOOL Author: 16-Nov-1993 Tue 10:46:42 created Revision History: --*/ { return(OutputString(pPDev, ",") == 1); } VOID ClearClipWindow( PPDEV pPDev ) /*++ Routine Description: This function clears the input window (plotter CLIP RECT) in the target device using the correct HPGL2 command. Arguments: pPDev - Pointer to the PDEV data structure Return Value: VOID Author: 30-Nov-1993 Tue 19:56:09 updated style clean up, commented Revision History: --*/ { if (pPDev->Flags & PDEVF_HAS_CLIPRECT) { pPDev->Flags &= ~PDEVF_HAS_CLIPRECT; OutputString(pPDev, "IW;"); } } VOID SetClipWindow( PPDEV pPDev, PRECTL pClipRectl ) /*++ Routine Description: This function sets the device clip rect to prevent objects drawn outside the rect from appearing on the target surface. The target device is doing the actual clipping in this case. Arguments: pPDev - Pointer to the PDEV data structure pClipRectl - Pointer to the RECTL data structure which defines the clipping rect to set inside the target device in engine units. Return Value: VOID Author: 30-Nov-1993 Tue 19:56:45 created style clean up, commented Revision History: --*/ { POINTL ptlPlot; SIZEL szlRect; RECTL rclCurClip; ptlPlot.x = LTODEVL(pPDev, pClipRectl->left); ptlPlot.y = LTODEVL(pPDev, pClipRectl->top ); szlRect.cx = LTODEVL(pPDev, pClipRectl->right) - ptlPlot.x; szlRect.cy = LTODEVL(pPDev, pClipRectl->bottom ) - ptlPlot.y; if ((szlRect.cx) && (szlRect.cy)) { // // Here we try to be intelligent about sending down coordinates thate // are too small and would adversly affect the target device. // if (szlRect.cx < (LONG)pPDev->MinLToDevL) { PLOTWARN(("SetClipWindow: cxRect=%ld < MIN=%ld, Make it as MIN", szlRect.cx, (LONG)pPDev->MinLToDevL)); szlRect.cx = (LONG)pPDev->MinLToDevL ; } if (szlRect.cy < (LONG)pPDev->MinLToDevL) { PLOTWARN(("SetClipWindow: cyRect=%ld < MIN=%ld, Make it as MIN", szlRect.cy, (LONG)pPDev->MinLToDevL)); szlRect.cy = (LONG)pPDev->MinLToDevL ; } } else { PLOTWARN(( "SetClipWindow: Clipping out EVERYTHING....")); } rclCurClip.right = (rclCurClip.left = ptlPlot.x) + szlRect.cx; rclCurClip.bottom = (rclCurClip.top = ptlPlot.y) + szlRect.cy; if ((pPDev->Flags & PDEVF_HAS_CLIPRECT) && (pPDev->rclCurClip.left == rclCurClip.left) && (pPDev->rclCurClip.top == rclCurClip.top) && (pPDev->rclCurClip.right == rclCurClip.right) && (pPDev->rclCurClip.bottom == rclCurClip.bottom)) { PLOTDBG(DBG_SETCLIPWINDOW, ("SetClipWindow: PP%ld, (%ld, %ld)-(%d, %ld) *CACHED*", pPDev->Flags & PDEVF_PP_CENTER ? 0 : 1, rclCurClip.left, rclCurClip.top, rclCurClip.right, rclCurClip.bottom)); } else { PLOTDBG(DBG_SETCLIPWINDOW, ("SetClipWindow: PP%ld, (%ld, %ld)-(%d, %ld)", pPDev->Flags & PDEVF_PP_CENTER ? 0 : 1, rclCurClip.left, rclCurClip.top, rclCurClip.right, rclCurClip.bottom)); pPDev->rclCurClip = rclCurClip; pPDev->Flags |= PDEVF_HAS_CLIPRECT; if (pPDev->Flags & PDEVF_PP_CENTER) { --rclCurClip.right; --rclCurClip.bottom; } OutputFormatStr(pPDev, "IW#d,#d,#d,#d", rclCurClip.left, // LL x rclCurClip.bottom, // LL y rclCurClip.right, // UR x rclCurClip.top); // UR y } } VOID SetPixelPlacement( PPDEV pPDev, UINT SetMode ) /*++ Routine Description: This function sets the pixel placement to the center or edge. This defines if a pixel is drawn at the intersection of the vertical and horizontal coordinates, or on the edge. Arguments: pPDev - Pointer to the PDEV data structure SetMode - SPP_MODE_CENTER (Intersection of pixel GRID) or SPP_MODE_EDGE (non intersection of the pixel GRID) SPP_FORCE_SET, force to reset regardless of the current cached mode Return Value: VOID Author: 25-Jan-1996 Thu 13:33:15 created Revision History: --*/ { UINT CurMode; CurMode = (pPDev->Flags & PDEVF_PP_CENTER) ? SPP_MODE_CENTER : SPP_MODE_EDGE; if ((SetMode & SPP_FORCE_SET) || ((SetMode & SPP_MODE_MASK) != CurMode)) { // // Set it now // if ((SetMode & SPP_MODE_MASK) == SPP_MODE_CENTER) { pPDev->Flags |= PDEVF_PP_CENTER; OutputString(pPDev, "PP0"); } else { pPDev->Flags &= ~PDEVF_PP_CENTER; OutputString(pPDev, "PP1"); } if (pPDev->Flags & PDEVF_HAS_CLIPRECT) { RECTL rclCurClip = pPDev->rclCurClip; // // Make sure we really reset the clipping rectangle // --(pPDev->rclCurClip.left); SetClipWindow(pPDev, &rclCurClip); } } } BOOL SetRopMode( PPDEV pPDev, DWORD Rop ) /*++ Routine Description: This function sends the Rop3 mode to the plotter if it is different than the current setting. Arguments: pPDev - Pointer to the PDEV Rop - a Rop3 code Return Value: TRUE/FALSE Author: 27-Jan-1994 Thu 18:55:54 created Revision History: --*/ { if (pPDev->LastDevROP != (WORD)(Rop &= 0xFF)) { pPDev->LastDevROP = (WORD)Rop; if (Rop == 0xCC) { return(OutputFormatStr(pPDev, "MC0;")); } else { return(OutputFormatStr(pPDev, "MC1,#d;", (LONG)Rop)); } } return(TRUE); } BOOL SetHSFillType( PPDEV pPDev, DWORD HSFillTypeIndex, LONG lParam ) /*++ Routine Description: This function set the fill type on the plotter only if not already so Arguments: pPDev - Pointer to our PDEV HSFillTypeIdx - a index to pHSFillType, if invalid or out of range then a solid color HS_SOLIDCLR is assumed lParam - a Long parameter to be sent with FT Return Value: TRUE/FALSE Author: 27-Jan-1994 Thu 19:00:21 created Revision History: --*/ { WORD Index; PLOTASSERT(1, "SetFillType: Invalid HSFillTypeIndex=%ld passed, set to SOLID", HSFillTypeIndex <= HS_FT_USER_DEFINED, HSFillTypeIndex); if (HSFillTypeIndex > HS_FT_USER_DEFINED) { HSFillTypeIndex = HS_DDI_MAX; } if ((Index = (WORD)HSFillTypeIndex) == (WORD)HS_FT_USER_DEFINED) { if ((lParam < 0) || (lParam > RF_MAX_IDX)) { PLOTASSERT(1, "SetFillType: User defined ID [%ld] invalid, make it 1", (lParam > 0) && (lParam <= RF_MAX_IDX), lParam); lParam = 1; } Index += (WORD)lParam; } if (Index != pPDev->LastFillTypeIndex) { PLOTDBG(DBG_FILLTYPE, ("SetFillType: Change %hs (%ld) -> %hs (%ld)", (pPDev->LastFillTypeIndex > HS_FT_USER_DEFINED) ? pHSFillTypeName[HS_FT_USER_DEFINED] : pHSFillTypeName[pPDev->LastFillTypeIndex], (pPDev->LastFillTypeIndex > HS_FT_USER_DEFINED) ? pPDev->LastFillTypeIndex - HS_FT_USER_DEFINED : lParam, (Index > HS_FT_USER_DEFINED) ? pHSFillTypeName[HS_FT_USER_DEFINED] : pHSFillTypeName[Index], (Index > HS_FT_USER_DEFINED) ? Index - HS_FT_USER_DEFINED : lParam)); pPDev->LastFillTypeIndex = Index; if ((!OutputString(pPDev, "FT")) || (!OutputFormatStr(pPDev, pHSFillType[HSFillTypeIndex], lParam))) { return(FALSE); } } else { PLOTDBG(DBG_FILLTYPE, ("SetFillType: HSFillType is SAME = %hs", (Index > HS_FT_USER_DEFINED) ? pHSFillTypeName[HS_FT_USER_DEFINED] : pHSFillTypeName[Index])); } return(TRUE); } BOOL SendPageHeader( PPDEV pPDev ) /*++ Routine Description: This function sends the initialization data to the device for each new page. Correct coordinate system and scaling is set. Arguments: pPDev - Pointer to the PDEV data structure for the page Return Value: BOOL Author: 30-Nov-1993 Tue 19:53:13 updated Re-write and update to correct system for the NT 29-Nov-1993 Mon 23:55:43 updated Re-write 24-Nov-1993 Wed 22:38:10 updated Using CurForm to replace the pform and PAPER_DIM 06-Jan-1994 Thu 00:21:17 updated Update for SPLTOPLOTUNITS() macro 15-Feb-1994 Tue 09:59:34 updated Set physical position and anchor corner after command is sent 18-Mar-1994 Fri 12:58:24 updated add ptlRTLCAP to zero at Page Reset 24-May-1994 Tue 00:59:17 updated SC command should range from 0 to DEVSIZE - 1 Revision History: --*/ { PPLOTGPC pPlotGPC; LONG xMin; LONG xMax; LONG yMin; LONG yMax; // // Compute minimum required pel size in PLOTDPI from RASTER DPI // // pPDev->MinLToDevL = (WORD)DIVRNDUP(__PLOT_DPI, _CURR_DPI); // pPDev->MinLToDevL = (WORD)LTODEVL(pPDev, 1); PLOTDBG(DBG_PAGE_HEADER, ("SendPageHeader: MinLToDevL=LTODEVL(1)=%ld", pPDev->MinLToDevL)); // // Speedy access // pPlotGPC = pPDev->pPlotGPC; // // First, output the Init string that the pPlotGPC has. The PCD file is // responsible for all initialization upto and including the IN command. // if ((pPlotGPC->InitString.pData) && (pPlotGPC->InitString.SizeEach)) { OutputBytes(pPDev, (LPBYTE)pPlotGPC->InitString.pData, (LONG)pPlotGPC->InitString.SizeEach); } // // DMRES_DRAFT (-1) // DMRES_LOW (-2) // DMRES_MEDIUM (-3) // DMRES_HIGH (-4) // // Assume BEST quality // xMax = 100; switch (pPDev->PlotDM.dm.dmPrintQuality) { case DMRES_DRAFT: xMax = 0; break; case DMRES_HIGH: xMax = 100; break; default: switch (pPlotGPC->MaxQuality) { case 2: xMax = 0; break; case 3: xMax = 50; break; default: xMax = 34; break; } if (pPDev->PlotDM.dm.dmPrintQuality == DMRES_MEDIUM) { xMax = 100 - xMax; } break; } OutputFormatStr(pPDev, "QL#d", xMax); // // PS: This command tells the target device what the hard clip limits should // be. The target device will adjust the command we send if its beyond // the real hard clip limits. Always send CY (lenght) first then CX // (width) // // RO: Only sent to rotate the target device coordinate system if the // PlotForm.Flags is set accordinly. This is because HPGL2 always // assumes the LONGER side sent using the PS command is X in the // standard coordinate system. Because of this behavior we may have // to swap X and Y in order to correct the coordinate system. // // IP: This command defines where the users's unit origin and extent is. // We set this so that the origin and extend is exactly the printable // rectangle related to the HARD CLIP LIMITS (not the paper/form size) // // SC: This defines the user unit scaling. Currently we are 1:1 but use // this command to flip the X or Y origin so we have the same // coordinate system as GDI. // // ALL PlotForm UNITS are in 1/1000mm or Windows 2000, Windows XP, // Windows Server 2003 spooler forms units. // // // If we support transparent mode we want to make sure its off to begin // with, because the driver assumes its off. // if (IS_TRANSPARENT(pPDev)) { OutputString( pPDev, "TR0;"); } OutputFormatStr(pPDev, "ROPS#d,#d", SPLTOPLOTUNITS(pPlotGPC, pPDev->PlotForm.PlotSize.cy), SPLTOPLOTUNITS(pPlotGPC, pPDev->PlotForm.PlotSize.cx)); PLOTDBG(DBG_PAGE_HEADER, ("SendPageHeader: ROPS%ld,%ld%hs", SPLTOPLOTUNITS(pPlotGPC, pPDev->PlotForm.PlotSize.cy), SPLTOPLOTUNITS(pPlotGPC, pPDev->PlotForm.PlotSize.cx), (pPDev->PlotForm.Flags & PFF_ROT_COORD_L90) ? "RO90" : "")); if (pPDev->PlotForm.Flags & PFF_ROT_COORD_L90) { OutputString(pPDev, "RO90"); } // // Compute the scaling amount and direction, if FLIP_X_COORD or a // FLIP_Y_COORD flags are set then we need to flip the scale in X or Y // direction. // #if 1 xMin = xMax = pPDev->HorzRes - 1; yMin = yMax = pPDev->VertRes - 1; #else xMin = xMax = SPLTOPLOTUNITS(pPlotGPC, pPDev->PlotForm.LogExt.cx) - 1; yMin = yMax = SPLTOPLOTUNITS(pPlotGPC, pPDev->PlotForm.LogExt.cy) - 1; #endif if (pPDev->PlotForm.Flags & PFF_FLIP_X_COORD) { xMax = 0; } else { xMin = 0; } if (pPDev->PlotForm.Flags & PFF_FLIP_Y_COORD) { yMax = 0; } else { yMin = 0; } // // IP - to set the p1/p2 // SC - to scale it (only used to flip the HPGL/2 coordinate) // AC - anchor point to default (0, 0) // OutputFormatStr(pPDev, "IP#d,#d,#d,#dSC#d,#d,#d,#dAC", SPLTOPLOTUNITS(pPlotGPC, pPDev->PlotForm.LogOrg.x), SPLTOPLOTUNITS(pPlotGPC, pPDev->PlotForm.LogOrg.y), SPLTOPLOTUNITS(pPlotGPC, (pPDev->PlotForm.LogOrg.x + pPDev->PlotForm.LogExt.cx)) - 1, SPLTOPLOTUNITS(pPlotGPC, (pPDev->PlotForm.LogOrg.y + pPDev->PlotForm.LogExt.cy)) - 1, xMin, xMax, yMin, yMax); PLOTDBG(DBG_PAGE_HEADER, ("SendPageHeader: IP%ld,%ld,%ld,%ldSC%ld,%ld,%ld,%ldAC", SPLTOPLOTUNITS(pPlotGPC, pPDev->PlotForm.LogOrg.x), SPLTOPLOTUNITS(pPlotGPC, pPDev->PlotForm.LogOrg.y), SPLTOPLOTUNITS(pPlotGPC, (pPDev->PlotForm.LogOrg.x + pPDev->PlotForm.LogExt.cx)) - 1, SPLTOPLOTUNITS(pPlotGPC, (pPDev->PlotForm.LogOrg.y + pPDev->PlotForm.LogExt.cy)) - 1, xMin, xMax, yMin, yMax)); // // Set RTL CAP back to zero, this is true after a EscE is sent // pPDev->ptlRTLCAP.x = pPDev->ptlRTLCAP.y = pPDev->ptlAnchorCorner.x = pPDev->ptlAnchorCorner.y = 0; pPDev->PenWidth.Integer = pPDev->PenWidth.Decimal = 0; // // Reset pen position to (0,0) // OutputString(pPDev, "PA0,0"); if ((IS_COLOR(pPDev)) && (IS_RASTER(pPDev))) { // // !!!Work around some color device limitations in order to make // TR/ROP function correctly. // OutputString(pPDev, "PC1,255,0,0PC2,255,255,255SP1PD99,0SP2PD0,0PU"); } // // Create the pallete, this will send out the pens as needed // if (!PlotCreatePalette(pPDev)) { PLOTERR(("DrvEnableSurface: PlotCreatePalette() failed.")); return(FALSE); } // // Reset PW to 0 // OutputString(pPDev, "WU0PW0"); if (IS_RASTER(pPDev)) { // // If we are in poster mode, set up for it now. // if (pPDev->PlotDM.Flags & PDMF_PLOT_ON_THE_FLY) { xMin = SPLTOENGUNITS(pPDev, pPDev->PlotForm.PlotSize.cx); yMin = SPLTOENGUNITS(pPDev, pPDev->PlotForm.PlotSize.cy); xMax = GetBmpDelta(HTBMPFORMAT(pPDev), xMin); yMax = xMax * yMin; PLOTDBG(DBG_PAGE_HEADER, ("SendPageHeader: ** POSTER MODE *** Scan=%ld bytes x cy (%ld) = %ld bytes", xMax, yMin, yMax)); if (yMax <= MIN_POSTER_SIZE) { pPDev->PlotDM.Flags &= ~PDMF_PLOT_ON_THE_FLY; PLOTDBG(DBG_PAGE_HEADER, ("SendPageHeader: Size <= %ld bytes, Turn OFF Poster Mode", MIN_POSTER_SIZE)); } } OutputFormatStr(pPDev, ";\033%0A\033*t#dR\033*v1N\033&a#dN\033%0B", pPDev->pPlotGPC->RasterXDPI, (pPDev->PlotDM.Flags & PDMF_PLOT_ON_THE_FLY) ? 1 : 0); } // // Whole surface can be drawn to // ClearClipWindow(pPDev); SetPixelPlacement(pPDev, SPP_FORCE_SET | SPP_MODE_EDGE); return(TRUE); } BOOL SendPageTrailer( PPDEV pPDev ) /*++ Routine Description: This function does any end of page commands, takes multiple copies into account, and ejects the page. Arguments: pPDev - Pointer to PDEV data structure Return Value: TRUE if sucessful FALSE if failed. Author: 15-Feb-1994 Tue 09:56:58 updated I move the physical position setting to the SendPageHeader 30-Nov-1993 Tue 21:42:21 updated clean up style, commented, Updated Revision History: --*/ { // // Store the pen back to the carousel and advance full page // OutputString(pPDev, "PUSPPG;"); // // Check to see if were doing multiple copies and send them if we are // if (pPDev->PlotDM.dm.dmCopies > 1) { OutputFormatStr(pPDev, "RP#d;", (LONG)pPDev->PlotDM.dm.dmCopies - 1); } // // Flush the output buffer. // return(FlushOutBuffer(pPDev)); }
Our Services
-
What our customers say about us?
Read our customer testimonials to find out why our clients keep returning for their projects.
View Testimonials