/*++ Copyright (c) 1996 Microsoft Corporation Module Name: custsize.c Abstract: Parser functions for handling custom page size feature Environment: Windows NT PostScript driver Revision History: 03/20/97 -davidx- Created it. --*/ #include "lib.h" #include "ppd.h" BOOL BFixupCustomSizeDataFeedDirection( PUIINFO pUIInfo, PPPDDATA pPpdData, PCUSTOMSIZEDATA pCSData ) /*++ Routine Description: Validate the requested paper feed direction parameter Fix up any inconsistency if necessary Arguments: pPpdData - Points to PPDDATA structure pCSData - Specifies custom page size parameters Return Value: TRUE if we can find a feeding direction to fit the custom page size. FALSE otherwise. Note: See Figure 3 on page 109 of PPD 4.3 spec for more details. --*/ #define ORIENTATION_AVAILABLE(iOrient) (dwFlags & (1 << (iOrient))) #define FIXUP_FEEDDIRECTION(iMainOrient, iAltOrient, wAltFeedDirection) \ { \ if (! ORIENTATION_AVAILABLE(iMainOrient)) \ { \ pCSData->wFeedDirection = \ ORIENTATION_AVAILABLE(iAltOrient) ? \ (wAltFeedDirection) : \ MAX_FEEDDIRECTION; \ } \ } { static const DWORD adwMasks[4] = { 0x1, 0x3, 0x7, 0xf }; DWORD dwFlags; BOOL bXGreaterThanY; BOOL bShortEdgeFirst; LONG lVal; WORD wFeedDirectionSave; // // Figure out which custom page size orientations are supported // dwFlags is DWORD value whose lower-order 4 bits are interpreted as flags: // If orientation N is supported, then bit 1 << N will be set // dwFlags = 0xf; if ((lVal = MINCUSTOMPARAM_ORIENTATION(pPpdData)) > 3) dwFlags = 0; else if (lVal > 0) dwFlags &= ~adwMasks[lVal - 1]; if ((lVal = MAXCUSTOMPARAM_ORIENTATION(pPpdData)) < 3) dwFlags &= adwMasks[lVal]; wFeedDirectionSave = pCSData->wFeedDirection; bXGreaterThanY = (pCSData->dwX > pCSData->dwY); // // First try to fit within the current feeding direction. // switch (pCSData->wFeedDirection) { case SHORTEDGEFIRST: if (bXGreaterThanY) { // orientation 0 (or 2) FIXUP_FEEDDIRECTION(0, 2, SHORTEDGEFIRST_FLIPPED); } else { // orientation 1 (or 3) FIXUP_FEEDDIRECTION(1, 3, SHORTEDGEFIRST_FLIPPED); } break; case SHORTEDGEFIRST_FLIPPED: if (bXGreaterThanY) { // orientation 2 (or 0) FIXUP_FEEDDIRECTION(2, 0, SHORTEDGEFIRST); } else { // orientation 3 (or 1) FIXUP_FEEDDIRECTION(3, 1, SHORTEDGEFIRST); } break; case LONGEDGEFIRST: if (bXGreaterThanY) { // orientation 1 (or 3) FIXUP_FEEDDIRECTION(1, 3, LONGEDGEFIRST_FLIPPED); } else { // orientation 0 (or 2) FIXUP_FEEDDIRECTION(0, 2, LONGEDGEFIRST_FLIPPED); } break; case LONGEDGEFIRST_FLIPPED: if (bXGreaterThanY) { // orientation 3 (or 1) FIXUP_FEEDDIRECTION(3, 1, LONGEDGEFIRST); } else { // orientation 2 (or 0) FIXUP_FEEDDIRECTION(2, 0, LONGEDGEFIRST); } break; } // // If the paper feed direction is not valid, we'll automatically // pick one here (default to long-edge-first if possible). This // should always change Long to Short, or Short to Long. // if (pCSData->wFeedDirection >= MAX_FEEDDIRECTION) { if (bXGreaterThanY) { if (ORIENTATION_AVAILABLE(1)) pCSData->wFeedDirection = LONGEDGEFIRST; else if (ORIENTATION_AVAILABLE(3)) pCSData->wFeedDirection = LONGEDGEFIRST_FLIPPED; else if (ORIENTATION_AVAILABLE(0)) pCSData->wFeedDirection = SHORTEDGEFIRST; else // (ORIENTATION_AVAILABLE(2)) pCSData->wFeedDirection = SHORTEDGEFIRST_FLIPPED; } else { if (ORIENTATION_AVAILABLE(0)) pCSData->wFeedDirection = LONGEDGEFIRST; else if (ORIENTATION_AVAILABLE(2)) pCSData->wFeedDirection = LONGEDGEFIRST_FLIPPED; else if (ORIENTATION_AVAILABLE(1)) pCSData->wFeedDirection = SHORTEDGEFIRST; else // (ORIENTATION_AVAILABLE(3)) pCSData->wFeedDirection = SHORTEDGEFIRST_FLIPPED; } } bShortEdgeFirst = (pCSData->wFeedDirection == SHORTEDGEFIRST || pCSData->wFeedDirection == SHORTEDGEFIRST_FLIPPED); if ( (!bShortEdgeFirst && !LONGEDGEFIRST_SUPPORTED(pUIInfo, pPpdData)) || (bShortEdgeFirst && !SHORTEDGEFIRST_SUPPORTED(pUIInfo, pPpdData))) { // // The other feeding direction we picked doesn't fit either, so we // have to stick with the original feeding direction. // pCSData->wFeedDirection = wFeedDirectionSave; // // Check the availability of orientations and flip the feed direction if necessary // if ((pCSData->wFeedDirection == LONGEDGEFIRST || pCSData->wFeedDirection == SHORTEDGEFIRST) && !(ORIENTATION_AVAILABLE(0) || ORIENTATION_AVAILABLE(1))) { pCSData->wFeedDirection = (pCSData->wFeedDirection == LONGEDGEFIRST) ? LONGEDGEFIRST_FLIPPED : SHORTEDGEFIRST_FLIPPED; } else if ((pCSData->wFeedDirection == LONGEDGEFIRST_FLIPPED || pCSData->wFeedDirection == SHORTEDGEFIRST_FLIPPED) && !(ORIENTATION_AVAILABLE(2) || ORIENTATION_AVAILABLE(3))) { pCSData->wFeedDirection = (pCSData->wFeedDirection == LONGEDGEFIRST_FLIPPED) ? LONGEDGEFIRST : SHORTEDGEFIRST; } return FALSE; } else return TRUE; } BOOL BValidateCustomPageSizeData( IN PRAWBINARYDATA pRawData, IN OUT PCUSTOMSIZEDATA pCSData ) /*++ Routine Description: Validate the specified custom page size parameters, and Fix up any inconsistencies found. Arguments: pRawData - Points to raw binary printer description data pCSData - Specifies the custom page size parameters to be validate Return Value: TRUE if the custom page size parameters are valid, FALSE otherwise. If FALSE is returned, custom page size parameters have been fixed up to a consistent state. --*/ { PUIINFO pUIInfo; PPPDDATA pPpdData; PPAGESIZE pPageSize; CUSTOMSIZEDATA csdata; PDWORD pdwWidth, pdwHeight; DWORD dwTemp; BOOL bShortEdgeFirst, bXGreaterThanY; BOOL bFit; pUIInfo = GET_UIINFO_FROM_INFOHEADER((PINFOHEADER) pRawData); pPpdData = GET_DRIVER_INFO_FROM_INFOHEADER((PINFOHEADER) pRawData); ASSERT(pUIInfo != NULL && pPpdData != NULL); if ((pPageSize = PGetCustomPageSizeOption(pUIInfo)) == NULL) { RIP(("Custom page size not supported\n")); return TRUE; } csdata = *pCSData; // // Width and height offset parameters are straightforward to verify // if ((LONG) csdata.dwWidthOffset < MINCUSTOMPARAM_WIDTHOFFSET(pPpdData)) csdata.dwWidthOffset = MINCUSTOMPARAM_WIDTHOFFSET(pPpdData); else if ((LONG) csdata.dwWidthOffset > MAXCUSTOMPARAM_WIDTHOFFSET(pPpdData)) csdata.dwWidthOffset = MAXCUSTOMPARAM_WIDTHOFFSET(pPpdData); if ((LONG) csdata.dwHeightOffset < MINCUSTOMPARAM_HEIGHTOFFSET(pPpdData)) csdata.dwHeightOffset = MINCUSTOMPARAM_HEIGHTOFFSET(pPpdData); else if ((LONG) csdata.dwHeightOffset > MAXCUSTOMPARAM_HEIGHTOFFSET(pPpdData)) csdata.dwHeightOffset = MAXCUSTOMPARAM_HEIGHTOFFSET(pPpdData); // // Validate cut-sheet vs. roll-fed selection // if (csdata.wCutSheet && !(pPpdData->dwCustomSizeFlags & CUSTOMSIZE_CUTSHEET)) csdata.wCutSheet = FALSE; else if (!csdata.wCutSheet && !(pPpdData->dwCustomSizeFlags & CUSTOMSIZE_ROLLFED)) csdata.wCutSheet = TRUE; // // Check if the specified paper feed direction can be satisfied // bFit = BFixupCustomSizeDataFeedDirection(pUIInfo, pPpdData, &csdata); // // If we haven't been able to fit the custom paper size in // correct feeding direction and orientation, then we have // to swap width and height here, because they will be opposite // of what PPD spec 4.3 page 109 Figure 3 specifies. // if (!bFit) { dwTemp = csdata.dwX; csdata.dwX = csdata.dwY; csdata.dwY = dwTemp; } // // Verify width and height parameters // bShortEdgeFirst = (csdata.wFeedDirection == SHORTEDGEFIRST || csdata.wFeedDirection == SHORTEDGEFIRST_FLIPPED); bXGreaterThanY = (csdata.dwX > csdata.dwY); if ((bShortEdgeFirst && bXGreaterThanY) || (!bShortEdgeFirst && !bXGreaterThanY)) { // In this case: x <=> height, y <=> width pdwHeight = &csdata.dwX; pdwWidth = &csdata.dwY; } else { // In this case: x <=> width, y <=> height pdwWidth = &csdata.dwX; pdwHeight = &csdata.dwY; } if ((LONG) (*pdwWidth + csdata.dwWidthOffset) > pPageSize->szPaperSize.cx) { *pdwWidth = pPageSize->szPaperSize.cx - csdata.dwWidthOffset; if ((LONG) *pdwWidth < MINCUSTOMPARAM_WIDTH(pPpdData)) { *pdwWidth = MINCUSTOMPARAM_WIDTH(pPpdData); csdata.dwWidthOffset = pPageSize->szPaperSize.cx - *pdwWidth; } } else if ((LONG) *pdwWidth < MINCUSTOMPARAM_WIDTH(pPpdData)) { *pdwWidth = MINCUSTOMPARAM_WIDTH(pPpdData); } if ((LONG) (*pdwHeight + csdata.dwHeightOffset) > pPageSize->szPaperSize.cy) { *pdwHeight = pPageSize->szPaperSize.cy - csdata.dwHeightOffset; if ((LONG) *pdwHeight < MINCUSTOMPARAM_HEIGHT(pPpdData)) { *pdwHeight = MINCUSTOMPARAM_HEIGHT(pPpdData); csdata.dwHeightOffset = pPageSize->szPaperSize.cy - *pdwHeight; } } else if ((LONG) *pdwHeight < MINCUSTOMPARAM_HEIGHT(pPpdData)) { *pdwHeight = MINCUSTOMPARAM_HEIGHT(pPpdData); } // // Check if anything has changed and // return appropriate result value // if (memcmp(pCSData, &csdata, sizeof(csdata)) == 0) return TRUE; *pCSData = csdata; return FALSE; } VOID VFillDefaultCustomPageSizeData( IN PRAWBINARYDATA pRawData, OUT PCUSTOMSIZEDATA pCSData, IN BOOL bMetric ) /*++ Routine Description: Initialize the custom page size parameters to their default values Arguments: pRawData - Points to raw printer description data pCSData - Buffer for storing default custom page size parameters bMetric - Whether we're on a metric system Return Value: NONE --*/ { PPPDDATA pPpdData; pPpdData = GET_DRIVER_INFO_FROM_INFOHEADER((PINFOHEADER) pRawData); ASSERT(pPpdData != NULL); // // Default to Letter or A4 depending on whether // we're on metric system or not // if (bMetric) { pCSData->dwX = 210000; // 210mm pCSData->dwY = 297000; // 297mm } else { pCSData->dwX = 215900; // 8.5" pCSData->dwY = 279400; // 11" } // // Get default offsets and feed direction // pCSData->dwWidthOffset = MINCUSTOMPARAM_WIDTHOFFSET(pPpdData); pCSData->dwHeightOffset = MINCUSTOMPARAM_HEIGHTOFFSET(pPpdData); pCSData->wFeedDirection = (pPpdData->dwCustomSizeFlags & CUSTOMSIZE_SHORTEDGEFEED) ? SHORTEDGEFIRST : LONGEDGEFIRST; // // Make sure the default custom page size parameters are consistent // (VOID) BValidateCustomPageSizeData(pRawData, pCSData); } VOID VGetCustomSizeParamRange( IN PRAWBINARYDATA pRawData, IN PCUSTOMSIZEDATA pCSData, OUT PCUSTOMSIZERANGE pCSRange ) /*++ Routine Description: Return the valid ranges for custom page size width, height, and offset parameters based on their current values Arguments: pRawData - Points to raw printer description data pCSData - Specifies the current custom page size parameter values pCSRange - Output buffer for returning custom page size parameter ranges It should point to an array of 4 CUSTOMSIZERANGE structures: 0 (CUSTOMPARAM_WIDTH) 1 (CUSTOMPARAM_HEIGHT) 2 (CUSTOMPARAM_WIDTHOFFSET) 3 (CUSTOMPARAM_HEIGHTOFFSET) Return Value: NONE --*/ { PUIINFO pUIInfo; PPPDDATA pPpdData; BOOL bShortEdgeFirst, bXGreaterThanY; PPAGESIZE pPageSize; CUSTOMSIZEDATA csdata; PCUSTOMSIZERANGE pWidthRange, pHeightRange, pTempRange; BOOL bFit; pUIInfo = GET_UIINFO_FROM_INFOHEADER((PINFOHEADER) pRawData); pPpdData = GET_DRIVER_INFO_FROM_INFOHEADER((PINFOHEADER) pRawData); ASSERT(pUIInfo != NULL && pPpdData != NULL); pPageSize = PGetCustomPageSizeOption(pUIInfo); ASSERT(pPageSize != NULL); // // The range for width and height offsets are predictable // pCSRange[CUSTOMPARAM_WIDTHOFFSET].dwMin = MINCUSTOMPARAM_WIDTHOFFSET(pPpdData); pCSRange[CUSTOMPARAM_WIDTHOFFSET].dwMax = MAXCUSTOMPARAM_WIDTHOFFSET(pPpdData); pCSRange[CUSTOMPARAM_HEIGHTOFFSET].dwMin = MINCUSTOMPARAM_HEIGHTOFFSET(pPpdData); pCSRange[CUSTOMPARAM_HEIGHTOFFSET].dwMax = MAXCUSTOMPARAM_HEIGHTOFFSET(pPpdData); // // The range for width and height are affected by the selected paper feed direction // csdata = *pCSData; bFit = BFixupCustomSizeDataFeedDirection(pUIInfo, pPpdData, &csdata); bShortEdgeFirst = (csdata.wFeedDirection == SHORTEDGEFIRST || csdata.wFeedDirection == SHORTEDGEFIRST_FLIPPED); bXGreaterThanY = (csdata.dwX > csdata.dwY); if ((bShortEdgeFirst && bXGreaterThanY) || (!bShortEdgeFirst && !bXGreaterThanY)) { // // Here user's logical x/y and custom page // size width/height are swapped // pWidthRange = pCSRange + CUSTOMPARAM_HEIGHT; pHeightRange = pCSRange + CUSTOMPARAM_WIDTH; } else { // // Here user's logical x/y correspond to // custom page size width/height // pWidthRange = pCSRange + CUSTOMPARAM_WIDTH; pHeightRange = pCSRange + CUSTOMPARAM_HEIGHT; } // // If we haven't been able to fit the custom paper size in // correct feeding direction and orientation, then we have // to swap width and height here, because they will be opposite // of what PPD spec 4.3 page 109 Figure 3 specifies. // if (!bFit) { pTempRange = pWidthRange; pWidthRange = pHeightRange; pHeightRange = pTempRange; } pWidthRange->dwMin = MINCUSTOMPARAM_WIDTH(pPpdData); pWidthRange->dwMax = MAXCUSTOMPARAM_WIDTH(pPpdData); pHeightRange->dwMin = MINCUSTOMPARAM_HEIGHT(pPpdData); pHeightRange->dwMax = MAXCUSTOMPARAM_HEIGHT(pPpdData); if (pWidthRange->dwMax > pPageSize->szPaperSize.cx - csdata.dwWidthOffset) pWidthRange->dwMax = pPageSize->szPaperSize.cx - csdata.dwWidthOffset; if (pHeightRange->dwMax > pPageSize->szPaperSize.cy - csdata.dwHeightOffset) pHeightRange->dwMax = pPageSize->szPaperSize.cy - csdata.dwHeightOffset; } BOOL BFormSupportedThruCustomSize( PRAWBINARYDATA pRawData, DWORD dwX, DWORD dwY, PWORD pwFeedDirection ) /*++ Routine Description: Determine whether a form can be supported through custom page size Arguments: pRawData - Points to raw printer description data dwX, dwY - Form width and height (in microns) pwFeedDirection - if not NULL, will be set to the selected feed direction Return Value: TRUE if the form can be supported through custom page size FALSE if not. In that case, pwFeedDirection will be LONGEDGEFIRST. --*/ { PPPDDATA pPpdData = GET_DRIVER_INFO_FROM_INFOHEADER((PINFOHEADER) pRawData); static WORD awPrefFeedDir[] = { LONGEDGEFIRST, SHORTEDGEFIRST }; CUSTOMSIZEDATA csdata; DWORD i; for (i = 0; i < (sizeof(awPrefFeedDir)/sizeof(WORD)); i++) { csdata.dwX = dwX; csdata.dwY = dwY; csdata.dwWidthOffset = csdata.dwHeightOffset = 0; csdata.wCutSheet = TRUE; csdata.wFeedDirection = awPrefFeedDir[i]; (VOID) BValidateCustomPageSizeData(pRawData, &csdata); if (dwX == csdata.dwX && dwY == csdata.dwY && csdata.wFeedDirection != MAX_FEEDDIRECTION) { if (pwFeedDirection != NULL) *pwFeedDirection = csdata.wFeedDirection; // might be flipped return TRUE; } } if (pwFeedDirection != NULL) *pwFeedDirection = LONGEDGEFIRST; // just set a safe default, the return value should be checked ! return FALSE; }