/*++ Copyright (c) 2000 Microsoft Corporation Module Name: pclxl.cpp Abstract: PCL-XL command output high level function implementation Environment: Windows Whistler Revision History: 08/23/99 Created initial framework. --*/ #include "xlpdev.h" #include "pclxlcmd.h" #include "pclxle.h" #include "xldebug.h" #include "xlgstate.h" #include "xloutput.h" #include "xlbmpcvt.h" // // Hatch brush raster pattern // const BYTE gubSizeOfHatchBrush = 32 * 32 / 8; const USHORT gusWidthOfHatchBrush = 32; const USHORT gusHeightOfHatchBrush = 32; const BYTE gubHatchBrush[6][gubSizeOfHatchBrush] = { {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff}, {0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01}, {0x80, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01}, { 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00}, {0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01}, {0x80, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x04, 0x10, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x10, 0x04, 0x00, 0x00, 0x20, 0x02, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x80, 0x00, 0x80, 0x01, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x20, 0x04, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x04, 0x20, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x04, 0x20, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x20, 0x04, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x80, 0x01, 0x00, 0x01, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x40, 0x04, 0x00, 0x00, 0x20, 0x08, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x04, 0x40, 0x00, 0x00, 0x02, 0x80, 0x00, 0x00, 0x01} }; // // High level output functions // HRESULT XLOutput:: BeginImage( ColorMapping CMapping, ULONG ulOutputBPP, ULONG ulSrcWidth, ULONG ulSrcHeight, ULONG ulDestWidth, ULONG ulDestHeight) /*++ Routine Description: Sends BeginImage operator. Arguments: Return Value: Note: --*/ { DWORD dwI = 0; XL_VERBOSE(("XLOutput::BeginImage:SrcW=%d, SrcH=%d, DstH=%d, DstW=%d\n", ulSrcWidth, ulSrcHeight, ulDestHeight, ulDestWidth)); SetOutputBPP(CMapping, ulOutputBPP); SetSourceWidth((uint16)ulSrcWidth); SetSourceHeight((uint16)ulSrcHeight); SetDestinationSize((uint16)ulDestWidth, (uint16)ulDestHeight); Send_cmd(eBeginImage); return S_OK; } HRESULT XLOutput:: SetOutputBPP( ColorMapping CMapping, ULONG ulOutputBPP) /*++ Routine Description: Sends Color mapping and output depth. Arguments: Return Value: Note: --*/ { switch (CMapping) { case eDirectPixel: SetColorMapping(eDirectPixel); break; case eIndexedPixel: SetColorMapping(eIndexedPixel); break; default: SetColorMapping(eDirectPixel); } switch (ulOutputBPP) { case 1: SetColorDepth(e1Bit); break; case 4: SetColorDepth(e4Bit); break; case 8: case 24: SetColorDepth(e8Bit); break; default: XL_ERR(("ulOutputBPP = %d is not supported\n", ulOutputBPP)); // // Send color depth anyway to avoid XL error. // SetColorDepth(e8Bit); } return S_OK; } HRESULT XLOutput:: SetPalette( ULONG ulOutputBPP, DWORD dwCEntries, DWORD *pdwColor) /*++ Routine Description: Arguments: Return Value: Note: --*/ { HRESULT hResult; if (dwCEntries != 0 && pdwColor != NULL) { SetPaletteDepth(e8Bit); SetPaletteData(m_DeviceColorDepth, dwCEntries, pdwColor); hResult = S_OK; } else { XL_ERR(("XLOutput::SetPalette pxlo = NULL\n")); hResult = S_FALSE; } return hResult; } HRESULT XLOutput:: SetClip( CLIPOBJ *pco) /*++ Routine Description: Sends clip object. Arguments: Return Value: Note: --*/ { PATHOBJ *ppo; XLGState *pGState = this; HRESULT hResult; if (S_OK == pGState->CheckClip(pco)) return S_OK; if ( NULL == pco ) { XL_VERBOSE(("XLOutput::SetClip pco = NULL.\n")); Send_cmd(eSetClipToPage); pGState->ClearClip(); return S_OK; } XL_VERBOSE(("XLOutput::SetClip: pco->iDComplexity=%d\n", pco->iDComplexity)); switch(pco->iDComplexity) { case DC_RECT: SetClipMode(eClipEvenOdd); Send_cmd(eNewPath); RectanglePath(&(pco->rclBounds)); SetClipRegion(eInterior); Send_cmd(eSetClipReplace); pGState->SetClip(pco); hResult = S_OK; break; case DC_COMPLEX: ppo = CLIPOBJ_ppoGetPath(pco); if (NULL == ppo) { XL_ERR(("XLOutput::SetClip ppo = NULL.\n")); Send_cmd(eSetClipToPage); pGState->ClearClip(); hResult = S_FALSE; break; } SetClipMode(eClipEvenOdd); Path(ppo); SetClipRegion(eInterior); Send_cmd(eSetClipReplace); pGState->SetClip(pco); hResult = S_OK; break; case DC_TRIVIAL: default: Send_cmd(eSetClipToPage); pGState->ClearClip(); hResult = S_OK; break; } return hResult; } HRESULT XLOutput:: RoundRectanglePath( RECTL *prclBounds) /*++ Routine Description: Arguments: Return Value: Note: --*/ { RECTL Rectl; if ( NULL == prclBounds ) { XL_ERR(("XLOutput::RoundRectangle prclBounds = NULL.\n")); return E_UNEXPECTED; } XL_VERBOSE(("XLOutput::RoundRectanglePath:left=%d, top=%d, right=%d, bottom=%d\n", prclBounds->left, prclBounds->top, prclBounds->right, prclBounds->bottom)); // // BoundingBox can handle only positive numbers. // Rectl = *prclBounds; if (Rectl.left < 0) { Rectl.left = 0; } if (Rectl.top < 0) { Rectl.top = 0; } if (Rectl.right < 0) { Rectl.right = 0; } if (Rectl.bottom < 0) { Rectl.bottom = 0; } // // DCR: Round value needs to be sent! // if (S_OK == SetBoundingBox((uint16)Rectl.left, (uint16)Rectl.top, (uint16)Rectl.right, (uint16)Rectl.bottom) && S_OK == Send_uint16_xy(0, 0) && S_OK == Send_attr_ubyte(eEllipseDimension) && S_OK == Send_cmd(eRoundRectanglePath)) return S_OK; else return S_FALSE; } HRESULT XLOutput:: SetCursor( LONG lX, LONG lY) /*++ Routine Description: Set cursor. Arguments: Return Value: Note: --*/ { XL_VERBOSE(("XLOutput::SetCursor:X=%d, Y=%d\n", lX, lY)); Send_sint16_xy((sint16)lX, (sint16)lY); Send_attr_ubyte(ePoint); Send_cmd(eSetCursor); m_lX = lX; m_lY = lY; return S_OK; } HRESULT XLOutput:: GetCursorPos( PLONG plX, PLONG plY) /*++ Routine Description: Arguments: Return Value: Note: --*/ { XL_VERBOSE(("XLOutput::GetCursor:X=%d, Y=%d\n", *plX, *plY)); if (plX == NULL || plY == NULL) return E_UNEXPECTED; *plX = m_lX; *plY = m_lY; return S_OK; } HRESULT XLOutput:: ReadImage( DWORD dwBlockHeight, CompressMode CMode) /*++ Routine Description: Sends ReadImage operator Arguments: Return Value: Note: --*/ { XL_VERBOSE(("XLOutput::ReadImage:dwBlockHeight=%d\n", dwBlockHeight)); Send_uint16((uint16)0); Send_attr_ubyte(eStartLine); Send_uint16((uint16)dwBlockHeight); Send_attr_ubyte(eBlockHeight); // // DCR: Need to support JPEG // SetCompressMode(CMode); Send_cmd(eReadImage); return S_OK; } HRESULT XLOutput:: ReadImage( DWORD dwStart, DWORD dwBlockHeight, CompressMode CMode) /*++ Routine Description: Sends ReadImage operator Arguments: Return Value: Note: --*/ { XL_VERBOSE(("XLOutput::ReadImage:dwBlockHeight=%d\n", dwBlockHeight)); Send_uint16((uint16)dwStart); Send_attr_ubyte(eStartLine); Send_uint16((uint16)dwBlockHeight); Send_attr_ubyte(eBlockHeight); // // DCR: Need to support JPEG // SetCompressMode(CMode); Send_cmd(eReadImage); return S_OK; } HRESULT XLOutput:: ReadRasterPattern( DWORD dwBlockHeight, CompressMode CMode) /*++ Routine Description: Sends ReadRasterPattern operator. Arguments: Return Value: Note: --*/ { XL_VERBOSE(("XLOutput::ReadRasterPattern:dwBlockHeight=%d\n", dwBlockHeight)); Send_uint16((uint16)0); Send_attr_ubyte(eStartLine); Send_uint16((uint16)dwBlockHeight); Send_attr_ubyte(eBlockHeight); // // DCR: Need to support JPEG // SetCompressMode(CMode); Send_cmd(eReadRastPattern); return S_OK; } HRESULT XLOutput:: SetRGBColor( uint32 uint32_RGB) /*++ Routine Description: Sends SetGrayLevel attribute. Arguments: Return Value: Note: --*/ { // // RGB color 3 bytes // Send_ubyte_array_header(3); WriteByte(RED(uint32_RGB)); WriteByte(GREEN(uint32_RGB)); WriteByte(BLUE(uint32_RGB)); Send_attr_ubyte(eRGBColor); return S_OK; } HRESULT XLOutput:: SetGrayLevel( ubyte ubyte_gray) /*++ Routine Description: Sends SetGrayLevel attribute. Arguments: Return Value: Note: --*/ { Send_ubyte(ubyte_gray); Send_attr_ubyte(eGrayLevel); return S_OK; } HRESULT XLOutput:: RectanglePath( RECTL *prclRect) /*++ Routine Description: Sends Rectangle Path Arguments: Return Value: Note: --*/ { RECTL Rectl; if (NULL == prclRect) { XL_ERR(("XLOutput::RectanglePath: prclRect == NULL\n")); return E_UNEXPECTED; } XL_VERBOSE(("XLOutput::RectanglePath:left=%d, top=%d, right=%d, bottom=%d\n", prclRect->left, prclRect->top, prclRect->right, prclRect->bottom)); Rectl = *prclRect; if (prclRect->left < 0) { Rectl.left = 0; } if (prclRect->top < 0) { Rectl.top = 0; } if (prclRect->right < 0) { Rectl.right = 0; } if (prclRect->bottom < 0) { Rectl.bottom = 0; } if (S_OK == SetBoundingBox((uint16)Rectl.left, (uint16)Rectl.top, (uint16)Rectl.right, (uint16)Rectl.bottom) && S_OK == Send_cmd(eRectanglePath) ) return S_OK; else return S_FALSE; } HRESULT XLOutput:: Path( PATHOBJ *ppo) /*++ Routine Description: Sends path. Arguments: Return Value: Note: --*/ { POINTFIX* pptfx; PATHDATA PathData; LONG lPoints; HRESULT hResult; BOOL bMore; XL_VERBOSE(("XLOutput::Path\n")); if (ppo == NULL) { XL_ERR(("XLOutput::Path ppo = NULL.\n")); return E_UNEXPECTED; } // // Emit newpath operator // Don't do it if we're between path escapes // hResult = Send_cmd(eNewPath); // // Path object case // PATHOBJ_vEnumStart(ppo); do { bMore = PATHOBJ_bEnum(ppo, &PathData); pptfx = PathData.pptfx; if ( 0 == (lPoints = PathData.count)) { XL_VERBOSE(("XLOutput::Path PathData.Count == 0\n")); hResult = S_FALSE; continue; } // // Begin new sub path // if (PathData.flags & PD_BEGINSUBPATH) { // // start new path // if (hResult == S_OK) hResult = SetCursor(FXTOL(pptfx->x), FXTOL(pptfx->y));; pptfx++; lPoints--; } if (lPoints > 0) { if (PathData.flags & PD_BEZIERS) { // // Output a Bezier curve segment // ASSERTMSG((lPoints % 3) == 0, ("Incorrect number of points for a Bezier curve: %d\n", lPoints)); if (hResult == S_OK) hResult = BezierPath(pptfx, lPoints); } else { // // Draw straight line segment // if (hResult == S_OK) hResult = LinePath(pptfx, lPoints); } } // // Close subpath // if (PathData.flags & PD_CLOSEFIGURE) { if (hResult == S_OK) hResult = Send_cmd(eCloseSubPath); } } while (bMore); return hResult; } HRESULT XLOutput:: BezierPath( POINTFIX* pptfx, LONG lPoints) /*++ Routine Description: Sends bezier path Arguments: Return Value: Note: --*/ { LONG lValue, lI; DWORD dwDataLength; if (NULL == pptfx) { XL_ERR(("XLOutput::BezierPath: pptfx == NULL\n")); return E_UNEXPECTED; } XL_VERBOSE(("XLOutput::BezierPath(lPoints=%d)\n",lPoints)); Send_uint16((uint16)lPoints); Send_attr_ubyte(eNumberOfPoints); Send_ubyte(eSint16); Send_attr_ubyte(ePointType); Send_cmd(eBezierPath); dwDataLength = lPoints * 2 * sizeof(sint16); if (dwDataLength > 0xff) { WriteByte(PCLXL_dataLength); Write((PBYTE)&dwDataLength, sizeof(DWORD)); } else { WriteByte(PCLXL_dataLengthByte); WriteByte((ubyte)dwDataLength); } for (lI = 0; lI < lPoints; lI++) { lValue = FXTOL(pptfx->x); Write((PBYTE)&lValue, sizeof(sint16)); lValue = FXTOL(pptfx->y); Write((PBYTE)&lValue, sizeof(sint16)); pptfx++; } // // Update the last coordinate. // Make sure that there are some points. if (lPoints > 0) { pptfx--; m_lX = FXTOL(pptfx->x); m_lY = FXTOL(pptfx->y); } else { m_lX = 0; m_lY = 0; } return S_OK; } HRESULT XLOutput:: LinePath( POINTFIX* pptfx, LONG lPoints) /*++ Routine Description: Sends line path. Arguments: Return Value: Note: --*/ { LONG lValueX, lValueY, lI, lJ; LONG lx, ly; DWORD dwDataLength; if (NULL == pptfx) { XL_ERR(("XLOutput::LinePath: pptfx == NULL\n")); return E_UNEXPECTED; } XL_VERBOSE(("XLOutput::LinePath(lPoints=%d)\n", lPoints)); // // Optimization. Use byte relpath to minimize the output size // First, check if the difference from the previous position is in a byte. // BOOL bModeChange; enum { eMode_SByte, eMode_SInt, eMode_None} Mode; LONG lStart, lEnd, lNumOfSByte; LONG lStartX, lStartY; POINTFIX *pptfx_tmp = pptfx; // // Get current cursor position // lStartX = lx = m_lX; lStartY = ly = m_lY; // // Reset // lStart = 0; Mode = eMode_None; bModeChange = FALSE; lNumOfSByte = 0; for (lI = 0; lI < lPoints; ) { XL_VERBOSE(("XLOutput::LinePath: (%d)=(%d,%d)\n",lI, lx, ly)); lValueX = FXTOL(pptfx_tmp->x) - (LONG)lx; lValueY = FXTOL(pptfx_tmp->y) - (LONG)ly; // // Mode needs to be in SByte or SInt? // if ( -128 <= lValueX && lValueX <= 127 && -128 <= lValueY && lValueY <= 127 ) { if (Mode == eMode_SInt) { // // Optimization // // To switch mode between SInt and SByte, it needs 7 bytes. // // uint16 XX NumberOfPoints // ubyte eSByte PointType // LineRelPath // // 4 points with SInt consumes 2 x 4 = 8 bytes extra data. // 3 points with SInt consumes 2 x 3 = 6 bytes extra data. // // 4 points is the threshold to swith mode to SInt. // // Number of points: lEnd - lStart + 1 // if (lI - 1 - lStartSByte + 1 >= 4) // // If SByte continues more than 4 points, switch mode from // SByte to SInt. // if (lNumOfSByte >= 4) { bModeChange = TRUE; lI -= lNumOfSByte; pptfx_tmp -= lNumOfSByte; lEnd = (lI - 1); lNumOfSByte = 0; } // // Reset starting point of SByte // lNumOfSByte ++; } else { Mode = eMode_SByte; } XL_VERBOSE(("XLOutput::LinePath: (SByte) lx1=%d, lx2=%d\n", lx, FXTOL(pptfx_tmp->x))); } else { if (Mode == eMode_SByte) { bModeChange = TRUE; lEnd = lI - 1; } else { Mode = eMode_SInt; lNumOfSByte = 0; } XL_VERBOSE(("XLOutput::LinePath: (SInt) lx1=%d, lx2=%d\n", lx, FXTOL(pptfx_tmp->x))); } if (!bModeChange && lI + 1 == lPoints) { bModeChange = TRUE; lEnd = lI; lI ++; } if (bModeChange) { XL_VERBOSE(("XLOutput::LinePath: Draw\n")); // // Get start cursor position // lx = lStartX; ly = lStartY; if (Mode == eMode_SByte) { // // SByte // Send_uint16((uint16)(lEnd - lStart + 1)); Send_attr_ubyte(eNumberOfPoints); Send_ubyte(eSByte); Send_attr_ubyte(ePointType); Send_cmd(eLineRelPath); dwDataLength = (lEnd - lStart + 1) * 2 * sizeof(ubyte); if (dwDataLength <= 0xFF) { WriteByte(PCLXL_dataLengthByte); WriteByte((ubyte)dwDataLength); } else { WriteByte(PCLXL_dataLength); Write((PBYTE)&dwDataLength, sizeof(DWORD)); } for (lJ = 0; lJ <= (lEnd - lStart); lJ++) { lValueX = FXTOL(pptfx->x) - (LONG)lx; lValueY = FXTOL(pptfx->y) - (LONG)ly; Write((PBYTE)&lValueX, sizeof(ubyte)); Write((PBYTE)&lValueY, sizeof(ubyte)); lx = FXTOL(pptfx->x); ly = FXTOL(pptfx->y); pptfx++; } Mode = eMode_SInt; } else if (Mode == eMode_SInt) { // // SInt16 // Send_uint16((uint16)(lEnd - lStart + 1)); Send_attr_ubyte(eNumberOfPoints); Send_ubyte(eSint16); Send_attr_ubyte(ePointType); Send_cmd(eLineRelPath); dwDataLength = (lEnd - lStart + 1) * 2 * sizeof(uint16); if (dwDataLength <= 0xFF) { WriteByte(PCLXL_dataLengthByte); WriteByte((ubyte)dwDataLength); } else { WriteByte(PCLXL_dataLength); Write((PBYTE)&dwDataLength, sizeof(DWORD)); } for (lJ = 0; lJ <= (lEnd - lStart); lJ++) { lValueX = FXTOL(pptfx->x) - (LONG)lx; lValueY = FXTOL(pptfx->y) - (LONG)ly; Write((PBYTE)&lValueX, sizeof(sint16)); Write((PBYTE)&lValueY, sizeof(sint16)); lx = FXTOL(pptfx->x); ly = FXTOL(pptfx->y); pptfx++; } Mode = eMode_SByte; } bModeChange = FALSE; lStartX = lx = FXTOL((pptfx_tmp-1)->x); lStartY = ly = FXTOL((pptfx_tmp-1)->y); lStart = lI; } else { lx = FXTOL((pptfx_tmp)->x); ly = FXTOL((pptfx_tmp)->y); pptfx_tmp ++; lI ++; } } // // Update cursor position // m_lX = FXTOL((pptfx_tmp)->x); m_lY = FXTOL((pptfx_tmp)->y); return S_OK; } inline VOID XLOutput:: SetupBrush( BRUSHOBJ *pbo, POINTL *pptlBrushOrg, CMNBRUSH *pcmnbrush) /*++ Routine Description: Arguments: Return Value: Note: --*/ { DWORD dwHatchID; XLBRUSH *pBrush; if (NULL == pcmnbrush) { // // Make sure that pcmnbrush is valid. // XL_ERR(("SetupBrush:pcmnbrush is invalid.\n")); return; } // // Initialize CMNBRUSH // pcmnbrush->dwSig = BRUSH_SIGNATURE; pcmnbrush->BrushType = kNoBrush; pcmnbrush->ulHatch = 0XFFFFFFFF; pcmnbrush->dwColor = 0x00FFFFFF; pcmnbrush->dwCEntries = 0; pcmnbrush->dwPatternBrushID = 0xFFFFFFFF; XL_VERBOSE(("XLOutput::SetupBrush\n")); if (NULL == pbo) { XL_VERBOSE(("XLOutput::SetupBrush: pbo == NULL, set NULL brush\n")); } else { #ifndef WINNT_40 if ( !(pbo->flColorType & BR_CMYKCOLOR) && (pbo->iSolidColor == NOT_SOLID_COLOR) ) #else if (pbo->iSolidColor == NOT_SOLID_COLOR) #endif { pcmnbrush->ulSolidColor = BRUSHOBJ_ulGetBrushColor(pbo); pBrush = (XLBRUSH*)BRUSHOBJ_pvGetRbrush(pbo); if (NULL == pBrush) { XL_ERR(("SetupBrush:BRUSHOBJ_pvGetRbrush failed.\n")); dwHatchID = HS_DDI_MAX; } else { dwHatchID = pBrush->dwHatch; } } else { dwHatchID = HS_DDI_MAX; pcmnbrush->ulSolidColor = pbo->iSolidColor; pBrush = NULL; } pcmnbrush->ulHatch = dwHatchID; switch (dwHatchID) { case HS_HORIZONTAL: case HS_VERTICAL: case HS_BDIAGONAL: case HS_FDIAGONAL: case HS_CROSS: case HS_DIAGCROSS: XL_VERBOSE(("XLOutput::SetupBrush(uiSolidColor=%d,dwHatchID=%d)\n", pbo->iSolidColor, dwHatchID)); pcmnbrush->BrushType = kBrushTypeHatch; pcmnbrush->dwPatternBrushID = dwHatchID; if (pBrush) { pcmnbrush->dwColor = pBrush->dwColor; } if (GetDeviceColorDepth() == e24Bit) { SetColorSpace(eRGB); } else { SetColorSpace(eGray); } SetPaletteDepth(e8Bit); if (pBrush->dwCEntries) { SetPaletteData(m_DeviceColorDepth, pBrush->dwCEntries, pBrush->adwColor); } else { DWORD dwColorTableTmp[2] = {0x00ffffff, 0x00ffffff}; dwColorTableTmp[1] = pBrush->dwColor; SetPaletteData(m_DeviceColorDepth, 2, dwColorTableTmp); } Send_cmd(eSetColorSpace); if (!(m_dwHatchBrushAvailability & (HORIZONTAL_AVAILABLE << dwHatchID))) { SetColorMapping(eIndexedPixel); SetColorDepth(e1Bit); SetSourceWidth((uint16)gusWidthOfHatchBrush); SetSourceHeight((uint16)gusHeightOfHatchBrush); // // Pattern scaling factor // 160 is an experimentally introduced number. // WORD wScale = (WORD)(160 * m_dwResolution / 1200); SetDestinationSize((uint16)wScale, (uint16)wScale); SetPatternPersistence(eSessionPattern); SetPatternDefineID((sint16)dwHatchID); Send_cmd(eBeginRastPattern); Send_uint16((uint16)0); Send_attr_ubyte(eStartLine); Send_uint16((uint16)gusHeightOfHatchBrush); Send_attr_ubyte(eBlockHeight); SetCompressMode(eNoCompression); Send_cmd(eReadRastPattern); WriteByte(PCLXL_dataLengthByte); WriteByte(gubSizeOfHatchBrush); Write((PBYTE)gubHatchBrush[dwHatchID], gubSizeOfHatchBrush); Send_cmd(eEndRastPattern); m_dwHatchBrushAvailability |= HORIZONTAL_AVAILABLE << dwHatchID; } // //SendPatternSelectID(); // Send_sint16((sint16)dwHatchID); Send_attr_ubyte(ePatternSelectID); break; case HS_DDI_MAX: pcmnbrush->BrushType = kBrushTypeSolid; //pcmnbrush->dwColor = BRUSHOBJ_ulGetBrushColor(pbo); pcmnbrush->dwColor = pcmnbrush->ulSolidColor; XL_VERBOSE(("XLOutput::SetupBrush(RGB=0x%x)\n", pcmnbrush->dwColor)); if (e24Bit == GetDeviceColorDepth()) { SetRGBColor(pcmnbrush->dwColor); } else { ubyte ubyte_gray = (ubyte) DWORD2GRAY(pcmnbrush->dwColor); SetGrayLevel(ubyte_gray); } break; default: if (NULL == pBrush) { XL_ERR(("XLOutput:SetupBrush: invalid pBrush\n")); return; } XL_VERBOSE(("XLOutput::SetupBrush(PatternID=%d)\n", pBrush->dwPatternID)); pcmnbrush->dwColor = pBrush->dwColor; pcmnbrush->dwPatternBrushID = pBrush->dwPatternID; pcmnbrush->BrushType = kBrushTypePattern; if (e24Bit == GetDeviceColorDepth()) { SetColorSpace(eRGB); } else { SetColorSpace(eGray); } if (pBrush->dwCEntries) { SetPaletteDepth(e8Bit); SetPaletteData(m_DeviceColorDepth, pBrush->dwCEntries, pBrush->adwColor); } Send_cmd(eSetColorSpace); //SendPatternSelectID(); Send_sint16((sint16)pBrush->dwPatternID); Send_attr_ubyte(ePatternSelectID); } } return; } HRESULT XLOutput:: SetPenColor( BRUSHOBJ *pbo, POINTL *pptlBrushOrg) /*++ Routine Description: Arguments: Return Value: Note: --*/ { XL_VERBOSE(("XLOutput::SetPenColor\n")); XLPen *pPen = this; CMNBRUSH cmnbrush; if (S_OK == pPen->CheckCurrentBrush(pbo)) return S_OK; if (NULL == pbo) { Send_ubyte(0); Send_attr_ubyte(eNullPen); } SetupBrush(pbo, pptlBrushOrg, &cmnbrush); Send_cmd(eSetPenSource); pPen->SetBrush(&cmnbrush); return S_OK; } HRESULT XLOutput:: SetPen( LINEATTRS *plineattrs, XFORMOBJ *pxo) /*++ Routine Description: Arguments: Return Value: Note: --*/ { LineCap linecap; XLLineEndCap xllinecap; LineJoin linejoin; XLLineJoin xllinejoin; FLOATOBJ fLineWidth; uint16 uint16_linewidth; XL_VERBOSE(("XLOutput::SetPen\n")); if (NULL == plineattrs) { XL_ERR(("XLOutput:SetPen: invalid parameters\n")); return E_UNEXPECTED; } XLGState *pGState = this; DWORD dwLine = pGState->GetDifferentAttribute(plineattrs); // // DCR: need to check each attribute. // if (XLLINE_NONE == dwLine) return S_OK; if (plineattrs->fl & LA_GEOMETRIC) { // // Line joint // switch(plineattrs->iJoin) { case JOIN_ROUND: linejoin = eRoundJoin; xllinejoin = kXLLineJoin_Round; break; case JOIN_BEVEL: linejoin = eBevelJoin; xllinejoin = kXLLineJoin_Bevel; break; case JOIN_MITER: linejoin = eMiterJoin; xllinejoin = kXLLineJoin_Miter; break; default: linejoin = eRoundJoin; xllinejoin = kXLLineJoin_Round; break; } // // Line endcap // switch(plineattrs->iEndCap) { case ENDCAP_ROUND: linecap = eRoundCap; xllinecap = kXLLineEndCapRound; break; case ENDCAP_SQUARE: linecap = eSquareCap; xllinecap = kXLLineEndCapSquare; break; case ENDCAP_BUTT: linecap = eButtCap; xllinecap = kXLLineEndCapButt; break; default: linecap = eRoundCap; xllinecap = kXLLineEndCapRound; break; } // // Line width // fLineWidth = plineattrs->elWidth.e; } else { linejoin = eRoundJoin; linecap = eRoundCap; FLOATOBJ_SetLong(&fLineWidth, plineattrs->elWidth.l); } if (dwLine & XLLINE_WIDTH) { uint16_linewidth = (uint16)FLOATOBJ_GetLong(&fLineWidth); SetPenWidth(uint16_linewidth); pGState->SetLineWidth(plineattrs->elWidth); } if (dwLine & XLLINE_ENDCAP) { SetLineCap(linecap); pGState->SetLineEndCap(xllinecap); } if (dwLine & XLLINE_JOIN) { SetLineJoin(linejoin); pGState->SetLineJoin(xllinejoin); } // // Line style // if (dwLine & XLLINE_STYLE) { if (plineattrs->cstyle == 0) { Send_ubyte((ubyte)0); Send_attr_ubyte(eSolidLine); Send_cmd(eSetLineDash); } else { DWORD dwI, dwSegCount; PFLOAT_LONG plSize; FLOAT_LONG lSize[2]; FLOATOBJ fSize; uint16 uint16_linesize; if (plineattrs->fl & LA_ALTERNATE) { if (plineattrs->fl & LA_GEOMETRIC) { FLOATOBJ_SetLong(&lSize[0].e, 1); FLOATOBJ_SetLong(&lSize[1].e, 1); } else { lSize[0].l = 1; lSize[1].l = 1; } dwSegCount = 2; plSize = lSize; } else { dwSegCount = plineattrs->cstyle; plSize = plineattrs->pstyle; } if (plSize) { Send_uint16_array_header(dwSegCount); for (dwI = 0; dwI < dwSegCount; dwI ++, plSize ++) { if (plineattrs->fl & LA_GEOMETRIC) { fSize = plSize->e; } else { FLOATOBJ_SetLong(&fSize, plSize->l); // // It is necessary to scale the line pattern. The number // 24 on 1200 dpi was introduced experimentally. // Here is an assumption. Resolution could be 300, 600, // or 1200. // if (m_dwResolution > 50) { FLOATOBJ_MulLong(&fSize, m_dwResolution / 50); } } uint16_linesize = (uint16)FLOATOBJ_GetLong(&fSize); Write((PBYTE)&uint16_linesize, sizeof(uint16_linesize)); } Send_attr_ubyte(eLineDashStyle); Send_cmd(eSetLineDash); } } pGState->SetLineStyle(plineattrs->cstyle, plineattrs->pstyle, plineattrs->elStyleState); } if (dwLine & XLLINE_MITERLIMIT) { FLOATOBJ fMiter; FLOATOBJ_SetFloat(&fMiter, plineattrs->eMiterLimit); uint16 uint16_miter = (uint16)FLOATOBJ_GetLong(&fMiter); // // PCLXL interpreter doesn't accept miterlimiter less than 1. // If it is less than 1, it replaces the value with 10. // We'd better set 1 instead. // // Actuall less than 1 means 0 here, though. // if (uint16_miter < 1) { uint16_miter = 1; } SetMiterLimit(uint16_miter); pGState->SetMiterLimit(plineattrs->eMiterLimit); } pGState->SetLineType((XLLineType)plineattrs->fl); return S_OK; } HRESULT XLOutput:: SetBrush( BRUSHOBJ *pbo, POINTL *pptlBrushOrg) /*++ Routine Description: Arguments: Return Value: Note: --*/ { XL_VERBOSE(("XLOutput::SetBrush\n")); XLBrush *pBrush = this; CMNBRUSH cmnbrush; if (S_OK == pBrush->CheckCurrentBrush(pbo)) return S_OK; if (NULL == pbo) { Send_ubyte(0); Send_attr_ubyte(eNullBrush); } SetupBrush(pbo, pptlBrushOrg, &cmnbrush); Send_cmd(eSetBrushSource); pBrush->SetBrush(&cmnbrush); return S_OK; } HRESULT XLOutput:: Paint( VOID) /*++ Routine Description: Arguments: Return Value: Note: --*/ { XL_VERBOSE(("XLOutput::Paint\n")); return Send_cmd(ePaintPath); } HRESULT XLOutput:: SetPaletteData( ColorDepth value, DWORD dwPaletteNum, DWORD *pdwColorTable) /*++ Routine Description: Arguments: Return Value: Note: --*/ { DWORD dwI; if (NULL == pdwColorTable) { XL_ERR(("XLOutput::SetPaletteData pdwColorTable == NULL\n")); return E_UNEXPECTED; } switch (value) { case e8Bit: WriteByte(PCLXL_ubyte_array); Send_uint16((uint16)dwPaletteNum); for (dwI = 0; dwI < dwPaletteNum; dwI ++) WriteByte((ubyte)DWORD2GRAY(*(pdwColorTable+dwI))); Send_attr_ubyte(ePaletteData); break; case e24Bit: WriteByte(PCLXL_ubyte_array); Send_uint16((uint16)dwPaletteNum * 3); for (dwI = 0; dwI < dwPaletteNum; dwI ++) { Write((PBYTE)(pdwColorTable+dwI), 3); } Send_attr_ubyte(ePaletteData); break; default: // // DCR: only supports 8bits gray scale // XL_ERR(("XLOutput::SetPaletteData: unsupported ColorDepth:%d\n", value)); } return S_OK; } HRESULT XLOutput:: SetFont( FontType fonttype, PBYTE pFontName, DWORD dwFontHeight, DWORD dwFontWidth, DWORD dwSymbolSet, DWORD dwFontSimulation) /*++ Routine Description: Arguments: Return Value: Note: --*/ { FLOATOBJ fSize; LONG lvalue; if (NULL == pFontName) { XL_ERR(("XLOutput::SetFont: Invalie pFontName parameter\n")); return E_UNEXPECTED; } XLGState *pGState = this; if (S_OK == pGState->CheckCurrentFont(fonttype, pFontName, dwFontHeight, dwFontWidth, dwSymbolSet, dwFontSimulation)) return S_OK; FLOATOBJ_SetLong(&fSize, dwFontHeight); lvalue = FLOATOBJ_GetFloat(&fSize); // // Select font // Send_ubyte_array_header(PCLXL_FONTNAME_SIZE); Write(pFontName, PCLXL_FONTNAME_SIZE); Send_attr_ubyte(eFontName); Send_real32(lvalue); Send_attr_ubyte(eCharSize); Send_uint16((uint16)dwSymbolSet); Send_attr_ubyte(eSymbolSet); Send_cmd(eSetFont); // // TrueType font outline or device font // Font Scale // Font bold/italic simulaiton // if (fonttype == kFontTypeTTOutline || fonttype == kFontTypeDevice ) { if (dwFontWidth != pGState->GetFontWidth() || dwFontHeight != pGState->GetFontHeight() ) { // // Scale X and Y // if (dwFontWidth != 0 && dwFontHeight != dwFontWidth) { FLOATOBJ fTemp; FLOATOBJ_SetLong(&fTemp, dwFontWidth); FLOATOBJ_DivFloat(&fTemp, fSize); lvalue = FLOATOBJ_GetFloat(&fTemp); Send_real32_xy((real32)lvalue, (real32)real32_IEEE_1_0F); Send_attr_ubyte(eCharScale); Send_cmd(eSetCharScale); } else { Send_real32_xy((real32)real32_IEEE_1_0F, (real32)real32_IEEE_1_0F); Send_attr_ubyte(eCharScale); Send_cmd(eSetCharScale); } } DWORD dwCurrentFontSim = pGState->GetFontSimulation(); // // Bold simulation // if ((dwFontSimulation & XLOUTPUT_FONTSIM_BOLD) != (dwCurrentFontSim& XLOUTPUT_FONTSIM_BOLD)) { if (dwFontSimulation & XLOUTPUT_FONTSIM_BOLD) { // // Hardcoded bold value 0.01500 // #define XL_BOLD_VALUE 0x3c75c28f Send_real32((real32)XL_BOLD_VALUE); } else Send_real32((real32)0); Send_attr_ubyte(eCharBoldValue); Send_cmd(eSetCharBoldValue); } // // Italic simulation // if ((dwFontSimulation & XLOUTPUT_FONTSIM_ITALIC) != (dwCurrentFontSim & XLOUTPUT_FONTSIM_ITALIC)) { if (dwFontSimulation & XLOUTPUT_FONTSIM_ITALIC) { // // Hardcoded italic value 0.316200 // #define XL_ITALIC_VALUE 0x3ea1e4f7 Send_real32_xy((real32)XL_ITALIC_VALUE, (real32)0); } else Send_real32_xy((real32)0, (real32)0); Send_attr_ubyte(eCharShear); Send_cmd(eSetCharShear); } // // Vertical font simulation // if ((dwFontSimulation & XLOUTPUT_FONTSIM_VERTICAL) != (dwCurrentFontSim & XLOUTPUT_FONTSIM_VERTICAL)) { if (dwFontSimulation & XLOUTPUT_FONTSIM_VERTICAL) { Send_ubyte(eVertical); } else { Send_ubyte(eHorizontal); } Send_attr_ubyte(eWritingMode); Send_cmd(eSetCharAttributes); } } else { if (kFontTypeTTBitmap != pGState->GetFontType()) { // // Bitmap font can't be scaled x and y. Need to set 1 : 1. // Send_real32_xy((real32)real32_IEEE_1_0F, (real32)real32_IEEE_1_0F); Send_attr_ubyte(eCharScale); Send_cmd(eSetCharScale); } } // // Change GState to set current selected font. // pGState->SetFont(fonttype, pFontName, dwFontHeight, dwFontWidth, dwSymbolSet, dwFontSimulation); return S_OK; } HRESULT XLOutput:: SetSourceTxMode( TxMode SrcTxMode) /*++ Routine Description: Arguments: Return Value: Note: --*/ { XLGState *pGState = this; if (SrcTxMode == pGState->GetSourceTxMode()) { return S_OK; } if (S_OK == SetTxMode(SrcTxMode) && S_OK == Send_cmd(eSetSourceTxMode)) { pGState->SetSourceTxMode(SrcTxMode); return S_OK; } else { return S_FALSE; } } HRESULT XLOutput:: SetPaintTxMode( TxMode PaintTxMode) /*++ Routine Description: Arguments: Return Value: Note: --*/ { XLGState *pGState = this; if (PaintTxMode == pGState->GetPaintTxMode()) { return S_OK; } if (S_OK == SetTxMode(PaintTxMode) && S_OK == Send_cmd(eSetPatternTxMode)) { pGState->SetPaintTxMode(PaintTxMode); return S_OK; } else { return S_FALSE; } }