Leaked source code of windows server 2003
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.
 
 
 
 
 
 

645 lines
16 KiB

/**************************************************************************\
*
* Copyright (c) 2000 Microsoft Corporation
*
* Abstract:
*
* Contains ClearType scan operations
*
* Revision History:
*
* 07/19/2000 mleonov
* Created it.
* 01/11/2001 mleonov
* Reengineered ClearType architecture to allow variable length scan records
*
\**************************************************************************/
#include "precomp.hpp"
static inline VOID
SetupGammaTables(ULONG ulGamma, const BYTE ** gamma, const BYTE ** gammaInv)
{
static BYTE const * const gammaTables[] =
{
Globals::TextContrastTableIdentity, Globals::TextContrastTableIdentity,
Globals::TextContrastTablesDir[0], Globals::TextContrastTablesInv[0],
Globals::TextContrastTablesDir[1], Globals::TextContrastTablesInv[1],
Globals::TextContrastTablesDir[2], Globals::TextContrastTablesInv[2],
Globals::TextContrastTablesDir[3], Globals::TextContrastTablesInv[3],
Globals::TextContrastTablesDir[4], Globals::TextContrastTablesInv[4],
Globals::TextContrastTablesDir[5], Globals::TextContrastTablesInv[5],
Globals::TextContrastTablesDir[6], Globals::TextContrastTablesInv[6],
Globals::TextContrastTablesDir[7], Globals::TextContrastTablesInv[7],
Globals::TextContrastTablesDir[8], Globals::TextContrastTablesInv[8],
Globals::TextContrastTablesDir[9], Globals::TextContrastTablesInv[9],
Globals::TextContrastTablesDir[10], Globals::TextContrastTablesInv[10],
Globals::TextContrastTablesDir[11], Globals::TextContrastTablesInv[11]
};
if (ulGamma > 12)
{
ASSERT(FALSE);
ulGamma = 12;
}
*gamma = gammaTables[2 * ulGamma];
*gammaInv = gammaTables[2 * ulGamma + 1];
} // SetupGammaTables
static __forceinline BYTE
BlendOneChannel(BYTE alphaCT, BYTE alphaBrush, BYTE foreground, BYTE background, const BYTE * gamma, const BYTE * gammaInv)
{
ASSERT(0 <= alphaCT && alphaCT <= CT_SAMPLE_F);
if (alphaCT == 0)
return background;
foreground = gamma[foreground];
background = gamma[background];
ULONG ulongRet = ULONG(0.5 + background + ((double)alphaBrush * (foreground - background) * alphaCT) / (255 * CT_SAMPLE_F));
ASSERT(ulongRet <= 255);
BYTE ret = (BYTE)ulongRet;
ret = gammaInv[ret];
return ret;
} // BlendOneChannel
namespace
{
class ClearTypeSolidBlend
{
const ARGB ArgbF;
const BYTE * ClearTypeBits;
public:
ClearTypeSolidBlend(const ScanOperation::OtherParams * otherParams)
: ClearTypeBits(otherParams->CTBuffer), ArgbF(otherParams->SolidColor)
{}
// always call IsCompletelyTransparent in the beginning of RMW operation
bool IsCompletelyTransparent() const
{
return GetAlpha() == 0;
}
BYTE GetCT() const
{
return *ClearTypeBits;
}
ARGB GetARGB() const
{
return ArgbF;
}
BYTE GetAlpha() const
{
return (BYTE)GpColor::GetAlphaARGB(ArgbF);
}
BYTE GetRed() const
{
return (BYTE)GpColor::GetRedARGB(ArgbF);
}
BYTE GetGreen() const
{
return (BYTE)GpColor::GetGreenARGB(ArgbF);
}
BYTE GetBlue() const
{
return (BYTE)GpColor::GetBlueARGB(ArgbF);
}
bool IsOpaque() const
{
return GetCT() == CT_LOOKUP - 1 && GetAlpha() == 255;
}
bool IsTransparent() const
{
// we took care of zero GetAlpha() in IsCompletelyTransparent()
return GetCT() == 0;
}
bool IsTranslucent() const
{
return !IsTransparent() && !IsOpaque();
}
void operator++()
{
++ClearTypeBits;
}
}; // class ClearTypeSolidBlend
class ClearTypeCARGBBlend
{
const ARGB * ArgbBrushBits;
const BYTE * ClearTypeBits;
public:
ClearTypeCARGBBlend(const ScanOperation::OtherParams * otherParams)
: ClearTypeBits(otherParams->CTBuffer),
ArgbBrushBits(static_cast<const ARGB*>(otherParams->BlendingScan))
{}
bool IsCompletelyTransparent() const
{
return false;
}
BYTE GetCT() const
{
return *ClearTypeBits;
}
ARGB GetARGB() const
{
return *ArgbBrushBits;
}
BYTE GetAlpha() const
{
return (BYTE)GpColor::GetAlphaARGB(*ArgbBrushBits);
}
BYTE GetRed() const
{
return (BYTE)GpColor::GetRedARGB(*ArgbBrushBits);
}
BYTE GetGreen() const
{
return (BYTE)GpColor::GetGreenARGB(*ArgbBrushBits);
}
BYTE GetBlue() const
{
return (BYTE)GpColor::GetBlueARGB(*ArgbBrushBits);
}
bool IsOpaque() const
{
return GetCT() == CT_LOOKUP - 1 && GetAlpha() == 255;
}
bool IsTransparent() const
{
return GetCT() == 0 || GetAlpha() == 0;
}
bool IsTranslucent() const
{
return !IsTransparent() && !IsOpaque();
}
void operator++()
{
++ClearTypeBits;
++ArgbBrushBits;
}
}; // class ClearTypeCARGBBlend
} // namespace
template <class BLENDTYPE>
static VOID ClearTypeBlend(
VOID *dst,
const VOID *src,
INT count,
const ScanOperation::OtherParams *otherParams,
BLENDTYPE & bl
)
{
if (bl.IsCompletelyTransparent())
return;
DEFINE_POINTERS(ARGB, ARGB)
ASSERT(count > 0);
ULONG gammaValue = otherParams->TextContrast;
const BYTE * gamma, * gammaInv;
SetupGammaTables(gammaValue, &gamma, &gammaInv);
do {
if (bl.IsTransparent())
; // fully transparent case, nothing to do
else if (bl.IsOpaque())
{ // fully opaque case, copy the foreground color
*d = bl.GetARGB();
}
else
{
const BYTE blendIndex = bl.GetCT();
ASSERT(0 <= blendIndex && blendIndex <= CT_LOOKUP - 1);
const Globals::F_RGB blend = Globals::gaOutTable[blendIndex];
const ARGB source = *s;
const BYTE alphaBrush = bl.GetAlpha();
const BYTE dstRed = BlendOneChannel(
blend.kR,
alphaBrush,
bl.GetRed(),
(BYTE)GpColor::GetRedARGB(source),
gamma,
gammaInv);
const BYTE dstGre = BlendOneChannel(
blend.kG,
alphaBrush,
bl.GetGreen(),
(BYTE)GpColor::GetGreenARGB(source),
gamma,
gammaInv);
const BYTE dstBlu = BlendOneChannel(
blend.kB,
alphaBrush,
bl.GetBlue(),
(BYTE)GpColor::GetBlueARGB(source),
gamma,
gammaInv);
*d = GpColor::MakeARGB(255, dstRed, dstGre, dstBlu);
}
++bl;
++s;
++d;
} while (--count);
} // ClearTypeBlend
VOID FASTCALL
ScanOperation::CTBlendCARGB(
VOID *dst,
const VOID *src,
INT count,
const OtherParams *otherParams
)
{
ClearTypeCARGBBlend bl(otherParams);
ClearTypeBlend(dst, src, count, otherParams, bl);
} // ScanOperation::CTBlendCARGB
VOID FASTCALL
ScanOperation::CTBlendSolid(
VOID *dst,
const VOID *src,
INT count,
const OtherParams *otherParams
)
{
ClearTypeSolidBlend bl(otherParams);
ClearTypeBlend(dst, src, count, otherParams, bl);
} // ScanOperation::CTBlendSolid
template <class BLENDTYPE>
static VOID
CTReadRMW16(
VOID *dst,
const VOID *src,
INT count,
const ScanOperation::OtherParams *otherParams,
BLENDTYPE & bl
)
{
if (bl.IsCompletelyTransparent())
return;
DEFINE_POINTERS(UINT16, UINT16)
// We want to get dword alignment for our copies, so handle the
// initial partial dword, if there is one:
if (((ULONG_PTR) s) & 0x2)
{
if (bl.IsTranslucent())
{
*(d) = *(s);
}
d++;
s++;
++bl;
count--;
}
// Now go through the aligned dword loop:
while ((count -= 2) >= 0)
{
if (bl.IsTranslucent())
{
++bl;
if (bl.IsTranslucent())
{
// Both pixels have partial alpha, so do a dword read:
*((UNALIGNED UINT32*) d) = *((UINT32*) s);
}
else
{
// Only the first pixel has partial alpha, so do a word read:
*(d) = *(s);
}
}
else
{
++bl;
if (bl.IsTranslucent())
{
// Only the second pixel has partial alpha, so do a word read:
*(d + 1) = *(s + 1);
}
}
d += 2;
s += 2;
++bl;
}
// Handle the end alignment:
if (count & 1)
{
if (bl.IsTranslucent())
{
*(d) = *(s);
}
}
} // CTReadRMW16
VOID FASTCALL ScanOperation::ReadRMW_16_CT_CARGB(
VOID *dst,
const VOID *src,
INT count,
const OtherParams *otherParams
)
{
ClearTypeCARGBBlend bl(otherParams);
CTReadRMW16(dst, src, count, otherParams, bl);
} // ScanOperation::ReadRMW_16_CT_CARGB
VOID FASTCALL ScanOperation::ReadRMW_16_CT_Solid(
VOID *dst,
const VOID *src,
INT count,
const OtherParams *otherParams
)
{
ClearTypeSolidBlend bl(otherParams);
CTReadRMW16(dst, src, count, otherParams, bl);
} // ScanOperation::ReadRMW_16_CT_Solid
template <class BLENDTYPE>
static VOID
CTReadRMW24(
VOID *dst,
const VOID *src,
INT count,
const ScanOperation::OtherParams *otherParams,
BLENDTYPE & bl
)
{
if (bl.IsCompletelyTransparent())
return;
DEFINE_POINTERS(BYTE, BYTE)
ULONG_PTR srcToDstDelta = (ULONG_PTR) d - (ULONG_PTR) s;
// Handle the initial partial read:
INT initialAlignment = (INT) ((ULONG_PTR) s & 3);
if (initialAlignment)
{
if (bl.IsTranslucent())
{
UINT32 *alignedSrc = (UINT32*) ((ULONG_PTR) s & ~3);
DWORD dwBuffer[2];
// Get pointer to start of pixel inside dwBuffer
BYTE *pByte = (BYTE*) dwBuffer + initialAlignment;
// Copy first aligned DWORDS from the source
dwBuffer[0] = *alignedSrc;
// Copy next one only if pixel is split between 2 aligned DWORDS
if (initialAlignment >= 2)
dwBuffer[1] = *(alignedSrc + 1);
// Copy 4 bytes to the destination
// This will cause an extra byte to have garbage in the
// destination buffer, but will be overwritten if next pixel
// is used.
*((DWORD*) d) = *((UNALIGNED DWORD*) pByte);
}
++bl;
s += 3;
if (--count == 0)
return;
}
while (TRUE)
{
// Find the first pixel to copy
while (!bl.IsTranslucent())
{
++bl;
s += 3;
if (--count == 0)
{
return;
}
}
UINT32 *startSrc = (UINT32*) ((ULONG_PTR) (s) & ~3);
// Now find the first "don't copy" pixel after that:
while (bl.IsTranslucent())
{
++bl;
s += 3;
if (--count == 0)
{
break;
}
}
// 'endSrc' is inclusive of the last pixel's last byte:
UINT32 *endSrc = (UINT32*) ((ULONG_PTR) (s + 2) & ~3);
UNALIGNED UINT32 *dstPtr = (UNALIGNED UINT32*) ((ULONG_PTR) startSrc + srcToDstDelta);
while (startSrc <= endSrc)
{
*dstPtr++ = *startSrc++;
}
if (count == 0)
return;
}
} // CTReadRMW24
VOID FASTCALL ScanOperation::ReadRMW_24_CT_CARGB(
VOID *dst,
const VOID *src,
INT count,
const OtherParams *otherParams
)
{
ClearTypeCARGBBlend bl(otherParams);
CTReadRMW24(dst, src, count, otherParams, bl);
} // ScanOperation::ReadRMW_24_CT_CARGB
VOID FASTCALL ScanOperation::ReadRMW_24_CT_Solid(
VOID *dst,
const VOID *src,
INT count,
const OtherParams *otherParams
)
{
ClearTypeSolidBlend bl(otherParams);
CTReadRMW24(dst, src, count, otherParams, bl);
} // ScanOperation::ReadRMW_24_CT_Solid
template <class BLENDTYPE>
static VOID
CTWriteRMW16(
VOID *dst,
const VOID *src,
INT count,
const ScanOperation::OtherParams *otherParams,
BLENDTYPE & bl
)
{
if (bl.IsCompletelyTransparent())
return;
DEFINE_POINTERS(UINT16, UINT16)
// We want to get dword alignment for our copies, so handle the
// initial partial dword, if there is one:
if (((ULONG_PTR) d) & 0x2)
{
if (!bl.IsTransparent())
{
*(d) = *(s);
}
d++;
s++;
++bl;
count--;
}
// Now go through the aligned dword loop:
while ((count -= 2) >= 0)
{
if (!bl.IsTransparent())
{
++bl;
if (!bl.IsTransparent())
{
// Both pixels have partial bl, so do a dword read:
*((UINT32*) d) = *((UNALIGNED UINT32*) s);
}
else
{
// Only the first pixel has partial bl, so do a word read:
*(d) = *(s);
}
}
else
{
++bl;
if (!bl.IsTransparent())
{
// Only the second pixel has partial bl, so do a word read:
*(d + 1) = *(s + 1);
}
}
d += 2;
s += 2;
++bl;
}
// Handle the end alignment:
if (count & 1)
{
if (!bl.IsTransparent())
{
*(d) = *(s);
}
}
} // CTWriteRMW16
VOID FASTCALL ScanOperation::WriteRMW_16_CT_CARGB(
VOID *dst,
const VOID *src,
INT count,
const OtherParams *otherParams
)
{
ClearTypeCARGBBlend bl(otherParams);
CTWriteRMW16(dst, src, count, otherParams, bl);
} // ScanOperation::WriteRMW_16_CT_CARGB
VOID FASTCALL ScanOperation::WriteRMW_16_CT_Solid(
VOID *dst,
const VOID *src,
INT count,
const OtherParams *otherParams
)
{
ClearTypeSolidBlend bl(otherParams);
CTWriteRMW16(dst, src, count, otherParams, bl);
} // ScanOperation::WriteRMW_16_CT_Solid
template <class BLENDTYPE>
static VOID
CTWriteRMW24(
VOID *dst,
const VOID *src,
INT count,
const ScanOperation::OtherParams *otherParams,
BLENDTYPE & bl
)
{
DEFINE_POINTERS(BYTE, BYTE)
ASSERT(count>0);
do {
if (!bl.IsTransparent())
{
// Doing byte per byte writes are much faster than finding
// runs and doing DWORD copies.
*(d) = *(s);
*(d + 1) = *(s + 1);
*(d + 2) = *(s + 2);
}
d += 3;
s += 3;
++bl;
} while (--count != 0);
} // CTWriteRMW24
VOID FASTCALL ScanOperation::WriteRMW_24_CT_CARGB(
VOID *dst,
const VOID *src,
INT count,
const OtherParams *otherParams
)
{
ClearTypeCARGBBlend bl(otherParams);
CTWriteRMW24(dst, src, count, otherParams, bl);
} // ScanOperation::WriteRMW_24_CT_CARGB
VOID FASTCALL ScanOperation::WriteRMW_24_CT_Solid(
VOID *dst,
const VOID *src,
INT count,
const OtherParams *otherParams
)
{
ClearTypeSolidBlend bl(otherParams);
CTWriteRMW24(dst, src, count, otherParams, bl);
} // ScanOperation::WriteRMW_24_CT_CARGB