Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2417 lines
64 KiB

/*++
Copyright (c) 1990-1991 Microsoft Corporation
Module Name:
htpat.c
Abstract:
This module contains all the functions which generate the halftone
patterns (brushs) to be used for later halftone process.
Author:
23-Apr-1992 Thu 20:01:55 updated -by- Daniel Chou (danielc)
changed 'CHAR' type to 'BYTE' type, this will make sure if compiled
under MIPS the default 'unsigned char' will not affect the signed
operation on the single 8 bits
15-Jan-1991 Tue 21:09:33 created -by- Daniel Chou (danielc)
[Environment:]
GDI Device Driver - Halftone.
[Notes:]
Revision History:
Change DrawPatLine() function to DrawCornerLine(), and speed up the
process by only using integer operation for modified DDA.
--*/
#define DBGP_VARNAME dbgpHTPat
#include "htp.h"
#include "htmath.h"
#include "htmapclr.h"
#include "htrender.h"
#include "htpat.h"
#include "stdio.h"
#ifdef UMODE
#include <search.h>
#endif
#define DBGP_REGRESS 0x0001
#define DBGP_SHOWBRUSH 0x0002
#define DBGP_DRAWLINE 0x0004
#define DBGP_CACHEDPAT 0x0008
#define DBGP_PATSIZE 0x0010
#define DBGP_BRUSHORG 0x0020
#define DBGP_SHOW_CACHEDPAT 0x0040
#define DBGP_SHOW_HTCELL 0x0080
DEF_DBGPVAR(BIT_IF(DBGP_REGRESS, 0) |
BIT_IF(DBGP_SHOWBRUSH, 0) |
BIT_IF(DBGP_DRAWLINE, 0) |
BIT_IF(DBGP_CACHEDPAT, 0) |
BIT_IF(DBGP_PATSIZE, 0) |
BIT_IF(DBGP_BRUSHORG, 0) |
BIT_IF(DBGP_SHOW_CACHEDPAT, 0) |
BIT_IF(DBGP_SHOW_HTCELL, 0))
//
// This array of bytes are the internal halftone pattern thresholds, they
// group together for saving the spaces and easy reference, we will using
// INTERNALPATTERN to reach any bytes defined in this array.
//
#define IPD_SIZE_OFFSET 0
#define IPD_CX_OFFSET 1
#define IPD_CY_OFFSET 2
#define IPD_PATTERN_OFFSET 3
#define IPD_HEADER_SIZE (IPD_PATTERN_OFFSET)
// #define ADD_REG_MODE (REGRESS_MODE_FLAG_L_LOG | REGRESS_MODE_LOG)
#define ADD_REG_MODE REGRESS_MODE_LINEAR
#define SUB_REG_MODE (REGRESS_MODE_FLAG_L_LOG | REGRESS_MODE_LOG)
#define BRUSH_REG_MODE (REGRESS_MODE_FLAG_L_LOG | REGRESS_MODE_POWER)
#if DBG
BYTE ADDITIVE_REG_MODE = ADD_REG_MODE; // REGRESS_MODE_POWER;
BYTE SUBSTRACTIVE_REG_MODE = SUB_REG_MODE;
BYTE SUB_BRUSH_REG_MODE = BRUSH_REG_MODE;
#else
#define ADDITIVE_REG_MODE ADD_REG_MODE
#define SUBSTRACTIVE_REG_MODE SUB_REG_MODE
#define SUB_BRUSH_REG_MODE BRUSH_REG_MODE
#endif
BYTE InternalPatternData[] = {
2, 2, 2, // 2x2
1, 2, //
8, 4, 4, // 4x4
7, 1, 2, 5, //
6, 3, 4, 8,
18, 6, 6, // 6x6
12, 9, 6, 7, 10, 14, //
17, 5, 1, 2, 15, 18,
11, 8, 3, 4, 13, 16,
32, 8, 8, // 8x8
28, 18, 14, 5, 9, 16, 19, 21, //
29, 27, 1, 2, 6, 10, 22, 32,
30, 26, 3, 4, 7, 11, 23, 31,
25, 20, 13, 8, 12, 15, 17, 24,
50, 10, 10, // 10x10
36, 28, 25, 21, 10, 11, 22, 26, 30, 38, //
45, 37, 20, 9, 1, 2, 12, 31, 42, 46,
50, 41, 19, 8, 3, 4, 5, 40, 47, 49,
43, 35, 18, 16, 7, 6, 13, 33, 44, 48,
34, 27, 24, 17, 15, 14, 23, 29, 32, 39,
72, 12, 12, // 12x12
50, 48, 39, 36, 32, 24, 13, 25, 33, 37, 41, 49,
67, 59, 47, 31, 23, 12, 5, 14, 26, 42, 57, 61,
70, 68, 53, 22, 11, 1, 2, 6, 15, 56, 62, 69,
71, 64, 54, 21, 10, 3, 4, 7, 16, 55, 65, 72,
63, 58, 44, 30, 20, 9, 8, 17, 27, 45, 60, 66,
52, 43, 40, 35, 29, 19, 18, 28, 34, 38, 46, 51,
98, 14, 14, // 14x14
76, 68, 58, 53, 48, 38, 23, 22, 37, 43, 47, 50, 54, 62,
88, 82, 73, 59, 39, 24, 15, 14, 21, 36, 42, 55, 70, 78,
94, 92, 83, 69, 25, 16, 12, 5, 13, 20, 35, 63, 79, 90,
98, 97, 86, 74, 26, 11, 1, 2, 6, 19, 34, 75, 87, 95,
96, 91, 81, 64, 27, 10, 3, 4, 7, 18, 33, 66, 84, 93,
89, 80, 72, 56, 44, 28, 9, 8, 17, 32, 41, 60, 71, 85,
77, 65, 57, 52, 49, 45, 29, 30, 31, 40, 46, 51, 61, 67,
128, 16, 16, // 16x16
93, 82, 74, 67, 64, 60, 52, 33, 34, 35, 53, 61, 65, 69, 77, 94,
110,102, 87, 73, 59, 51, 32, 24, 13, 25, 36, 54, 70, 85, 97,105,
122,115,101, 81, 50, 31, 23, 12, 5, 14, 26, 37, 78, 98,113,117,
127,121,109, 91, 49, 22, 11, 1, 2, 6, 15, 38, 89,106,118,125,
128,119,107, 92, 48, 21, 10, 3, 4, 7, 16, 39, 90,111,123,126,
120,114, 99, 79, 47, 30, 20, 9, 8, 17, 27, 40, 83,103,116,124,
108,100, 86, 71, 58, 46, 29, 19, 18, 28, 41, 55, 75, 88,104,112,
95, 80, 72, 66, 63, 57, 45, 44, 43, 42, 56, 62, 68, 76, 84, 96,
0 // no more
};
BYTE OD4x4Thresholds[] = {
1, 9, 3, 11,
13, 5, 15, 7,
4, 12, 2, 10,
16, 8, 14, 6
};
HTCELL HTCell_OD4x4 = { 4, 4, 16, 16, OD4x4Thresholds };
MONOPATRATIO MonoPatRatio[] = {
{ 2680, 2589 }, // 15 degree
{ 5774, 5000 }, // 30 degree
{ 10000, 7071 }, // 45 degree
{ 17321, 8660 }, // 60 degree
{ 37321, 9659 } // 75 degree
};
// 8765432187654321
// 8421842184218421
BYTE CircleDevPel[] = { 0x1f, 0xf8, // 1...@@@@@@@@@@...
0x7f, 0xfe, // 2.@@@@@@@@@@@@@@.
0x7f, 0xfe, // 3.@@@@@@@@@@@@@@.
0xff, 0xff, // 4@@@@@@@@@@@@@@@@
0xff, 0xff, // 5@@@@@@@@@@@@@@@@
0xff, 0xff, // 6@@@@@@@@@@@@@@@@
0xff, 0xff, // 7@@@@@@@@@@@@@@@@
0xff, 0xff, // 8@@@@@@@@@@@@@@@@
0xff, 0xff, // 9@@@@@@@@@@@@@@@@
0xff, 0xff, // 0@@@@@@@@@@@@@@@@
0xff, 0xff, // 1@@@@@@@@@@@@@@@@
0xff, 0xff, // 2@@@@@@@@@@@@@@@@
0xff, 0xff, // 3@@@@@@@@@@@@@@@@
0x7f, 0xfe, // 4.@@@@@@@@@@@@@@.
0x7f, 0xfe, // 5.@@@@@@@@@@@@@@.
0x1f, 0xf8 // 6...@@@@@@@@@@...
};
#if DBG
VOID
DbgShowThresholds(
LPBYTE pTitle,
PHTCELL pHTCell
)
/*++
Routine Description:
This is a debug functions which show all the HTCELL Infomation
Arguments:
pHTCell - HTCELL to be displayed
Return Value:
VOID
Author:
01-Feb-1995 Wed 14:24:45 created -by- Daniel Chou (danielc)
Revision History:
--*/
{
//
// Output some information
//
DBGP_IF(DBGP_SHOW_HTCELL,
{
LPBYTE pbPat;
LPBYTE pbBuf;
BYTE Buf[256];
UINT xLoop;
UINT yLoop;
DBGP("\n*** %s ****\n\n%ldx%ld=%ld, Step=%ld\n\n"
ARGDW(pTitle)
ARGDW(pHTCell->Width) ARGDW(pHTCell->Height)
ARGDW(pHTCell->Size) ARGDW(pHTCell->DensitySteps));
yLoop = pHTCell->Height;
pbPat = pHTCell->pThresholds;
while (yLoop--) {
xLoop = (UINT)pHTCell->Width;
pbBuf = Buf;
while (xLoop--) {
pbBuf += sprintf(pbBuf, "%3u ", (UINT)*pbPat++);
}
DBGP(Buf);
}
}
)
}
VOID
CheckRegression(
LPSTR pName,
PREGRESS pRegress
)
/*++
Routine Description:
Output debugging Regression test result
Arguments:
pRegress - Pointer to REGRESS data structure which already done the
regression test
Return Value:
VOID
Author:
02-Feb-1995 Thu 19:53:14 created -by- Daniel Chou (danielc)
Revision History:
--*/
{
DBGP_IF(DBGP_REGRESS,
{
FD6 X;
FD6 Y;
DBGP("*** %s Regression Y -> X Test ***" ARG(pName));
for (Y = FD6_0; Y <= FD6_1; Y += (FD6)(FD6_1 / 50)) {
X = Y;
RegressXFromY(&X, pRegress, 1);
DBGP("Y -> X: %s ---> %s = %ld [%s]"
ARGFD6(Y, 2, 4)
ARGFD6(X, 2, 4)
ARGDW(MulFD6(X, pRegress->DataCount))
ARGFD6(FD6_1 - X, 2, 4));
}
}
)
}
#endif
//
// Following 2 compare functions are locally used for qsort
//
INT
_CRTAPI1
ThresholdCompare(
const void *pDevPelQS1,
const void *pDevPelQS2
)
{
return((INT)(((PDEVPELQS)pDevPelQS1)->PelData.Threshold) -
(INT)(((PDEVPELQS)pDevPelQS2)->PelData.Threshold));
}
INT
_CRTAPI1
ToneValueCompare(
const void *pDevPelQS1,
const void *pDevPelQS2
)
{
return((INT)(((PDEVPELQS)pDevPelQS1)->PelData4.ToneValue) -
(INT)(((PDEVPELQS)pDevPelQS2)->PelData4.ToneValue));
}
LONG
HTENTRY
ThresholdsFromYData(
PDEVICECOLORINFO pDCI,
LPWORD pToneMap,
WORD MaxToneValue,
PPATINFO pPatInfo
)
/*++
Routine Description:
This function do the regression analysis based on the device's pel info
and halftone cell info.
Arguments:
pDeviceColorInfo - Pointer to the DEVICECOLORINFO data structure, this
function allocate the HTDyeDensity[] and put the
pointer in this data structure for later references.
Return Value:
The return value is the total bits turned on which were not previouesly
turned on in the halftone pattern pels cell.
Author:
24-May-1991 Fri 22:30:43 created -by- Daniel Chou (danielc)
Revision History:
--*/
{
PDEVPELQS pDevPelQS;
LPBYTE pThresholds;
PFD6 pYData;
PATINFO PatInfo;
DEVPELQS DevPelQS;
WORD PrevToneValue;
WORD CurToneValue;
WORD DensitySteps;
WORD Index;
PatInfo = *pPatInfo;
Index = (WORD)sizeof(DEVPELQS) * (WORD)(PatInfo.HTCell.Size + 1);
if (!(PatInfo.pYData = (LPBYTE)HTLocalAlloc((DWORD)PDCI_TO_PDHI(pDCI),
"ThresholdsFromYData-pYData",
NONZEROLPTR,
Index))) {
return(HTERR_INSUFFICIENT_MEMORY);
}
for (Index = 0, pDevPelQS = (PDEVPELQS)PatInfo.pYData;
Index < PatInfo.HTCell.Size; Index++) {
if ((!(DevPelQS.PelData4.ToneValue = *pToneMap++)) ||
(DevPelQS.PelData4.ToneValue > MaxToneValue)) {
HTLocalFree((HLOCAL)PatInfo.pYData);
return(HTERR_INVALID_TONEMAP_VALUE);
}
DevPelQS.PelData4.Index = Index;
*pDevPelQS++ = DevPelQS;
}
pDevPelQS->PelData4.ToneValue = (WORD)0; // stop at here
pDevPelQS = (PDEVPELQS)(pYData = (PFD6)(pPatInfo->pYData = PatInfo.pYData));
qsort((LPVOID)pYData,
PatInfo.HTCell.Size,
sizeof(DEVPELQS),
ToneValueCompare);
pThresholds = PatInfo.HTCell.pThresholds;
PrevToneValue = 0;
DensitySteps = 1;
while (CurToneValue = (WORD)pDevPelQS->PelData4.ToneValue) {
*(pThresholds + pDevPelQS->PelData4.Index) = (BYTE)DensitySteps;
if (CurToneValue != PrevToneValue) {
*pYData++ = DivFD6((FD6)CurToneValue, (FD6)MaxToneValue);
PrevToneValue = CurToneValue;
if (++DensitySteps >= (WORD)PRIM_INVALID_DENSITY) {
--DensitySteps;
}
}
++pDevPelQS;
}
return(DensitySteps);
}
#define GETMASKDEST(i) (BYTE)(HIBYTE(SrcWord) & sm.Mask[(i)])
LONG
HTENTRY
YDataFromThresholds(
PDEVICECOLORINFO pDCI,
PPATINFO pPatInfo
)
/*++
Routine Description:
This function do the regression analysis based on the device's pel info
and halftone cell info.
Arguments:
pDeviceColorInfo - Pointer to the DEVICECOLORINFO data structure, this
function allocate the HTDyeDensity[] and put the
pointer in this data structure for later references.
Return Value:
The return value is the total bits turned on which were not previouesly
turned on in the halftone pattern pels cell.
Author:
24-May-1991 Fri 22:30:43 created -by- Daniel Chou (danielc)
30-Nov-1994 Wed 14:51:52 updated -by- Daniel Chou (danielc)
Make sure DWORD aligned pShiftMask
30-Mar-1995 Thu 08:48:43 updated -by- Daniel Chou (danielc)
Not return HTERR_INVALID_DEVICE_RESOLUTION but compute the minimum
acceptable size
Revision History:
--*/
{
LPBYTE pCellData;
LPBYTE pDest;
LPBYTE pDestCur;
LPBYTE pSrc;
LPBYTE pThresholds;
PFD6 pYData;
PSHIFTMASK pShiftMask;
PDEVPELQS pDevPelQS;
PATINFO PatInfo;
SHIFTMASK sm;
DEVPELQS DevPelQS;
FD6 PelCX;
FD6 PelCY;
DWORD OnBits;
DWORD NewBits;
DWORD CurBits;
DWORD TotalBits;
WORD BegY;
WORD SrcWord;
WORD DataCount;
WORD SizeQS;
WORD SizeSM;
WORD SizeCell;
WORD CellCX;
WORD CellCY;
WORD CellCXBytes;
SHORT CXWrapSize;
WORD x;
WORD y;
INT Loop;
BYTE DestByte;
BYTE Count;
BYTE CurIndex;
BYTE BitsLookUp[256];
//
// First we have to make sure we have enough memory to do the job
//
PatInfo = *pPatInfo;
if (PatInfo.DevicePelsDPI) {
PelCX = DivFD6(FD6xL(PatInfo.DevicePelsDPI, DEV_PEL_CX),
PatInfo.DeviceResXDPI);
PelCY = DivFD6(FD6xL(PatInfo.DevicePelsDPI, DEV_PEL_CY),
PatInfo.DeviceResYDPI);
} else {
PelCX = INTToFD6(DEV_PEL_CX);
PelCY = INTToFD6(DEV_PEL_CY);
}
CellCX = (WORD)MulFD6(PelCX, (FD6)PatInfo.HTCell.Width);
CellCY = (WORD)MulFD6(PelCY, (FD6)PatInfo.HTCell.Height);
//
// The device pel just to big compare to its resolution/halftone cell,
// now make it to the minimum acceptable size
//
if (CellCX <= (WORD)DEV_PEL_CX) {
CellCX = (WORD)(DEV_PEL_CX + 1);
DBGP("HT: Warning - Invalid DeviceXDPI=%ld, PelsDPI=%ld, cxCELL Min.=%ld"
ARGDW(PatInfo.DeviceResXDPI)
ARGDW(PatInfo.DevicePelsDPI)
ARGDW(CellCX));
}
if (CellCY <= (WORD)DEV_PEL_CX) {
CellCY = (WORD)(DEV_PEL_CX + 1);
DBGP("HT: Warning - Invalid DeviceYDPI=%ld, PelsDPI=%ld, cyCELL Min.=%ld"
ARGDW(PatInfo.DeviceResYDPI)
ARGDW(PatInfo.DevicePelsDPI)
ARGDW(CellCY));
}
//
// SizeQS, SizeSM are guaranteed DWORD aligned because DEVPELQS and
// SHIFTMASK structures are both DWORD aligned
//
CellCXBytes = (WORD)((CellCX + 7) >> 3); // byte boundary
DataCount = (SizeQS = (WORD)ALIGN_DW(sizeof(DEVPELQS),
(PatInfo.HTCell.Size + 1))) +
(SizeSM = (WORD)ALIGN_DW(sizeof(SHIFTMASK),
PatInfo.HTCell.Width)) +
(SizeCell = CellCY * CellCXBytes);
//
// Clear all the data to zero before it get use
//
if (!(PatInfo.pYData = (LPBYTE)HTLocalAlloc((DWORD)PDCI_TO_PDHI(pDCI),
"YDataFromThresholds-pYData",
LPTR,
DataCount))) {
return(HTERR_INSUFFICIENT_MEMORY);
}
//
// pYData, pShiftMask must assigned first, because SizeCell may not be
// DWORD aligned
//
pYData = (PFD6)(pPatInfo->pYData = PatInfo.pYData);
pShiftMask = (PSHIFTMASK)(PatInfo.pYData + SizeQS);
pCellData = (LPBYTE)pShiftMask + SizeSM;
pThresholds = PatInfo.HTCell.pThresholds;
//
// Now set up the qsort data for the device pel, and sort it
//
for (y = 0, pDevPelQS = (PDEVPELQS)pYData; y < PatInfo.HTCell.Height; y++) {
for (x = 0; x < PatInfo.HTCell.Width; x++) {
DevPelQS.PelData.Threshold = *pThresholds++;
DevPelQS.PelData.x = (BYTE)x;
DevPelQS.PelData.y = (BYTE)y;
*pDevPelQS++ = DevPelQS;
}
}
//
// Sort the Threshold value, so we can setup the incremental pel coverage
// for the regression analysis
//
qsort((LPVOID)pYData,
PatInfo.HTCell.Size,
sizeof(DEVPELQS),
ThresholdCompare);
//
// Compute the bits count look up table
//
DestByte = 0;
do {
CurIndex = 0x80;
Count = 0;
do {
if (DestByte & CurIndex) {
++Count;
}
} while (CurIndex >>= 1);
BitsLookUp[DestByte] = Count;
} while (++DestByte);
//
// Initialize all data required during the computations
//
CXWrapSize = -(SHORT)((CellCX - 1) >> 3);
TotalBits = (DWORD)CellCX * (DWORD)CellCY;
OnBits = 0;
NewBits = 0;
DataCount = 0;
DBGP_IF(DBGP_REGRESS,
DBGP("REGESS: PelsCX/CY = %s/%s, CellCX/CY=%2u/%2u, TotalBits=%lu"
ARGFD6(PelCX, 2, 4)
ARGFD6(PelCY, 2, 4)
ARGU(CellCX)
ARGU(CellCY)
ARGDW(TotalBits)));
//
// pYData points to the final FD6 ratios, and pDevPelQS points to the
// sorrted data, both use same buffer, but pYData will only updated after
// data item in pDevPelQS is no longer needed
//
pDevPelQS = (PDEVPELQS)pYData;
//
// Starting to traverse the threshold data
//
DevPelQS = *pDevPelQS++;
while (CurIndex = DevPelQS.PelData.Threshold) {
sm = pShiftMask[DevPelQS.PelData.x];
CurBits = 0;
if (!sm.BitsUsed[0]) {
BYTE BitsUsed;
INT Count;
INT Index;
BOOL Wrap;
//
// Compute for this X column
//
sm.BegX = (WORD)MulFD6(PelCX, (FD6)DevPelQS.PelData.x);
sm.XOffset = (WORD)(sm.BegX >> 3);
sm.Shift1st = (WORD)(sm.BegX & 0x07);
BitsUsed = 0;
Count = (INT)(8 - sm.Shift1st);
Index = 0;
Loop = 16;
while (Loop--) {
Wrap = (BOOL)(++sm.BegX >= CellCX);
++BitsUsed;
if ((!(--Count)) || (Wrap) || (!Loop)) {
if (Index >= 4) {
ASSERTMSG("Internal Error: INVALID DEVICE x/y/Pels Resolution(s)", FALSE);
HTLocalFree((HLOCAL)PatInfo.pYData);
return(HTERR_INVALID_DEVICE_RESOLUTION);
}
sm.BitsUsed[Index] = BitsUsed;
sm.Mask[Index] = (BYTE)~(0xff >> BitsUsed);
if (Index < 3) {
if (Wrap) {
sm.NextDest[Index] = CXWrapSize;
sm.BegX = 0;
} else {
sm.NextDest[Index] = 1;
}
}
Count = 8;
BitsUsed = 0;
++Index;
}
}
ASSERT((sm.BitsUsed[0] + sm.BitsUsed[1] + sm.BitsUsed[2] +
sm.BitsUsed[3]) == 16);
pShiftMask[DevPelQS.PelData.x] = sm; // save it back
}
if (!PatInfo.DevPelData) {
pSrc = (LPBYTE)CircleDevPel;
}
BegY = (WORD)MulFD6(PelCY, (FD6)DevPelQS.PelData.y);
pDest = pCellData + (BegY * CellCXBytes) + (WORD)sm.XOffset;
Loop = DEV_PEL_CY;
BegY = CellCY - BegY;
while (Loop--) {
//
// Get the DevPel Source, this is a 16x16 bitmap,
// or NULL for square
//
if (!(SrcWord = PatInfo.DevPelData)) {
SrcWord = (((WORD)*pSrc) << 8) | (WORD)*(pSrc + 1);
pSrc += 2;
}
//
// Get Starting Destination byte
//
DestByte = *(pDestCur = pDest);
//
// Advance the Dest for next scanline, noted we have to check if
// we wrap around in Y direction, it may be wrap more than once?
//
pDest += CellCXBytes;
if (!(--BegY)) {
BegY = CellCY;
pDest -= SizeCell;
}
//
// 1st Byte: Minimum has 2 bytes
//
DestByte ^= *pDestCur |= (BYTE)(GETMASKDEST(0) >> sm.Shift1st);
CurBits += (DWORD)BitsLookUp[DestByte];
//
// 2nd byte: Minimum has 2 bytes
//
SrcWord <<= sm.BitsUsed[0];
DestByte = *(pDestCur += sm.NextDest[0]);
DestByte ^= *pDestCur |= GETMASKDEST(1);
CurBits += (DWORD)BitsLookUp[DestByte];
if (sm.BitsUsed[2]) {
//
// If we have more than 2 bytes
//
SrcWord <<= sm.BitsUsed[1];
DestByte = *(pDestCur += sm.NextDest[1]);
DestByte ^= *pDestCur |= GETMASKDEST(2);
CurBits += (DWORD)BitsLookUp[DestByte];
if (sm.BitsUsed[3]) {
//
// If we have more than 3 bytes
//
SrcWord <<= sm.BitsUsed[2];
DestByte = *(pDestCur += sm.NextDest[2]);
DestByte ^= *pDestCur |= GETMASKDEST(3);
CurBits += (DWORD)BitsLookUp[DestByte];
}
}
}
//
// Get current location information, we will set the threshold to 255
// if the dot already covered by other dots
//
NewBits += CurBits;
pThresholds = PatInfo.HTCell.pThresholds +
(DevPelQS.PelData.y * PatInfo.HTCell.Width) +
DevPelQS.PelData.x;
DevPelQS = *pDevPelQS++;
*pThresholds = (BYTE)((CurBits) ? (DataCount + 1) : 255);
if ((CurIndex != DevPelQS.PelData.Threshold) && (NewBits)) {
//
// Compute the current on bits ratio
//
OnBits += NewBits;
*pYData++ = (FD6)OnBits;
NewBits = 0;
++DataCount;
DBGP_IF(DBGP_SHOW_CACHEDPAT,
{
LPBYTE pbCell;
LPBYTE pbData;
LPBYTE pbBuf;
BYTE Buf[512];
UINT xLoop;
UINT yLoop;
BYTE b;
BYTE Mask;
DBGP("\n");
pbCell = pCellData;
yLoop = (UINT)CellCY;
while (yLoop--) {
pbData = pbCell;
pbCell += CellCXBytes;
pbBuf = Buf;
xLoop = (UINT)CellCX;
Mask = 0;
while (xLoop--) {
if (!(Mask >>= 1)) {
Mask = 0x80;
b = *pbData++;
}
*pbBuf++ = ((b & Mask) ? 'Û' : '°');
}
*pbBuf = 0;
DBGP(Buf);
}
}
)
}
}
y = DataCount;
while (y--) {
PelCY = *(--pYData);
*pYData = FD6_1 - DivFD6(PelCY, (FD6)OnBits);
DBGP_IF(DBGP_REGRESS,
DBGP("REGESS: %2u - %s [%6lu] OnBits=%ld, TotalBits=%ld"
ARGU(y + 1)
ARGFD6(*pYData, 1, 6)
ARGDW(PelCY)
ARGDW(OnBits)
ARGDW(TotalBits)));
}
#if DBG
DbgShowThresholds("Halftone Pattern", &PatInfo.HTCell);
#endif
return(DataCount);
}
#undef GETMASKDEST
#ifdef HAS_ENHANCED_HTPAT
BOOL
MakeEnhancedHTPat(
PDEVICECOLORINFO pDCI,
PHTCELL pHTCell
)
/*++
Routine Description:
This function double the halftone pattern in width and copy flip the
uppper/lower half on the expanded pattern
Arguments:
pHTCell - Pointer to the cell to be rotated
Return Value:
BOOL
Author:
20-May-1995 Sat 16:37:31 created -by- Daniel Chou (danielc)
Revision History:
--*/
{
LPBYTE pPatSrc1;
LPBYTE pPatSrc2;
LPBYTE pPatDst;
HTCELL HTCell = *pHTCell;
UINT OldWidth;
WORD i;
WORD j;
ASSERT((HTCell.Height & 0x01) == 0);
HTCell.Size <<= 1;
HTCell.Width <<= 1;
if (!(HTCell.pThresholds =
(LPBYTE)HTLocalAlloc((DWORD)PDCI_TO_PDHI(pDCI),
"MakeEnhanceHTPat-pThresholds",
NONZEROLPTR,
HTCell.Size))) {
return(FALSE);
}
OldWidth = pHTCell->Width;
pPatSrc1 = pHTCell->pThresholds;
pPatSrc2 = pPatSrc1 + (pHTCell->Size >> 1);
pPatDst = HTCell.pThresholds;
for (i = 0, j = (WORD)(HTCell.Height >> 1); i < HTCell.Height; i++, j--) {
//
// Copy the old pattern start from Upper part
//
CopyMemory(pPatDst, pPatSrc1, OldWidth);
pPatDst += OldWidth;
pPatSrc1 += OldWidth;
//
// Now Copy the old pattern from lower part
//
if (!j) {
pPatSrc2 = pHTCell->pThresholds;
}
CopyMemory(pPatDst, pPatSrc2, OldWidth);
pPatDst += OldWidth;
pPatSrc2 += OldWidth;
}
HTLocalFree((HLOCAL)pHTCell->pThresholds);
*pHTCell = HTCell;
#if DBG
DbgShowThresholds("Halftone Pattern", pHTCell);
#endif
return(TRUE);
}
#endif
VOID
RotateHTPat45(
PHTCELL pHTCell
)
/*++
Routine Description:
This function rotate the pattern 45 degree by copy first top half
and exchange left/right
Arguments:
pHTCell - Pointer to the cell to be rotated
Return Value:
VOID
Author:
07-Mar-1995 Tue 17:45:09 created -by- Daniel Chou (danielc)
Revision History:
--*/
{
LPBYTE pPatSrc;
LPBYTE pPatDst;
HTCELL HTCell = *pHTCell;
UINT SizeL;
UINT SizeR;
UINT Loop;
ASSERT((HTCell.Height & 0x01) == 0);
SizeL = (UINT)(HTCell.Width >> 1);
SizeR = (UINT)(HTCell.Width - SizeL);
Loop = (UINT)(HTCell.Height >> 1);
pPatSrc = HTCell.pThresholds;
pPatDst = pPatSrc + (Loop * HTCell.Width);
//
// for each scan line, we need to swap first half of the bytes
// with second half of the bytes, this will make the halftone
// pattern as 45 degree angle.
//
while (Loop--) {
CopyMemory(pPatDst, pPatSrc + SizeL, SizeR);
CopyMemory(pPatDst + SizeR, pPatSrc, SizeL);
pPatSrc += HTCell.Width;
pPatDst += HTCell.Width;
}
}
LONG
HTENTRY
ComputeHTCellRegress(
WORD HTPatternIndex,
PHALFTONEPATTERN pHalftonePattern,
PDEVICECOLORINFO pDCI
)
/*++
Routine Description:
This function creates the halftone threshold pattern and places them in
to supplied buffer.
Arguments:
HTPatternIndex - index to the internal halftone pattern, if this
number is not 0xffff.
pHalftonePattern - pointer to user's halftone pattern
pDCI - pointer to the DEVICECOLORINFO data structure. This
structure describes the required halftone pattern.
Return Value:
The return value is the size of the pattern copied or a zero
to indicate failure.
Author:
21-Jan-1991 Mon 12:47:48 created -by- Daniel Chou (danielc)
30-Mar-1995 Thu 13:56:45 updated -by- Daniel Chou (danielc)
Adding new brush regression
Revision History:
--*/
{
LPBYTE pDefPat;
PATINFO PatInfo;
REGRESS Regress;
LONG Result;
UINT SizeDefPat;
INT ModifyDefPatThresholds;
BOOL IsDefPat;
BOOL HasThresholdArray = FALSE;
if (IsDefPat = !(BOOL)pHalftonePattern) {
pDefPat = (LPBYTE)InternalPatternData;
ModifyDefPatThresholds = (INT)(HTPatternIndex & 0x01);
HTPatternIndex >>= 1;
while (HTPatternIndex--) {
if (!(SizeDefPat = (UINT)*(pDefPat + IPD_SIZE_OFFSET))) {
return(HTERR_INVALID_HTPATTERN_INDEX);
}
pDefPat += (SizeDefPat + IPD_HEADER_SIZE);
}
SizeDefPat = (UINT)*(pDefPat + IPD_SIZE_OFFSET);
PatInfo.HTCell.Width = (WORD)*(pDefPat + IPD_CX_OFFSET);
PatInfo.HTCell.Height = (WORD)*(pDefPat + IPD_CY_OFFSET);
} else {
if (pHalftonePattern->pToneMap) {
HasThresholdArray = (BOOL)(pHalftonePattern->Flags &
HTPF_THRESHOLD_ARRAY);
PatInfo.HTCell.Width = (WORD)pHalftonePattern->Width;
PatInfo.HTCell.Height = (WORD)pHalftonePattern->Height;
} else {
return(HTERR_NO_TONEMAP_DATA);
}
}
if ((PatInfo.HTCell.Width > MAX_HTPATTERN_WIDTH) ||
(PatInfo.HTCell.Height > MAX_HTPATTERN_HEIGHT)) {
return(HTERR_HTPATTERN_SIZE_TOO_BIG);
}
if (!(PatInfo.HTCell.Size = (WORD)PatInfo.HTCell.Width *
(WORD)PatInfo.HTCell.Height)) {
return(HTERR_INVALID_HALFTONE_PATTERN);
}
//
// Allocate the memory for the pattern buffer which we will stored the
// final halftone pattern for this device.
//
if (!(PatInfo.HTCell.pThresholds =
(LPBYTE)HTLocalAlloc((DWORD)PDCI_TO_PDHI(pDCI),
"ComputeHTCellRegress-pThresholds",
NONZEROLPTR,
PatInfo.HTCell.Size))) {
return(HTERR_INSUFFICIENT_MEMORY);
}
if ((IsDefPat) || (HasThresholdArray)) {
PatInfo.DevPelData = (WORD)((pDCI->Flags &
DCIF_SQUARE_DEVICE_PEL) ? 0xffff : 0);
if (!(PatInfo.DevicePelsDPI = pDCI->DevicePelsDPI)) {
PatInfo.DevPelData = (WORD)0xffff;
}
PatInfo.DeviceResXDPI = pDCI->DeviceResXDPI;
PatInfo.DeviceResYDPI = pDCI->DeviceResYDPI;
if (HasThresholdArray) {
//
// Use caller's pattern thresholds array
//
CopyMemory((LPBYTE)PatInfo.HTCell.pThresholds,
(LPBYTE)pHalftonePattern->pToneMap,
PatInfo.HTCell.Size);
} else {
LPBYTE pPatSrc;
WORD Threshold;
UINT Loop;
//
// copy the pattern which do not need to rotate.
//
CopyMemory(PatInfo.HTCell.pThresholds,
pDefPat + IPD_PATTERN_OFFSET,
SizeDefPat);
//
// if the internal pattern thresholds need to be modified, then we
// will modify the first half of it, then use it to generate the
// second half of the pattern threshold.
//
if (ModifyDefPatThresholds) {
//
// Because we already copied the source to the destination and
// we may need to modify the source, so Make the source point
// to the first byte of the destination.
//
// The way of thresholds modification works is that we try to
// make full use of the thresholds. Normally for example, a
// 8x8 pattern only has 32 levels, the thresholds modification
// will try to make it more than 32 levels such as make it to
// 60 levels.
//
pPatSrc = PatInfo.HTCell.pThresholds;
Loop = SizeDefPat;
while (Loop--) {
if ((Threshold = (WORD)((WORD)*pPatSrc << 1)) >=
(WORD)PRIM_INVALID_DENSITY) {
Threshold = (WORD)(PRIM_INVALID_DENSITY - 1);
}
*pPatSrc++ = (BYTE)Threshold;
}
}
//
// Rotate the default pattern to align in 45 degree
//
RotateHTPat45(&PatInfo.HTCell);
//
// Now check the second half of the threshold values
//
if (ModifyDefPatThresholds) {
pPatSrc = PatInfo.HTCell.pThresholds + (Loop = SizeDefPat);
while (Loop--) {
--*pPatSrc;
++pPatSrc;
}
#ifdef HAS_ENHANCED_HTPAT
MakeEnhancedHTPat(pDCI, &PatInfo.HTCell);
#endif
}
}
Result = YDataFromThresholds(pDCI, &PatInfo);
} else {
Result = ThresholdsFromYData(pDCI,
(LPWORD)pHalftonePattern->pToneMap,
(WORD)pHalftonePattern->MaxToneValue,
&PatInfo);
}
if (Result < 0L) {
return(Result);
} else if (Result < 2L) {
Result = HTERR_TONEMAP_VALUE_IS_SINGULAR;
} else {
//
// Fixed this one so that we will never regress for more than 254
//
if (Result >= PRIM_INVALID_DENSITY) {
Result = PRIM_INVALID_DENSITY - 1;
}
//
// The YRamge is the DevRGBGamma for the device halftone cell
//
PatInfo.HTCell.DensitySteps =
Regress.DataCount = (WORD)Result;
Regress.YRange = FD6_1;
pDCI->HTCell = PatInfo.HTCell;
Regress.Flags = (WORD)((pDCI->Flags & DCIF_ADDITIVE_PRIMS) ?
ADDITIVE_REG_MODE : SUBSTRACTIVE_REG_MODE);
if ((Result = RegressionAnalysis(PatInfo.pYData, &Regress)) > 0) {
pDCI->ClrXFormBlock.Regress = Regress;
#if DBG
CheckRegression("BITMAP", &Regress);
#endif
if (pDCI->Flags & DCIF_ADDITIVE_PRIMS) {
Regress.YRange = FD6_1;
Regress.Flags = (WORD)ADDITIVE_REG_MODE;
} else {
Regress.YRange = MulFD6(pDCI->ClrXFormBlock.DevRGBGamma,
pDCI->ClrXFormBlock.DevCIEPrims.Yw);
Regress.Flags = (WORD)SUB_BRUSH_REG_MODE;
}
if ((Result = RegressionAnalysis(PatInfo.pYData, &Regress)) > 0) {
pDCI->ClrXFormBlock.RegressBrush = Regress;
#if DBG
CheckRegression("BRUSH", &Regress);
#endif
}
}
}
return((HTLocalFree((HLOCAL)PatInfo.pYData)) ?
HTERR_CANNOT_DEALLOCATE_MEMORY : Result);
}
VOID
HTENTRY
DrawCornerLine(
LPBYTE pPattern,
WORD cxPels,
WORD cyPels,
WORD BytesPerScanLine,
WORD LineWidthPels,
BOOL FlipY
)
/*++
Routine Description:
This function draw a line from lower left corner to the upper right
corner, to draw a line from upper left corner to the lower right corner
just set the FlipY to true.
This is the modified integer DDA algorithm which the line always symmetry,
it make the line look less starsteps, if need to draw line from specified
(x1, y1) to (x2, y2) then this function can be modified whih only changed
to the startingt/end points for calculating the ErrorInc/ErrorDec/Error
and Length parameters.
Origin X, Y - at first pel of last scan line and the X moving to
the right and Y moving to the top.
Color - only black/white where white=0, and black=1
Arguments:
pPattern - The pointer to the buffer, it must already initialize
to all zero and must have the size in bytes of
BytesPerScanLine * cyPels
cxPels - The width in pels of the visible area in the pattern.
cyPels - The height of the pattern buffer in scan line.
BytesPerScanLine - Total bytes of one scan line.
LineWidthPels - The line width in pels which will be draw into the
pattern buffer, (pen width).
FlipY - If true then the final pattern will be up-side-down
Return Value:
No return value
Author:
24-May-1991 Fri 22:30:43 created -by- Daniel Chou (danielc)
Revision History:
20-Sep-1991 Fri 18:14:28 updated -by- Daniel Chou (danielc)
Updated so it only using interger operation only (fast) and plus
modified DDA so it will symmetric for better line constant brightness,
the parameters for this call is reduced by assuming that the line
is always drawing from corner to corner only.
--*/
{
LPBYTE pCurPat;
INT NextScanLine;
INT x;
INT y;
INT xLast;
INT yLast;
INT MinPels;
INT TotalPels;
INT xyInc[2];
INT Error;
INT ErrorInc;
INT ErrorDec;
INT Length;
BYTE DestMask;
BYTE DestByte;
ASSERT((LineWidthPels) && (LineWidthPels <= cxPels));
if (!LineWidthPels) {
return;
}
if ((cxPels == 1) || (cyPels == 1) || (LineWidthPels >= cxPels)) {
FillMemory(pPattern, BytesPerScanLine * cyPels, 0xff);
return;
}
if (FlipY) {
//
// Flip the Y, draw from top/left, it located at first line
//
NextScanLine = (INT)BytesPerScanLine;
} else {
//
// no Y flip so we have to draw from the lower left corner, and its
// buffer location is at last scan line
//
pPattern += ((LONG)BytesPerScanLine * (LONG)(cyPels - 1));
NextScanLine = -(INT)BytesPerScanLine;
}
//
// Calculate the X/Y increment and initial error values, remember we must
// always truncate the XInc/YInc values. how this works is that we keep a
// fixed floating point version of the error terms (15-bit fixed point
// value, one unit of fixed value is 0.000031) and has bit 15 (ie. 0x8000)
// as the overrun indicator, if after the X/Y increment and this bit is
// set then X/Y will need to increment by 1.
//
// At first we initialize the X/Y error terms to the half of the slope
// different, this way the DDA lines will be balanced distributed
// for the pels in the line resulting better constant line brightness and
// less stairsteps than the round up type of error term for reqular DDA.
//
// For drawing from starting points (x1, x2) to (x2, y2) (ie. point at
// (x2, y2) is exclusive) then using following changes
//
// xLast = x = x1;
// yLast = y = y1;
//
// change 'cxPels' to '(x2 - x1)' when calcaulate Inc/Dec/Error terms
// change 'cyPels' to '(y2 - y1)' when calcaulate Inc/Dec/Error terms
//
if (cxPels >= cyPels) {
xyInc[0] = 1;
xyInc[1] = 0;
ErrorDec = (INT)cxPels;
ErrorInc = (INT)cyPels;
} else {
xyInc[0] = 0;
xyInc[1] = 1;
ErrorDec = (INT)cyPels;
ErrorInc = (INT)cxPels;
}
Length = ErrorDec; // DeltaX = total run (larger one)
ErrorDec += ErrorDec; // Delta2X
Error = ErrorInc - ErrorDec; // DeltaY - Delta2X (initlal negative)
ErrorInc += ErrorInc; // Delta2Y
MinPels = (INT)LineWidthPels - 1;
if (cxPels > cyPels) {
if ((MinPels -= (INT)(cxPels / cyPels)) < 0) {
MinPels = 0;
}
}
TotalPels = MinPels;
xLast =
yLast =
x =
y = 0;
DBGP_IF(DBGP_DRAWLINE,
DBGP("[%3u:%3u]: pPat=%p, Err=%d, Inc=%d, Dec=%d, Pels=%d)"
ARGW(cxPels)
ARGW(cyPels)
ARG(pPattern)
ARGS(Error)
ARGS(ErrorInc)
ARGS(ErrorDec)
ARGW(LineWidthPels)));
//
// The single pel version of modified integer DDA for all octants is as
// following:
// ;
// while (Length--) { ; do until all DeltaX finished
// ;
// PlotPoint(x, y); ; Ploting point at (x,y)
// ;
// x += xyInc[0]; ; Increment either x or y by one
// y += xyInc[1]; ; unit depends on which octant.
// ;
// if ((Error += ErrorInc) >= 0) { ; adding error terms for shorter
// ; axis, integer sign operation.
// x += xyInc[1]; ; adding either x or y by one if
// y += xyInc[0]; ; 'pel' is closer to the slop.
// Error -= ErrorDec; ; reset the error term
// } ;
// }
//
while (Length--) { // do all the DeltaX pels
++TotalPels;
x += xyInc[0]; // x=running number 0-up
y += xyInc[1]; // y only need 0/1
if ((Error += ErrorInc) >= 0) {
x += xyInc[1];
y += xyInc[0];
Error -= ErrorDec;
}
if (y != yLast) {
ASSERT(y <= (INT)cyPels);
DestMask = (BYTE)(0x80 >> (xLast & 0x07)); // starting mask
pCurPat = pPattern + (xLast >> 3); // byte start
DestByte = (BYTE)0x00; // start w/0
DBGP_IF(DBGP_DRAWLINE,
DBGP("3u: Plot(%3d, %3d) %3d Pels, Next(x,y)=(%3d,%3d), Error=%d"
ARGS(Length)
ARGS(xLast)
ARGS(yLast)
ARGS(TotalPels)
ARGW(x)
ARGW(y)
ARGS(Error)));
while (TotalPels--) {
DestByte |= DestMask;
if (++xLast >= (INT)cxPels) {
//
// If we wrap around, we have get the old data byte back
// since first byte may already has some on bits.
//
*pCurPat = DestByte;
DestByte = *(pCurPat = pPattern);
DestMask = (BYTE)0x80;
xLast = 0;
} else if (!(DestMask >>= 1)) {
*pCurPat++ = DestByte;
DestMask = 0x80;
DestByte = 0x00;
}
}
//
// Since we using DestByte as temparory data area, we need to make
// sure that last modified data byte is saved back to the buffer,
// to do that we only need to check if Mask=0x80, because if the
// mask is equal to 0x80 then we just saved the byte, otherwise
// we are in middle of the byte processing, we could do this by
// extra checking for (TotalPels == 0) but this should check
// at outside of the (DestMask >>= 1) loop to reduced the overhead.
//
if (DestMask != (BYTE)0x80) {
*pCurPat = DestByte; // last one if any
}
pPattern += NextScanLine; // next scan line start
xLast = x; // remember this one
yLast = y; // reset y
TotalPels = MinPels;
}
}
ASSERT(y == (INT)cyPels);
}
LONG
HTENTRY
CreateStandardMonoPattern(
PDEVICECOLORINFO pDeviceColorInfo,
PSTDMONOPATTERN pStdMonoPat
)
/*++
Routine Description:
This function create standard pre-defined monochrome pattern to a
1 bit per pel bitmap, alignment of each bitmap scan line to the
specified
Arguments:
pDeviceColorInfo - Pointer to the DEVICECOLORINFO data structure, this
is used to get the device resolution information
pStdMonoPat - Pointer to the STDMONOPATTERN data structure.
NOTE: The pStdMonoPat->PatternIndex must be < HT_SMP_0_PERCENT_SCREEN
Return Value:
Retrun value will be the size of the final pattern, it will be <= 0 if an
error occurred and the return value is the halftone error code.
If the pPattern field in the pStdMonoPat data structure then only the
pattern size is returned.
Author:
24-May-1991 Fri 12:39:33 created -by- Daniel Chou (danielc)
Revision History:
18-Sep-1991 Wed 18:49:50 updated -by- Daniel Chou (danielc)
Fixed the bugs for the HORZ_VERT cross lines which has bad LineHeight
and LineWidh variables,
adding 2 decimal points accuracy when calculation the device pels to
prevent run away intermediate result.
--*/
{
LPBYTE pPat;
LPBYTE pTempPat;
STDMONOPATTERN StdMonoPat;
MONOPATRATIO PatRatio;
WORD DeviceResXDPI;
WORD DeviceResYDPI;
WORD DevicePelsDPI;
WORD Index;
WORD Loop;
WORD LineMode;
LONG PatSize;
DWORD YPels2; // retain 2 decimal points
DWORD LineWidth2; // retain 2 decimal points
DWORD LineHeight2; // retain 2 decimal points
DWORD LineSpace2; // retain 2 decimal points
WORD LineWidthPels;
WORD LineHeightPels;
BOOL FlipY;
BYTE Mask;
BYTE TempByte;
StdMonoPat = *pStdMonoPat;
ASSERTMSG("CreateStdMonoPattern: PatIndex >= HT_SMP_PERCENT_SCREEN(0)",
StdMonoPat.PatternIndex < HT_SMP_PERCENT_SCREEN(0));
DeviceResXDPI = pDeviceColorInfo->DeviceResXDPI;
DeviceResYDPI = pDeviceColorInfo->DeviceResYDPI;
DevicePelsDPI = pDeviceColorInfo->DevicePelsDPI;
FlipY = (BOOL)((StdMonoPat.Flags & SMP_TOPDOWN) ? FALSE : TRUE);
if (!StdMonoPat.LineWidth) {
StdMonoPat.LineWidth = DEFAULT_SMP_LINE_WIDTH;
}
if (!StdMonoPat.LinesPerInch) {
StdMonoPat.LinesPerInch = DEFAULT_SMP_LINES_PER_INCH;
}
LineSpace2 = (DWORD)DIVRUNUP((DWORD)DeviceResXDPI * 100L,
(DWORD)StdMonoPat.LinesPerInch);
LineWidth2 = (DWORD)DIVRUNUP((DWORD)StdMonoPat.LineWidth *
(DWORD)DeviceResXDPI,
10L);
switch (StdMonoPat.PatternIndex) {
case HT_SMP_HORZ_LINE:
case HT_SMP_VERT_LINE:
case HT_SMP_HORZ_VERT_CROSS:
YPels2 = LineSpace2; // default cyPels size
StdMonoPat.cxPels = (WORD)DIVRUNUP(LineSpace2, 100L);
if (StdMonoPat.PatternIndex == HT_SMP_HORZ_LINE) {
// Maximize to the width size of the alignbytes
StdMonoPat.cxPels = (WORD)StdMonoPat.ScanLineAlignBytes << 3;
} else if (StdMonoPat.PatternIndex == HT_SMP_VERT_LINE) {
YPels2 = 800L; // using 8 pels
}
break;
case HT_SMP_DIAG_15_LINE_UP:
case HT_SMP_DIAG_15_LINE_DOWN:
case HT_SMP_DIAG_15_CROSS:
case HT_SMP_DIAG_30_LINE_UP:
case HT_SMP_DIAG_30_LINE_DOWN:
case HT_SMP_DIAG_30_CROSS:
case HT_SMP_DIAG_45_LINE_UP:
case HT_SMP_DIAG_45_LINE_DOWN:
case HT_SMP_DIAG_45_CROSS:
case HT_SMP_DIAG_60_LINE_UP:
case HT_SMP_DIAG_60_LINE_DOWN:
case HT_SMP_DIAG_60_CROSS:
case HT_SMP_DIAG_75_LINE_UP:
case HT_SMP_DIAG_75_LINE_DOWN:
case HT_SMP_DIAG_75_CROSS:
Index = StdMonoPat.PatternIndex - (WORD)HT_SMP_DIAG_15_LINE_UP;
if (LineMode = (WORD)(Index % 3)) {
FlipY = !FlipY; // Down or Cross
}
PatRatio = MonoPatRatio[Index / 3];
StdMonoPat.cxPels = (WORD)DIVRUNUP(LineSpace2 * 100L,
(DWORD)PatRatio.Distance);
YPels2 = (DWORD)DIVRUNUP((DWORD)PatRatio.YSize * LineSpace2,
(DWORD)PatRatio.Distance);
LineWidth2 = (DWORD)DIVRUNUP(LineWidth2 * 10000L,
(DWORD)PatRatio.Distance);
break;
default: // all other percentage density
break;
}
//
// Now LineWidth2 = width of the line in pels (2 decimal points) and
// we have to compensate the size of pels which at most time is greater
// than its 'resolution', but since the distance between two device pels
// is assume to be its point 'resolution' so actually we just have to
// compensate the left/right edges of the total line width, the first
// and last pels that is.
//
// ResPels to reduced = (SizePel / SizeResolution)
// = (PelDPI / ResDPI) - 1.0
//
if (DevicePelsDPI) {
LineWidth2 -= (DWORD)DIVRUNUP((DWORD)DevicePelsDPI * 100L,
(DWORD)DeviceResXDPI) - (DWORD)100;
}
//
// Adjust YPels2 for the non-equal X/Y aspect ratio, the ratio is based
// one the XDPI
//
if (DeviceResXDPI != DeviceResYDPI) {
YPels2 = (DWORD)DIVRUNUP(YPels2 * (DWORD)DeviceResYDPI,
(DWORD)DeviceResXDPI);
}
//
// Convert to device pels and check all the zero term, the LineHeightPels
// only check later for the HORZ/VERT/HORZ_VERT_CROSS line types
//
if (!StdMonoPat.cxPels) {
++StdMonoPat.cxPels;
}
if (!(StdMonoPat.cyPels = (WORD)DIVRUNUP(YPels2, 100))) {
++StdMonoPat.cyPels;
}
if ((LineWidthPels = (WORD)DIVRUNUP(LineWidth2, 100)) >
StdMonoPat.cxPels) {
LineWidthPels = (WORD)(StdMonoPat.cxPels - 1);
}
if (!LineWidthPels) {
++LineWidthPels;
}
//
// calculate the buffer size for storing the pattern
//
StdMonoPat.BytesPerScanLine =
(WORD)ComputeBytesPerScanLine(BMF_1BPP,
StdMonoPat.ScanLineAlignBytes,
(LONG)StdMonoPat.cxPels);
PatSize = (LONG)(StdMonoPat.BytesPerScanLine * StdMonoPat.cyPels);
ASSERTMSG("StdMonoPattern Size Too big", PatSize < 0x10000L);
if (pPat = StdMonoPat.pPattern) {
ZeroMemory(pPat, (WORD)PatSize);
switch (StdMonoPat.PatternIndex) {
case HT_SMP_VERT_LINE:
case HT_SMP_HORZ_VERT_CROSS:
Index = (StdMonoPat.cxPels - (Loop = LineWidthPels)) >> 1;
pTempPat = pPat + (Index >> 3);
Mask = (BYTE)(0x80 >> (Index & 0x07));
TempByte = (BYTE)0;
//
// Do this for the first row then copy the rest
//
while (Loop--) {
TempByte |= Mask;
if ((!(Mask >>= 1)) || (!Loop)) {
*pTempPat++ = TempByte;
TempByte = (BYTE)0;
Mask = (BYTE)0x80;
}
}
for (Index = 0, pTempPat = pPat;
Index < StdMonoPat.cyPels;
Index++) {
CopyMemory(pTempPat, pPat, StdMonoPat.BytesPerScanLine);
pTempPat += StdMonoPat.BytesPerScanLine;
}
//
// Fall through
//
case HT_SMP_HORZ_LINE:
if (StdMonoPat.PatternIndex != HT_SMP_VERT_LINE) {
//
// Set Line Height according to the size of device Y
// resolution and its pel resolution. (see above for
// resolution pels reduction)
//
LineHeight2 = (DWORD)DIVRUNUP((DWORD)StdMonoPat.LineWidth *
(DWORD)DeviceResYDPI,
10L);
if (DevicePelsDPI) {
LineHeight2 -= (DWORD)DIVRUNUP((DWORD)DevicePelsDPI * 100L,
(DWORD)DeviceResYDPI) -
(DWORD)100;
}
if ((LineHeightPels = (WORD)DIVRUNUP(LineHeight2, 100)) >=
StdMonoPat.cyPels) {
LineHeightPels = (WORD)(StdMonoPat.cyPels - 1);
}
if (!LineHeightPels) {
++LineHeightPels;
}
FillMemory(pPat + (((StdMonoPat.cyPels -
LineHeightPels) >> 1) *
StdMonoPat.BytesPerScanLine),
LineHeightPels * StdMonoPat.BytesPerScanLine,
0xff);
}
break;
case HT_SMP_DIAG_15_LINE_UP:
case HT_SMP_DIAG_15_LINE_DOWN:
case HT_SMP_DIAG_15_CROSS:
case HT_SMP_DIAG_30_LINE_UP:
case HT_SMP_DIAG_30_LINE_DOWN:
case HT_SMP_DIAG_30_CROSS:
case HT_SMP_DIAG_45_LINE_UP:
case HT_SMP_DIAG_45_LINE_DOWN:
case HT_SMP_DIAG_45_CROSS:
case HT_SMP_DIAG_60_LINE_UP:
case HT_SMP_DIAG_60_LINE_DOWN:
case HT_SMP_DIAG_60_CROSS:
case HT_SMP_DIAG_75_LINE_UP:
case HT_SMP_DIAG_75_LINE_DOWN:
case HT_SMP_DIAG_75_CROSS:
DrawCornerLine(StdMonoPat.pPattern,
StdMonoPat.cxPels,
StdMonoPat.cyPels,
StdMonoPat.BytesPerScanLine,
LineWidthPels,
FlipY);
if (LineMode == 2) { // cross section
pTempPat = pPat + ((StdMonoPat.cyPels - 1) *
StdMonoPat.BytesPerScanLine);
//
// Make the up-side-down mirror which create a cross section
//
Index = StdMonoPat.cyPels >> 1;
while (Index--) {
Loop = StdMonoPat.BytesPerScanLine;
while (Loop--) {
*pPat++ = *pTempPat++ = (*pPat | *pTempPat);
}
pTempPat -= (StdMonoPat.BytesPerScanLine << 1);
}
pPat = StdMonoPat.pPattern; // restore address
}
break;
default: // all other percentage density
break;
}
if (StdMonoPat.Flags & SMP_0_IS_BLACK) {
Index = (WORD)PatSize;
while (Index--) {
*pPat++ ^= 0xff;
}
}
}
*pStdMonoPat = StdMonoPat;
return(PatSize);
}
LONG
HTENTRY
CachedHalftonePattern(
PHALFTONERENDER pHR
)
/*++
Routine Description:
This function create a cached pattern depends on the source color table,
if the source color table only has one entry and we are using the pattern
solid fill then the cached table will be the final color mask bits, else
the color table will be the color threshold values.
Note: the cached pattern will rotate both X, Y direction to aligned with
destination so that first pel/scanline in the cached pattern will
be corresponsed to the first pel in the destination.
Arguments:
pHR - Pointer to the HALFTONERENDER data structure.
Return Value:
The return value will be <= 0 if an error occurred and the return value is
the error code, otherwise the return value is the size of the cached
pattern allocated.
Author:
05-Mar-1991 Tue 11:08:18 created -by- Daniel Chou (danielc)
Revision History:
07-Jun-1991 Fri 17:23:16 updated -by- Daniel Chou (danielc)
Fixed pattern solid fill's pattern alignment problems
--*/
{
PDEVICECOLORINFO pDCI;
HTCELL HTCell;
LPBYTE pPat;
LPBYTE pPatXStart;
LPBYTE pThresholds;
OSIPAT Pattern;
INT PatXOff;
INT PatYOff;
INT PatCurX;
UINT XLoop;
UINT YLoop;
UINT PatXScale;
UINT PatSize;
BYTE SubValue;
BYTE OldValue;
//
// See how we will cached the halftone pattern
//
pDCI = pHR->HR_Header.pDeviceColorInfo;
if ((pDCI->Flags & DCIF_HAS_ALT_4x4_HTPAT) &&
((pHR->OutputSI.DestCBParams.SurfaceFormat == BMF_8BPP_VGA256) ||
(pHR->OutputSI.DestCBParams.SurfaceFormat == BMF_16BPP_555))) {
DBGP_IF(DBGP_CACHEDPAT,
DBGP("Use ALTERNATE 4x4 Pattern for Multiple Levels Device"));
HTCell = HTCell_OD4x4;
} else {
HTCell = pDCI->HTCell;
}
//
// We will always make the pattern width is multiple of 8, this will make
// the output process faster.
//
Pattern.WidthBytes = HTCell.Width;
Pattern.Height = HTCell.Height;
PatXScale = 0;
while ((Pattern.WidthBytes < (WORD)CACHED_PAT_MIN_WIDTH) ||
(Pattern.WidthBytes & (WORD)0x07)) {
++PatXScale;
Pattern.WidthBytes += HTCell.Width;
}
PatSize = Pattern.WidthBytes * Pattern.Height;
if (!(Pattern.pCachedPattern =
(LPBYTE)HTLocalAlloc((DWORD)PDCI_TO_PDHI(pDCI),
"CachedHalftonePattern-CachedPattern",
NONZEROLPTR,
PatSize))) {
return(HTERR_INSUFFICIENT_MEMORY);
}
//
// Save the Pattern back to pHR so it can be use to render later
//
pHR->OutputSI.Pattern = Pattern;
//
// Now construct the final pattern with pattern rotate X/Y to the right
// start,
//
// 1. Our render function getting the pattern from the end, so we must
// construct the pattern from right to left, this is why we add
// Pattern.WidthBytes - 1L
// 2. Our render function also automatically skip the FirstSkipPels
// so we will construct the whole pattern with roatation X/Y only
//
PatXOff = (INT)(((LONG)pHR->XStretch.PatternAlign +
(LONG)HTCell.Width - 1L -
(LONG)pHR->XStretch.DestEdge.FirstByteSkipPels) %
(LONG)HTCell.Width);
PatYOff = (INT)(pHR->YStretch.PatternAlign % (LONG)HTCell.Height);
//
// 25-Feb-1993 Thu 02:30:12 updated -by- Daniel Chou (danielc)
//
// Wrap the Pat X/Y offset so that it always counted as possitive number
//
if (PatXOff < 0) {
DBGP_IF(DBGP_BRUSHORG,
DBGP("\nPatXOff [%d] < 0, wrap around WIDTH [%d] --> %d"
ARGI(PatXOff)
ARGI(HTCell.Width)
ARGI(PatXOff + (INT)HTCell.Width)));
PatXOff += (INT)HTCell.Width;
}
if (PatYOff < 0) {
DBGP_IF(DBGP_BRUSHORG,
DBGP("\nPatYOff [%d] < 0, wrap around HEIGHT [%d] --> %d"
ARGI(PatYOff)
ARGU(HTCell.Height)
ARGI(PatYOff + (INT)HTCell.Height)));
PatYOff += (INT)HTCell.Height;
}
DBGP_IF(DBGP_CACHEDPAT,
DBGP("\nCACHED PATTERN - PrimAdj.Flags=%04x\n"
ARGW(pHR->HR_Header.pDevClrAdj->PrimAdj.Flags));
DBGP(" Dest Size: Start=(%ld, %ld), Size=(%ld x %ld)"
ARGDW(pHR->XStretch.DestBitOffset)
ARGDW(pHR->YStretch.DestBitOffset)
ARGDW(pHR->XStretch.DestExtend)
ARGDW(pHR->YStretch.DestExtend));
DBGP("Dest Skips: L=%u (0x%02x), R=%u (0x%02x), M=%ld bytes"
ARGW(pHR->XStretch.DestEdge.FirstByteSkipPels)
ARGW(pHR->XStretch.DestEdge.FirstByteMask)
ARGW(pHR->XStretch.DestEdge.LastByteSkipPels)
ARGW(pHR->XStretch.DestEdge.LastByteMask)
ARGDW(pHR->XStretch.DestFullByteSize));
DBGP(" PatSize: %u x %u ---> %u x %u = %u bytes"
ARGU(HTCell.Width) ARGU(HTCell.Height)
ARGU(Pattern.WidthBytes) ARGU(Pattern.Height)
ARGU(PatSize));
);
DBGP_IF(DBGP_BRUSHORG,
DBGP("PatAlign: (%ld, %ld) = (%d, %d) --Flip X--> (%d, %d)"
ARGDW(pHR->XStretch.PatternAlign)
ARGDW(pHR->YStretch.PatternAlign)
ARGI(((pHR->XStretch.PatternAlign % (LONG)HTCell.Width) +
(LONG)HTCell.Width) % (LONG)HTCell.Width)
ARGI(PatYOff) ARGI(PatXOff) ARGI(PatYOff)));
pPat = Pattern.pCachedPattern;
HTCell.pThresholds += (PatYOff * HTCell.Width) + PatXOff;
YLoop = (UINT)Pattern.Height;
//
// Cached pattern construction:
//
// 1. Aligned pattern Y start and wrap around at pattern height.
// 2. Aligned pattern at (pattern X start + pattern width) and moving
// from right to left, wrap around at begining of the pattern scan line
// 3. Invert the pattern threshold valus if it is a additive prims output.
//
if (pHR->HR_Header.pDevClrAdj->PrimAdj.Flags & DCA_USE_ADDITIVE_PRIMS) {
SubValue = (BYTE)(HTCell.DensitySteps + 1);
} else {
SubValue = 0;
}
DBGP_IF(DBGP_CACHEDPAT, DBGP("SubValue = %d" ARGU(SubValue)));
while (YLoop--) {
pThresholds = HTCell.pThresholds;
PatCurX = PatXOff;
pPatXStart = pPat;
XLoop = (UINT)HTCell.Width;
if (SubValue) {
while (XLoop--) {
//
// 255 is the invalide density, which will not used
//
if ((OldValue = *pThresholds--) == 255) {
*pPat++ = (BYTE)0;
} else {
*pPat++ = (BYTE)(SubValue - OldValue);
}
if (!(PatCurX--)) {
pThresholds += HTCell.Width; // wrap X around
PatCurX += (INT)HTCell.Width;
}
}
} else {
while (XLoop--) {
*pPat++ = (BYTE)*pThresholds--;
if (!(PatCurX--)) {
pThresholds += HTCell.Width; // wrap X around
PatCurX += (INT)HTCell.Width;
}
}
}
XLoop = PatXScale;
while (XLoop--) {
CopyMemory(pPat, pPatXStart, HTCell.Width);
pPat += HTCell.Width;
}
HTCell.pThresholds += HTCell.Width; // assume in range
if ((++PatYOff) >= (INT)Pattern.Height) {
HTCell.pThresholds -= HTCell.Size; // wrap Y around
PatYOff = 0;
}
}
return((LONG)PatSize);
}