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.
 
 
 
 
 
 

3441 lines
145 KiB

/******************************Module*Header*******************************\
* Module Name: aatext.cxx *
* *
* Routines for rendering anti aliased text to dib surfaces *
* *
* Created: 13-Mar-1995 10:44:05 *
* Author: Kirk Olynyk [kirko] *
* *
* Copyright (c) 1995 Microsoft Corporation *
\**************************************************************************/
#include "precomp.hxx"
extern "C" {
VOID vSrcTranCopyS4D16(
BYTE*,LONG,LONG,BYTE*,LONG,LONG,LONG,LONG,ULONG,ULONG,SURFACE*);
VOID vSrcTranCopyS4D24(
BYTE*,LONG,LONG,BYTE*,LONG,LONG,LONG,LONG,ULONG,ULONG,SURFACE*);
VOID vSrcTranCopyS4D32(
BYTE*,LONG,LONG,BYTE*,LONG,LONG,LONG,LONG,ULONG,ULONG,SURFACE*);
VOID vSrcOpaqCopyS4D32(
BYTE*,LONG,LONG,BYTE*,LONG,LONG,LONG,LONG,ULONG,ULONG,SURFACE*);
VOID vSrcOpaqCopyS4D16(
BYTE*,LONG,LONG,BYTE*,LONG,LONG,LONG,LONG,ULONG,ULONG,SURFACE*);
VOID vSrcOpaqCopyS4D24(
BYTE*,LONG,LONG,BYTE*,LONG,LONG,LONG,LONG,ULONG,ULONG,SURFACE*);
}
/********************************************************************
* *
* 16.16 fix point numbers representing *
* *
* aulB[16] = floor(65536 * (a[k]/16)^(1/gamma) + 1/2) *
* aulIB[k] = floor(65536 * (1 - a[k]/16)^(1/gamma) + 1/2) *
* *
* where a[k] = k == 0 ? 0 : k+1 *
* gamma = 2.33 *
********************************************************************/
static const ULONG aulB[16] =
{
0 , 26846 , 31949 , 36148 , 39781 , 43019 , 45961 , 48672 ,
51196 , 53564 , 55800 , 57923 , 59948 , 61885 , 63745 , 65536
};
static const ULONG aulIB[16] =
{ 0 , 3650 , 5587 , 7612 , 9735 , 11971 , 14339 , 16863 ,
19574 , 22516 , 25754 , 29387 , 33586 , 38689 , 45597 , 65536
};
/******************************Public*Routine******************************\
* *
* Routine Name: *
* *
* pvFillOpaqTable *
* *
* Routine Description: *
* *
* The case of opaqe text is special because the destiantion pixels *
* must be chosen from a set of 16 colors. This routine calculates *
* those 16 colors and puts them in an array. This array is addressed *
* by the value of the 4-bpp antialiased glyph. *
* *
* Let k be the value contained in a 4-bpp antialiased glyph value. *
* Thus the allowed range for k is *
* *
* k = 0,1..15 *
* *
* This is interpreted as a blending fraction alpha_k given by *
* *
* alpha_k = a_k / 16 *
* where *
* *
* a_k = (0,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16) *
* *
* The color values are normalized by the maximum color value *
* that a color channel can have, i_max *
* *
* For a single color channel, the normalized foreground and *
* background colors are given by *
* *
* c0 = i0 / i_max , *
* *
* c1 = i1 / i_max . *
* *
* The blended and gamma corrected color value is *
* *
* c_k = (1 - alpha_k) * c0^gam + alpha_k * c1^gam)^(1/gam) *
* *
* The unnormalized blended and gamma corrected color values *
* are: *
* *
* i_k = floor( i_max * c_k + 1/2) *
* *
* wbere 'gam' is the gamma correction value which I have chosen *
* to be equal to 2.33. *
* *
* In order to speed up the caluclation we cut corners by *
* making some approximations. The basic idea is to replace *
* the slow process of calculating various powers of real *
* numbers by table look up's. *
* *
* The first table G[i] is defined as follows: *
* *
* G[i] = floor(g_max * (i/i_max)^gam + 1/2) , *
* *
* where *
* *
* 0 <= i <= i_max , *
* and *
* 0 <= G[i] <= g_max . *
* *
* The second table is essentially the inverse to G[i], which *
* I shall call I[j]. *
* *
* I[j] = floor(i_max * (j / j_max)^(1/gam) + 1/2) , *
* *
* 0 <= j <= j_max . *
* *
* i_max = 31 (255) *
* g_max = 65536 *
* j_max = 256 *
* *
* The complete process of calculating the blended and gamma *
* corrected color is given by *
* *
* g = 16*G[i0]; *
* dg = G[i1] - G[i0]; *
* c = 16 * g_max / j_max; // 2^12 *
* for (k = 0; k < 16; k++) { *
* i[k] = I[ (g + c/2)/c]; *
* g += dg; *
* } *
* *
* Arguments: *
* *
* cj ............................... size of each array element in *
* BYTE's. *
* *
* uF ............................... a 32-bit value whose lowest *
* 16 bits contain the foreground *
* color *
* *
* uB ............................... a 32-bit value whose lowest 16 *
* bits contain the background *
* color *
* *
* pS ............................... pointer to destination surface *
* *
* Return Value: *
* *
* pointer to color table *
* *
\**************************************************************************/
#define vFreeOpaqTable(x) // this is the stub that free's the
// color table after it is used. Since
// the color table is permanent in memory
// there is no need to free it.
VOID *pvFillOpaqTable(ULONG size, ULONG uF, ULONG uB, SURFACE *pS)
{
int iRedL, iRedR; // shift numbers
int iGreL, iGreR; // shift numbers
int iBluL, iBluR; // shift numbers
ULONG uRed, dRed, flRed;
ULONG uGre, dGre, flGre;
ULONG uBlu, dBlu, flBlu;
ULONG ul;
static ULONG aulCache[16]; // set to zero prior to first call
static HANDLE hCache; // set to zero prior to first call
static ULONG uFCache;
static ULONG uBCache;
static ULONG sizeCache;
static VOID *pv = (VOID*) aulCache;
// I have been assured of two things....
// 1) Since this routine is a child of EngTextOut then there
// will be only one thread in this routine at any one time.
// This means that I do not need to protect the color
// table, aulCache[] with a critical section
// 2) I have been assured that the format of a surface
// is unique. Thus if the handle of the surface matches
// the handle of the cached color table, then the
// formats of the surface are the same.
if (pS->hGet() == hCache && uB == uBCache && uF == uFCache)
{
ASSERTGDI(size == sizeCache, "size != sizeCache");
}
else
{
sizeCache = size;
uFCache = uF;
uBCache = uB;
hCache = pS->hGet();
#if DBG
if (size == sizeof(USHORT))
{
ASSERTGDI(uF <= USHRT_MAX, "bad uF");
ASSERTGDI(uB <= USHRT_MAX, "bad uB");
}
else if (size == sizeof(ULONG))
{
ASSERTGDI(uF < 0x1000000, "bad uF");
ASSERTGDI(uB < 0x1000000, "bad uB");
}
else
{
RIP("bad size");
}
#endif
XEPALOBJ xpo(pS->pPal);
ASSERTGDI(xpo.bValid(), "Invalid XEPALOBJ" );
#if DBG
if (gflFontDebug & DEBUG_AA)
{
PALETTE *pPal = pS->pPal;
FLONG flPal = pPal->flPal;
DbgPrint(
"\n"
"Dumping PALETTE @ %-#x\n"
" flPal = %-#x\n"
, pPal
, flPal
);
if (flPal & PAL_INDEXED)
DbgPrint(" = PAL_INDEXED\n");
if (flPal & PAL_BITFIELDS)
DbgPrint(" = PAL_BITFIELDS\n");
if (flPal & PAL_RGB)
DbgPrint(" = PAL_RGB\n");
if (flPal & PAL_BGR)
DbgPrint(" = PAL_BGR\n");
if (flPal & PAL_DC)
DbgPrint(" = PAL_DC\n");
if (flPal & PAL_FIXED)
DbgPrint(" = PAL_FIXED\n");
if (flPal & PAL_FREE)
DbgPrint(" = PAL_FREE\n");
if (flPal & PAL_MANAGED)
DbgPrint(" = PAL_MANAGED\n");
if (flPal & PAL_NOSTATIC)
DbgPrint(" = PAL_NOSTATIC\n");
if (flPal & PAL_MONOCHROME)
DbgPrint(" = PAL_MONOCHROME\n");
if (flPal & PAL_BRUSHHACK)
DbgPrint(" = PAL_BRUSHHACK\n");
if (flPal & PAL_DIBSECTION)
DbgPrint(" = PAL_DIBSECTION\n");
DbgPrint(
" cEntries = %u\n"
" ulTime = %u\n"
" hdcHead = %-#x\n"
" hSelected = %-#x\n"
" cRefhpal = %u\n"
" cRefRegular = %u\n"
, pPal->cEntries
, pPal->ulTime
, pPal->hdcHead
, pPal->hSelected
, pPal->cRefhpal
, pPal->cRefRegular
);
DbgPrint(
" ptransFore = %-#x\n"
" ptransCurrent = %-#x\n"
" ptransOld = %-#x\n"
" hcmXform = %-#x\n"
" apalColor = %-#x\n"
"\n\n"
, pPal->ptransFore
, pPal->ptransCurrent
, pPal->ptransOld
, pPal->hcmXform
, pPal->apalColor
);
}
#endif
#if DBG
if (gflFontDebug & DEBUG_AA)
{
DbgPrint(
"pvFillOpaqTable(\n"
" SIZE_T size = %u\n"
" ULONG uF = %-#x\n"
" ULONG uB = %-#x\n"
" SURFACE *pS = %-#x\n"
" )\n"
, size, uF, uB, pS
);
DbgBreakPoint();
}
#endif
if (xpo.bIsBitfields())
{
flRed = xpo.flRed();
flGre = xpo.flGre();
flBlu = xpo.flBlu();
iRedR = (int) (xpo.cRedRight() + xpo.cRedMiddle() - 8);
iGreR = (int) (xpo.cGreRight() + xpo.cGreMiddle() - 8);
iBluR = (int) (xpo.cBluRight() + xpo.cBluMiddle() - 8);
}
else
{
int cBits;
ULONG flBits;
if (size == sizeof(USHORT))
{
// assumes standard RGB is 5+5+5 for 16-bit color
cBits = 5;
flBits = 0x1f;
}
else
{
cBits = 8;
flBits = 0xff;
}
if (xpo.bIsRGB())
{
flRed = flBits;
flGre = flRed << cBits;
flBlu = flGre << cBits;
iRedR = cBits - 8;
iGreR = iRedR + cBits;
iBluR = iGreR + cBits;
}
else if (xpo.bIsBGR())
{
flBlu = flBits;
flGre = flBlu << cBits;
flRed = flGre << cBits;
iBluR = cBits - 8;
iGreR = iBluR + cBits;
iRedR = iGreR + cBits;
}
else
{
RIP("Palette format not supported\n");
}
}
#define GAMMA (ULONG) RFONTOBJ::gTables[1]
/***************************************************************
* *
* Now I shall calculate the shift numbers. *
* *
* I shall explain the shift numbers for the red channel. *
* The green and blue channels are treated in the same way. *
* *
* I want to shift the red bits of the red channel colors *
* so that the most significant bit of the red channel *
* bits corresponds to a value of 2^7. This means that *
* if I mask off all of the other color bits, then I *
* will end up with a number between zero and 255. This *
* process of going to the 0 .. 255 range looks like *
* *
* ((color & flRed) << iRedL) >> iRedR *
* *
* Only on of iRedL or iRedR is non zero. *
* *
* I then use this number to index into a 256 element *
* gamma correction table. The gamma correction table *
* elements are BYTE values that are in the range 0 .. 255. *
* *
***************************************************************/
iRedL = 0;
if (iRedR < 0)
{
iRedL = - iRedR;
iRedR = 0;
}
uRed = GAMMA[(((uB & flRed) << iRedL) >> iRedR) & 255];
dRed = GAMMA[(((uF & flRed) << iRedL) >> iRedR) & 255];
dRed -= uRed;
uRed *= 16;
iGreL = 0;
if (iGreR < 0)
{
iGreL = - iGreR;
iGreR = 0;
}
uGre = GAMMA[(((uB & flGre) << iGreL) >> iGreR) & 255];
dGre = GAMMA[(((uF & flGre) << iGreL) >> iGreR) & 255];
dGre -= uGre;
uGre *= 16;
iBluL = 0;
if (iBluR < 0)
{
iBluL = - iBluR;
iBluR = 0;
}
uBlu = GAMMA[(((uB & flBlu) << iBluL) >> iBluR) & 255];
dBlu = GAMMA[(((uF & flBlu) << iBluL) >> iBluR) & 255];
dBlu -= uBlu;
uBlu *= 16;
#undef GAMMA
#if DBG
if (gflFontDebug & DEBUG_AA)
{
DbgPrint(
"flRed = %-#x\n"
"iRedL = %d\n"
"iRedR = %d\n"
"uRed = %-#x\n"
"dRed = %-#x\n"
, flRed, iRedL, iRedR, uRed, dRed
);
DbgPrint(
"flGre = %-#x\n"
"iGreL = %d\n"
"iGreR = %d\n"
"uRed = %-#x\n"
"dGre = %-#x\n"
, flGre, iGreL, iGreR, uGre, dGre
);
DbgPrint(
"flBlu = %-#x\n"
"iBluL = %d\n"
"iBluR = %d\n"
"uBlu = %-#x\n"
"dBlu = %-#x\n"
, flBlu, iBluL, iBluR, uBlu, dBlu
);
}
#endif
#define IGAMMA (ULONG) RFONTOBJ::gTables[0]
if (size == sizeof(USHORT))
{
USHORT *aus = (USHORT*) pv;
USHORT *pus = aus;
*pus++ = (USHORT) uB;
#if DBG
if (gflFontDebug & DEBUG_AA)
{
DbgPrint(
"Table of 16-bit colors ...\n"
"------------------------------------\n"
" %0-#4x %0-#4x %0-#4x = %0-#6x\n"
, (uB & flRed) >> xpo.cRedRight()
, (uB & flGre) >> xpo.cGreRight()
, (uB & flBlu) >> xpo.cBluRight()
, uB
);
}
#endif
while (pus < aus + 15)
{
ul = (((IGAMMA[(uRed += dRed)/16 & 255] << iRedR) >> iRedL) & flRed);
ul |= (((IGAMMA[(uGre += dGre)/16 & 255] << iGreR) >> iGreL) & flGre);
ul |= (((IGAMMA[(uBlu += dBlu)/16 & 255] << iBluR) >> iBluL) & flBlu);
*pus++ = (USHORT) ul;
#if DBG
if (gflFontDebug & DEBUG_AA)
{
DbgPrint(
" %0-#4x %0-#4x %0-#4x = %0-#6x\n"
, IGAMMA[uRed/16 & 255]
, IGAMMA[uGre/16 & 255]
, IGAMMA[uBlu/16 & 255]
, ul
);
}
#endif
}
*pus = (USHORT) uF;
#if DBG
if (gflFontDebug & DEBUG_AA)
{
DbgPrint(
" %0-#4x %0-#4x %0-#4x = %0-#6x\n"
, (uF & flRed) >> xpo.cRedRight()
, (uF & flGre) >> xpo.cGreRight()
, (uF & flBlu) >> xpo.cBluRight()
, uF
);
}
#endif
}
else
{
ASSERTGDI(size == sizeof(ULONG), "bad size");
ULONG *aul = (ULONG*) pv;
ULONG *pul = aul;
*pul++ = uB;
#if DBG
if (gflFontDebug & DEBUG_AA)
{
DbgPrint(
"Table of 32-bit colors .....\n"
"------------------------------------\n"
" %0-#4x %0-#4x %0-#4x = %0-#8x\n"
, (uB & flRed) >> xpo.cRedRight()
, (uB & flGre) >> xpo.cGreRight()
, (uB & flBlu) >> xpo.cBluRight()
, uB
);
}
#endif
while (pul < aul + 15)
{
ul = (((IGAMMA[(uRed += dRed)/16 & 255] << iRedR) >> iRedL) & flRed);
ul |= (((IGAMMA[(uGre += dGre)/16 & 255] << iGreR) >> iGreL) & flGre);
ul |= (((IGAMMA[(uBlu += dBlu)/16 & 255] << iBluR) >> iBluL) & flBlu);
*pul++ = ul;
#if DBG
if (gflFontDebug & DEBUG_AA)
{
DbgPrint(
"%0-#4x %0-#4x %0-#4x = %0-#8x\n"
, IGAMMA[uRed/16 & 255]
, IGAMMA[uGre/16 & 255]
, IGAMMA[uBlu/16 & 255]
, ul
);
}
#endif
}
*pul = uF;
#if DBG
if (gflFontDebug & DEBUG_AA)
{
DbgPrint(
" %0-#4x %0-#4x %0-#4x = %0-#8x\n"
, (uF & flRed) >> xpo.cRedRight()
, (uF & flGre) >> xpo.cGreRight()
, (uF & flBlu) >> xpo.cBluRight()
, uF
);
}
#endif
}
#undef IGAMMA
}
return(pv);
}
// Indices into the default palette
#define I_BLACK 0
#define I_DKGRAY 248
#define I_GRAY 7
#define I_WHITE 255
static const BYTE ajWhiteOnBlack[16] = {
I_BLACK , I_BLACK , I_DKGRAY , I_DKGRAY
, I_DKGRAY , I_GRAY , I_GRAY , I_GRAY
, I_GRAY , I_GRAY , I_GRAY , I_WHITE
, I_WHITE , I_WHITE , I_WHITE , I_WHITE
};
static const BYTE ajBlackOnWhite[16] = {
I_WHITE , I_WHITE , I_WHITE , I_WHITE
, I_GRAY , I_GRAY , I_GRAY , I_GRAY
, I_GRAY , I_DKGRAY , I_DKGRAY , I_DKGRAY
, I_DKGRAY , I_DKGRAY , I_BLACK , I_BLACK
};
static const BYTE ajBlackOnBlack[16] = {
I_BLACK, I_BLACK, I_BLACK, I_BLACK,
I_BLACK, I_BLACK, I_BLACK, I_BLACK,
I_BLACK, I_BLACK, I_BLACK, I_BLACK,
I_BLACK, I_BLACK, I_BLACK, I_BLACK
};
static const BYTE ajWhiteOnWhite[16] = {
I_WHITE, I_WHITE, I_WHITE, I_WHITE,
I_WHITE, I_WHITE, I_WHITE, I_WHITE,
I_WHITE, I_WHITE, I_WHITE, I_WHITE,
I_WHITE, I_WHITE, I_WHITE, I_WHITE
};
#if 0
/******************************Public*Routine******************************\
* *
* Routine Name *
* *
* vSrcOpaqCopyS4D8 *
* *
* Routine Description: *
* *
* Copies a 4bpp gray bitmap onto an 8bpp palettized surface. The *
* only case that this routine handles is white text on a black *
* background or black text on a white background. *
* *
* Arguments: *
* *
* pjSrcIn - pointer to beginning of current scan line of src buffer *
* This points to a 4-bit per pixel anti-aliased bitmap *
* whose scans start and end on 32-bit boundaries. *
* SrcLeft - left (starting) pixel in src rectangle *
* That is, this is the number of pixels in from the edge *
* of the start of each scan line that the actual pixels *
* of the image begins. All pixels before and after the *
* image pixels of the scan are to be ignored. This offset *
* has been put in to guarantee that 32-bit boundaries *
* in the 4bpp source correspond to 32-bit boundaries *
* in the destination. *
* DeltaSrcIn - bytes from one src scan line to next *
* pjDstIn - pointer to beginning of current scan line of Dst buffer *
* DstLeft - left(first) dst pixel *
* DstRight - exclusive right dst pixel *
* DeltaDstIn - bytes from one Dst scan line to next *
* cy - number of scan lines *
* uF - Foreground color *
* uB - Background color *
* pS - pointer to destination SURFACE *
* *
* If the destination suface is 8-bits per pixels then the only form *
* of antialiased text allowed is opaque textout with foreground and *
* background are either black or white. *
* *
* On palette devices (8-bit devices) we are guaranteed to have 4 shades *
* of gray to work with. These gray come from 4 of the 20 reserved *
* entries in the palette and are given by: *
* *
* name rgb index *
* *
* BLACK (0x00, 0x00, 0x00) 0 *
* DKGRAY (0x80, 0x80, 0x80) 12 *
* GRAY (0xc0, 0xc0, 0xc0) 7 *
* WHITE (0xff, 0xff, 0xff) 19 *
* *
* There are, two cases of interest: 1) white text on black; and 2) *
* black text on white. The various levels of gray seen on the screen *
* is controled by the 16 values of blending as defined by each of the *
* 4-bit gray levels in the glyphs images. The allowed value of blending *
* are: *
* *
* alpha[i] = (i == 0) ? 0 : (i+1)/16 *
* *
* where i = <value of 4-bit pixel> *
* *
* For case 1) (white text on a black background) the gamma corrected *
* color channel values are given by: *
* *
* c[i] = floor(255*(alpha[i]^(1/gamma)) + 1/2) *
* *
* which is equivalent to the following table *
* *
* c[16] = { 0, 104, 124, 141, *
* 155, 167, 179, 189, *
* 199, 208, 217, 225, *
* 233, 241, 248, 255 }; *
* *
* This result applies to each of the three color channels. *
* *
* The problem is that there are only four colors available: BLACK, DKGRAY, *
* GRAY, WHITE with the color values of 0, 128, 192, and 255 respectively. *
* This means that the color table that is used is an *
* approximation to the correct color table given by: *
* *
* c' = { BLACK, BLACK, *
* DKGRAY, DKGRAY, DKGRAY, *
* GRAY, GRAY, GRAY, GRAY, GRAY, GRAY, *
* WHITE, WHITE, WHITE, WHITE, WHITE }; *
* *
* For case 2) (black text on white) the gamma corrected color channel *
* values are given by: *
* *
* d[i] = floor(255*((1-alpha[i])^(1/gamma) + 1/2) = c[15 - i] *
* = *
* { *
* 255, 248, 241, 233, *
* 225, 217, 208, 199, *
* 189, 179, 167, 155, *
* 141, 124, 104, 0 *
* }; *
* *
* which is approximated by *
* *
* d' = { *
* WHITE, WHITE, WHITE, WHITE, *
* GRAY, GRAY, GRAY, GRAY, GRAY, *
* DKGRAY, DKGRAY, DKGRAY, DKGRAY, DKGRAY, *
* BLACK, BLACK *
* } *
* *
* *
* Return Value: *
* *
* None *
* *
\**************************************************************************/
VOID
vSrcOpaqCopyS4D8(
PBYTE pjSrcIn,
LONG SrcLeft,
LONG DeltaSrcIn,
PBYTE pjDstIn,
LONG DstLeft,
LONG DstRight,
LONG DeltaDstIn,
LONG cy,
ULONG uF,
ULONG uB,
SURFACE *pS
)
{
int cPreamble, cMiddle, cPostamble, A, B;
const BYTE *ajIndex;
BYTE jSrc, *pjSrc, *pjDst;
static const BYTE *apjIndex[4] = {
ajBlackOnBlack // uB = 0 uF = 0
, ajBlackOnWhite // uB = 0xff uF = 0
, ajWhiteOnBlack // uB = 0 uF = 0xff
, ajWhiteOnWhite // uB = 0xff uF = 0xff
};
#if DBG
if (gflFontDebug & DEBUG_AA)
{
DbgPrint(
"vSrcOpaqCopyS4D8(\n"
" PBYTE pjSrcIn = %-#x\n"
" LONG SrcLeft = %d\n"
" LONG DeltaSrcIn = %d\n"
" PBYTE pjDstIn = %-#x\n"
" LONG DstLeft = %d\n"
" LONG DstRight = %d\n"
" LONG DeltaDstIn = %d\n"
" LONG cy = %d\n"
" ULONG uF = %-#x\n"
" ULONG uB = %-#x\n"
" SURFACE *pS = %-#x\n"
");\n\n"
, pjSrcIn
, SrcLeft
, DeltaSrcIn
, pjDstIn
, DstLeft
, DstRight
, DeltaDstIn
, cy
, uF
, uB
, pS
);
DbgBreakPoint();
}
#endif
ASSERTGDI((uF == 0xff) || (uF == 0), "Bad Foreground Color\n");
ASSERTGDI((uB == 0xff) || (uB == 0), "Bad Background Color\n");
ASSERTGDI((unsigned) pjSrcIn % 4 == 0,
"Source buffer not 32-bit aligned\n");
ASSERTGDI((unsigned) DeltaSrcIn % 4 == 0,
"Source scans are not 32-bit aligned\n");
/******************************************************************
* Select the appropriate byte table *
* *
* I take advantage of the restricted values of the foreground and *
* background colors to form an index into a table. This requires *
* that the foreground and bacground colors be either 0 or -1. *
******************************************************************/
ajIndex = apjIndex[(uB & 1) + (uF & 2)];
/******************************************************************
* Each nyble of the source maps to a byte in the *
* destination. I want to separate the pixels into three *
* groups: preamble, middle, and postamble. The middle *
* pixels of the destination start and end on 32-bit *
* boundaries. The preamble and postamble are the *
* other pixels on the left and right respectively. *
* The preamble ends on a 32-bit address and the postamble *
* begins on a 32-bit address. *
* *
* It is possible for small images (1 or 2 wide) to be *
* contained completely within a DWORD of the destination such *
* that the destination image does not start on, contain, or *
* end on a 32-bit boundary. I treat this situation as *
* special cases. *
******************************************************************/
pjSrcIn += SrcLeft / 2; // 2 pixels per source byte
pjDstIn += DstLeft; // one byte per dest pixel
A = (DstLeft + 3) & ~3; // A = 4 * ceil(DstLeft/4)
B = (DstRight ) & ~3; // B = 4 * floor(DstRight/4)
if (B < A)
{
/*****************************************************
* There are only three ways that you can get here *
* *
* 1) DstLeft & 3 == 1 && DstRight == DstLeft + 1 *
* 2) DstLeft & 3 == 1 && DstRight == DstLeft + 2 *
* 3) DstLeft & 3 == 2 && DstRight == DstLeft + 1 *
*****************************************************/
if (DstLeft & 3 == 1)
{
*pjDstIn++ = ajIndex[*pjSrcIn++ & 15];
}
if (DstRight & 3 == 3)
{
*pjDstIn = ajIndex[*pjSrcIn >> 4];
}
}
else
{
cPreamble = A - DstLeft; // # pixels in preamble
cMiddle = (B - A)/4;
cPostamble = DstRight - B; // # pixels in postamble
for (; cy; cy--, pjSrcIn += DeltaSrcIn, pjDstIn += DeltaDstIn)
{
int cLast;
int i;
pjSrc = pjSrcIn;
pjDst = pjDstIn;
switch (cPreamble)
{
case 3:
jSrc = *pjSrc++;
*pjDst++ = ajIndex[jSrc & 15];
// fall through
case 2:
jSrc = *pjSrc;
*pjDst++ = ajIndex[jSrc >> 4];
// fall through
case 1:
jSrc = *pjSrc++;
*pjDst++ = ajIndex[jSrc & 15];
// fall through
}
for (i = 0 ; i < cMiddle ; i++)
{
jSrc = *pjSrc++;
*pjDst++ = ajIndex[jSrc >> 4];
*pjDst++ = ajIndex[jSrc & 15];
jSrc = *pjSrc++;
*pjDst++ = ajIndex[jSrc >> 4];
*pjDst++ = ajIndex[jSrc & 15];
}
if (cLast = cPostamble)
{
cLast -= 1;
jSrc = *pjSrc++;
*pjDst++ = ajIndex[jSrc >> 4];
if (cLast)
{
cLast -= 1;
*pjDst++ = ajIndex[jSrc & 15];
if (cLast)
{
jSrc = *pjSrc;
*pjDst++ = ajIndex[jSrc >> 4];
*pjDst++ = ajIndex[jSrc & 15];
}
}
}
}
}
}
/******************************Public*Routine******************************\
* *
* Routine Name *
* *
* vSrcTranCopyS4D8 *
* *
* Routine Description: *
* *
* Despite what the title implies this routine is not a `transparent' *
* copy of a 4bpp gray scale bitmap onto an arbitrary 8bpp surface. *
* What it really does is do an opaque copy of a 4bpp gray scale *
* bitmap onto an 8bpp surface EXCEPT for the case where the value *
* of the 4bpp gray scale pixel is zero. In that special case, the *
* destination pixel is untouched. This routine nearly identical to *
* the routine named `vSrcOpaqCopyS4D8' except that this routine tests *
* each 4bpp pixel to see if it is zero. *
* *
* Arguments: *
* *
* pjSrcIn - pointer to beginning of current scan line of src buffer *
* This points to a 4-bit per pixel anti-aliased bitmap *
* whose scans start and end on 32-bit boundaries. *
* SrcLeft - left (starting) pixel in src rectangle *
* That is, this is the number of pixels in from the edge *
* of the start of each scan line that the actual pixels *
* of the image begins. All pixels before and after the *
* image pixels of the scan are to be ignored. This offset *
* has been put in to guarantee that 32-bit boundaries *
* in the 4bpp source correspond to 32-bit boundaries *
* in the destination. *
* DeltaSrcIn - bytes from one src scan line to next *
* pjDstIn - pointer to beginning of current scan line of Dst buffer *
* DstLeft - left(first) dst pixel *
* DstRight - exclusive right dst pixel *
* DeltaDstIn - bytes from one Dst scan line to next *
* cy - number of scan lines *
* uF - Foreground color (0x00 or 0xff) *
* uB - Background color (not used) *
* pS - pointer to destination SURFACE *
* *
* Return Value: *
* *
* None *
* *
\**************************************************************************/
VOID
vSrcTranCopyS4D8(
PBYTE pjSrcIn,
LONG SrcLeft,
LONG DeltaSrcIn,
PBYTE pjDstIn,
LONG DstLeft,
LONG DstRight,
LONG DeltaDstIn,
LONG cy,
ULONG uF,
ULONG uB,
SURFACE *pS
)
{
int cPreamble, cMiddle, cPostamble, A, B;
const BYTE *ajIndex;
BYTE jSrc, *pjSrc, *pjDst;
static const BYTE *apjIndex[2] = {
ajBlackOnWhite // uF = 0 // black text
, ajWhiteOnBlack // uF = 0xFF // white text
};
#if DBG
if (gflFontDebug & DEBUG_AA)
{
DbgPrint(
"vSrcTranCopyS4D8(\n"
" PBYTE pjSrcIn = %-#x\n"
" LONG SrcLeft = %d\n"
" LONG DeltaSrcIn = %d\n"
" PBYTE pjDstIn = %-#x\n"
" LONG DstLeft = %d\n"
" LONG DstRight = %d\n"
" LONG DeltaDstIn = %d\n"
" LONG cy = %d\n"
" ULONG uF = %-#x\n"
" ULONG uB = %-#x\n"
" SURFACE *pS = %-#x\n"
");\n\n"
, pjSrcIn
, SrcLeft
, DeltaSrcIn
, pjDstIn
, DstLeft
, DstRight
, DeltaDstIn
, cy
, uF
, uB
, pS
);
DbgBreakPoint();
}
#endif
ASSERTGDI((uF == 0xff) || (uF == 0), "Bad Foreground Color\n");
ASSERTGDI((unsigned) pjSrcIn % 4 == 0,
"Source buffer not 32-bit aligned\n");
ASSERTGDI((unsigned) DeltaSrcIn % 4 == 0,
"Source scans are not 32-bit aligned\n");
static const BYTE ajTranWhiteOnBlack[16] = {
I_BLACK , I_BLACK , I_DKGRAY , I_DKGRAY
, I_DKGRAY , I_GRAY , I_GRAY , I_GRAY
, I_GRAY , I_GRAY , I_GRAY , I_WHITE
, I_WHITE , I_WHITE , I_WHITE , I_WHITE
};
static const BYTE ajBlackOnWhite[16] = {
I_WHITE , I_WHITE , I_WHITE , I_WHITE
, I_GRAY , I_GRAY , I_GRAY , I_GRAY
, I_GRAY , I_DKGRAY , I_DKGRAY , I_DKGRAY
, I_DKGRAY , I_DKGRAY , I_BLACK , I_BLACK
};
ajIndex = apjIndex[uF & 1];
pjSrcIn += SrcLeft / 2; // 2 pixels per source byte
pjDstIn += DstLeft; // one byte per dest pixel
A = (DstLeft + 3) & ~3; // A = 4 * ceil(DstLeft/4)
B = (DstRight ) & ~3; // B = 4 * floor(DstRight/4)
if (B < A)
{
if (DstLeft & 3 == 1)
{
jSrc = *pjSrc++;
if (jSrc & 15) // is gray pixel zero?
{
*pjDstIn = ajIndex[jSrc & 15]; // no, modify dest
}
pjDstIn++;
}
if (DstRight & 3 == 3)
{
if (jSrc = *pjSrcIn >> 4)
{
*pjDstIn = ajIndex[jSrc];
}
}
}
else
{
cPreamble = A - DstLeft;
cMiddle = (B - A)/4;
cPostamble = DstRight - B;
for (; cy; cy--, pjSrcIn += DeltaSrcIn, pjDstIn += DeltaDstIn)
{
int cLast;
int i;
pjSrc = pjSrcIn;
pjDst = pjDstIn;
switch (cPreamble)
{
case 3:
jSrc = *pjSrc++;
if (jSrc & 15)
{
*pjDst = ajIndex[jSrc & 15];
}
*pjDst++;
// fall through
case 2:
jSrc = *pjSrc;
if (jSrc >> 4)
{
*pjDst = ajIndex[jSrc >> 4];
}
*pjDst++;
// fall through
case 1:
jSrc = *pjSrc++;
if (jSrc & 15)
{
*pjDst = ajIndex[jSrc & 15];
}
pjDst++;
// fall through
}
for (i = 0; i < cMiddle ; i++)
{
jSrc = *pjSrc++;
if (jSrc >> 4)
{
*pjDst = ajIndex[jSrc >> 4];
}
pjDst++;
if (jSrc & 15)
{
*pjDst = ajIndex[jSrc & 15];
}
pjDst++;
jSrc = *pjSrc++;
if (jSrc >> 4)
{
*pjDst = ajIndex[jSrc >> 4];
}
pjDst++;
if (jSrc & 15)
{
*pjDst = ajIndex[jSrc & 15];
}
pjDst++;
}
if (cLast = cPostamble)
{
cLast -= 1;
jSrc = *pjSrc++;
if (jSrc >> 4)
{
*pjDst = ajIndex[jSrc >> 4];
}
pjDst++;
if (cLast)
{
cLast -= 1;
if (jSrc & 15)
{
*pjDst = ajIndex[jSrc & 15];
}
pjDst++;
if (cLast)
{
jSrc = *pjSrc;
if (jSrc >> 4)
{
*pjDst = ajIndex[jSrc >> 4];
}
pjDst++;
if (jSrc & 15)
{
*pjDst = ajIndex[jSrc & 15];
}
pjDst++;
}
}
}
}
}
}
#endif
/******************************Public*Routine******************************\
* *
* Routine Name *
* *
* vSrcOpaqCopyS4D16 *
* *
* Routine Description: *
* *
* Arguments: *
* *
* pjSrcIn - pointer to beginning of current scan line of src buffer *
* SrcLeft - left (starting) pixel in src rectangle *
* DeltaSrcIn - bytes from one src scan line to next *
* pjDstIn - pointer to beginning of current scan line of Dst buffer *
* DstLeft - left(first) dst pixel *
* DstRight - right(last) dst pixel *
* DeltaDstIn - bytes from one Dst scan line to next *
* cy - number of scan lines *
* uF - Foreground color *
* uB - Background color *
* pS - pointer to destination SURFACE *
* *
* Return Value: *
* *
* None *
* *
\**************************************************************************/
VOID
vSrcOpaqCopyS4D16(
PBYTE pjSrcIn,
LONG SrcLeft,
LONG DeltaSrcIn,
PBYTE pjDstIn,
LONG DstLeft,
LONG DstRight,
LONG DeltaDstIn,
LONG cy,
ULONG uF,
ULONG uB,
SURFACE *pS
)
{
int cPreamble, cMiddle, cPostamble, A, B;
USHORT *aus; // array of 16 possible colors
USHORT *pus; // convenient pointer into the color array
//
// If filling the color table in aus
// turns out to be time consuming we could cache the table
// off of the FONTOBJ and check to see if the foreground and
// background colors have not changed since the last time.
//
#if DBG
if (gflFontDebug & DEBUG_AA)
{
DbgPrint(
"vSrcOpaqCopyS4D16(\n"
" pjSrcIn = %-#x\n"
" SrcLeft = %-#x\n"
" pjDstIn = %-#x\n"
" DstLeft = %-#x\n"
" DstRight = %-#x\n"
" DeltaDstIn = %-#x\n"
" cy = %-#x\n"
" uF = %-#x\n"
" uB = %-#x\n"
" pS = %-#x\n"
, pjSrcIn
, SrcLeft
, pjDstIn
, DstLeft
, DstRight
, DeltaDstIn
, cy
, uF
, uB
, pS
);
DbgBreakPoint();
}
#endif
aus = (USHORT*) pvFillOpaqTable(sizeof(*aus), uF, uB, pS);
A = (DstLeft + 1) & ~1;
B = (DstRight ) & ~1;
pjSrcIn += SrcLeft/2;
pjDstIn += DstLeft * sizeof(USHORT);
cPreamble = A - DstLeft;
cMiddle = (B - A) / 2;
cPostamble = DstRight - B;
for (; cy; cy--, pjSrcIn += DeltaSrcIn, pjDstIn += DeltaDstIn)
{
int i;
BYTE jSrc;
BYTE *pjSrc = pjSrcIn;
USHORT *pusDst = (USHORT*) pjDstIn;
if (cPreamble)
{
jSrc = *pjSrc++;
*pusDst++ = aus[jSrc & 15];
}
for (i = 0; i < cMiddle; i++)
{
jSrc = *pjSrc++;
*pusDst++ = aus[jSrc >> 4];
*pusDst++ = aus[jSrc & 15];
}
if (cPostamble)
{
jSrc = *pjSrc;
*pusDst = aus[jSrc >> 4];
}
}
vFreeOpaqTable(aus);
}
/******************************Public*Routine******************************\
* *
* Routine Name *
* *
* vSrcTranCopyS4D16 *
* *
* Routine Description: *
* *
* Arguments: *
* *
* pjSrcIn - pointer to beginning of current scan line of src buffer *
* SrcLeft - left (starting) pixel in src rectangle *
* DeltaSrcIn - bytes from one src scan line to next *
* pjDstIn - pointer to beginning of current scan line of Dst buffer *
* DstLeft - left(first) dst pixel *
* DstRight - right(last) dst pixel *
* DeltaDstIn - bytes from one Dst scan line to next *
* cy - number of scan lines *
* uF - Foreground color *
* uB - Background color *
* pS - pointer to the FINAL destination SURFACE *
* *
* Return Value: *
* *
* None *
* *
\**************************************************************************/
VOID
vSrcTranCopyS4D16(
PBYTE pjSrcIn,
LONG SrcLeft,
LONG DeltaSrcIn,
PBYTE pjDstIn,
LONG DstLeft,
LONG DstRight,
LONG DeltaDstIn,
LONG cy,
ULONG uF,
ULONG uB,
SURFACE *pS
)
{
ULONG flRed, cRedRight, uRedF, flRedRight;
ULONG flGre, cGreRight, uGreF, flGreRight;
ULONG flBlu, cBluRight, uBluF, flBluRight;
ULONG uT, dT, u;
CONST ULONG *aul;
int cPreamble, cMiddle, cPostamble, A, B;
BYTE j;
XEPALOBJ xpo(pS->pPal);
ASSERTGDI(xpo.bValid(), "Invalid XEPALOBJ" );
if (xpo.bIsBitfields())
{
flRed = xpo.flRed(); // masks red bits
cRedRight = xpo.cRedRight();
flGre = xpo.flGre(); // masks green bits
cGreRight = xpo.cGreRight();
flBlu = xpo.flBlu(); // masks blu bits
cBluRight = xpo.cBluRight();
}
else if (xpo.bIsRGB())
{
WARNING("16 bit-RGB -- assuming 5+5+5\n");
flRed = 0x001f;
cRedRight = 0;
flGre = 0x03e0;
cGreRight = 5;
flBlu = 0x7c00;
cBluRight = 10;
}
else if (xpo.bIsBGR())
{
WARNING("16 bit-BGR -- assuming 5+5+5\n");
flRed = 0x7c00;
cRedRight = 10;
flGre = 0x03e0;
cGreRight = 5;
flBlu = 0x001f;
cBluRight = 0;
}
else
{
RIP("unsuported palette format\n");
}
uRedF = (uF & flRed) >> cRedRight;
flRedRight = flRed >> cRedRight;
uGreF = (uF & flGre) >> cGreRight;
flGreRight = flGre >> cGreRight;
uBluF = (uF & flBlu) >> cBluRight;
flBluRight = flBlu >> cBluRight;
#if DBG
if (gflFontDebug & DEBUG_AA)
{
DbgPrint(
"vSrcTranCopyS4D16(\n"
" pjSrcIn = %-#x\n"
" SrcLeft = %d\n"
" DeltaSrcIn = %d\n"
" pjDstIn = %-#x\n"
" DstLeft = %d\n"
" DstRight = %d\n"
" DeltaDstIn = %d\n"
" cy = %d\n"
" uF = %-#x\n"
" uB = %-#x\n"
" pS = %-#x\n"
, pjSrcIn
, SrcLeft
, DeltaSrcIn
, pjDstIn
, DstLeft
, DstRight
, DeltaDstIn
, cy
, uF
, uB
, pS
);
DbgPrint(
" flRed = %-#x\n"
" cRedRight = %d\n"
" uRedF = %-#x\n"
" flRedRight = %-#x\n"
, flRed, cRedRight, uRedF, flRedRight
);
DbgPrint(
" flGre = %-#x\n"
" cGreRight = %d\n"
" uGreF = %-#x\n"
" flGreRight = %-#x\n"
, flGre, cGreRight, uGreF, flGreRight
);
DbgPrint(
" flBlu = %-#x\n"
" cBluRight = %d\n"
" uBluF = %-#x\n"
" flBluRight = %-#x\n"
, flBlu, cBluRight, uBluF, flBluRight
);
DbgBreakPoint();
}
#endif
/*****************************************************************************
* *
* The CCC macro blends forground and background colors of a single color *
* channel. Gamma correction is taken into account using an approximate *
* correction scheme. uB contains all three background colors. We first *
* mask off the bits of interest and then shift them down until the *
* least significant color bit resides at the lowest bit of the dword. *
* The answer is placed in uT ("temporary ULONG"). This must be done for *
* each pixel in the destination. The same thing has been done for the *
* each of the forground color channels and placed in uRedF, uGreF, *
* and uBluF. These values do not change from pixel to pixel and so the *
* calculation of these down shifted forground color channel values is *
* done up front before the loop. Then for each color channel we *
* calculate the difference between the down-shifted forground- and *
* background color channels and place the answer in dT ("temporary *
* difference"). The approximate gamma correction is done in the *
* following manner: If the background color value is smaller than *
* the foreground color value then the approximate correction is: *
* *
* (c_f >= c_b): *
* *
* c = c_b + alpha_k ^ (1/gamma) * (c_f - c_b) *
* *
* (c_f <= c_b): *
* *
* c = c_b + (1 - (1 - alpha_k)^(1/gamma)) * (c_f - c_b) *
* *
* where *
* *
* c := blended color *
* c_b := background color *
* c_f := foreground color *
* alpha_k := k'th blending fraction = k == 0 ? 0 : (k+1)/16; *
* gamma := 2.33 *
* *
* I have storred all sixteen values of alpha_k ^ (1/gamma) in 16.16 *
* representation in an array ULONG aulB[16] and I have storred the *
* values of 1 - (1 - alpha_k)^(1/gamma) in aulIB[k] *
* *
* Thus the blended color value is *
* *
* (c_f >= c_b): *
* *
* c = (2^16 * c_b + aulB[k] * (c_f - c_b)) / 2^16 *
* *
* *
* (c_f <= c_b): *
* *
* c = (2^16 * c_b + aulB[15-k] * (c_f - c_b)) / 2^16 *
* Instead of accessing aulB[15-k], I access aulIB which has *
* aulIB[k] = aulB[15-k] *
* In the macro below, I actually blend the down-shifted color *
* channel values and then shift the answer up and mask it (the *
* mask shouldn't be necessary, but this is a precaution). *
* *
*****************************************************************************/
#define CCC(Color,jj) \
uT = (uB & fl##Color) >> c##Color##Right; \
dT = u##Color##F - uT; \
aul = ((LONG) dT < 0) ? aulIB : aulB; \
u |= (((dT * aul[jj] + (uT << 16)) >> 16) << c##Color##Right) & fl##Color
/******************************************************************************
* *
* The SETCOLOR macro looks at the blending value. If it is zero then *
* the destination pixel does not change and we do nothing. If the blending *
* value is 15 then the destination pixel should take the forground color *
* , no blending is necessary. If the blending value is one of 1..14 then *
* all three color channels are blended and added together. *
* *
******************************************************************************/
#define SETCOLOR(jj) \
if (j = (jj)) \
{ \
if (j == 15) \
{ \
u = uF; \
} \
else \
{ \
u = 0; \
uB = (ULONG) *pusDst; \
CCC(Red,j); \
CCC(Gre,j); \
CCC(Blu,j); \
} \
*pusDst = (USHORT) u; \
} \
pusDst++
/*********************************************************************
* *
* Each pixel takes 16-bits, half of a DWORD. I will separate *
* each scan into three sections: the "preamble", the *
* "middle", and the "postamble". The preamble are the set of *
* pixels that occur before the first 32-bit boundary in the *
* destination. Either a pixel starts on a DWORD or it doesn't. *
* Therefore there can be at most one pixel in the preamble. *
* The middle section starts and ends on a 32-bit boundary. *
* The postamble starts on a 32-bit boundary but ends on an *
* address that is not 32-bit aligned. There can be at most *
* one pixel in the postamble. *
* *
* A = x-coord of pixel starting on the lowest *
* 32-bit aligned address in the scan *
* *
* = 2 (pixels/dword) *
* * ceiling (16 (bits/pixel) * left / 32 (bits/dword)) *
* *
* = 2 * ceiling( left / 2 ) *
* *
* = 2 * floor((left + 1) / 2) *
* *
* = (left + 1) & ~1; *
* *
* *
* B = x-coord of pixel starting at the highest *
* 32-bit aligned address in the scan *
* *
* = 2 * floor( right / 2) *
* *
* = right & ~1 *
* *
* *
* cPreamble = # pixels in preamble *
* cPostamble = # pixels in postamble *
* *
* Each nyble of the gray 4-bpp source bitmap corresponds to a *
* pixel in the destination. The pixels of the scan do not *
* start on the left edge of the gray 4-bpp bitmap, they are *
* indented by SrcLeft pixels. The reason is that the gray *
* bitmap was aligned so that the initial starting address *
* of the gray bitmap started at a position corresponding to *
* a 32-bit aligned address in the destination. Thus there *
* is a relationship between cPreamble and SrcLeft. In any *
* case we have to move the pointer to the first source pixel *
* of interest inward away from the left edge of the gray *
* source bitmap. Since we move pointers in BYTE increments *
* we must convert the number of pixels (SrcLeft), each *
* of which corresponds to an nyble to a count of bytes. The *
* conversion is easy *
* *
* source shift in bytes = floor(SrcLeft/2) *
* *
* Similarly, the pointer to the destination must be indented *
* by the offset of the x-coordinate of the destination *
* rectangle and thus pjDstIn is shifted *
* *
*********************************************************************/
A = (DstLeft + 1) & ~1;
B = (DstRight ) & ~1;
cPreamble = A - DstLeft;
cMiddle = (B - A)/2;
cPostamble = DstRight - B;
pjSrcIn += SrcLeft / 2;
pjDstIn += DstLeft * sizeof(USHORT);
for (; cy; cy--, pjSrcIn += DeltaSrcIn, pjDstIn += DeltaDstIn)
{
int i;
BYTE jSrc;
BYTE *pjSrc = pjSrcIn;
USHORT *pusDst = (USHORT*) pjDstIn;
if (cPreamble)
{
jSrc = *pjSrc;
SETCOLOR(jSrc & 15);
pjSrc++;
}
for (i = 0; i < cMiddle; i++)
{
jSrc = *pjSrc;
SETCOLOR(jSrc >> 4);
SETCOLOR(jSrc & 15);
pjSrc++;
}
if (cPostamble)
{
SETCOLOR(*pjSrc >> 4);
}
}
#undef SETCOLOR
#undef CCC
}
/******************************Public*Routine******************************\
* *
* Routine Name *
* *
* vSrcOpaqCopyS4D24 *
* *
* Routine Description: *
* *
* Arguments: *
* *
* pjSrcIn - pointer to beginning of current scan line of src buffer *
* SrcLeft - left (starting) pixel in src rectangle *
* DeltaSrcIn - bytes from one src scan line to next *
* pjDstIn - pointer to beginning of current scan line of Dst buffer *
* DstLeft - left(first) dst pixel *
* DstRight - right(last) dst pixel *
* DeltaDstIn - bytes from one Dst scan line to next *
* cy - number of scan lines *
* uF - Foreground color *
* uB - Background color *
* pS - pointer to destination SURFACE *
* *
* Return Value: *
* *
* None *
* *
\**************************************************************************/
VOID
vSrcOpaqCopyS4D24(
PBYTE pjSrcIn,
LONG SrcLeft,
LONG DeltaSrcIn,
PBYTE pjDstIn,
LONG DstLeft,
LONG DstRight,
LONG DeltaDstIn,
LONG cy,
ULONG uF,
ULONG uB,
SURFACE *pS
)
{
int A; // position of first 32-bit aligned pixel
int B; // position of last 32-bit aligned pixel
int cPreamble; // The preamble is the set of pixeles
// that you need to go through to get
// nearest 32-bit boundary in the destination
int cMiddle; // This is the number of interations
// that are done in the middle section
// in which we are guaranteed 32-bit alignment. Each time through
// the loop, we use 2 source bytes which corresponds to 4 pixels.
// In this case of 24-bits per destination pixel, this means that
// each itteration of the loop affects 3 DWORD's of the destination.
// This means that cMiddle = (#destination DWORD's)/3 in the
// middle (32-bit aligned) section.
int cPostamble; // The postamble is the set of pixels
// that remain after the last 32-bit
// boundary in the destination. Thus number is can be 0, 1, or 2.
ULONG *aul; // a cache of the 16 possible 24-bit
// colors that can be seen on the
// destination surface.
#if DBG
if (gflFontDebug & DEBUG_AA)
{
DbgPrint(
"vSrcOpaqCopyS4D24(\n"
" PBYTE pjSrcIn = %-#x\n"
" LONG SrcLeft = %d\n"
" LONG DeltaSrcIn = %d\n"
" PBYTE pjDstIn = %-#x\n"
" LONG DstLeft = %d\n"
" LONG DstRight = %d\n"
" LONG DeltaDstIn = %d\n"
" LONG cy = %d\n"
" ULONG uF = %-#x\n"
" ULONG uB = %-#x\n"
" SURFACE *pS = %-#x\n"
, pjSrcIn
, SrcLeft
, DeltaSrcIn
, pjDstIn
, DstLeft
, DstRight
, DeltaDstIn
, cy
, uF
, uB
, pS
);
DbgBreakPoint();
}
#endif
aul = (ULONG*) pvFillOpaqTable(sizeof(*aul), uF, uB, pS);
pjSrcIn += SrcLeft / 2; // 2 pixels per src byte
pjDstIn += DstLeft * 3; // 3 bytes per dest pixel
A = (DstLeft + 3) & ~3; // round up to nearest multiple of 4
B = (DstRight ) & ~3; // round down to nearest multiple of 4
#if DBG
if (gflFontDebug & DEBUG_AA)
{
DbgPrint(
"\n"
" pjSrcIn = %-#x\n"
" pjDstIn = %-#x\n"
" A = %d\n"
" B = %d\n"
, pjSrcIn
, pjDstIn
, A
, B
);
DbgBreakPoint();
}
#endif
if (A <= B)
{
cPreamble = A - DstLeft; // # pixels in preamble
cMiddle = (B - A) / 4; // each loop does 4 pixels
cPostamble = DstRight - B; // # pixels in postample
#if DBG
if (gflFontDebug & DEBUG_AA)
{
DbgPrint(
" cPreamble = %d\n"
" cMiddle = %d\n"
" cPostamble = %d\n"
, cPreamble, cMiddle, cPostamble
);
DbgBreakPoint();
}
#endif
for (; cy; cy--, pjSrcIn += DeltaSrcIn, pjDstIn += DeltaDstIn)
{
int i;
BYTE *ajSrc; // points directly into the gamma correction table
ULONG *pul;
BYTE *pjSrc = pjSrcIn;
BYTE *pjDst = pjDstIn;
switch (cPreamble)
{
case 3:
ajSrc = (BYTE*) & (aul[*pjSrc & 15]);
*pjDst++ = *ajSrc++;
*pjDst++ = *ajSrc++;
*pjDst++ = *ajSrc;
pjSrc++;
// fall through
case 2:
ajSrc = (BYTE*) & (aul[*pjSrc >> 4]);
*pjDst++ = *ajSrc++;
*pjDst++ = *ajSrc++;
*pjDst++ = *ajSrc;
// fall through
case 1:
ajSrc = (BYTE*) & (aul[*pjSrc & 15]);
*pjDst++ = *ajSrc++;
*pjDst++ = *ajSrc++;
*pjDst++ = *ajSrc;
pjSrc++;
case 0:
;
}
for (pul = (ULONG*) pjDst, i = 0; i < cMiddle; i++)
{
/*****************************************************
* Each time through the loop four pixels are *
* processed (3 DWORD's in the destination, 2 *
* bytes in the source glyph.) *
*****************************************************/
ULONG c0, c1, c2, c3;
BYTE j0,j1;
ASSERTGDI(!((unsigned) pjDst & 3),"bad alignment\n");
j0 = *pjSrc++;
j1 = *pjSrc++;
c0 = aul[j0 >> 4];
c1 = aul[j0 & 15];
c2 = aul[j1 >> 4];
c3 = aul[j1 & 15];
*pul++ = (c0 ) + (c1 << 24);
*pul++ = (c1 >> 8) + (c2 << 16);
*pul++ = (c2 >> 16) + (c3 << 8);
}
pjDst = (BYTE*) pul;
if (i = cPostamble)
{
/*****************************************************
* I do the postamble a byte at a time so that I *
* don't overwrite pixels beyond the scan. If I *
* wrote a DWORD at a time, then I would have to *
* do some tricky masking. *
*****************************************************/
i--;
ajSrc = (BYTE*) & (aul[*pjSrc >> 4]);
*pjDst++ = *ajSrc++;
*pjDst++ = *ajSrc++;
*pjDst++ = *ajSrc;
if (i)
{
i--;
ajSrc = (BYTE*) & (aul[*pjSrc & 15]);
*pjDst++ = *ajSrc++;
*pjDst++ = *ajSrc++;
*pjDst++ = *ajSrc;
pjSrc++;
if (i) {
ajSrc = (BYTE*) & (aul[*pjSrc >> 4]);
*pjDst++ = *ajSrc++;
*pjDst++ = *ajSrc++;
*pjDst++ = *ajSrc;
}
}
}
}
}
else
{
/***************************************************************
* If the text bitmap is narrow (3 wide or less) then *
* it is possible to have B < A. There are three such cases: *
* *
* 1) DstLeft & 3 == 2 AND DstLeft + 1 == DstRight *
* 1) DstLeft & 3 == 1 AND DstLeft + 1 == DstRight *
* 2) DstLeft & 3 == 1 AND DstLeft + 2 == DstRight *
* *
* I shall treat each of these as a special case *
***************************************************************/
ASSERTGDI(B < A, "A <= B");
BYTE *ajSrc; // points directly into the gamma correction table
BYTE *pjDst = pjDstIn;
BYTE *pjSrc = pjSrcIn;
#if DBG
if (gflFontDebug & DEBUG_AA)
{
DbgPrint(
" SPECIAL CASE: A < B\n"
" DstLeft & 3 = %d\n"
, DstLeft & 3
);
DbgBreakPoint();
}
#endif
switch (DstLeft & 3)
{
case 0:
RIP("DstLeft & 3 == 0");
break;
case 1:
/********************************************************
* *
* H H H L L L H H H L L L *
* +---------------+---------------+---------------+ *
* | 0 | 0 | 0 | 1 | 1 | 1 | 2 | 2 | 2 | 3 | 3 | 3 | *
* +---------------+---------------+---------------+ *
* X X X *
* ^ *
* | *
* pjDst *
* *
********************************************************/
// copy three bytes from the opaque color table
ajSrc = (BYTE*) & (aul[*pjSrc & 15]);
*pjDst++ = *ajSrc++;
*pjDst++ = *ajSrc++;
*pjDst++ = *ajSrc;
if (DstLeft + 1 == DstRight)
break;
pjSrc++; // done with this source byte
// fall through
case 2:
/*********************************************************
* *
* H H H L L L H H H L L L *
* +---------------+---------------+---------------+ *
* | 0 | 0 | 0 | 1 | 1 | 1 | 2 | 2 | 2 | 3 | 3 | 3 | *
* +---------------+---------------+---------------+ *
* X X X *
* ^ *
* | *
* pjDst *
* *
*********************************************************/
// copy three bytes from the opaque color table
ajSrc = (BYTE*) & (aul[*pjSrc >> 4]);
*pjDst++ = *ajSrc++;
*pjDst++ = *ajSrc++;
*pjDst = *ajSrc;
break;
}
}
vFreeOpaqTable(aul);
}
/******************************Public*Routine******************************\
* *
* Routine Name *
* *
* vSrcTranCopyS4D24 *
* *
* Routine Description: *
* *
* Arguments: *
* *
* pjSrcIn - pointer to beginning of current scan line of src buffer *
* SrcLeft - left (starting) pixel in src rectangle *
* DeltaSrcIn - bytes from one src scan line to next *
* pjDstIn - pointer to beginning of current scan line of Dst buffer *
* DstLeft - left(first) dst pixel *
* DstRight - right(last) dst pixel *
* DeltaDstIn - bytes from one Dst scan line to next *
* cy - number of scan lines *
* uF - Foreground color *
* uB - Background color *
* pS - pointer to destination SURFACE *
* *
* Return Value: *
* *
* None *
* *
\**************************************************************************/
VOID
vSrcTranCopyS4D24(
PBYTE pjSrcIn,
LONG SrcLeft,
LONG DeltaSrcIn,
PBYTE pjDstIn,
LONG DstLeft,
LONG DstRight,
LONG DeltaDstIn,
LONG cy,
ULONG uF,
ULONG uB,
SURFACE *pS
)
{
#if DBG
if (gflFontDebug & DEBUG_AA)
{
DbgPrint(
"vSrcTranCopyS4D24(\n"
" PBYTE pjSrcIn = %-#x\n"
" LONG SrcLeft = %d\n"
" LONG DeltaSrcIn = %d\n"
" PBYTE pjDstIn = %-#x\n"
" LONG DstLeft = %d\n"
" LONG DstRight = %d\n"
" LONG DeltaDstIn = %d\n"
" LONG cy = %d\n"
" ULONG uF = %-#x\n"
" ULONG uB = %-#x\n"
" SURFACE *pS = %-#x\n"
" )\n"
, pjSrcIn
, SrcLeft
, DeltaSrcIn
, pjDstIn
, DstLeft
, DstRight
, DeltaDstIn
, cy
, uF
, uB
, pS
);
DbgBreakPoint();
}
#endif
ULONG flRed, cRedRight, uRedF, flRedRight;
ULONG flGre, cGreRight, uGreF, flGreRight;
ULONG flBlu, cBluRight, uBluF, flBluRight;
ULONG uT, dT, u;
CONST ULONG *aul;
int cPreamble, cMiddle, cPostamble, A, B;
BYTE j;
XEPALOBJ xpo(pS->pPal);
ASSERTGDI(xpo.bValid(), "Invalid XEPALOBJ" );
if (xpo.bIsBitfields())
{
flRed = xpo.flRed(); // masks red bits
cRedRight = xpo.cRedRight();
flGre = xpo.flGre(); // masks green bits
cGreRight = xpo.cGreRight();
flBlu = xpo.flBlu(); // masks blu bits
cBluRight = xpo.cBluRight();
}
else if (xpo.bIsRGB())
{
// assuming 8+8+8
flRed = 0x0000ff;
cRedRight = 0;
flGre = 0x00ff00;
cGreRight = 8;
flBlu = 0xff0000;
cBluRight = 16;
}
else if (xpo.bIsBGR())
{
// assuming 8+8+8
flRed = 0xff0000;
cRedRight = 16;
flGre = 0x00ff00;
cGreRight = 8;
flBlu = 0x0000ff;
cBluRight = 0;
}
else
{
RIP("unsuported palette format\n");
}
uRedF = (uF & flRed) >> cRedRight;
flRedRight = flRed >> cRedRight;
uGreF = (uF & flGre) >> cGreRight;
flGreRight = flGre >> cGreRight;
uBluF = (uF & flBlu) >> cBluRight;
flBluRight = flBlu >> cBluRight;
#if DBG
if (gflFontDebug & DEBUG_AA)
{
DbgPrint(
" flRed = %-#x\n"
" cRedRight = %d\n"
" uRedF = %-#x\n"
" flRedRight = %-#x\n"
, flRed, cRedRight, uRedF, flRedRight
);
DbgPrint(
" flGre = %-#x\n"
" cGreRight = %d\n"
" uGreF = %-#x\n"
" flGreRight = %-#x\n"
, flGre, cGreRight, uGreF, flGreRight
);
DbgPrint(
" flBlu = %-#x\n"
" cBluRight = %d\n"
" uBluF = %-#x\n"
" flBluRight = %-#x\n"
, flBlu, cBluRight, uBluF, flBluRight
);
DbgBreakPoint();
}
#endif
/******************************************************************************
* *
* See the discussion of the CCC macro in vSrcTranCopyS4D16() *
* *
* *
*/
#define CCC(Color,jj) \
uT = (uB & fl##Color) >> c##Color##Right; \
dT = u##Color##F - uT; \
aul = ((LONG) dT < 0) ? aulIB : aulB; \
u |= (((dT * aul[jj] + (uT << 16)) >> 16) \
<< c##Color##Right) & fl##Color
/* *
* *
* *
/******************************************************************************/
/******************************************************************************
* *
* The SETCOLOR macro looks at the blending value. If it is zero then *
* the destination pixel does not change and we do nothing. If the blending *
* value is 15 then the destination pixel should take the forground color *
* , no blending is necessary. If the blending value is one of 1..14 then *
* all three color channels are blended and added together. *
* *
* */
#define SETCOLOR(jj) \
if (j = (jj)) \
{ \
if (j == 15) \
{ \
u = uF; \
} \
else \
{ \
u = 0; \
*(((BYTE*) & uB)+0) = *(pjDst+0); \
*(((BYTE*) & uB)+1) = *(pjDst+1); \
*(((BYTE*) & uB)+2) = *(pjDst+2); \
CCC(Red,j); \
CCC(Gre,j); \
CCC(Blu,j); \
} \
*(pjDst+0) = *(((BYTE*) & u)+0); \
*(pjDst+1) = *(((BYTE*) & u)+1); \
*(pjDst+2) = *(((BYTE*) & u)+2); \
} \
pjDst += 3
/* *
* *
* *
/******************************************************************************/
A = (DstLeft + 3) & ~3;
B = (DstRight ) & ~3;
pjSrcIn += SrcLeft / 2; // 4-bits per source pixel
pjDstIn += DstLeft * 3; // 24-bits per destination pixel
if (A <= B)
{
cPreamble = A - DstLeft;
cMiddle = (B - A) / 4;
cPostamble = DstRight - B;
for (; cy; cy--, pjSrcIn += DeltaSrcIn, pjDstIn += DeltaDstIn)
{
int i;
BYTE *pjSrc = pjSrcIn;
BYTE *pjDst = pjDstIn;
switch (cPreamble)
{
case 3:
SETCOLOR(*pjSrc & 15);
pjSrc++;
case 2:
SETCOLOR(*pjSrc >> 4);
case 1:
SETCOLOR(*pjSrc & 15);
pjSrc++;
case 0:
;
}
ASSERTGDI(!((unsigned) pjDst & 3),"bad alignment\n");
for (i = 0; i < cMiddle; i++)
{
SETCOLOR(*pjSrc >> 4);
SETCOLOR(*pjSrc & 15);
pjSrc++;
SETCOLOR(*pjSrc >> 4);
SETCOLOR(*pjSrc & 15);
pjSrc++;
}
if (i = cPostamble)
{
SETCOLOR(*pjSrc >> 4);
i--;
if (i)
{
SETCOLOR(*pjSrc & 15);
i--;
if (i)
{
pjSrc++;
SETCOLOR(*pjSrc >> 4);
}
}
}
}
}
else
{
/***************************************************************
* If the text bitmap is narrow (3 wide or less) then *
* it is possible to have B < A. There are three such cases: *
* *
* 1) DstLeft & 3 == 2 AND DstLeft + 1 == DstRight *
* 1) DstLeft & 3 == 1 AND DstLeft + 1 == DstRight *
* 2) DstLeft & 3 == 1 AND DstLeft + 2 == DstRight *
* *
* I shall treat each of these as a special case *
***************************************************************/
ASSERTGDI(B < A, "A <= B");
BYTE *ajSrc; // points directly into the gamma correction table
BYTE *pjDst = pjDstIn;
BYTE *pjSrc = pjSrcIn;
#if DBG
if (gflFontDebug & DEBUG_AA)
{
DbgPrint(
" SPECIAL CASE: A < B\n"
" DstLeft & 3 = %d\n"
, DstLeft & 3
);
DbgBreakPoint();
}
#endif
switch (DstLeft & 3)
{
case 0:
RIP("DstLeft & 3 == 0");
break;
case 1:
/********************************************************
* *
* H H H L L L H H H L L L *
* +---------------+---------------+---------------+ *
* | 0 | 0 | 0 | 1 | 1 | 1 | 2 | 2 | 2 | 3 | 3 | 3 | *
* +---------------+---------------+---------------+ *
* X X X *
* ^ *
* | *
* pjDst *
* *
********************************************************/
SETCOLOR(*pjSrc & 15);
if (DstLeft + 1 == DstRight)
break;
pjSrc++; // done with this byte
// fall through
case 2:
/*********************************************************
* *
* H H H L L L H H H L L L *
* +---------------+---------------+---------------+ *
* | 0 | 0 | 0 | 1 | 1 | 1 | 2 | 2 | 2 | 3 | 3 | 3 | *
* +---------------+---------------+---------------+ *
* X X X *
* ^ *
* | *
* pjDst *
* *
*********************************************************/
SETCOLOR(*pjSrc >> 4);
break;
}
}
#undef SETCOLOR
#undef CCC
}
/******************************Public*Routine******************************\
* *
* Routine Name *
* *
* vSrcOpaqCopyS4D32 *
* *
* Routine Description: *
* *
* Arguments: *
* *
* pjSrcIn - pointer to beginning of current scan line of src buffer *
* SrcLeft - left (starting) pixel in src rectangle *
* DeltaSrcIn - bytes from one src scan line to next *
* pjDstIn - pointer to beginning of current scan line of Dst buffer *
* DstLeft - left(first) dst pixel *
* DstRight - right(last) dst pixel *
* DeltaDstIn - bytes from one Dst scan line to next *
* cy - number of scan lines *
* uF - Foreground color *
* uB - Background color *
* pS - pointer to destination SURFACE *
* *
* Return Value: *
* *
* None *
* *
\**************************************************************************/
VOID
vSrcOpaqCopyS4D32(
PBYTE pjSrcIn,
LONG SrcLeft,
LONG DeltaSrcIn,
PBYTE pjDstIn,
LONG DstLeft,
LONG DstRight,
LONG DeltaDstIn,
LONG cy,
ULONG uF,
ULONG uB,
SURFACE *pS
)
{
int A, B, cPreamble, cMiddle, cPostamble;
ULONG *aul; // array of 16 possible colors
#if DBG
if (gflFontDebug & DEBUG_AA)
{
DbgPrint(
"vSrcOpaqCopyS4D32(\n"
" pjSrcIn = %-#x\n"
" SrcLeft = %-#x\n"
" pjDstIn = %-#x\n"
" DstLeft = %-#x\n"
" DstRight = %-#x\n"
" DeltaDstIn = %-#x\n"
" cy = %-#x\n"
" uF = %-#x\n"
" uB = %-#x\n"
" pS = %-#x\n"
, pjSrcIn
, SrcLeft
, DeltaSrcIn
, pjDstIn
, DstLeft
, DstRight
, DeltaDstIn
, cy
, uF
, uB
, pS
);
DbgBreakPoint();
}
#endif
aul = (ULONG*) pvFillOpaqTable(sizeof(*aul), uF, uB, pS);
A = (DstLeft + 1) & ~1;
B = (DstRight ) & ~1;
cPreamble = A - DstLeft; // # pixels in preamble
cMiddle = (B - A)/2;
cPostamble = DstRight - B; // # pixels in postamble
pjSrcIn += SrcLeft / 2;
pjDstIn += DstLeft * sizeof(ULONG);
for (; cy; cy--, pjSrcIn += DeltaSrcIn, pjDstIn += DeltaDstIn)
{
int i;
BYTE *pjSrc = pjSrcIn;
ULONG *pul = (ULONG*) pjDstIn;
if (cPreamble)
{
*pul++ = aul[*pjSrc++ & 15];
}
for (i = 0; i < cMiddle; i++)
{
BYTE j = *pjSrc++;
*pul++ = aul[j >> 4];
*pul++ = aul[j & 15];
}
if (cPostamble)
{
*pul = aul[*pjSrc >> 4];
}
}
vFreeOpaqTable(aul);
}
/******************************Public*Routine******************************\
* *
* Routine Name *
* *
* vSrcTranCopyS4D32 *
* *
* Routine Description: *
* *
* Arguments: *
* *
* pjSrcIn - pointer to beginning of current scan line of src buffer *
* SrcLeft - left (starting) pixel in src rectangle *
* DeltaSrcIn - bytes from one src scan line to next *
* pjDstIn - pointer to beginning of current scan line of Dst buffer *
* DstLeft - left(first) dst pixel *
* DstRight - right(last) dst pixel *
* DeltaDstIn - bytes from one Dst scan line to next *
* cy - number of scan lines *
* uF - Foreground color *
* uB - Background color *
* pS - pointer to destination SURFACE *
* *
* Return Value: *
* *
* None *
* *
\**************************************************************************/
VOID
vSrcTranCopyS4D32(
PBYTE pjSrcIn,
LONG SrcLeft,
LONG DeltaSrcIn,
PBYTE pjDstIn,
LONG DstLeft,
LONG DstRight,
LONG DeltaDstIn,
LONG cy,
ULONG uF,
ULONG uB,
SURFACE *pS
)
{
ULONG flRed, cRedRight, uRedF, flRedRight;
ULONG flGre, cGreRight, uGreF, flGreRight;
ULONG flBlu, cBluRight, uBluF, flBluRight;
ULONG uT, dT, u;
CONST ULONG *aul;
int cPreamble, cMiddle, cPostamble, A, B;
BYTE j;
XEPALOBJ xpo(pS->pPal);
ASSERTGDI(xpo.bValid(), "Invalid XEPALOBJ" );
if (xpo.bIsBitfields())
{
flRed = xpo.flRed(); // masks red bits
cRedRight = xpo.cRedRight();
flGre = xpo.flGre(); // masks green bits
cGreRight = xpo.cGreRight();
flBlu = xpo.flBlu(); // masks blu bits
cBluRight = xpo.cBluRight();
}
else if (xpo.bIsRGB())
{
// assuming 8+8+8
flRed = 0x0000ff;
cRedRight = 0;
flGre = 0x00ff00;
cGreRight = 8;
flBlu = 0xff0000;
cBluRight = 16;
}
else if (xpo.bIsBGR())
{
// assuming 8+8+8
flRed = 0xff0000;
cRedRight = 16;
flGre = 0x00ff00;
cGreRight = 8;
flBlu = 0x0000ff;
cBluRight = 0;
}
else
{
RIP("unsuported palette format\n");
}
uRedF = (uF & flRed) >> cRedRight;
flRedRight = flRed >> cRedRight;
uGreF = (uF & flGre) >> cGreRight;
flGreRight = flGre >> cGreRight;
uBluF = (uF & flBlu) >> cBluRight;
flBluRight = flBlu >> cBluRight;
#if DBG
if (gflFontDebug & DEBUG_AA)
{
DbgPrint(
"vSrcTranCopyS4D32(\n"
" PBYTE pjSrcIn = %-#x\n"
" LONG SrcLeft = %d\n"
" LONG DeltaSrcIn = %d\n"
" PBYTE pjDstIn = %-#x\n"
" LONG DstLeft = %d\n"
" LONG DstRight = %d\n"
" LONG DeltaDstIn = %d\n"
" LONG cy = %d\n"
" ULONG uF = %-#x\n"
" ULONG uB = %-#x\n"
" SURFACE *pS = %-#x\n"
, pjSrcIn
, SrcLeft
, DeltaSrcIn
, pjDstIn
, DstLeft
, DstRight
, DeltaDstIn
, cy
, uF
, uB
, pS
);
DbgPrint(
" flRed = %-#x\n"
" cRedRight = %d\n"
" uRedF = %-#x\n"
" flRedRight = %-#x\n"
, flRed, cRedRight, uRedF, flRedRight
);
DbgPrint(
" flGre = %-#x\n"
" cGreRight = %d\n"
" uGreF = %-#x\n"
" flGreRight = %-#x\n"
, flGre, cGreRight, uGreF, flGreRight
);
DbgPrint(
" flBlu = %-#x\n"
" cBluRight = %d\n"
" uBluF = %-#x\n"
" flBluRight = %-#x\n"
, flBlu, cBluRight, uBluF, flBluRight
);
DbgBreakPoint();
}
#endif
/*****************************************************************************
* *
* The CCC macro blends forground and background colors of a single color *
* channel. Gamma correction is taken into account using an approximate *
* correction scheme. uB contains all three background colors. We first *
* mask off the bits of interest and then shift them down until the *
* least significant color bit resides at the lowest bit of the dword. *
* The answer is placed in uT ("temporary ULONG"). This must be done for *
* each pixel in the destination. The same thing has been done for the *
* each of the forground color channels and placed in uRedF, uGreF, *
* and uBluF. These values do not change from pixel to pixel and so the *
* calculation of these down shifted forground color channel values is *
* done up front before the loop. Then for each color channel we *
* calculate the difference between the down-shifted forground- and *
* background color channels and place the answer in dT ("temporary *
* difference"). The approximate gamma correction is done in the *
* following manner: If the background color value is smaller than *
* the foreground color value then the approximate correction is: *
* *
* (c_f >= c_b): *
* *
* c = c_b + alpha_k ^ (1/gamma) * (c_f - c_b) *
* *
* (c_f <= c_b): *
* *
* c = c_b + (1 - (1 - alpha_k)^(1/gamma)) * (c_f - c_b) *
* *
* where *
* *
* c := blended color *
* c_b := background color *
* c_f := foreground color *
* alpha_k := k'th blending fraction = k == 0 ? 0 : (k+1)/16; *
* gamma := 2.33 *
* *
* I have storred all sixteen values of alpha_k ^ (1/gamma) in 16.16 *
* representation in an array ULONG aulB[16] and I have storred the *
* values of 1 - (1 - alpha_k)^(1/gamma) in aulIB[k] *
* *
* Thus the blended color value is *
* *
* (c_f >= c_b): *
* *
* c = (2^16 * c_b + aulB[k] * (c_f - c_b)) / 2^16 *
* *
* *
* (c_f <= c_b): *
* *
* c = (2^16 * c_b + aulB[15-k] * (c_f - c_b)) / 2^16 *
* Instead of accessing aulB[15-k], I access aulIB which has *
* aulIB[k] = aulB[15-k] *
* In the macro below, I actually blend the down-shifted color *
* channel values and then shift the answer up and mask it (the *
* mask shouldn't be necessary, but this is a precaution). *
* *
*****************************************************************************/
#define CCC(Color,jj) \
uT = (uB & fl##Color) >> c##Color##Right; \
dT = u##Color##F - uT; \
aul = ((LONG) dT < 0) ? aulIB : aulB; \
u |= (((dT * aul[jj] + (uT << 16)) >> 16) << c##Color##Right) & fl##Color
/******************************************************************************
* *
* The SETCOLOR macro looks at the blending value. If it is zero then *
* the destination pixel does not change and we do nothing. If the blending *
* value is 15 then the destination pixel should take the forground color *
* , no blending is necessary. If the blending value is one of 1..14 then *
* all three color channels are blended and added together. *
* *
******************************************************************************/
#define SETCOLOR(jj) \
if (j = (jj)) \
{ \
if (j == 15) \
{ \
u = uF; \
} \
else \
{ \
u = 0; \
uB = *pulDst; \
CCC(Red,j); \
CCC(Gre,j); \
CCC(Blu,j); \
} \
*pulDst = u; \
} \
pulDst++
/************************************************************************
* *
* Each nyble of the source bitmap corresponds to 32 bits *
* in the destination bitmap. I have decided to arrange things *
* so that the inner most loop sets two pixels at a time. The *
* first of these two pixels starts on an even address in *
* the destination. After separating these 'aligned' pairs *
* in the middle of the scan there may be some left over *
* at the left (preamble) and the right (postamble). The *
* preamble can have at most one pixel in it. If there is *
* a pixel in the postamble then it correxponds to the *
* low nybble of the source byte. If there is a pixel in *
* the postamble then it corresponds to the high nybble of *
* the source byte. Each time, we have dealt with an odd *
* x-coordinate in the destination (corresponding to the *
* low nybble in the source byte) we advance the source pointer *
* to the next byte. *
* *
************************************************************************/
A = (DstLeft + 1) & ~1; // nearest multiple of 2 left of left edge
B = (DstRight ) & ~1; // nearest multiple of 2 right of right edge
cPreamble = A - DstLeft; // # pixels in preamble
cMiddle = (B - A)/2; // # pixels in middle
cPostamble = DstRight - B; // # pixels in postamble
pjSrcIn += SrcLeft / 2; // points to first source byte
pjDstIn += DstLeft * sizeof(ULONG); // points to first dst DWORD
for (; cy; cy--, pjSrcIn += DeltaSrcIn, pjDstIn += DeltaDstIn)
{
int i;
BYTE jSrc;
BYTE *pjSrc = pjSrcIn;
ULONG *pulDst = (ULONG*) pjDstIn;
if (cPreamble)
{
SETCOLOR(*pjSrc & 15);
pjSrc++;
}
for (i = 0; i < cMiddle; i++)
{
jSrc = *pjSrc;
SETCOLOR(jSrc >> 4);
SETCOLOR(jSrc & 15);
pjSrc++;
}
if (cPostamble)
{
SETCOLOR(*pjSrc >> 4);
}
}
#undef SETCOLOR
#undef CCC
}
/******************************Public*Routine******************************\
* *
* Routine Name: *
* *
* vOrNonAlignedGrayGlyphEven *
* *
* Routine Description: *
* *
* Writes the a single gray glyph to a 4bpp buffer. This is for the *
* special case where the destination starts on a non byte (nyble ) *
* boundary and the glyph images is an even number of pixels wide. *
* *
* The source gray pixel image is guaranteed to have its initial scan *
* start on a 32-bit boundary, all subsequent scans start on byte *
* boundaries. *
* *
* Arguments: *
* *
* pgb - address of gray GLYPHBITS structure *
* dpSrcScan - number of bytes between address of start of glyph scans *
* pjDstScan - starting address of glyph image in destination buffer *
* dpDstScan - increment between scan addresses in destination buffer *
* *
* Return Value: *
* *
* None *
* *
\**************************************************************************/
void
vOrNonAlignedGrayGlyphEven(
GLYPHBITS* pgb ,
unsigned dpSrcScan,
BYTE* pjDstScan,
unsigned dpDstScan
)
{
/*
0 1 2 3 4 <-- byte number
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|n n |n n |n n |n n |n n | | | |
| 1 0| 3 2| 5 4| 7 6| 9 8| | | |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
^ ^ ^
pjSrc Hi Lo
0 1 2 3 4 5 <-- byte number
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| n |n n |n n |n n |n n |n | | |
| 1| 0 3| 2 5| 4 7| 6 9| 8 | | |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
^ ^
pjDst pjDstLast
*/
#if DBG
if (gflFontDebug & DEBUG_AA)
{
DbgPrint(
"void\n"
"vOrNonAlignedGrayGlyphEven(\n"
" GLYPHBITS* pgb = %-#x\n"
" unsigned dpSrcScan = %-#x\n"
" BYTE* pjDstScan = %-#x\n"
" unsigned dpDstScan = %-#x\n"
" )\n"
, pgb
, dpSrcScan
, pjDstScan
, dpDstScan
);
DbgBreakPoint();
}
#endif
BYTE jLo, jHi, *pjSrc, *pjDst, *pjSrcOut, *pjDstScanOut;
dpSrcScan = (pgb->sizlBitmap.cx + 1)/2;
pjSrcOut = pgb->aj;
pjDstScanOut = pjDstScan + ((unsigned) pgb->sizlBitmap.cy) * dpDstScan;
for ( ; pjDstScan < pjDstScanOut ; pjDstScan += dpDstScan)
{
pjSrc = pjSrcOut;
pjSrcOut += dpSrcScan;
for (jLo = 0, pjDst = pjDstScan; pjSrc < pjSrcOut; )
{
jHi = *pjSrc++;
*pjDst++ |= (jLo << 4) + (jHi >> 4);
jLo = jHi;
}
*pjDst |= (jLo << 4);
}
}
/******************************Public*Routine******************************\
* *
* Routine Name: *
* *
* vOrNonAlignedGrayGlyphOdd *
* *
* Routine Description: *
* *
* Writes the a single gray glyph to a 4bpp buffer. This is for the *
* special case where the destination starts on a non byte (nyble ) *
* boundary and the glyph images is an odd number of pixels wide. *
* *
* The source gray pixel image is guaranteed to have its initial scan *
* start on a 32-bit boundary, all subsequent scans start on byte *
* boundaries. *
* *
* Arguments: *
* *
* pgb - address of gray GLYPHBITS structure *
* dpSrcScan - number of bytes between address of start of glyph scans *
* pjDstScan - starting address of glyph image in destination buffer *
* dpDstScan - increment between scan addresses in destination buffer *
* *
* Return Value: *
* *
* None *
* *
\**************************************************************************/
void
vOrNonAlignedGrayGlyphOdd(
GLYPHBITS* pgb ,
unsigned dpSrcScan,
BYTE* pjDstScan,
unsigned dpDstScan
)
{
/*
0 1 2 3 4 <-- byte number
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|n n |n n |n n |n n |n | | | |
| 1 0| 3 2| 5 4| 7 6| 9 | | | |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
^ ^ ^
pjSrc Hi Lo
0 1 2 3 4 5 <-- byte number
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| n |n n |n n |n n |n n | | | |
| 1| 0 3| 2 5| 4 7| 6 9| | | |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
^ ^
pjDst pjDstLast
*/
BYTE j1, j0, *pjDst, *pjSrc, *pjDstLast, *pjDstScanOut;
unsigned cy = (unsigned) pgb->sizlBitmap.cy;
unsigned cx = (unsigned) pgb->sizlBitmap.cx / 2;
BYTE *pjSrcScan = &(pgb->aj[0]);
#if DBG
if (gflFontDebug & DEBUG_AA)
{
DbgPrint(
"void\n"
"vOrNonAlignedGrayGlyphOdd(\n"
" GLYPHBITS* pgb = %-#x\n"
" unsigned dpSrcScan = %-#x\n"
" BYTE* pjDstScan = %-#x\n"
" unsigned dpDstScan = %-#x\n"
" )\n"
, pgb
, dpSrcScan
, pjDstScan
, dpDstScan
);
DbgBreakPoint();
}
#endif
for (
pjDstScanOut = pjDstScan + cy * dpDstScan
; pjDstScan < pjDstScanOut
; pjDstScan += dpDstScan, pjSrcScan += dpSrcScan
)
{
//
// set the source and destination pointers to point to the
// start of the scans
//
pjSrc = pjSrcScan;
pjDst = pjDstScan;
//
// do the first pixel in the scan
//
j1 = *pjSrc;
*pjDst |= (j1 >> 4) & 0x0f;
//
// advance the pointers to the next pixel in the scans
//
pjSrc++;
pjDst++;
//
// do the rest of the pixels in the scan
//
for (
pjDstLast = pjDst + cx
; pjDst < pjDstLast
; pjDst++, pjSrc++
)
{
j0 = j1;
j1 = *pjSrc;
*pjDst |= ((j1 >> 4) & 0x0f) | ((j0 << 4) & 0xf0);
}
//
// last pixel in the scan has already been done
//
}
}
/******************************Public*Routine******************************\
* *
* Routine Name: *
* *
* vOrAlignedGrayGlyphEven *
* *
* Routine Description: *
* *
* Writes the a single gray glyph to a 4bpp buffer. This is for the *
* special case where the destination starts on a byte aligned boundary *
* and the glyph is an even number of pixels wide. *
* *
* This routine can be used for glyphs with odd widths. *
* *
* The source gray pixel image is guaranteed to have its initial scan *
* start on a 32-bit boundary, all subsequent scans start on byte *
* boundaries. *
* *
* Arguments: *
* *
* pgb - address of gray GLYPHBITS structure *
* dpSrcScan - number of bytes between address of start of glyph scans *
* pjDstScan - starting address of glyph image in destination buffer *
* dpDstScan - increment between scan addresses in destination buffer *
* *
* Return Value: *
* *
* None *
* *
\**************************************************************************/
void
vOrAlignedGrayGlyphEven(
GLYPHBITS* pgb ,
unsigned dpSrcScan,
BYTE* pjDstScan,
unsigned dpDstScan
)
{
/*
0 1 2 3 4 <-- byte number
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|n n |n n |n n |n n |n n | | | |
| 1 0| 3 2| 5 4| 7 6| 9 8| | | |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
^ ^ ^
pjSrc Hi Lo
0 1 2 3 4 <-- byte number
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|n n |n n |n n |n n |n n | | | |
| 1 0| 3 2| 5 4| 7 6| 9 8| | | |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
^ ^
pjDst pjDstOut
Note that this routine will also work for source
glyphs with an odd number of pixels because
the source glyph is padded with zeros. This means
that for the case of odd length scans the last
byte is or'ed into the destination but the
extra nyble of the source is guaranteed to have
the value zero and thus has no effect.
*/
BYTE *pjDst, *pjSrc, *pjDstOut, *pjDstScanOut;
unsigned cy = (unsigned) pgb->sizlBitmap.cy;
// I round cx up to the nearest byte. This makes no
// difference for glyphs of even width but it will
// get that last column for glyphs with odd width.
unsigned cx = (unsigned) (pgb->sizlBitmap.cx+1) / 2;
BYTE *pjSrcScan = &(pgb->aj[0]);
#if DBG
if (gflFontDebug & DEBUG_AA)
{
DbgPrint(
"void\n"
"vOrAlignedGrayGlyphEven(\n"
" GLYPHBITS* pgb = %-#x\n"
" unsigned dpSrcScan = %-#x\n"
" BYTE* pjDstScan = %-#x\n"
" unsigned dpDstScan = %-#x\n"
" )\n"
, pgb
, dpSrcScan
, pjDstScan
, dpDstScan
);
DbgBreakPoint();
}
#endif
for (
pjDstScanOut = pjDstScan + cy * dpDstScan
; pjDstScan < pjDstScanOut
; pjDstScan += dpDstScan, pjSrcScan += dpSrcScan
)
{
pjSrc = pjSrcScan;
pjDst = pjDstScan;
for (pjDstOut = pjDst + cx ; pjDst < pjDstOut; pjDst++, pjSrc++)
{
*pjDst |= *pjSrc;
}
}
}
void (*(apfnGray[4]))(GLYPHBITS*, unsigned, BYTE*, unsigned) =
{
vOrAlignedGrayGlyphEven
, vOrAlignedGrayGlyphEven // can handle odd width glyphs
, vOrNonAlignedGrayGlyphEven
, vOrNonAlignedGrayGlyphOdd
};
/******************************Public*Routine******************************\
* *
* Routine Name: *
* *
* draw_gray_nf_ntb_o_to_temp_start *
* *
* Routine Description: *
* *
* Assembles a gray glyph string into a temporary 4bpp right and left *
* DWORD aligned buffer. This routine assumes a variable pitch font. *
* *
* Arguments: *
* *
* pGlyphPos - pointer to an array of cGlyph gray GLYPHPOS structures *
* cGlyphs - count of gray glyphs in array starting at pGlyphPos *
* pjDst - pointer to a 4bpp buffer where string is to be assembled *
* This buffer is DWORD aligned at the left and right *
* edges of each scan. *
* ulLeftEdge - screen coordinate corresponding to the left edge of *
* the temporary buffer *
* dpDst - count of bytes in each scan of the destination buffer *
* (this must be a multiple of 4 because the buffer is *
* DWORD aligned on each scan). *
* ulCharInc - This must be zero. *
* ulTempTop - screen coordinate corresponding to the top of the *
* destination buffer. This is used to convert the *
* glyph positions on the screen to addresses in the *
* destination bitmap. *
* *
* Return Value: *
* *
* None *
* *
\**************************************************************************/
extern "C" VOID draw_gray_nf_ntb_o_to_temp_start(
PGLYPHPOS pGlyphPos,
ULONG cGlyphs,
PUCHAR pjDst,
ULONG ulLeftEdge,
ULONG dpDst,
ULONG ulCharInc,
ULONG ulTempTop
)
{
GLYPHBITS *pgb; // pointer to current GLYPHBITS
int x; // pixel offset of the
// left edge of the glyph bitmap
// from the left edge of the
// output (4-bpp) bitmap
int y; // the pixel offset of the top edge
// of the glyph bitmap from the top
// edge of the output bitmap.
unsigned bOddPos; // (x-coordinate is odd) ? 1 : 0
unsigned cx; // number of pixels per glyph scan
// If non zero then the destination
// bitmap is out of alignment with
// the source glyph by a one nyble
// shift and a single byte of the
// source will affect two consecutive
// bytes of the destination.
unsigned dpSrc; // number of bytes per source scan. Each
// scan is BYTE aligned.
// = ceil(4*cx/8) = floor((cx+1)/2)
GLYPHPOS *pgpOut; // sentinel for loop
BYTE *pj; // pointer into Buffer corresponding
// to the upper left pixel of the
// current gray glyph
pj = pjDst;
for (pgpOut = pGlyphPos + cGlyphs; pGlyphPos < pgpOut; pGlyphPos++)
{
pgb = pGlyphPos->pgdf->pgb;
x = pGlyphPos->ptl.x + pgb->ptlOrigin.x - ulLeftEdge;
y = pGlyphPos->ptl.y + pgb->ptlOrigin.y - ulTempTop ;
bOddPos = (unsigned) x & 1;
cx = (unsigned) pgb->sizlBitmap.cx;
dpSrc = (cx + 1)/2;
pj = pjDst + (y * dpDst) + (x/2);
(*(apfnGray[(cx & 1) + 2*bOddPos]))(pgb, dpSrc, pj, dpDst);
}
}
/******************************Public*Routine******************************\
* *
* Routine Name: *
* *
* draw_gray_f_ntb_o_to_temp_start *
* *
* Routine Description: *
* *
* Assembles a gray glyph string into a temporary 4bpp right and left *
* DWORD aligned buffer. This routine assumes a fixed pitch font with *
* character increment equal to ulCharInc *
* *
* Arguments: *
* *
* pGlyphPos - pointer to an array of cGlyph gray GLYPHPOS structures *
* cGlyphs - count of gray glyphs in array starting at pGlyphPos *
* pjDst - pointer to a 4bpp buffer where string is to be assembled *
* This buffer is DWORD aligned at the left and right *
* edges of each scan. *
* ulLeftEdge - screen coordinate corresponding to the left edge of *
* the temporary buffer *
* dpDst - count of bytes in each scan of the destination buffer *
* (this must be a multiple of 4 because the buffer is *
* DWORD aligned on each scan). *
* ulCharInc - This must be zero. *
* ulTempTop - screen coordinate corresponding to the top of the *
* destination buffer. This is used to convert the *
* glyph positions on the screen to addresses in the *
* destination bitmap. *
* *
* Return Value: *
* *
* None *
* *
\**************************************************************************/
extern "C" VOID draw_gray_f_ntb_o_to_temp_start(
PGLYPHPOS pGlyphPos,
ULONG cGlyphs,
PUCHAR pjDst,
ULONG ulLeftEdge,
ULONG dpDst,
ULONG ulCharInc,
ULONG ulTempTop
)
{
GLYPHBITS *pgb; // pointer to current GLYPHBITS
int x; // x-coordinate of the current
// character origin with respect
// to the upper left pixel of the
// output (4-bpp) bitmap
int y; // y-coordinate of the current
// character origin with respect
// to the upper left pixel of the
// output (4-bpp) bitmap
unsigned bOddPos; // (x-coordinate is odd) ? 1 : 0
unsigned cx; // number of pixels per glyph scan
// If non zero then the destination
// bitmap is out of alignment with
// the source glyph by a one nyble
// shift and a single byte of the
// source will affect two consecutive
// bytes of the destination.
unsigned dpSrc; // number of bytes per source scan. Each
// scan is BYTE aligned.
// = ceil(4*cx/8) = floor((cx+1)/2)
GLYPHPOS *pgpOut; // sentinel for loop
BYTE *pj; // pointer into Buffer corresponding
// to the upper left pixel of the
// current gray glyph
#if DBG
if (gflFontDebug & DEBUG_AA)
{
DbgPrint(
"draw_gray_f_ntb_o_to_temp_start(\n"
" PGLYPHPOS pGlyphPos = %-#x\n"
" ULONG cGlyphs = %u\n"
" PUCHAR pjDst = %-#x\n"
" ULONG ulLeftEdge = %u\n"
" ULONG dpDst = %u\n"
" ULONG ulCharInc = %u\n"
" ULONG ulTempTop = %u\n"
" )\n"
, pGlyphPos
, cGlyphs
, pjDst
, ulLeftEdge
, dpDst
, ulCharInc
, ulTempTop
);
DbgBreakPoint();
}
#endif
// (x,y) = position of first CHARACTER ORIGIN with respect to
// the upper left pixel of the destination 4bpp bitmap
x = pGlyphPos->ptl.x - ulLeftEdge;
y = pGlyphPos->ptl.y - ulTempTop;
for (pgpOut = pGlyphPos + cGlyphs; pGlyphPos < pgpOut; x += ulCharInc, pGlyphPos++)
{
int xT, yT; // position of UPPER LEFT pixel of glyph
// with respect to the upper left pixel
// of the bitmap.
pgb = pGlyphPos->pgdf->pgb;
xT = x + pgb->ptlOrigin.x;
yT = y + pgb->ptlOrigin.y;
bOddPos = (unsigned) xT & 1;
cx = (unsigned) pgb->sizlBitmap.cx;
dpSrc = (cx + 1)/2;
pj = pjDst + (yT * dpDst) + (xT/2);
#if DBG
if (gflFontDebug & DEBUG_AA)
{
DbgPrint(
"\n"
" pgb = %-#x\n"
" ptlOrigin = (%d,%d)\n"
" xT = %d\n"
" yT = %d\n"
" bOddPos = %d\n"
, pgb
, pgb->ptlOrigin.x
, pgb->ptlOrigin.y
, xT
, yT
, bOddPos
);
DbgPrint(
" cx = %u\n"
" dpSrc = %u\n"
" pj = %-#x\n"
" (cx & 1) + 2*bOddPos = %d\n"
, cx
, dpSrc
, pj
, (cx & 1) + 2*bOddPos
);
DbgBreakPoint();
}
#endif
(*(apfnGray[(cx & 1) + 2*bOddPos]))(pgb, dpSrc, pj, dpDst);
}
}
#if DBG
/******************************Public*Routine******************************\
* *
* Routine Name: *
* *
* vDumpGrayBuffer *
* *
* Routine Description: *
* *
* Debug routine for dumping the temporary 4bpp gray string buffer *
* *
* Arguments: *
* *
* pjBuffer - pointer to gray 4bpp image *
* dpjScan - count of bytes per scan *
* prcl - rectangle surrounding 4bpp gray image *
* *
* Return Value: *
* *
* None *
* *
\**************************************************************************/
void vDumpGrayBuffer(BYTE *pjBuffer, ULONG dpjScan, RECTL *prcl)
{
BYTE *pj, *pjNext, *pjOut;
static char achNyble[16] = {
' ','1','2','3','4','5','6','7'
,'8','9','a','b','c','d','e','f'
};
DbgPrint(
"vDumpGrayBuffer(\n"
" pjBuffer = %-#x\n"
" dpjScan = %u\n"
" prcl = %-#x ==> %d %d %d %d\n"
")\n"
, pjBuffer
, dpjScan
, prcl
, prcl->left, prcl->top, prcl->right, prcl->bottom
);
DbgPrint("+");
for (pj = 0, pjOut = (BYTE*) dpjScan; pj < pjOut; pj++)
DbgPrint("--");
DbgPrint("+\n");
pjOut = pjBuffer + dpjScan * (prcl->bottom - prcl->top);
for (pj = pjBuffer; pj < pjOut;) {
DbgPrint("|");
for (pjNext = pj + dpjScan; pj < pjNext; pj++)
DbgPrint("%c%c", achNyble[*pj >> 4], achNyble[*pj & 15]);
DbgPrint("|\n");
}
DbgPrint("+");
for (pj = 0, pjOut= (BYTE*) dpjScan; pj < pjOut; pj++)
DbgPrint("--");
DbgPrint("+\n");
}
/******************************Public*Routine******************************\
* *
* Routine Name: *
* *
* vPrintGrayGLYPHBITS *
* *
* Routine Description: *
* *
* Dumps Gray GLYPHBITS to the debug screen *
* *
* Arguments: *
* *
* pgb - pointer to a gray GLYPHBITS structure *
* *
* Return Value: *
* *
* none *
* *
\**************************************************************************/
void vPrintGrayGLYPHBITS(GLYPHBITS *pgb)
{
BYTE *pj, *pjNext, *pjEnd;
ptrdiff_t cjScan, i;
static char achNyble[16] =
{' ','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
DbgPrint(
"Gray GLYPHBITS at = %-#x\n"
" ptlOrigin = %d %d\n"
" sizlBitmap = %u %u\n"
, pgb
, pgb->ptlOrigin.x
, pgb->ptlOrigin.y
, pgb->sizlBitmap.cx
, pgb->sizlBitmap.cy
);
pj = pgb->aj;
cjScan = ((ptrdiff_t) pgb->sizlBitmap.cx + 1)/2;
pjNext = pj + cjScan;
pjEnd = pj + cjScan * (ptrdiff_t) pgb->sizlBitmap.cy;
DbgPrint("+");
for (i = 0; i < cjScan; i++)
DbgPrint("--");
DbgPrint("+\n");
while (pj < pjEnd) {
DbgPrint("|");
while (pj < pjNext) {
DbgPrint("%c%c" , achNyble[*pj >> 4], achNyble[*pj & 0xf]);
pj += 1;
}
pj = pjNext;
pjNext += cjScan;
DbgPrint("|\n");
}
DbgPrint("+");
for (i = 0; i < cjScan; i++)
DbgPrint("--");
DbgPrint("+\n\n");
}
/******************************Public*Routine******************************\
* *
* Routine Name: *
* *
* vPrintGrayGLYPHPOS *
* *
* Routine Description: *
* *
* Dumps the contents of a Gray GLYPHPOS structure to the *
* debugger. *
* *
* Arguments: *
* *
* pgpos - a pointer to a gray GLYPHPOS structure *
* *
* Return Value: *
* *
* none *
* *
\**************************************************************************/
void vPrintGrayGLYPHPOS(GLYPHPOS *pgpos)
{
DbgPrint("Gray GLYPHPOS at %-#x\n", pgpos);
DbgPrint(" hg = %-#x\n", pgpos->hg);
DbgPrint(" pgdf = %-#x\n", pgpos->pgdf);
DbgPrint(" ptl = (%d,%d)\n", pgpos->ptl.x, pgpos->ptl.y);
// vPrintGrayGLYPHBITS(pgpos->pgdf->pgb);
}
/******************************Public*Routine******************************\
* *
* Routine Name: *
* *
* vDump8bppDIB *
* *
* Routine Description: *
* *
* Dumps an 8bpp DIB to the screen. This routine only recognizes the *
* four canonical shades of gray, all other colors are marked with *
* a question mark *
* *
* Arguments: *
* *
* SURFMEM reference. *
* *
* Return Value: *
* *
* none *
* *
\**************************************************************************/
void vDump8bppDIB(SURFMEM& surfmem)
{
char ch;
int j;
BYTE *pjScan, *pj, *pjOut;
ULONG dpjScan;
SURFOBJ *pso = surfmem.pSurfobj();
DbgPrint("Dumping the contents of the 8bpp DIB\n");
pso = surfmem.pSurfobj();
pjScan = (BYTE*) pso->pvBits;
dpjScan = 4 * ((pso->sizlBitmap.cx + 3) / 4);
DbgPrint("+");
for (j = 0; j < pso->sizlBitmap.cx; j++)
{
DbgPrint("-");
}
DbgPrint("+\n");
for (j = pso->sizlBitmap.cy; j; j--)
{
pj = pjScan;
pjOut = pjScan + pso->sizlBitmap.cx;
pjScan += dpjScan;
DbgPrint("|");
while (pj < pjOut)
{
switch (*pj++)
{
case 0: ch = ' '; break;
case 248: ch = '+'; break;
case 7: ch = '*'; break;
case 255: ch = '#'; break;
default: ch = '?'; break;
}
DbgPrint("%c",ch);
}
DbgPrint("|\n");
}
DbgPrint("+");
for (j = 0; j < pso->sizlBitmap.cx; j++)
{
DbgPrint("-");
}
DbgPrint("+\n");
}
#endif